• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #define LOG_TAG "hwservicemanager"
2 
3 #include "TokenManager.h"
4 
5 #include <android-base/logging.h>
6 #include <functional>
7 #include <log/log.h>
8 #include <openssl/hmac.h>
9 #include <openssl/rand.h>
10 
11 namespace android {
12 namespace hidl {
13 namespace token {
14 namespace V1_0 {
15 namespace implementation {
16 
ReadRandomBytes(uint8_t * buf,size_t len)17 static void ReadRandomBytes(uint8_t *buf, size_t len) {
18     int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
19     if (fd == -1) {
20         ALOGE("%s: cannot read /dev/urandom", __func__);
21         return;
22     }
23 
24     size_t n;
25     while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) {
26         len -= n;
27         buf += n;
28     }
29     if (len > 0) {
30         ALOGW("%s: there are %d bytes skipped", __func__, (int)len);
31     }
32     close(fd);
33 }
34 
TokenManager()35 TokenManager::TokenManager() {
36     ReadRandomBytes(mKey.data(), mKey.size());
37 }
38 
39 // Methods from ::android::hidl::token::V1_0::ITokenManager follow.
createToken(const sp<IBase> & store,createToken_cb hidl_cb)40 Return<void> TokenManager::createToken(const sp<IBase>& store, createToken_cb hidl_cb) {
41     TokenInterface interface = generateToken(store);
42 
43     if (interface.interface == nullptr) {
44         hidl_cb({});
45         return Void();
46     }
47 
48     uint64_t id = getTokenId(interface.token);
49 
50     if (id == TOKEN_ID_NONE) {
51         hidl_cb({});
52         return Void();
53     }
54 
55     mMap[id] = interface;
56 
57     hidl_cb(interface.token);
58     return Void();
59 }
60 
61 std::unordered_map<uint64_t,  TokenManager::TokenInterface>::const_iterator
lookupToken(const hidl_vec<uint8_t> & token)62         TokenManager::lookupToken(const hidl_vec<uint8_t> &token) {
63     uint64_t tokenId = getTokenId(token);
64 
65     if (tokenId == TOKEN_ID_NONE) {
66         return mMap.end();
67     }
68 
69     auto it = mMap.find(tokenId);
70 
71     if (it == mMap.end()) {
72         return mMap.end();
73     }
74 
75     const TokenInterface &interface = it->second;
76 
77     if (!constantTimeCompare(token, interface.token)) {
78         ALOGE("Fetch of token with invalid hash.");
79         return mMap.end();
80     }
81 
82     return it;
83 }
84 
unregister(const hidl_vec<uint8_t> & token)85 Return<bool> TokenManager::unregister(const hidl_vec<uint8_t> &token) {
86     auto it = lookupToken(token);
87 
88     if (it == mMap.end()) {
89         return false;
90     }
91 
92     mMap.erase(it);
93     return true;
94 }
95 
get(const hidl_vec<uint8_t> & token)96 Return<sp<IBase>> TokenManager::get(const hidl_vec<uint8_t> &token) {
97     auto it = lookupToken(token);
98 
99     if (it == mMap.end()) {
100         return nullptr;
101     }
102 
103     return it->second.interface;
104 }
105 
106 
generateToken(const sp<IBase> & interface)107 TokenManager::TokenInterface TokenManager::generateToken(const sp<IBase> &interface) {
108     uint64_t id = ++mTokenIndex;
109 
110     std::array<uint8_t, EVP_MAX_MD_SIZE> hmac;
111     uint32_t hmacSize;
112 
113     uint8_t *hmacOut = HMAC(EVP_sha256(),
114                             mKey.data(), mKey.size(),
115                             (uint8_t*) &id, ID_SIZE,
116                             hmac.data(), &hmacSize);
117 
118     if (hmacOut == nullptr ||
119             hmacOut != hmac.data()) {
120         ALOGE("Generating token failed, got %p.", hmacOut);
121         return { nullptr, {} };
122     }
123 
124     // only care about the first HMAC_SIZE bytes of the HMAC
125     const hidl_vec<uint8_t> &token = TokenManager::getToken(id, hmac.data(), hmacSize);
126 
127     return { interface, token };
128 }
129 
130 __attribute__((optnone))
constantTimeCompare(const hidl_vec<uint8_t> & t1,const hidl_vec<uint8_t> & t2)131 bool TokenManager::constantTimeCompare(const hidl_vec<uint8_t> &t1, const hidl_vec<uint8_t> &t2) {
132     if (t1.size() != t2.size()) {
133         return false;
134     }
135 
136     uint8_t x = 0;
137     for (size_t i = 0; i < t1.size(); i++) {
138         x |= t1[i] ^ t2[i];
139     }
140 
141     return x == 0;
142 }
143 
getTokenId(const hidl_vec<uint8_t> & token)144 uint64_t TokenManager::getTokenId(const hidl_vec<uint8_t> &token) {
145     if (token.size() < ID_SIZE) {
146         return TOKEN_ID_NONE;
147     }
148 
149     uint64_t id = 0;
150     for (size_t i = 0; i < ID_SIZE; i++) {
151         id |= token[i] << i;
152     }
153 
154     return id;
155 }
156 
getToken(const uint64_t id,const uint8_t * hmac,uint64_t hmacSize)157 hidl_vec<uint8_t> TokenManager::getToken(const uint64_t id, const uint8_t *hmac, uint64_t hmacSize) {
158     hidl_vec<uint8_t> token;
159     token.resize(ID_SIZE + hmacSize);
160 
161     for (size_t i = 0; i < ID_SIZE; i++) {
162         token[i] = (id >> i) & 0xFF;
163     }
164 
165     for (size_t i = 0; i < hmacSize; i++) {
166         token[i + ID_SIZE] = hmac[i];
167     }
168 
169     return token;
170 }
171 
172 
173 }  // namespace implementation
174 }  // namespace V1_0
175 }  // namespace token
176 }  // namespace hidl
177 }  // namespace android
178