• 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 <cutils/log.h>
25 
26 #include "blob.h"
27 #include "entropy.h"
28 
29 #include "keystore_utils.h"
30 
31 namespace {
32 
33 constexpr size_t kGcmIvSizeBytes = 96 / 8;
34 
35 template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter {
operator ()__anonaa95c8ee0111::OpenSslObjectDeleter36     void operator()(T* p) { FreeFunc(p); }
37 };
38 
39 #define DEFINE_OPENSSL_OBJECT_POINTER(name)                                                        \
40     typedef OpenSslObjectDeleter<name, name##_free> name##_Delete;                                 \
41     typedef std::unique_ptr<name, name##_Delete> name##_Ptr;
42 
43 DEFINE_OPENSSL_OBJECT_POINTER(EVP_CIPHER_CTX);
44 
45 #if defined(__clang__)
46 #define OPTNONE __attribute__((optnone))
47 #elif defined(__GNUC__)
48 #define OPTNONE __attribute__((optimize("O0")))
49 #else
50 #error Need a definition for OPTNONE
51 #endif
52 
53 class ArrayEraser {
54   public:
ArrayEraser(uint8_t * arr,size_t size)55     ArrayEraser(uint8_t* arr, size_t size) : mArr(arr), mSize(size) {}
~ArrayEraser()56     OPTNONE ~ArrayEraser() { std::fill(mArr, mArr + mSize, 0); }
57 
58   private:
59     volatile uint8_t* mArr;
60     size_t mSize;
61 };
62 
63 /*
64  * Encrypt 'len' data at 'in' with AES-GCM, using 128-bit key at 'key', 96-bit IV at 'iv' and write
65  * output to 'out' (which may be the same location as 'in') and 128-bit tag to 'tag'.
66  */
AES_gcm_encrypt(const uint8_t * in,uint8_t * out,size_t len,const uint8_t * key,const uint8_t * iv,uint8_t * tag)67 ResponseCode AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len, const uint8_t* key,
68                              const uint8_t* iv, uint8_t* tag) {
69     const EVP_CIPHER* cipher = EVP_aes_128_gcm();
70     EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
71 
72     EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key, iv);
73     EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
74 
75     std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
76     uint8_t* out_pos = out_tmp.get();
77     int out_len;
78 
79     EVP_EncryptUpdate(ctx.get(), out_pos, &out_len, in, len);
80     out_pos += out_len;
81     EVP_EncryptFinal_ex(ctx.get(), out_pos, &out_len);
82     out_pos += out_len;
83     if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
84         ALOGD("Encrypted ciphertext is the wrong size, expected %zu, got %zd", len,
85               out_pos - out_tmp.get());
86         return ResponseCode::SYSTEM_ERROR;
87     }
88 
89     std::copy(out_tmp.get(), out_pos, out);
90     EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kGcmTagLength, tag);
91 
92     return ResponseCode::NO_ERROR;
93 }
94 
95 /*
96  * Decrypt 'len' data at 'in' with AES-GCM, using 128-bit key at 'key', 96-bit IV at 'iv', checking
97  * 128-bit tag at 'tag' and writing plaintext to 'out' (which may be the same location as 'in').
98  */
AES_gcm_decrypt(const uint8_t * in,uint8_t * out,size_t len,const uint8_t * key,const uint8_t * iv,const uint8_t * tag)99 ResponseCode AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len, const uint8_t* key,
100                              const uint8_t* iv, const uint8_t* tag) {
101     const EVP_CIPHER* cipher = EVP_aes_128_gcm();
102     EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
103 
104     EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key, iv);
105     EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
106     EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kGcmTagLength, const_cast<uint8_t*>(tag));
107 
108     std::unique_ptr<uint8_t[]> out_tmp(new uint8_t[len]);
109     ArrayEraser out_eraser(out_tmp.get(), len);
110     uint8_t* out_pos = out_tmp.get();
111     int out_len;
112 
113     EVP_DecryptUpdate(ctx.get(), out_pos, &out_len, in, len);
114     out_pos += out_len;
115     if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) {
116         ALOGD("Failed to decrypt blob; ciphertext or tag is likely corrupted");
117         return ResponseCode::SYSTEM_ERROR;
118     }
119     out_pos += out_len;
120     if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
121         ALOGD("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
122               out_pos - out_tmp.get());
123         return ResponseCode::SYSTEM_ERROR;
124     }
125 
126     std::copy(out_tmp.get(), out_pos, out);
127 
128     return ResponseCode::NO_ERROR;
129 }
130 
131 }  // namespace
132 
Blob(const uint8_t * value,size_t valueLength,const uint8_t * info,uint8_t infoLength,BlobType type)133 Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
134            BlobType type) {
135     memset(&mBlob, 0, sizeof(mBlob));
136     if (valueLength > kValueSize) {
137         valueLength = kValueSize;
138         ALOGW("Provided blob length too large");
139     }
140     if (infoLength + valueLength > kValueSize) {
141         infoLength = kValueSize - valueLength;
142         ALOGW("Provided info length too large");
143     }
144     mBlob.length = valueLength;
145     memcpy(mBlob.value, value, valueLength);
146 
147     mBlob.info = infoLength;
148     memcpy(mBlob.value + valueLength, info, infoLength);
149 
150     mBlob.version = CURRENT_BLOB_VERSION;
151     mBlob.type = uint8_t(type);
152 
153     if (type == TYPE_MASTER_KEY) {
154         mBlob.flags = KEYSTORE_FLAG_ENCRYPTED;
155     } else {
156         mBlob.flags = KEYSTORE_FLAG_NONE;
157     }
158 }
159 
Blob(blobv3 b)160 Blob::Blob(blobv3 b) {
161     mBlob = b;
162 }
163 
Blob()164 Blob::Blob() {
165     memset(&mBlob, 0, sizeof(mBlob));
166 }
167 
isEncrypted() const168 bool Blob::isEncrypted() const {
169     if (mBlob.version < 2) {
170         return true;
171     }
172 
173     return mBlob.flags & KEYSTORE_FLAG_ENCRYPTED;
174 }
175 
isSuperEncrypted() const176 bool Blob::isSuperEncrypted() const {
177     return mBlob.flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
178 }
179 
isCriticalToDeviceEncryption() const180 bool Blob::isCriticalToDeviceEncryption() const {
181     return mBlob.flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
182 }
183 
setFlag(uint8_t flags,bool set,KeyStoreFlag flag)184 inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
185     return set ? (flags | flag) : (flags & ~flag);
186 }
187 
setEncrypted(bool encrypted)188 void Blob::setEncrypted(bool encrypted) {
189     mBlob.flags = setFlag(mBlob.flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
190 }
191 
setSuperEncrypted(bool superEncrypted)192 void Blob::setSuperEncrypted(bool superEncrypted) {
193     mBlob.flags = setFlag(mBlob.flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
194 }
195 
setCriticalToDeviceEncryption(bool critical)196 void Blob::setCriticalToDeviceEncryption(bool critical) {
197     mBlob.flags = setFlag(mBlob.flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
198 }
199 
setFallback(bool fallback)200 void Blob::setFallback(bool fallback) {
201     if (fallback) {
202         mBlob.flags |= KEYSTORE_FLAG_FALLBACK;
203     } else {
204         mBlob.flags &= ~KEYSTORE_FLAG_FALLBACK;
205     }
206 }
207 
writeBlob(const std::string & filename,const uint8_t * aes_key,State state,Entropy * entropy)208 ResponseCode Blob::writeBlob(const std::string& filename, const uint8_t* aes_key, State state,
209                              Entropy* entropy) {
210     ALOGV("writing blob %s", filename.c_str());
211 
212     const size_t dataLength = mBlob.length;
213     mBlob.length = htonl(mBlob.length);
214 
215     if (isEncrypted() || isSuperEncrypted()) {
216         if (state != STATE_NO_ERROR) {
217             ALOGD("couldn't insert encrypted blob while not unlocked");
218             return ResponseCode::LOCKED;
219         }
220 
221         memset(mBlob.initialization_vector, 0, AES_BLOCK_SIZE);
222         if (!entropy->generate_random_data(mBlob.initialization_vector, kGcmIvSizeBytes)) {
223             ALOGW("Could not read random data for: %s", filename.c_str());
224             return ResponseCode::SYSTEM_ERROR;
225         }
226 
227         auto rc = AES_gcm_encrypt(mBlob.value /* in */, mBlob.value /* out */, dataLength, aes_key,
228                                   mBlob.initialization_vector, mBlob.aead_tag);
229         if (rc != ResponseCode::NO_ERROR) return rc;
230     }
231 
232     size_t fileLength = offsetof(blobv3, value) + dataLength + mBlob.info;
233 
234     const char* tmpFileName = ".tmp";
235     int out =
236         TEMP_FAILURE_RETRY(open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
237     if (out < 0) {
238         ALOGW("could not open file: %s: %s", tmpFileName, strerror(errno));
239         return ResponseCode::SYSTEM_ERROR;
240     }
241 
242     const size_t writtenBytes = writeFully(out, (uint8_t*)&mBlob, fileLength);
243     if (close(out) != 0) {
244         return ResponseCode::SYSTEM_ERROR;
245     }
246     if (writtenBytes != fileLength) {
247         ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength);
248         unlink(tmpFileName);
249         return ResponseCode::SYSTEM_ERROR;
250     }
251     if (rename(tmpFileName, filename.c_str()) == -1) {
252         ALOGW("could not rename blob to %s: %s", filename.c_str(), strerror(errno));
253         return ResponseCode::SYSTEM_ERROR;
254     }
255     return ResponseCode::NO_ERROR;
256 }
257 
readBlob(const std::string & filename,const uint8_t * aes_key,State state)258 ResponseCode Blob::readBlob(const std::string& filename, const uint8_t* aes_key, State state) {
259     ALOGV("reading blob %s", filename.c_str());
260     const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY));
261     if (in < 0) {
262         return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
263     }
264 
265     // fileLength may be less than sizeof(mBlob)
266     const size_t fileLength = readFully(in, (uint8_t*)&mBlob, sizeof(mBlob));
267     if (close(in) != 0) {
268         return ResponseCode::SYSTEM_ERROR;
269     }
270 
271     if (fileLength == 0) {
272         return ResponseCode::VALUE_CORRUPTED;
273     }
274 
275     if ((isEncrypted() || isSuperEncrypted())) {
276         if (state == STATE_LOCKED) return ResponseCode::LOCKED;
277         if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
278     }
279 
280     if (fileLength < offsetof(blobv3, value)) return ResponseCode::VALUE_CORRUPTED;
281 
282     if (mBlob.version == 3) {
283         const ssize_t encryptedLength = ntohl(mBlob.length);
284 
285         if (isEncrypted() || isSuperEncrypted()) {
286             auto rc = AES_gcm_decrypt(mBlob.value /* in */, mBlob.value /* out */, encryptedLength,
287                                       aes_key, mBlob.initialization_vector, mBlob.aead_tag);
288             if (rc != ResponseCode::NO_ERROR) return rc;
289         }
290     } else if (mBlob.version < 3) {
291         blobv2& blob = reinterpret_cast<blobv2&>(mBlob);
292         const size_t headerLength = offsetof(blobv2, encrypted);
293         const ssize_t encryptedLength = fileLength - headerLength - blob.info;
294         if (encryptedLength < 0) return ResponseCode::VALUE_CORRUPTED;
295 
296         if (isEncrypted() || isSuperEncrypted()) {
297             if (encryptedLength % AES_BLOCK_SIZE != 0) {
298                 return ResponseCode::VALUE_CORRUPTED;
299             }
300 
301             AES_KEY key;
302             AES_set_decrypt_key(aes_key, kAesKeySize * 8, &key);
303             AES_cbc_encrypt(blob.encrypted, blob.encrypted, encryptedLength, &key, blob.vector,
304                             AES_DECRYPT);
305             key = {};  // clear key
306 
307             uint8_t computedDigest[MD5_DIGEST_LENGTH];
308             ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
309             MD5(blob.digested, digestedLength, computedDigest);
310             if (memcmp(blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
311                 return ResponseCode::VALUE_CORRUPTED;
312             }
313         }
314     }
315 
316     const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - mBlob.info;
317     mBlob.length = ntohl(mBlob.length);
318     if (mBlob.length < 0 || mBlob.length > maxValueLength ||
319         mBlob.length + mBlob.info + AES_BLOCK_SIZE > static_cast<ssize_t>(sizeof(mBlob.value))) {
320         return ResponseCode::VALUE_CORRUPTED;
321     }
322 
323     if (mBlob.info != 0 && mBlob.version < 3) {
324         // move info from after padding to after data
325         memmove(mBlob.value + mBlob.length, mBlob.value + maxValueLength, mBlob.info);
326     }
327 
328     return ResponseCode::NO_ERROR;
329 }
330