1*ee3b7b62SAndroid Build Coastguard Worker /*
2*ee3b7b62SAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*ee3b7b62SAndroid Build Coastguard Worker *
4*ee3b7b62SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ee3b7b62SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ee3b7b62SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ee3b7b62SAndroid Build Coastguard Worker *
8*ee3b7b62SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ee3b7b62SAndroid Build Coastguard Worker *
10*ee3b7b62SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ee3b7b62SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ee3b7b62SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ee3b7b62SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ee3b7b62SAndroid Build Coastguard Worker * limitations under the License.
15*ee3b7b62SAndroid Build Coastguard Worker */
16*ee3b7b62SAndroid Build Coastguard Worker
17*ee3b7b62SAndroid Build Coastguard Worker #define LOG_TAG "hwservicemanager"
18*ee3b7b62SAndroid Build Coastguard Worker
19*ee3b7b62SAndroid Build Coastguard Worker #include "TokenManager.h"
20*ee3b7b62SAndroid Build Coastguard Worker
21*ee3b7b62SAndroid Build Coastguard Worker #include <fcntl.h>
22*ee3b7b62SAndroid Build Coastguard Worker
23*ee3b7b62SAndroid Build Coastguard Worker #include <hwbinder/IPCThreadState.h>
24*ee3b7b62SAndroid Build Coastguard Worker #include <log/log.h>
25*ee3b7b62SAndroid Build Coastguard Worker #include <openssl/hmac.h>
26*ee3b7b62SAndroid Build Coastguard Worker #include <openssl/rand.h>
27*ee3b7b62SAndroid Build Coastguard Worker #include <functional>
28*ee3b7b62SAndroid Build Coastguard Worker
29*ee3b7b62SAndroid Build Coastguard Worker namespace android {
30*ee3b7b62SAndroid Build Coastguard Worker namespace hidl {
31*ee3b7b62SAndroid Build Coastguard Worker namespace token {
32*ee3b7b62SAndroid Build Coastguard Worker namespace V1_0 {
33*ee3b7b62SAndroid Build Coastguard Worker namespace implementation {
34*ee3b7b62SAndroid Build Coastguard Worker
ReadRandomBytes(uint8_t * buf,size_t len)35*ee3b7b62SAndroid Build Coastguard Worker static void ReadRandomBytes(uint8_t *buf, size_t len) {
36*ee3b7b62SAndroid Build Coastguard Worker int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
37*ee3b7b62SAndroid Build Coastguard Worker if (fd == -1) {
38*ee3b7b62SAndroid Build Coastguard Worker ALOGE("%s: cannot read /dev/urandom", __func__);
39*ee3b7b62SAndroid Build Coastguard Worker return;
40*ee3b7b62SAndroid Build Coastguard Worker }
41*ee3b7b62SAndroid Build Coastguard Worker
42*ee3b7b62SAndroid Build Coastguard Worker size_t n;
43*ee3b7b62SAndroid Build Coastguard Worker while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) {
44*ee3b7b62SAndroid Build Coastguard Worker len -= n;
45*ee3b7b62SAndroid Build Coastguard Worker buf += n;
46*ee3b7b62SAndroid Build Coastguard Worker }
47*ee3b7b62SAndroid Build Coastguard Worker if (len > 0) {
48*ee3b7b62SAndroid Build Coastguard Worker ALOGW("%s: there are %d bytes skipped", __func__, (int)len);
49*ee3b7b62SAndroid Build Coastguard Worker }
50*ee3b7b62SAndroid Build Coastguard Worker close(fd);
51*ee3b7b62SAndroid Build Coastguard Worker }
52*ee3b7b62SAndroid Build Coastguard Worker
TokenManager()53*ee3b7b62SAndroid Build Coastguard Worker TokenManager::TokenManager() {
54*ee3b7b62SAndroid Build Coastguard Worker ReadRandomBytes(mKey.data(), mKey.size());
55*ee3b7b62SAndroid Build Coastguard Worker }
56*ee3b7b62SAndroid Build Coastguard Worker
noteTmUsage(const char * action,size_t size)57*ee3b7b62SAndroid Build Coastguard Worker static void noteTmUsage(const char* action, size_t size) {
58*ee3b7b62SAndroid Build Coastguard Worker using android::hardware::IPCThreadState;
59*ee3b7b62SAndroid Build Coastguard Worker const auto& self = IPCThreadState::self();
60*ee3b7b62SAndroid Build Coastguard Worker ALOGI("TokenManager tokens count %s by (uid: %d, pid: %d), now: %zu", action,
61*ee3b7b62SAndroid Build Coastguard Worker self->getCallingUid(), self->getCallingPid(), size);
62*ee3b7b62SAndroid Build Coastguard Worker }
63*ee3b7b62SAndroid Build Coastguard Worker
64*ee3b7b62SAndroid Build Coastguard Worker // Methods from ::android::hidl::token::V1_0::ITokenManager follow.
createToken(const sp<IBase> & store,createToken_cb hidl_cb)65*ee3b7b62SAndroid Build Coastguard Worker Return<void> TokenManager::createToken(const sp<IBase>& store, createToken_cb hidl_cb) {
66*ee3b7b62SAndroid Build Coastguard Worker TokenInterface interface = generateToken(store);
67*ee3b7b62SAndroid Build Coastguard Worker
68*ee3b7b62SAndroid Build Coastguard Worker if (interface.interface == nullptr) {
69*ee3b7b62SAndroid Build Coastguard Worker hidl_cb({});
70*ee3b7b62SAndroid Build Coastguard Worker return Void();
71*ee3b7b62SAndroid Build Coastguard Worker }
72*ee3b7b62SAndroid Build Coastguard Worker
73*ee3b7b62SAndroid Build Coastguard Worker uint64_t id = getTokenId(interface.token);
74*ee3b7b62SAndroid Build Coastguard Worker
75*ee3b7b62SAndroid Build Coastguard Worker if (id != interface.id) {
76*ee3b7b62SAndroid Build Coastguard Worker ALOGE("Token creation failed.");
77*ee3b7b62SAndroid Build Coastguard Worker hidl_cb({});
78*ee3b7b62SAndroid Build Coastguard Worker return Void();
79*ee3b7b62SAndroid Build Coastguard Worker }
80*ee3b7b62SAndroid Build Coastguard Worker
81*ee3b7b62SAndroid Build Coastguard Worker if (id == TOKEN_ID_NONE) {
82*ee3b7b62SAndroid Build Coastguard Worker hidl_cb({});
83*ee3b7b62SAndroid Build Coastguard Worker return Void();
84*ee3b7b62SAndroid Build Coastguard Worker }
85*ee3b7b62SAndroid Build Coastguard Worker
86*ee3b7b62SAndroid Build Coastguard Worker mMap[id] = interface;
87*ee3b7b62SAndroid Build Coastguard Worker noteTmUsage("added", mMap.size());
88*ee3b7b62SAndroid Build Coastguard Worker
89*ee3b7b62SAndroid Build Coastguard Worker hidl_cb(interface.token);
90*ee3b7b62SAndroid Build Coastguard Worker return Void();
91*ee3b7b62SAndroid Build Coastguard Worker }
92*ee3b7b62SAndroid Build Coastguard Worker
93*ee3b7b62SAndroid Build Coastguard Worker std::unordered_map<uint64_t, TokenManager::TokenInterface>::const_iterator
lookupToken(const hidl_vec<uint8_t> & token)94*ee3b7b62SAndroid Build Coastguard Worker TokenManager::lookupToken(const hidl_vec<uint8_t> &token) {
95*ee3b7b62SAndroid Build Coastguard Worker uint64_t tokenId = getTokenId(token);
96*ee3b7b62SAndroid Build Coastguard Worker
97*ee3b7b62SAndroid Build Coastguard Worker if (tokenId == TOKEN_ID_NONE) {
98*ee3b7b62SAndroid Build Coastguard Worker return mMap.end();
99*ee3b7b62SAndroid Build Coastguard Worker }
100*ee3b7b62SAndroid Build Coastguard Worker
101*ee3b7b62SAndroid Build Coastguard Worker auto it = mMap.find(tokenId);
102*ee3b7b62SAndroid Build Coastguard Worker
103*ee3b7b62SAndroid Build Coastguard Worker if (it == mMap.end()) {
104*ee3b7b62SAndroid Build Coastguard Worker return mMap.end();
105*ee3b7b62SAndroid Build Coastguard Worker }
106*ee3b7b62SAndroid Build Coastguard Worker
107*ee3b7b62SAndroid Build Coastguard Worker const TokenInterface &interface = it->second;
108*ee3b7b62SAndroid Build Coastguard Worker
109*ee3b7b62SAndroid Build Coastguard Worker if (!constantTimeCompare(token, interface.token)) {
110*ee3b7b62SAndroid Build Coastguard Worker ALOGE("Fetch of token with invalid hash.");
111*ee3b7b62SAndroid Build Coastguard Worker return mMap.end();
112*ee3b7b62SAndroid Build Coastguard Worker }
113*ee3b7b62SAndroid Build Coastguard Worker
114*ee3b7b62SAndroid Build Coastguard Worker return it;
115*ee3b7b62SAndroid Build Coastguard Worker }
116*ee3b7b62SAndroid Build Coastguard Worker
unregister(const hidl_vec<uint8_t> & token)117*ee3b7b62SAndroid Build Coastguard Worker Return<bool> TokenManager::unregister(const hidl_vec<uint8_t> &token) {
118*ee3b7b62SAndroid Build Coastguard Worker auto it = lookupToken(token);
119*ee3b7b62SAndroid Build Coastguard Worker
120*ee3b7b62SAndroid Build Coastguard Worker if (it == mMap.end()) {
121*ee3b7b62SAndroid Build Coastguard Worker return false;
122*ee3b7b62SAndroid Build Coastguard Worker }
123*ee3b7b62SAndroid Build Coastguard Worker
124*ee3b7b62SAndroid Build Coastguard Worker mMap.erase(it);
125*ee3b7b62SAndroid Build Coastguard Worker noteTmUsage("removed", mMap.size());
126*ee3b7b62SAndroid Build Coastguard Worker
127*ee3b7b62SAndroid Build Coastguard Worker return true;
128*ee3b7b62SAndroid Build Coastguard Worker }
129*ee3b7b62SAndroid Build Coastguard Worker
get(const hidl_vec<uint8_t> & token)130*ee3b7b62SAndroid Build Coastguard Worker Return<sp<IBase>> TokenManager::get(const hidl_vec<uint8_t> &token) {
131*ee3b7b62SAndroid Build Coastguard Worker auto it = lookupToken(token);
132*ee3b7b62SAndroid Build Coastguard Worker
133*ee3b7b62SAndroid Build Coastguard Worker if (it == mMap.end()) {
134*ee3b7b62SAndroid Build Coastguard Worker return nullptr;
135*ee3b7b62SAndroid Build Coastguard Worker }
136*ee3b7b62SAndroid Build Coastguard Worker
137*ee3b7b62SAndroid Build Coastguard Worker return it->second.interface;
138*ee3b7b62SAndroid Build Coastguard Worker }
139*ee3b7b62SAndroid Build Coastguard Worker
140*ee3b7b62SAndroid Build Coastguard Worker
generateToken(const sp<IBase> & interface)141*ee3b7b62SAndroid Build Coastguard Worker TokenManager::TokenInterface TokenManager::generateToken(const sp<IBase> &interface) {
142*ee3b7b62SAndroid Build Coastguard Worker uint64_t id = ++mTokenIndex;
143*ee3b7b62SAndroid Build Coastguard Worker
144*ee3b7b62SAndroid Build Coastguard Worker std::array<uint8_t, EVP_MAX_MD_SIZE> hmac;
145*ee3b7b62SAndroid Build Coastguard Worker uint32_t hmacSize;
146*ee3b7b62SAndroid Build Coastguard Worker
147*ee3b7b62SAndroid Build Coastguard Worker uint8_t *hmacOut = HMAC(EVP_sha256(),
148*ee3b7b62SAndroid Build Coastguard Worker mKey.data(), mKey.size(),
149*ee3b7b62SAndroid Build Coastguard Worker (uint8_t*) &id, sizeof(id),
150*ee3b7b62SAndroid Build Coastguard Worker hmac.data(), &hmacSize);
151*ee3b7b62SAndroid Build Coastguard Worker
152*ee3b7b62SAndroid Build Coastguard Worker if (hmacOut == nullptr ||
153*ee3b7b62SAndroid Build Coastguard Worker hmacOut != hmac.data()) {
154*ee3b7b62SAndroid Build Coastguard Worker ALOGE("Generating token failed, got %p.", hmacOut);
155*ee3b7b62SAndroid Build Coastguard Worker return { nullptr, TOKEN_ID_NONE, {} };
156*ee3b7b62SAndroid Build Coastguard Worker }
157*ee3b7b62SAndroid Build Coastguard Worker
158*ee3b7b62SAndroid Build Coastguard Worker // only care about the first HMAC_SIZE bytes of the HMAC
159*ee3b7b62SAndroid Build Coastguard Worker const hidl_vec<uint8_t> &token = makeToken(id, hmac.data(), hmacSize);
160*ee3b7b62SAndroid Build Coastguard Worker
161*ee3b7b62SAndroid Build Coastguard Worker return { interface, id, token };
162*ee3b7b62SAndroid Build Coastguard Worker }
163*ee3b7b62SAndroid Build Coastguard Worker
164*ee3b7b62SAndroid Build Coastguard Worker __attribute__((optnone))
constantTimeCompare(const hidl_vec<uint8_t> & t1,const hidl_vec<uint8_t> & t2)165*ee3b7b62SAndroid Build Coastguard Worker bool TokenManager::constantTimeCompare(const hidl_vec<uint8_t> &t1, const hidl_vec<uint8_t> &t2) {
166*ee3b7b62SAndroid Build Coastguard Worker if (t1.size() != t2.size()) {
167*ee3b7b62SAndroid Build Coastguard Worker return false;
168*ee3b7b62SAndroid Build Coastguard Worker }
169*ee3b7b62SAndroid Build Coastguard Worker
170*ee3b7b62SAndroid Build Coastguard Worker uint8_t x = 0;
171*ee3b7b62SAndroid Build Coastguard Worker for (size_t i = 0; i < t1.size(); i++) {
172*ee3b7b62SAndroid Build Coastguard Worker x |= t1[i] ^ t2[i];
173*ee3b7b62SAndroid Build Coastguard Worker }
174*ee3b7b62SAndroid Build Coastguard Worker
175*ee3b7b62SAndroid Build Coastguard Worker return x == 0;
176*ee3b7b62SAndroid Build Coastguard Worker }
177*ee3b7b62SAndroid Build Coastguard Worker
getTokenId(const hidl_vec<uint8_t> & token)178*ee3b7b62SAndroid Build Coastguard Worker uint64_t TokenManager::getTokenId(const hidl_vec<uint8_t> &token) {
179*ee3b7b62SAndroid Build Coastguard Worker uint64_t id = 0;
180*ee3b7b62SAndroid Build Coastguard Worker
181*ee3b7b62SAndroid Build Coastguard Worker if (token.size() < sizeof(id)) {
182*ee3b7b62SAndroid Build Coastguard Worker return TOKEN_ID_NONE;
183*ee3b7b62SAndroid Build Coastguard Worker }
184*ee3b7b62SAndroid Build Coastguard Worker
185*ee3b7b62SAndroid Build Coastguard Worker memcpy(&id, token.data(), sizeof(id));
186*ee3b7b62SAndroid Build Coastguard Worker
187*ee3b7b62SAndroid Build Coastguard Worker return id;
188*ee3b7b62SAndroid Build Coastguard Worker }
189*ee3b7b62SAndroid Build Coastguard Worker
makeToken(const uint64_t id,const uint8_t * hmac,uint64_t hmacSize)190*ee3b7b62SAndroid Build Coastguard Worker hidl_vec<uint8_t> TokenManager::makeToken(const uint64_t id, const uint8_t *hmac, uint64_t hmacSize) {
191*ee3b7b62SAndroid Build Coastguard Worker hidl_vec<uint8_t> token;
192*ee3b7b62SAndroid Build Coastguard Worker token.resize(sizeof(id) + hmacSize);
193*ee3b7b62SAndroid Build Coastguard Worker
194*ee3b7b62SAndroid Build Coastguard Worker memcpy(token.data(), &id, sizeof(id));
195*ee3b7b62SAndroid Build Coastguard Worker memcpy(token.data() + sizeof(id), hmac, hmacSize);
196*ee3b7b62SAndroid Build Coastguard Worker
197*ee3b7b62SAndroid Build Coastguard Worker return token;
198*ee3b7b62SAndroid Build Coastguard Worker }
199*ee3b7b62SAndroid Build Coastguard Worker
200*ee3b7b62SAndroid Build Coastguard Worker
201*ee3b7b62SAndroid Build Coastguard Worker } // namespace implementation
202*ee3b7b62SAndroid Build Coastguard Worker } // namespace V1_0
203*ee3b7b62SAndroid Build Coastguard Worker } // namespace token
204*ee3b7b62SAndroid Build Coastguard Worker } // namespace hidl
205*ee3b7b62SAndroid Build Coastguard Worker } // namespace android
206