blob: 0987139f4d3e660f47e8f4b5a4bac8a876207d92 [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>
Janis Danisevskis6a0d9982019-04-30 15:43:59 -070039#include <android-base/unique_fd.h>
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070040
Shawn Willdene9830582017-04-18 10:47:57 -060041namespace {
42
43constexpr size_t kGcmIvSizeBytes = 96 / 8;
44
45template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter {
46 void operator()(T* p) { FreeFunc(p); }
47};
48
49#define DEFINE_OPENSSL_OBJECT_POINTER(name) \
50 typedef OpenSslObjectDeleter<name, name##_free> name##_Delete; \
51 typedef std::unique_ptr<name, name##_Delete> name##_Ptr;
52
53DEFINE_OPENSSL_OBJECT_POINTER(EVP_CIPHER_CTX);
54
Shawn Willden0ed642c2017-05-26 10:13:28 -060055#if defined(__clang__)
Shawn Willdene9830582017-04-18 10:47:57 -060056#define OPTNONE __attribute__((optnone))
Shawn Willden0ed642c2017-05-26 10:13:28 -060057#elif defined(__GNUC__)
Shawn Willdene9830582017-04-18 10:47:57 -060058#define OPTNONE __attribute__((optimize("O0")))
Shawn Willden0ed642c2017-05-26 10:13:28 -060059#else
60#error Need a definition for OPTNONE
61#endif
Shawn Willdene9830582017-04-18 10:47:57 -060062
63class ArrayEraser {
64 public:
65 ArrayEraser(uint8_t* arr, size_t size) : mArr(arr), mSize(size) {}
66 OPTNONE ~ArrayEraser() { std::fill(mArr, mArr + mSize, 0); }
67
68 private:
Shawn Willden0ed642c2017-05-26 10:13:28 -060069 volatile uint8_t* mArr;
Shawn Willdene9830582017-04-18 10:47:57 -060070 size_t mSize;
71};
72
Branden Archerd0315732019-01-10 14:56:05 -080073/**
74 * Returns a EVP_CIPHER appropriate for the given key, based on the key's size.
75 */
76const EVP_CIPHER* getAesCipherForKey(const std::vector<uint8_t>& key) {
77 const EVP_CIPHER* cipher = EVP_aes_256_gcm();
78 if (key.size() == kAes128KeySizeBytes) {
79 cipher = EVP_aes_128_gcm();
80 }
81 return cipher;
82}
83
Shawn Willdene9830582017-04-18 10:47:57 -060084/*
Branden Archerd0315732019-01-10 14:56:05 -080085 * Encrypt 'len' data at 'in' with AES-GCM, using 128-bit or 256-bit key at 'key', 96-bit IV at
86 * 'iv' and write output to 'out' (which may be the same location as 'in') and 128-bit tag to
87 * 'tag'.
Shawn Willdene9830582017-04-18 10:47:57 -060088 */
Branden Archerf5953d72019-01-10 09:08:18 -080089ResponseCode AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len,
90 const std::vector<uint8_t>& key, const uint8_t* iv, uint8_t* tag) {
Branden Archerd0315732019-01-10 14:56:05 -080091
92 // There can be 128-bit and 256-bit keys
93 const EVP_CIPHER* cipher = getAesCipherForKey(key);
94
Shawn Willdene9830582017-04-18 10:47:57 -060095 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
96
Branden Archerf5953d72019-01-10 09:08:18 -080097 EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
Shawn Willdene9830582017-04-18 10:47:57 -060098 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
99
100 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
101 uint8_t* out_pos = out_tmp.get();
102 int out_len;
103
104 EVP_EncryptUpdate(ctx.get(), out_pos, &out_len, in, len);
105 out_pos += out_len;
106 EVP_EncryptFinal_ex(ctx.get(), out_pos, &out_len);
107 out_pos += out_len;
108 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
109 ALOGD("Encrypted ciphertext is the wrong size, expected %zu, got %zd", len,
110 out_pos - out_tmp.get());
111 return ResponseCode::SYSTEM_ERROR;
112 }
113
114 std::copy(out_tmp.get(), out_pos, out);
115 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kGcmTagLength, tag);
116
117 return ResponseCode::NO_ERROR;
118}
119
120/*
Branden Archerd0315732019-01-10 14:56:05 -0800121 * Decrypt 'len' data at 'in' with AES-GCM, using 128-bit or 256-bit key at 'key', 96-bit IV at
122 * 'iv', checking 128-bit tag at 'tag' and writing plaintext to 'out'(which may be the same
123 * location as 'in').
Shawn Willdene9830582017-04-18 10:47:57 -0600124 */
Branden Archerf5953d72019-01-10 09:08:18 -0800125ResponseCode AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len,
126 const std::vector<uint8_t> key, const uint8_t* iv,
127 const uint8_t* tag) {
Branden Archerd0315732019-01-10 14:56:05 -0800128
129 // There can be 128-bit and 256-bit keys
130 const EVP_CIPHER* cipher = getAesCipherForKey(key);
131
Shawn Willdene9830582017-04-18 10:47:57 -0600132 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
133
Branden Archerf5953d72019-01-10 09:08:18 -0800134 EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
Shawn Willdene9830582017-04-18 10:47:57 -0600135 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
136 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kGcmTagLength, const_cast<uint8_t*>(tag));
137
138 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
139 ArrayEraser out_eraser(out_tmp.get(), len);
140 uint8_t* out_pos = out_tmp.get();
141 int out_len;
142
143 EVP_DecryptUpdate(ctx.get(), out_pos, &out_len, in, len);
144 out_pos += out_len;
145 if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700146 ALOGE("Failed to decrypt blob; ciphertext or tag is likely corrupted");
Pavel Grafovcef39472018-02-12 18:45:02 +0000147 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdene9830582017-04-18 10:47:57 -0600148 }
149 out_pos += out_len;
150 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700151 ALOGE("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
Shawn Willdene9830582017-04-18 10:47:57 -0600152 out_pos - out_tmp.get());
Pavel Grafovcef39472018-02-12 18:45:02 +0000153 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdene9830582017-04-18 10:47:57 -0600154 }
155
156 std::copy(out_tmp.get(), out_pos, out);
157
158 return ResponseCode::NO_ERROR;
159}
160
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700161class ArrayStreamBuffer : public std::streambuf {
162 public:
Chih-Hung Hsieh4fa39ef2019-01-04 13:34:17 -0800163 template <typename T, size_t size> explicit ArrayStreamBuffer(const T (&data)[size]) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700164 static_assert(sizeof(T) == 1, "Array element size too large");
165 std::streambuf::char_type* d = const_cast<std::streambuf::char_type*>(
166 reinterpret_cast<const std::streambuf::char_type*>(&data[0]));
167 setg(d, d, d + size);
168 setp(d, d + size);
169 }
170
171 protected:
172 pos_type seekoff(off_type off, std::ios_base::seekdir dir,
173 std::ios_base::openmode which = std::ios_base::in |
174 std::ios_base::out) override {
175 bool in = which & std::ios_base::in;
176 bool out = which & std::ios_base::out;
177 if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1;
178 std::streambuf::char_type* newPosPtr;
179 switch (dir) {
180 case std::ios_base::beg:
181 newPosPtr = pbase();
182 break;
183 case std::ios_base::cur:
184 // if dir == cur then in xor out due to
185 // if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1; above
186 if (in)
187 newPosPtr = gptr();
188 else
189 newPosPtr = pptr();
190 break;
191 case std::ios_base::end:
192 // in and out bounds are the same and cannot change, so we can take either range
193 // regardless of the value of "which"
194 newPosPtr = epptr();
195 break;
196 }
197 newPosPtr += off;
198 if (newPosPtr < pbase() || newPosPtr > epptr()) return -1;
199 if (in) {
200 gbump(newPosPtr - gptr());
201 }
202 if (out) {
203 pbump(newPosPtr - pptr());
204 }
205 return newPosPtr - pbase();
206 }
207};
208
Shawn Willdene9830582017-04-18 10:47:57 -0600209} // namespace
210
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700211Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
212 BlobType type) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700213 mBlob = std::make_unique<blobv3>();
214 memset(mBlob.get(), 0, sizeof(blobv3));
Shawn Willdene9830582017-04-18 10:47:57 -0600215 if (valueLength > kValueSize) {
216 valueLength = kValueSize;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700217 ALOGW("Provided blob length too large");
218 }
Shawn Willdene9830582017-04-18 10:47:57 -0600219 if (infoLength + valueLength > kValueSize) {
220 infoLength = kValueSize - valueLength;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700221 ALOGW("Provided info length too large");
222 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700223 mBlob->length = valueLength;
224 memcpy(mBlob->value, value, valueLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700225
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700226 mBlob->info = infoLength;
227 memcpy(mBlob->value + valueLength, info, infoLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700228
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700229 mBlob->version = CURRENT_BLOB_VERSION;
230 mBlob->type = uint8_t(type);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700231
232 if (type == TYPE_MASTER_KEY) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700233 mBlob->flags = KEYSTORE_FLAG_ENCRYPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700234 } else {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700235 mBlob->flags = KEYSTORE_FLAG_NONE;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700236 }
237}
238
Shawn Willdene9830582017-04-18 10:47:57 -0600239Blob::Blob(blobv3 b) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700240 mBlob = std::make_unique<blobv3>(b);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700241}
242
243Blob::Blob() {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700244 if (mBlob) *mBlob = {};
245}
246
247Blob::Blob(const Blob& rhs) {
248 if (rhs.mBlob) {
249 mBlob = std::make_unique<blobv3>(*rhs.mBlob);
250 }
251}
252
253Blob::Blob(Blob&& rhs) : mBlob(std::move(rhs.mBlob)) {}
254
255Blob& Blob::operator=(const Blob& rhs) {
256 if (&rhs != this) {
257 if (mBlob) *mBlob = {};
258 if (rhs) {
259 mBlob = std::make_unique<blobv3>(*rhs.mBlob);
260 } else {
261 mBlob = {};
262 }
263 }
264 return *this;
265}
266
267Blob& Blob::operator=(Blob&& rhs) {
268 if (mBlob) *mBlob = {};
269 mBlob = std::move(rhs.mBlob);
270 return *this;
271}
272
273template <typename BlobType> static bool rawBlobIsEncrypted(const BlobType& blob) {
274 if (blob.version < 2) return true;
275
276 return blob.flags & (KEYSTORE_FLAG_ENCRYPTED | KEYSTORE_FLAG_SUPER_ENCRYPTED);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700277}
278
279bool Blob::isEncrypted() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700280 if (mBlob->version < 2) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700281 return true;
282 }
283
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700284 return mBlob->flags & KEYSTORE_FLAG_ENCRYPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700285}
286
Shawn Willdend5a24e62017-02-28 13:53:24 -0700287bool Blob::isSuperEncrypted() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700288 return mBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
Shawn Willdend5a24e62017-02-28 13:53:24 -0700289}
290
Rubin Xu67899de2017-04-21 19:15:13 +0100291bool Blob::isCriticalToDeviceEncryption() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700292 return mBlob->flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
Rubin Xu67899de2017-04-21 19:15:13 +0100293}
294
Shawn Willdend5a24e62017-02-28 13:53:24 -0700295inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
296 return set ? (flags | flag) : (flags & ~flag);
297}
298
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700299void Blob::setEncrypted(bool encrypted) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700300 mBlob->flags = setFlag(mBlob->flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
Shawn Willdend5a24e62017-02-28 13:53:24 -0700301}
302
Rubin Xu67899de2017-04-21 19:15:13 +0100303void Blob::setSuperEncrypted(bool superEncrypted) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700304 mBlob->flags = setFlag(mBlob->flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
Rubin Xu67899de2017-04-21 19:15:13 +0100305}
Rubin Xu48477952017-04-19 14:16:57 +0100306
Rubin Xu67899de2017-04-21 19:15:13 +0100307void Blob::setCriticalToDeviceEncryption(bool critical) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700308 mBlob->flags = setFlag(mBlob->flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700309}
310
311void Blob::setFallback(bool fallback) {
312 if (fallback) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700313 mBlob->flags |= KEYSTORE_FLAG_FALLBACK;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700314 } else {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700315 mBlob->flags &= ~KEYSTORE_FLAG_FALLBACK;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700316 }
317}
318
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700319static ResponseCode writeBlob(const std::string& filename, Blob blob, blobv3* rawBlob,
Branden Archerf5953d72019-01-10 09:08:18 -0800320 const std::vector<uint8_t>& aes_key, State state) {
Shawn Willdene9830582017-04-18 10:47:57 -0600321 ALOGV("writing blob %s", filename.c_str());
322
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700323 const size_t dataLength = rawBlob->length;
324 rawBlob->length = htonl(rawBlob->length);
Shawn Willdene9830582017-04-18 10:47:57 -0600325
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700326 if (blob.isEncrypted() || blob.isSuperEncrypted()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700327 if (state != STATE_NO_ERROR) {
328 ALOGD("couldn't insert encrypted blob while not unlocked");
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100329 return ResponseCode::LOCKED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700330 }
331
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700332 memset(rawBlob->initialization_vector, 0, AES_BLOCK_SIZE);
Branden Archer44d1afa2018-12-28 09:10:49 -0800333 if (!RAND_bytes(rawBlob->initialization_vector, kGcmIvSizeBytes)) {
Shawn Willdene9830582017-04-18 10:47:57 -0600334 ALOGW("Could not read random data for: %s", filename.c_str());
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100335 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700336 }
Shawn Willdene9830582017-04-18 10:47:57 -0600337
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700338 auto rc = AES_gcm_encrypt(rawBlob->value /* in */, rawBlob->value /* out */, dataLength,
339 aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
Shawn Willdene9830582017-04-18 10:47:57 -0600340 if (rc != ResponseCode::NO_ERROR) return rc;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700341 }
342
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700343 size_t fileLength = offsetof(blobv3, value) + dataLength + rawBlob->info;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700344
Janis Danisevskis6a0d9982019-04-30 15:43:59 -0700345 char tmpFileName[] = ".tmpXXXXXX";
346 {
347 android::base::unique_fd out(TEMP_FAILURE_RETRY(mkstemp(tmpFileName)));
348 if (out < 0) {
349 LOG(ERROR) << "could not open temp file: " << tmpFileName
350 << " for writing blob file: " << filename.c_str()
351 << " because: " << strerror(errno);
352 return ResponseCode::SYSTEM_ERROR;
353 }
354
355 const size_t writtenBytes =
356 writeFully(out, reinterpret_cast<uint8_t*>(rawBlob), fileLength);
357
358 if (writtenBytes != fileLength) {
359 LOG(ERROR) << "blob not fully written " << writtenBytes << " != " << fileLength;
360 unlink(tmpFileName);
361 return ResponseCode::SYSTEM_ERROR;
362 }
363 }
364
365 if (rename(tmpFileName, filename.c_str()) == -1) {
366 LOG(ERROR) << "could not rename blob file to " << filename
367 << " because: " << strerror(errno);
368 unlink(tmpFileName);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100369 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700370 }
Shawn Willdene9830582017-04-18 10:47:57 -0600371
Janis Danisevskis6a0d9982019-04-30 15:43:59 -0700372 fsyncDirectory(getContainingDirectory(filename));
373
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100374 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700375}
376
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700377ResponseCode LockedKeyBlobEntry::writeBlobs(Blob keyBlob, Blob characteristicsBlob,
Branden Archerf5953d72019-01-10 09:08:18 -0800378 const std::vector<uint8_t>& aes_key,
379 State state) const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700380 if (entry_ == nullptr) {
381 return ResponseCode::SYSTEM_ERROR;
382 }
383 ResponseCode rc;
384 if (keyBlob) {
385 blobv3* rawBlob = keyBlob.mBlob.get();
Branden Archer44d1afa2018-12-28 09:10:49 -0800386 rc = writeBlob(entry_->getKeyBlobPath(), std::move(keyBlob), rawBlob, aes_key, state);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700387 if (rc != ResponseCode::NO_ERROR) {
388 return rc;
389 }
390 }
391
392 if (characteristicsBlob) {
393 blobv3* rawBlob = characteristicsBlob.mBlob.get();
394 rc = writeBlob(entry_->getCharacteristicsBlobPath(), std::move(characteristicsBlob),
Branden Archer44d1afa2018-12-28 09:10:49 -0800395 rawBlob, aes_key, state);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700396 }
397 return rc;
398}
399
Branden Archerf5953d72019-01-10 09:08:18 -0800400ResponseCode Blob::readBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
401 State state) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700402 ResponseCode rc;
Shawn Willdene9830582017-04-18 10:47:57 -0600403 ALOGV("reading blob %s", filename.c_str());
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700404 std::unique_ptr<blobv3> rawBlob = std::make_unique<blobv3>();
405
Shawn Willdene9830582017-04-18 10:47:57 -0600406 const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700407 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100408 return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700409 }
Shawn Willdene9830582017-04-18 10:47:57 -0600410
411 // fileLength may be less than sizeof(mBlob)
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700412 const size_t fileLength = readFully(in, (uint8_t*)rawBlob.get(), sizeof(blobv3));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700413 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100414 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700415 }
416
417 if (fileLength == 0) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700418 LOG(ERROR) << __func__ << " VALUE_CORRUPTED file length == 0";
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100419 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700420 }
421
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700422 if (rawBlobIsEncrypted(*rawBlob)) {
423 if (state == STATE_LOCKED) {
424 mBlob = std::move(rawBlob);
425 return ResponseCode::LOCKED;
426 }
Janis Danisevskis36316d62017-09-01 14:31:36 -0700427 if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700428 }
429
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700430 if (fileLength < offsetof(blobv3, value)) {
431 LOG(ERROR) << __func__ << " VALUE_CORRUPTED blob file too short: " << fileLength;
432 return ResponseCode::VALUE_CORRUPTED;
433 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700434
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700435 if (rawBlob->version == 3) {
436 const ssize_t encryptedLength = ntohl(rawBlob->length);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700437
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700438 if (rawBlobIsEncrypted(*rawBlob)) {
439 rc = AES_gcm_decrypt(rawBlob->value /* in */, rawBlob->value /* out */, encryptedLength,
440 aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
Max Bires66694212018-11-02 10:45:12 -0700441 if (rc != ResponseCode::NO_ERROR) {
442 // If the blob was superencrypted and decryption failed, it is
443 // almost certain that decryption is failing due to a user's
444 // changed master key.
445 if ((rawBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED) &&
446 (rc == ResponseCode::VALUE_CORRUPTED)) {
447 return ResponseCode::KEY_PERMANENTLY_INVALIDATED;
448 }
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700449 LOG(ERROR) << __func__ << " AES_gcm_decrypt returned: " << uint32_t(rc);
450
Max Bires66694212018-11-02 10:45:12 -0700451 return rc;
452 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700453 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700454 } else if (rawBlob->version < 3) {
455 blobv2& v2blob = reinterpret_cast<blobv2&>(*rawBlob);
Shawn Willdene9830582017-04-18 10:47:57 -0600456 const size_t headerLength = offsetof(blobv2, encrypted);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700457 const ssize_t encryptedLength = fileLength - headerLength - v2blob.info;
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700458 if (encryptedLength < 0) {
459 LOG(ERROR) << __func__ << " VALUE_CORRUPTED v2blob file too short";
460 return ResponseCode::VALUE_CORRUPTED;
461 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700462
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700463 if (rawBlobIsEncrypted(*rawBlob)) {
Shawn Willdene9830582017-04-18 10:47:57 -0600464 if (encryptedLength % AES_BLOCK_SIZE != 0) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700465 LOG(ERROR) << __func__
466 << " VALUE_CORRUPTED encrypted length is not a multiple"
467 " of the AES block size";
Shawn Willdene9830582017-04-18 10:47:57 -0600468 return ResponseCode::VALUE_CORRUPTED;
469 }
470
471 AES_KEY key;
Branden Archerf5953d72019-01-10 09:08:18 -0800472 AES_set_decrypt_key(aes_key.data(), kAesKeySize * 8, &key);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700473 AES_cbc_encrypt(v2blob.encrypted, v2blob.encrypted, encryptedLength, &key,
474 v2blob.vector, AES_DECRYPT);
Shawn Willdene9830582017-04-18 10:47:57 -0600475 key = {}; // clear key
476
477 uint8_t computedDigest[MD5_DIGEST_LENGTH];
478 ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700479 MD5(v2blob.digested, digestedLength, computedDigest);
480 if (memcmp(v2blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700481 LOG(ERROR) << __func__ << " v2blob MD5 digest mismatch";
Shawn Willdene9830582017-04-18 10:47:57 -0600482 return ResponseCode::VALUE_CORRUPTED;
483 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700484 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700485 }
486
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700487 const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - rawBlob->info;
488 rawBlob->length = ntohl(rawBlob->length);
489 if (rawBlob->length < 0 || rawBlob->length > maxValueLength ||
490 rawBlob->length + rawBlob->info + AES_BLOCK_SIZE >
491 static_cast<ssize_t>(sizeof(rawBlob->value))) {
Janis Danisevskis56ec4392019-04-11 13:16:48 -0700492 LOG(ERROR) << __func__ << " raw blob length is out of bounds";
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100493 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700494 }
Shawn Willdene9830582017-04-18 10:47:57 -0600495
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700496 if (rawBlob->info != 0 && rawBlob->version < 3) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700497 // move info from after padding to after data
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700498 memmove(rawBlob->value + rawBlob->length, rawBlob->value + maxValueLength, rawBlob->info);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700499 }
Shawn Willdene9830582017-04-18 10:47:57 -0600500
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700501 mBlob = std::move(rawBlob);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100502 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700503}
Janis Danisevskisc1460142017-12-18 16:48:46 -0800504
Branden Archerf5953d72019-01-10 09:08:18 -0800505std::tuple<ResponseCode, Blob, Blob>
506LockedKeyBlobEntry::readBlobs(const std::vector<uint8_t>& aes_key, State state) const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700507 std::tuple<ResponseCode, Blob, Blob> result;
508 auto& [rc, keyBlob, characteristicsBlob] = result;
509 if (entry_ == nullptr) return rc = ResponseCode::SYSTEM_ERROR, result;
510
511 rc = keyBlob.readBlob(entry_->getKeyBlobPath(), aes_key, state);
512 if (rc != ResponseCode::NO_ERROR && rc != ResponseCode::UNINITIALIZED) {
513 return result;
514 }
515
516 if (entry_->hasCharacteristicsBlob()) {
517 characteristicsBlob.readBlob(entry_->getCharacteristicsBlobPath(), aes_key, state);
518 }
519 return result;
520}
521
522ResponseCode LockedKeyBlobEntry::deleteBlobs() const {
523 if (entry_ == nullptr) return ResponseCode::NO_ERROR;
524
525 // always try to delete both
526 ResponseCode rc1 = (unlink(entry_->getKeyBlobPath().c_str()) && errno != ENOENT)
527 ? ResponseCode::SYSTEM_ERROR
528 : ResponseCode::NO_ERROR;
529 if (rc1 != ResponseCode::NO_ERROR) {
530 ALOGW("Failed to delete key blob file \"%s\"", entry_->getKeyBlobPath().c_str());
531 }
532 ResponseCode rc2 = (unlink(entry_->getCharacteristicsBlobPath().c_str()) && errno != ENOENT)
533 ? ResponseCode::SYSTEM_ERROR
534 : ResponseCode::NO_ERROR;
535 if (rc2 != ResponseCode::NO_ERROR) {
536 ALOGW("Failed to delete key characteristics file \"%s\"",
537 entry_->getCharacteristicsBlobPath().c_str());
538 }
539 // then report the first error that occured
540 if (rc1 != ResponseCode::NO_ERROR) return rc1;
541 return rc2;
542}
543
Janis Danisevskisc1460142017-12-18 16:48:46 -0800544keystore::SecurityLevel Blob::getSecurityLevel() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700545 return keystore::flagsToSecurityLevel(mBlob->flags);
Janis Danisevskisc1460142017-12-18 16:48:46 -0800546}
547
548void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700549 mBlob->flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
550 mBlob->flags |= keystore::securityLevelToFlags(secLevel);
551}
552
553std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet>
554Blob::getKeyCharacteristics() const {
555 std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet> result;
556 auto& [success, hwEnforced, swEnforced] = result;
557 success = false;
558 ArrayStreamBuffer buf(mBlob->value);
559 std::istream in(&buf);
560
561 // only the characteristics cache has both sets
562 if (getType() == TYPE_KEY_CHARACTERISTICS_CACHE) {
563 hwEnforced.Deserialize(&in);
564 } else if (getType() != TYPE_KEY_CHARACTERISTICS) {
565 // if its not the cache and not the legacy characteristics file we have no business
566 // here
567 return result;
568 }
569 swEnforced.Deserialize(&in);
570 success = !in.bad();
571
572 return result;
573}
574bool Blob::putKeyCharacteristics(const keystore::AuthorizationSet& hwEnforced,
575 const keystore::AuthorizationSet& swEnforced) {
576 if (!mBlob) mBlob = std::make_unique<blobv3>();
577 mBlob->version = CURRENT_BLOB_VERSION;
578 ArrayStreamBuffer buf(mBlob->value);
579 std::ostream out(&buf);
580 hwEnforced.Serialize(&out);
581 swEnforced.Serialize(&out);
582 if (out.bad()) return false;
583 setType(TYPE_KEY_CHARACTERISTICS_CACHE);
584 mBlob->length = out.tellp();
585 return true;
586}
587
588void LockedKeyBlobEntry::put(const KeyBlobEntry& entry) {
589 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
590 locked_blobs_.erase(entry);
591 lock.unlock();
592 locked_blobs_mutex_cond_var_.notify_all();
593}
594
595LockedKeyBlobEntry::~LockedKeyBlobEntry() {
596 if (entry_ != nullptr) put(*entry_);
597}
598
599LockedKeyBlobEntry LockedKeyBlobEntry::get(KeyBlobEntry entry) {
600 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
601 locked_blobs_mutex_cond_var_.wait(
602 lock, [&] { return locked_blobs_.find(entry) == locked_blobs_.end(); });
603 auto [iterator, success] = locked_blobs_.insert(std::move(entry));
604 if (!success) return {};
605 return LockedKeyBlobEntry(*iterator);
606}
607
608std::set<KeyBlobEntry> LockedKeyBlobEntry::locked_blobs_;
609std::mutex LockedKeyBlobEntry::locked_blobs_mutex_;
610std::condition_variable LockedKeyBlobEntry::locked_blobs_mutex_cond_var_;
611
612/* Here is the encoding of key names. This is necessary in order to allow arbitrary
613 * characters in key names. Characters in [0-~] are not encoded. Others are encoded
614 * into two bytes. The first byte is one of [+-.] which represents the first
615 * two bits of the character. The second byte encodes the rest of the bits into
616 * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
617 * that Base64 cannot be used here due to the need of prefix match on keys. */
618
Eran Messeri2ba77c32018-12-04 12:22:16 +0000619std::string encodeKeyName(const std::string& keyName) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700620 std::string encodedName;
621 encodedName.reserve(keyName.size() * 2);
622 auto in = keyName.begin();
623 while (in != keyName.end()) {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000624 // Input character needs to be encoded.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700625 if (*in < '0' || *in > '~') {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000626 // Encode the two most-significant bits of the input char in the first
627 // output character, by counting up from 43 ('+').
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700628 encodedName.append(1, '+' + (uint8_t(*in) >> 6));
Eran Messeri2ba77c32018-12-04 12:22:16 +0000629 // Encode the six least-significant bits of the input char in the second
630 // output character, by counting up from 48 ('0').
631 // This is safe because the maximum value is 112, which is the
632 // character 'p'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700633 encodedName.append(1, '0' + (*in & 0x3F));
634 } else {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000635 // No need to encode input char - append as-is.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700636 encodedName.append(1, *in);
637 }
638 ++in;
639 }
640 return encodedName;
641}
642
Eran Messeri2ba77c32018-12-04 12:22:16 +0000643std::string decodeKeyName(const std::string& encodedName) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700644 std::string decodedName;
645 decodedName.reserve(encodedName.size());
646 auto in = encodedName.begin();
647 bool multichar = false;
648 char c;
649 while (in != encodedName.end()) {
650 if (multichar) {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000651 // Second part of a multi-character encoding. Turn off the multichar
652 // flag and set the six least-significant bits of c to the value originally
653 // encoded by counting up from '0'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700654 multichar = false;
Eran Messeri2ba77c32018-12-04 12:22:16 +0000655 decodedName.append(1, c | (uint8_t(*in) - '0'));
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700656 } else if (*in >= '+' && *in <= '.') {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000657 // First part of a multi-character encoding. Set the multichar flag
658 // and set the two most-significant bits of c to be the two bits originally
659 // encoded by counting up from '+'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700660 multichar = true;
661 c = (*in - '+') << 6;
662 } else {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000663 // Regular character, append as-is.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700664 decodedName.append(1, *in);
665 }
666 ++in;
667 }
668 // mulitchars at the end get truncated
669 return decodedName;
670}
671
672std::string KeyBlobEntry::getKeyBlobBaseName() const {
673 std::stringstream s;
674 if (masterkey_) {
675 s << alias_;
676 } else {
677 s << uid_ << "_" << encodeKeyName(alias_);
678 }
679 return s.str();
680}
681
682std::string KeyBlobEntry::getKeyBlobPath() const {
683 std::stringstream s;
684 if (masterkey_) {
685 s << user_dir_ << "/" << alias_;
686 } else {
687 s << user_dir_ << "/" << uid_ << "_" << encodeKeyName(alias_);
688 }
689 return s.str();
690}
691
692std::string KeyBlobEntry::getCharacteristicsBlobBaseName() const {
693 std::stringstream s;
694 if (!masterkey_) s << "." << uid_ << "_chr_" << encodeKeyName(alias_);
695 return s.str();
696}
697
698std::string KeyBlobEntry::getCharacteristicsBlobPath() const {
699 std::stringstream s;
700 if (!masterkey_)
701 s << user_dir_ << "/"
702 << "." << uid_ << "_chr_" << encodeKeyName(alias_);
703 return s.str();
704}
705
706bool KeyBlobEntry::hasKeyBlob() const {
707 return !access(getKeyBlobPath().c_str(), R_OK | W_OK);
708}
709bool KeyBlobEntry::hasCharacteristicsBlob() const {
710 return !access(getCharacteristicsBlobPath().c_str(), R_OK | W_OK);
711}
712
713static std::tuple<bool, uid_t, std::string> filename2UidAlias(const std::string& filepath) {
714 std::tuple<bool, uid_t, std::string> result;
715
716 auto& [success, uid, alias] = result;
717
718 success = false;
719
720 auto filenamebase = filepath.find_last_of('/');
721 std::string filename =
722 filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1);
723
724 if (filename[0] == '.') return result;
725
726 auto sep = filename.find('_');
727 if (sep == std::string::npos) return result;
728
729 std::stringstream s(filename.substr(0, sep));
730 s >> uid;
731 if (!s) return result;
732
733 alias = decodeKeyName(filename.substr(sep + 1));
734 success = true;
735 return result;
736}
737
738std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>>
739LockedKeyBlobEntry::list(const std::string& user_dir,
740 std::function<bool(uid_t, const std::string&)> filter) {
741 std::list<LockedKeyBlobEntry> matches;
742
743 // This is a fence against any concurrent database accesses during database iteration.
744 // Only the keystore thread can lock entries. So it cannot be starved
745 // by workers grabbing new individual locks. We just wait here until all
746 // workers have relinquished their locked files.
747 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
748 locked_blobs_mutex_cond_var_.wait(lock, [&] { return locked_blobs_.empty(); });
749
750 DIR* dir = opendir(user_dir.c_str());
751 if (!dir) {
752 ALOGW("can't open directory for user: %s", strerror(errno));
753 return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::SYSTEM_ERROR,
754 std::move(matches)};
755 }
756
757 struct dirent* file;
758 while ((file = readdir(dir)) != nullptr) {
759 // We only care about files.
760 if (file->d_type != DT_REG) {
761 continue;
762 }
763
764 // Skip anything that starts with a "."
765 if (file->d_name[0] == '.') {
766 continue;
767 }
768
769 auto [success, uid, alias] = filename2UidAlias(file->d_name);
770
771 if (!success) {
772 ALOGW("could not parse key filename \"%s\"", file->d_name);
773 continue;
774 }
775
776 if (!filter(uid, alias)) continue;
777
778 auto [iterator, dummy] = locked_blobs_.emplace(alias, user_dir, uid);
779 matches.push_back(*iterator);
780 }
781 closedir(dir);
782 return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::NO_ERROR,
783 std::move(matches)};
Janis Danisevskisc1460142017-12-18 16:48:46 -0800784}