blob: c3956f0019a3b293722f96cc4ee3bf6263fc406a [file] [log] [blame]
Shawn Willdenc1d1fee2016-01-26 22:44:56 -07001/*
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>
Branden Archere489a032018-12-28 09:10:49 -080022#include <openssl/rand.h>
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070023#include <string.h>
24
25#include <cutils/log.h>
26
27#include "blob.h"
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070028
29#include "keystore_utils.h"
30
Shawn Willdene9830582017-04-18 10:47:57 -060031namespace {
32
33constexpr size_t kGcmIvSizeBytes = 96 / 8;
34
35template <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
43DEFINE_OPENSSL_OBJECT_POINTER(EVP_CIPHER_CTX);
44
Shawn Willden0ed642c2017-05-26 10:13:28 -060045#if defined(__clang__)
Shawn Willdene9830582017-04-18 10:47:57 -060046#define OPTNONE __attribute__((optnone))
Shawn Willden0ed642c2017-05-26 10:13:28 -060047#elif defined(__GNUC__)
Shawn Willdene9830582017-04-18 10:47:57 -060048#define OPTNONE __attribute__((optimize("O0")))
Shawn Willden0ed642c2017-05-26 10:13:28 -060049#else
50#error Need a definition for OPTNONE
51#endif
Shawn Willdene9830582017-04-18 10:47:57 -060052
53class 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:
Shawn Willden0ed642c2017-05-26 10:13:28 -060059 volatile uint8_t* mArr;
Shawn Willdene9830582017-04-18 10:47:57 -060060 size_t mSize;
61};
62
Branden Archerb7ff91b2019-01-10 15:01:49 -080063/**
64 * Returns a EVP_CIPHER appropriate for the given key, based on the key's size.
65 */
66const EVP_CIPHER* getAesCipherForKey(const std::vector<uint8_t>& key) {
67 const EVP_CIPHER* cipher = EVP_aes_256_gcm();
68 if (key.size() == kAes128KeySizeBytes) {
69 cipher = EVP_aes_128_gcm();
70 }
71 return cipher;
72}
73
Shawn Willdene9830582017-04-18 10:47:57 -060074/*
Branden Archerb7ff91b2019-01-10 15:01:49 -080075 * Encrypt 'len' data at 'in' with AES-GCM, using 128-bit or 256-bit key at 'key', 96-bit IV at
76 * 'iv' and write output to 'out' (which may be the same location as 'in') and 128-bit tag to
77 * 'tag'.
Shawn Willdene9830582017-04-18 10:47:57 -060078 */
Branden Archera7a29fa2019-01-10 09:24:14 -080079ResponseCode AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len,
80 const std::vector<uint8_t>& key, const uint8_t* iv, uint8_t* tag) {
Branden Archerb7ff91b2019-01-10 15:01:49 -080081
82 // There can be 128-bit and 256-bit keys
83 const EVP_CIPHER* cipher = getAesCipherForKey(key);
84
Shawn Willdene9830582017-04-18 10:47:57 -060085 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
86
Branden Archera7a29fa2019-01-10 09:24:14 -080087 EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
Shawn Willdene9830582017-04-18 10:47:57 -060088 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
89
90 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
91 uint8_t* out_pos = out_tmp.get();
92 int out_len;
93
94 EVP_EncryptUpdate(ctx.get(), out_pos, &out_len, in, len);
95 out_pos += out_len;
96 EVP_EncryptFinal_ex(ctx.get(), out_pos, &out_len);
97 out_pos += out_len;
98 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
99 ALOGD("Encrypted ciphertext is the wrong size, expected %zu, got %zd", len,
100 out_pos - out_tmp.get());
101 return ResponseCode::SYSTEM_ERROR;
102 }
103
104 std::copy(out_tmp.get(), out_pos, out);
105 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kGcmTagLength, tag);
106
107 return ResponseCode::NO_ERROR;
108}
109
110/*
Branden Archerb7ff91b2019-01-10 15:01:49 -0800111 * Decrypt 'len' data at 'in' with AES-GCM, using 128-bit or 256-bit key at 'key', 96-bit IV at
112 * 'iv', checking 128-bit tag at 'tag' and writing plaintext to 'out'(which may be the same
113 * location as 'in').
Shawn Willdene9830582017-04-18 10:47:57 -0600114 */
Branden Archera7a29fa2019-01-10 09:24:14 -0800115ResponseCode AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len,
116 const std::vector<uint8_t> key, const uint8_t* iv,
117 const uint8_t* tag) {
Branden Archerb7ff91b2019-01-10 15:01:49 -0800118
119 // There can be 128-bit and 256-bit keys
120 const EVP_CIPHER* cipher = getAesCipherForKey(key);
121
Shawn Willdene9830582017-04-18 10:47:57 -0600122 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
123
Branden Archera7a29fa2019-01-10 09:24:14 -0800124 EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
Shawn Willdene9830582017-04-18 10:47:57 -0600125 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
126 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kGcmTagLength, const_cast<uint8_t*>(tag));
127
128 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
129 ArrayEraser out_eraser(out_tmp.get(), len);
130 uint8_t* out_pos = out_tmp.get();
131 int out_len;
132
133 EVP_DecryptUpdate(ctx.get(), out_pos, &out_len, in, len);
134 out_pos += out_len;
135 if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) {
136 ALOGD("Failed to decrypt blob; ciphertext or tag is likely corrupted");
Pavel Grafovcef39472018-02-12 18:45:02 +0000137 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdene9830582017-04-18 10:47:57 -0600138 }
139 out_pos += out_len;
140 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
141 ALOGD("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
142 out_pos - out_tmp.get());
Pavel Grafovcef39472018-02-12 18:45:02 +0000143 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdene9830582017-04-18 10:47:57 -0600144 }
145
146 std::copy(out_tmp.get(), out_pos, out);
147
148 return ResponseCode::NO_ERROR;
149}
150
151} // namespace
152
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700153Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
154 BlobType type) {
155 memset(&mBlob, 0, sizeof(mBlob));
Shawn Willdene9830582017-04-18 10:47:57 -0600156 if (valueLength > kValueSize) {
157 valueLength = kValueSize;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700158 ALOGW("Provided blob length too large");
159 }
Shawn Willdene9830582017-04-18 10:47:57 -0600160 if (infoLength + valueLength > kValueSize) {
161 infoLength = kValueSize - valueLength;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700162 ALOGW("Provided info length too large");
163 }
164 mBlob.length = valueLength;
165 memcpy(mBlob.value, value, valueLength);
166
167 mBlob.info = infoLength;
168 memcpy(mBlob.value + valueLength, info, infoLength);
169
170 mBlob.version = CURRENT_BLOB_VERSION;
171 mBlob.type = uint8_t(type);
172
173 if (type == TYPE_MASTER_KEY) {
174 mBlob.flags = KEYSTORE_FLAG_ENCRYPTED;
175 } else {
176 mBlob.flags = KEYSTORE_FLAG_NONE;
177 }
178}
179
Shawn Willdene9830582017-04-18 10:47:57 -0600180Blob::Blob(blobv3 b) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700181 mBlob = b;
182}
183
184Blob::Blob() {
185 memset(&mBlob, 0, sizeof(mBlob));
186}
187
188bool Blob::isEncrypted() const {
189 if (mBlob.version < 2) {
190 return true;
191 }
192
193 return mBlob.flags & KEYSTORE_FLAG_ENCRYPTED;
194}
195
Shawn Willdend5a24e62017-02-28 13:53:24 -0700196bool Blob::isSuperEncrypted() const {
197 return mBlob.flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
198}
199
Rubin Xu67899de2017-04-21 19:15:13 +0100200bool Blob::isCriticalToDeviceEncryption() const {
201 return mBlob.flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
202}
203
Shawn Willdend5a24e62017-02-28 13:53:24 -0700204inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
205 return set ? (flags | flag) : (flags & ~flag);
206}
207
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700208void Blob::setEncrypted(bool encrypted) {
Shawn Willdend5a24e62017-02-28 13:53:24 -0700209 mBlob.flags = setFlag(mBlob.flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
210}
211
Rubin Xu67899de2017-04-21 19:15:13 +0100212void Blob::setSuperEncrypted(bool superEncrypted) {
213 mBlob.flags = setFlag(mBlob.flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
214}
Rubin Xu48477952017-04-19 14:16:57 +0100215
Rubin Xu67899de2017-04-21 19:15:13 +0100216void Blob::setCriticalToDeviceEncryption(bool critical) {
217 mBlob.flags = setFlag(mBlob.flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700218}
219
220void Blob::setFallback(bool fallback) {
221 if (fallback) {
222 mBlob.flags |= KEYSTORE_FLAG_FALLBACK;
223 } else {
224 mBlob.flags &= ~KEYSTORE_FLAG_FALLBACK;
225 }
226}
227
Branden Archera7a29fa2019-01-10 09:24:14 -0800228ResponseCode Blob::writeBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
229 State state) {
Shawn Willdene9830582017-04-18 10:47:57 -0600230 ALOGV("writing blob %s", filename.c_str());
231
232 const size_t dataLength = mBlob.length;
233 mBlob.length = htonl(mBlob.length);
234
Shawn Willdend5a24e62017-02-28 13:53:24 -0700235 if (isEncrypted() || isSuperEncrypted()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700236 if (state != STATE_NO_ERROR) {
237 ALOGD("couldn't insert encrypted blob while not unlocked");
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100238 return ResponseCode::LOCKED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700239 }
240
Shawn Willdene9830582017-04-18 10:47:57 -0600241 memset(mBlob.initialization_vector, 0, AES_BLOCK_SIZE);
Branden Archere489a032018-12-28 09:10:49 -0800242 if (!RAND_bytes(mBlob.initialization_vector, kGcmIvSizeBytes)) {
Shawn Willdene9830582017-04-18 10:47:57 -0600243 ALOGW("Could not read random data for: %s", filename.c_str());
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100244 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700245 }
Shawn Willdene9830582017-04-18 10:47:57 -0600246
247 auto rc = AES_gcm_encrypt(mBlob.value /* in */, mBlob.value /* out */, dataLength, aes_key,
248 mBlob.initialization_vector, mBlob.aead_tag);
249 if (rc != ResponseCode::NO_ERROR) return rc;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700250 }
251
Shawn Willdene9830582017-04-18 10:47:57 -0600252 size_t fileLength = offsetof(blobv3, value) + dataLength + mBlob.info;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700253
254 const char* tmpFileName = ".tmp";
255 int out =
256 TEMP_FAILURE_RETRY(open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
257 if (out < 0) {
258 ALOGW("could not open file: %s: %s", tmpFileName, strerror(errno));
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100259 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700260 }
Shawn Willdene9830582017-04-18 10:47:57 -0600261
262 const size_t writtenBytes = writeFully(out, (uint8_t*)&mBlob, fileLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700263 if (close(out) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100264 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700265 }
266 if (writtenBytes != fileLength) {
267 ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength);
268 unlink(tmpFileName);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100269 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700270 }
Shawn Willdene9830582017-04-18 10:47:57 -0600271 if (rename(tmpFileName, filename.c_str()) == -1) {
272 ALOGW("could not rename blob to %s: %s", filename.c_str(), strerror(errno));
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100273 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700274 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100275 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700276}
277
Branden Archera7a29fa2019-01-10 09:24:14 -0800278ResponseCode Blob::readBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
279 State state) {
Shawn Willdene9830582017-04-18 10:47:57 -0600280 ALOGV("reading blob %s", filename.c_str());
281 const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700282 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100283 return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700284 }
Shawn Willdene9830582017-04-18 10:47:57 -0600285
286 // fileLength may be less than sizeof(mBlob)
287 const size_t fileLength = readFully(in, (uint8_t*)&mBlob, sizeof(mBlob));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700288 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100289 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700290 }
291
292 if (fileLength == 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100293 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700294 }
295
Janis Danisevskis36316d62017-09-01 14:31:36 -0700296 if ((isEncrypted() || isSuperEncrypted())) {
297 if (state == STATE_LOCKED) return ResponseCode::LOCKED;
298 if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700299 }
300
Shawn Willdene9830582017-04-18 10:47:57 -0600301 if (fileLength < offsetof(blobv3, value)) return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700302
Shawn Willdene9830582017-04-18 10:47:57 -0600303 if (mBlob.version == 3) {
304 const ssize_t encryptedLength = ntohl(mBlob.length);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700305
Shawn Willdene9830582017-04-18 10:47:57 -0600306 if (isEncrypted() || isSuperEncrypted()) {
307 auto rc = AES_gcm_decrypt(mBlob.value /* in */, mBlob.value /* out */, encryptedLength,
308 aes_key, mBlob.initialization_vector, mBlob.aead_tag);
309 if (rc != ResponseCode::NO_ERROR) return rc;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700310 }
Shawn Willdene9830582017-04-18 10:47:57 -0600311 } else if (mBlob.version < 3) {
312 blobv2& blob = reinterpret_cast<blobv2&>(mBlob);
313 const size_t headerLength = offsetof(blobv2, encrypted);
314 const ssize_t encryptedLength = fileLength - headerLength - blob.info;
315 if (encryptedLength < 0) return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700316
Shawn Willdene9830582017-04-18 10:47:57 -0600317 if (isEncrypted() || isSuperEncrypted()) {
318 if (encryptedLength % AES_BLOCK_SIZE != 0) {
319 return ResponseCode::VALUE_CORRUPTED;
320 }
321
322 AES_KEY key;
Branden Archera7a29fa2019-01-10 09:24:14 -0800323 AES_set_decrypt_key(aes_key.data(), kAesKeySize * 8, &key);
Shawn Willdene9830582017-04-18 10:47:57 -0600324 AES_cbc_encrypt(blob.encrypted, blob.encrypted, encryptedLength, &key, blob.vector,
325 AES_DECRYPT);
326 key = {}; // clear key
327
328 uint8_t computedDigest[MD5_DIGEST_LENGTH];
329 ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
330 MD5(blob.digested, digestedLength, computedDigest);
331 if (memcmp(blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
332 return ResponseCode::VALUE_CORRUPTED;
333 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700334 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700335 }
336
Shawn Willdene9830582017-04-18 10:47:57 -0600337 const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - mBlob.info;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700338 mBlob.length = ntohl(mBlob.length);
Shawn Willdene9830582017-04-18 10:47:57 -0600339 if (mBlob.length < 0 || mBlob.length > maxValueLength ||
340 mBlob.length + mBlob.info + AES_BLOCK_SIZE > static_cast<ssize_t>(sizeof(mBlob.value))) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100341 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700342 }
Shawn Willdene9830582017-04-18 10:47:57 -0600343
344 if (mBlob.info != 0 && mBlob.version < 3) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700345 // move info from after padding to after data
Shawn Willdene9830582017-04-18 10:47:57 -0600346 memmove(mBlob.value + mBlob.length, mBlob.value + maxValueLength, mBlob.info);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700347 }
Shawn Willdene9830582017-04-18 10:47:57 -0600348
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100349 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700350}
Janis Danisevskisc1460142017-12-18 16:48:46 -0800351
352keystore::SecurityLevel Blob::getSecurityLevel() const {
353 return keystore::flagsToSecurityLevel(mBlob.flags);
354}
355
356void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) {
357 mBlob.flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
358 mBlob.flags |= keystore::securityLevelToFlags(secLevel);
359}