blob: b9fbbe07cc363681d1b4efed833975ab10c9fabd [file] [log] [blame]
/*
* 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 "guest/hals/keymint/remote/remote_keymint_device.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 "KeyMintUtils.h"
#include "guest/hals/keymint/remote/remote_keymint_operation.h"
namespace aidl::android::hardware::security::keymint {
using namespace ::keymaster;
using namespace km_utils;
using secureclock::TimeStampToken;
namespace {
vector<KeyCharacteristics> convertKeyCharacteristics(
SecurityLevel keyMintSecurityLevel, const AuthorizationSet& sw_enforced,
const AuthorizationSet& hw_enforced) {
KeyCharacteristics keyMintEnforced{keyMintSecurityLevel, {}};
if (keyMintSecurityLevel != SecurityLevel::SOFTWARE) {
// We're pretending to be TRUSTED_ENVIRONMENT or STRONGBOX.
keyMintEnforced.authorizations = kmParamSet2Aidl(hw_enforced);
// Put all the software authorizations in the keystore list.
KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE,
kmParamSet2Aidl(sw_enforced)};
return {std::move(keyMintEnforced), std::move(keystoreEnforced)};
}
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_EARLY_BOOT_ONLY:
case KM_TAG_ROLLBACK_RESISTANT:
case KM_TAG_STORAGE_KEY:
case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
break;
/* Unenforceable */
case KM_TAG_CREATION_DATETIME:
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_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_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 (!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;
}
} // namespace
RemoteKeyMintDevice::RemoteKeyMintDevice(::keymaster::RemoteKeymaster& impl,
SecurityLevel securityLevel)
: impl_(impl), securityLevel_(securityLevel) {}
RemoteKeyMintDevice::~RemoteKeyMintDevice() {}
ScopedAStatus RemoteKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
info->versionNumber = 1;
info->securityLevel = securityLevel_;
info->keyMintName = "RemoteKeyMintDevice";
info->keyMintAuthorName = "Google";
info->timestampTokenRequired = false;
return ScopedAStatus::ok();
}
ScopedAStatus RemoteKeyMintDevice::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 RemoteKeyMintDevice::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_, response.unenforced, response.enforced);
creationResult->certificateChain =
convertCertificateChain(response.certificate_chain);
return ScopedAStatus::ok();
}
ScopedAStatus RemoteKeyMintDevice::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_, response.unenforced, response.enforced);
creationResult->certificateChain =
convertCertificateChain(response.certificate_chain);
return ScopedAStatus::ok();
}
ScopedAStatus RemoteKeyMintDevice::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_, response.unenforced, response.enforced);
creationResult->certificateChain =
convertCertificateChain(response.certificate_chain);
return ScopedAStatus::ok();
}
ScopedAStatus RemoteKeyMintDevice::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 RemoteKeyMintDevice::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 RemoteKeyMintDevice::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 RemoteKeyMintDevice::destroyAttestationIds() {
return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
}
ScopedAStatus RemoteKeyMintDevice::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<RemoteKeyMintOperation>(
impl_, response.op_handle);
return ScopedAStatus::ok();
}
ScopedAStatus RemoteKeyMintDevice::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 RemoteKeyMintDevice::earlyBootEnded() {
EarlyBootEndedResponse response = impl_.EarlyBootEnded();
return kmError2ScopedAStatus(response.error);
}
ScopedAStatus RemoteKeyMintDevice::convertStorageKeyToEphemeral(
const std::vector<uint8_t>& /* storageKeyBlob */,
std::vector<uint8_t>* /* ephemeralKeyBlob */) {
return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
}
ScopedAStatus RemoteKeyMintDevice::getKeyCharacteristics(
const std::vector<uint8_t>& /* storageKeyBlob */,
const std::vector<uint8_t>& /* appId */,
const std::vector<uint8_t>& /* appData */,
std::vector<KeyCharacteristics>* /* keyCharacteristics */) {
return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
}
} // namespace aidl::android::hardware::security::keymint