d86a8abec7
Now that vold uses Keystore2 rather than the Keymaster HAL directly, and also the new version of Keymaster is called "KeyMint" instead, replace most of the references to Keymaster in vold with Keystore. (I decided not to include the "2" in most places, as it seemed unnecessarily precise in most places, and it would be something that might need to keep being updated. Only Keystore.{cpp,h} really need to care about the version number.) I didn't rename many things in cryptfs.cpp, as that file will be going away soon anyway. I also left "wait_for_keymaster" and "vdc keymaster earlyBootEnded" as-is for now, as those are referenced outside vold. Bug: 183669495 Change-Id: I92cd648fae09f8c9769f7cf34dbf6c6e956be4e8
234 lines
8.5 KiB
C++
234 lines
8.5 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "Keystore.h"
|
|
|
|
#include <android-base/logging.h>
|
|
|
|
#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
|
|
#include <aidl/android/security/maintenance/IKeystoreMaintenance.h>
|
|
#include <aidl/android/system/keystore2/Domain.h>
|
|
#include <aidl/android/system/keystore2/EphemeralStorageKeyResponse.h>
|
|
#include <aidl/android/system/keystore2/KeyDescriptor.h>
|
|
|
|
// Keep these in sync with system/security/keystore2/src/keystore2_main.rs
|
|
static constexpr const char keystore2_service_name[] =
|
|
"android.system.keystore2.IKeystoreService/default";
|
|
static constexpr const char maintenance_service_name[] = "android.security.maintenance";
|
|
|
|
/*
|
|
* Keep this in sync with the description for update() in
|
|
* system/hardware/interfaces/keystore2/aidl/android/system/keystore2/IKeystoreOperation.aidl
|
|
*/
|
|
static constexpr const size_t UPDATE_INPUT_MAX_SIZE = 32 * 1024; // 32 KiB
|
|
|
|
// Keep this in sync with system/sepolicy/private/keystore2_key_contexts
|
|
static constexpr const int VOLD_NAMESPACE = 100;
|
|
|
|
namespace android {
|
|
namespace vold {
|
|
|
|
namespace ks2_maint = ::aidl::android::security::maintenance;
|
|
|
|
KeystoreOperation::~KeystoreOperation() {
|
|
if (ks2Operation) ks2Operation->abort();
|
|
}
|
|
|
|
static void zeroize_vector(std::vector<uint8_t>& vec) {
|
|
memset_s(vec.data(), 0, vec.size());
|
|
}
|
|
|
|
static bool logKeystore2ExceptionIfPresent(::ndk::ScopedAStatus& rc, const std::string& func_name) {
|
|
if (rc.isOk()) return false;
|
|
|
|
auto exception_code = rc.getExceptionCode();
|
|
if (exception_code == EX_SERVICE_SPECIFIC) {
|
|
LOG(ERROR) << "keystore2 Keystore " << func_name
|
|
<< " returned service specific error: " << rc.getServiceSpecificError();
|
|
} else {
|
|
LOG(ERROR) << "keystore2 Communication with Keystore " << func_name
|
|
<< " failed error: " << exception_code;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool KeystoreOperation::updateCompletely(const char* input, size_t inputLen,
|
|
const std::function<void(const char*, size_t)> consumer) {
|
|
if (!ks2Operation) return false;
|
|
|
|
while (inputLen != 0) {
|
|
size_t currLen = std::min(inputLen, UPDATE_INPUT_MAX_SIZE);
|
|
std::vector<uint8_t> input_vec(input, input + currLen);
|
|
inputLen -= currLen;
|
|
input += currLen;
|
|
|
|
std::optional<std::vector<uint8_t>> output;
|
|
auto rc = ks2Operation->update(input_vec, &output);
|
|
zeroize_vector(input_vec);
|
|
if (logKeystore2ExceptionIfPresent(rc, "update")) {
|
|
ks2Operation = nullptr;
|
|
return false;
|
|
}
|
|
if (output) consumer((const char*)output->data(), output->size());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool KeystoreOperation::finish(std::string* output) {
|
|
std::optional<std::vector<uint8_t>> out_vec;
|
|
|
|
if (!ks2Operation) return false;
|
|
|
|
auto rc = ks2Operation->finish(std::nullopt, std::nullopt, &out_vec);
|
|
if (logKeystore2ExceptionIfPresent(rc, "finish")) {
|
|
ks2Operation = nullptr;
|
|
return false;
|
|
}
|
|
|
|
if (output) *output = std::string(out_vec->begin(), out_vec->end());
|
|
|
|
return true;
|
|
}
|
|
|
|
Keystore::Keystore() {
|
|
::ndk::SpAIBinder binder(AServiceManager_waitForService(keystore2_service_name));
|
|
auto keystore2Service = ks2::IKeystoreService::fromBinder(binder);
|
|
|
|
if (!keystore2Service) {
|
|
LOG(ERROR) << "Vold unable to connect to keystore2.";
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* There are only two options available to vold for the SecurityLevel: TRUSTED_ENVIRONMENT (TEE)
|
|
* and STRONGBOX. We don't use STRONGBOX because if a TEE is present it will have Weaver, which
|
|
* already strengthens CE, so there's no additional benefit from using StrongBox.
|
|
*
|
|
* The picture is slightly more complicated because Keystore2 reports a SOFTWARE instance as
|
|
* a TEE instance when there isn't a TEE instance available, but in that case, a STRONGBOX
|
|
* instance won't be available either, so we'll still be doing the best we can.
|
|
*/
|
|
auto rc = keystore2Service->getSecurityLevel(km::SecurityLevel::TRUSTED_ENVIRONMENT,
|
|
&securityLevel);
|
|
if (logKeystore2ExceptionIfPresent(rc, "getSecurityLevel"))
|
|
LOG(ERROR) << "Vold unable to get security level from keystore2.";
|
|
}
|
|
|
|
bool Keystore::generateKey(const km::AuthorizationSet& inParams, std::string* key) {
|
|
ks2::KeyDescriptor in_key = {
|
|
.domain = ks2::Domain::BLOB,
|
|
.alias = std::nullopt,
|
|
.nspace = VOLD_NAMESPACE,
|
|
.blob = std::nullopt,
|
|
};
|
|
ks2::KeyMetadata keyMetadata;
|
|
auto rc = securityLevel->generateKey(in_key, std::nullopt, inParams.vector_data(), 0, {},
|
|
&keyMetadata);
|
|
|
|
if (logKeystore2ExceptionIfPresent(rc, "generateKey")) return false;
|
|
|
|
if (keyMetadata.key.blob == std::nullopt) {
|
|
LOG(ERROR) << "keystore2 generated key blob was null";
|
|
return false;
|
|
}
|
|
if (key) *key = std::string(keyMetadata.key.blob->begin(), keyMetadata.key.blob->end());
|
|
|
|
zeroize_vector(keyMetadata.key.blob.value());
|
|
return true;
|
|
}
|
|
|
|
bool Keystore::exportKey(const KeyBuffer& ksKey, std::string* key) {
|
|
bool ret = false;
|
|
ks2::KeyDescriptor storageKey = {
|
|
.domain = ks2::Domain::BLOB,
|
|
.alias = std::nullopt,
|
|
.nspace = VOLD_NAMESPACE,
|
|
};
|
|
storageKey.blob = std::make_optional<std::vector<uint8_t>>(ksKey.begin(), ksKey.end());
|
|
ks2::EphemeralStorageKeyResponse ephemeral_key_response;
|
|
auto rc = securityLevel->convertStorageKeyToEphemeral(storageKey, &ephemeral_key_response);
|
|
|
|
if (logKeystore2ExceptionIfPresent(rc, "exportKey")) goto out;
|
|
if (key)
|
|
*key = std::string(ephemeral_key_response.ephemeralKey.begin(),
|
|
ephemeral_key_response.ephemeralKey.end());
|
|
|
|
// TODO b/185811713 store the upgraded key blob if provided and delete the old key blob.
|
|
|
|
ret = true;
|
|
out:
|
|
zeroize_vector(ephemeral_key_response.ephemeralKey);
|
|
zeroize_vector(storageKey.blob.value());
|
|
return ret;
|
|
}
|
|
|
|
bool Keystore::deleteKey(const std::string& key) {
|
|
ks2::KeyDescriptor keyDesc = {
|
|
.domain = ks2::Domain::BLOB,
|
|
.alias = std::nullopt,
|
|
.nspace = VOLD_NAMESPACE,
|
|
};
|
|
keyDesc.blob =
|
|
std::optional<std::vector<uint8_t>>(std::vector<uint8_t>(key.begin(), key.end()));
|
|
|
|
auto rc = securityLevel->deleteKey(keyDesc);
|
|
return !logKeystore2ExceptionIfPresent(rc, "deleteKey");
|
|
}
|
|
|
|
KeystoreOperation Keystore::begin(const std::string& key, const km::AuthorizationSet& inParams,
|
|
km::AuthorizationSet* outParams) {
|
|
ks2::KeyDescriptor keyDesc = {
|
|
.domain = ks2::Domain::BLOB,
|
|
.alias = std::nullopt,
|
|
.nspace = VOLD_NAMESPACE,
|
|
};
|
|
keyDesc.blob =
|
|
std::optional<std::vector<uint8_t>>(std::vector<uint8_t>(key.begin(), key.end()));
|
|
|
|
ks2::CreateOperationResponse cor;
|
|
auto rc = securityLevel->createOperation(keyDesc, inParams.vector_data(), true, &cor);
|
|
if (logKeystore2ExceptionIfPresent(rc, "createOperation")) {
|
|
if (rc.getExceptionCode() == EX_SERVICE_SPECIFIC)
|
|
return KeystoreOperation((km::ErrorCode)rc.getServiceSpecificError());
|
|
else
|
|
return KeystoreOperation();
|
|
}
|
|
|
|
if (!cor.iOperation) {
|
|
LOG(ERROR) << "keystore2 createOperation didn't return an operation";
|
|
return KeystoreOperation();
|
|
}
|
|
|
|
if (outParams && cor.parameters) *outParams = cor.parameters->keyParameter;
|
|
|
|
return KeystoreOperation(cor.iOperation, cor.upgradedBlob);
|
|
}
|
|
|
|
void Keystore::earlyBootEnded() {
|
|
::ndk::SpAIBinder binder(AServiceManager_getService(maintenance_service_name));
|
|
auto maint_service = ks2_maint::IKeystoreMaintenance::fromBinder(binder);
|
|
|
|
if (!maint_service) {
|
|
LOG(ERROR) << "Unable to connect to keystore2 maintenance service for earlyBootEnded";
|
|
return;
|
|
}
|
|
|
|
auto rc = maint_service->earlyBootEnded();
|
|
logKeystore2ExceptionIfPresent(rc, "earlyBootEnded");
|
|
}
|
|
|
|
} // namespace vold
|
|
} // namespace android
|