You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
473 lines
19 KiB
473 lines
19 KiB
/*
|
|
* Copyright 2020, 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 "android.hardware.security.keymint-impl"
|
|
#include <android-base/logging.h>
|
|
|
|
#include "AndroidKeyMintDevice.h"
|
|
|
|
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
|
|
|
|
#include <keymaster/android_keymaster.h>
|
|
#include <keymaster/contexts/pure_soft_keymaster_context.h>
|
|
#include <keymaster/keymaster_configuration.h>
|
|
|
|
#include "AndroidKeyMintOperation.h"
|
|
#include "KeyMintUtils.h"
|
|
|
|
namespace aidl::android::hardware::security::keymint {
|
|
|
|
using namespace keymaster; // NOLINT(google-build-using-namespace)
|
|
|
|
using km_utils::authToken2AidlVec;
|
|
using km_utils::kmBlob2vector;
|
|
using km_utils::kmError2ScopedAStatus;
|
|
using km_utils::kmParam2Aidl;
|
|
using km_utils::KmParamSet;
|
|
using km_utils::kmParamSet2Aidl;
|
|
using km_utils::legacy_enum_conversion;
|
|
using secureclock::TimeStampToken;
|
|
|
|
namespace {
|
|
|
|
vector<KeyCharacteristics> convertKeyCharacteristics(SecurityLevel keyMintSecurityLevel,
|
|
const AuthorizationSet& requestParams,
|
|
const AuthorizationSet& sw_enforced,
|
|
const AuthorizationSet& hw_enforced,
|
|
bool include_keystore_enforced = true) {
|
|
KeyCharacteristics keyMintEnforced{keyMintSecurityLevel, {}};
|
|
|
|
if (keyMintSecurityLevel != SecurityLevel::SOFTWARE) {
|
|
// We're pretending to be TRUSTED_ENVIRONMENT or STRONGBOX.
|
|
keyMintEnforced.authorizations = kmParamSet2Aidl(hw_enforced);
|
|
if (include_keystore_enforced) {
|
|
// Put all the software authorizations in the keystore list.
|
|
KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE,
|
|
kmParamSet2Aidl(sw_enforced)};
|
|
return {std::move(keyMintEnforced), std::move(keystoreEnforced)};
|
|
} else {
|
|
return {std::move(keyMintEnforced)};
|
|
}
|
|
}
|
|
|
|
KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE, {}};
|
|
CHECK(hw_enforced.empty()) << "Hardware-enforced list is non-empty for pure SW KeyMint";
|
|
|
|
// This is a pure software implementation, so all tags are in sw_enforced.
|
|
// We need to walk through the SW-enforced list and figure out which tags to
|
|
// return in the software list and which in the keystore list.
|
|
|
|
for (auto& entry : sw_enforced) {
|
|
switch (entry.tag) {
|
|
/* Invalid and unused */
|
|
case KM_TAG_ECIES_SINGLE_HASH_MODE:
|
|
case KM_TAG_INVALID:
|
|
case KM_TAG_KDF:
|
|
case KM_TAG_ROLLBACK_RESISTANCE:
|
|
CHECK(false) << "We shouldn't see tag " << entry.tag;
|
|
break;
|
|
|
|
/* Unimplemented */
|
|
case KM_TAG_ALLOW_WHILE_ON_BODY:
|
|
case KM_TAG_BOOTLOADER_ONLY:
|
|
case KM_TAG_ROLLBACK_RESISTANT:
|
|
case KM_TAG_STORAGE_KEY:
|
|
break;
|
|
|
|
/* Keystore-enforced if not locally generated. */
|
|
case KM_TAG_CREATION_DATETIME:
|
|
// A KeyMaster implementation is required to add this tag to generated/imported keys.
|
|
// A KeyMint implementation is not required to create this tag, only to echo it back if
|
|
// it was included in the key generation/import request.
|
|
if (requestParams.Contains(KM_TAG_CREATION_DATETIME)) {
|
|
keystoreEnforced.authorizations.push_back(kmParam2Aidl(entry));
|
|
}
|
|
break;
|
|
|
|
/* Disallowed in KeyCharacteristics */
|
|
case KM_TAG_APPLICATION_DATA:
|
|
case KM_TAG_ATTESTATION_APPLICATION_ID:
|
|
break;
|
|
|
|
/* Not key characteristics */
|
|
case KM_TAG_ASSOCIATED_DATA:
|
|
case KM_TAG_ATTESTATION_CHALLENGE:
|
|
case KM_TAG_ATTESTATION_ID_BRAND:
|
|
case KM_TAG_ATTESTATION_ID_DEVICE:
|
|
case KM_TAG_ATTESTATION_ID_IMEI:
|
|
case KM_TAG_ATTESTATION_ID_MANUFACTURER:
|
|
case KM_TAG_ATTESTATION_ID_MEID:
|
|
case KM_TAG_ATTESTATION_ID_MODEL:
|
|
case KM_TAG_ATTESTATION_ID_PRODUCT:
|
|
case KM_TAG_ATTESTATION_ID_SERIAL:
|
|
case KM_TAG_AUTH_TOKEN:
|
|
case KM_TAG_CERTIFICATE_SERIAL:
|
|
case KM_TAG_CERTIFICATE_SUBJECT:
|
|
case KM_TAG_CERTIFICATE_NOT_AFTER:
|
|
case KM_TAG_CERTIFICATE_NOT_BEFORE:
|
|
case KM_TAG_CONFIRMATION_TOKEN:
|
|
case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
|
|
case KM_TAG_IDENTITY_CREDENTIAL_KEY:
|
|
case KM_TAG_MAC_LENGTH:
|
|
case KM_TAG_NONCE:
|
|
case KM_TAG_RESET_SINCE_ID_ROTATION:
|
|
case KM_TAG_ROOT_OF_TRUST:
|
|
case KM_TAG_UNIQUE_ID:
|
|
break;
|
|
|
|
/* KeyMint-enforced */
|
|
case KM_TAG_ALGORITHM:
|
|
case KM_TAG_APPLICATION_ID:
|
|
case KM_TAG_AUTH_TIMEOUT:
|
|
case KM_TAG_BLOB_USAGE_REQUIREMENTS:
|
|
case KM_TAG_BLOCK_MODE:
|
|
case KM_TAG_BOOT_PATCHLEVEL:
|
|
case KM_TAG_CALLER_NONCE:
|
|
case KM_TAG_DIGEST:
|
|
case KM_TAG_EARLY_BOOT_ONLY:
|
|
case KM_TAG_EC_CURVE:
|
|
case KM_TAG_EXPORTABLE:
|
|
case KM_TAG_INCLUDE_UNIQUE_ID:
|
|
case KM_TAG_KEY_SIZE:
|
|
case KM_TAG_MAX_USES_PER_BOOT:
|
|
case KM_TAG_MIN_MAC_LENGTH:
|
|
case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
|
|
case KM_TAG_NO_AUTH_REQUIRED:
|
|
case KM_TAG_ORIGIN:
|
|
case KM_TAG_OS_PATCHLEVEL:
|
|
case KM_TAG_OS_VERSION:
|
|
case KM_TAG_PADDING:
|
|
case KM_TAG_PURPOSE:
|
|
case KM_TAG_RSA_OAEP_MGF_DIGEST:
|
|
case KM_TAG_RSA_PUBLIC_EXPONENT:
|
|
case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
|
|
case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
|
|
case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
|
|
case KM_TAG_USER_AUTH_TYPE:
|
|
case KM_TAG_USER_SECURE_ID:
|
|
case KM_TAG_VENDOR_PATCHLEVEL:
|
|
keyMintEnforced.authorizations.push_back(kmParam2Aidl(entry));
|
|
break;
|
|
|
|
/* Keystore-enforced */
|
|
case KM_TAG_ACTIVE_DATETIME:
|
|
case KM_TAG_ALL_APPLICATIONS:
|
|
case KM_TAG_ALL_USERS:
|
|
case KM_TAG_MAX_BOOT_LEVEL:
|
|
case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
|
|
case KM_TAG_USAGE_EXPIRE_DATETIME:
|
|
case KM_TAG_USER_ID:
|
|
case KM_TAG_USAGE_COUNT_LIMIT:
|
|
keystoreEnforced.authorizations.push_back(kmParam2Aidl(entry));
|
|
break;
|
|
}
|
|
}
|
|
|
|
vector<KeyCharacteristics> retval;
|
|
retval.reserve(2);
|
|
if (!keyMintEnforced.authorizations.empty()) retval.push_back(std::move(keyMintEnforced));
|
|
if (include_keystore_enforced && !keystoreEnforced.authorizations.empty()) {
|
|
retval.push_back(std::move(keystoreEnforced));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
Certificate convertCertificate(const keymaster_blob_t& cert) {
|
|
return {std::vector<uint8_t>(cert.data, cert.data + cert.data_length)};
|
|
}
|
|
|
|
vector<Certificate> convertCertificateChain(const CertificateChain& chain) {
|
|
vector<Certificate> retval;
|
|
retval.reserve(chain.entry_count);
|
|
std::transform(chain.begin(), chain.end(), std::back_inserter(retval), convertCertificate);
|
|
return retval;
|
|
}
|
|
|
|
void addClientAndAppData(const std::vector<uint8_t>& appId, const std::vector<uint8_t>& appData,
|
|
::keymaster::AuthorizationSet* params) {
|
|
params->Clear();
|
|
if (appId.size()) {
|
|
params->push_back(::keymaster::TAG_APPLICATION_ID, appId.data(), appId.size());
|
|
}
|
|
if (appData.size()) {
|
|
params->push_back(::keymaster::TAG_APPLICATION_DATA, appData.data(), appData.size());
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
constexpr size_t kOperationTableSize = 16;
|
|
|
|
AndroidKeyMintDevice::AndroidKeyMintDevice(SecurityLevel securityLevel)
|
|
: impl_(new ::keymaster::AndroidKeymaster(
|
|
[&]() -> auto {
|
|
auto context = new PureSoftKeymasterContext(
|
|
KmVersion::KEYMINT_1, static_cast<keymaster_security_level_t>(securityLevel));
|
|
context->SetSystemVersion(::keymaster::GetOsVersion(),
|
|
::keymaster::GetOsPatchlevel());
|
|
return context;
|
|
}(),
|
|
kOperationTableSize)),
|
|
securityLevel_(securityLevel) {}
|
|
|
|
AndroidKeyMintDevice::~AndroidKeyMintDevice() {}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
|
|
info->versionNumber = 1;
|
|
info->securityLevel = securityLevel_;
|
|
info->keyMintName = "FakeKeyMintDevice";
|
|
info->keyMintAuthorName = "Google";
|
|
info->timestampTokenRequired = false;
|
|
return ScopedAStatus::ok();
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::addRngEntropy(const vector<uint8_t>& data) {
|
|
if (data.size() == 0) {
|
|
return ScopedAStatus::ok();
|
|
}
|
|
|
|
AddEntropyRequest request(impl_->message_version());
|
|
request.random_data.Reinitialize(data.data(), data.size());
|
|
|
|
AddEntropyResponse response(impl_->message_version());
|
|
impl_->AddRngEntropy(request, &response);
|
|
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::generateKey(const vector<KeyParameter>& keyParams,
|
|
const optional<AttestationKey>& attestationKey,
|
|
KeyCreationResult* creationResult) {
|
|
|
|
GenerateKeyRequest request(impl_->message_version());
|
|
request.key_description.Reinitialize(KmParamSet(keyParams));
|
|
if (attestationKey) {
|
|
request.attestation_signing_key_blob =
|
|
KeymasterKeyBlob(attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
|
|
request.attest_key_params.Reinitialize(KmParamSet(attestationKey->attestKeyParams));
|
|
request.issuer_subject = KeymasterBlob(attestationKey->issuerSubjectName.data(),
|
|
attestationKey->issuerSubjectName.size());
|
|
}
|
|
|
|
GenerateKeyResponse response(impl_->message_version());
|
|
impl_->GenerateKey(request, &response);
|
|
|
|
if (response.error != KM_ERROR_OK) {
|
|
// Note a key difference between this current aidl and previous hal, is
|
|
// that hal returns void where as aidl returns the error status. If
|
|
// aidl returns error, then aidl will not return any change you may make
|
|
// to the out parameters. This is quite different from hal where all
|
|
// output variable can be modified due to hal returning void.
|
|
//
|
|
// So the caller need to be aware not to expect aidl functions to clear
|
|
// the output variables for you in case of error. If you left some
|
|
// wrong data set in the out parameters, they will stay there.
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
creationResult->keyBlob = kmBlob2vector(response.key_blob);
|
|
creationResult->keyCharacteristics = convertKeyCharacteristics(
|
|
securityLevel_, request.key_description, response.unenforced, response.enforced);
|
|
creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
|
|
return ScopedAStatus::ok();
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::importKey(const vector<KeyParameter>& keyParams,
|
|
KeyFormat keyFormat, const vector<uint8_t>& keyData,
|
|
const optional<AttestationKey>& attestationKey,
|
|
KeyCreationResult* creationResult) {
|
|
|
|
ImportKeyRequest request(impl_->message_version());
|
|
request.key_description.Reinitialize(KmParamSet(keyParams));
|
|
request.key_format = legacy_enum_conversion(keyFormat);
|
|
request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
|
|
if (attestationKey) {
|
|
request.attestation_signing_key_blob =
|
|
KeymasterKeyBlob(attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
|
|
request.attest_key_params.Reinitialize(KmParamSet(attestationKey->attestKeyParams));
|
|
request.issuer_subject = KeymasterBlob(attestationKey->issuerSubjectName.data(),
|
|
attestationKey->issuerSubjectName.size());
|
|
}
|
|
|
|
ImportKeyResponse response(impl_->message_version());
|
|
impl_->ImportKey(request, &response);
|
|
|
|
if (response.error != KM_ERROR_OK) {
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
creationResult->keyBlob = kmBlob2vector(response.key_blob);
|
|
creationResult->keyCharacteristics = convertKeyCharacteristics(
|
|
securityLevel_, request.key_description, response.unenforced, response.enforced);
|
|
creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
|
|
|
|
return ScopedAStatus::ok();
|
|
}
|
|
|
|
ScopedAStatus
|
|
AndroidKeyMintDevice::importWrappedKey(const vector<uint8_t>& wrappedKeyData, //
|
|
const vector<uint8_t>& wrappingKeyBlob, //
|
|
const vector<uint8_t>& maskingKey, //
|
|
const vector<KeyParameter>& unwrappingParams, //
|
|
int64_t passwordSid, int64_t biometricSid, //
|
|
KeyCreationResult* creationResult) {
|
|
|
|
ImportWrappedKeyRequest request(impl_->message_version());
|
|
request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
|
|
request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
|
|
request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
|
|
request.additional_params.Reinitialize(KmParamSet(unwrappingParams));
|
|
request.password_sid = static_cast<uint64_t>(passwordSid);
|
|
request.biometric_sid = static_cast<uint64_t>(biometricSid);
|
|
|
|
ImportWrappedKeyResponse response(impl_->message_version());
|
|
impl_->ImportWrappedKey(request, &response);
|
|
|
|
if (response.error != KM_ERROR_OK) {
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
creationResult->keyBlob = kmBlob2vector(response.key_blob);
|
|
creationResult->keyCharacteristics = convertKeyCharacteristics(
|
|
securityLevel_, request.additional_params, response.unenforced, response.enforced);
|
|
creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
|
|
|
|
return ScopedAStatus::ok();
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
|
|
const vector<KeyParameter>& upgradeParams,
|
|
vector<uint8_t>* keyBlob) {
|
|
|
|
UpgradeKeyRequest request(impl_->message_version());
|
|
request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
|
|
request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
|
|
|
|
UpgradeKeyResponse response(impl_->message_version());
|
|
impl_->UpgradeKey(request, &response);
|
|
|
|
if (response.error != KM_ERROR_OK) {
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
*keyBlob = kmBlob2vector(response.upgraded_key);
|
|
return ScopedAStatus::ok();
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
|
|
DeleteKeyRequest request(impl_->message_version());
|
|
request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
|
|
|
|
DeleteKeyResponse response(impl_->message_version());
|
|
impl_->DeleteKey(request, &response);
|
|
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::deleteAllKeys() {
|
|
// There's nothing to be done to delete software key blobs.
|
|
DeleteAllKeysRequest request(impl_->message_version());
|
|
DeleteAllKeysResponse response(impl_->message_version());
|
|
impl_->DeleteAllKeys(request, &response);
|
|
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::destroyAttestationIds() {
|
|
return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
|
|
const vector<KeyParameter>& params,
|
|
const optional<HardwareAuthToken>& authToken,
|
|
BeginResult* result) {
|
|
|
|
BeginOperationRequest request(impl_->message_version());
|
|
request.purpose = legacy_enum_conversion(purpose);
|
|
request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
|
|
request.additional_params.Reinitialize(KmParamSet(params));
|
|
|
|
vector<uint8_t> vector_token = authToken2AidlVec(authToken);
|
|
request.additional_params.push_back(
|
|
TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(vector_token.data()), vector_token.size());
|
|
|
|
BeginOperationResponse response(impl_->message_version());
|
|
impl_->BeginOperation(request, &response);
|
|
|
|
if (response.error != KM_ERROR_OK) {
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
result->params = kmParamSet2Aidl(response.output_params);
|
|
result->challenge = response.op_handle;
|
|
result->operation =
|
|
ndk::SharedRefBase::make<AndroidKeyMintOperation>(impl_, response.op_handle);
|
|
return ScopedAStatus::ok();
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::deviceLocked(
|
|
bool passwordOnly, const std::optional<secureclock::TimeStampToken>& timestampToken) {
|
|
DeviceLockedRequest request(impl_->message_version());
|
|
request.passwordOnly = passwordOnly;
|
|
if (timestampToken.has_value()) {
|
|
request.token.challenge = timestampToken->challenge;
|
|
request.token.mac = {timestampToken->mac.data(), timestampToken->mac.size()};
|
|
request.token.timestamp = timestampToken->timestamp.milliSeconds;
|
|
}
|
|
DeviceLockedResponse response = impl_->DeviceLocked(request);
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::earlyBootEnded() {
|
|
EarlyBootEndedResponse response = impl_->EarlyBootEnded();
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
ScopedAStatus
|
|
AndroidKeyMintDevice::convertStorageKeyToEphemeral(const std::vector<uint8_t>& /* storageKeyBlob */,
|
|
std::vector<uint8_t>* /* ephemeralKeyBlob */) {
|
|
return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
|
|
}
|
|
|
|
ScopedAStatus AndroidKeyMintDevice::getKeyCharacteristics(
|
|
const std::vector<uint8_t>& keyBlob, const std::vector<uint8_t>& appId,
|
|
const std::vector<uint8_t>& appData, std::vector<KeyCharacteristics>* keyCharacteristics) {
|
|
GetKeyCharacteristicsRequest request(impl_->message_version());
|
|
request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
|
|
addClientAndAppData(appId, appData, &request.additional_params);
|
|
|
|
GetKeyCharacteristicsResponse response(impl_->message_version());
|
|
impl_->GetKeyCharacteristics(request, &response);
|
|
|
|
if (response.error != KM_ERROR_OK) {
|
|
return kmError2ScopedAStatus(response.error);
|
|
}
|
|
|
|
AuthorizationSet emptySet;
|
|
*keyCharacteristics =
|
|
convertKeyCharacteristics(securityLevel_, emptySet, response.unenforced, response.enforced,
|
|
/* include_keystore_enforced = */ false);
|
|
|
|
return ScopedAStatus::ok();
|
|
}
|
|
|
|
IKeyMintDevice* CreateKeyMintDevice(SecurityLevel securityLevel) {
|
|
return ::new AndroidKeyMintDevice(securityLevel);
|
|
}
|
|
|
|
} // namespace aidl::android::hardware::security::keymint
|