summaryrefslogtreecommitdiff
path: root/keystore/KeyStore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'keystore/KeyStore.cpp')
-rw-r--r--keystore/KeyStore.cpp512
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