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