blob: b482efd26e15d4c12d6d8bbe7359eeb3dff71438 [file] [log] [blame]
Shawn Willdenc1d1fee2016-01-26 22:44:56 -07001/*
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
Branden Archer020d5352018-12-28 12:24:53 -080027#include <openssl/digest.h>
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070028#include <openssl/evp.h>
Branden Archere489a032018-12-28 09:10:49 -080029#include <openssl/rand.h>
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070030
31#include <cutils/log.h>
32
33#include "blob.h"
34#include "keystore_utils.h"
35
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010036
37UserState::UserState(uid_t userId) :
38 mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070039 asprintf(&mUserDir, "user_%u", mUserId);
40 asprintf(&mMasterKeyFile, "%s/.masterkey", mUserDir);
41}
42
43UserState::~UserState() {
44 free(mUserDir);
45 free(mMasterKeyFile);
46}
47
48bool UserState::initialize() {
49 if ((mkdir(mUserDir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) && (errno != EEXIST)) {
50 ALOGE("Could not create directory '%s'", mUserDir);
51 return false;
52 }
53
54 if (access(mMasterKeyFile, R_OK) == 0) {
55 setState(STATE_LOCKED);
56 } else {
57 setState(STATE_UNINITIALIZED);
58 }
59
60 return true;
61}
62
63void UserState::setState(State state) {
64 mState = state;
65 if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
66 mRetry = MAX_RETRY;
67 }
68}
69
70void UserState::zeroizeMasterKeysInMemory() {
Branden Archera7a29fa2019-01-10 09:24:14 -080071 memset(mMasterKey.data(), 0, mMasterKey.size());
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070072 memset(mSalt, 0, sizeof(mSalt));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070073}
74
75bool UserState::deleteMasterKey() {
76 setState(STATE_UNINITIALIZED);
77 zeroizeMasterKeysInMemory();
78 return unlink(mMasterKeyFile) == 0 || errno == ENOENT;
79}
80
Branden Archere489a032018-12-28 09:10:49 -080081ResponseCode UserState::initialize(const android::String8& pw) {
82 if (!generateMasterKey()) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010083 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070084 }
Branden Archere489a032018-12-28 09:10:49 -080085 ResponseCode response = writeMasterKey(pw);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010086 if (response != ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070087 return response;
88 }
89 setupMasterKeys();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010090 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070091}
92
93ResponseCode UserState::copyMasterKey(UserState* src) {
94 if (mState != STATE_UNINITIALIZED) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010095 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070096 }
97 if (src->getState() != STATE_NO_ERROR) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010098 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070099 }
Branden Archera7a29fa2019-01-10 09:24:14 -0800100 mMasterKey = src->mMasterKey;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700101 setupMasterKeys();
102 return copyMasterKeyFile(src);
103}
104
105ResponseCode 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) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100111 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700112 }
Shawn Willdene9830582017-04-18 10:47:57 -0600113 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700114 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
115 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100116 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700117 }
118 int out =
119 TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
120 if (out < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100121 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700122 }
123 size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length);
124 if (close(out) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100125 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700126 }
127 if (outLength != length) {
128 ALOGW("blob not fully written %zu != %zu", outLength, length);
129 unlink(mMasterKeyFile);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100130 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700131 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100132 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700133}
134
Branden Archere489a032018-12-28 09:10:49 -0800135ResponseCode UserState::writeMasterKey(const android::String8& pw) {
Branden Archera7a29fa2019-01-10 09:24:14 -0800136 std::vector<uint8_t> passwordKey(MASTER_KEY_SIZE_BYTES);
137 generateKeyFromPassword(passwordKey, pw, mSalt);
138 Blob masterKeyBlob(mMasterKey.data(), mMasterKey.size(), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
Branden Archere489a032018-12-28 09:10:49 -0800139 return masterKeyBlob.writeBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700140}
141
Branden Archere489a032018-12-28 09:10:49 -0800142ResponseCode UserState::readMasterKey(const android::String8& pw) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700143 int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY));
144 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100145 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700146 }
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
Shawn Willdene9830582017-04-18 10:47:57 -0600150 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700151 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
152 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100153 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700154 }
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 }
Branden Archera7a29fa2019-01-10 09:24:14 -0800162 std::vector<uint8_t> passwordKey(MASTER_KEY_SIZE_BYTES);
163 generateKeyFromPassword(passwordKey, pw, salt);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700164 Blob masterKeyBlob(rawBlob);
Shawn Willdene9830582017-04-18 10:47:57 -0600165 ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100166 if (response == ResponseCode::SYSTEM_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700167 return response;
168 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100169 if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700170 // If salt was missing, generate one and write a new master key file with the salt.
171 if (salt == NULL) {
Branden Archere489a032018-12-28 09:10:49 -0800172 if (!generateSalt()) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100173 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700174 }
Branden Archere489a032018-12-28 09:10:49 -0800175 response = writeMasterKey(pw);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700176 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100177 if (response == ResponseCode::NO_ERROR) {
Branden Archera7a29fa2019-01-10 09:24:14 -0800178 mMasterKey = std::vector<uint8_t>(masterKeyBlob.getValue(),
179 masterKeyBlob.getValue() + masterKeyBlob.getLength());
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700180 setupMasterKeys();
181 }
182 return response;
183 }
184 if (mRetry <= 0) {
185 reset();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100186 return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700187 }
188 --mRetry;
189 switch (mRetry) {
190 case 0:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100191 return ResponseCode::WRONG_PASSWORD_0;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700192 case 1:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100193 return ResponseCode::WRONG_PASSWORD_1;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700194 case 2:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100195 return ResponseCode::WRONG_PASSWORD_2;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700196 case 3:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100197 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700198 default:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100199 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700200 }
201}
202
203bool UserState::reset() {
204 DIR* dir = opendir(getUserDirName());
205 if (!dir) {
206 // If the directory doesn't exist then nothing to do.
207 if (errno == ENOENT) {
208 return true;
209 }
210 ALOGW("couldn't open user directory: %s", strerror(errno));
211 return false;
212 }
213
214 struct dirent* file;
215 while ((file = readdir(dir)) != NULL) {
216 // skip . and ..
217 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
218 continue;
219 }
220
221 unlinkat(dirfd(dir), file->d_name, 0);
222 }
223 closedir(dir);
224 return true;
225}
226
Branden Archera7a29fa2019-01-10 09:24:14 -0800227void UserState::generateKeyFromPassword(std::vector<uint8_t>& key, const android::String8& pw,
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700228 uint8_t* salt) {
229 size_t saltSize;
230 if (salt != NULL) {
231 saltSize = SALT_SIZE;
232 } else {
233 // Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
234 salt = (uint8_t*)"keystore";
235 // sizeof = 9, not strlen = 8
236 saltSize = sizeof("keystore");
237 }
238
Branden Archer020d5352018-12-28 12:24:53 -0800239 const EVP_MD* digest = EVP_sha256();
240
241 // SHA1 was used prior to increasing the key size
Branden Archera7a29fa2019-01-10 09:24:14 -0800242 if (key.size() == SHA1_DIGEST_SIZE_BYTES) {
Branden Archer020d5352018-12-28 12:24:53 -0800243 digest = EVP_sha1();
244 }
245
246 PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(pw.string()), pw.length(), salt, saltSize, 8192,
Branden Archera7a29fa2019-01-10 09:24:14 -0800247 digest, key.size(), key.data());
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700248}
249
Branden Archere489a032018-12-28 09:10:49 -0800250bool UserState::generateSalt() {
251 return RAND_bytes(mSalt, sizeof(mSalt));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700252}
253
Branden Archere489a032018-12-28 09:10:49 -0800254bool UserState::generateMasterKey() {
Branden Archera7a29fa2019-01-10 09:24:14 -0800255 mMasterKey.resize(MASTER_KEY_SIZE_BYTES);
256 if (!RAND_bytes(mMasterKey.data(), mMasterKey.size())) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700257 return false;
258 }
Branden Archere489a032018-12-28 09:10:49 -0800259 if (!generateSalt()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700260 return false;
261 }
262 return true;
263}
264
265void UserState::setupMasterKeys() {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700266 setState(STATE_NO_ERROR);
267}