xref: /aosp_15_r20/system/hwservicemanager/TokenManager.cpp (revision ee3b7b6295061e544d3520b965ea91a90424af41)
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