blob: 9fe1347d8b52dadf48d15eb78f9e1e3a13b31407 [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 Archer44d1afa2018-12-28 09:10:49 -080028#include <openssl/rand.h>
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070029
Logan Chiencdc813f2018-04-23 13:52:28 +080030#include <log/log.h>
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070031
32#include "blob.h"
33#include "keystore_utils.h"
34
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070035namespace keystore {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010036
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070037UserState::UserState(uid_t userId)
38 : mMasterKeyEntry(".masterkey", "user_" + std::to_string(userId), userId, /* masterkey */ true),
39 mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {}
40
41bool UserState::operator<(const UserState& rhs) const {
42 return getUserId() < rhs.getUserId();
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070043}
44
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070045bool UserState::operator<(uid_t userId) const {
46 return getUserId() < userId;
47}
48
49bool operator<(uid_t userId, const UserState& rhs) {
50 return userId < rhs.getUserId();
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070051}
52
53bool UserState::initialize() {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070054 if ((mkdir(mMasterKeyEntry.user_dir().c_str(), S_IRUSR | S_IWUSR | S_IXUSR) < 0) &&
55 (errno != EEXIST)) {
56 ALOGE("Could not create directory '%s'", mMasterKeyEntry.user_dir().c_str());
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070057 return false;
58 }
59
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070060 if (mMasterKeyEntry.hasKeyBlob()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070061 setState(STATE_LOCKED);
62 } else {
63 setState(STATE_UNINITIALIZED);
64 }
65
66 return true;
67}
68
69void UserState::setState(State state) {
70 mState = state;
71 if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
72 mRetry = MAX_RETRY;
73 }
74}
75
76void UserState::zeroizeMasterKeysInMemory() {
77 memset(mMasterKey, 0, sizeof(mMasterKey));
78 memset(mSalt, 0, sizeof(mSalt));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070079}
80
81bool UserState::deleteMasterKey() {
82 setState(STATE_UNINITIALIZED);
83 zeroizeMasterKeysInMemory();
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070084 return unlink(mMasterKeyEntry.getKeyBlobPath().c_str()) == 0 || errno == ENOENT;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070085}
86
Branden Archer44d1afa2018-12-28 09:10:49 -080087ResponseCode UserState::initialize(const android::String8& pw) {
88 if (!generateMasterKey()) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010089 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070090 }
Branden Archer44d1afa2018-12-28 09:10:49 -080091 ResponseCode response = writeMasterKey(pw);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010092 if (response != ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070093 return response;
94 }
95 setupMasterKeys();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +010096 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -070097}
98
Janis Danisevskisff3d7f42018-10-08 07:15:09 -070099ResponseCode UserState::copyMasterKey(LockedUserState<UserState>* src) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700100 if (mState != STATE_UNINITIALIZED) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100101 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700102 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700103 if ((*src)->getState() != STATE_NO_ERROR) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100104 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700105 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700106 memcpy(mMasterKey, (*src)->mMasterKey, MASTER_KEY_SIZE_BYTES);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700107 setupMasterKeys();
108 return copyMasterKeyFile(src);
109}
110
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700111ResponseCode UserState::copyMasterKeyFile(LockedUserState<UserState>* src) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700112 /* Copy the master key file to the new user. Unfortunately we don't have the src user's
113 * password so we cannot generate a new file with a new salt.
114 */
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700115 int in = TEMP_FAILURE_RETRY(open((*src)->getMasterKeyFileName().c_str(), O_RDONLY));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700116 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100117 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700118 }
Shawn Willdene9830582017-04-18 10:47:57 -0600119 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700120 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
121 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100122 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700123 }
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700124 int out = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(),
125 O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700126 if (out < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100127 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700128 }
129 size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length);
130 if (close(out) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100131 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700132 }
133 if (outLength != length) {
134 ALOGW("blob not fully written %zu != %zu", outLength, length);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700135 unlink(mMasterKeyEntry.getKeyBlobPath().c_str());
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100136 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700137 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100138 return ResponseCode::NO_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700139}
140
Branden Archer44d1afa2018-12-28 09:10:49 -0800141ResponseCode UserState::writeMasterKey(const android::String8& pw) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700142 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
143 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700144 Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700145 auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
Branden Archer44d1afa2018-12-28 09:10:49 -0800146 return lockedEntry.writeBlobs(masterKeyBlob, {}, passwordKey, STATE_NO_ERROR);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700147}
148
Branden Archer44d1afa2018-12-28 09:10:49 -0800149ResponseCode UserState::readMasterKey(const android::String8& pw) {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700150
151 auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
152
153 int in = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(), O_RDONLY));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700154 if (in < 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100155 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700156 }
157
158 // We read the raw blob to just to get the salt to generate the AES key, then we create the Blob
159 // to use with decryptBlob
Shawn Willdene9830582017-04-18 10:47:57 -0600160 blobv3 rawBlob;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700161 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
162 if (close(in) != 0) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100163 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700164 }
165 // find salt at EOF if present, otherwise we have an old file
166 uint8_t* salt;
167 if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
168 salt = (uint8_t*)&rawBlob + length - SALT_SIZE;
169 } else {
Yi Kongd2916752018-07-26 17:44:27 -0700170 salt = nullptr;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700171 }
172 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
173 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt);
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700174 Blob masterKeyBlob, dummyBlob;
175 ResponseCode response;
176 std::tie(response, masterKeyBlob, dummyBlob) =
177 lockedEntry.readBlobs(passwordKey, STATE_NO_ERROR);
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100178 if (response == ResponseCode::SYSTEM_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700179 return response;
180 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100181 if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700182 // If salt was missing, generate one and write a new master key file with the salt.
Yi Kongd2916752018-07-26 17:44:27 -0700183 if (salt == nullptr) {
Branden Archer44d1afa2018-12-28 09:10:49 -0800184 if (!generateSalt()) {
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100185 return ResponseCode::SYSTEM_ERROR;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700186 }
Branden Archer44d1afa2018-12-28 09:10:49 -0800187 response = writeMasterKey(pw);
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700188 }
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100189 if (response == ResponseCode::NO_ERROR) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700190 memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
191 setupMasterKeys();
192 }
193 return response;
194 }
195 if (mRetry <= 0) {
196 reset();
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100197 return ResponseCode::UNINITIALIZED;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700198 }
199 --mRetry;
200 switch (mRetry) {
201 case 0:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100202 return ResponseCode::WRONG_PASSWORD_0;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700203 case 1:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100204 return ResponseCode::WRONG_PASSWORD_1;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700205 case 2:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100206 return ResponseCode::WRONG_PASSWORD_2;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700207 case 3:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100208 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700209 default:
Janis Danisevskisc7a9fa22016-10-13 18:43:45 +0100210 return ResponseCode::WRONG_PASSWORD_3;
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700211 }
212}
213
214bool UserState::reset() {
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700215 DIR* dir = opendir(mMasterKeyEntry.user_dir().c_str());
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700216 if (!dir) {
217 // If the directory doesn't exist then nothing to do.
218 if (errno == ENOENT) {
219 return true;
220 }
221 ALOGW("couldn't open user directory: %s", strerror(errno));
222 return false;
223 }
224
225 struct dirent* file;
Yi Kongd2916752018-07-26 17:44:27 -0700226 while ((file = readdir(dir)) != nullptr) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700227 // skip . and ..
228 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
229 continue;
230 }
231
232 unlinkat(dirfd(dir), file->d_name, 0);
233 }
234 closedir(dir);
235 return true;
236}
237
238void UserState::generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw,
239 uint8_t* salt) {
240 size_t saltSize;
Yi Kongd2916752018-07-26 17:44:27 -0700241 if (salt != nullptr) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700242 saltSize = SALT_SIZE;
243 } else {
244 // Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
245 salt = (uint8_t*)"keystore";
246 // sizeof = 9, not strlen = 8
247 saltSize = sizeof("keystore");
248 }
249
250 PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt, saltSize,
251 8192, keySize, key);
252}
253
Branden Archer44d1afa2018-12-28 09:10:49 -0800254bool UserState::generateSalt() {
255 return RAND_bytes(mSalt, sizeof(mSalt));
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700256}
257
Branden Archer44d1afa2018-12-28 09:10:49 -0800258bool UserState::generateMasterKey() {
259 if (!RAND_bytes(mMasterKey, sizeof(mMasterKey))) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700260 return false;
261 }
Branden Archer44d1afa2018-12-28 09:10:49 -0800262 if (!generateSalt()) {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700263 return false;
264 }
265 return true;
266}
267
268void UserState::setupMasterKeys() {
Shawn Willdenc1d1fee2016-01-26 22:44:56 -0700269 setState(STATE_NO_ERROR);
270}
Janis Danisevskisff3d7f42018-10-08 07:15:09 -0700271
272LockedUserState<UserState> UserStateDB::getUserState(uid_t userId) {
273 std::unique_lock<std::mutex> lock(locked_state_mutex_);
274 decltype(mMasterKeys.begin()) it;
275 bool inserted;
276 std::tie(it, inserted) = mMasterKeys.emplace(userId, userId);
277 if (inserted) {
278 if (!it->second.initialize()) {
279 /* There's not much we can do if initialization fails. Trying to
280 * unlock the keystore for that user will fail as well, so any
281 * subsequent request for this user will just return SYSTEM_ERROR.
282 */
283 ALOGE("User initialization failed for %u; subsequent operations will fail", userId);
284 }
285 }
286 return get(std::move(lock), &it->second);
287}
288
289LockedUserState<UserState> UserStateDB::getUserStateByUid(uid_t uid) {
290 return getUserState(get_user_id(uid));
291}
292
293LockedUserState<const UserState> UserStateDB::getUserState(uid_t userId) const {
294 std::unique_lock<std::mutex> lock(locked_state_mutex_);
295 auto it = mMasterKeys.find(userId);
296 if (it == mMasterKeys.end()) return {};
297 return get(std::move(lock), &it->second);
298}
299
300LockedUserState<const UserState> UserStateDB::getUserStateByUid(uid_t uid) const {
301 return getUserState(get_user_id(uid));
302}
303
304} // namespace keystore