blob: 8633635c3668f4b9d7c6e7072e843d38d794674f [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
72/*
73 * Encrypt 'len' data at 'in' with AES-GCM, using 128-bit key at 'key', 96-bit IV at 'iv' and write
74 * output to 'out' (which may be the same location as 'in') and 128-bit tag to 'tag'.
75 */
76ResponseCode AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len, const uint8_t* key,
77 const uint8_t* iv, uint8_t* tag) {
78 const EVP_CIPHER* cipher = EVP_aes_128_gcm();
79 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
80
81 EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key, iv);
82 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
83
84 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
85 uint8_t* out_pos = out_tmp.get();
86 int out_len;
87
88 EVP_EncryptUpdate(ctx.get(), out_pos, &out_len, in, len);
89 out_pos += out_len;
90 EVP_EncryptFinal_ex(ctx.get(), out_pos, &out_len);
91 out_pos += out_len;
92 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
93 ALOGD("Encrypted ciphertext is the wrong size, expected %zu, got %zd", len,
94 out_pos - out_tmp.get());
95 return ResponseCode::SYSTEM_ERROR;
96 }
97
98 std::copy(out_tmp.get(), out_pos, out);
99 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kGcmTagLength, tag);
100
101 return ResponseCode::NO_ERROR;
102}
103
104/*
105 * Decrypt 'len' data at 'in' with AES-GCM, using 128-bit key at 'key', 96-bit IV at 'iv', checking
106 * 128-bit tag at 'tag' and writing plaintext to 'out' (which may be the same location as 'in').
107 */
108ResponseCode AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len, const uint8_t* key,
109 const uint8_t* iv, const uint8_t* tag) {
110 const EVP_CIPHER* cipher = EVP_aes_128_gcm();
111 EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
112
113 EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key, iv);
114 EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
115 EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kGcmTagLength, const_cast<uint8_t*>(tag));
116
117 std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
118 ArrayEraser out_eraser(out_tmp.get(), len);
119 uint8_t* out_pos = out_tmp.get();
120 int out_len;
121
122 EVP_DecryptUpdate(ctx.get(), out_pos, &out_len, in, len);
123 out_pos += out_len;
124 if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) {
125 ALOGD("Failed to decrypt blob; ciphertext or tag is likely corrupted");
Pavel Grafovcef39472018-02-12 18:45:02 +0000126 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdene9830582017-04-18 10:47:57 -0600127 }
128 out_pos += out_len;
129 if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
130 ALOGD("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
131 out_pos - out_tmp.get());
Pavel Grafovcef39472018-02-12 18:45:02 +0000132 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdene9830582017-04-18 10:47:57 -0600133 }
134
135 std::copy(out_tmp.get(), out_pos, out);
136
137 return ResponseCode::NO_ERROR;
138}
139
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700140class ArrayStreamBuffer : public std::streambuf {
141 public:
142 template <typename T, size_t size> ArrayStreamBuffer(const T (&data)[size]) {
143 static_assert(sizeof(T) == 1, "Array element size too large");
144 std::streambuf::char_type* d = const_cast<std::streambuf::char_type*>(
145 reinterpret_cast<const std::streambuf::char_type*>(&data[0]));
146 setg(d, d, d + size);
147 setp(d, d + size);
148 }
149
150 protected:
151 pos_type seekoff(off_type off, std::ios_base::seekdir dir,
152 std::ios_base::openmode which = std::ios_base::in |
153 std::ios_base::out) override {
154 bool in = which & std::ios_base::in;
155 bool out = which & std::ios_base::out;
156 if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1;
157 std::streambuf::char_type* newPosPtr;
158 switch (dir) {
159 case std::ios_base::beg:
160 newPosPtr = pbase();
161 break;
162 case std::ios_base::cur:
163 // if dir == cur then in xor out due to
164 // if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1; above
165 if (in)
166 newPosPtr = gptr();
167 else
168 newPosPtr = pptr();
169 break;
170 case std::ios_base::end:
171 // in and out bounds are the same and cannot change, so we can take either range
172 // regardless of the value of "which"
173 newPosPtr = epptr();
174 break;
175 }
176 newPosPtr += off;
177 if (newPosPtr < pbase() || newPosPtr > epptr()) return -1;
178 if (in) {
179 gbump(newPosPtr - gptr());
180 }
181 if (out) {
182 pbump(newPosPtr - pptr());
183 }
184 return newPosPtr - pbase();
185 }
186};
187
Shawn Willdene9830582017-04-18 10:47:57 -0600188} // namespace
189
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700190Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
191 BlobType type) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700192 mBlob = std::make_unique<blobv3>();
193 memset(mBlob.get(), 0, sizeof(blobv3));
Shawn Willdene9830582017-04-18 10:47:57 -0600194 if (valueLength > kValueSize) {
195 valueLength = kValueSize;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700196 ALOGW("Provided blob length too large");
197 }
Shawn Willdene9830582017-04-18 10:47:57 -0600198 if (infoLength + valueLength > kValueSize) {
199 infoLength = kValueSize - valueLength;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700200 ALOGW("Provided info length too large");
201 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700202 mBlob->length = valueLength;
203 memcpy(mBlob->value, value, valueLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700204
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700205 mBlob->info = infoLength;
206 memcpy(mBlob->value + valueLength, info, infoLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700207
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700208 mBlob->version = CURRENT_BLOB_VERSION;
209 mBlob->type = uint8_t(type);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700210
211 if (type == TYPE_MASTER_KEY) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700212 mBlob->flags = KEYSTORE_FLAG_ENCRYPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700213 } else {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700214 mBlob->flags = KEYSTORE_FLAG_NONE;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700215 }
216}
217
Shawn Willdene9830582017-04-18 10:47:57 -0600218Blob::Blob(blobv3 b) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700219 mBlob = std::make_unique<blobv3>(b);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700220}
221
222Blob::Blob() {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700223 if (mBlob) *mBlob = {};
224}
225
226Blob::Blob(const Blob& rhs) {
227 if (rhs.mBlob) {
228 mBlob = std::make_unique<blobv3>(*rhs.mBlob);
229 }
230}
231
232Blob::Blob(Blob&& rhs) : mBlob(std::move(rhs.mBlob)) {}
233
234Blob& Blob::operator=(const Blob& rhs) {
235 if (&rhs != this) {
236 if (mBlob) *mBlob = {};
237 if (rhs) {
238 mBlob = std::make_unique<blobv3>(*rhs.mBlob);
239 } else {
240 mBlob = {};
241 }
242 }
243 return *this;
244}
245
246Blob& Blob::operator=(Blob&& rhs) {
247 if (mBlob) *mBlob = {};
248 mBlob = std::move(rhs.mBlob);
249 return *this;
250}
251
252template <typename BlobType> static bool rawBlobIsEncrypted(const BlobType& blob) {
253 if (blob.version < 2) return true;
254
255 return blob.flags & (KEYSTORE_FLAG_ENCRYPTED | KEYSTORE_FLAG_SUPER_ENCRYPTED);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700256}
257
258bool Blob::isEncrypted() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700259 if (mBlob->version < 2) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700260 return true;
261 }
262
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700263 return mBlob->flags & KEYSTORE_FLAG_ENCRYPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700264}
265
Shawn Willdend5a24e62017-02-28 13:53:24 -0700266bool Blob::isSuperEncrypted() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700267 return mBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
Shawn Willdend5a24e62017-02-28 13:53:24 -0700268}
269
Rubin Xu67899de2017-04-21 19:15:13 +0100270bool Blob::isCriticalToDeviceEncryption() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700271 return mBlob->flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
Rubin Xu67899de2017-04-21 19:15:13 +0100272}
273
Shawn Willdend5a24e62017-02-28 13:53:24 -0700274inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
275 return set ? (flags | flag) : (flags & ~flag);
276}
277
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700278void Blob::setEncrypted(bool encrypted) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700279 mBlob->flags = setFlag(mBlob->flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
Shawn Willdend5a24e62017-02-28 13:53:24 -0700280}
281
Rubin Xu67899de2017-04-21 19:15:13 +0100282void Blob::setSuperEncrypted(bool superEncrypted) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700283 mBlob->flags = setFlag(mBlob->flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
Rubin Xu67899de2017-04-21 19:15:13 +0100284}
Rubin Xu48477952017-04-19 14:16:57 +0100285
Rubin Xu67899de2017-04-21 19:15:13 +0100286void Blob::setCriticalToDeviceEncryption(bool critical) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700287 mBlob->flags = setFlag(mBlob->flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700288}
289
290void Blob::setFallback(bool fallback) {
291 if (fallback) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700292 mBlob->flags |= KEYSTORE_FLAG_FALLBACK;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700293 } else {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700294 mBlob->flags &= ~KEYSTORE_FLAG_FALLBACK;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700295 }
296}
297
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700298static ResponseCode writeBlob(const std::string& filename, Blob blob, blobv3* rawBlob,
Branden Archer44d1afa2018-12-28 09:10:49 -0800299 const uint8_t* aes_key, State state) {
Shawn Willdene9830582017-04-18 10:47:57 -0600300 ALOGV("writing blob %s", filename.c_str());
301
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700302 const size_t dataLength = rawBlob->length;
303 rawBlob->length = htonl(rawBlob->length);
Shawn Willdene9830582017-04-18 10:47:57 -0600304
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700305 if (blob.isEncrypted() || blob.isSuperEncrypted()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700306 if (state != STATE_NO_ERROR) {
307 ALOGD("couldn't insert encrypted blob while not unlocked");
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100308 return ResponseCode::LOCKED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700309 }
310
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700311 memset(rawBlob->initialization_vector, 0, AES_BLOCK_SIZE);
Branden Archer44d1afa2018-12-28 09:10:49 -0800312 if (!RAND_bytes(rawBlob->initialization_vector, kGcmIvSizeBytes)) {
Shawn Willdene9830582017-04-18 10:47:57 -0600313 ALOGW("Could not read random data for: %s", filename.c_str());
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100314 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700315 }
Shawn Willdene9830582017-04-18 10:47:57 -0600316
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700317 auto rc = AES_gcm_encrypt(rawBlob->value /* in */, rawBlob->value /* out */, dataLength,
318 aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
Shawn Willdene9830582017-04-18 10:47:57 -0600319 if (rc != ResponseCode::NO_ERROR) return rc;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700320 }
321
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700322 size_t fileLength = offsetof(blobv3, value) + dataLength + rawBlob->info;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700323
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700324 int out =
325 TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700326 if (out < 0) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700327 ALOGW("could not open file: %s: %s", filename.c_str(), strerror(errno));
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100328 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700329 }
Shawn Willdene9830582017-04-18 10:47:57 -0600330
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700331 const size_t writtenBytes = writeFully(out, reinterpret_cast<uint8_t*>(rawBlob), fileLength);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700332 if (close(out) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100333 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700334 }
335 if (writtenBytes != fileLength) {
336 ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700337 unlink(filename.c_str());
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100338 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700339 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100340 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700341}
342
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700343ResponseCode LockedKeyBlobEntry::writeBlobs(Blob keyBlob, Blob characteristicsBlob,
Branden Archer44d1afa2018-12-28 09:10:49 -0800344 const uint8_t* aes_key, State state) const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700345 if (entry_ == nullptr) {
346 return ResponseCode::SYSTEM_ERROR;
347 }
348 ResponseCode rc;
349 if (keyBlob) {
350 blobv3* rawBlob = keyBlob.mBlob.get();
Branden Archer44d1afa2018-12-28 09:10:49 -0800351 rc = writeBlob(entry_->getKeyBlobPath(), std::move(keyBlob), rawBlob, aes_key, state);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700352 if (rc != ResponseCode::NO_ERROR) {
353 return rc;
354 }
355 }
356
357 if (characteristicsBlob) {
358 blobv3* rawBlob = characteristicsBlob.mBlob.get();
359 rc = writeBlob(entry_->getCharacteristicsBlobPath(), std::move(characteristicsBlob),
Branden Archer44d1afa2018-12-28 09:10:49 -0800360 rawBlob, aes_key, state);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700361 }
362 return rc;
363}
364
Shawn Willdene9830582017-04-18 10:47:57 -0600365ResponseCode Blob::readBlob(const std::string& filename, const uint8_t* aes_key, State state) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700366 ResponseCode rc;
Shawn Willdene9830582017-04-18 10:47:57 -0600367 ALOGV("reading blob %s", filename.c_str());
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700368 std::unique_ptr<blobv3> rawBlob = std::make_unique<blobv3>();
369
Shawn Willdene9830582017-04-18 10:47:57 -0600370 const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700371 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100372 return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700373 }
Shawn Willdene9830582017-04-18 10:47:57 -0600374
375 // fileLength may be less than sizeof(mBlob)
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700376 const size_t fileLength = readFully(in, (uint8_t*)rawBlob.get(), sizeof(blobv3));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700377 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100378 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700379 }
380
381 if (fileLength == 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100382 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700383 }
384
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700385 if (rawBlobIsEncrypted(*rawBlob)) {
386 if (state == STATE_LOCKED) {
387 mBlob = std::move(rawBlob);
388 return ResponseCode::LOCKED;
389 }
Janis Danisevskis36316d62017-09-01 14:31:36 -0700390 if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700391 }
392
Shawn Willdene9830582017-04-18 10:47:57 -0600393 if (fileLength < offsetof(blobv3, value)) return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700394
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700395 if (rawBlob->version == 3) {
396 const ssize_t encryptedLength = ntohl(rawBlob->length);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700397
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700398 if (rawBlobIsEncrypted(*rawBlob)) {
399 rc = AES_gcm_decrypt(rawBlob->value /* in */, rawBlob->value /* out */, encryptedLength,
400 aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
Shawn Willdene9830582017-04-18 10:47:57 -0600401 if (rc != ResponseCode::NO_ERROR) return rc;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700402 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700403 } else if (rawBlob->version < 3) {
404 blobv2& v2blob = reinterpret_cast<blobv2&>(*rawBlob);
Shawn Willdene9830582017-04-18 10:47:57 -0600405 const size_t headerLength = offsetof(blobv2, encrypted);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700406 const ssize_t encryptedLength = fileLength - headerLength - v2blob.info;
Shawn Willdene9830582017-04-18 10:47:57 -0600407 if (encryptedLength < 0) return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700408
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700409 if (rawBlobIsEncrypted(*rawBlob)) {
Shawn Willdene9830582017-04-18 10:47:57 -0600410 if (encryptedLength % AES_BLOCK_SIZE != 0) {
411 return ResponseCode::VALUE_CORRUPTED;
412 }
413
414 AES_KEY key;
415 AES_set_decrypt_key(aes_key, kAesKeySize * 8, &key);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700416 AES_cbc_encrypt(v2blob.encrypted, v2blob.encrypted, encryptedLength, &key,
417 v2blob.vector, AES_DECRYPT);
Shawn Willdene9830582017-04-18 10:47:57 -0600418 key = {}; // clear key
419
420 uint8_t computedDigest[MD5_DIGEST_LENGTH];
421 ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700422 MD5(v2blob.digested, digestedLength, computedDigest);
423 if (memcmp(v2blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
Shawn Willdene9830582017-04-18 10:47:57 -0600424 return ResponseCode::VALUE_CORRUPTED;
425 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700426 }
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700427 }
428
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700429 const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - rawBlob->info;
430 rawBlob->length = ntohl(rawBlob->length);
431 if (rawBlob->length < 0 || rawBlob->length > maxValueLength ||
432 rawBlob->length + rawBlob->info + AES_BLOCK_SIZE >
433 static_cast<ssize_t>(sizeof(rawBlob->value))) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100434 return ResponseCode::VALUE_CORRUPTED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700435 }
Shawn Willdene9830582017-04-18 10:47:57 -0600436
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700437 if (rawBlob->info != 0 && rawBlob->version < 3) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700438 // move info from after padding to after data
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700439 memmove(rawBlob->value + rawBlob->length, rawBlob->value + maxValueLength, rawBlob->info);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700440 }
Shawn Willdene9830582017-04-18 10:47:57 -0600441
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700442 mBlob = std::move(rawBlob);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100443 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700444}
Janis Danisevskisc1460142017-12-18 16:48:46 -0800445
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700446std::tuple<ResponseCode, Blob, Blob> LockedKeyBlobEntry::readBlobs(const uint8_t* aes_key,
447 State state) const {
448 std::tuple<ResponseCode, Blob, Blob> result;
449 auto& [rc, keyBlob, characteristicsBlob] = result;
450 if (entry_ == nullptr) return rc = ResponseCode::SYSTEM_ERROR, result;
451
452 rc = keyBlob.readBlob(entry_->getKeyBlobPath(), aes_key, state);
453 if (rc != ResponseCode::NO_ERROR && rc != ResponseCode::UNINITIALIZED) {
454 return result;
455 }
456
457 if (entry_->hasCharacteristicsBlob()) {
458 characteristicsBlob.readBlob(entry_->getCharacteristicsBlobPath(), aes_key, state);
459 }
460 return result;
461}
462
463ResponseCode LockedKeyBlobEntry::deleteBlobs() const {
464 if (entry_ == nullptr) return ResponseCode::NO_ERROR;
465
466 // always try to delete both
467 ResponseCode rc1 = (unlink(entry_->getKeyBlobPath().c_str()) && errno != ENOENT)
468 ? ResponseCode::SYSTEM_ERROR
469 : ResponseCode::NO_ERROR;
470 if (rc1 != ResponseCode::NO_ERROR) {
471 ALOGW("Failed to delete key blob file \"%s\"", entry_->getKeyBlobPath().c_str());
472 }
473 ResponseCode rc2 = (unlink(entry_->getCharacteristicsBlobPath().c_str()) && errno != ENOENT)
474 ? ResponseCode::SYSTEM_ERROR
475 : ResponseCode::NO_ERROR;
476 if (rc2 != ResponseCode::NO_ERROR) {
477 ALOGW("Failed to delete key characteristics file \"%s\"",
478 entry_->getCharacteristicsBlobPath().c_str());
479 }
480 // then report the first error that occured
481 if (rc1 != ResponseCode::NO_ERROR) return rc1;
482 return rc2;
483}
484
Janis Danisevskisc1460142017-12-18 16:48:46 -0800485keystore::SecurityLevel Blob::getSecurityLevel() const {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700486 return keystore::flagsToSecurityLevel(mBlob->flags);
Janis Danisevskisc1460142017-12-18 16:48:46 -0800487}
488
489void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700490 mBlob->flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
491 mBlob->flags |= keystore::securityLevelToFlags(secLevel);
492}
493
494std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet>
495Blob::getKeyCharacteristics() const {
496 std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet> result;
497 auto& [success, hwEnforced, swEnforced] = result;
498 success = false;
499 ArrayStreamBuffer buf(mBlob->value);
500 std::istream in(&buf);
501
502 // only the characteristics cache has both sets
503 if (getType() == TYPE_KEY_CHARACTERISTICS_CACHE) {
504 hwEnforced.Deserialize(&in);
505 } else if (getType() != TYPE_KEY_CHARACTERISTICS) {
506 // if its not the cache and not the legacy characteristics file we have no business
507 // here
508 return result;
509 }
510 swEnforced.Deserialize(&in);
511 success = !in.bad();
512
513 return result;
514}
515bool Blob::putKeyCharacteristics(const keystore::AuthorizationSet& hwEnforced,
516 const keystore::AuthorizationSet& swEnforced) {
517 if (!mBlob) mBlob = std::make_unique<blobv3>();
518 mBlob->version = CURRENT_BLOB_VERSION;
519 ArrayStreamBuffer buf(mBlob->value);
520 std::ostream out(&buf);
521 hwEnforced.Serialize(&out);
522 swEnforced.Serialize(&out);
523 if (out.bad()) return false;
524 setType(TYPE_KEY_CHARACTERISTICS_CACHE);
525 mBlob->length = out.tellp();
526 return true;
527}
528
529void LockedKeyBlobEntry::put(const KeyBlobEntry& entry) {
530 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
531 locked_blobs_.erase(entry);
532 lock.unlock();
533 locked_blobs_mutex_cond_var_.notify_all();
534}
535
536LockedKeyBlobEntry::~LockedKeyBlobEntry() {
537 if (entry_ != nullptr) put(*entry_);
538}
539
540LockedKeyBlobEntry LockedKeyBlobEntry::get(KeyBlobEntry entry) {
541 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
542 locked_blobs_mutex_cond_var_.wait(
543 lock, [&] { return locked_blobs_.find(entry) == locked_blobs_.end(); });
544 auto [iterator, success] = locked_blobs_.insert(std::move(entry));
545 if (!success) return {};
546 return LockedKeyBlobEntry(*iterator);
547}
548
549std::set<KeyBlobEntry> LockedKeyBlobEntry::locked_blobs_;
550std::mutex LockedKeyBlobEntry::locked_blobs_mutex_;
551std::condition_variable LockedKeyBlobEntry::locked_blobs_mutex_cond_var_;
552
553/* Here is the encoding of key names. This is necessary in order to allow arbitrary
554 * characters in key names. Characters in [0-~] are not encoded. Others are encoded
555 * into two bytes. The first byte is one of [+-.] which represents the first
556 * two bits of the character. The second byte encodes the rest of the bits into
557 * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
558 * that Base64 cannot be used here due to the need of prefix match on keys. */
559
Eran Messeri2ba77c32018-12-04 12:22:16 +0000560std::string encodeKeyName(const std::string& keyName) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700561 std::string encodedName;
562 encodedName.reserve(keyName.size() * 2);
563 auto in = keyName.begin();
564 while (in != keyName.end()) {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000565 // Input character needs to be encoded.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700566 if (*in < '0' || *in > '~') {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000567 // Encode the two most-significant bits of the input char in the first
568 // output character, by counting up from 43 ('+').
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700569 encodedName.append(1, '+' + (uint8_t(*in) >> 6));
Eran Messeri2ba77c32018-12-04 12:22:16 +0000570 // Encode the six least-significant bits of the input char in the second
571 // output character, by counting up from 48 ('0').
572 // This is safe because the maximum value is 112, which is the
573 // character 'p'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700574 encodedName.append(1, '0' + (*in & 0x3F));
575 } else {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000576 // No need to encode input char - append as-is.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700577 encodedName.append(1, *in);
578 }
579 ++in;
580 }
581 return encodedName;
582}
583
Eran Messeri2ba77c32018-12-04 12:22:16 +0000584std::string decodeKeyName(const std::string& encodedName) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700585 std::string decodedName;
586 decodedName.reserve(encodedName.size());
587 auto in = encodedName.begin();
588 bool multichar = false;
589 char c;
590 while (in != encodedName.end()) {
591 if (multichar) {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000592 // Second part of a multi-character encoding. Turn off the multichar
593 // flag and set the six least-significant bits of c to the value originally
594 // encoded by counting up from '0'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700595 multichar = false;
Eran Messeri2ba77c32018-12-04 12:22:16 +0000596 decodedName.append(1, c | (uint8_t(*in) - '0'));
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700597 } else if (*in >= '+' && *in <= '.') {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000598 // First part of a multi-character encoding. Set the multichar flag
599 // and set the two most-significant bits of c to be the two bits originally
600 // encoded by counting up from '+'.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700601 multichar = true;
602 c = (*in - '+') << 6;
603 } else {
Eran Messeri2ba77c32018-12-04 12:22:16 +0000604 // Regular character, append as-is.
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700605 decodedName.append(1, *in);
606 }
607 ++in;
608 }
609 // mulitchars at the end get truncated
610 return decodedName;
611}
612
613std::string KeyBlobEntry::getKeyBlobBaseName() const {
614 std::stringstream s;
615 if (masterkey_) {
616 s << alias_;
617 } else {
618 s << uid_ << "_" << encodeKeyName(alias_);
619 }
620 return s.str();
621}
622
623std::string KeyBlobEntry::getKeyBlobPath() const {
624 std::stringstream s;
625 if (masterkey_) {
626 s << user_dir_ << "/" << alias_;
627 } else {
628 s << user_dir_ << "/" << uid_ << "_" << encodeKeyName(alias_);
629 }
630 return s.str();
631}
632
633std::string KeyBlobEntry::getCharacteristicsBlobBaseName() const {
634 std::stringstream s;
635 if (!masterkey_) s << "." << uid_ << "_chr_" << encodeKeyName(alias_);
636 return s.str();
637}
638
639std::string KeyBlobEntry::getCharacteristicsBlobPath() const {
640 std::stringstream s;
641 if (!masterkey_)
642 s << user_dir_ << "/"
643 << "." << uid_ << "_chr_" << encodeKeyName(alias_);
644 return s.str();
645}
646
647bool KeyBlobEntry::hasKeyBlob() const {
648 return !access(getKeyBlobPath().c_str(), R_OK | W_OK);
649}
650bool KeyBlobEntry::hasCharacteristicsBlob() const {
651 return !access(getCharacteristicsBlobPath().c_str(), R_OK | W_OK);
652}
653
654static std::tuple<bool, uid_t, std::string> filename2UidAlias(const std::string& filepath) {
655 std::tuple<bool, uid_t, std::string> result;
656
657 auto& [success, uid, alias] = result;
658
659 success = false;
660
661 auto filenamebase = filepath.find_last_of('/');
662 std::string filename =
663 filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1);
664
665 if (filename[0] == '.') return result;
666
667 auto sep = filename.find('_');
668 if (sep == std::string::npos) return result;
669
670 std::stringstream s(filename.substr(0, sep));
671 s >> uid;
672 if (!s) return result;
673
674 alias = decodeKeyName(filename.substr(sep + 1));
675 success = true;
676 return result;
677}
678
679std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>>
680LockedKeyBlobEntry::list(const std::string& user_dir,
681 std::function<bool(uid_t, const std::string&)> filter) {
682 std::list<LockedKeyBlobEntry> matches;
683
684 // This is a fence against any concurrent database accesses during database iteration.
685 // Only the keystore thread can lock entries. So it cannot be starved
686 // by workers grabbing new individual locks. We just wait here until all
687 // workers have relinquished their locked files.
688 std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
689 locked_blobs_mutex_cond_var_.wait(lock, [&] { return locked_blobs_.empty(); });
690
691 DIR* dir = opendir(user_dir.c_str());
692 if (!dir) {
693 ALOGW("can't open directory for user: %s", strerror(errno));
694 return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::SYSTEM_ERROR,
695 std::move(matches)};
696 }
697
698 struct dirent* file;
699 while ((file = readdir(dir)) != nullptr) {
700 // We only care about files.
701 if (file->d_type != DT_REG) {
702 continue;
703 }
704
705 // Skip anything that starts with a "."
706 if (file->d_name[0] == '.') {
707 continue;
708 }
709
710 auto [success, uid, alias] = filename2UidAlias(file->d_name);
711
712 if (!success) {
713 ALOGW("could not parse key filename \"%s\"", file->d_name);
714 continue;
715 }
716
717 if (!filter(uid, alias)) continue;
718
719 auto [iterator, dummy] = locked_blobs_.emplace(alias, user_dir, uid);
720 matches.push_back(*iterator);
721 }
722 closedir(dir);
723 return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::NO_ERROR,
724 std::move(matches)};
Janis Danisevskisc1460142017-12-18 16:48:46 -0800725}