blob: c9a2d7220d422aa8c0410f1a0bba43d5552dcd95 [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
Logan Chiencdc813f2018-04-23 13:52:28 +080029#include <log/log.h>
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070030
31#include "blob.h"
32#include "keystore_utils.h"
33
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070034namespace keystore {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010035
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070036UserState::UserState(uid_t userId)
37 : mMasterKeyEntry(".masterkey", "user_" + std::to_string(userId), userId, /* masterkey */ true),
38 mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {}
39
40bool UserState::operator<(const UserState& rhs) const {
41 return getUserId() < rhs.getUserId();
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070042}
43
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070044bool UserState::operator<(uid_t userId) const {
45 return getUserId() < userId;
46}
47
48bool operator<(uid_t userId, const UserState& rhs) {
49 return userId < rhs.getUserId();
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070050}
51
52bool UserState::initialize() {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070053 if ((mkdir(mMasterKeyEntry.user_dir().c_str(), S_IRUSR | S_IWUSR | S_IXUSR) < 0) &&
54 (errno != EEXIST)) {
55 ALOGE("Could not create directory '%s'", mMasterKeyEntry.user_dir().c_str());
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070056 return false;
57 }
58
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070059 if (mMasterKeyEntry.hasKeyBlob()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070060 setState(STATE_LOCKED);
61 } else {
62 setState(STATE_UNINITIALIZED);
63 }
64
65 return true;
66}
67
68void UserState::setState(State state) {
69 mState = state;
70 if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
71 mRetry = MAX_RETRY;
72 }
73}
74
75void UserState::zeroizeMasterKeysInMemory() {
76 memset(mMasterKey, 0, sizeof(mMasterKey));
77 memset(mSalt, 0, sizeof(mSalt));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070078}
79
80bool UserState::deleteMasterKey() {
81 setState(STATE_UNINITIALIZED);
82 zeroizeMasterKeysInMemory();
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070083 return unlink(mMasterKeyEntry.getKeyBlobPath().c_str()) == 0 || errno == ENOENT;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070084}
85
86ResponseCode UserState::initialize(const android::String8& pw, Entropy* entropy) {
87 if (!generateMasterKey(entropy)) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010088 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070089 }
90 ResponseCode response = writeMasterKey(pw, entropy);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010091 if (response != ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070092 return response;
93 }
94 setupMasterKeys();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010095 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070096}
97
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070098ResponseCode UserState::copyMasterKey(LockedUserState<UserState>* src) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070099 if (mState != STATE_UNINITIALIZED) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100100 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700101 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700102 if ((*src)->getState() != STATE_NO_ERROR) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100103 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700104 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700105 memcpy(mMasterKey, (*src)->mMasterKey, MASTER_KEY_SIZE_BYTES);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700106 setupMasterKeys();
107 return copyMasterKeyFile(src);
108}
109
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700110ResponseCode UserState::copyMasterKeyFile(LockedUserState<UserState>* src) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700111 /* Copy the master key file to the new user. Unfortunately we don't have the src user's
112 * password so we cannot generate a new file with a new salt.
113 */
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700114 int in = TEMP_FAILURE_RETRY(open((*src)->getMasterKeyFileName().c_str(), O_RDONLY));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700115 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100116 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700117 }
Shawn Willdene9830582017-04-18 10:47:57 -0600118 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700119 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
120 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100121 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700122 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700123 int out = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(),
124 O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700125 if (out < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100126 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700127 }
128 size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length);
129 if (close(out) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100130 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700131 }
132 if (outLength != length) {
133 ALOGW("blob not fully written %zu != %zu", outLength, length);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700134 unlink(mMasterKeyEntry.getKeyBlobPath().c_str());
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100135 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700136 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100137 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700138}
139
140ResponseCode UserState::writeMasterKey(const android::String8& pw, Entropy* entropy) {
141 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
142 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700143 Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700144 auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
145 return lockedEntry.writeBlobs(masterKeyBlob, {}, passwordKey, STATE_NO_ERROR, entropy);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700146}
147
148ResponseCode UserState::readMasterKey(const android::String8& pw, Entropy* entropy) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700149
150 auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
151
152 int in = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(), O_RDONLY));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700153 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100154 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700155 }
156
157 // We read the raw blob to just to get the salt to generate the AES key, then we create the Blob
158 // to use with decryptBlob
Shawn Willdene9830582017-04-18 10:47:57 -0600159 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700160 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
161 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100162 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700163 }
164 // find salt at EOF if present, otherwise we have an old file
165 uint8_t* salt;
166 if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
167 salt = (uint8_t*)&rawBlob + length - SALT_SIZE;
168 } else {
Yi Kongd2916752018-07-26 17:44:27 -0700169 salt = nullptr;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700170 }
171 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
172 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700173 Blob masterKeyBlob, dummyBlob;
174 ResponseCode response;
175 std::tie(response, masterKeyBlob, dummyBlob) =
176 lockedEntry.readBlobs(passwordKey, STATE_NO_ERROR);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100177 if (response == ResponseCode::SYSTEM_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700178 return response;
179 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100180 if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700181 // If salt was missing, generate one and write a new master key file with the salt.
Yi Kongd2916752018-07-26 17:44:27 -0700182 if (salt == nullptr) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700183 if (!generateSalt(entropy)) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100184 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700185 }
186 response = writeMasterKey(pw, entropy);
187 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100188 if (response == ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700189 memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
190 setupMasterKeys();
191 }
192 return response;
193 }
194 if (mRetry <= 0) {
195 reset();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100196 return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700197 }
198 --mRetry;
199 switch (mRetry) {
200 case 0:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100201 return ResponseCode::WRONG_PASSWORD_0;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700202 case 1:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100203 return ResponseCode::WRONG_PASSWORD_1;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700204 case 2:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100205 return ResponseCode::WRONG_PASSWORD_2;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700206 case 3:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100207 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700208 default:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100209 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700210 }
211}
212
213bool UserState::reset() {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700214 DIR* dir = opendir(mMasterKeyEntry.user_dir().c_str());
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700215 if (!dir) {
216 // If the directory doesn't exist then nothing to do.
217 if (errno == ENOENT) {
218 return true;
219 }
220 ALOGW("couldn't open user directory: %s", strerror(errno));
221 return false;
222 }
223
224 struct dirent* file;
Yi Kongd2916752018-07-26 17:44:27 -0700225 while ((file = readdir(dir)) != nullptr) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700226 // skip . and ..
227 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
228 continue;
229 }
230
231 unlinkat(dirfd(dir), file->d_name, 0);
232 }
233 closedir(dir);
234 return true;
235}
236
237void UserState::generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw,
238 uint8_t* salt) {
239 size_t saltSize;
Yi Kongd2916752018-07-26 17:44:27 -0700240 if (salt != nullptr) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700241 saltSize = SALT_SIZE;
242 } else {
243 // Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
244 salt = (uint8_t*)"keystore";
245 // sizeof = 9, not strlen = 8
246 saltSize = sizeof("keystore");
247 }
248
249 PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt, saltSize,
250 8192, keySize, key);
251}
252
253bool UserState::generateSalt(Entropy* entropy) {
254 return entropy->generate_random_data(mSalt, sizeof(mSalt));
255}
256
257bool UserState::generateMasterKey(Entropy* entropy) {
258 if (!entropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) {
259 return false;
260 }
261 if (!generateSalt(entropy)) {
262 return false;
263 }
264 return true;
265}
266
267void UserState::setupMasterKeys() {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700268 setState(STATE_NO_ERROR);
269}
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700270
271LockedUserState<UserState> UserStateDB::getUserState(uid_t userId) {
272 std::unique_lock<std::mutex> lock(locked_state_mutex_);
273 decltype(mMasterKeys.begin()) it;
274 bool inserted;
275 std::tie(it, inserted) = mMasterKeys.emplace(userId, userId);
276 if (inserted) {
277 if (!it->second.initialize()) {
278 /* There's not much we can do if initialization fails. Trying to
279 * unlock the keystore for that user will fail as well, so any
280 * subsequent request for this user will just return SYSTEM_ERROR.
281 */
282 ALOGE("User initialization failed for %u; subsequent operations will fail", userId);
283 }
284 }
285 return get(std::move(lock), &it->second);
286}
287
288LockedUserState<UserState> UserStateDB::getUserStateByUid(uid_t uid) {
289 return getUserState(get_user_id(uid));
290}
291
292LockedUserState<const UserState> UserStateDB::getUserState(uid_t userId) const {
293 std::unique_lock<std::mutex> lock(locked_state_mutex_);
294 auto it = mMasterKeys.find(userId);
295 if (it == mMasterKeys.end()) return {};
296 return get(std::move(lock), &it->second);
297}
298
299LockedUserState<const UserState> UserStateDB::getUserStateByUid(uid_t uid) const {
300 return getUserState(get_user_id(uid));
301}
302
303} // namespace keystore