blob: 5f9cd5f54b235b65976a277f51224486c049dee0 [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>
28
29#include <cutils/log.h>
30
31#include "blob.h"
32#include "keystore_utils.h"
33
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010034
35UserState::UserState(uid_t userId) :
36 mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070037 asprintf(&mUserDir, "user_%u", mUserId);
38 asprintf(&mMasterKeyFile, "%s/.masterkey", mUserDir);
39}
40
41UserState::~UserState() {
42 free(mUserDir);
43 free(mMasterKeyFile);
44}
45
46bool 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
61void UserState::setState(State state) {
62 mState = state;
63 if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
64 mRetry = MAX_RETRY;
65 }
66}
67
68void UserState::zeroizeMasterKeysInMemory() {
69 memset(mMasterKey, 0, sizeof(mMasterKey));
70 memset(mSalt, 0, sizeof(mSalt));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070071}
72
73bool UserState::deleteMasterKey() {
74 setState(STATE_UNINITIALIZED);
75 zeroizeMasterKeysInMemory();
76 return unlink(mMasterKeyFile) == 0 || errno == ENOENT;
77}
78
79ResponseCode UserState::initialize(const android::String8& pw, Entropy* entropy) {
80 if (!generateMasterKey(entropy)) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010081 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070082 }
83 ResponseCode response = writeMasterKey(pw, entropy);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010084 if (response != ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070085 return response;
86 }
87 setupMasterKeys();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010088 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070089}
90
91ResponseCode UserState::copyMasterKey(UserState* src) {
92 if (mState != STATE_UNINITIALIZED) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010093 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070094 }
95 if (src->getState() != STATE_NO_ERROR) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010096 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070097 }
98 memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES);
99 setupMasterKeys();
100 return copyMasterKeyFile(src);
101}
102
103ResponseCode 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) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100109 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700110 }
Shawn Willdene9830582017-04-18 10:47:57 -0600111 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700112 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
113 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100114 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700115 }
116 int out =
117 TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
118 if (out < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100119 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700120 }
121 size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length);
122 if (close(out) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100123 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700124 }
125 if (outLength != length) {
126 ALOGW("blob not fully written %zu != %zu", outLength, length);
127 unlink(mMasterKeyFile);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100128 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700129 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100130 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700131}
132
133ResponseCode 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);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700136 Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
Shawn Willdene9830582017-04-18 10:47:57 -0600137 return masterKeyBlob.writeBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR, entropy);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700138}
139
140ResponseCode UserState::readMasterKey(const android::String8& pw, Entropy* entropy) {
141 int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY));
142 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100143 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700144 }
145
146 // We read the raw blob to just to get the salt to generate the AES key, then we create the Blob
147 // to use with decryptBlob
Shawn Willdene9830582017-04-18 10:47:57 -0600148 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700149 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
150 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100151 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700152 }
153 // find salt at EOF if present, otherwise we have an old file
154 uint8_t* salt;
155 if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
156 salt = (uint8_t*)&rawBlob + length - SALT_SIZE;
157 } else {
158 salt = NULL;
159 }
160 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
161 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700162 Blob masterKeyBlob(rawBlob);
Shawn Willdene9830582017-04-18 10:47:57 -0600163 ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100164 if (response == ResponseCode::SYSTEM_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700165 return response;
166 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100167 if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700168 // If salt was missing, generate one and write a new master key file with the salt.
169 if (salt == NULL) {
170 if (!generateSalt(entropy)) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100171 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700172 }
173 response = writeMasterKey(pw, entropy);
174 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100175 if (response == ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700176 memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
177 setupMasterKeys();
178 }
179 return response;
180 }
181 if (mRetry <= 0) {
182 reset();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100183 return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700184 }
185 --mRetry;
186 switch (mRetry) {
187 case 0:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100188 return ResponseCode::WRONG_PASSWORD_0;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700189 case 1:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100190 return ResponseCode::WRONG_PASSWORD_1;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700191 case 2:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100192 return ResponseCode::WRONG_PASSWORD_2;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700193 case 3:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100194 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700195 default:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100196 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700197 }
198}
199
200bool UserState::reset() {
201 DIR* dir = opendir(getUserDirName());
202 if (!dir) {
203 // If the directory doesn't exist then nothing to do.
204 if (errno == ENOENT) {
205 return true;
206 }
207 ALOGW("couldn't open user directory: %s", strerror(errno));
208 return false;
209 }
210
211 struct dirent* file;
212 while ((file = readdir(dir)) != NULL) {
213 // skip . and ..
214 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
215 continue;
216 }
217
218 unlinkat(dirfd(dir), file->d_name, 0);
219 }
220 closedir(dir);
221 return true;
222}
223
224void UserState::generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw,
225 uint8_t* salt) {
226 size_t saltSize;
227 if (salt != NULL) {
228 saltSize = SALT_SIZE;
229 } else {
230 // Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
231 salt = (uint8_t*)"keystore";
232 // sizeof = 9, not strlen = 8
233 saltSize = sizeof("keystore");
234 }
235
236 PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt, saltSize,
237 8192, keySize, key);
238}
239
240bool UserState::generateSalt(Entropy* entropy) {
241 return entropy->generate_random_data(mSalt, sizeof(mSalt));
242}
243
244bool UserState::generateMasterKey(Entropy* entropy) {
245 if (!entropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) {
246 return false;
247 }
248 if (!generateSalt(entropy)) {
249 return false;
250 }
251 return true;
252}
253
254void UserState::setupMasterKeys() {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700255 setState(STATE_NO_ERROR);
256}