blob: b62598d126dac6553761232625afc963a7f8fde6 [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
27#include <openssl/evp.h>
Branden Archere489a032018-12-28 09:10:49 -080028#include <openssl/rand.h>
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070029
30#include <cutils/log.h>
31
32#include "blob.h"
33#include "keystore_utils.h"
34
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010035
36UserState::UserState(uid_t userId) :
37 mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070038 asprintf(&mUserDir, "user_%u", mUserId);
39 asprintf(&mMasterKeyFile, "%s/.masterkey", mUserDir);
40}
41
42UserState::~UserState() {
43 free(mUserDir);
44 free(mMasterKeyFile);
45}
46
47bool UserState::initialize() {
48 if ((mkdir(mUserDir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) && (errno != EEXIST)) {
49 ALOGE("Could not create directory '%s'", mUserDir);
50 return false;
51 }
52
53 if (access(mMasterKeyFile, R_OK) == 0) {
54 setState(STATE_LOCKED);
55 } else {
56 setState(STATE_UNINITIALIZED);
57 }
58
59 return true;
60}
61
62void UserState::setState(State state) {
63 mState = state;
64 if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
65 mRetry = MAX_RETRY;
66 }
67}
68
69void UserState::zeroizeMasterKeysInMemory() {
70 memset(mMasterKey, 0, sizeof(mMasterKey));
71 memset(mSalt, 0, sizeof(mSalt));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070072}
73
74bool UserState::deleteMasterKey() {
75 setState(STATE_UNINITIALIZED);
76 zeroizeMasterKeysInMemory();
77 return unlink(mMasterKeyFile) == 0 || errno == ENOENT;
78}
79
Branden Archere489a032018-12-28 09:10:49 -080080ResponseCode UserState::initialize(const android::String8& pw) {
81 if (!generateMasterKey()) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010082 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070083 }
Branden Archere489a032018-12-28 09:10:49 -080084 ResponseCode response = writeMasterKey(pw);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010085 if (response != ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070086 return response;
87 }
88 setupMasterKeys();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010089 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070090}
91
92ResponseCode UserState::copyMasterKey(UserState* src) {
93 if (mState != STATE_UNINITIALIZED) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010094 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070095 }
96 if (src->getState() != STATE_NO_ERROR) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010097 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070098 }
99 memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES);
100 setupMasterKeys();
101 return copyMasterKeyFile(src);
102}
103
104ResponseCode UserState::copyMasterKeyFile(UserState* src) {
105 /* Copy the master key file to the new user. Unfortunately we don't have the src user's
106 * password so we cannot generate a new file with a new salt.
107 */
108 int in = TEMP_FAILURE_RETRY(open(src->getMasterKeyFileName(), O_RDONLY));
109 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100110 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700111 }
Shawn Willdene9830582017-04-18 10:47:57 -0600112 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700113 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
114 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100115 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700116 }
117 int out =
118 TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
119 if (out < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100120 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700121 }
122 size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length);
123 if (close(out) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100124 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700125 }
126 if (outLength != length) {
127 ALOGW("blob not fully written %zu != %zu", outLength, length);
128 unlink(mMasterKeyFile);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100129 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700130 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100131 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700132}
133
Branden Archere489a032018-12-28 09:10:49 -0800134ResponseCode UserState::writeMasterKey(const android::String8& pw) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700135 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
136 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700137 Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
Branden Archere489a032018-12-28 09:10:49 -0800138 return masterKeyBlob.writeBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700139}
140
Branden Archere489a032018-12-28 09:10:49 -0800141ResponseCode UserState::readMasterKey(const android::String8& pw) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700142 int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY));
143 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100144 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700145 }
146
147 // We read the raw blob to just to get the salt to generate the AES key, then we create the Blob
148 // to use with decryptBlob
Shawn Willdene9830582017-04-18 10:47:57 -0600149 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700150 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
151 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100152 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700153 }
154 // find salt at EOF if present, otherwise we have an old file
155 uint8_t* salt;
156 if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
157 salt = (uint8_t*)&rawBlob + length - SALT_SIZE;
158 } else {
159 salt = NULL;
160 }
161 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
162 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700163 Blob masterKeyBlob(rawBlob);
Shawn Willdene9830582017-04-18 10:47:57 -0600164 ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100165 if (response == ResponseCode::SYSTEM_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700166 return response;
167 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100168 if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700169 // If salt was missing, generate one and write a new master key file with the salt.
170 if (salt == NULL) {
Branden Archere489a032018-12-28 09:10:49 -0800171 if (!generateSalt()) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100172 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700173 }
Branden Archere489a032018-12-28 09:10:49 -0800174 response = writeMasterKey(pw);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700175 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100176 if (response == ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700177 memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
178 setupMasterKeys();
179 }
180 return response;
181 }
182 if (mRetry <= 0) {
183 reset();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100184 return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700185 }
186 --mRetry;
187 switch (mRetry) {
188 case 0:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100189 return ResponseCode::WRONG_PASSWORD_0;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700190 case 1:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100191 return ResponseCode::WRONG_PASSWORD_1;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700192 case 2:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100193 return ResponseCode::WRONG_PASSWORD_2;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700194 case 3:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100195 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700196 default:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100197 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700198 }
199}
200
201bool UserState::reset() {
202 DIR* dir = opendir(getUserDirName());
203 if (!dir) {
204 // If the directory doesn't exist then nothing to do.
205 if (errno == ENOENT) {
206 return true;
207 }
208 ALOGW("couldn't open user directory: %s", strerror(errno));
209 return false;
210 }
211
212 struct dirent* file;
213 while ((file = readdir(dir)) != NULL) {
214 // skip . and ..
215 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
216 continue;
217 }
218
219 unlinkat(dirfd(dir), file->d_name, 0);
220 }
221 closedir(dir);
222 return true;
223}
224
225void UserState::generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw,
226 uint8_t* salt) {
227 size_t saltSize;
228 if (salt != NULL) {
229 saltSize = SALT_SIZE;
230 } else {
231 // Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
232 salt = (uint8_t*)"keystore";
233 // sizeof = 9, not strlen = 8
234 saltSize = sizeof("keystore");
235 }
236
237 PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt, saltSize,
238 8192, keySize, key);
239}
240
Branden Archere489a032018-12-28 09:10:49 -0800241bool UserState::generateSalt() {
242 return RAND_bytes(mSalt, sizeof(mSalt));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700243}
244
Branden Archere489a032018-12-28 09:10:49 -0800245bool UserState::generateMasterKey() {
246 if (!RAND_bytes(mMasterKey, sizeof(mMasterKey))) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700247 return false;
248 }
Branden Archere489a032018-12-28 09:10:49 -0800249 if (!generateSalt()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700250 return false;
251 }
252 return true;
253}
254
255void UserState::setupMasterKeys() {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700256 setState(STATE_NO_ERROR);
257}