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