• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "keystore"
18 
19 #include <arpa/inet.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <string.h>
23 
24 #include <log/log.h>
25 
26 #include "blob.h"
27 
28 #include "keystore_utils.h"
29 
30 #include <openssl/evp.h>
31 #include <openssl/rand.h>
32 
33 #include <istream>
34 #include <ostream>
35 #include <streambuf>
36 #include <string>
37 
38 #include <android-base/logging.h>
39 
40 namespace {
41 
42 constexpr size_t kGcmIvSizeBytes = 96 / 8;
43 
44 template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter {
operator ()__anon63e3c1780111::OpenSslObjectDeleter45     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 
52 DEFINE_OPENSSL_OBJECT_POINTER(EVP_CIPHER_CTX);
53 
54 #if defined(__clang__)
55 #define OPTNONE __attribute__((optnone))
56 #elif defined(__GNUC__)
57 #define OPTNONE __attribute__((optimize("O0")))
58 #else
59 #error Need a definition for OPTNONE
60 #endif
61 
62 class ArrayEraser {
63   public:
ArrayEraser(uint8_t * arr,size_t size)64     ArrayEraser(uint8_t* arr, size_t size) : mArr(arr), mSize(size) {}
~ArrayEraser()65     OPTNONE ~ArrayEraser() { std::fill(mArr, mArr + mSize, 0); }
66 
67   private:
68     volatile uint8_t* mArr;
69     size_t mSize;
70 };
71 
72 /**
73  * Returns a EVP_CIPHER appropriate for the given key, based on the key's size.
74  */
getAesCipherForKey(const std::vector<uint8_t> & key)75 const 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 
83 /*
84  * 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'.
87  */
AES_gcm_encrypt(const uint8_t * in,uint8_t * out,size_t len,const std::vector<uint8_t> & key,const uint8_t * iv,uint8_t * tag)88 ResponseCode 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) {
90 
91     // There can be 128-bit and 256-bit keys
92     const EVP_CIPHER* cipher = getAesCipherForKey(key);
93 
94     EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
95 
96     EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
97     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 /*
120  * 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').
123  */
AES_gcm_decrypt(const uint8_t * in,uint8_t * out,size_t len,const std::vector<uint8_t> key,const uint8_t * iv,const uint8_t * tag)124 ResponseCode 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) {
127 
128     // There can be 128-bit and 256-bit keys
129     const EVP_CIPHER* cipher = getAesCipherForKey(key);
130 
131     EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
132 
133     EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
134     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)) {
145         ALOGD("Failed to decrypt blob; ciphertext or tag is likely corrupted");
146         return ResponseCode::VALUE_CORRUPTED;
147     }
148     out_pos += out_len;
149     if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
150         ALOGD("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
151               out_pos - out_tmp.get());
152         return ResponseCode::VALUE_CORRUPTED;
153     }
154 
155     std::copy(out_tmp.get(), out_pos, out);
156 
157     return ResponseCode::NO_ERROR;
158 }
159 
160 class ArrayStreamBuffer : public std::streambuf {
161   public:
ArrayStreamBuffer(const T (& data)[size])162     template <typename T, size_t size> explicit ArrayStreamBuffer(const T (&data)[size]) {
163         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:
seekoff(off_type off,std::ios_base::seekdir dir,std::ios_base::openmode which=std::ios_base::in|std::ios_base::out)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 
208 }  // namespace
209 
Blob(const uint8_t * value,size_t valueLength,const uint8_t * info,uint8_t infoLength,BlobType type)210 Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
211            BlobType type) {
212     mBlob = std::make_unique<blobv3>();
213     memset(mBlob.get(), 0, sizeof(blobv3));
214     if (valueLength > kValueSize) {
215         valueLength = kValueSize;
216         ALOGW("Provided blob length too large");
217     }
218     if (infoLength + valueLength > kValueSize) {
219         infoLength = kValueSize - valueLength;
220         ALOGW("Provided info length too large");
221     }
222     mBlob->length = valueLength;
223     memcpy(mBlob->value, value, valueLength);
224 
225     mBlob->info = infoLength;
226     memcpy(mBlob->value + valueLength, info, infoLength);
227 
228     mBlob->version = CURRENT_BLOB_VERSION;
229     mBlob->type = uint8_t(type);
230 
231     if (type == TYPE_MASTER_KEY || type == TYPE_MASTER_KEY_AES256) {
232         mBlob->flags = KEYSTORE_FLAG_ENCRYPTED;
233     } else {
234         mBlob->flags = KEYSTORE_FLAG_NONE;
235     }
236 }
237 
Blob(blobv3 b)238 Blob::Blob(blobv3 b) {
239     mBlob = std::make_unique<blobv3>(b);
240 }
241 
Blob()242 Blob::Blob() {
243     if (mBlob) *mBlob = {};
244 }
245 
Blob(const Blob & rhs)246 Blob::Blob(const Blob& rhs) {
247     if (rhs.mBlob) {
248         mBlob = std::make_unique<blobv3>(*rhs.mBlob);
249     }
250 }
251 
Blob(Blob && rhs)252 Blob::Blob(Blob&& rhs) : mBlob(std::move(rhs.mBlob)) {}
253 
operator =(const Blob & rhs)254 Blob& 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 
operator =(Blob && rhs)266 Blob& Blob::operator=(Blob&& rhs) {
267     if (mBlob) *mBlob = {};
268     mBlob = std::move(rhs.mBlob);
269     return *this;
270 }
271 
rawBlobIsEncrypted(const BlobType & blob)272 template <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);
276 }
277 
isEncrypted() const278 bool Blob::isEncrypted() const {
279     if (mBlob->version < 2) {
280         return true;
281     }
282 
283     return mBlob->flags & KEYSTORE_FLAG_ENCRYPTED;
284 }
285 
isSuperEncrypted() const286 bool Blob::isSuperEncrypted() const {
287     return mBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
288 }
289 
isCriticalToDeviceEncryption() const290 bool Blob::isCriticalToDeviceEncryption() const {
291     return mBlob->flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
292 }
293 
setFlag(uint8_t flags,bool set,KeyStoreFlag flag)294 inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
295     return set ? (flags | flag) : (flags & ~flag);
296 }
297 
setEncrypted(bool encrypted)298 void Blob::setEncrypted(bool encrypted) {
299     mBlob->flags = setFlag(mBlob->flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
300 }
301 
setSuperEncrypted(bool superEncrypted)302 void Blob::setSuperEncrypted(bool superEncrypted) {
303     mBlob->flags = setFlag(mBlob->flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
304 }
305 
setCriticalToDeviceEncryption(bool critical)306 void Blob::setCriticalToDeviceEncryption(bool critical) {
307     mBlob->flags = setFlag(mBlob->flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
308 }
309 
setFallback(bool fallback)310 void Blob::setFallback(bool fallback) {
311     if (fallback) {
312         mBlob->flags |= KEYSTORE_FLAG_FALLBACK;
313     } else {
314         mBlob->flags &= ~KEYSTORE_FLAG_FALLBACK;
315     }
316 }
317 
writeBlob(const std::string & filename,Blob blob,blobv3 * rawBlob,const std::vector<uint8_t> & aes_key,State state)318 static ResponseCode writeBlob(const std::string& filename, Blob blob, blobv3* rawBlob,
319                               const std::vector<uint8_t>& aes_key, State state) {
320     ALOGV("writing blob %s", filename.c_str());
321 
322     const size_t dataLength = rawBlob->length;
323     rawBlob->length = htonl(rawBlob->length);
324 
325     if (blob.isEncrypted() || blob.isSuperEncrypted()) {
326         if (state != STATE_NO_ERROR) {
327             ALOGD("couldn't insert encrypted blob while not unlocked");
328             return ResponseCode::LOCKED;
329         }
330 
331         memset(rawBlob->initialization_vector, 0, AES_BLOCK_SIZE);
332         if (!RAND_bytes(rawBlob->initialization_vector, kGcmIvSizeBytes)) {
333             ALOGW("Could not read random data for: %s", filename.c_str());
334             return ResponseCode::SYSTEM_ERROR;
335         }
336 
337         auto rc = AES_gcm_encrypt(rawBlob->value /* in */, rawBlob->value /* out */, dataLength,
338                                   aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
339         if (rc != ResponseCode::NO_ERROR) return rc;
340     }
341 
342     size_t fileLength = offsetof(blobv3, value) + dataLength + rawBlob->info;
343 
344     int out =
345         TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
346     if (out < 0) {
347         ALOGW("could not open file: %s: %s", filename.c_str(), strerror(errno));
348         return ResponseCode::SYSTEM_ERROR;
349     }
350 
351     const size_t writtenBytes = writeFully(out, reinterpret_cast<uint8_t*>(rawBlob), fileLength);
352     if (close(out) != 0) {
353         return ResponseCode::SYSTEM_ERROR;
354     }
355     if (writtenBytes != fileLength) {
356         ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength);
357         unlink(filename.c_str());
358         return ResponseCode::SYSTEM_ERROR;
359     }
360     return ResponseCode::NO_ERROR;
361 }
362 
writeBlobs(Blob keyBlob,Blob characteristicsBlob,const std::vector<uint8_t> & aes_key,State state) const363 ResponseCode LockedKeyBlobEntry::writeBlobs(Blob keyBlob, Blob characteristicsBlob,
364                                             const std::vector<uint8_t>& aes_key,
365                                             State state) const {
366     if (entry_ == nullptr) {
367         return ResponseCode::SYSTEM_ERROR;
368     }
369     ResponseCode rc;
370     if (keyBlob) {
371         blobv3* rawBlob = keyBlob.mBlob.get();
372         rc = writeBlob(entry_->getKeyBlobPath(), std::move(keyBlob), rawBlob, aes_key, state);
373         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),
381                        rawBlob, aes_key, state);
382     }
383     return rc;
384 }
385 
readBlob(const std::string & filename,const std::vector<uint8_t> & aes_key,State state)386 ResponseCode Blob::readBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
387                             State state) {
388     ResponseCode rc;
389     ALOGV("reading blob %s", filename.c_str());
390     std::unique_ptr<blobv3> rawBlob = std::make_unique<blobv3>();
391 
392     const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY));
393     if (in < 0) {
394         return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
395     }
396 
397     // fileLength may be less than sizeof(mBlob)
398     const size_t fileLength = readFully(in, (uint8_t*)rawBlob.get(), sizeof(blobv3));
399     if (close(in) != 0) {
400         return ResponseCode::SYSTEM_ERROR;
401     }
402 
403     if (fileLength == 0) {
404         return ResponseCode::VALUE_CORRUPTED;
405     }
406 
407     if (rawBlobIsEncrypted(*rawBlob)) {
408         if (state == STATE_LOCKED) {
409             mBlob = std::move(rawBlob);
410             return ResponseCode::LOCKED;
411         }
412         if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
413     }
414 
415     if (fileLength < offsetof(blobv3, value)) return ResponseCode::VALUE_CORRUPTED;
416 
417     if (rawBlob->version == 3) {
418         const ssize_t encryptedLength = ntohl(rawBlob->length);
419 
420         if (rawBlobIsEncrypted(*rawBlob)) {
421             rc = AES_gcm_decrypt(rawBlob->value /* in */, rawBlob->value /* out */, encryptedLength,
422                                  aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
423             if (rc != ResponseCode::NO_ERROR) {
424                 // If the blob was superencrypted and decryption failed, it is
425                 // almost certain that decryption is failing due to a user's
426                 // changed master key.
427                 if ((rawBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED) &&
428                     (rc == ResponseCode::VALUE_CORRUPTED)) {
429                     return ResponseCode::KEY_PERMANENTLY_INVALIDATED;
430                 }
431                 return rc;
432             }
433         }
434     } else if (rawBlob->version < 3) {
435         blobv2& v2blob = reinterpret_cast<blobv2&>(*rawBlob);
436         const size_t headerLength = offsetof(blobv2, encrypted);
437         const ssize_t encryptedLength = fileLength - headerLength - v2blob.info;
438         if (encryptedLength < 0) return ResponseCode::VALUE_CORRUPTED;
439 
440         if (rawBlobIsEncrypted(*rawBlob)) {
441             if (encryptedLength % AES_BLOCK_SIZE != 0) {
442                 return ResponseCode::VALUE_CORRUPTED;
443             }
444 
445             AES_KEY key;
446             AES_set_decrypt_key(aes_key.data(), kAesKeySize * 8, &key);
447             AES_cbc_encrypt(v2blob.encrypted, v2blob.encrypted, encryptedLength, &key,
448                             v2blob.vector, AES_DECRYPT);
449             key = {};  // clear key
450 
451             uint8_t computedDigest[MD5_DIGEST_LENGTH];
452             ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
453             MD5(v2blob.digested, digestedLength, computedDigest);
454             if (memcmp(v2blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
455                 return ResponseCode::VALUE_CORRUPTED;
456             }
457         }
458     }
459 
460     const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - rawBlob->info;
461     rawBlob->length = ntohl(rawBlob->length);
462     if (rawBlob->length < 0 || rawBlob->length > maxValueLength ||
463         rawBlob->length + rawBlob->info + AES_BLOCK_SIZE >
464             static_cast<ssize_t>(sizeof(rawBlob->value))) {
465         return ResponseCode::VALUE_CORRUPTED;
466     }
467 
468     if (rawBlob->info != 0 && rawBlob->version < 3) {
469         // move info from after padding to after data
470         memmove(rawBlob->value + rawBlob->length, rawBlob->value + maxValueLength, rawBlob->info);
471     }
472 
473     mBlob = std::move(rawBlob);
474     return ResponseCode::NO_ERROR;
475 }
476 
477 std::tuple<ResponseCode, Blob, Blob>
readBlobs(const std::vector<uint8_t> & aes_key,State state) const478 LockedKeyBlobEntry::readBlobs(const std::vector<uint8_t>& aes_key, State state) const {
479     std::tuple<ResponseCode, Blob, Blob> result;
480     auto& [rc, keyBlob, characteristicsBlob] = result;
481     if (entry_ == nullptr) return rc = ResponseCode::SYSTEM_ERROR, result;
482 
483     rc = keyBlob.readBlob(entry_->getKeyBlobPath(), aes_key, state);
484     if (rc != ResponseCode::NO_ERROR && rc != ResponseCode::UNINITIALIZED) {
485         return result;
486     }
487 
488     if (entry_->hasCharacteristicsBlob()) {
489         characteristicsBlob.readBlob(entry_->getCharacteristicsBlobPath(), aes_key, state);
490     }
491     return result;
492 }
493 
deleteBlobs() const494 ResponseCode LockedKeyBlobEntry::deleteBlobs() const {
495     if (entry_ == nullptr) return ResponseCode::NO_ERROR;
496 
497     // always try to delete both
498     ResponseCode rc1 = (unlink(entry_->getKeyBlobPath().c_str()) && errno != ENOENT)
499                            ? ResponseCode::SYSTEM_ERROR
500                            : ResponseCode::NO_ERROR;
501     if (rc1 != ResponseCode::NO_ERROR) {
502         ALOGW("Failed to delete key blob file \"%s\"", entry_->getKeyBlobPath().c_str());
503     }
504     ResponseCode rc2 = (unlink(entry_->getCharacteristicsBlobPath().c_str()) && errno != ENOENT)
505                            ? ResponseCode::SYSTEM_ERROR
506                            : ResponseCode::NO_ERROR;
507     if (rc2 != ResponseCode::NO_ERROR) {
508         ALOGW("Failed to delete key characteristics file \"%s\"",
509               entry_->getCharacteristicsBlobPath().c_str());
510     }
511     // then report the first error that occured
512     if (rc1 != ResponseCode::NO_ERROR) return rc1;
513     return rc2;
514 }
515 
getSecurityLevel() const516 keystore::SecurityLevel Blob::getSecurityLevel() const {
517     return keystore::flagsToSecurityLevel(mBlob->flags);
518 }
519 
setSecurityLevel(keystore::SecurityLevel secLevel)520 void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) {
521     mBlob->flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
522     mBlob->flags |= keystore::securityLevelToFlags(secLevel);
523 }
524 
525 std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet>
getKeyCharacteristics() const526 Blob::getKeyCharacteristics() const {
527     std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet> result;
528     auto& [success, hwEnforced, swEnforced] = result;
529     success = false;
530     ArrayStreamBuffer buf(mBlob->value);
531     std::istream in(&buf);
532 
533     // only the characteristics cache has both sets
534     if (getType() == TYPE_KEY_CHARACTERISTICS_CACHE) {
535         hwEnforced.Deserialize(&in);
536     } else if (getType() != TYPE_KEY_CHARACTERISTICS) {
537         // if its not the cache and not the legacy characteristics file we have no business
538         // here
539         return result;
540     }
541     swEnforced.Deserialize(&in);
542     success = !in.bad();
543 
544     return result;
545 }
putKeyCharacteristics(const keystore::AuthorizationSet & hwEnforced,const keystore::AuthorizationSet & swEnforced)546 bool Blob::putKeyCharacteristics(const keystore::AuthorizationSet& hwEnforced,
547                                  const keystore::AuthorizationSet& swEnforced) {
548     if (!mBlob) mBlob = std::make_unique<blobv3>();
549     mBlob->version = CURRENT_BLOB_VERSION;
550     ArrayStreamBuffer buf(mBlob->value);
551     std::ostream out(&buf);
552     hwEnforced.Serialize(&out);
553     swEnforced.Serialize(&out);
554     if (out.bad()) return false;
555     setType(TYPE_KEY_CHARACTERISTICS_CACHE);
556     mBlob->length = out.tellp();
557     return true;
558 }
559 
put(const KeyBlobEntry & entry)560 void LockedKeyBlobEntry::put(const KeyBlobEntry& entry) {
561     std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
562     locked_blobs_.erase(entry);
563     lock.unlock();
564     locked_blobs_mutex_cond_var_.notify_all();
565 }
566 
~LockedKeyBlobEntry()567 LockedKeyBlobEntry::~LockedKeyBlobEntry() {
568     if (entry_ != nullptr) put(*entry_);
569 }
570 
get(KeyBlobEntry entry)571 LockedKeyBlobEntry LockedKeyBlobEntry::get(KeyBlobEntry entry) {
572     std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
573     locked_blobs_mutex_cond_var_.wait(
574         lock, [&] { return locked_blobs_.find(entry) == locked_blobs_.end(); });
575     auto [iterator, success] = locked_blobs_.insert(std::move(entry));
576     if (!success) return {};
577     return LockedKeyBlobEntry(*iterator);
578 }
579 
580 std::set<KeyBlobEntry> LockedKeyBlobEntry::locked_blobs_;
581 std::mutex LockedKeyBlobEntry::locked_blobs_mutex_;
582 std::condition_variable LockedKeyBlobEntry::locked_blobs_mutex_cond_var_;
583 
584 /* Here is the encoding of key names. This is necessary in order to allow arbitrary
585  * characters in key names. Characters in [0-~] are not encoded. Others are encoded
586  * into two bytes. The first byte is one of [+-.] which represents the first
587  * two bits of the character. The second byte encodes the rest of the bits into
588  * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
589  * that Base64 cannot be used here due to the need of prefix match on keys. */
590 
encodeKeyName(const std::string & keyName)591 std::string encodeKeyName(const std::string& keyName) {
592     std::string encodedName;
593     encodedName.reserve(keyName.size() * 2);
594     auto in = keyName.begin();
595     while (in != keyName.end()) {
596         // Input character needs to be encoded.
597         if (*in < '0' || *in > '~') {
598             // Encode the two most-significant bits of the input char in the first
599             // output character, by counting up from 43 ('+').
600             encodedName.append(1, '+' + (uint8_t(*in) >> 6));
601             // Encode the six least-significant bits of the input char in the second
602             // output character, by counting up from 48 ('0').
603             // This is safe because the maximum value is 112, which is the
604             // character 'p'.
605             encodedName.append(1, '0' + (*in & 0x3F));
606         } else {
607             // No need to encode input char - append as-is.
608             encodedName.append(1, *in);
609         }
610         ++in;
611     }
612     return encodedName;
613 }
614 
decodeKeyName(const std::string & encodedName)615 std::string decodeKeyName(const std::string& encodedName) {
616     std::string decodedName;
617     decodedName.reserve(encodedName.size());
618     auto in = encodedName.begin();
619     bool multichar = false;
620     char c;
621     while (in != encodedName.end()) {
622         if (multichar) {
623             // Second part of a multi-character encoding. Turn off the multichar
624             // flag and set the six least-significant bits of c to the value originally
625             // encoded by counting up from '0'.
626             multichar = false;
627             decodedName.append(1, c | (uint8_t(*in) - '0'));
628         } else if (*in >= '+' && *in <= '.') {
629             // First part of a multi-character encoding. Set the multichar flag
630             // and set the two most-significant bits of c to be the two bits originally
631             // encoded by counting up from '+'.
632             multichar = true;
633             c = (*in - '+') << 6;
634         } else {
635             // Regular character, append as-is.
636             decodedName.append(1, *in);
637         }
638         ++in;
639     }
640     // mulitchars at the end get truncated
641     return decodedName;
642 }
643 
getKeyBlobBaseName() const644 std::string KeyBlobEntry::getKeyBlobBaseName() const {
645     std::stringstream s;
646     if (masterkey_) {
647         s << alias_;
648     } else {
649         s << uid_ << "_" << encodeKeyName(alias_);
650     }
651     return s.str();
652 }
653 
getKeyBlobPath() const654 std::string KeyBlobEntry::getKeyBlobPath() const {
655     std::stringstream s;
656     if (masterkey_) {
657         s << user_dir_ << "/" << alias_;
658     } else {
659         s << user_dir_ << "/" << uid_ << "_" << encodeKeyName(alias_);
660     }
661     return s.str();
662 }
663 
getCharacteristicsBlobBaseName() const664 std::string KeyBlobEntry::getCharacteristicsBlobBaseName() const {
665     std::stringstream s;
666     if (!masterkey_) s << "." << uid_ << "_chr_" << encodeKeyName(alias_);
667     return s.str();
668 }
669 
getCharacteristicsBlobPath() const670 std::string KeyBlobEntry::getCharacteristicsBlobPath() const {
671     std::stringstream s;
672     if (!masterkey_)
673         s << user_dir_ << "/"
674           << "." << uid_ << "_chr_" << encodeKeyName(alias_);
675     return s.str();
676 }
677 
hasKeyBlob() const678 bool KeyBlobEntry::hasKeyBlob() const {
679     int trys = 3;
680     while (trys--) {
681         if (!access(getKeyBlobPath().c_str(), R_OK | W_OK)) return true;
682         if (errno == ENOENT) return false;
683         LOG(WARNING) << "access encountered " << strerror(errno) << " (" << errno << ")"
684                      << " while checking for key blob";
685         if (errno != EAGAIN) break;
686     }
687     return false;
688 }
689 
hasCharacteristicsBlob() const690 bool KeyBlobEntry::hasCharacteristicsBlob() const {
691     int trys = 3;
692     while (trys--) {
693         if (!access(getCharacteristicsBlobPath().c_str(), R_OK | W_OK)) return true;
694         if (errno == ENOENT) return false;
695         LOG(WARNING) << "access encountered " << strerror(errno) << " (" << errno << ")"
696                      << " while checking for key characteristics blob";
697         if (errno != EAGAIN) break;
698     }
699     return false;
700 }
701 
filename2UidAlias(const std::string & filepath)702 static std::tuple<bool, uid_t, std::string> filename2UidAlias(const std::string& filepath) {
703     std::tuple<bool, uid_t, std::string> result;
704 
705     auto& [success, uid, alias] = result;
706 
707     success = false;
708 
709     auto filenamebase = filepath.find_last_of('/');
710     std::string filename =
711         filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1);
712 
713     if (filename[0] == '.') return result;
714 
715     auto sep = filename.find('_');
716     if (sep == std::string::npos) return result;
717 
718     std::stringstream s(filename.substr(0, sep));
719     s >> uid;
720     if (!s) return result;
721 
722     alias = decodeKeyName(filename.substr(sep + 1));
723     success = true;
724     return result;
725 }
726 
727 std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>>
list(const std::string & user_dir,std::function<bool (uid_t,const std::string &)> filter)728 LockedKeyBlobEntry::list(const std::string& user_dir,
729                          std::function<bool(uid_t, const std::string&)> filter) {
730     std::list<LockedKeyBlobEntry> matches;
731 
732     // This is a fence against any concurrent database accesses during database iteration.
733     // Only the keystore thread can lock entries. So it cannot be starved
734     // by workers grabbing new individual locks. We just wait here until all
735     // workers have relinquished their locked files.
736     std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
737     locked_blobs_mutex_cond_var_.wait(lock, [&] { return locked_blobs_.empty(); });
738 
739     DIR* dir = opendir(user_dir.c_str());
740     if (!dir) {
741         ALOGW("can't open directory for user: %s", strerror(errno));
742         return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::SYSTEM_ERROR,
743                                                                          std::move(matches)};
744     }
745 
746     struct dirent* file;
747     while ((file = readdir(dir)) != nullptr) {
748         // We only care about files.
749         if (file->d_type != DT_REG) {
750             continue;
751         }
752 
753         // Skip anything that starts with a "."
754         if (file->d_name[0] == '.') {
755             continue;
756         }
757 
758         auto [success, uid, alias] = filename2UidAlias(file->d_name);
759 
760         if (!success) {
761             ALOGW("could not parse key filename \"%s\"", file->d_name);
762             continue;
763         }
764 
765         if (!filter(uid, alias)) continue;
766 
767         auto [iterator, dummy] = locked_blobs_.emplace(alias, user_dir, uid);
768         matches.push_back(*iterator);
769     }
770     closedir(dir);
771     return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::NO_ERROR,
772                                                                      std::move(matches)};
773 }
774