/*
 * Copyright (C) 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.
 */

#include "km_compat.h"

#include "km_compat_type_conversion.h"
#include <AndroidKeyMintDevice.h>
#include <aidl/android/hardware/security/keymint/Algorithm.h>
#include <aidl/android/hardware/security/keymint/Digest.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <aidl/android/hardware/security/keymint/KeyParameterValue.h>
#include <aidl/android/hardware/security/keymint/PaddingMode.h>
#include <aidl/android/system/keystore2/ResponseCode.h>
#include <android-base/logging.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <binder/IServiceManager.h>
#include <hardware/keymaster_defs.h>
#include <keymasterV4_1/Keymaster.h>
#include <keymasterV4_1/Keymaster3.h>
#include <keymasterV4_1/Keymaster4.h>

#include <chrono>

#include "certificate_utils.h"

using ::aidl::android::hardware::security::keymint::Algorithm;
using ::aidl::android::hardware::security::keymint::CreateKeyMintDevice;
using ::aidl::android::hardware::security::keymint::Digest;
using ::aidl::android::hardware::security::keymint::KeyParameterValue;
using ::aidl::android::hardware::security::keymint::PaddingMode;
using ::aidl::android::hardware::security::keymint::Tag;
using ::aidl::android::system::keystore2::ResponseCode;
using ::android::hardware::hidl_vec;
using ::android::hardware::keymaster::V4_0::TagType;
using ::android::hidl::manager::V1_2::IServiceManager;
using V4_0_HardwareAuthToken = ::android::hardware::keymaster::V4_0::HardwareAuthToken;
using V4_0_HmacSharingParameters = ::android::hardware::keymaster::V4_0::HmacSharingParameters;
using V4_0_KeyCharacteristics = ::android::hardware::keymaster::V4_0::KeyCharacteristics;
using V4_0_KeyFormat = ::android::hardware::keymaster::V4_0::KeyFormat;
using V4_0_KeyParameter = ::android::hardware::keymaster::V4_0::KeyParameter;
using V4_0_VerificationToken = ::android::hardware::keymaster::V4_0::VerificationToken;
namespace V4_0 = ::android::hardware::keymaster::V4_0;
namespace V4_1 = ::android::hardware::keymaster::V4_1;
namespace KMV1 = ::aidl::android::hardware::security::keymint;

using namespace std::chrono_literals;
using std::chrono::duration_cast;

// Utility functions

// Returns true if this parameter may be passed to attestKey.
bool isAttestationParameter(const KMV1::KeyParameter& param) {
    switch (param.tag) {
    case Tag::APPLICATION_ID:
    case Tag::APPLICATION_DATA:
    case Tag::ATTESTATION_CHALLENGE:
    case Tag::ATTESTATION_APPLICATION_ID:
    case Tag::ATTESTATION_ID_BRAND:
    case Tag::ATTESTATION_ID_DEVICE:
    case Tag::ATTESTATION_ID_PRODUCT:
    case Tag::ATTESTATION_ID_SERIAL:
    case Tag::ATTESTATION_ID_IMEI:
    case Tag::ATTESTATION_ID_MEID:
    case Tag::ATTESTATION_ID_MANUFACTURER:
    case Tag::ATTESTATION_ID_MODEL:
    case Tag::CERTIFICATE_SERIAL:
    case Tag::CERTIFICATE_SUBJECT:
    case Tag::CERTIFICATE_NOT_BEFORE:
    case Tag::CERTIFICATE_NOT_AFTER:
    case Tag::DEVICE_UNIQUE_ATTESTATION:
        return true;
    default:
        return false;
    }
}

// Returns true if this parameter may be passed to generate/importKey.
bool isKeyCreationParameter(const KMV1::KeyParameter& param) {
    switch (param.tag) {
    case Tag::APPLICATION_ID:
    case Tag::APPLICATION_DATA:
    case Tag::CERTIFICATE_SERIAL:
    case Tag::CERTIFICATE_SUBJECT:
    case Tag::CERTIFICATE_NOT_BEFORE:
    case Tag::CERTIFICATE_NOT_AFTER:
    case Tag::PURPOSE:
    case Tag::ALGORITHM:
    case Tag::KEY_SIZE:
    case Tag::BLOCK_MODE:
    case Tag::DIGEST:
    case Tag::PADDING:
    case Tag::CALLER_NONCE:
    case Tag::MIN_MAC_LENGTH:
    case Tag::EC_CURVE:
    case Tag::RSA_PUBLIC_EXPONENT:
    case Tag::RSA_OAEP_MGF_DIGEST:
    case Tag::BOOTLOADER_ONLY:
    case Tag::ROLLBACK_RESISTANCE:
    case Tag::EARLY_BOOT_ONLY:
    case Tag::ACTIVE_DATETIME:
    case Tag::ORIGINATION_EXPIRE_DATETIME:
    case Tag::USAGE_EXPIRE_DATETIME:
    case Tag::MIN_SECONDS_BETWEEN_OPS:
    case Tag::MAX_USES_PER_BOOT:
    case Tag::USAGE_COUNT_LIMIT:
    case Tag::USER_ID:
    case Tag::USER_SECURE_ID:
    case Tag::NO_AUTH_REQUIRED:
    case Tag::USER_AUTH_TYPE:
    case Tag::AUTH_TIMEOUT:
    case Tag::ALLOW_WHILE_ON_BODY:
    case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
    case Tag::TRUSTED_CONFIRMATION_REQUIRED:
    case Tag::UNLOCKED_DEVICE_REQUIRED:
    case Tag::CREATION_DATETIME:
    case Tag::INCLUDE_UNIQUE_ID:
    case Tag::IDENTITY_CREDENTIAL_KEY:
    case Tag::STORAGE_KEY:
    case Tag::MAC_LENGTH:
        return true;
    default:
        return false;
    }
}

// Size of prefix for blobs, see keyBlobPrefix().
//
const size_t kKeyBlobPrefixSize = 8;

// Magic used in blob prefix, see keyBlobPrefix().
//
const uint8_t kKeyBlobMagic[7] = {'p', 'K', 'M', 'b', 'l', 'o', 'b'};

// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set
// to 9999-12-31T23:59:59Z.
//
const uint64_t kUndefinedNotAfter = 253402300799000;

// Prefixes a keyblob returned by e.g. generateKey() with information on whether it
// originated from the real underlying KeyMaster HAL or from soft-KeyMint.
//
// When dealing with a keyblob, use prefixedKeyBlobRemovePrefix() to remove the
// prefix and prefixedKeyBlobIsSoftKeyMint() to determine its origin.
//
// Note how the prefix itself has a magic marker ("pKMblob") which can be used
// to identify if a blob has a prefix at all (it's assumed that any valid blob
// from KeyMint or KeyMaster HALs never starts with the magic). This is needed
// because blobs persisted to disk prior to using this code will not have the
// prefix and in that case we want prefixedKeyBlobRemovePrefix() to still work.
//
std::vector<uint8_t> keyBlobPrefix(const std::vector<uint8_t>& blob, bool isSoftKeyMint) {
    std::vector<uint8_t> result;
    result.reserve(blob.size() + kKeyBlobPrefixSize);
    result.insert(result.begin(), kKeyBlobMagic, kKeyBlobMagic + sizeof kKeyBlobMagic);
    result.push_back(isSoftKeyMint ? 1 : 0);
    std::copy(blob.begin(), blob.end(), std::back_inserter(result));
    return result;
}

// Helper for prefixedKeyBlobRemovePrefix() and prefixedKeyBlobIsSoftKeyMint().
//
// First bool is whether there's a valid prefix. If there is, the second bool is
// the |isSoftKeyMint| value of the prefix
//
std::pair<bool, bool> prefixedKeyBlobParsePrefix(const std::vector<uint8_t>& prefixedBlob) {
    // Having a unprefixed blob is not that uncommon, for example all devices
    // upgrading to keystore2 (so e.g. upgrading to Android 12) will have
    // unprefixed blobs. So don't spew warnings/errors in this case...
    if (prefixedBlob.size() < kKeyBlobPrefixSize) {
        return std::make_pair(false, false);
    }
    if (std::memcmp(prefixedBlob.data(), kKeyBlobMagic, sizeof kKeyBlobMagic) != 0) {
        return std::make_pair(false, false);
    }
    if (prefixedBlob[kKeyBlobPrefixSize - 1] != 0 && prefixedBlob[kKeyBlobPrefixSize - 1] != 1) {
        return std::make_pair(false, false);
    }
    bool isSoftKeyMint = (prefixedBlob[kKeyBlobPrefixSize - 1] == 1);
    return std::make_pair(true, isSoftKeyMint);
}

// Removes the prefix from a blob. If there's no prefix, returns the passed-in blob.
//
std::vector<uint8_t> prefixedKeyBlobRemovePrefix(const std::vector<uint8_t>& prefixedBlob) {
    auto parsed = prefixedKeyBlobParsePrefix(prefixedBlob);
    if (!parsed.first) {
        // Not actually prefixed, blob was probably persisted to disk prior to the
        // prefixing code being introduced.
        return prefixedBlob;
    }
    return std::vector<uint8_t>(prefixedBlob.begin() + kKeyBlobPrefixSize, prefixedBlob.end());
}

// Returns true if the blob's origin is soft-KeyMint, false otherwise or if there
// is no prefix on the passed-in blob.
//
bool prefixedKeyBlobIsSoftKeyMint(const std::vector<uint8_t>& prefixedBlob) {
    auto parsed = prefixedKeyBlobParsePrefix(prefixedBlob);
    return parsed.second;
}

// Inspects the given blob for prefixes.
// Returns the blob stripped of the prefix if present. The boolean argument is true if the blob was
// a software blob.
std::pair<std::vector<uint8_t>, bool>
dissectPrefixedKeyBlob(const std::vector<uint8_t>& prefixedBlob) {
    auto [hasPrefix, isSoftware] = prefixedKeyBlobParsePrefix(prefixedBlob);
    if (!hasPrefix) {
        // Not actually prefixed, blob was probably persisted to disk prior to the
        // prefixing code being introduced.
        return {prefixedBlob, false};
    }
    return {std::vector<uint8_t>(prefixedBlob.begin() + kKeyBlobPrefixSize, prefixedBlob.end()),
            isSoftware};
}

/*
 * Returns true if the parameter is not understood by KM 4.1 and older but can be enforced by
 * Keystore. These parameters need to be included in the returned KeyCharacteristics, but will not
 * be passed to the legacy backend.
 */
bool isNewAndKeystoreEnforceable(const KMV1::KeyParameter& param) {
    switch (param.tag) {
    case KMV1::Tag::MAX_BOOT_LEVEL:
        return true;
    case KMV1::Tag::USAGE_COUNT_LIMIT:
        return true;
    default:
        return false;
    }
}

std::vector<KMV1::KeyParameter>
extractGenerationParams(const std::vector<KMV1::KeyParameter>& params) {
    std::vector<KMV1::KeyParameter> result;
    std::copy_if(params.begin(), params.end(), std::back_inserter(result), isKeyCreationParameter);
    return result;
}

std::vector<KMV1::KeyParameter>
extractAttestationParams(const std::vector<KMV1::KeyParameter>& params) {
    std::vector<KMV1::KeyParameter> result;
    std::copy_if(params.begin(), params.end(), std::back_inserter(result), isAttestationParameter);
    return result;
}

std::vector<KMV1::KeyParameter>
extractNewAndKeystoreEnforceableParams(const std::vector<KMV1::KeyParameter>& params) {
    std::vector<KMV1::KeyParameter> result;
    std::copy_if(params.begin(), params.end(), std::back_inserter(result),
                 isNewAndKeystoreEnforceable);
    return result;
}

std::vector<KMV1::KeyParameter>
extractCombinedParams(const std::vector<KMV1::KeyCharacteristics>& characteristics) {
    std::vector<KMV1::KeyParameter> result;
    for (auto characteristic : characteristics) {
        std::copy(characteristic.authorizations.begin(), characteristic.authorizations.end(),
                  std::back_inserter(result));
    }
    return result;
}

ScopedAStatus convertErrorCode(KMV1::ErrorCode result) {
    if (result == KMV1::ErrorCode::OK) {
        return ScopedAStatus::ok();
    }
    return ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(result));
}

// Converts a V4 error code into a ScopedAStatus
ScopedAStatus convertErrorCode(V4_0_ErrorCode result) {
    return convertErrorCode(convert(result));
}

static KMV1::ErrorCode toErrorCode(const ScopedAStatus& status) {
    if (status.getExceptionCode() == EX_SERVICE_SPECIFIC) {
        return static_cast<KMV1::ErrorCode>(status.getServiceSpecificError());
    } else {
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }
}

static std::vector<V4_0::KeyParameter>
convertKeyParametersToLegacy(const std::vector<KeyParameter>& kps) {
    std::vector<V4_0::KeyParameter> legacyKps;
    legacyKps.reserve(kps.size());
    for (const auto& kp : kps) {
        auto p = convertKeyParameterToLegacy(kp);
        if (p.tag != V4_0::Tag::INVALID) {
            legacyKps.push_back(std::move(p));
        }
    }
    return legacyKps;
}

static std::vector<KeyParameter>
convertKeyParametersFromLegacy(const std::vector<V4_0_KeyParameter>& legacyKps) {
    std::vector<KeyParameter> kps(legacyKps.size());
    std::transform(legacyKps.begin(), legacyKps.end(), kps.begin(), convertKeyParameterFromLegacy);
    return kps;
}

static std::vector<KeyCharacteristics>
processLegacyCharacteristics(KeyMintSecurityLevel securityLevel,
                             const std::vector<KeyParameter>& genParams,
                             const V4_0_KeyCharacteristics& legacyKc, bool kmEnforcedOnly = false) {

    KeyCharacteristics kmEnforced{securityLevel, convertKeyParametersFromLegacy(
                                                     securityLevel == KeyMintSecurityLevel::SOFTWARE
                                                         ? legacyKc.softwareEnforced
                                                         : legacyKc.hardwareEnforced)};

    if (securityLevel == KeyMintSecurityLevel::SOFTWARE && legacyKc.hardwareEnforced.size() > 0) {
        LOG(WARNING) << "Unexpected hardware enforced parameters.";
    }

    if (kmEnforcedOnly) {
        return {kmEnforced};
    }

    KeyCharacteristics keystoreEnforced{KeyMintSecurityLevel::KEYSTORE, {}};

    if (securityLevel != KeyMintSecurityLevel::SOFTWARE) {
        // Don't include these tags on software backends, else they'd end up duplicated
        // across both the keystore-enforced and software keymaster-enforced tags.
        keystoreEnforced.authorizations = convertKeyParametersFromLegacy(legacyKc.softwareEnforced);
    }

    // Add all parameters that we know can be enforced by keystore but not by the legacy backend.
    auto unsupported_requested = extractNewAndKeystoreEnforceableParams(genParams);
    keystoreEnforced.authorizations.insert(keystoreEnforced.authorizations.end(),
                                           std::begin(unsupported_requested),
                                           std::end(unsupported_requested));

    return {kmEnforced, keystoreEnforced};
}

static V4_0_KeyFormat convertKeyFormatToLegacy(const KeyFormat& kf) {
    return static_cast<V4_0_KeyFormat>(kf);
}

static V4_0_HardwareAuthToken convertAuthTokenToLegacy(const std::optional<HardwareAuthToken>& at) {
    if (!at) return {};

    V4_0_HardwareAuthToken legacyAt;
    legacyAt.challenge = at->challenge;
    legacyAt.userId = at->userId;
    legacyAt.authenticatorId = at->authenticatorId;
    legacyAt.authenticatorType =
        static_cast<::android::hardware::keymaster::V4_0::HardwareAuthenticatorType>(
            at->authenticatorType);
    legacyAt.timestamp = at->timestamp.milliSeconds;
    legacyAt.mac = at->mac;
    return legacyAt;
}

static V4_0_VerificationToken
convertTimestampTokenToLegacy(const std::optional<TimeStampToken>& tst) {
    if (!tst) return {};

    V4_0_VerificationToken legacyVt;
    legacyVt.challenge = tst->challenge;
    legacyVt.timestamp = tst->timestamp.milliSeconds;
    // Legacy verification tokens were always minted by TEE.
    legacyVt.securityLevel = V4_0::SecurityLevel::TRUSTED_ENVIRONMENT;
    legacyVt.mac = tst->mac;
    return legacyVt;
}

static V4_0_HmacSharingParameters
convertSharedSecretParameterToLegacy(const SharedSecretParameters& ssp) {
    V4_0_HmacSharingParameters legacyHsp;
    legacyHsp.seed = ssp.seed;
    std::copy(ssp.nonce.begin(), ssp.nonce.end(), legacyHsp.nonce.data());
    return legacyHsp;
}

static std::vector<V4_0_HmacSharingParameters>
convertSharedSecretParametersToLegacy(const std::vector<SharedSecretParameters>& legacySsps) {
    std::vector<V4_0_HmacSharingParameters> ssps(legacySsps.size());
    std::transform(legacySsps.begin(), legacySsps.end(), ssps.begin(),
                   convertSharedSecretParameterToLegacy);
    return ssps;
}

void OperationSlotManager::setNumFreeSlots(uint8_t numFreeSlots) {
    std::lock_guard<std::mutex> lock(mNumFreeSlotsMutex);
    mNumFreeSlots = numFreeSlots;
}

std::optional<OperationSlot>
OperationSlotManager::claimSlot(std::shared_ptr<OperationSlotManager> operationSlots) {
    std::lock_guard<std::mutex> lock(operationSlots->mNumFreeSlotsMutex);
    if (operationSlots->mNumFreeSlots > 0) {
        operationSlots->mNumFreeSlots--;
        return OperationSlot(std::move(operationSlots), std::nullopt);
    }
    return std::nullopt;
}

OperationSlot
OperationSlotManager::claimReservedSlot(std::shared_ptr<OperationSlotManager> operationSlots) {
    std::unique_lock<std::mutex> reservedGuard(operationSlots->mReservedSlotMutex);
    return OperationSlot(std::move(operationSlots), std::move(reservedGuard));
}

OperationSlot::OperationSlot(std::shared_ptr<OperationSlotManager> slots,
                             std::optional<std::unique_lock<std::mutex>> reservedGuard)
    : mOperationSlots(std::move(slots)), mReservedGuard(std::move(reservedGuard)) {}

void OperationSlotManager::freeSlot() {
    std::lock_guard<std::mutex> lock(mNumFreeSlotsMutex);
    mNumFreeSlots++;
}

OperationSlot::~OperationSlot() {
    if (!mReservedGuard && mOperationSlots) {
        mOperationSlots->freeSlot();
    }
}

// KeyMintDevice implementation

ScopedAStatus KeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* _aidl_return) {
    auto result = mDevice->halVersion();
    _aidl_return->versionNumber = result.majorVersion * 10 + result.minorVersion;
    securityLevel_ = convert(result.securityLevel);
    _aidl_return->securityLevel = securityLevel_;
    _aidl_return->keyMintName = result.keymasterName;
    _aidl_return->keyMintAuthorName = result.authorName;
    _aidl_return->timestampTokenRequired = securityLevel_ == KMV1::SecurityLevel::STRONGBOX;
    return ScopedAStatus::ok();
}

ScopedAStatus KeyMintDevice::addRngEntropy(const std::vector<uint8_t>& in_data) {
    auto result = mDevice->addRngEntropy(in_data);
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    return convertErrorCode(result);
}

ScopedAStatus KeyMintDevice::generateKey(const std::vector<KeyParameter>& inKeyParams,
                                         const std::optional<AttestationKey>& in_attestationKey,
                                         KeyCreationResult* out_creationResult) {

    // Since KeyMaster doesn't support ECDH, route all key creation requests to
    // soft-KeyMint if and only an ECDH key is requested.
    //
    // For this to work we'll need to also route begin() and deleteKey() calls to
    // soft-KM. In order to do that, we'll prefix all keyblobs with whether it was
    // created by the real underlying KeyMaster HAL or whether it was created by
    // soft-KeyMint.
    //
    // See keyBlobPrefix() for more discussion.
    //
    for (const auto& keyParam : inKeyParams) {
        if (keyParam.tag == Tag::PURPOSE &&
            keyParam.value.get<KeyParameterValue::Tag::keyPurpose>() == KeyPurpose::AGREE_KEY) {
            auto ret =
                softKeyMintDevice_->generateKey(inKeyParams, in_attestationKey, out_creationResult);
            if (ret.isOk()) {
                out_creationResult->keyBlob = keyBlobPrefix(out_creationResult->keyBlob, true);
            }
            return ret;
        }
    }

    auto legacyKeyGenParams = convertKeyParametersToLegacy(extractGenerationParams(inKeyParams));
    KMV1::ErrorCode errorCode;
    auto result = mDevice->generateKey(
        legacyKeyGenParams, [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                                const V4_0_KeyCharacteristics& keyCharacteristics) {
            errorCode = convert(error);
            out_creationResult->keyBlob = keyBlobPrefix(keyBlob, false);
            out_creationResult->keyCharacteristics =
                processLegacyCharacteristics(securityLevel_, inKeyParams, keyCharacteristics);
        });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    if (errorCode == KMV1::ErrorCode::OK) {
        auto cert = getCertificate(inKeyParams, out_creationResult->keyBlob);
        if (std::holds_alternative<KMV1::ErrorCode>(cert)) {
            auto code = std::get<KMV1::ErrorCode>(cert);
            // We return OK in successful cases that do not generate a certificate.
            if (code != KMV1::ErrorCode::OK) {
                errorCode = code;
                deleteKey(out_creationResult->keyBlob);
            }
        } else {
            out_creationResult->certificateChain = std::get<std::vector<Certificate>>(cert);
        }
    }
    return convertErrorCode(errorCode);
}

ScopedAStatus KeyMintDevice::importKey(const std::vector<KeyParameter>& inKeyParams,
                                       KeyFormat in_inKeyFormat,
                                       const std::vector<uint8_t>& in_inKeyData,
                                       const std::optional<AttestationKey>& in_attestationKey,
                                       KeyCreationResult* out_creationResult) {
    // Since KeyMaster doesn't support ECDH, route all ECDH key import requests to
    // soft-KeyMint.
    //
    // For this to work we'll need to also route begin() and deleteKey() calls to
    // soft-KM. In order to do that, we'll prefix all keyblobs with whether it was
    // created by the real underlying KeyMaster HAL or whether it was created by
    // soft-KeyMint.
    //
    // See keyBlobPrefix() for more discussion.
    //
    for (const auto& keyParam : inKeyParams) {
        if (keyParam.tag == Tag::PURPOSE &&
            keyParam.value.get<KeyParameterValue::Tag::keyPurpose>() == KeyPurpose::AGREE_KEY) {
            auto ret = softKeyMintDevice_->importKey(inKeyParams, in_inKeyFormat, in_inKeyData,
                                                     in_attestationKey, out_creationResult);
            if (ret.isOk()) {
                out_creationResult->keyBlob = keyBlobPrefix(out_creationResult->keyBlob, true);
            }
            return ret;
        }
    }

    auto legacyKeyGENParams = convertKeyParametersToLegacy(extractGenerationParams(inKeyParams));
    auto legacyKeyFormat = convertKeyFormatToLegacy(in_inKeyFormat);
    KMV1::ErrorCode errorCode;
    auto result = mDevice->importKey(
        legacyKeyGENParams, legacyKeyFormat, in_inKeyData,
        [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
            const V4_0_KeyCharacteristics& keyCharacteristics) {
            errorCode = convert(error);
            out_creationResult->keyBlob = keyBlobPrefix(keyBlob, false);
            out_creationResult->keyCharacteristics =
                processLegacyCharacteristics(securityLevel_, inKeyParams, keyCharacteristics);
        });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    if (errorCode == KMV1::ErrorCode::OK) {
        auto cert = getCertificate(inKeyParams, out_creationResult->keyBlob);
        if (std::holds_alternative<KMV1::ErrorCode>(cert)) {
            auto code = std::get<KMV1::ErrorCode>(cert);
            // We return OK in successful cases that do not generate a certificate.
            if (code != KMV1::ErrorCode::OK) {
                errorCode = code;
                deleteKey(out_creationResult->keyBlob);
            }
        } else {
            out_creationResult->certificateChain = std::get<std::vector<Certificate>>(cert);
        }
    }
    return convertErrorCode(errorCode);
}

ScopedAStatus
KeyMintDevice::importWrappedKey(const std::vector<uint8_t>& in_inWrappedKeyData,
                                const std::vector<uint8_t>& in_inPrefixedWrappingKeyBlob,
                                const std::vector<uint8_t>& in_inMaskingKey,
                                const std::vector<KeyParameter>& in_inUnwrappingParams,
                                int64_t in_inPasswordSid, int64_t in_inBiometricSid,
                                KeyCreationResult* out_creationResult) {
    const std::vector<uint8_t>& wrappingKeyBlob =
        prefixedKeyBlobRemovePrefix(in_inPrefixedWrappingKeyBlob);
    if (prefixedKeyBlobIsSoftKeyMint(in_inPrefixedWrappingKeyBlob)) {
        return softKeyMintDevice_->importWrappedKey(
            in_inWrappedKeyData, wrappingKeyBlob, in_inMaskingKey, in_inUnwrappingParams,
            in_inPasswordSid, in_inBiometricSid, out_creationResult);
    }

    auto legacyUnwrappingParams = convertKeyParametersToLegacy(in_inUnwrappingParams);
    KMV1::ErrorCode errorCode;
    auto result = mDevice->importWrappedKey(
        in_inWrappedKeyData, wrappingKeyBlob, in_inMaskingKey, legacyUnwrappingParams,
        in_inPasswordSid, in_inBiometricSid,
        [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
            const V4_0_KeyCharacteristics& keyCharacteristics) {
            errorCode = convert(error);
            out_creationResult->keyBlob = keyBlobPrefix(keyBlob, false);
            out_creationResult->keyCharacteristics =
                processLegacyCharacteristics(securityLevel_, {}, keyCharacteristics);
        });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    if (errorCode == KMV1::ErrorCode::OK) {
        auto params = extractCombinedParams(out_creationResult->keyCharacteristics);
        auto cert = getCertificate(params, out_creationResult->keyBlob, true /* isWrappedKey */);
        // importWrappedKey used to not generate a certificate. Ignore the error to preserve
        // backwards compatibility with clients that can't successfully generate a certificate.
        if (std::holds_alternative<std::vector<Certificate>>(cert)) {
            out_creationResult->certificateChain = std::get<std::vector<Certificate>>(cert);
        }
    }
    return convertErrorCode(errorCode);
}

ScopedAStatus KeyMintDevice::upgradeKey(const std::vector<uint8_t>& in_inKeyBlobToUpgrade,
                                        const std::vector<KeyParameter>& in_inUpgradeParams,
                                        std::vector<uint8_t>* _aidl_return) {
    auto legacyUpgradeParams = convertKeyParametersToLegacy(in_inUpgradeParams);
    V4_0_ErrorCode errorCode;

    if (prefixedKeyBlobIsSoftKeyMint(in_inKeyBlobToUpgrade)) {
        auto status = softKeyMintDevice_->upgradeKey(
            prefixedKeyBlobRemovePrefix(in_inKeyBlobToUpgrade), in_inUpgradeParams, _aidl_return);
        if (!status.isOk()) {
            LOG(ERROR) << __func__ << " transaction failed. " << status.getDescription();
        } else {
            *_aidl_return = keyBlobPrefix(*_aidl_return, true);
        }
        return status;
    }

    auto result =
        mDevice->upgradeKey(prefixedKeyBlobRemovePrefix(in_inKeyBlobToUpgrade), legacyUpgradeParams,
                            [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& upgradedKeyBlob) {
                                errorCode = error;
                                *_aidl_return = keyBlobPrefix(upgradedKeyBlob, false);
                            });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    return convertErrorCode(errorCode);
}

ScopedAStatus KeyMintDevice::deleteKey(const std::vector<uint8_t>& prefixedKeyBlob) {
    const std::vector<uint8_t>& keyBlob = prefixedKeyBlobRemovePrefix(prefixedKeyBlob);
    if (prefixedKeyBlobIsSoftKeyMint(prefixedKeyBlob)) {
        return softKeyMintDevice_->deleteKey(keyBlob);
    }

    auto result = mDevice->deleteKey(keyBlob);
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    return convertErrorCode(result);
}

ScopedAStatus KeyMintDevice::deleteAllKeys() {
    auto result = mDevice->deleteAllKeys();
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    return convertErrorCode(result);
}

// We're not implementing this.
ScopedAStatus KeyMintDevice::destroyAttestationIds() {
    return ScopedAStatus::fromServiceSpecificError(
        static_cast<int32_t>(V4_0_ErrorCode::UNIMPLEMENTED));
}

ScopedAStatus KeyMintDevice::begin(KeyPurpose in_inPurpose,
                                   const std::vector<uint8_t>& prefixedKeyBlob,
                                   const std::vector<KeyParameter>& in_inParams,
                                   const std::optional<HardwareAuthToken>& in_inAuthToken,
                                   BeginResult* _aidl_return) {
    return beginInternal(in_inPurpose, prefixedKeyBlob, in_inParams, in_inAuthToken,
                         false /* useReservedSlot */, _aidl_return);
}

ScopedAStatus KeyMintDevice::beginInternal(KeyPurpose in_inPurpose,
                                           const std::vector<uint8_t>& prefixedKeyBlob,
                                           const std::vector<KeyParameter>& in_inParams,
                                           const std::optional<HardwareAuthToken>& in_inAuthToken,
                                           bool useReservedSlot, BeginResult* _aidl_return) {

    const std::vector<uint8_t>& in_inKeyBlob = prefixedKeyBlobRemovePrefix(prefixedKeyBlob);
    if (prefixedKeyBlobIsSoftKeyMint(prefixedKeyBlob)) {
        return softKeyMintDevice_->begin(in_inPurpose, in_inKeyBlob, in_inParams, in_inAuthToken,
                                         _aidl_return);
    }

    OperationSlot slot;
    // No need to claim a slot for software device.
    if (useReservedSlot) {
        // There is only one reserved slot. This function blocks until
        // the reserved slot becomes available.
        slot = OperationSlotManager::claimReservedSlot(mOperationSlots);
    } else {
        if (auto opt_slot = OperationSlotManager::claimSlot(mOperationSlots)) {
            slot = std::move(*opt_slot);
        } else {
            return convertErrorCode(V4_0_ErrorCode::TOO_MANY_OPERATIONS);
        }
    }

    auto legacyPurpose =
        static_cast<::android::hardware::keymaster::V4_0::KeyPurpose>(in_inPurpose);
    auto legacyParams = convertKeyParametersToLegacy(in_inParams);
    auto legacyAuthToken = convertAuthTokenToLegacy(in_inAuthToken);
    KMV1::ErrorCode errorCode;
    auto result =
        mDevice->begin(legacyPurpose, in_inKeyBlob, legacyParams, legacyAuthToken,
                       [&](V4_0_ErrorCode error, const hidl_vec<V4_0_KeyParameter>& outParams,
                           uint64_t operationHandle) {
                           errorCode = convert(error);
                           if (error == V4_0_ErrorCode::OK) {
                               _aidl_return->challenge = operationHandle;
                               _aidl_return->params = convertKeyParametersFromLegacy(outParams);
                               _aidl_return->operation = ndk::SharedRefBase::make<KeyMintOperation>(
                                   mDevice, operationHandle, std::move(slot));
                           }
                       });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
    }
    return convertErrorCode(errorCode);
}

ScopedAStatus KeyMintDevice::deviceLocked(bool passwordOnly,
                                          const std::optional<TimeStampToken>& timestampToken) {
    V4_0_VerificationToken token;
    if (timestampToken.has_value()) {
        token = convertTimestampTokenToLegacy(timestampToken.value());
    }
    auto ret = mDevice->deviceLocked(passwordOnly, token);
    if (!ret.isOk()) {
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    } else {
        return convertErrorCode(KMV1::ErrorCode::OK);
    }
}

ScopedAStatus KeyMintDevice::earlyBootEnded() {
    auto ret = mDevice->earlyBootEnded();
    if (!ret.isOk()) {
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    } else {
        return convertErrorCode(KMV1::ErrorCode::OK);
    }
}

ScopedAStatus
KeyMintDevice::convertStorageKeyToEphemeral(const std::vector<uint8_t>& prefixedStorageKeyBlob,
                                            std::vector<uint8_t>* ephemeralKeyBlob) {
    KMV1::ErrorCode km_error;

    /*
     * Wrapped storage keys cannot be emulated (and they don't need to, because if a platform
     * supports wrapped storage keys, then the legacy backend will support it too. So error out
     * if the wrapped storage key given is a soft keymint key.
     */
    if (prefixedKeyBlobIsSoftKeyMint(prefixedStorageKeyBlob)) {
        return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
    }

    const std::vector<uint8_t>& storageKeyBlob =
        prefixedKeyBlobRemovePrefix(prefixedStorageKeyBlob);

    auto hidlCb = [&](V4_0_ErrorCode ret, const hidl_vec<uint8_t>& exportedKeyBlob) {
        km_error = convert(ret);
        if (km_error != KMV1::ErrorCode::OK) return;
        /*
         * This must return the blob without the prefix since it will be used directly
         * as a storage encryption key. But this is alright, since this wrapped ephemeral
         * key shouldn't/won't ever be used with keymint.
         */
        *ephemeralKeyBlob = exportedKeyBlob;
    };

    auto ret = mDevice->exportKey(V4_0_KeyFormat::RAW, storageKeyBlob, {}, {}, hidlCb);
    if (!ret.isOk()) {
        LOG(ERROR) << __func__ << " export_key failed: " << ret.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    if (km_error != KMV1::ErrorCode::OK) {
        LOG(ERROR) << __func__ << " export_key failed, code " << int32_t(km_error);
    }

    return convertErrorCode(km_error);
}

ScopedAStatus KeyMintDevice::getKeyCharacteristics(
    const std::vector<uint8_t>& prefixedKeyBlob, const std::vector<uint8_t>& appId,
    const std::vector<uint8_t>& appData, std::vector<KeyCharacteristics>* keyCharacteristics) {
    auto [strippedKeyBlob, isSoftware] = dissectPrefixedKeyBlob(prefixedKeyBlob);
    if (isSoftware) {
        return softKeyMintDevice_->getKeyCharacteristics(strippedKeyBlob, appId, appData,
                                                         keyCharacteristics);
    } else {
        KMV1::ErrorCode km_error;
        auto ret = mDevice->getKeyCharacteristics(
            strippedKeyBlob, appId, appData,
            [&](V4_0_ErrorCode errorCode, const V4_0_KeyCharacteristics& v40KeyCharacteristics) {
                km_error = convert(errorCode);
                *keyCharacteristics =
                    processLegacyCharacteristics(securityLevel_, {} /* getParams */,
                                                 v40KeyCharacteristics, true /* kmEnforcedOnly */);
            });

        if (!ret.isOk()) {
            LOG(ERROR) << __func__ << " getKeyCharacteristics failed: " << ret.description();
            return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
        }
        if (km_error != KMV1::ErrorCode::OK) {
            LOG(ERROR) << __func__
                       << " getKeyCharacteristics failed with code: " << toString(km_error);
        }

        return convertErrorCode(km_error);
    }
}

ScopedAStatus KeyMintDevice::getRootOfTrustChallenge(std::array<uint8_t, 16>* /* challenge */) {
    return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
}

ScopedAStatus KeyMintDevice::getRootOfTrust(const std::array<uint8_t, 16>& /* challenge */,
                                            std::vector<uint8_t>* /* rootOfTrust */) {
    return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
}

ScopedAStatus KeyMintDevice::sendRootOfTrust(const std::vector<uint8_t>& /* rootOfTrust */) {
    return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
}

ScopedAStatus KeyMintDevice::setAdditionalAttestationInfo(
    const std::vector<KeyParameter>& /* additionalAttestationInfo */) {
    return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
}

ScopedAStatus KeyMintOperation::updateAad(const std::vector<uint8_t>& input,
                                          const std::optional<HardwareAuthToken>& optAuthToken,
                                          const std::optional<TimeStampToken>& optTimeStampToken) {
    V4_0_HardwareAuthToken authToken = convertAuthTokenToLegacy(optAuthToken);
    V4_0_VerificationToken verificationToken = convertTimestampTokenToLegacy(optTimeStampToken);

    KMV1::ErrorCode errorCode;
    auto result = mDevice->update(
        mOperationHandle, {V4_0::makeKeyParameter(V4_0::TAG_ASSOCIATED_DATA, input)}, {}, authToken,
        verificationToken,
        [&](V4_0_ErrorCode error, auto, auto, auto) { errorCode = convert(error); });

    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
    }

    // Operation slot is no longer occupied.
    if (errorCode != KMV1::ErrorCode::OK) {
        mOperationSlot = std::nullopt;
    }

    return convertErrorCode(errorCode);
}

void KeyMintOperation::setUpdateBuffer(std::vector<uint8_t> data) {
    mUpdateBuffer = std::move(data);
}

const std::vector<uint8_t>&
KeyMintOperation::getExtendedUpdateBuffer(const std::vector<uint8_t>& suffix) {
    if (mUpdateBuffer.empty()) {
        return suffix;
    } else {
        mUpdateBuffer.insert(mUpdateBuffer.end(), suffix.begin(), suffix.end());
        return mUpdateBuffer;
    }
}

ScopedAStatus KeyMintOperation::update(const std::vector<uint8_t>& input_raw,
                                       const std::optional<HardwareAuthToken>& optAuthToken,
                                       const std::optional<TimeStampToken>& optTimeStampToken,
                                       std::vector<uint8_t>* out_output) {
    V4_0_HardwareAuthToken authToken = convertAuthTokenToLegacy(optAuthToken);
    V4_0_VerificationToken verificationToken = convertTimestampTokenToLegacy(optTimeStampToken);

    size_t inputPos = 0;
    *out_output = {};
    KMV1::ErrorCode errorCode = KMV1::ErrorCode::OK;
    auto input = getExtendedUpdateBuffer(input_raw);

    while (inputPos < input.size() && errorCode == KMV1::ErrorCode::OK) {
        uint32_t consumed = 0;
        auto result =
            mDevice->update(mOperationHandle, {} /* inParams */,
                            {input.begin() + inputPos, input.end()}, authToken, verificationToken,
                            [&](V4_0_ErrorCode error, uint32_t inputConsumed, auto /* outParams */,
                                const hidl_vec<uint8_t>& output) {
                                errorCode = convert(error);
                                out_output->insert(out_output->end(), output.begin(), output.end());
                                consumed = inputConsumed;
                            });

        if (!result.isOk()) {
            LOG(ERROR) << __func__ << " transaction failed. " << result.description();
            errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
        }

        if (errorCode == KMV1::ErrorCode::OK && consumed == 0) {
            // Some very old KM implementations do not buffer sub blocks in certain block modes,
            // instead, the simply return consumed == 0. So we buffer the input here in the
            // hope that we complete the bock in a future call to update.
            setUpdateBuffer({input.begin() + inputPos, input.end()});
            return convertErrorCode(errorCode);
        }
        inputPos += consumed;
    }

    // Operation slot is no longer occupied.
    if (errorCode != KMV1::ErrorCode::OK) {
        mOperationSlot = std::nullopt;
    }

    return convertErrorCode(errorCode);
}

ScopedAStatus
KeyMintOperation::finish(const std::optional<std::vector<uint8_t>>& in_input,
                         const std::optional<std::vector<uint8_t>>& in_signature,
                         const std::optional<HardwareAuthToken>& in_authToken,
                         const std::optional<TimeStampToken>& in_timeStampToken,
                         const std::optional<std::vector<uint8_t>>& in_confirmationToken,
                         std::vector<uint8_t>* out_output) {
    auto input_raw = in_input.value_or(std::vector<uint8_t>());
    auto input = getExtendedUpdateBuffer(input_raw);
    auto signature = in_signature.value_or(std::vector<uint8_t>());
    V4_0_HardwareAuthToken authToken = convertAuthTokenToLegacy(in_authToken);
    V4_0_VerificationToken verificationToken = convertTimestampTokenToLegacy(in_timeStampToken);

    std::vector<V4_0_KeyParameter> inParams;
    if (in_confirmationToken) {
        inParams.push_back(makeKeyParameter(V4_0::TAG_CONFIRMATION_TOKEN, *in_confirmationToken));
    }

    KMV1::ErrorCode errorCode;
    auto result = mDevice->finish(
        mOperationHandle, inParams, input, signature, authToken, verificationToken,
        [&](V4_0_ErrorCode error, auto /* outParams */, const hidl_vec<uint8_t>& output) {
            errorCode = convert(error);
            *out_output = output;
        });

    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
    }

    mOperationSlot = std::nullopt;

    return convertErrorCode(errorCode);
}

ScopedAStatus KeyMintOperation::abort() {
    auto result = mDevice->abort(mOperationHandle);
    mOperationSlot = std::nullopt;
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
    }
    return convertErrorCode(result);
}

KeyMintOperation::~KeyMintOperation() {
    if (mOperationSlot) {
        auto error = abort();
        if (!error.isOk()) {
            LOG(WARNING) << "Error calling abort in ~KeyMintOperation: " << error.getMessage();
        }
    }
}

// SecureClock implementation

ScopedAStatus SecureClock::generateTimeStamp(int64_t in_challenge, TimeStampToken* _aidl_return) {
    KMV1::ErrorCode errorCode;
    auto result = mDevice->verifyAuthorization(
        in_challenge, {}, V4_0_HardwareAuthToken(),
        [&](V4_0_ErrorCode error, const V4_0_VerificationToken& token) {
            errorCode = convert(error);
            _aidl_return->challenge = token.challenge;
            _aidl_return->timestamp.milliSeconds = token.timestamp;
            _aidl_return->mac = token.mac;
        });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
    }
    return convertErrorCode(errorCode);
}

// SharedSecret implementation

ScopedAStatus SharedSecret::getSharedSecretParameters(SharedSecretParameters* _aidl_return) {
    KMV1::ErrorCode errorCode;
    auto result = mDevice->getHmacSharingParameters(
        [&](V4_0_ErrorCode error, const V4_0_HmacSharingParameters& params) {
            errorCode = convert(error);
            _aidl_return->seed = params.seed;
            std::copy(params.nonce.data(), params.nonce.data() + params.nonce.elementCount(),
                      std::back_inserter(_aidl_return->nonce));
        });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
    }
    return convertErrorCode(errorCode);
}

ScopedAStatus
SharedSecret::computeSharedSecret(const std::vector<SharedSecretParameters>& in_params,
                                  std::vector<uint8_t>* _aidl_return) {
    KMV1::ErrorCode errorCode;
    auto legacyParams = convertSharedSecretParametersToLegacy(in_params);
    auto result = mDevice->computeSharedHmac(
        legacyParams, [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& sharingCheck) {
            errorCode = convert(error);
            *_aidl_return = sharingCheck;
        });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " transaction failed. " << result.description();
        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
    }
    return convertErrorCode(errorCode);
}

// Certificate implementation

template <KMV1::Tag tag, KMV1::TagType type>
static auto getParam(const std::vector<KeyParameter>& keyParams, KMV1::TypedTag<type, tag> ttag)
    -> decltype(authorizationValue(ttag, KeyParameter())) {
    for (const auto& p : keyParams) {

        if (auto v = authorizationValue(ttag, p)) {
            return v;
        }
    }
    return {};
}

template <typename T>
static bool containsParam(const std::vector<KeyParameter>& keyParams, T ttag) {
    return static_cast<bool>(getParam(keyParams, ttag));
}

// Prefer the smallest.
// If no options are found, return the first.
template <typename T>
static typename KMV1::TypedTag2ValueType<T>::type
getMaximum(const std::vector<KeyParameter>& keyParams, T tag,
           std::vector<typename KMV1::TypedTag2ValueType<T>::type> sortedOptions) {
    auto bestSoFar = sortedOptions.end();
    for (const KeyParameter& kp : keyParams) {
        if (auto value = authorizationValue(tag, kp)) {
            auto candidate = std::find(sortedOptions.begin(), sortedOptions.end(), *value);
            // sortedOptions is sorted from best to worst. `std::distance(first, last)` counts the
            // hops from `first` to `last`. So a better `candidate` yields a positive distance to
            // `bestSoFar`.
            if (std::distance(candidate, bestSoFar) > 0) {
                bestSoFar = candidate;
            }
        }
    }
    if (bestSoFar == sortedOptions.end()) {
        return sortedOptions[0];
    }
    return *bestSoFar;
}

static std::variant<keystore::X509_Ptr, KMV1::ErrorCode>
makeCert(::android::sp<Keymaster> mDevice, const std::vector<KeyParameter>& keyParams,
         const std::vector<uint8_t>& keyBlob, bool isWrappedKey) {
    // Start generating the certificate.
    // Get public key for makeCert.
    KMV1::ErrorCode errorCode;
    std::vector<uint8_t> key;
    static std::vector<uint8_t> empty_vector;
    auto unwrapBlob = [&](auto b) -> const std::vector<uint8_t>& {
        if (b)
            return *b;
        else
            return empty_vector;
    };
    auto result = mDevice->exportKey(
        V4_0_KeyFormat::X509, keyBlob, unwrapBlob(getParam(keyParams, KMV1::TAG_APPLICATION_ID)),
        unwrapBlob(getParam(keyParams, KMV1::TAG_APPLICATION_DATA)),
        [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyMaterial) {
            errorCode = convert(error);
            key = keyMaterial;
        });
    if (!result.isOk()) {
        LOG(ERROR) << __func__ << " exportKey transaction failed. " << result.description();
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }
    if (errorCode != KMV1::ErrorCode::OK) {
        return errorCode;
    }
    // Get pkey for makeCert.
    CBS cbs;
    CBS_init(&cbs, key.data(), key.size());
    auto pkey = EVP_parse_public_key(&cbs);

    // makeCert
    std::optional<std::reference_wrapper<const std::vector<uint8_t>>> subject;
    if (auto blob = getParam(keyParams, KMV1::TAG_CERTIFICATE_SUBJECT)) {
        subject = *blob;
    }

    std::optional<std::reference_wrapper<const std::vector<uint8_t>>> serial;
    if (auto blob = getParam(keyParams, KMV1::TAG_CERTIFICATE_SERIAL)) {
        serial = *blob;
    }

    // There is no way to specify CERTIFICATE_NOT_BEFORE and CERTIFICATE_NOT_AFTER for wrapped keys.
    // So we provide default values.
    int64_t activation;
    if (isWrappedKey) {
        activation = 0;
    } else if (auto date = getParam(keyParams, KMV1::TAG_CERTIFICATE_NOT_BEFORE)) {
        activation = static_cast<int64_t>(*date);
    } else {
        return KMV1::ErrorCode::MISSING_NOT_BEFORE;
    }

    int64_t expiration;
    if (isWrappedKey) {
        expiration = kUndefinedNotAfter;
    } else if (auto date = getParam(keyParams, KMV1::TAG_CERTIFICATE_NOT_AFTER)) {
        expiration = static_cast<int64_t>(*date);
    } else {
        return KMV1::ErrorCode::MISSING_NOT_AFTER;
    }

    auto certOrError = keystore::makeCert(
        pkey, serial, subject, activation, expiration, false /* intentionally left blank */,
        std::nullopt /* intentionally left blank */, std::nullopt /* intentionally left blank */);
    if (std::holds_alternative<keystore::CertUtilsError>(certOrError)) {
        LOG(ERROR) << __func__ << ": Failed to make certificate";
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }
    return std::move(std::get<keystore::X509_Ptr>(certOrError));
}

static std::variant<keystore::Algo, KMV1::ErrorCode> getKeystoreAlgorithm(Algorithm algorithm) {
    switch (algorithm) {
    case Algorithm::RSA:
        return keystore::Algo::RSA;
    case Algorithm::EC:
        return keystore::Algo::ECDSA;
    default:
        LOG(ERROR) << __func__ << ": This should not be called with symmetric algorithm.";
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }
}

static std::variant<keystore::Padding, KMV1::ErrorCode> getKeystorePadding(PaddingMode padding) {
    switch (padding) {
    case PaddingMode::RSA_PKCS1_1_5_SIGN:
        return keystore::Padding::PKCS1_5;
    case PaddingMode::RSA_PSS:
        return keystore::Padding::PSS;
    default:
        return keystore::Padding::Ignored;
    }
}

static std::variant<keystore::Digest, KMV1::ErrorCode> getKeystoreDigest(Digest digest) {
    switch (digest) {
    case Digest::SHA1:
        return keystore::Digest::SHA1;
    case Digest::SHA_2_224:
        return keystore::Digest::SHA224;
    case Digest::SHA_2_256:
    case Digest::NONE:
        return keystore::Digest::SHA256;
    case Digest::SHA_2_384:
        return keystore::Digest::SHA384;
    case Digest::SHA_2_512:
        return keystore::Digest::SHA512;
    default:
        LOG(ERROR) << __func__ << ": Unknown digest.";
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }
}

std::optional<KMV1::ErrorCode>
KeyMintDevice::signCertificate(const std::vector<KeyParameter>& keyParams,
                               const std::vector<uint8_t>& prefixedKeyBlob, X509* cert) {

    auto algorithm = getParam(keyParams, KMV1::TAG_ALGORITHM);
    auto algoOrError = getKeystoreAlgorithm(*algorithm);
    if (std::holds_alternative<KMV1::ErrorCode>(algoOrError)) {
        return std::get<KMV1::ErrorCode>(algoOrError);
    }
    auto algo = std::get<keystore::Algo>(algoOrError);
    auto origPadding = getMaximum(keyParams, KMV1::TAG_PADDING,
                                  {PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN});
    auto paddingOrError = getKeystorePadding(origPadding);
    if (std::holds_alternative<KMV1::ErrorCode>(paddingOrError)) {
        return std::get<KMV1::ErrorCode>(paddingOrError);
    }
    auto padding = std::get<keystore::Padding>(paddingOrError);
    auto origDigest = getMaximum(keyParams, KMV1::TAG_DIGEST,
                                 {Digest::SHA_2_256, Digest::SHA_2_512, Digest::SHA_2_384,
                                  Digest::SHA_2_224, Digest::SHA1, Digest::NONE});
    auto digestOrError = getKeystoreDigest(origDigest);
    if (std::holds_alternative<KMV1::ErrorCode>(digestOrError)) {
        return std::get<KMV1::ErrorCode>(digestOrError);
    }
    auto digest = std::get<keystore::Digest>(digestOrError);

    KMV1::ErrorCode errorCode = KMV1::ErrorCode::OK;
    auto error = keystore::signCertWith(
        &*cert,
        [&](const uint8_t* data, size_t len) {
            std::vector<uint8_t> dataVec(data, data + len);
            std::vector<KeyParameter> kps = {
                KMV1::makeKeyParameter(KMV1::TAG_DIGEST, origDigest),
            };
            if (algorithm == KMV1::Algorithm::RSA) {
                kps.push_back(KMV1::makeKeyParameter(KMV1::TAG_PADDING, origPadding));
            }
            BeginResult beginResult;
            auto error = beginInternal(KeyPurpose::SIGN, prefixedKeyBlob, kps, HardwareAuthToken(),
                                       true /* useReservedSlot */, &beginResult);
            if (!error.isOk()) {
                errorCode = toErrorCode(error);
                return std::vector<uint8_t>();
            }

            std::vector<uint8_t> result;
            error = beginResult.operation->finish(dataVec,                     //
                                                  {} /* signature */,          //
                                                  {} /* authToken */,          //
                                                  {} /* timestampToken */,     //
                                                  {} /* confirmationToken */,  //
                                                  &result);
            if (!error.isOk()) {
                errorCode = toErrorCode(error);
                return std::vector<uint8_t>();
            }
            return result;
        },
        algo, padding, digest);
    if (error) {
        LOG(ERROR) << __func__
                   << ": signCertWith failed. (Callback diagnosed: " << toString(errorCode) << ")";
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }
    if (errorCode != KMV1::ErrorCode::OK) {
        return errorCode;
    }
    return std::nullopt;
}

std::variant<std::vector<Certificate>, KMV1::ErrorCode>
KeyMintDevice::getCertificate(const std::vector<KeyParameter>& keyParams,
                              const std::vector<uint8_t>& prefixedKeyBlob, bool isWrappedKey) {
    const std::vector<uint8_t>& keyBlob = prefixedKeyBlobRemovePrefix(prefixedKeyBlob);

    // There are no certificates for symmetric keys.
    auto algorithm = getParam(keyParams, KMV1::TAG_ALGORITHM);
    if (!algorithm) {
        LOG(ERROR) << __func__ << ": Unable to determine key algorithm.";
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }
    switch (*algorithm) {
    case Algorithm::RSA:
    case Algorithm::EC:
        break;
    default:
        return KMV1::ErrorCode::OK;
    }

    // If attestation was requested, call and use attestKey.
    if (containsParam(keyParams, KMV1::TAG_ATTESTATION_CHALLENGE)) {
        auto legacyParams = convertKeyParametersToLegacy(extractAttestationParams(keyParams));
        std::vector<Certificate> certs;
        KMV1::ErrorCode errorCode = KMV1::ErrorCode::OK;
        auto result = mDevice->attestKey(
            keyBlob, legacyParams,
            [&](V4_0::ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
                errorCode = convert(error);
                for (const auto& cert : certChain) {
                    Certificate certificate;
                    certificate.encodedCertificate = cert;
                    certs.push_back(certificate);
                }
            });
        if (!result.isOk()) {
            LOG(ERROR) << __func__ << ": Call to attestKey failed.";
            return KMV1::ErrorCode::UNKNOWN_ERROR;
        }
        if (errorCode != KMV1::ErrorCode::OK) {
            return errorCode;
        }
        return certs;
    }

    // makeCert
    auto certOrError = makeCert(mDevice, keyParams, keyBlob, isWrappedKey);
    if (std::holds_alternative<KMV1::ErrorCode>(certOrError)) {
        return std::get<KMV1::ErrorCode>(certOrError);
    }
    auto cert = std::move(std::get<keystore::X509_Ptr>(certOrError));

    // setIssuer
    auto error = keystore::setIssuer(&*cert, &*cert, false);
    if (error) {
        LOG(ERROR) << __func__ << ": Set issuer failed.";
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }

    // Signing
    auto canSelfSign =
        std::find_if(keyParams.begin(), keyParams.end(), [&](const KeyParameter& kp) {
            if (auto v = KMV1::authorizationValue(KMV1::TAG_PURPOSE, kp)) {
                return *v == KeyPurpose::SIGN;
            }
            return false;
        }) != keyParams.end();
    auto noAuthRequired = containsParam(keyParams, KMV1::TAG_NO_AUTH_REQUIRED);
    // If we cannot sign because of purpose or authorization requirement,
    if (!(canSelfSign && noAuthRequired)
        // or if self signing fails for any other reason,
        || signCertificate(keyParams, keyBlob, &*cert).has_value()) {
        // we sign with ephemeral key.
        keystore::EVP_PKEY_CTX_Ptr pkey_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL));
        EVP_PKEY_keygen_init(pkey_ctx.get());
        EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx.get(), NID_X9_62_prime256v1);
        EVP_PKEY* pkey_ptr = nullptr;
        EVP_PKEY_keygen(pkey_ctx.get(), &pkey_ptr);
        error = keystore::signCert(&*cert, pkey_ptr);
        if (error) {
            LOG(ERROR) << __func__ << ": signCert failed.";
            return KMV1::ErrorCode::UNKNOWN_ERROR;
        }
    }

    // encodeCert
    auto encodedCertOrError = keystore::encodeCert(&*cert);
    if (std::holds_alternative<keystore::CertUtilsError>(encodedCertOrError)) {
        LOG(ERROR) << __func__ << ": encodeCert failed.";
        return KMV1::ErrorCode::UNKNOWN_ERROR;
    }

    Certificate certificate{.encodedCertificate =
                                std::get<std::vector<uint8_t>>(encodedCertOrError)};
    std::vector certificates = {certificate};
    return certificates;
}

// Code to find the Keymaster devices (copied from existing code).

// Copied from system/security/keystore/include/keystore/keymaster_types.h.

// Changing this namespace alias will change the keymaster version.
namespace keymasterNs = ::android::hardware::keymaster::V4_1;

using keymasterNs::SecurityLevel;

// Copied from system/security/keystore/KeyStore.h.

using ::android::sp;
using keymasterNs::support::Keymaster;

template <typename T, size_t count> class Devices : public std::array<T, count> {
  public:
    T& operator[](SecurityLevel secLevel) {
        static_assert(uint32_t(SecurityLevel::SOFTWARE) == 0 &&
                          uint32_t(SecurityLevel::TRUSTED_ENVIRONMENT) == 1 &&
                          uint32_t(SecurityLevel::STRONGBOX) == 2,
                      "Numeric values of security levels have changed");
        return std::array<T, count>::at(static_cast<uint32_t>(secLevel));
    }
    T operator[](SecurityLevel secLevel) const {
        if (static_cast<uint32_t>(secLevel) > static_cast<uint32_t>(SecurityLevel::STRONGBOX)) {
            LOG(ERROR) << "Invalid security level requested";
            return {};
        }
        return (*const_cast<Devices*>(this))[secLevel];
    }
};

using KeymasterDevices = Devices<sp<Keymaster>, 3>;

// Copied from system/security/keystore/keystore_main.cpp.

using ::android::hardware::hidl_string;
using keymasterNs::support::Keymaster3;
using keymasterNs::support::Keymaster4;

template <typename Wrapper>
KeymasterDevices enumerateKeymasterDevices(IServiceManager* serviceManager) {
    KeymasterDevices result;
    serviceManager->listManifestByInterface(
        Wrapper::WrappedIKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
            auto try_get_device = [&](const auto& name, bool fail_silent) {
                auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
                if (fail_silent && !device) return;
                CHECK(device) << "Failed to get service for \""
                              << Wrapper::WrappedIKeymasterDevice::descriptor
                              << "\" with interface name \"" << name << "\"";

                sp<Keymaster> kmDevice(new Wrapper(device, name));
                auto halVersion = kmDevice->halVersion();
                SecurityLevel securityLevel = halVersion.securityLevel;
                LOG(INFO) << "found " << Wrapper::WrappedIKeymasterDevice::descriptor
                          << " with interface name " << name << " and seclevel "
                          << toString(securityLevel);
                CHECK(static_cast<uint32_t>(securityLevel) < result.size())
                    << "Security level of \"" << Wrapper::WrappedIKeymasterDevice::descriptor
                    << "\" with interface name \"" << name << "\" out of range";
                auto& deviceSlot = result[securityLevel];
                if (deviceSlot) {
                    if (!fail_silent) {
                        LOG(WARNING) << "Implementation of \""
                                     << Wrapper::WrappedIKeymasterDevice::descriptor
                                     << "\" with interface name \"" << name
                                     << "\" and security level: " << toString(securityLevel)
                                     << " Masked by other implementation of Keymaster";
                    }
                } else {
                    deviceSlot = kmDevice;
                }
            };
            bool has_default = false;
            for (auto& n : names) {
                try_get_device(n, false);
                if (n == "default") has_default = true;
            }
            // Make sure that we always check the default device. If we enumerate only what is
            // known to hwservicemanager, we miss a possible passthrough HAL.
            if (!has_default) {
                try_get_device("default", true /* fail_silent */);
            }
        });
    return result;
}

KeymasterDevices initializeKeymasters() {
    auto serviceManager = IServiceManager::getService();
    if (!serviceManager.get()) {
        // New devices no longer have HIDL support, so failing to get hwservicemanager is
        // expected behavior.
        LOG(INFO) << "Skipping keymaster compat, this system is AIDL only.";
        return KeymasterDevices();
    }
    auto result = enumerateKeymasterDevices<Keymaster4>(serviceManager.get());
    auto softKeymaster = result[SecurityLevel::SOFTWARE];
    if ((!result[SecurityLevel::TRUSTED_ENVIRONMENT]) && (!result[SecurityLevel::STRONGBOX])) {
        result = enumerateKeymasterDevices<Keymaster3>(serviceManager.get());
    }
    if (softKeymaster) result[SecurityLevel::SOFTWARE] = softKeymaster;
    if (result[SecurityLevel::SOFTWARE] && !result[SecurityLevel::TRUSTED_ENVIRONMENT]) {
        LOG(WARNING) << "No secure Keymaster implementation found, but device offers insecure"
                        " Keymaster HAL. Using as default.";
        result[SecurityLevel::TRUSTED_ENVIRONMENT] = result[SecurityLevel::SOFTWARE];
        result[SecurityLevel::SOFTWARE] = nullptr;
    }
    // The software bit was removed since we do not need it.
    return result;
}

void KeyMintDevice::setNumFreeSlots(uint8_t numFreeSlots) {
    mOperationSlots->setNumFreeSlots(numFreeSlots);
}

// Constructors and helpers.

KeyMintDevice::KeyMintDevice(sp<Keymaster> device, KeyMintSecurityLevel securityLevel)
    : mDevice(device), mOperationSlots(std::make_shared<OperationSlotManager>()),
      securityLevel_(securityLevel) {
    if (securityLevel == KeyMintSecurityLevel::STRONGBOX) {
        setNumFreeSlots(3);
    } else {
        setNumFreeSlots(15);
    }

    softKeyMintDevice_ = CreateKeyMintDevice(KeyMintSecurityLevel::SOFTWARE);
}

sp<Keymaster> getDevice(KeyMintSecurityLevel securityLevel) {
    static std::mutex mutex;
    static sp<Keymaster> teeDevice;
    static sp<Keymaster> sbDevice;
    std::lock_guard<std::mutex> lock(mutex);
    if (!teeDevice) {
        auto devices = initializeKeymasters();
        teeDevice = devices[V4_0::SecurityLevel::TRUSTED_ENVIRONMENT];
        sbDevice = devices[V4_0::SecurityLevel::STRONGBOX];
    }
    switch (securityLevel) {
    case KeyMintSecurityLevel::TRUSTED_ENVIRONMENT:
        return teeDevice;
    case KeyMintSecurityLevel::STRONGBOX:
        return sbDevice;
    default:
        return {};
    }
}

std::shared_ptr<IKeyMintDevice> getSoftwareKeymintDevice() {
    static std::mutex mutex;
    static std::shared_ptr<IKeyMintDevice> swDevice;
    std::lock_guard<std::mutex> lock(mutex);
    if (!swDevice) {
        swDevice = CreateKeyMintDevice(KeyMintSecurityLevel::SOFTWARE);
    }
    return swDevice;
}

std::shared_ptr<KeyMintDevice>
KeyMintDevice::getWrappedKeymasterDevice(KeyMintSecurityLevel securityLevel) {
    if (auto dev = getDevice(securityLevel)) {
        return ndk::SharedRefBase::make<KeyMintDevice>(std::move(dev), securityLevel);
    }
    return {};
}

std::shared_ptr<IKeyMintDevice>
KeyMintDevice::createKeyMintDevice(KeyMintSecurityLevel securityLevel) {
    if (securityLevel == KeyMintSecurityLevel::SOFTWARE) {
        return getSoftwareKeymintDevice();
    } else {
        return getWrappedKeymasterDevice(securityLevel);
    }
}

std::shared_ptr<SharedSecret> SharedSecret::createSharedSecret(KeyMintSecurityLevel securityLevel) {
    auto device = getDevice(securityLevel);
    if (!device) {
        return {};
    }
    return ndk::SharedRefBase::make<SharedSecret>(std::move(device));
}

std::shared_ptr<SecureClock> SecureClock::createSecureClock(KeyMintSecurityLevel securityLevel) {
    auto device = getDevice(securityLevel);
    if (!device) {
        return {};
    }
    return ndk::SharedRefBase::make<SecureClock>(std::move(device));
}

ScopedAStatus
KeystoreCompatService::getKeyMintDevice(KeyMintSecurityLevel in_securityLevel,
                                        std::shared_ptr<IKeyMintDevice>* _aidl_return) {
    auto i = mDeviceCache.find(in_securityLevel);
    if (i == mDeviceCache.end()) {
        auto device = KeyMintDevice::createKeyMintDevice(in_securityLevel);
        if (!device) {
            return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
        }
        i = mDeviceCache.insert(i, {in_securityLevel, std::move(device)});
    }
    *_aidl_return = i->second;
    return ScopedAStatus::ok();
}

ScopedAStatus KeystoreCompatService::getSharedSecret(KeyMintSecurityLevel in_securityLevel,
                                                     std::shared_ptr<ISharedSecret>* _aidl_return) {
    auto i = mSharedSecretCache.find(in_securityLevel);
    if (i == mSharedSecretCache.end()) {
        auto secret = SharedSecret::createSharedSecret(in_securityLevel);
        if (!secret) {
            return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
        }
        i = mSharedSecretCache.insert(i, {in_securityLevel, std::move(secret)});
    }
    *_aidl_return = i->second;
    return ScopedAStatus::ok();
}

ScopedAStatus KeystoreCompatService::getSecureClock(std::shared_ptr<ISecureClock>* _aidl_return) {
    if (!mSecureClock) {
        // The legacy verification service was always provided by the TEE variant.
        auto clock = SecureClock::createSecureClock(KeyMintSecurityLevel::TRUSTED_ENVIRONMENT);
        if (!clock) {
            return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
        }
        mSecureClock = std::move(clock);
    }
    *_aidl_return = mSecureClock;
    return ScopedAStatus::ok();
}
