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