• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 "user_state.h"
20 
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/stat.h>
26 
27 #include <openssl/evp.h>
28 
29 #include <cutils/log.h>
30 
31 #include "blob.h"
32 #include "keystore_utils.h"
33 
34 
UserState(uid_t userId)35 UserState::UserState(uid_t userId) :
36         mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {
37     asprintf(&mUserDir, "user_%u", mUserId);
38     asprintf(&mMasterKeyFile, "%s/.masterkey", mUserDir);
39 }
40 
~UserState()41 UserState::~UserState() {
42     free(mUserDir);
43     free(mMasterKeyFile);
44 }
45 
initialize()46 bool UserState::initialize() {
47     if ((mkdir(mUserDir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) && (errno != EEXIST)) {
48         ALOGE("Could not create directory '%s'", mUserDir);
49         return false;
50     }
51 
52     if (access(mMasterKeyFile, R_OK) == 0) {
53         setState(STATE_LOCKED);
54     } else {
55         setState(STATE_UNINITIALIZED);
56     }
57 
58     return true;
59 }
60 
setState(State state)61 void UserState::setState(State state) {
62     mState = state;
63     if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
64         mRetry = MAX_RETRY;
65     }
66 }
67 
zeroizeMasterKeysInMemory()68 void UserState::zeroizeMasterKeysInMemory() {
69     memset(mMasterKey, 0, sizeof(mMasterKey));
70     memset(mSalt, 0, sizeof(mSalt));
71     memset(&mMasterKeyEncryption, 0, sizeof(mMasterKeyEncryption));
72     memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption));
73 }
74 
deleteMasterKey()75 bool UserState::deleteMasterKey() {
76     setState(STATE_UNINITIALIZED);
77     zeroizeMasterKeysInMemory();
78     return unlink(mMasterKeyFile) == 0 || errno == ENOENT;
79 }
80 
initialize(const android::String8 & pw,Entropy * entropy)81 ResponseCode UserState::initialize(const android::String8& pw, Entropy* entropy) {
82     if (!generateMasterKey(entropy)) {
83         return ResponseCode::SYSTEM_ERROR;
84     }
85     ResponseCode response = writeMasterKey(pw, entropy);
86     if (response != ResponseCode::NO_ERROR) {
87         return response;
88     }
89     setupMasterKeys();
90     return ResponseCode::NO_ERROR;
91 }
92 
copyMasterKey(UserState * src)93 ResponseCode UserState::copyMasterKey(UserState* src) {
94     if (mState != STATE_UNINITIALIZED) {
95         return ResponseCode::SYSTEM_ERROR;
96     }
97     if (src->getState() != STATE_NO_ERROR) {
98         return ResponseCode::SYSTEM_ERROR;
99     }
100     memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES);
101     setupMasterKeys();
102     return copyMasterKeyFile(src);
103 }
104 
copyMasterKeyFile(UserState * src)105 ResponseCode UserState::copyMasterKeyFile(UserState* src) {
106     /* Copy the master key file to the new user.  Unfortunately we don't have the src user's
107      * password so we cannot generate a new file with a new salt.
108      */
109     int in = TEMP_FAILURE_RETRY(open(src->getMasterKeyFileName(), O_RDONLY));
110     if (in < 0) {
111         return ResponseCode::SYSTEM_ERROR;
112     }
113     blob rawBlob;
114     size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
115     if (close(in) != 0) {
116         return ResponseCode::SYSTEM_ERROR;
117     }
118     int out =
119         TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
120     if (out < 0) {
121         return ResponseCode::SYSTEM_ERROR;
122     }
123     size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length);
124     if (close(out) != 0) {
125         return ResponseCode::SYSTEM_ERROR;
126     }
127     if (outLength != length) {
128         ALOGW("blob not fully written %zu != %zu", outLength, length);
129         unlink(mMasterKeyFile);
130         return ResponseCode::SYSTEM_ERROR;
131     }
132     return ResponseCode::NO_ERROR;
133 }
134 
writeMasterKey(const android::String8 & pw,Entropy * entropy)135 ResponseCode UserState::writeMasterKey(const android::String8& pw, Entropy* entropy) {
136     uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
137     generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
138     AES_KEY passwordAesKey;
139     AES_set_encrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
140     Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
141     return masterKeyBlob.writeBlob(mMasterKeyFile, &passwordAesKey, STATE_NO_ERROR, entropy);
142 }
143 
readMasterKey(const android::String8 & pw,Entropy * entropy)144 ResponseCode UserState::readMasterKey(const android::String8& pw, Entropy* entropy) {
145     int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY));
146     if (in < 0) {
147         return ResponseCode::SYSTEM_ERROR;
148     }
149 
150     // We read the raw blob to just to get the salt to generate the AES key, then we create the Blob
151     // to use with decryptBlob
152     blob rawBlob;
153     size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
154     if (close(in) != 0) {
155         return ResponseCode::SYSTEM_ERROR;
156     }
157     // find salt at EOF if present, otherwise we have an old file
158     uint8_t* salt;
159     if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
160         salt = (uint8_t*)&rawBlob + length - SALT_SIZE;
161     } else {
162         salt = NULL;
163     }
164     uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
165     generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt);
166     AES_KEY passwordAesKey;
167     AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
168     Blob masterKeyBlob(rawBlob);
169     ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, &passwordAesKey, STATE_NO_ERROR);
170     if (response == ResponseCode::SYSTEM_ERROR) {
171         return response;
172     }
173     if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
174         // If salt was missing, generate one and write a new master key file with the salt.
175         if (salt == NULL) {
176             if (!generateSalt(entropy)) {
177                 return ResponseCode::SYSTEM_ERROR;
178             }
179             response = writeMasterKey(pw, entropy);
180         }
181         if (response == ResponseCode::NO_ERROR) {
182             memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
183             setupMasterKeys();
184         }
185         return response;
186     }
187     if (mRetry <= 0) {
188         reset();
189         return ResponseCode::UNINITIALIZED;
190     }
191     --mRetry;
192     switch (mRetry) {
193     case 0:
194         return ResponseCode::WRONG_PASSWORD_0;
195     case 1:
196         return ResponseCode::WRONG_PASSWORD_1;
197     case 2:
198         return ResponseCode::WRONG_PASSWORD_2;
199     case 3:
200         return ResponseCode::WRONG_PASSWORD_3;
201     default:
202         return ResponseCode::WRONG_PASSWORD_3;
203     }
204 }
205 
reset()206 bool UserState::reset() {
207     DIR* dir = opendir(getUserDirName());
208     if (!dir) {
209         // If the directory doesn't exist then nothing to do.
210         if (errno == ENOENT) {
211             return true;
212         }
213         ALOGW("couldn't open user directory: %s", strerror(errno));
214         return false;
215     }
216 
217     struct dirent* file;
218     while ((file = readdir(dir)) != NULL) {
219         // skip . and ..
220         if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
221             continue;
222         }
223 
224         unlinkat(dirfd(dir), file->d_name, 0);
225     }
226     closedir(dir);
227     return true;
228 }
229 
generateKeyFromPassword(uint8_t * key,ssize_t keySize,const android::String8 & pw,uint8_t * salt)230 void UserState::generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw,
231                                         uint8_t* salt) {
232     size_t saltSize;
233     if (salt != NULL) {
234         saltSize = SALT_SIZE;
235     } else {
236         // Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
237         salt = (uint8_t*)"keystore";
238         // sizeof = 9, not strlen = 8
239         saltSize = sizeof("keystore");
240     }
241 
242     PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt, saltSize,
243                            8192, keySize, key);
244 }
245 
generateSalt(Entropy * entropy)246 bool UserState::generateSalt(Entropy* entropy) {
247     return entropy->generate_random_data(mSalt, sizeof(mSalt));
248 }
249 
generateMasterKey(Entropy * entropy)250 bool UserState::generateMasterKey(Entropy* entropy) {
251     if (!entropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) {
252         return false;
253     }
254     if (!generateSalt(entropy)) {
255         return false;
256     }
257     return true;
258 }
259 
setupMasterKeys()260 void UserState::setupMasterKeys() {
261     AES_set_encrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyEncryption);
262     AES_set_decrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyDecryption);
263     setState(STATE_NO_ERROR);
264 }
265