1/* 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 34 35UserState::UserState(uid_t userId) : 36 mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) { 37 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)); 71 memset(&mMasterKeyEncryption, 0, sizeof(mMasterKeyEncryption)); 72 memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption)); 73} 74 75bool UserState::deleteMasterKey() { 76 setState(STATE_UNINITIALIZED); 77 zeroizeMasterKeysInMemory(); 78 return unlink(mMasterKeyFile) == 0 || errno == ENOENT; 79} 80 81ResponseCode UserState::initialize(const android::String8& pw, Entropy* entropy) { 82 if (!generateMasterKey(entropy)) { 83 return ResponseCode::SYSTEM_ERROR; 84 } 85 ResponseCode response = writeMasterKey(pw, entropy); 86 if (response != ResponseCode::NO_ERROR) { 87 return response; 88 } 89 setupMasterKeys(); 90 return ResponseCode::NO_ERROR; 91} 92 93ResponseCode UserState::copyMasterKey(UserState* src) { 94 if (mState != STATE_UNINITIALIZED) { 95 return ResponseCode::SYSTEM_ERROR; 96 } 97 if (src->getState() != STATE_NO_ERROR) { 98 return ResponseCode::SYSTEM_ERROR; 99 } 100 memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES); 101 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) { 111 return ResponseCode::SYSTEM_ERROR; 112 } 113 blob rawBlob; 114 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob)); 115 if (close(in) != 0) { 116 return ResponseCode::SYSTEM_ERROR; 117 } 118 int out = 119 TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)); 120 if (out < 0) { 121 return ResponseCode::SYSTEM_ERROR; 122 } 123 size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length); 124 if (close(out) != 0) { 125 return ResponseCode::SYSTEM_ERROR; 126 } 127 if (outLength != length) { 128 ALOGW("blob not fully written %zu != %zu", outLength, length); 129 unlink(mMasterKeyFile); 130 return ResponseCode::SYSTEM_ERROR; 131 } 132 return ResponseCode::NO_ERROR; 133} 134 135ResponseCode UserState::writeMasterKey(const android::String8& pw, Entropy* entropy) { 136 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES]; 137 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt); 138 AES_KEY passwordAesKey; 139 AES_set_encrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey); 140 Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY); 141 return masterKeyBlob.writeBlob(mMasterKeyFile, &passwordAesKey, STATE_NO_ERROR, entropy); 142} 143 144ResponseCode UserState::readMasterKey(const android::String8& pw, Entropy* entropy) { 145 int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY)); 146 if (in < 0) { 147 return ResponseCode::SYSTEM_ERROR; 148 } 149 150 // We read the raw blob to just to get the salt to generate the AES key, then we create the Blob 151 // to use with decryptBlob 152 blob rawBlob; 153 size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob)); 154 if (close(in) != 0) { 155 return ResponseCode::SYSTEM_ERROR; 156 } 157 // find salt at EOF if present, otherwise we have an old file 158 uint8_t* salt; 159 if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) { 160 salt = (uint8_t*)&rawBlob + length - SALT_SIZE; 161 } else { 162 salt = NULL; 163 } 164 uint8_t passwordKey[MASTER_KEY_SIZE_BYTES]; 165 generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt); 166 AES_KEY passwordAesKey; 167 AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey); 168 Blob masterKeyBlob(rawBlob); 169 ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, &passwordAesKey, STATE_NO_ERROR); 170 if (response == ResponseCode::SYSTEM_ERROR) { 171 return response; 172 } 173 if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) { 174 // If salt was missing, generate one and write a new master key file with the salt. 175 if (salt == NULL) { 176 if (!generateSalt(entropy)) { 177 return ResponseCode::SYSTEM_ERROR; 178 } 179 response = writeMasterKey(pw, entropy); 180 } 181 if (response == ResponseCode::NO_ERROR) { 182 memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES); 183 setupMasterKeys(); 184 } 185 return response; 186 } 187 if (mRetry <= 0) { 188 reset(); 189 return ResponseCode::UNINITIALIZED; 190 } 191 --mRetry; 192 switch (mRetry) { 193 case 0: 194 return ResponseCode::WRONG_PASSWORD_0; 195 case 1: 196 return ResponseCode::WRONG_PASSWORD_1; 197 case 2: 198 return ResponseCode::WRONG_PASSWORD_2; 199 case 3: 200 return ResponseCode::WRONG_PASSWORD_3; 201 default: 202 return ResponseCode::WRONG_PASSWORD_3; 203 } 204} 205 206bool UserState::reset() { 207 DIR* dir = opendir(getUserDirName()); 208 if (!dir) { 209 // If the directory doesn't exist then nothing to do. 210 if (errno == ENOENT) { 211 return true; 212 } 213 ALOGW("couldn't open user directory: %s", strerror(errno)); 214 return false; 215 } 216 217 struct dirent* file; 218 while ((file = readdir(dir)) != NULL) { 219 // skip . and .. 220 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) { 221 continue; 222 } 223 224 unlinkat(dirfd(dir), file->d_name, 0); 225 } 226 closedir(dir); 227 return true; 228} 229 230void UserState::generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw, 231 uint8_t* salt) { 232 size_t saltSize; 233 if (salt != NULL) { 234 saltSize = SALT_SIZE; 235 } else { 236 // Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found 237 salt = (uint8_t*)"keystore"; 238 // sizeof = 9, not strlen = 8 239 saltSize = sizeof("keystore"); 240 } 241 242 PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt, saltSize, 243 8192, keySize, key); 244} 245 246bool UserState::generateSalt(Entropy* entropy) { 247 return entropy->generate_random_data(mSalt, sizeof(mSalt)); 248} 249 250bool UserState::generateMasterKey(Entropy* entropy) { 251 if (!entropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) { 252 return false; 253 } 254 if (!generateSalt(entropy)) { 255 return false; 256 } 257 return true; 258} 259 260void UserState::setupMasterKeys() { 261 AES_set_encrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyEncryption); 262 AES_set_decrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyDecryption); 263 setState(STATE_NO_ERROR); 264} 265