diff options
Diffstat (limited to 'keystore/KeyStore.cpp')
-rw-r--r-- | keystore/KeyStore.cpp | 512 |
1 files changed, 0 insertions, 512 deletions
diff --git a/keystore/KeyStore.cpp b/keystore/KeyStore.cpp deleted file mode 100644 index 1f808997..00000000 --- a/keystore/KeyStore.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "keystore" - -#include "KeyStore.h" - -#include <dirent.h> -#include <fcntl.h> - -#include <openssl/bio.h> - -#include <utils/String16.h> -#include <utils/String8.h> - -#include <android-base/scopeguard.h> -#include <android/hardware/keymaster/3.0/IKeymasterDevice.h> -#include <android/security/keystore/IKeystoreService.h> -#include <log/log_event_list.h> - -#include <private/android_logger.h> - -#include "keystore_utils.h" -#include "permissions.h" -#include <keystore/keystore_hidl_support.h> - -#include "keymaster_worker.h" - -namespace keystore { - -const char* KeyStore::kOldMasterKey = ".masterkey"; -const char* KeyStore::kMetaDataFile = ".metadata"; - -const android::String16 KeyStore::kRsaKeyType("RSA"); -const android::String16 KeyStore::kEcKeyType("EC"); - -using android::String8; - -KeyStore::KeyStore(const KeymasterDevices& kmDevices, - SecurityLevel minimalAllowedSecurityLevelForNewKeys) - : mAllowNewFallback(minimalAllowedSecurityLevelForNewKeys == SecurityLevel::SOFTWARE), - mConfirmationManager(new ConfirmationManager(this)) { - memset(&mMetaData, '\0', sizeof(mMetaData)); - - static_assert(std::tuple_size<std::decay_t<decltype(kmDevices)>>::value == - std::tuple_size<decltype(mKmDevices)>::value, - "KmasterDevices and KeymasterWorkers must have the same size"); - for (size_t i = 0; i < kmDevices.size(); ++i) { - if (kmDevices[SecurityLevel(i)]) { - mKmDevices[SecurityLevel(i)] = std::make_shared<KeymasterWorker>( - kmDevices[SecurityLevel(i)], this, SecurityLevel(i)); - } - } -} - -KeyStore::~KeyStore() { -} - -ResponseCode KeyStore::initialize() { - readMetaData(); - if (upgradeKeystore()) { - writeMetaData(); - } - - return ResponseCode::NO_ERROR; -} - -ResponseCode KeyStore::initializeUser(const android::String8& pw, uid_t userId) { - auto userState = mUserStateDB.getUserState(userId); - return userState->initialize(pw); -} - -ResponseCode KeyStore::copyMasterKey(uid_t srcUser, uid_t dstUser) { - auto userState = mUserStateDB.getUserState(dstUser); - auto initState = mUserStateDB.getUserState(srcUser); - return userState->copyMasterKey(&initState); -} - -ResponseCode KeyStore::writeMasterKey(const android::String8& pw, uid_t userId) { - auto userState = mUserStateDB.getUserState(userId); - return userState->writeMasterKey(pw); -} - -ResponseCode KeyStore::readMasterKey(const android::String8& pw, uid_t userId) { - auto userState = mUserStateDB.getUserState(userId); - return userState->readMasterKey(pw); -} - -LockedKeyBlobEntry KeyStore::getLockedBlobEntryIfNotExists(const std::string& alias, uid_t uid) { - KeyBlobEntry kbe(alias, mUserStateDB.getUserStateByUid(uid)->getUserDirName(), uid); - auto result = LockedKeyBlobEntry::get(std::move(kbe)); - if (result->hasKeyBlob()) return {}; - return result; -} - -std::optional<KeyBlobEntry> KeyStore::getBlobEntryIfExists(const std::string& alias, uid_t uid) { - KeyBlobEntry kbe(alias, mUserStateDB.getUserStateByUid(uid)->getUserDirName(), uid); - if (kbe.hasKeyBlob()) return kbe; - - // If this is one of the legacy UID->UID mappings, use it. - uid_t euid = get_keystore_euid(uid); - if (euid != uid) { - kbe = KeyBlobEntry(alias, mUserStateDB.getUserStateByUid(euid)->getUserDirName(), euid); - if (kbe.hasKeyBlob()) return kbe; - } - - // They might be using a granted key. - auto grant = mGrants.get(uid, alias); - if (grant) { - kbe = grant->entry_; - if (kbe.hasKeyBlob()) return kbe; - } - return {}; -} -LockedKeyBlobEntry KeyStore::getLockedBlobEntryIfExists(const std::string& alias, uid_t uid) { - auto blobentry = getBlobEntryIfExists(alias, uid); - if (!blobentry) return {}; - LockedKeyBlobEntry lockedentry = LockedKeyBlobEntry::get(std::move(*blobentry)); - if (!lockedentry || !lockedentry->hasKeyBlob()) return {}; - return lockedentry; -} - -void KeyStore::resetUser(uid_t userId, bool keepUnenryptedEntries) { - android::String8 prefix(""); - android::Vector<android::String16> aliases; - - auto userState = mUserStateDB.getUserState(userId); - std::string userDirName = userState->getUserDirName(); - auto encryptionKey = userState->getEncryptionKey(); - auto state = userState->getState(); - // userState is a proxy that holds a lock which may be required by a worker. - // LockedKeyBlobEntry::list has a fence that waits until all workers have finished which may - // not happen if a user state lock is held. The following line relinquishes the lock. - userState = {}; - - ResponseCode rc; - std::list<LockedKeyBlobEntry> matches; - - // must not be called by a keymaster worker. List waits for workers to relinquish all access - // to blob entries - std::tie(rc, matches) = LockedKeyBlobEntry::list(userDirName); - if (rc != ResponseCode::NO_ERROR) { - return; - } - - for (LockedKeyBlobEntry& lockedEntry : matches) { - bool shouldDelete = true; - - if (keepUnenryptedEntries) { - Blob blob; - Blob charBlob; - ResponseCode rc; - - std::tie(rc, blob, charBlob) = lockedEntry.readBlobs(encryptionKey, state); - - switch (rc) { - case ResponseCode::SYSTEM_ERROR: - case ResponseCode::VALUE_CORRUPTED: - // If we can't read blobs, delete them. - shouldDelete = true; - break; - - case ResponseCode::NO_ERROR: - case ResponseCode::LOCKED: - // Delete encrypted blobs but keep unencrypted blobs and super-encrypted blobs. We - // need to keep super-encrypted blobs so we can report that the user is - // unauthenticated if a caller tries to use them, rather than reporting that they - // don't exist. - shouldDelete = blob.isEncrypted(); - break; - - default: - ALOGE("Got unexpected return code %d from readBlobs", rc); - // This shouldn't happen. To be on the safe side, delete it. - shouldDelete = true; - break; - } - } - if (shouldDelete) { - del(lockedEntry); - } - } - - userState = mUserStateDB.getUserState(userId); - if (!userState->deleteMasterKey()) { - ALOGE("Failed to delete user %d's master key", userId); - } - if (!keepUnenryptedEntries) { - if (!userState->reset()) { - ALOGE("Failed to remove user %d's directory", userId); - } - } -} - -bool KeyStore::isEmpty(uid_t userId) const { - std::string userDirName; - { - // userState holds a lock which must be relinquished before list is called. This scope - // prevents deadlocks. - auto userState = mUserStateDB.getUserState(userId); - if (!userState) { - return true; - } - userDirName = userState->getUserDirName(); - } - - ResponseCode rc; - std::list<LockedKeyBlobEntry> matches; - - // must not be called by a keymaster worker. List waits for workers to relinquish all access - // to blob entries - std::tie(rc, matches) = LockedKeyBlobEntry::list(userDirName); - - return rc == ResponseCode::SYSTEM_ERROR || matches.size() == 0; -} - -void KeyStore::lock(uid_t userId) { - auto userState = mUserStateDB.getUserState(userId); - userState->zeroizeMasterKeysInMemory(); - userState->setState(STATE_LOCKED); -} - -static void maybeLogKeyIntegrityViolation(const LockedKeyBlobEntry& lockedEntry, - const BlobType type) { - if (!__android_log_security() || (type != TYPE_KEY_PAIR && type != TYPE_KEYMASTER_10)) return; - log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid()); -} - -std::tuple<ResponseCode, Blob, Blob> KeyStore::get(const LockedKeyBlobEntry& blobfile) { - std::tuple<ResponseCode, Blob, Blob> result; - - uid_t userId = get_user_id(blobfile->uid()); - Blob& keyBlob = std::get<1>(result); - ResponseCode& rc = std::get<0>(result); - - auto userState = mUserStateDB.getUserState(userId); - BlobType type = BlobType::TYPE_ANY; - auto logOnScopeExit = android::base::make_scope_guard([&] { - if (rc == ResponseCode::VALUE_CORRUPTED) { - maybeLogKeyIntegrityViolation(blobfile, type); - } - }); - - result = blobfile.readBlobs(userState->getEncryptionKey(), userState->getState()); - if (rc != ResponseCode::NO_ERROR) { - return result; - } - - // update the type for logging (see scope_guard above) - type = keyBlob.getType(); - - const uint8_t version = keyBlob.getVersion(); - if (version < CURRENT_BLOB_VERSION) { - /* If we upgrade the key, we need to write it to disk again. Then - * it must be read it again since the blob is encrypted each time - * it's written. - */ - if (upgradeBlob(&keyBlob, version)) { - if ((rc = this->put(blobfile, keyBlob, {})) != ResponseCode::NO_ERROR || - (result = blobfile.readBlobs(userState->getEncryptionKey(), userState->getState()), - rc) != ResponseCode::NO_ERROR) { - return result; - } - } - } - - return result; -} - -ResponseCode KeyStore::put(const LockedKeyBlobEntry& blobfile, Blob keyBlob, - Blob characteristicsBlob) { - auto userState = mUserStateDB.getUserStateByUid(blobfile->uid()); - return blobfile.writeBlobs(std::move(keyBlob), std::move(characteristicsBlob), - userState->getEncryptionKey(), userState->getState()); -} - -ResponseCode KeyStore::del(const LockedKeyBlobEntry& blobfile) { - Blob keyBlob; - Blob charactaristicsBlob; - ResponseCode rc; - uid_t uid = blobfile->uid(); - std::string alias = blobfile->alias(); - - std::tie(rc, keyBlob, charactaristicsBlob) = get(blobfile); - - // after getting the blob from the file system we scrub the filesystem. - mGrants.removeAllGrantsToKey(uid, alias); - auto result = blobfile.deleteBlobs(); - - if (rc != ResponseCode::NO_ERROR) { - LOG(ERROR) << "get keyblob failed " << int(rc); - return rc; - } - - // if we got the blob successfully, we try and delete it from the keymaster device - auto dev = getDevice(keyBlob); - - if (keyBlob.getType() == ::TYPE_KEYMASTER_10) { - dev->deleteKey(blob2hidlVec(keyBlob), [dev, alias, uid](Return<ErrorCode> rc) { - auto ret = KS_HANDLE_HIDL_ERROR(dev, rc); - // A device doesn't have to implement delete_key. - bool success = ret == ErrorCode::OK || ret == ErrorCode::UNIMPLEMENTED; - if (__android_log_security()) { - android_log_event_list(SEC_TAG_KEY_DESTROYED) - << int32_t(success) << alias << int32_t(uid) << LOG_ID_SECURITY; - } - if (!success) { - LOG(ERROR) << "Keymaster delete for key " << alias << " of uid " << uid - << " failed"; - } - }); - } - - return result; -} - -std::string KeyStore::addGrant(const LockedKeyBlobEntry& blobfile, uid_t granteeUid) { - return mGrants.put(granteeUid, blobfile); -} - -bool KeyStore::removeGrant(const LockedKeyBlobEntry& blobfile, const uid_t granteeUid) { - return mGrants.removeByFileAlias(granteeUid, blobfile); -} -void KeyStore::removeAllGrantsToUid(const uid_t granteeUid) { - mGrants.removeAllGrantsToUid(granteeUid); -} - -bool KeyStore::isHardwareBacked(const android::String16& keyType) const { - // if strongbox device is present TEE must also be present and of sufficiently high version - // to support all keys in hardware - if (getDevice(SecurityLevel::STRONGBOX)) return true; - if (!getDevice(SecurityLevel::TRUSTED_ENVIRONMENT)) { - ALOGW("can't get keymaster device"); - return false; - } - - auto version = getDevice(SecurityLevel::TRUSTED_ENVIRONMENT)->halVersion(); - if (keyType == kRsaKeyType) return true; // All versions support RSA - return keyType == kEcKeyType && version.supportsEc; -} - -std::tuple<ResponseCode, Blob, Blob, LockedKeyBlobEntry> -KeyStore::getKeyForName(const android::String8& keyName, const uid_t uid, const BlobType type) { - std::tuple<ResponseCode, Blob, Blob, LockedKeyBlobEntry> result; - auto& [rc, keyBlob, charBlob, lockedEntry] = result; - - lockedEntry = getLockedBlobEntryIfExists(keyName.string(), uid); - - if (!lockedEntry) return rc = ResponseCode::KEY_NOT_FOUND, std::move(result); - - std::tie(rc, keyBlob, charBlob) = get(lockedEntry); - - if (rc == ResponseCode::NO_ERROR) { - if (keyBlob.getType() != type) return rc = ResponseCode::KEY_NOT_FOUND, std::move(result); - } - return result; -} - -bool KeyStore::upgradeBlob(Blob* blob, const uint8_t oldVersion) { - bool updated = false; - uint8_t version = oldVersion; - - if (!blob || !(*blob)) return false; - - /* From V0 -> V1: All old types were unknown */ - if (version == 0) { - ALOGE("Failed to upgrade key blob. Ancient blob version 0 is no longer supported"); - - return false; - } - - /* From V1 -> V2: All old keys were encrypted */ - if (version == 1) { - ALOGV("upgrading to version 2"); - - blob->setEncrypted(true); - version = 2; - updated = true; - } - - /* - * If we've updated, set the key blob to the right version - * and write it. - */ - if (updated) { - blob->setVersion(version); - } - - return updated; -} - -void KeyStore::readMetaData() { - int in = TEMP_FAILURE_RETRY(open(kMetaDataFile, O_RDONLY)); - if (in < 0) { - return; - } - size_t fileLength = readFully(in, (uint8_t*)&mMetaData, sizeof(mMetaData)); - if (fileLength != sizeof(mMetaData)) { - ALOGI("Metadata file is %zd bytes (%zd experted); upgrade?", fileLength, sizeof(mMetaData)); - } - close(in); -} - -void KeyStore::writeMetaData() { - const char* tmpFileName = ".metadata.tmp"; - int out = - TEMP_FAILURE_RETRY(open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)); - if (out < 0) { - ALOGE("couldn't write metadata file: %s", strerror(errno)); - return; - } - size_t fileLength = writeFully(out, (uint8_t*)&mMetaData, sizeof(mMetaData)); - if (fileLength != sizeof(mMetaData)) { - ALOGI("Could only write %zd bytes to metadata file (%zd expected)", fileLength, - sizeof(mMetaData)); - } - close(out); - rename(tmpFileName, kMetaDataFile); -} - -bool KeyStore::upgradeKeystore() { - bool upgraded = false; - - if (mMetaData.version == 0) { - auto userState = getUserStateDB().getUserStateByUid(0); - - // Initialize first so the directory is made. - userState->initialize(); - - // Migrate the old .masterkey file to user 0. - if (access(kOldMasterKey, R_OK) == 0) { - if (rename(kOldMasterKey, userState->getMasterKeyFileName().c_str()) < 0) { - ALOGE("couldn't migrate old masterkey: %s", strerror(errno)); - return false; - } - } - - // Initialize again in case we had a key. - userState->initialize(); - - // Try to migrate existing keys. - DIR* dir = opendir("."); - if (!dir) { - // Give up now; maybe we can upgrade later. - ALOGE("couldn't open keystore's directory; something is wrong"); - return false; - } - - struct dirent* file; - while ((file = readdir(dir)) != nullptr) { - // We only care about files. - if (file->d_type != DT_REG) { - continue; - } - - // Skip anything that starts with a "." - if (file->d_name[0] == '.') { - continue; - } - - // Find the current file's user. - char* end; - unsigned long thisUid = strtoul(file->d_name, &end, 10); - if (end[0] != '_' || end[1] == 0) { - continue; - } - auto otherUser = getUserStateDB().getUserStateByUid(thisUid); - if (otherUser->getUserId() != 0) { - unlinkat(dirfd(dir), file->d_name, 0); - } - - // Rename the file into user directory. - DIR* otherdir = opendir(otherUser->getUserDirName().c_str()); - if (otherdir == nullptr) { - ALOGW("couldn't open user directory for rename"); - continue; - } - if (renameat(dirfd(dir), file->d_name, dirfd(otherdir), file->d_name) < 0) { - ALOGW("couldn't rename blob: %s: %s", file->d_name, strerror(errno)); - } - closedir(otherdir); - } - closedir(dir); - - mMetaData.version = 1; - upgraded = true; - } - - return upgraded; -} - -void KeyStore::binderDied(const ::android::wp<IBinder>& who) { - for (unsigned i = 0; i < mKmDevices.size(); ++i) { - if (mKmDevices[SecurityLevel(i)]) mKmDevices[SecurityLevel(i)]->binderDied(who); - } - getConfirmationManager().binderDied(who); -} - -} // namespace keystore |