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