blob: 4f6ae5683268385328b1b5f96d0cbe6bdf944d27 [file] [log] [blame]
/*
* Copyright (c) 2021-2022 TRUSTONIC LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the TRUSTONIC LIMITED nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstring>
#include <sys/endian.h>
#include "km_shared_util.h"
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include "AndroidKeyMintDevice.h"
#include "AndroidKeyMintOperation.h"
#include "TrustonicKeymintDeviceImpl.h"
namespace aidl::android::hardware::security::keymint {
using ::ndk::ScopedAStatus;
namespace {
} // namespace
inline ScopedAStatus kmError2ScopedAStatus(const keymaster_error_t value) {
return (value == KM_ERROR_OK
? ScopedAStatus::ok()
: ScopedAStatus(AStatus_fromServiceSpecificError(static_cast<int32_t>(value))));
}
class KmKeyParamSet : public keymaster_key_param_set_t {
public:
KmKeyParamSet(const vector<KeyParameter>& keyParams) {
size_t n_params = keyParams.size();
params = new keymaster_key_param_t[n_params];
size_t j = 0;
for (size_t i = 0; i < n_params; ++i) {
const KeyParameter& p = keyParams[i];
const keymaster_tag_t tag = keymaster_tag_t(p.tag);
if (tag != KM_TAG_INVALID) {
keymaster_key_param_t *q = &params[j];
q->tag = tag;
switch (keymaster_tag_get_type(tag)) {
case KM_ENUM:
case KM_ENUM_REP:
switch (tag) {
case KM_TAG_ALGORITHM:
q->enumerated = keymaster_algorithm_t(p.value.get<KeyParameterValue::algorithm>());
break;
case KM_TAG_BLOCK_MODE:
q->enumerated = keymaster_block_mode_t(p.value.get<KeyParameterValue::blockMode>());
break;
case KM_TAG_PADDING:
q->enumerated = keymaster_padding_t(p.value.get<KeyParameterValue::paddingMode>());
break;
case KM_TAG_DIGEST:
case KM_TAG_RSA_OAEP_MGF_DIGEST:
q->enumerated = keymaster_digest_t(p.value.get<KeyParameterValue::digest>());
break;
case KM_TAG_EC_CURVE:
q->enumerated = keymaster_ec_curve_t(p.value.get<KeyParameterValue::ecCurve>());
break;
case KM_TAG_ORIGIN:
q->enumerated = keymaster_key_origin_t(p.value.get<KeyParameterValue::origin>());
break;
case KM_TAG_PURPOSE:
q->enumerated = keymaster_purpose_t(p.value.get<KeyParameterValue::keyPurpose>());
break;
case KM_TAG_USER_AUTH_TYPE:
q->enumerated = uint32_t(p.value.get<KeyParameterValue::hardwareAuthenticatorType>());
break;
case KM_TAG_HARDWARE_TYPE:
q->enumerated = keymaster_security_level_t(p.value.get<KeyParameterValue::securityLevel>());
break;
default:
break;
}
break;
case KM_UINT:
case KM_UINT_REP:
q->integer = p.value.get<KeyParameterValue::integer>();
break;
case KM_ULONG:
case KM_ULONG_REP:
q->long_integer = p.value.get<KeyParameterValue::longInteger>();
break;
case KM_DATE:
q->date_time = p.value.get<KeyParameterValue::dateTime>();
break;
case KM_BOOL:
q->boolean = true;
break;
case KM_BIGNUM:
case KM_BYTES: {
std::vector<uint8_t> blob = p.value.get<KeyParameterValue::blob>();
if (blob.size() != 0) {
q->blob.data = (const uint8_t *)malloc(blob.size());
if (q->blob.data != NULL) {
std::memcpy((void*)q->blob.data, blob.data(), blob.size());
q->blob.data_length = blob.size();
}
}
}
break;
default:
break;
}
j++;
}
}
length = j;
}
KmKeyParamSet(KmKeyParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
other.length = 0;
other.params = nullptr;
}
KmKeyParamSet(const KmKeyParamSet&) = delete;
~KmKeyParamSet() { delete[] params; }
};
inline keymaster_key_blob_t convert_to_key_blob(const vector<uint8_t>& blob) {
keymaster_key_blob_t result = {blob.data(), blob.size()};
return result;
}
inline vector<uint8_t> kmBlob2vector(const keymaster_key_blob_t& blob) {
vector<uint8_t> result(blob.key_material, blob.key_material + blob.key_material_size);
return result;
}
AndroidKeyMintDevice::AndroidKeyMintDevice(SecurityLevel /*securityLevel*/)
: impl_(new TrustonicKeymintDeviceImpl()) {}
AndroidKeyMintDevice::~AndroidKeyMintDevice() {}
ScopedAStatus AndroidKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
keymaster_security_level_t securityLevel = KM_SECURITY_LEVEL_SOFTWARE;
const char *keyMintName = NULL;
const char *keyMintAuthorName = NULL;
impl_->get_hardware_info(
&securityLevel, &keyMintName, &keyMintAuthorName);
info->versionNumber = 2;
info->securityLevel = (SecurityLevel)securityLevel;
info->keyMintName = keyMintName;
info->keyMintAuthorName = keyMintAuthorName;
info->timestampTokenRequired = false;
return ScopedAStatus::ok();
}
ScopedAStatus AndroidKeyMintDevice::addRngEntropy(const vector<uint8_t>& data) {
return kmError2ScopedAStatus(impl_->add_rng_entropy(
data.data(), data.size()));
}
vector<KeyParameter> kmParamSet2Aidl(const keymaster_key_param_set_t& set) {
vector<KeyParameter> result;
if (set.length == 0 || set.params == nullptr) return result;
keymaster_key_param_t* params = set.params;
for (size_t i = 0; i < set.length; ++i) {
auto tag = params[i].tag;
KeyParameter key_param;
key_param.tag = static_cast<Tag>(tag);
KeyParameterValue key_param_value;
switch (keymaster_tag_get_type(tag)) {
case KM_ENUM:
case KM_ENUM_REP:
switch(tag) {
case KM_TAG_ALGORITHM:
key_param_value = KeyParameterValue::make<KeyParameterValue::algorithm>(static_cast<Algorithm>(params[i].enumerated));
break;
case KM_TAG_BLOCK_MODE:
key_param_value = KeyParameterValue::make<KeyParameterValue::blockMode>(static_cast<BlockMode>(params[i].enumerated));
break;
case KM_TAG_PADDING:
key_param_value = KeyParameterValue::make<KeyParameterValue::paddingMode>(static_cast<PaddingMode>(params[i].enumerated));
break;
case KM_TAG_DIGEST:
case KM_TAG_RSA_OAEP_MGF_DIGEST:
key_param_value = KeyParameterValue::make<KeyParameterValue::digest>(static_cast<Digest>(params[i].enumerated));
break;
case KM_TAG_EC_CURVE:
key_param_value = KeyParameterValue::make<KeyParameterValue::ecCurve>(static_cast<EcCurve>(params[i].enumerated));
break;
case KM_TAG_ORIGIN:
key_param_value = KeyParameterValue::make<KeyParameterValue::origin>(static_cast<KeyOrigin>(params[i].enumerated));
break;
case KM_TAG_PURPOSE:
key_param_value = KeyParameterValue::make<KeyParameterValue::keyPurpose>(static_cast<KeyPurpose>(params[i].enumerated));
break;
case KM_TAG_USER_AUTH_TYPE:
key_param_value = KeyParameterValue::make<KeyParameterValue::hardwareAuthenticatorType>(static_cast<HardwareAuthenticatorType>(params[i].enumerated));
break;
case KM_TAG_HARDWARE_TYPE:
key_param_value = KeyParameterValue::make<KeyParameterValue::securityLevel>(static_cast<SecurityLevel>(params[i].enumerated));
break;
default:
/* Shouldn't get here. */
LOG_E("%s %d KM_TAG_INVALID tag=%d/%X", __func__, __LINE__, (uint32_t)tag, (uint32_t)tag);
key_param.tag = static_cast<Tag>(KM_TAG_INVALID);
break;
}
break;
case KM_UINT:
case KM_UINT_REP:
key_param_value = KeyParameterValue::make<KeyParameterValue::integer>(params[i].integer);
break;
case KM_ULONG:
case KM_ULONG_REP:
key_param_value = KeyParameterValue::make<KeyParameterValue::longInteger>(params[i].long_integer);
break;
case KM_DATE:
key_param_value = KeyParameterValue::make<KeyParameterValue::dateTime>(params[i].date_time);
break;
case KM_BOOL:
key_param_value = KeyParameterValue::make<KeyParameterValue::boolValue>(params[i].boolean);
break;
case KM_BIGNUM:
case KM_BYTES:
key_param_value = KeyParameterValue::make<KeyParameterValue::blob>(std::vector<uint8_t>(params[i].blob.data, params[i].blob.data + params[i].blob.data_length));
break;
case KM_INVALID:
default:
LOG_E("%s %d KM_TAG_INVALID type=%d/%X", __func__, __LINE__, (uint32_t)keymaster_tag_get_type(tag), (uint32_t)keymaster_tag_get_type(tag));
key_param.tag = static_cast<Tag>(KM_TAG_INVALID);
/* just skip */
break;
}
key_param.value = key_param_value;
result.push_back(key_param);
}
return result;
}
inline vector<KeyCharacteristics> convertKeyCharacteristics(
const keymaster_key_characteristics_t& characteristics,
bool add_keystore_enforced)
{
vector<KeyCharacteristics> key_characteristics = {};
KeyCharacteristics keyMintEnforced{SecurityLevel::TRUSTED_ENVIRONMENT, kmParamSet2Aidl(characteristics.hw_enforced)};
key_characteristics.push_back({std::move(keyMintEnforced)});
if ((add_keystore_enforced) && (characteristics.sw_enforced.length != 0)) {
// Put all the software authorizations in the keystore list.*
KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE, kmParamSet2Aidl(characteristics.sw_enforced)};
key_characteristics.push_back({std::move(keystoreEnforced)});
}
return key_characteristics;
}
Certificate convertCertificate(const keymaster_blob_t& cert) {
return {std::vector<uint8_t>(cert.data, cert.data + cert.data_length)};
}
vector<Certificate> convertCertificateChain(const keymaster_cert_chain_t& chain) {
vector<Certificate> retval;
for (size_t i = 0; i < chain.entry_count; ++i) {
retval.push_back(convertCertificate(chain.entries[i]));
}
return retval;
}
ScopedAStatus AndroidKeyMintDevice::generateKey(const vector<KeyParameter>& keyParams,
const optional<AttestationKey>& attestationKey,
KeyCreationResult* creationResult) {
KmKeyParamSet key_params(keyParams);
keymaster_key_blob_t key_blob = {};
keymaster_key_characteristics_t characteristics = {};
KmKeyParamSet* attestation_key_params = NULL;
keymaster_key_blob_t attestation_key_blob = {};
keymaster_blob_t attestation_issuer_blob = {};
if (attestationKey) {
attestation_key_blob.key_material = attestationKey->keyBlob.data();
attestation_key_blob.key_material_size = attestationKey->keyBlob.size();
attestation_issuer_blob.data = attestationKey->issuerSubjectName.data();
attestation_issuer_blob.data_length = attestationKey->issuerSubjectName.size();
attestation_key_params = new KmKeyParamSet(attestationKey->attestKeyParams);
}
keymaster_cert_chain_t cert_chain = {};
keymaster_error_t ret = impl_->generate_and_attest_key(
&key_params,
attestationKey?&attestation_key_blob:NULL,
attestation_key_params,
(attestationKey->issuerSubjectName.size() != 0)?&attestation_issuer_blob:NULL,
&key_blob, &characteristics, &cert_chain);
if (ret != KM_ERROR_OK) {
/* ExySp */
keymaster_free_param_set(&key_params);
keymaster_free_param_set(attestation_key_params);
return kmError2ScopedAStatus(ret);
}
creationResult->keyBlob = kmBlob2vector(key_blob);
creationResult->keyCharacteristics =
convertKeyCharacteristics(characteristics, true);
creationResult->certificateChain = convertCertificateChain(cert_chain);
keymaster_free_param_set(&key_params);
keymaster_free_param_set(attestation_key_params);
keymaster_free_cert_chain(&cert_chain);
free((void*)key_blob.key_material);
key_blob.key_material = NULL;
key_blob.key_material_size = 0;
keymaster_free_characteristics(&characteristics);
return ScopedAStatus::ok();
}
ScopedAStatus AndroidKeyMintDevice::importKey(const vector<KeyParameter>& keyParams,
KeyFormat keyFormat, const vector<uint8_t>& keyData,
const optional<AttestationKey>& attestationKey,
KeyCreationResult* creationResult) {
KmKeyParamSet key_params(keyParams);
const keymaster_blob_t key_data = {keyData.data(), keyData.size()};
keymaster_key_blob_t key_blob = {};
keymaster_key_characteristics_t characteristics = {};
KmKeyParamSet* attestation_key_params = NULL;
keymaster_key_blob_t attestation_key_blob = {};
keymaster_blob_t attestation_issuer_blob = {};
if (attestationKey) {
attestation_key_blob.key_material = attestationKey->keyBlob.data();
attestation_key_blob.key_material_size = attestationKey->keyBlob.size();
attestation_issuer_blob.data = attestationKey->issuerSubjectName.data();
attestation_issuer_blob.data_length = attestationKey->issuerSubjectName.size();
attestation_key_params = new KmKeyParamSet(attestationKey->attestKeyParams);
}
keymaster_cert_chain_t cert_chain = {};
keymaster_error_t ret = impl_->import_and_attest_key(
&key_params, keymaster_key_format_t(keyFormat), &key_data,
attestationKey?&attestation_key_blob:NULL,
attestation_key_params,
(attestationKey->issuerSubjectName.size() != 0)?&attestation_issuer_blob:NULL,
&key_blob, &characteristics, &cert_chain);
if (ret != KM_ERROR_OK) {
/* ExySp */
keymaster_free_param_set(&key_params);
keymaster_free_param_set(attestation_key_params);
return kmError2ScopedAStatus(ret);
}
creationResult->keyBlob = kmBlob2vector(key_blob);
creationResult->keyCharacteristics =
convertKeyCharacteristics(characteristics, true);
creationResult->certificateChain = convertCertificateChain(cert_chain);
keymaster_free_param_set(&key_params);
keymaster_free_param_set(attestation_key_params);
keymaster_free_cert_chain(&cert_chain);
free((void*)key_blob.key_material);
key_blob.key_material = NULL;
key_blob.key_material_size = 0;
keymaster_free_characteristics(&characteristics);
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) {
KmKeyParamSet unwrapping_key_params(unwrappingParams);
const keymaster_blob_t wrapped_key_data = {
wrappedKeyData.data(), wrappedKeyData.size()};
const keymaster_key_blob_t wrapping_key_blob = {
wrappingKeyBlob.data(), wrappingKeyBlob.size()};
keymaster_key_blob_t key_blob = {};
keymaster_key_characteristics_t characteristics = {};
if (maskingKey.size() != 32) {
return kmError2ScopedAStatus(KM_ERROR_INVALID_ARGUMENT);
}
keymaster_cert_chain_t cert_chain = {};
keymaster_error_t ret = impl_->import_wrapped_key(
&wrapped_key_data, &wrapping_key_blob,
maskingKey.data(),
&unwrapping_key_params,
passwordSid, biometricSid,
&key_blob, &characteristics, &cert_chain);
if (ret != KM_ERROR_OK) {
return kmError2ScopedAStatus(ret);
}
creationResult->keyBlob = kmBlob2vector(key_blob);
creationResult->keyCharacteristics =
convertKeyCharacteristics(characteristics, true);
creationResult->certificateChain = convertCertificateChain(cert_chain);
keymaster_free_cert_chain(&cert_chain);
keymaster_free_param_set(&unwrapping_key_params);
free((void*)key_blob.key_material);
key_blob.key_material = NULL;
key_blob.key_material_size = 0;
keymaster_free_characteristics(&characteristics);
return ScopedAStatus::ok();
}
ScopedAStatus AndroidKeyMintDevice::upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
const vector<KeyParameter>& upgradeParams,
vector<uint8_t>* keyBlob) {
KmKeyParamSet upgrade_key_params(upgradeParams);
const keymaster_key_blob_t key_to_upgrade = {
keyBlobToUpgrade.data(), keyBlobToUpgrade.size()};
keymaster_key_blob_t key_blob = {};
keymaster_error_t ret = impl_->upgrade_key(
&key_to_upgrade, &upgrade_key_params, &key_blob);
if (ret != KM_ERROR_OK) {
return kmError2ScopedAStatus(ret);
}
*keyBlob = kmBlob2vector(key_blob);
keymaster_free_param_set(&upgrade_key_params);
free((void*)key_blob.key_material);
key_blob.key_material = NULL;
key_blob.key_material_size = 0;
return ScopedAStatus::ok();
}
ScopedAStatus AndroidKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
const keymaster_key_blob_t key = {
keyBlob.data(), keyBlob.size()};
keymaster_error_t ret = impl_->delete_key(&key);
return kmError2ScopedAStatus(ret);
}
ScopedAStatus AndroidKeyMintDevice::deleteAllKeys() {
keymaster_error_t ret = impl_->delete_all_keys();
return kmError2ScopedAStatus(ret);
}
ScopedAStatus AndroidKeyMintDevice::destroyAttestationIds() {
return kmError2ScopedAStatus(impl_->destroy_attestation_ids());
}
ScopedAStatus AndroidKeyMintDevice::begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
const vector<KeyParameter>& params,
const optional<HardwareAuthToken>& authToken, BeginResult* result) {
const keymaster_key_blob_t key = {
keyBlob.data(), keyBlob.size()};
KmKeyParamSet in_params(params);
keymaster_key_param_set_t out_params = {};
uint64_t operation_handle = 0;
keymaster_hw_auth_token_t auth_token = {};
if (authToken) {
auth_token.challenge = authToken->challenge;
auth_token.user_id = authToken->userId;
auth_token.authenticator_id = authToken->authenticatorId;
auth_token.authenticator_type = keymaster_hw_auth_type_t(ntohl(static_cast<uint32_t>(authToken->authenticatorType)));
auth_token.timestamp = ntohq(authToken->timestamp.milliSeconds);
auth_token.mac = {authToken->mac.data(), authToken->mac.size()};
}
keymaster_error_t ret = impl_->begin(
keymaster_purpose_t(purpose), &key, &in_params, (authToken)?&auth_token:NULL, &out_params, &operation_handle);
if (ret != KM_ERROR_OK) {
return kmError2ScopedAStatus(ret);
}
result->params = kmParamSet2Aidl(out_params);
result->challenge = operation_handle;
result->operation =
ndk::SharedRefBase::make<AndroidKeyMintOperation>(impl_, operation_handle);
keymaster_free_param_set(&in_params);
keymaster_free_param_set(&out_params);
return ScopedAStatus::ok();
}
ScopedAStatus AndroidKeyMintDevice::deviceLocked(bool passwordOnly,
const optional<TimeStampToken>& /*timestampToken*/) {
return kmError2ScopedAStatus(impl_->device_locked(passwordOnly));
}
ScopedAStatus AndroidKeyMintDevice::earlyBootEnded() {
return kmError2ScopedAStatus(impl_->early_boot_ended());
}
/* ExySp */
ScopedAStatus
AndroidKeyMintDevice::convertStorageKeyToEphemeral(const std::vector<uint8_t>&storageKeyBlob ,
std::vector<uint8_t>* ephemeralKeyBlob) {
keymaster_key_blob_t key_storage_blob = {storageKeyBlob.data(), storageKeyBlob.size()};
keymaster_blob_t output_blob = {};
keymaster_error_t ret = impl_->export_key(KM_KEY_FORMAT_RAW,
&key_storage_blob, {}, {}, &output_blob );
if (ret != KM_ERROR_OK) {
return kmError2ScopedAStatus(ret);
}
*ephemeralKeyBlob = std::vector(output_blob.data, output_blob.data + output_blob.data_length);
free((void*)output_blob.data);
output_blob.data = NULL;
output_blob.data_length = 0;
return ScopedAStatus::ok();
}
/* End */
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)
{
keymaster_key_blob_t key_blob = {keyBlob.data(), keyBlob.size()};
keymaster_blob_t app_id = {appId.data(), appId.size()};
keymaster_blob_t app_data = {appData.data(), appData.size()};
keymaster_key_characteristics_t characteristics = {};
keymaster_error_t ret = impl_->get_key_characteristics(
&key_blob, &app_id, &app_data, &characteristics);
if (ret != KM_ERROR_OK) {
return kmError2ScopedAStatus(ret);
}
*keyCharacteristics = convertKeyCharacteristics(characteristics, false);
keymaster_free_characteristics(&characteristics);
return ScopedAStatus::ok();
}
ScopedAStatus AndroidKeyMintDevice::getRootOfTrustChallenge(std::array<uint8_t, 16>* rootOfTrustChallenge){
(void)rootOfTrustChallenge;
return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
}
ScopedAStatus AndroidKeyMintDevice::getRootOfTrust(const std::array<uint8_t, 16>& in_challenge,
std::vector<uint8_t>* rootOfTrust) {
keymaster_blob_t rot_blob = {};
keymaster_error_t ret = impl_->get_root_of_trust(in_challenge.data(), &rot_blob);
if (ret != KM_ERROR_OK) {
return kmError2ScopedAStatus(ret);
}
*rootOfTrust = vector<uint8_t>(
rot_blob.data,
rot_blob.data + rot_blob.data_length);
free((void*)rot_blob.data);
rot_blob.data = NULL;
rot_blob.data_length = 0;
return ScopedAStatus::ok();
}
ScopedAStatus AndroidKeyMintDevice::sendRootOfTrust(const std::vector<uint8_t>& in_rootOfTrust) {
(void)in_rootOfTrust;
return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
}
IKeyMintDevice* CreateKeyMintDevice(SecurityLevel securityLevel) {
return ::new AndroidKeyMintDevice(securityLevel);
}
} // namespace aidl::android::hardware::security::keymint