blob: d1629cb744ca616f41f8ebf42dcb0c0a021e8f04 [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>
22#include <string.h>
23
Logan Chiencdc813f2018-04-23 13:52:28 +080024#include <log/log.h>
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070025
26#include "blob.h"
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070027
28#include "keystore_utils.h"
29
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070030#include <openssl/evp.h>
Branden Archer44d1afa2018-12-28 09:10:49 -080031#include <openssl/rand.h>
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070032
33#include <istream>
34#include <ostream>
35#include <streambuf>
36#include <string>
37
38#include <android-base/logging.h>
39
Shawn Willdene9830582017-04-18 10:47:57 -060040namespace {
41
42constexpr size_t kGcmIvSizeBytes = 96 / 8;
43
44template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter {
45 void operator()(T* p) { FreeFunc(p); }
46};
47
48#define DEFINE_OPENSSL_OBJECT_POINTER(name) \
49 typedef OpenSslObjectDeleter<name, name##_free> name##_Delete; \
50 typedef std::unique_ptr<name, name##_Delete> name##_Ptr;
51
52DEFINE_OPENSSL_OBJECT_POINTER(EVP_CIPHER_CTX);
53
Shawn Willden0ed642c2017-05-26 10:13:28 -060054#if defined(__clang__)
Shawn Willdene9830582017-04-18 10:47:57 -060055#define OPTNONE __attribute__((optnone))
Shawn Willden0ed642c2017-05-26 10:13:28 -060056#elif defined(__GNUC__)
Shawn Willdene9830582017-04-18 10:47:57 -060057#define OPTNONE __attribute__((optimize("O0")))
Shawn Willden0ed642c2017-05-26 10:13:28 -060058#else
59#error Need a definition for OPTNONE
60#endif
Shawn Willdene9830582017-04-18 10:47:57 -060061
62class ArrayEraser {
63 public:
64 ArrayEraser(uint8_t* arr, size_t size) : mArr(arr), mSize(size) {}
65 OPTNONE ~ArrayEraser() { std::fill(mArr, mArr + mSize, 0); }
66
67 private:
Shawn Willden0ed642c2017-05-26 10:13:28 -060068 volatile uint8_t* mArr;
Shawn Willdene9830582017-04-18 10:47:57 -060069 size_t mSize;
70};
71
Branden Archerd0315732019-01-10 14:56:05 -080072/**
73 * Returns a EVP_CIPHER appropriate for the given key, based on the key's size.
74 */
75const EVP_CIPHER* getAesCipherForKey(const std::vector<uint8_t>& key) {
76 const EVP_CIPHER* cipher = EVP_aes_256_gcm();
77 if (key.size() == kAes128KeySizeBytes) {
78 cipher = EVP_aes_128_gcm();
79 }
80 return cipher;
81}
82
Shawn Willdene9830582017-04-18 10:47:57 -060083/*
Branden Archerd0315732019-01-10 14:56:05 -080084 * Encrypt 'len' data at 'in' with AES-GCM, using 128-bit or 256-bit key at 'key', 96-bit IV at
85 * 'iv' and write output to 'out' (which may be the same location as 'in') and 128-bit tag to
86 * 'tag'.
Shawn Willdene9830582017-04-18 10:47:57 -060087 */
Branden Archerf5953d72019-01-10 09:08:18 -080088ResponseCode AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len,
89 const std::vector<uint8_t>& key, const uint8_t* iv, uint8_t* tag) {
Branden Archerd0315732019-01-10 14:56:05 -080090
91 // There can be 128-bit and 256-bit keys
92 const EVP_CIPHER* cipher = getAesCipherForKey(key);
93
Shawn Willdene9830582017-04-18 10:47:57 -060094 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
95
Branden Archerf5953d72019-01-10 09:08:18 -080096 EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
Shawn Willdene9830582017-04-18 10:47:57 -060097 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
98
99 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
100 uint8_t* out_pos = out_tmp.get();
101 int out_len;
102
103 EVP_EncryptUpdate(ctx.get(), out_pos, &out_len, in, len);
104 out_pos += out_len;
105 EVP_EncryptFinal_ex(ctx.get(), out_pos, &out_len);
106 out_pos += out_len;
107 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
108 ALOGD("Encrypted ciphertext is the wrong size, expected %zu, got %zd", len,
109 out_pos - out_tmp.get());
110 return ResponseCode::SYSTEM_ERROR;
111 }
112
113 std::copy(out_tmp.get(), out_pos, out);
114 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kGcmTagLength, tag);
115
116 return ResponseCode::NO_ERROR;
117}
118
119/*
Branden Archerd0315732019-01-10 14:56:05 -0800120 * Decrypt 'len' data at 'in' with AES-GCM, using 128-bit or 256-bit key at 'key', 96-bit IV at
121 * 'iv', checking 128-bit tag at 'tag' and writing plaintext to 'out'(which may be the same
122 * location as 'in').
Shawn Willdene9830582017-04-18 10:47:57 -0600123 */
Branden Archerf5953d72019-01-10 09:08:18 -0800124ResponseCode AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len,
125 const std::vector<uint8_t> key, const uint8_t* iv,
126 const uint8_t* tag) {
Branden Archerd0315732019-01-10 14:56:05 -0800127
128 // There can be 128-bit and 256-bit keys
129 const EVP_CIPHER* cipher = getAesCipherForKey(key);
130
Shawn Willdene9830582017-04-18 10:47:57 -0600131 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
132
Branden Archerf5953d72019-01-10 09:08:18 -0800133 EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
Shawn Willdene9830582017-04-18 10:47:57 -0600134 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
135 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kGcmTagLength, const_cast<uint8_t*>(tag));
136
137 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
138 ArrayEraser out_eraser(out_tmp.get(), len);
139 uint8_t* out_pos = out_tmp.get();
140 int out_len;
141
142 EVP_DecryptUpdate(ctx.get(), out_pos, &out_len, in, len);
143 out_pos += out_len;
144 if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700145 ALOGE("Failed to decrypt blob; ciphertext or tag is likely corrupted");
Pavel Grafovcef39472018-02-12 18:45:02 +0000146 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdene9830582017-04-18 10:47:57 -0600147 }
148 out_pos += out_len;
149 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700150 ALOGE("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
Shawn Willdene9830582017-04-18 10:47:57 -0600151 out_pos - out_tmp.get());
Pavel Grafovcef39472018-02-12 18:45:02 +0000152 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdene9830582017-04-18 10:47:57 -0600153 }
154
155 std::copy(out_tmp.get(), out_pos, out);
156
157 return ResponseCode::NO_ERROR;
158}
159
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700160class ArrayStreamBuffer : public std::streambuf {
161 public:
Chih-Hung Hsieh4fa39ef2019-01-04 13:34:17 -0800162 template <typename T, size_t size> explicit ArrayStreamBuffer(const T (&data)[size]) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700163 static_assert(sizeof(T) == 1, "Array element size too large");
164 std::streambuf::char_type* d = const_cast<std::streambuf::char_type*>(
165 reinterpret_cast<const std::streambuf::char_type*>(&data[0]));
166 setg(d, d, d + size);
167 setp(d, d + size);
168 }
169
170 protected:
171 pos_type seekoff(off_type off, std::ios_base::seekdir dir,
172 std::ios_base::openmode which = std::ios_base::in |
173 std::ios_base::out) override {
174 bool in = which & std::ios_base::in;
175 bool out = which & std::ios_base::out;
176 if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1;
177 std::streambuf::char_type* newPosPtr;
178 switch (dir) {
179 case std::ios_base::beg:
180 newPosPtr = pbase();
181 break;
182 case std::ios_base::cur:
183 // if dir == cur then in xor out due to
184 // if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1; above
185 if (in)
186 newPosPtr = gptr();
187 else
188 newPosPtr = pptr();
189 break;
190 case std::ios_base::end:
191 // in and out bounds are the same and cannot change, so we can take either range
192 // regardless of the value of "which"
193 newPosPtr = epptr();
194 break;
195 }
196 newPosPtr += off;
197 if (newPosPtr < pbase() || newPosPtr > epptr()) return -1;
198 if (in) {
199 gbump(newPosPtr - gptr());
200 }
201 if (out) {
202 pbump(newPosPtr - pptr());
203 }
204 return newPosPtr - pbase();
205 }
206};
207
Shawn Willdene9830582017-04-18 10:47:57 -0600208} // namespace
209
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700210Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
211 BlobType type) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700212 mBlob = std::make_unique<blobv3>();
213 memset(mBlob.get(), 0, sizeof(blobv3));
Shawn Willdene9830582017-04-18 10:47:57 -0600214 if (valueLength > kValueSize) {
215 valueLength = kValueSize;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700216 ALOGW("Provided blob length too large");
217 }
Shawn Willdene9830582017-04-18 10:47:57 -0600218 if (infoLength + valueLength > kValueSize) {
219 infoLength = kValueSize - valueLength;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700220 ALOGW("Provided info length too large");
221 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700222 mBlob->length = valueLength;
223 memcpy(mBlob->value, value, valueLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700224
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700225 mBlob->info = infoLength;
226 memcpy(mBlob->value + valueLength, info, infoLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700227
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700228 mBlob->version = CURRENT_BLOB_VERSION;
229 mBlob->type = uint8_t(type);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700230
231 if (type == TYPE_MASTER_KEY) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700232 mBlob->flags = KEYSTORE_FLAG_ENCRYPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700233 } else {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700234 mBlob->flags = KEYSTORE_FLAG_NONE;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700235 }
236}
237
Shawn Willdene9830582017-04-18 10:47:57 -0600238Blob::Blob(blobv3 b) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700239 mBlob = std::make_unique<blobv3>(b);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700240}
241
242Blob::Blob() {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700243 if (mBlob) *mBlob = {};
244}
245
246Blob::Blob(const Blob& rhs) {
247 if (rhs.mBlob) {
248 mBlob = std::make_unique<blobv3>(*rhs.mBlob);
249 }
250}
251
252Blob::Blob(Blob&& rhs) : mBlob(std::move(rhs.mBlob)) {}
253
254Blob& Blob::operator=(const Blob& rhs) {
255 if (&rhs != this) {
256 if (mBlob) *mBlob = {};
257 if (rhs) {
258 mBlob = std::make_unique<blobv3>(*rhs.mBlob);
259 } else {
260 mBlob = {};
261 }
262 }
263 return *this;
264}
265
266Blob& Blob::operator=(Blob&& rhs) {
267 if (mBlob) *mBlob = {};
268 mBlob = std::move(rhs.mBlob);
269 return *this;
270}
271
272template <typename BlobType> static bool rawBlobIsEncrypted(const BlobType& blob) {
273 if (blob.version < 2) return true;
274
275 return blob.flags & (KEYSTORE_FLAG_ENCRYPTED | KEYSTORE_FLAG_SUPER_ENCRYPTED);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700276}
277
278bool Blob::isEncrypted() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700279 if (mBlob->version < 2) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700280 return true;
281 }
282
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700283 return mBlob->flags & KEYSTORE_FLAG_ENCRYPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700284}
285
Shawn Willdend5a24e62017-02-28 13:53:24 -0700286bool Blob::isSuperEncrypted() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700287 return mBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
Shawn Willdend5a24e62017-02-28 13:53:24 -0700288}
289
Rubin Xu67899de2017-04-21 19:15:13 +0100290bool Blob::isCriticalToDeviceEncryption() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700291 return mBlob->flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
Rubin Xu67899de2017-04-21 19:15:13 +0100292}
293
Shawn Willdend5a24e62017-02-28 13:53:24 -0700294inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
295 return set ? (flags | flag) : (flags & ~flag);
296}
297
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700298void Blob::setEncrypted(bool encrypted) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700299 mBlob->flags = setFlag(mBlob->flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
Shawn Willdend5a24e62017-02-28 13:53:24 -0700300}
301
Rubin Xu67899de2017-04-21 19:15:13 +0100302void Blob::setSuperEncrypted(bool superEncrypted) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700303 mBlob->flags = setFlag(mBlob->flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
Rubin Xu67899de2017-04-21 19:15:13 +0100304}
Rubin Xu48477952017-04-19 14:16:57 +0100305
Rubin Xu67899de2017-04-21 19:15:13 +0100306void Blob::setCriticalToDeviceEncryption(bool critical) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700307 mBlob->flags = setFlag(mBlob->flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700308}
309
310void Blob::setFallback(bool fallback) {
311 if (fallback) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700312 mBlob->flags |= KEYSTORE_FLAG_FALLBACK;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700313 } else {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700314 mBlob->flags &= ~KEYSTORE_FLAG_FALLBACK;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700315 }
316}
317
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700318static ResponseCode writeBlob(const std::string& filename, Blob blob, blobv3* rawBlob,
Branden Archerf5953d72019-01-10 09:08:18 -0800319 const std::vector<uint8_t>& aes_key, State state) {
Shawn Willdene9830582017-04-18 10:47:57 -0600320 ALOGV("writing blob %s", filename.c_str());
321
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700322 const size_t dataLength = rawBlob->length;
323 rawBlob->length = htonl(rawBlob->length);
Shawn Willdene9830582017-04-18 10:47:57 -0600324
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700325 if (blob.isEncrypted() || blob.isSuperEncrypted()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700326 if (state != STATE_NO_ERROR) {
327 ALOGD("couldn't insert encrypted blob while not unlocked");
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100328 return ResponseCode::LOCKED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700329 }
330
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700331 memset(rawBlob->initialization_vector, 0, AES_BLOCK_SIZE);
Branden Archer44d1afa2018-12-28 09:10:49 -0800332 if (!RAND_bytes(rawBlob->initialization_vector, kGcmIvSizeBytes)) {
Shawn Willdene9830582017-04-18 10:47:57 -0600333 ALOGW("Could not read random data for: %s", filename.c_str());
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100334 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700335 }
Shawn Willdene9830582017-04-18 10:47:57 -0600336
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700337 auto rc = AES_gcm_encrypt(rawBlob->value /* in */, rawBlob->value /* out */, dataLength,
338 aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
Shawn Willdene9830582017-04-18 10:47:57 -0600339 if (rc != ResponseCode::NO_ERROR) return rc;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700340 }
341
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700342 size_t fileLength = offsetof(blobv3, value) + dataLength + rawBlob->info;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700343
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700344 int out =
345 TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700346 if (out < 0) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700347 ALOGW("could not open file: %s: %s", filename.c_str(), strerror(errno));
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100348 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700349 }
Shawn Willdene9830582017-04-18 10:47:57 -0600350
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700351 const size_t writtenBytes = writeFully(out, reinterpret_cast<uint8_t*>(rawBlob), fileLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700352 if (close(out) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100353 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700354 }
355 if (writtenBytes != fileLength) {
356 ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700357 unlink(filename.c_str());
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100358 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700359 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100360 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700361}
362
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700363ResponseCode LockedKeyBlobEntry::writeBlobs(Blob keyBlob, Blob characteristicsBlob,
Branden Archerf5953d72019-01-10 09:08:18 -0800364 const std::vector<uint8_t>& aes_key,
365 State state) const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700366 if (entry_ == nullptr) {
367 return ResponseCode::SYSTEM_ERROR;
368 }
369 ResponseCode rc;
370 if (keyBlob) {
371 blobv3* rawBlob = keyBlob.mBlob.get();
Branden Archer44d1afa2018-12-28 09:10:49 -0800372 rc = writeBlob(entry_->getKeyBlobPath(), std::move(keyBlob), rawBlob, aes_key, state);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700373 if (rc != ResponseCode::NO_ERROR) {
374 return rc;
375 }
376 }
377
378 if (characteristicsBlob) {
379 blobv3* rawBlob = characteristicsBlob.mBlob.get();
380 rc = writeBlob(entry_->getCharacteristicsBlobPath(), std::move(characteristicsBlob),
Branden Archer44d1afa2018-12-28 09:10:49 -0800381 rawBlob, aes_key, state);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700382 }
383 return rc;
384}
385
Branden Archerf5953d72019-01-10 09:08:18 -0800386ResponseCode Blob::readBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
387 State state) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700388 ResponseCode rc;
Shawn Willdene9830582017-04-18 10:47:57 -0600389 ALOGV("reading blob %s", filename.c_str());
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700390 std::unique_ptr<blobv3> rawBlob = std::make_unique<blobv3>();
391
Shawn Willdene9830582017-04-18 10:47:57 -0600392 const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700393 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100394 return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700395 }
Shawn Willdene9830582017-04-18 10:47:57 -0600396
397 // fileLength may be less than sizeof(mBlob)
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700398 const size_t fileLength = readFully(in, (uint8_t*)rawBlob.get(), sizeof(blobv3));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700399 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100400 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700401 }
402
403 if (fileLength == 0) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700404 LOG(ERROR) << __func__ << " VALUE_CORRUPTED file length == 0";
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100405 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700406 }
407
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700408 if (rawBlobIsEncrypted(*rawBlob)) {
409 if (state == STATE_LOCKED) {
410 mBlob = std::move(rawBlob);
411 return ResponseCode::LOCKED;
412 }
Janis Danisevskis36316d62017-09-01 14:31:36 -0700413 if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700414 }
415
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700416 if (fileLength < offsetof(blobv3, value)) {
417 LOG(ERROR) << __func__ << " VALUE_CORRUPTED blob file too short: " << fileLength;
418 return ResponseCode::VALUE_CORRUPTED;
419 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700420
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700421 if (rawBlob->version == 3) {
422 const ssize_t encryptedLength = ntohl(rawBlob->length);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700423
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700424 if (rawBlobIsEncrypted(*rawBlob)) {
425 rc = AES_gcm_decrypt(rawBlob->value /* in */, rawBlob->value /* out */, encryptedLength,
426 aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
Max Bires66694212018-11-02 10:45:12 -0700427 if (rc != ResponseCode::NO_ERROR) {
428 // If the blob was superencrypted and decryption failed, it is
429 // almost certain that decryption is failing due to a user's
430 // changed master key.
431 if ((rawBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED) &&
432 (rc == ResponseCode::VALUE_CORRUPTED)) {
433 return ResponseCode::KEY_PERMANENTLY_INVALIDATED;
434 }
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700435 LOG(ERROR) << __func__ << " AES_gcm_decrypt returned: " << uint32_t(rc);
436
Max Bires66694212018-11-02 10:45:12 -0700437 return rc;
438 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700439 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700440 } else if (rawBlob->version < 3) {
441 blobv2& v2blob = reinterpret_cast<blobv2&>(*rawBlob);
Shawn Willdene9830582017-04-18 10:47:57 -0600442 const size_t headerLength = offsetof(blobv2, encrypted);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700443 const ssize_t encryptedLength = fileLength - headerLength - v2blob.info;
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700444 if (encryptedLength < 0) {
445 LOG(ERROR) << __func__ << " VALUE_CORRUPTED v2blob file too short";
446 return ResponseCode::VALUE_CORRUPTED;
447 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700448
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700449 if (rawBlobIsEncrypted(*rawBlob)) {
Shawn Willdene9830582017-04-18 10:47:57 -0600450 if (encryptedLength % AES_BLOCK_SIZE != 0) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700451 LOG(ERROR) << __func__
452 << " VALUE_CORRUPTED encrypted length is not a multiple"
453 " of the AES block size";
Shawn Willdene9830582017-04-18 10:47:57 -0600454 return ResponseCode::VALUE_CORRUPTED;
455 }
456
457 AES_KEY key;
Branden Archerf5953d72019-01-10 09:08:18 -0800458 AES_set_decrypt_key(aes_key.data(), kAesKeySize * 8, &key);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700459 AES_cbc_encrypt(v2blob.encrypted, v2blob.encrypted, encryptedLength, &key,
460 v2blob.vector, AES_DECRYPT);
Shawn Willdene9830582017-04-18 10:47:57 -0600461 key = {}; // clear key
462
463 uint8_t computedDigest[MD5_DIGEST_LENGTH];
464 ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700465 MD5(v2blob.digested, digestedLength, computedDigest);
466 if (memcmp(v2blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700467 LOG(ERROR) << __func__ << " v2blob MD5 digest mismatch";
Shawn Willdene9830582017-04-18 10:47:57 -0600468 return ResponseCode::VALUE_CORRUPTED;
469 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700470 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700471 }
472
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700473 const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - rawBlob->info;
474 rawBlob->length = ntohl(rawBlob->length);
475 if (rawBlob->length < 0 || rawBlob->length > maxValueLength ||
476 rawBlob->length + rawBlob->info + AES_BLOCK_SIZE >
477 static_cast<ssize_t>(sizeof(rawBlob->value))) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700478 LOG(ERROR) << __func__ << " raw blob length is out of bounds";
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100479 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700480 }
Shawn Willdene9830582017-04-18 10:47:57 -0600481
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700482 if (rawBlob->info != 0 && rawBlob->version < 3) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700483 // move info from after padding to after data
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700484 memmove(rawBlob->value + rawBlob->length, rawBlob->value + maxValueLength, rawBlob->info);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700485 }
Shawn Willdene9830582017-04-18 10:47:57 -0600486
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700487 mBlob = std::move(rawBlob);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100488 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700489}
Janis Danisevskisc1460142017-12-18 16:48:46 -0800490
Branden Archerf5953d72019-01-10 09:08:18 -0800491std::tuple<ResponseCode, Blob, Blob>
492LockedKeyBlobEntry::readBlobs(const std::vector<uint8_t>& aes_key, State state) const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700493 std::tuple<ResponseCode, Blob, Blob> result;
494 auto& [rc, keyBlob, characteristicsBlob] = result;
495 if (entry_ == nullptr) return rc = ResponseCode::SYSTEM_ERROR, result;
496
497 rc = keyBlob.readBlob(entry_->getKeyBlobPath(), aes_key, state);
498 if (rc != ResponseCode::NO_ERROR && rc != ResponseCode::UNINITIALIZED) {
499 return result;
500 }
501
502 if (entry_->hasCharacteristicsBlob()) {
503 characteristicsBlob.readBlob(entry_->getCharacteristicsBlobPath(), aes_key, state);
504 }
505 return result;
506}
507
508ResponseCode LockedKeyBlobEntry::deleteBlobs() const {
509 if (entry_ == nullptr) return ResponseCode::NO_ERROR;
510
511 // always try to delete both
512 ResponseCode rc1 = (unlink(entry_->getKeyBlobPath().c_str()) && errno != ENOENT)
513 ? ResponseCode::SYSTEM_ERROR
514 : ResponseCode::NO_ERROR;
515 if (rc1 != ResponseCode::NO_ERROR) {
516 ALOGW("Failed to delete key blob file \"%s\"", entry_->getKeyBlobPath().c_str());
517 }
518 ResponseCode rc2 = (unlink(entry_->getCharacteristicsBlobPath().c_str()) && errno != ENOENT)
519 ? ResponseCode::SYSTEM_ERROR
520 : ResponseCode::NO_ERROR;
521 if (rc2 != ResponseCode::NO_ERROR) {
522 ALOGW("Failed to delete key characteristics file \"%s\"",
523 entry_->getCharacteristicsBlobPath().c_str());
524 }
525 // then report the first error that occured
526 if (rc1 != ResponseCode::NO_ERROR) return rc1;
527 return rc2;
528}
529
Janis Danisevskisc1460142017-12-18 16:48:46 -0800530keystore::SecurityLevel Blob::getSecurityLevel() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700531 return keystore::flagsToSecurityLevel(mBlob->flags);
Janis Danisevskisc1460142017-12-18 16:48:46 -0800532}
533
534void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700535 mBlob->flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
536 mBlob->flags |= keystore::securityLevelToFlags(secLevel);
537}
538
539std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet>
540Blob::getKeyCharacteristics() const {
541 std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet> result;
542 auto& [success, hwEnforced, swEnforced] = result;
543 success = false;
544 ArrayStreamBuffer buf(mBlob->value);
545 std::istream in(&buf);
546
547 // only the characteristics cache has both sets
548 if (getType() == TYPE_KEY_CHARACTERISTICS_CACHE) {
549 hwEnforced.Deserialize(&in);
550 } else if (getType() != TYPE_KEY_CHARACTERISTICS) {
551 // if its not the cache and not the legacy characteristics file we have no business
552 // here
553 return result;
554 }
555 swEnforced.Deserialize(&in);
556 success = !in.bad();
557
558 return result;
559}
560bool Blob::putKeyCharacteristics(const keystore::AuthorizationSet& hwEnforced,
561 const keystore::AuthorizationSet& swEnforced) {
562 if (!mBlob) mBlob = std::make_unique<blobv3>();
563 mBlob->version = CURRENT_BLOB_VERSION;
564 ArrayStreamBuffer buf(mBlob->value);
565 std::ostream out(&buf);
566 hwEnforced.Serialize(&out);
567 swEnforced.Serialize(&out);
568 if (out.bad()) return false;
569 setType(TYPE_KEY_CHARACTERISTICS_CACHE);
570 mBlob->length = out.tellp();
571 return true;
572}
573
574void LockedKeyBlobEntry::put(const KeyBlobEntry& entry) {
575 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
576 locked_blobs_.erase(entry);
577 lock.unlock();
578 locked_blobs_mutex_cond_var_.notify_all();
579}
580
581LockedKeyBlobEntry::~LockedKeyBlobEntry() {
582 if (entry_ != nullptr) put(*entry_);
583}
584
585LockedKeyBlobEntry LockedKeyBlobEntry::get(KeyBlobEntry entry) {
586 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
587 locked_blobs_mutex_cond_var_.wait(
588 lock, [&] { return locked_blobs_.find(entry) == locked_blobs_.end(); });
589 auto [iterator, success] = locked_blobs_.insert(std::move(entry));
590 if (!success) return {};
591 return LockedKeyBlobEntry(*iterator);
592}
593
594std::set<KeyBlobEntry> LockedKeyBlobEntry::locked_blobs_;
595std::mutex LockedKeyBlobEntry::locked_blobs_mutex_;
596std::condition_variable LockedKeyBlobEntry::locked_blobs_mutex_cond_var_;
597
598/* Here is the encoding of key names. This is necessary in order to allow arbitrary
599 * characters in key names. Characters in [0-~] are not encoded. Others are encoded
600 * into two bytes. The first byte is one of [+-.] which represents the first
601 * two bits of the character. The second byte encodes the rest of the bits into
602 * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
603 * that Base64 cannot be used here due to the need of prefix match on keys. */
604
Eran Messeri2ba77c32018-12-04 12:22:16 +0000605std::string encodeKeyName(const std::string& keyName) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700606 std::string encodedName;
607 encodedName.reserve(keyName.size() * 2);
608 auto in = keyName.begin();
609 while (in != keyName.end()) {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000610 // Input character needs to be encoded.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700611 if (*in < '0' || *in > '~') {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000612 // Encode the two most-significant bits of the input char in the first
613 // output character, by counting up from 43 ('+').
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700614 encodedName.append(1, '+' + (uint8_t(*in) >> 6));
Eran Messeri2ba77c32018-12-04 12:22:16 +0000615 // Encode the six least-significant bits of the input char in the second
616 // output character, by counting up from 48 ('0').
617 // This is safe because the maximum value is 112, which is the
618 // character 'p'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700619 encodedName.append(1, '0' + (*in & 0x3F));
620 } else {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000621 // No need to encode input char - append as-is.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700622 encodedName.append(1, *in);
623 }
624 ++in;
625 }
626 return encodedName;
627}
628
Eran Messeri2ba77c32018-12-04 12:22:16 +0000629std::string decodeKeyName(const std::string& encodedName) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700630 std::string decodedName;
631 decodedName.reserve(encodedName.size());
632 auto in = encodedName.begin();
633 bool multichar = false;
634 char c;
635 while (in != encodedName.end()) {
636 if (multichar) {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000637 // Second part of a multi-character encoding. Turn off the multichar
638 // flag and set the six least-significant bits of c to the value originally
639 // encoded by counting up from '0'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700640 multichar = false;
Eran Messeri2ba77c32018-12-04 12:22:16 +0000641 decodedName.append(1, c | (uint8_t(*in) - '0'));
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700642 } else if (*in >= '+' && *in <= '.') {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000643 // First part of a multi-character encoding. Set the multichar flag
644 // and set the two most-significant bits of c to be the two bits originally
645 // encoded by counting up from '+'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700646 multichar = true;
647 c = (*in - '+') << 6;
648 } else {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000649 // Regular character, append as-is.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700650 decodedName.append(1, *in);
651 }
652 ++in;
653 }
654 // mulitchars at the end get truncated
655 return decodedName;
656}
657
658std::string KeyBlobEntry::getKeyBlobBaseName() const {
659 std::stringstream s;
660 if (masterkey_) {
661 s << alias_;
662 } else {
663 s << uid_ << "_" << encodeKeyName(alias_);
664 }
665 return s.str();
666}
667
668std::string KeyBlobEntry::getKeyBlobPath() const {
669 std::stringstream s;
670 if (masterkey_) {
671 s << user_dir_ << "/" << alias_;
672 } else {
673 s << user_dir_ << "/" << uid_ << "_" << encodeKeyName(alias_);
674 }
675 return s.str();
676}
677
678std::string KeyBlobEntry::getCharacteristicsBlobBaseName() const {
679 std::stringstream s;
680 if (!masterkey_) s << "." << uid_ << "_chr_" << encodeKeyName(alias_);
681 return s.str();
682}
683
684std::string KeyBlobEntry::getCharacteristicsBlobPath() const {
685 std::stringstream s;
686 if (!masterkey_)
687 s << user_dir_ << "/"
688 << "." << uid_ << "_chr_" << encodeKeyName(alias_);
689 return s.str();
690}
691
692bool KeyBlobEntry::hasKeyBlob() const {
693 return !access(getKeyBlobPath().c_str(), R_OK | W_OK);
694}
695bool KeyBlobEntry::hasCharacteristicsBlob() const {
696 return !access(getCharacteristicsBlobPath().c_str(), R_OK | W_OK);
697}
698
699static std::tuple<bool, uid_t, std::string> filename2UidAlias(const std::string& filepath) {
700 std::tuple<bool, uid_t, std::string> result;
701
702 auto& [success, uid, alias] = result;
703
704 success = false;
705
706 auto filenamebase = filepath.find_last_of('/');
707 std::string filename =
708 filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1);
709
710 if (filename[0] == '.') return result;
711
712 auto sep = filename.find('_');
713 if (sep == std::string::npos) return result;
714
715 std::stringstream s(filename.substr(0, sep));
716 s >> uid;
717 if (!s) return result;
718
719 alias = decodeKeyName(filename.substr(sep + 1));
720 success = true;
721 return result;
722}
723
724std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>>
725LockedKeyBlobEntry::list(const std::string& user_dir,
726 std::function<bool(uid_t, const std::string&)> filter) {
727 std::list<LockedKeyBlobEntry> matches;
728
729 // This is a fence against any concurrent database accesses during database iteration.
730 // Only the keystore thread can lock entries. So it cannot be starved
731 // by workers grabbing new individual locks. We just wait here until all
732 // workers have relinquished their locked files.
733 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
734 locked_blobs_mutex_cond_var_.wait(lock, [&] { return locked_blobs_.empty(); });
735
736 DIR* dir = opendir(user_dir.c_str());
737 if (!dir) {
738 ALOGW("can't open directory for user: %s", strerror(errno));
739 return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::SYSTEM_ERROR,
740 std::move(matches)};
741 }
742
743 struct dirent* file;
744 while ((file = readdir(dir)) != nullptr) {
745 // We only care about files.
746 if (file->d_type != DT_REG) {
747 continue;
748 }
749
750 // Skip anything that starts with a "."
751 if (file->d_name[0] == '.') {
752 continue;
753 }
754
755 auto [success, uid, alias] = filename2UidAlias(file->d_name);
756
757 if (!success) {
758 ALOGW("could not parse key filename \"%s\"", file->d_name);
759 continue;
760 }
761
762 if (!filter(uid, alias)) continue;
763
764 auto [iterator, dummy] = locked_blobs_.emplace(alias, user_dir, uid);
765 matches.push_back(*iterator);
766 }
767 closedir(dir);
768 return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::NO_ERROR,
769 std::move(matches)};
Janis Danisevskisc1460142017-12-18 16:48:46 -0800770}