1 /* 2 * Copyright (C) 2015 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 "keystore" 18 19 #include <arpa/inet.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <string.h> 23 24 #include <cutils/log.h> 25 26 #include "blob.h" 27 #include "entropy.h" 28 29 #include "keystore_utils.h" 30 31 namespace { 32 33 constexpr size_t kGcmIvSizeBytes = 96 / 8; 34 35 template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter { 36 void operator()(T* p) { FreeFunc(p); } 37 }; 38 39 #define DEFINE_OPENSSL_OBJECT_POINTER(name) \ 40 typedef OpenSslObjectDeleter<name, name##_free> name##_Delete; \ 41 typedef std::unique_ptr<name, name##_Delete> name##_Ptr; 42 43 DEFINE_OPENSSL_OBJECT_POINTER(EVP_CIPHER_CTX); 44 45 #if defined(__clang__) 46 #define OPTNONE __attribute__((optnone)) 47 #elif defined(__GNUC__) 48 #define OPTNONE __attribute__((optimize("O0"))) 49 #else 50 #error Need a definition for OPTNONE 51 #endif 52 53 class ArrayEraser { 54 public: 55 ArrayEraser(uint8_t* arr, size_t size) : mArr(arr), mSize(size) {} 56 OPTNONE ~ArrayEraser() { std::fill(mArr, mArr + mSize, 0); } 57 58 private: 59 volatile uint8_t* mArr; 60 size_t mSize; 61 }; 62 63 /* 64 * Encrypt 'len' data at 'in' with AES-GCM, using 128-bit key at 'key', 96-bit IV at 'iv' and write 65 * output to 'out' (which may be the same location as 'in') and 128-bit tag to 'tag'. 66 */ 67 ResponseCode AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len, const uint8_t* key, 68 const uint8_t* iv, uint8_t* tag) { 69 const EVP_CIPHER* cipher = EVP_aes_128_gcm(); 70 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new()); 71 72 EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key, iv); 73 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */); 74 75 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]); 76 uint8_t* out_pos = out_tmp.get(); 77 int out_len; 78 79 EVP_EncryptUpdate(ctx.get(), out_pos, &out_len, in, len); 80 out_pos += out_len; 81 EVP_EncryptFinal_ex(ctx.get(), out_pos, &out_len); 82 out_pos += out_len; 83 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) { 84 ALOGD("Encrypted ciphertext is the wrong size, expected %zu, got %zd", len, 85 out_pos - out_tmp.get()); 86 return ResponseCode::SYSTEM_ERROR; 87 } 88 89 std::copy(out_tmp.get(), out_pos, out); 90 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kGcmTagLength, tag); 91 92 return ResponseCode::NO_ERROR; 93 } 94 95 /* 96 * Decrypt 'len' data at 'in' with AES-GCM, using 128-bit key at 'key', 96-bit IV at 'iv', checking 97 * 128-bit tag at 'tag' and writing plaintext to 'out' (which may be the same location as 'in'). 98 */ 99 ResponseCode AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len, const uint8_t* key, 100 const uint8_t* iv, const uint8_t* tag) { 101 const EVP_CIPHER* cipher = EVP_aes_128_gcm(); 102 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new()); 103 104 EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key, iv); 105 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */); 106 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kGcmTagLength, const_cast<uint8_t*>(tag)); 107 108 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]); 109 ArrayEraser out_eraser(out_tmp.get(), len); 110 uint8_t* out_pos = out_tmp.get(); 111 int out_len; 112 113 EVP_DecryptUpdate(ctx.get(), out_pos, &out_len, in, len); 114 out_pos += out_len; 115 if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) { 116 ALOGD("Failed to decrypt blob; ciphertext or tag is likely corrupted"); 117 return ResponseCode::SYSTEM_ERROR; 118 } 119 out_pos += out_len; 120 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) { 121 ALOGD("Encrypted plaintext is the wrong size, expected %zu, got %zd", len, 122 out_pos - out_tmp.get()); 123 return ResponseCode::SYSTEM_ERROR; 124 } 125 126 std::copy(out_tmp.get(), out_pos, out); 127 128 return ResponseCode::NO_ERROR; 129 } 130 131 } // namespace 132 133 Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength, 134 BlobType type) { 135 memset(&mBlob, 0, sizeof(mBlob)); 136 if (valueLength > kValueSize) { 137 valueLength = kValueSize; 138 ALOGW("Provided blob length too large"); 139 } 140 if (infoLength + valueLength > kValueSize) { 141 infoLength = kValueSize - valueLength; 142 ALOGW("Provided info length too large"); 143 } 144 mBlob.length = valueLength; 145 memcpy(mBlob.value, value, valueLength); 146 147 mBlob.info = infoLength; 148 memcpy(mBlob.value + valueLength, info, infoLength); 149 150 mBlob.version = CURRENT_BLOB_VERSION; 151 mBlob.type = uint8_t(type); 152 153 if (type == TYPE_MASTER_KEY) { 154 mBlob.flags = KEYSTORE_FLAG_ENCRYPTED; 155 } else { 156 mBlob.flags = KEYSTORE_FLAG_NONE; 157 } 158 } 159 160 Blob::Blob(blobv3 b) { 161 mBlob = b; 162 } 163 164 Blob::Blob() { 165 memset(&mBlob, 0, sizeof(mBlob)); 166 } 167 168 bool Blob::isEncrypted() const { 169 if (mBlob.version < 2) { 170 return true; 171 } 172 173 return mBlob.flags & KEYSTORE_FLAG_ENCRYPTED; 174 } 175 176 bool Blob::isSuperEncrypted() const { 177 return mBlob.flags & KEYSTORE_FLAG_SUPER_ENCRYPTED; 178 } 179 180 bool Blob::isCriticalToDeviceEncryption() const { 181 return mBlob.flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION; 182 } 183 184 inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) { 185 return set ? (flags | flag) : (flags & ~flag); 186 } 187 188 void Blob::setEncrypted(bool encrypted) { 189 mBlob.flags = setFlag(mBlob.flags, encrypted, KEYSTORE_FLAG_ENCRYPTED); 190 } 191 192 void Blob::setSuperEncrypted(bool superEncrypted) { 193 mBlob.flags = setFlag(mBlob.flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED); 194 } 195 196 void Blob::setCriticalToDeviceEncryption(bool critical) { 197 mBlob.flags = setFlag(mBlob.flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION); 198 } 199 200 void Blob::setFallback(bool fallback) { 201 if (fallback) { 202 mBlob.flags |= KEYSTORE_FLAG_FALLBACK; 203 } else { 204 mBlob.flags &= ~KEYSTORE_FLAG_FALLBACK; 205 } 206 } 207 208 ResponseCode Blob::writeBlob(const std::string& filename, const uint8_t* aes_key, State state, 209 Entropy* entropy) { 210 ALOGV("writing blob %s", filename.c_str()); 211 212 const size_t dataLength = mBlob.length; 213 mBlob.length = htonl(mBlob.length); 214 215 if (isEncrypted() || isSuperEncrypted()) { 216 if (state != STATE_NO_ERROR) { 217 ALOGD("couldn't insert encrypted blob while not unlocked"); 218 return ResponseCode::LOCKED; 219 } 220 221 memset(mBlob.initialization_vector, 0, AES_BLOCK_SIZE); 222 if (!entropy->generate_random_data(mBlob.initialization_vector, kGcmIvSizeBytes)) { 223 ALOGW("Could not read random data for: %s", filename.c_str()); 224 return ResponseCode::SYSTEM_ERROR; 225 } 226 227 auto rc = AES_gcm_encrypt(mBlob.value /* in */, mBlob.value /* out */, dataLength, aes_key, 228 mBlob.initialization_vector, mBlob.aead_tag); 229 if (rc != ResponseCode::NO_ERROR) return rc; 230 } 231 232 size_t fileLength = offsetof(blobv3, value) + dataLength + mBlob.info; 233 234 const char* tmpFileName = ".tmp"; 235 int out = 236 TEMP_FAILURE_RETRY(open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)); 237 if (out < 0) { 238 ALOGW("could not open file: %s: %s", tmpFileName, strerror(errno)); 239 return ResponseCode::SYSTEM_ERROR; 240 } 241 242 const size_t writtenBytes = writeFully(out, (uint8_t*)&mBlob, fileLength); 243 if (close(out) != 0) { 244 return ResponseCode::SYSTEM_ERROR; 245 } 246 if (writtenBytes != fileLength) { 247 ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength); 248 unlink(tmpFileName); 249 return ResponseCode::SYSTEM_ERROR; 250 } 251 if (rename(tmpFileName, filename.c_str()) == -1) { 252 ALOGW("could not rename blob to %s: %s", filename.c_str(), strerror(errno)); 253 return ResponseCode::SYSTEM_ERROR; 254 } 255 return ResponseCode::NO_ERROR; 256 } 257 258 ResponseCode Blob::readBlob(const std::string& filename, const uint8_t* aes_key, State state) { 259 ALOGV("reading blob %s", filename.c_str()); 260 const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY)); 261 if (in < 0) { 262 return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR; 263 } 264 265 // fileLength may be less than sizeof(mBlob) 266 const size_t fileLength = readFully(in, (uint8_t*)&mBlob, sizeof(mBlob)); 267 if (close(in) != 0) { 268 return ResponseCode::SYSTEM_ERROR; 269 } 270 271 if (fileLength == 0) { 272 return ResponseCode::VALUE_CORRUPTED; 273 } 274 275 if ((isEncrypted() || isSuperEncrypted())) { 276 if (state == STATE_LOCKED) return ResponseCode::LOCKED; 277 if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED; 278 } 279 280 if (fileLength < offsetof(blobv3, value)) return ResponseCode::VALUE_CORRUPTED; 281 282 if (mBlob.version == 3) { 283 const ssize_t encryptedLength = ntohl(mBlob.length); 284 285 if (isEncrypted() || isSuperEncrypted()) { 286 auto rc = AES_gcm_decrypt(mBlob.value /* in */, mBlob.value /* out */, encryptedLength, 287 aes_key, mBlob.initialization_vector, mBlob.aead_tag); 288 if (rc != ResponseCode::NO_ERROR) return rc; 289 } 290 } else if (mBlob.version < 3) { 291 blobv2& blob = reinterpret_cast<blobv2&>(mBlob); 292 const size_t headerLength = offsetof(blobv2, encrypted); 293 const ssize_t encryptedLength = fileLength - headerLength - blob.info; 294 if (encryptedLength < 0) return ResponseCode::VALUE_CORRUPTED; 295 296 if (isEncrypted() || isSuperEncrypted()) { 297 if (encryptedLength % AES_BLOCK_SIZE != 0) { 298 return ResponseCode::VALUE_CORRUPTED; 299 } 300 301 AES_KEY key; 302 AES_set_decrypt_key(aes_key, kAesKeySize * 8, &key); 303 AES_cbc_encrypt(blob.encrypted, blob.encrypted, encryptedLength, &key, blob.vector, 304 AES_DECRYPT); 305 key = {}; // clear key 306 307 uint8_t computedDigest[MD5_DIGEST_LENGTH]; 308 ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH; 309 MD5(blob.digested, digestedLength, computedDigest); 310 if (memcmp(blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) { 311 return ResponseCode::VALUE_CORRUPTED; 312 } 313 } 314 } 315 316 const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - mBlob.info; 317 mBlob.length = ntohl(mBlob.length); 318 if (mBlob.length < 0 || mBlob.length > maxValueLength || 319 mBlob.length + mBlob.info + AES_BLOCK_SIZE > static_cast<ssize_t>(sizeof(mBlob.value))) { 320 return ResponseCode::VALUE_CORRUPTED; 321 } 322 323 if (mBlob.info != 0 && mBlob.version < 3) { 324 // move info from after padding to after data 325 memmove(mBlob.value + mBlob.length, mBlob.value + maxValueLength, mBlob.info); 326 } 327 328 return ResponseCode::NO_ERROR; 329 } 330