Keystore 2.0: Make compatiblity wrapper use union KeyParameters.

Test: N/A
Change-Id: I411d90a71c5722281f13c28d55961d571f2eec90
diff --git a/keystore2/src/km_compat/Android.bp b/keystore2/src/km_compat/Android.bp
index 01cf2cc..7ca6a63 100644
--- a/keystore2/src/km_compat/Android.bp
+++ b/keystore2/src/km_compat/Android.bp
@@ -56,6 +56,7 @@
         "libcrypto",
         "libhidlbase",
         "libkeymaster4_1support",
+        "libkeymint_support",
         "libkeystore2_crypto",
         "libutils",
     ],
@@ -75,6 +76,7 @@
 }
 
 cc_test {
+    name: "keystore2_km_compat_test_cpp",
     cflags: [
         "-Wall",
         "-Werror",
@@ -83,6 +85,7 @@
     srcs: [
         "certificate_test.cpp",
         "gtest_main.cpp",
+        "parameter_conversion_test.cpp",
         "slot_test.cpp",
     ],
     shared_libs: [
@@ -97,9 +100,9 @@
         "libcrypto",
         "libhidlbase",
         "libkeymaster4_1support",
+        "libkeymint_support",
         "libkeystore2_crypto",
         "libkm_compat",
         "libutils",
     ],
-    name: "keystore2_certificate_test",
 }
diff --git a/keystore2/src/km_compat/certificate_test.cpp b/keystore2/src/km_compat/certificate_test.cpp
index d8c8c0a..9307569 100644
--- a/keystore2/src/km_compat/certificate_test.cpp
+++ b/keystore2/src/km_compat/certificate_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include "km_compat.h"
+#include <keymint_support/keymint_tags.h>
 
 #include <aidl/android/hardware/security/keymint/Algorithm.h>
 #include <aidl/android/hardware/security/keymint/BlockMode.h>
@@ -39,10 +40,15 @@
 using ::aidl::android::hardware::security::keymint::SecurityLevel;
 using ::aidl::android::hardware::security::keymint::Tag;
 
+namespace KMV1 = ::aidl::android::hardware::security::keymint;
+
 static std::variant<std::vector<Certificate>, ScopedAStatus>
 getCertificate(const std::vector<KeyParameter>& keyParams) {
     static std::shared_ptr<KeyMintDevice> device =
         KeyMintDevice::createKeyMintDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
+    if (!device) {
+        return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
+    }
     ByteArray blob;
     KeyCharacteristics characteristics;
     std::vector<Certificate> certChain;
@@ -69,9 +75,9 @@
 
 static std::vector<KeyParameter> getRSAKeyParams(const std::vector<KeyParameter>& extraParams) {
     auto keyParams = std::vector<KeyParameter>({
-        KeyParameter{.tag = Tag::ALGORITHM, .integer = static_cast<int32_t>(Algorithm::RSA)},
-        KeyParameter{.tag = Tag::KEY_SIZE, .integer = 2048},
-        KeyParameter{.tag = Tag::RSA_PUBLIC_EXPONENT, .longInteger = 65537},
+        KMV1::makeKeyParameter(KMV1::TAG_ALGORITHM, Algorithm::RSA),
+        KMV1::makeKeyParameter(KMV1::TAG_KEY_SIZE, 2048),
+        KMV1::makeKeyParameter(KMV1::TAG_RSA_PUBLIC_EXPONENT, 65537),
     });
     keyParams.insert(keyParams.end(), extraParams.begin(), extraParams.end());
     return keyParams;
@@ -79,11 +85,11 @@
 
 TEST(CertificateTest, TestRSAKeygen) {
     auto keyParams = getRSAKeyParams({
-        KeyParameter{.tag = Tag::DIGEST, .integer = static_cast<int32_t>(Digest::SHA_2_256)},
-        KeyParameter{.tag = Tag::PADDING, .integer = static_cast<int32_t>(PaddingMode::RSA_PSS)},
-        KeyParameter{.tag = Tag::NO_AUTH_REQUIRED, .boolValue = true},
-        KeyParameter{.tag = Tag::PURPOSE, .integer = static_cast<int32_t>(KeyPurpose::SIGN)},
-        KeyParameter{.tag = Tag::PURPOSE, .integer = static_cast<int32_t>(KeyPurpose::ENCRYPT)},
+        KMV1::makeKeyParameter(KMV1::TAG_DIGEST, Digest::SHA_2_256),
+        KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::RSA_PSS),
+        KMV1::makeKeyParameter(KMV1::TAG_NO_AUTH_REQUIRED),
+        KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
+        KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::ENCRYPT),
     });
     auto result = getCertificate(keyParams);
     ensureCertChainSize(result, 1);
@@ -91,21 +97,21 @@
 
 TEST(CertificateTest, TestAES) {
     auto keyParams = {
-        KeyParameter{.tag = Tag::ALGORITHM, .integer = static_cast<int32_t>(Algorithm::AES)},
-        KeyParameter{.tag = Tag::KEY_SIZE, .integer = 128},
-        KeyParameter{.tag = Tag::BLOCK_MODE, .integer = static_cast<int32_t>(BlockMode::CBC)},
-        KeyParameter{.tag = Tag::PADDING, .integer = static_cast<int32_t>(PaddingMode::NONE)},
-        KeyParameter{.tag = Tag::PURPOSE, .integer = static_cast<int32_t>(KeyPurpose::ENCRYPT)},
+        KMV1::makeKeyParameter(KMV1::TAG_ALGORITHM, Algorithm::AES),
+        KMV1::makeKeyParameter(KMV1::TAG_KEY_SIZE, 128),
+        KMV1::makeKeyParameter(KMV1::TAG_BLOCK_MODE, BlockMode::CBC),
+        KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::NONE),
+        KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::ENCRYPT),
     };
     auto result = getCertificate(keyParams);
     ensureCertChainSize(result, 0);
 }
 
-TEST(CertificateTest, TestAttestion) {
+TEST(CertificateTest, TestAttestation) {
     auto keyParams = getRSAKeyParams({
-        KeyParameter{.tag = Tag::PURPOSE, .integer = static_cast<int32_t>(KeyPurpose::SIGN)},
-        KeyParameter{.tag = Tag::ATTESTATION_CHALLENGE, .blob = {42}},
-        KeyParameter{.tag = Tag::ATTESTATION_APPLICATION_ID, .blob = {42}},
+        KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
+        KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_CHALLENGE, 42),
+        KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_APPLICATION_ID, 42),
     });
     auto result = getCertificate(keyParams);
     ensureCertChainSize(result, 3);
@@ -114,10 +120,10 @@
 
 TEST(CertificateTest, TestRSAKeygenNoEncryptNoAuthRequired) {
     auto keyParams = getRSAKeyParams({
-        KeyParameter{.tag = Tag::DIGEST, .integer = static_cast<int32_t>(Digest::SHA_2_256)},
-        KeyParameter{.tag = Tag::PADDING, .integer = static_cast<int32_t>(PaddingMode::RSA_PSS)},
-        KeyParameter{.tag = Tag::NO_AUTH_REQUIRED, .boolValue = true},
-        KeyParameter{.tag = Tag::PURPOSE, .integer = static_cast<int32_t>(KeyPurpose::SIGN)},
+        KMV1::makeKeyParameter(KMV1::TAG_DIGEST, Digest::SHA_2_256),
+        KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::RSA_PSS),
+        KMV1::makeKeyParameter(KMV1::TAG_NO_AUTH_REQUIRED, true),
+        KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
     });
     auto result = getCertificate(keyParams);
     ensureCertChainSize(result, 1);
@@ -126,9 +132,9 @@
 
 TEST(CertificateTest, TestRSAKeygenNoEncryptAuthRequired) {
     auto keyParams = getRSAKeyParams({
-        KeyParameter{.tag = Tag::DIGEST, .integer = static_cast<int32_t>(Digest::SHA_2_256)},
-        KeyParameter{.tag = Tag::PADDING, .integer = static_cast<int32_t>(PaddingMode::RSA_PSS)},
-        KeyParameter{.tag = Tag::PURPOSE, .integer = static_cast<int32_t>(KeyPurpose::SIGN)},
+        KMV1::makeKeyParameter(KMV1::TAG_DIGEST, Digest::SHA_2_256),
+        KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::RSA_PSS),
+        KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
     });
     auto result = getCertificate(keyParams);
     ensureCertChainSize(result, 1);
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 7900576..c9af80d 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -16,6 +16,7 @@
 
 #include "km_compat.h"
 
+#include "km_compat_type_conversion.h"
 #include <aidl/android/hardware/security/keymint/Algorithm.h>
 #include <aidl/android/hardware/security/keymint/Digest.h>
 #include <aidl/android/hardware/security/keymint/PaddingMode.h>
@@ -23,10 +24,12 @@
 #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 <keymasterV4_1/keymaster_tags.h>
+
+#include "certificate_utils.h"
 
 using ::aidl::android::hardware::security::keymint::Algorithm;
 using ::aidl::android::hardware::security::keymint::Digest;
@@ -42,6 +45,9 @@
 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;
 
 // Utility functions
 
@@ -53,75 +59,13 @@
     return ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(result));
 }
 
-// TODO: The enum representation will need to be updated when we get unions.
-static V4_0_KeyParameter convertKeyParameterToLegacy(const KeyParameter& kp) {
-    V4_0_KeyParameter lkp;
-    lkp.tag = static_cast<::android::hardware::keymaster::V4_0::Tag>(kp.tag);
-    switch (::android::hardware::keymaster::V4_0::typeFromTag(lkp.tag)) {
-    case TagType::ENUM:
-    case TagType::ENUM_REP:
-    case TagType::UINT:
-    case TagType::UINT_REP:
-        lkp.f.integer = kp.integer;
-        break;
-    case TagType::ULONG:
-    case TagType::ULONG_REP:
-        lkp.f.longInteger = kp.longInteger;
-        break;
-    case TagType::DATE:
-        lkp.f.dateTime = kp.longInteger;
-        break;
-    case TagType::BOOL:
-        lkp.f.boolValue = kp.boolValue;
-        break;
-    case TagType::BIGNUM:
-    case TagType::BYTES:
-        lkp.blob = kp.blob;
-        break;
-    case TagType::INVALID:
-        break;
-    }
-    return lkp;
-}
-
-static std::vector<V4_0_KeyParameter>
+static std::vector<V4_0::KeyParameter>
 convertKeyParametersToLegacy(const std::vector<KeyParameter>& kps) {
-    std::vector<V4_0_KeyParameter> legacyKps(kps.size());
+    std::vector<V4_0::KeyParameter> legacyKps(kps.size());
     std::transform(kps.begin(), kps.end(), legacyKps.begin(), convertKeyParameterToLegacy);
     return legacyKps;
 }
 
-// TODO: The enum representation will need to be updated when we get unions.
-static KeyParameter convertKeyParameterFromLegacy(const V4_0_KeyParameter& lkp) {
-    KeyParameter kp;
-    kp.tag = static_cast<Tag>(lkp.tag);
-    switch (::android::hardware::keymaster::V4_0::typeFromTag(lkp.tag)) {
-    case TagType::ENUM:
-    case TagType::ENUM_REP:
-    case TagType::UINT:
-    case TagType::UINT_REP:
-        kp.integer = lkp.f.integer;
-        break;
-    case TagType::ULONG:
-    case TagType::ULONG_REP:
-        kp.longInteger = lkp.f.longInteger;
-        break;
-    case TagType::DATE:
-        kp.longInteger = lkp.f.dateTime;
-        break;
-    case TagType::BOOL:
-        kp.boolValue = lkp.f.boolValue;
-        break;
-    case TagType::BIGNUM:
-    case TagType::BYTES:
-        kp.blob = lkp.blob;
-        break;
-    case TagType::INVALID:
-        break;
-    }
-    return kp;
-}
-
 static std::vector<KeyParameter>
 convertKeyParametersFromLegacy(const std::vector<V4_0_KeyParameter>& legacyKps) {
     std::vector<KeyParameter> kps(legacyKps.size());
@@ -487,29 +431,32 @@
 
 // Certificate implementation
 
-static std::optional<KeyParameter> getParam(const std::vector<KeyParameter>& keyParams, Tag tag) {
-    auto it = find_if(keyParams.begin(), keyParams.end(),
-                      [&](const KeyParameter& kp) { return kp.tag == tag; });
-    if (it == keyParams.end()) {
-        return std::nullopt;
+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 std::optional(*it);
+    return {};
 }
 
-static bool containsParam(const std::vector<KeyParameter>& keyParams, Tag tag) {
-    return getParam(keyParams, tag).has_value();
+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 T getMaximum(const std::vector<KeyParameter>& keyParams, Tag tag,
-                    std::vector<T> sortedOptions) {
+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 (kp.tag == tag) {
-            auto it =
-                std::find(sortedOptions.begin(), sortedOptions.end(), static_cast<T>(kp.integer));
+        if (auto value = authorizationValue(tag, kp)) {
+            auto it = std::find(sortedOptions.begin(), sortedOptions.end(), *value);
             if (std::distance(it, bestSoFar) < 0) {
                 bestSoFar = it;
             }
@@ -521,40 +468,23 @@
     return *bestSoFar;
 }
 
-// TODO: What should I do if these tags don't exist?  An empty blob might be okay, but what about
-// the integers and longs?
-// TODO: Migrate to using accessTagValue when possible.
-static std::vector<uint8_t> getBlob(const std::optional<KeyParameter> kp) {
-    if (!kp.has_value()) {
-        return {};
-    }
-    return kp->blob;
-}
-
-static int32_t getLong(std::optional<KeyParameter> kp) {
-    if (!kp.has_value()) {
-        return -1;
-    }
-    return kp->longInteger;
-}
-
-static int64_t getInteger(std::optional<KeyParameter> kp) {
-    if (!kp.has_value()) {
-        return -1;
-    }
-    return kp->integer;
-}
-
 static std::variant<keystore::X509_Ptr, V4_0_ErrorCode>
 makeCert(::android::sp<Keymaster> mDevice, const std::vector<KeyParameter>& keyParams,
          const std::vector<uint8_t>& keyBlob) {
     // Start generating the certificate.
     // Get public key for makeCert.
-    V4_0_ErrorCode errorCode = V4_0_ErrorCode::OK;
+    V4_0_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, getBlob(getParam(keyParams, Tag::APPLICATION_ID)),
-        getBlob(getParam(keyParams, Tag::APPLICATION_DATA)),
+        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 = error;
             key = keyMaterial;
@@ -572,13 +502,21 @@
     // makeCert
     // TODO: Get the serial and subject from key params once the tags are added.  Also use new tags
     // for the two datetime parameters once we get those.
+
+    uint64_t activation = 0;
+    if (auto date = getParam(keyParams, KMV1::TAG_ACTIVE_DATETIME)) {
+        activation = *date;
+    }
+    uint64_t expiration = std::numeric_limits<uint64_t>::max();
+    if (auto date = getParam(keyParams, KMV1::TAG_USAGE_EXPIRE_DATETIME)) {
+        expiration = *date;
+    }
+
     auto certOrError = keystore::makeCert(
-        pkey, 42, "TODO", getLong(getParam(keyParams, Tag::ACTIVE_DATETIME)),
-        getLong(getParam(keyParams, Tag::USAGE_EXPIRE_DATETIME)),
-        false /* intentionally left blank */, std::nullopt /* intentionally left blank */,
-        std::nullopt /* intentionally left blank */);
+        pkey, 42, "TODO", activation, expiration, false /* intentionally left blank */,
+        std::nullopt /* intentionally left blank */, std::nullopt /* intentionally left blank */);
     if (std::holds_alternative<keystore::CertUtilsError>(certOrError)) {
-        // TODO: What error should I actually return?  And the same everywhere below.
+        LOG(ERROR) << __func__ << ": Failed to make certificate";
         return V4_0_ErrorCode::UNKNOWN_ERROR;
     }
     return std::move(std::get<keystore::X509_Ptr>(certOrError));
@@ -591,6 +529,7 @@
     case Algorithm::EC:
         return keystore::Algo::ECDSA;
     default:
+        LOG(ERROR) << __func__ << ": This should not be called with symmetric algorithm.";
         return V4_0_ErrorCode::UNKNOWN_ERROR;
     }
 }
@@ -620,6 +559,7 @@
     case Digest::SHA_2_512:
         return keystore::Digest::SHA512;
     default:
+        LOG(ERROR) << __func__ << ": Unknown digest.";
         return V4_0_ErrorCode::UNKNOWN_ERROR;
     }
 }
@@ -627,21 +567,21 @@
 std::optional<V4_0_ErrorCode>
 KeyMintDevice::signCertificate(const std::vector<KeyParameter>& keyParams,
                                const std::vector<uint8_t>& keyBlob, X509* cert) {
-    auto algorithm = static_cast<Algorithm>(getInteger(getParam(keyParams, Tag::ALGORITHM)));
-    auto algoOrError = getKeystoreAlgorithm(algorithm);
+    auto algorithm = getParam(keyParams, KMV1::TAG_ALGORITHM);
+    auto algoOrError = getKeystoreAlgorithm(*algorithm);
     if (std::holds_alternative<V4_0_ErrorCode>(algoOrError)) {
         return std::get<V4_0_ErrorCode>(algoOrError);
     }
     auto algo = std::get<keystore::Algo>(algoOrError);
-    auto origPadding = getMaximum<PaddingMode>(
-        keyParams, Tag::PADDING, {PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN});
+    auto origPadding = getMaximum(keyParams, KMV1::TAG_PADDING,
+                                  {PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN});
     auto paddingOrError = getKeystorePadding(origPadding);
     if (std::holds_alternative<V4_0_ErrorCode>(paddingOrError)) {
         return std::get<V4_0_ErrorCode>(paddingOrError);
     }
     auto padding = std::get<keystore::Padding>(paddingOrError);
-    auto origDigest = getMaximum<Digest>(
-        keyParams, Tag::DIGEST,
+    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});
     auto digestOrError = getKeystoreDigest(origDigest);
     if (std::holds_alternative<V4_0_ErrorCode>(digestOrError)) {
@@ -655,8 +595,8 @@
         [&](const uint8_t* data, size_t len) {
             std::vector<uint8_t> dataVec(data, data + len);
             std::vector<KeyParameter> kps = {
-                KeyParameter{.tag = Tag::PADDING, .integer = static_cast<int32_t>(origPadding)},
-                KeyParameter{.tag = Tag::DIGEST, .integer = static_cast<int32_t>(origDigest)},
+                KMV1::makeKeyParameter(KMV1::TAG_PADDING, origPadding),
+                KMV1::makeKeyParameter(KMV1::TAG_DIGEST, origDigest),
             };
             BeginResult beginResult;
             auto error = begin(KeyPurpose::SIGN, keyBlob, kps, HardwareAuthToken(), &beginResult);
@@ -683,6 +623,8 @@
         },
         algo, padding, digest);
     if (error) {
+        LOG(ERROR) << __func__
+                   << ": signCertWith failed. (Callback diagnosed: " << toString(errorCode) << ")";
         return V4_0_ErrorCode::UNKNOWN_ERROR;
     }
     if (errorCode != V4_0_ErrorCode::OK) {
@@ -695,16 +637,21 @@
 KeyMintDevice::getCertificate(const std::vector<KeyParameter>& keyParams,
                               const std::vector<uint8_t>& keyBlob) {
     // There are no certificates for symmetric keys.
-    auto algorithm = static_cast<Algorithm>(getInteger(getParam(keyParams, Tag::ALGORITHM)));
-    switch (algorithm) {
+    auto algorithm = getParam(keyParams, KMV1::TAG_ALGORITHM);
+    if (!algorithm) {
+        LOG(ERROR) << __func__ << ": Unable to determine key algorithm.";
+        return V4_0_ErrorCode::UNKNOWN_ERROR;
+    }
+    switch (*algorithm) {
     case Algorithm::RSA:
     case Algorithm::EC:
         break;
     default:
         return V4_0_ErrorCode::OK;
     }
+
     // If attestation was requested, call and use attestKey.
-    if (containsParam(keyParams, Tag::ATTESTATION_CHALLENGE)) {
+    if (containsParam(keyParams, KMV1::TAG_ATTESTATION_CHALLENGE)) {
         auto legacyParams = convertKeyParametersToLegacy(keyParams);
         std::vector<Certificate> certs;
         V4_0_ErrorCode errorCode = V4_0_ErrorCode::OK;
@@ -743,10 +690,12 @@
     // Signing
     auto canSelfSign =
         std::find_if(keyParams.begin(), keyParams.end(), [&](const KeyParameter& kp) {
-            return kp.tag == Tag::PURPOSE &&
-                   static_cast<KeyPurpose>(kp.integer) == KeyPurpose::SIGN;
+            if (auto v = KMV1::authorizationValue(KMV1::TAG_PURPOSE, kp)) {
+                return *v == KeyPurpose::SIGN;
+            }
+            return false;
         }) != keyParams.end();
-    auto noAuthRequired = containsParam(keyParams, Tag::NO_AUTH_REQUIRED);
+    auto noAuthRequired = containsParam(keyParams, KMV1::TAG_NO_AUTH_REQUIRED);
     if (canSelfSign && noAuthRequired) {
         auto errorCode = signCertificate(keyParams, keyBlob, &*cert);
         if (errorCode.has_value()) {
@@ -900,13 +849,19 @@
 
 std::shared_ptr<KeyMintDevice>
 KeyMintDevice::createKeyMintDevice(KeyMintSecurityLevel securityLevel) {
-    auto secLevel = static_cast<SecurityLevel>(securityLevel);
-    auto devices = initializeKeymasters();
-    auto device = devices[secLevel];
-    if (!device) {
-        return {};
+    static std::mutex mutex;
+    std::lock_guard<std::mutex> lock(mutex);
+    static std::shared_ptr<KeyMintDevice> device_ptr;
+    if (!device_ptr) {
+        auto secLevel = static_cast<SecurityLevel>(securityLevel);
+        auto devices = initializeKeymasters();
+        auto device = devices[secLevel];
+        if (!device) {
+            return {};
+        }
+        device_ptr = ndk::SharedRefBase::make<KeyMintDevice>(std::move(device), securityLevel);
     }
-    return ndk::SharedRefBase::make<KeyMintDevice>(std::move(device), securityLevel);
+    return device_ptr;
 }
 
 ScopedAStatus
diff --git a/keystore2/src/km_compat/km_compat_service.cpp b/keystore2/src/km_compat/km_compat_service.cpp
index 56d7909..d2ced49 100644
--- a/keystore2/src/km_compat/km_compat_service.cpp
+++ b/keystore2/src/km_compat/km_compat_service.cpp
@@ -17,13 +17,24 @@
 #include "km_compat.h"
 #include <android/binder_manager.h>
 
+#include <mutex>
+
 extern "C" {
 
 // Create a KeyMintDevice and add it as a service.
 int32_t addKeyMintDeviceService() {
-    std::shared_ptr<KeystoreCompatService> ti = ndk::SharedRefBase::make<KeystoreCompatService>();
-    const auto instanceName = "android.security.compat";
-    binder_status_t status = AServiceManager_addService(ti->asBinder().get(), instanceName);
+    static std::mutex mutex;
+    std::lock_guard<std::mutex> lock(mutex);
+    static std::shared_ptr<KeystoreCompatService> ti;
+    binder_status_t status = STATUS_OK;
+    if (!ti) {
+        ti = ndk::SharedRefBase::make<KeystoreCompatService>();
+        const auto instanceName = "android.security.compat";
+        status = AServiceManager_addService(ti->asBinder().get(), instanceName);
+        if (status != STATUS_OK) {
+            ti.reset();
+        }
+    }
     return status;
 }
 }
diff --git a/keystore2/src/km_compat/km_compat_type_conversion.h b/keystore2/src/km_compat/km_compat_type_conversion.h
new file mode 100644
index 0000000..97c61ce
--- /dev/null
+++ b/keystore2/src/km_compat/km_compat_type_conversion.h
@@ -0,0 +1,886 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <keymasterV4_1/keymaster_tags.h>
+#include <keymint_support/keymint_tags.h>
+
+namespace V4_0 = ::android::hardware::keymaster::V4_0;
+namespace V4_1 = ::android::hardware::keymaster::V4_1;
+namespace KMV1 = ::aidl::android::hardware::security::keymint;
+
+static V4_0::KeyPurpose convert(KMV1::KeyPurpose p) {
+    switch (p) {
+    case KMV1::KeyPurpose::ENCRYPT:
+        return V4_0::KeyPurpose::ENCRYPT;
+    case KMV1::KeyPurpose::DECRYPT:
+        return V4_0::KeyPurpose::DECRYPT;
+    case KMV1::KeyPurpose::SIGN:
+        return V4_0::KeyPurpose::SIGN;
+    case KMV1::KeyPurpose::VERIFY:
+        return V4_0::KeyPurpose::VERIFY;
+    case KMV1::KeyPurpose::WRAP_KEY:
+        return V4_0::KeyPurpose::WRAP_KEY;
+    }
+}
+
+static KMV1::KeyPurpose convert(V4_0::KeyPurpose p) {
+    switch (p) {
+    case V4_0::KeyPurpose::ENCRYPT:
+        return KMV1::KeyPurpose::ENCRYPT;
+    case V4_0::KeyPurpose::DECRYPT:
+        return KMV1::KeyPurpose::DECRYPT;
+    case V4_0::KeyPurpose::SIGN:
+        return KMV1::KeyPurpose::SIGN;
+    case V4_0::KeyPurpose::VERIFY:
+        return KMV1::KeyPurpose::VERIFY;
+    case V4_0::KeyPurpose::WRAP_KEY:
+        return KMV1::KeyPurpose::WRAP_KEY;
+    }
+}
+
+static V4_0::Algorithm convert(KMV1::Algorithm a) {
+    switch (a) {
+    case KMV1::Algorithm::RSA:
+        return V4_0::Algorithm::RSA;
+    case KMV1::Algorithm::EC:
+        return V4_0::Algorithm::EC;
+    case KMV1::Algorithm::AES:
+        return V4_0::Algorithm::AES;
+    case KMV1::Algorithm::TRIPLE_DES:
+        return V4_0::Algorithm::TRIPLE_DES;
+    case KMV1::Algorithm::HMAC:
+        return V4_0::Algorithm::HMAC;
+    }
+}
+
+static KMV1::Algorithm convert(V4_0::Algorithm a) {
+    switch (a) {
+    case V4_0::Algorithm::RSA:
+        return KMV1::Algorithm::RSA;
+    case V4_0::Algorithm::EC:
+        return KMV1::Algorithm::EC;
+    case V4_0::Algorithm::AES:
+        return KMV1::Algorithm::AES;
+    case V4_0::Algorithm::TRIPLE_DES:
+        return KMV1::Algorithm::TRIPLE_DES;
+    case V4_0::Algorithm::HMAC:
+        return KMV1::Algorithm::HMAC;
+    }
+}
+
+static V4_0::Digest convert(KMV1::Digest d) {
+    switch (d) {
+    case KMV1::Digest::NONE:
+        return V4_0::Digest::NONE;
+    case KMV1::Digest::MD5:
+        return V4_0::Digest::MD5;
+    case KMV1::Digest::SHA1:
+        return V4_0::Digest::SHA1;
+    case KMV1::Digest::SHA_2_224:
+        return V4_0::Digest::SHA_2_224;
+    case KMV1::Digest::SHA_2_256:
+        return V4_0::Digest::SHA_2_256;
+    case KMV1::Digest::SHA_2_384:
+        return V4_0::Digest::SHA_2_384;
+    case KMV1::Digest::SHA_2_512:
+        return V4_0::Digest::SHA_2_512;
+    }
+}
+
+static KMV1::Digest convert(V4_0::Digest d) {
+    switch (d) {
+    case V4_0::Digest::NONE:
+        return KMV1::Digest::NONE;
+    case V4_0::Digest::MD5:
+        return KMV1::Digest::MD5;
+    case V4_0::Digest::SHA1:
+        return KMV1::Digest::SHA1;
+    case V4_0::Digest::SHA_2_224:
+        return KMV1::Digest::SHA_2_224;
+    case V4_0::Digest::SHA_2_256:
+        return KMV1::Digest::SHA_2_256;
+    case V4_0::Digest::SHA_2_384:
+        return KMV1::Digest::SHA_2_384;
+    case V4_0::Digest::SHA_2_512:
+        return KMV1::Digest::SHA_2_512;
+    }
+}
+
+static V4_0::EcCurve convert(KMV1::EcCurve e) {
+    switch (e) {
+    case KMV1::EcCurve::P_224:
+        return V4_0::EcCurve::P_224;
+    case KMV1::EcCurve::P_256:
+        return V4_0::EcCurve::P_256;
+    case KMV1::EcCurve::P_384:
+        return V4_0::EcCurve::P_384;
+    case KMV1::EcCurve::P_521:
+        return V4_0::EcCurve::P_521;
+    }
+}
+
+static KMV1::EcCurve convert(V4_0::EcCurve e) {
+    switch (e) {
+    case V4_0::EcCurve::P_224:
+        return KMV1::EcCurve::P_224;
+    case V4_0::EcCurve::P_256:
+        return KMV1::EcCurve::P_256;
+    case V4_0::EcCurve::P_384:
+        return KMV1::EcCurve::P_384;
+    case V4_0::EcCurve::P_521:
+        return KMV1::EcCurve::P_521;
+    }
+}
+
+static V4_0::BlockMode convert(KMV1::BlockMode b) {
+    switch (b) {
+    case KMV1::BlockMode::ECB:
+        return V4_0::BlockMode::ECB;
+    case KMV1::BlockMode::CBC:
+        return V4_0::BlockMode::CBC;
+    case KMV1::BlockMode::CTR:
+        return V4_0::BlockMode::CTR;
+    case KMV1::BlockMode::GCM:
+        return V4_0::BlockMode::GCM;
+    }
+}
+
+static KMV1::BlockMode convert(V4_0::BlockMode b) {
+    switch (b) {
+    case V4_0::BlockMode::ECB:
+        return KMV1::BlockMode::ECB;
+    case V4_0::BlockMode::CBC:
+        return KMV1::BlockMode::CBC;
+    case V4_0::BlockMode::CTR:
+        return KMV1::BlockMode::CTR;
+    case V4_0::BlockMode::GCM:
+        return KMV1::BlockMode::GCM;
+    }
+}
+
+static V4_0::PaddingMode convert(KMV1::PaddingMode p) {
+    switch (p) {
+    case KMV1::PaddingMode::NONE:
+        return V4_0::PaddingMode::NONE;
+    case KMV1::PaddingMode::RSA_OAEP:
+        return V4_0::PaddingMode::RSA_OAEP;
+    case KMV1::PaddingMode::RSA_PSS:
+        return V4_0::PaddingMode::RSA_PSS;
+    case KMV1::PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+        return V4_0::PaddingMode::RSA_PKCS1_1_5_ENCRYPT;
+    case KMV1::PaddingMode::RSA_PKCS1_1_5_SIGN:
+        return V4_0::PaddingMode::RSA_PKCS1_1_5_SIGN;
+    case KMV1::PaddingMode::PKCS7:
+        return V4_0::PaddingMode::PKCS7;
+    }
+}
+
+static KMV1::PaddingMode convert(V4_0::PaddingMode p) {
+    switch (p) {
+    case V4_0::PaddingMode::NONE:
+        return KMV1::PaddingMode::NONE;
+    case V4_0::PaddingMode::RSA_OAEP:
+        return KMV1::PaddingMode::RSA_OAEP;
+    case V4_0::PaddingMode::RSA_PSS:
+        return KMV1::PaddingMode::RSA_PSS;
+    case V4_0::PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+        return KMV1::PaddingMode::RSA_PKCS1_1_5_ENCRYPT;
+    case V4_0::PaddingMode::RSA_PKCS1_1_5_SIGN:
+        return KMV1::PaddingMode::RSA_PKCS1_1_5_SIGN;
+    case V4_0::PaddingMode::PKCS7:
+        return KMV1::PaddingMode::PKCS7;
+    }
+}
+
+static V4_0::HardwareAuthenticatorType convert(KMV1::HardwareAuthenticatorType h) {
+    uint32_t result = 0;
+    uint32_t hat = static_cast<uint32_t>(h);
+    if (hat & static_cast<uint32_t>(KMV1::HardwareAuthenticatorType::PASSWORD)) {
+        result |= static_cast<uint32_t>(V4_0::HardwareAuthenticatorType::PASSWORD);
+    }
+    if (hat & static_cast<uint32_t>(KMV1::HardwareAuthenticatorType::FINGERPRINT)) {
+        result |= static_cast<uint32_t>(V4_0::HardwareAuthenticatorType::FINGERPRINT);
+    }
+    return static_cast<V4_0::HardwareAuthenticatorType>(result);
+}
+
+static KMV1::HardwareAuthenticatorType convert(V4_0::HardwareAuthenticatorType h) {
+    uint32_t result = 0;
+    if ((uint32_t)h & (uint32_t)V4_0::HardwareAuthenticatorType::PASSWORD) {
+        result |= (uint32_t)KMV1::HardwareAuthenticatorType::PASSWORD;
+    }
+    if ((uint32_t)h & (uint32_t)V4_0::HardwareAuthenticatorType::FINGERPRINT) {
+        result |= (uint32_t)KMV1::HardwareAuthenticatorType::FINGERPRINT;
+    }
+    return static_cast<KMV1::HardwareAuthenticatorType>(result);
+}
+
+static V4_0::SecurityLevel convert(KMV1::SecurityLevel s) {
+    switch (s) {
+    case KMV1::SecurityLevel::SOFTWARE:
+        return V4_0::SecurityLevel::SOFTWARE;
+    case KMV1::SecurityLevel::TRUSTED_ENVIRONMENT:
+        return V4_0::SecurityLevel::TRUSTED_ENVIRONMENT;
+    case KMV1::SecurityLevel::STRONGBOX:
+        return V4_0::SecurityLevel::STRONGBOX;
+    }
+}
+
+static KMV1::SecurityLevel convert(V4_0::SecurityLevel s) {
+    switch (s) {
+    case V4_0::SecurityLevel::SOFTWARE:
+        return KMV1::SecurityLevel::SOFTWARE;
+    case V4_0::SecurityLevel::TRUSTED_ENVIRONMENT:
+        return KMV1::SecurityLevel::TRUSTED_ENVIRONMENT;
+    case V4_0::SecurityLevel::STRONGBOX:
+        return KMV1::SecurityLevel::STRONGBOX;
+    }
+}
+
+static V4_0::KeyOrigin convert(KMV1::KeyOrigin o) {
+    switch (o) {
+    case KMV1::KeyOrigin::GENERATED:
+        return V4_0::KeyOrigin::GENERATED;
+    case KMV1::KeyOrigin::DERIVED:
+        return V4_0::KeyOrigin::DERIVED;
+    case KMV1::KeyOrigin::IMPORTED:
+        return V4_0::KeyOrigin::IMPORTED;
+    case KMV1::KeyOrigin::RESERVED:
+        return V4_0::KeyOrigin::UNKNOWN;
+    case KMV1::KeyOrigin::SECURELY_IMPORTED:
+        return V4_0::KeyOrigin::SECURELY_IMPORTED;
+    }
+}
+
+static KMV1::KeyOrigin convert(V4_0::KeyOrigin o) {
+    switch (o) {
+    case V4_0::KeyOrigin::GENERATED:
+        return KMV1::KeyOrigin::GENERATED;
+    case V4_0::KeyOrigin::DERIVED:
+        return KMV1::KeyOrigin::DERIVED;
+    case V4_0::KeyOrigin::IMPORTED:
+        return KMV1::KeyOrigin::IMPORTED;
+    case V4_0::KeyOrigin::UNKNOWN:
+        return KMV1::KeyOrigin::RESERVED;
+    case V4_0::KeyOrigin::SECURELY_IMPORTED:
+        return KMV1::KeyOrigin::SECURELY_IMPORTED;
+    }
+}
+
+static V4_0::KeyParameter convertKeyParameterToLegacy(const KMV1::KeyParameter& kp) {
+    switch (kp.tag) {
+    case KMV1::Tag::INVALID:
+        break;
+    case KMV1::Tag::PURPOSE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_PURPOSE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_PURPOSE, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::ALGORITHM:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ALGORITHM, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ALGORITHM, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::KEY_SIZE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_KEY_SIZE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_KEY_SIZE, v->get());
+        }
+        break;
+    case KMV1::Tag::BLOCK_MODE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_BLOCK_MODE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_BLOCK_MODE, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::DIGEST:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_DIGEST, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_DIGEST, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::PADDING:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_PADDING, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_PADDING, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::CALLER_NONCE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_CALLER_NONCE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_CALLER_NONCE, v->get());
+        }
+        break;
+    case KMV1::Tag::MIN_MAC_LENGTH:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_MIN_MAC_LENGTH, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_MIN_MAC_LENGTH, v->get());
+        }
+        break;
+    case KMV1::Tag::EC_CURVE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_EC_CURVE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_EC_CURVE, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::RSA_PUBLIC_EXPONENT:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_RSA_PUBLIC_EXPONENT, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_RSA_PUBLIC_EXPONENT, v->get());
+        }
+        break;
+    case KMV1::Tag::INCLUDE_UNIQUE_ID:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_INCLUDE_UNIQUE_ID, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_INCLUDE_UNIQUE_ID, v->get());
+        }
+        break;
+    case KMV1::Tag::BLOB_USAGE_REQUIREMENTS:
+        // This tag has been removed. Mapped on invalid.
+        break;
+    case KMV1::Tag::BOOTLOADER_ONLY:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_BOOTLOADER_ONLY, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_BOOTLOADER_ONLY, v->get());
+        }
+        break;
+    case KMV1::Tag::ROLLBACK_RESISTANCE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ROLLBACK_RESISTANCE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ROLLBACK_RESISTANCE, v->get());
+        }
+        break;
+    case KMV1::Tag::HARDWARE_TYPE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_HARDWARE_TYPE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_HARDWARE_TYPE, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::EARLY_BOOT_ONLY:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_EARLY_BOOT_ONLY, kp)) {
+            return V4_0::makeKeyParameter(V4_1::TAG_EARLY_BOOT_ONLY, v->get());
+        }
+        break;
+    case KMV1::Tag::ACTIVE_DATETIME:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ACTIVE_DATETIME, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ACTIVE_DATETIME, v->get());
+        }
+        break;
+    case KMV1::Tag::ORIGINATION_EXPIRE_DATETIME:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ORIGINATION_EXPIRE_DATETIME, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ORIGINATION_EXPIRE_DATETIME, v->get());
+        }
+        break;
+    case KMV1::Tag::USAGE_EXPIRE_DATETIME:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_USAGE_EXPIRE_DATETIME, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_USAGE_EXPIRE_DATETIME, v->get());
+        }
+        break;
+    case KMV1::Tag::MIN_SECONDS_BETWEEN_OPS:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_MIN_SECONDS_BETWEEN_OPS, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_MIN_SECONDS_BETWEEN_OPS, v->get());
+        }
+        break;
+    case KMV1::Tag::MAX_USES_PER_BOOT:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_MAX_USES_PER_BOOT, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_MAX_USES_PER_BOOT, v->get());
+        }
+        break;
+    case KMV1::Tag::USER_ID:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_USER_ID, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_USER_ID, v->get());
+        }
+        break;
+    case KMV1::Tag::USER_SECURE_ID:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_USER_SECURE_ID, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_USER_SECURE_ID, v->get());
+        }
+        break;
+    case KMV1::Tag::NO_AUTH_REQUIRED:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_NO_AUTH_REQUIRED, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_NO_AUTH_REQUIRED, v->get());
+        }
+        break;
+    case KMV1::Tag::USER_AUTH_TYPE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_USER_AUTH_TYPE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_USER_AUTH_TYPE, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::AUTH_TIMEOUT:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_AUTH_TIMEOUT, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_AUTH_TIMEOUT, v->get());
+        }
+        break;
+    case KMV1::Tag::ALLOW_WHILE_ON_BODY:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ALLOW_WHILE_ON_BODY, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ALLOW_WHILE_ON_BODY, v->get());
+        }
+        break;
+    case KMV1::Tag::TRUSTED_USER_PRESENCE_REQUIRED:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_TRUSTED_USER_PRESENCE_REQUIRED, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_TRUSTED_USER_PRESENCE_REQUIRED, v->get());
+        }
+        break;
+    case KMV1::Tag::TRUSTED_CONFIRMATION_REQUIRED:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_TRUSTED_CONFIRMATION_REQUIRED, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_TRUSTED_CONFIRMATION_REQUIRED, v->get());
+        }
+        break;
+    case KMV1::Tag::UNLOCKED_DEVICE_REQUIRED:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_UNLOCKED_DEVICE_REQUIRED, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_UNLOCKED_DEVICE_REQUIRED, v->get());
+        }
+        break;
+    case KMV1::Tag::APPLICATION_ID:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_APPLICATION_ID, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_APPLICATION_ID, v->get());
+        }
+        break;
+    case KMV1::Tag::APPLICATION_DATA:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_APPLICATION_DATA, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_APPLICATION_DATA, v->get());
+        }
+        break;
+    case KMV1::Tag::CREATION_DATETIME:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_CREATION_DATETIME, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_CREATION_DATETIME, v->get());
+        }
+        break;
+    case KMV1::Tag::ORIGIN:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ORIGIN, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ORIGIN, convert(v->get()));
+        }
+        break;
+    case KMV1::Tag::ROOT_OF_TRUST:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ROOT_OF_TRUST, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ROOT_OF_TRUST, v->get());
+        }
+        break;
+    case KMV1::Tag::OS_VERSION:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_OS_VERSION, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_OS_VERSION, v->get());
+        }
+        break;
+    case KMV1::Tag::OS_PATCHLEVEL:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_OS_PATCHLEVEL, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_OS_PATCHLEVEL, v->get());
+        }
+        break;
+    case KMV1::Tag::UNIQUE_ID:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_UNIQUE_ID, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_UNIQUE_ID, v->get());
+        }
+        break;
+    case KMV1::Tag::ATTESTATION_CHALLENGE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ATTESTATION_CHALLENGE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ATTESTATION_CHALLENGE, v->get());
+        }
+        break;
+    case KMV1::Tag::ATTESTATION_APPLICATION_ID:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ATTESTATION_APPLICATION_ID, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ATTESTATION_APPLICATION_ID, v->get());
+        }
+        break;
+    case KMV1::Tag::ATTESTATION_ID_BRAND:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ATTESTATION_ID_BRAND, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ATTESTATION_ID_BRAND, v->get());
+        }
+        break;
+    case KMV1::Tag::ATTESTATION_ID_DEVICE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ATTESTATION_ID_DEVICE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ATTESTATION_ID_DEVICE, v->get());
+        }
+        break;
+    case KMV1::Tag::ATTESTATION_ID_PRODUCT:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ATTESTATION_ID_PRODUCT, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ATTESTATION_ID_PRODUCT, v->get());
+        }
+        break;
+    case KMV1::Tag::ATTESTATION_ID_SERIAL:
+        // TODO This tag is missing from 4.0 keymaster_tags.h
+        break;
+    case KMV1::Tag::ATTESTATION_ID_IMEI:
+        // TODO This tag is missing from 4.0 keymaster_tags.h
+        break;
+    case KMV1::Tag::ATTESTATION_ID_MEID:
+        // TODO This tag is missing from 4.0 keymaster_tags.h
+        break;
+    case KMV1::Tag::ATTESTATION_ID_MANUFACTURER:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ATTESTATION_ID_MANUFACTURER, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ATTESTATION_ID_MANUFACTURER, v->get());
+        }
+        break;
+    case KMV1::Tag::ATTESTATION_ID_MODEL:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ATTESTATION_ID_MODEL, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ATTESTATION_ID_MODEL, v->get());
+        }
+        break;
+    case KMV1::Tag::VENDOR_PATCHLEVEL:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_VENDOR_PATCHLEVEL, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_VENDOR_PATCHLEVEL, v->get());
+        }
+        break;
+    case KMV1::Tag::BOOT_PATCHLEVEL:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_BOOT_PATCHLEVEL, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_BOOT_PATCHLEVEL, v->get());
+        }
+        break;
+    case KMV1::Tag::DEVICE_UNIQUE_ATTESTATION:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_DEVICE_UNIQUE_ATTESTATION, kp)) {
+            return V4_0::makeKeyParameter(V4_1::TAG_DEVICE_UNIQUE_ATTESTATION, v->get());
+        }
+        break;
+    case KMV1::Tag::IDENTITY_CREDENTIAL_KEY:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_IDENTITY_CREDENTIAL_KEY, kp)) {
+            return V4_0::makeKeyParameter(V4_1::TAG_IDENTITY_CREDENTIAL_KEY, v->get());
+        }
+        break;
+    case KMV1::Tag::STORAGE_KEY:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_STORAGE_KEY, kp)) {
+            return V4_0::makeKeyParameter(V4_1::TAG_STORAGE_KEY, v->get());
+        }
+        break;
+    case KMV1::Tag::ASSOCIATED_DATA:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_ASSOCIATED_DATA, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_ASSOCIATED_DATA, v->get());
+        }
+        break;
+    case KMV1::Tag::NONCE:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_NONCE, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_NONCE, v->get());
+        }
+        break;
+    case KMV1::Tag::MAC_LENGTH:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_MAC_LENGTH, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_MAC_LENGTH, v->get());
+        }
+        break;
+    case KMV1::Tag::RESET_SINCE_ID_ROTATION:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_RESET_SINCE_ID_ROTATION, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_RESET_SINCE_ID_ROTATION, v->get());
+        }
+        break;
+    case KMV1::Tag::CONFIRMATION_TOKEN:
+        if (auto v = KMV1::authorizationValue(KMV1::TAG_CONFIRMATION_TOKEN, kp)) {
+            return V4_0::makeKeyParameter(V4_0::TAG_CONFIRMATION_TOKEN, v->get());
+        }
+        break;
+    case KMV1::Tag::RSA_OAEP_MGF_DIGEST:
+        // Does not exist in KM < KeyMint 1.0.
+        break;
+    }
+    return V4_0::KeyParameter{.tag = V4_0::Tag::INVALID};
+}
+
+static KMV1::KeyParameter convertKeyParameterFromLegacy(const V4_0::KeyParameter& kp) {
+    auto unwrapper = [](auto v) -> auto {
+        if (v.isOk()) {
+            return std::optional(std::reference_wrapper(v.value()));
+        } else {
+            return std::optional<decltype(std::reference_wrapper(v.value()))>{};
+        }
+    };
+    switch (kp.tag) {
+    case V4_0::Tag::INVALID:
+        break;
+    case V4_0::Tag::PURPOSE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_PURPOSE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::ALGORITHM:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ALGORITHM, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ALGORITHM, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::KEY_SIZE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_KEY_SIZE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_KEY_SIZE, v->get());
+        }
+        break;
+    case V4_0::Tag::BLOCK_MODE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_BLOCK_MODE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_BLOCK_MODE, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::DIGEST:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_DIGEST, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_DIGEST, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::PADDING:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_PADDING, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_PADDING, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::CALLER_NONCE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_CALLER_NONCE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_CALLER_NONCE, v->get());
+        }
+        break;
+    case V4_0::Tag::MIN_MAC_LENGTH:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_MIN_MAC_LENGTH, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_MIN_MAC_LENGTH, v->get());
+        }
+        break;
+    case V4_0::Tag::EC_CURVE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_EC_CURVE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_EC_CURVE, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::RSA_PUBLIC_EXPONENT:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_RSA_PUBLIC_EXPONENT, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_RSA_PUBLIC_EXPONENT, v->get());
+        }
+        break;
+    case V4_0::Tag::INCLUDE_UNIQUE_ID:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_INCLUDE_UNIQUE_ID, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_INCLUDE_UNIQUE_ID, v->get());
+        }
+        break;
+    case V4_0::Tag::BLOB_USAGE_REQUIREMENTS:
+        // This tag has been removed. Mapped on invalid.
+        break;
+    case V4_0::Tag::BOOTLOADER_ONLY:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_BOOTLOADER_ONLY, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_BOOTLOADER_ONLY, v->get());
+        }
+        break;
+    case V4_0::Tag::ROLLBACK_RESISTANCE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ROLLBACK_RESISTANCE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ROLLBACK_RESISTANCE, v->get());
+        }
+        break;
+    case V4_0::Tag::HARDWARE_TYPE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_HARDWARE_TYPE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_HARDWARE_TYPE, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::ACTIVE_DATETIME:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ACTIVE_DATETIME, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ACTIVE_DATETIME, v->get());
+        }
+        break;
+    case V4_0::Tag::ORIGINATION_EXPIRE_DATETIME:
+        if (auto v =
+                unwrapper(V4_0::authorizationValue(V4_0::TAG_ORIGINATION_EXPIRE_DATETIME, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ORIGINATION_EXPIRE_DATETIME, v->get());
+        }
+        break;
+    case V4_0::Tag::USAGE_EXPIRE_DATETIME:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_USAGE_EXPIRE_DATETIME, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_USAGE_EXPIRE_DATETIME, v->get());
+        }
+        break;
+    case V4_0::Tag::MIN_SECONDS_BETWEEN_OPS:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_MIN_SECONDS_BETWEEN_OPS, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_MIN_SECONDS_BETWEEN_OPS, v->get());
+        }
+        break;
+    case V4_0::Tag::MAX_USES_PER_BOOT:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_MAX_USES_PER_BOOT, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_MAX_USES_PER_BOOT, v->get());
+        }
+        break;
+    case V4_0::Tag::USER_ID:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_USER_ID, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_USER_ID, v->get());
+        }
+        break;
+    case V4_0::Tag::USER_SECURE_ID:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_USER_SECURE_ID, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_USER_SECURE_ID, v->get());
+        }
+        break;
+    case V4_0::Tag::NO_AUTH_REQUIRED:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_NO_AUTH_REQUIRED, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_NO_AUTH_REQUIRED, v->get());
+        }
+        break;
+    case V4_0::Tag::USER_AUTH_TYPE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_USER_AUTH_TYPE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_USER_AUTH_TYPE, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::AUTH_TIMEOUT:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_AUTH_TIMEOUT, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_AUTH_TIMEOUT, v->get());
+        }
+        break;
+    case V4_0::Tag::ALLOW_WHILE_ON_BODY:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ALLOW_WHILE_ON_BODY, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ALLOW_WHILE_ON_BODY, v->get());
+        }
+        break;
+    case V4_0::Tag::TRUSTED_USER_PRESENCE_REQUIRED:
+        if (auto v =
+                unwrapper(V4_0::authorizationValue(V4_0::TAG_TRUSTED_USER_PRESENCE_REQUIRED, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_TRUSTED_USER_PRESENCE_REQUIRED, v->get());
+        }
+        break;
+    case V4_0::Tag::TRUSTED_CONFIRMATION_REQUIRED:
+        if (auto v =
+                unwrapper(V4_0::authorizationValue(V4_0::TAG_TRUSTED_CONFIRMATION_REQUIRED, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_TRUSTED_CONFIRMATION_REQUIRED, v->get());
+        }
+        break;
+    case V4_0::Tag::UNLOCKED_DEVICE_REQUIRED:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_UNLOCKED_DEVICE_REQUIRED, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_UNLOCKED_DEVICE_REQUIRED, v->get());
+        }
+        break;
+    case V4_0::Tag::APPLICATION_ID:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_APPLICATION_ID, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_APPLICATION_ID, v->get());
+        }
+        break;
+    case V4_0::Tag::APPLICATION_DATA:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_APPLICATION_DATA, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_APPLICATION_DATA, v->get());
+        }
+        break;
+    case V4_0::Tag::CREATION_DATETIME:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_CREATION_DATETIME, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_CREATION_DATETIME, v->get());
+        }
+        break;
+    case V4_0::Tag::ORIGIN:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ORIGIN, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ORIGIN, convert(v->get()));
+        }
+        break;
+    case V4_0::Tag::ROOT_OF_TRUST:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ROOT_OF_TRUST, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ROOT_OF_TRUST, v->get());
+        }
+        break;
+    case V4_0::Tag::OS_VERSION:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_OS_VERSION, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_OS_VERSION, v->get());
+        }
+        break;
+    case V4_0::Tag::OS_PATCHLEVEL:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_OS_PATCHLEVEL, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_OS_PATCHLEVEL, v->get());
+        }
+        break;
+    case V4_0::Tag::UNIQUE_ID:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_UNIQUE_ID, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_UNIQUE_ID, v->get());
+        }
+        break;
+    case V4_0::Tag::ATTESTATION_CHALLENGE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ATTESTATION_CHALLENGE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_CHALLENGE, v->get());
+        }
+        break;
+    case V4_0::Tag::ATTESTATION_APPLICATION_ID:
+        if (auto v =
+                unwrapper(V4_0::authorizationValue(V4_0::TAG_ATTESTATION_APPLICATION_ID, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_APPLICATION_ID, v->get());
+        }
+        break;
+    case V4_0::Tag::ATTESTATION_ID_BRAND:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ATTESTATION_ID_BRAND, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_ID_BRAND, v->get());
+        }
+        break;
+    case V4_0::Tag::ATTESTATION_ID_DEVICE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ATTESTATION_ID_DEVICE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_ID_DEVICE, v->get());
+        }
+        break;
+    case V4_0::Tag::ATTESTATION_ID_PRODUCT:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ATTESTATION_ID_PRODUCT, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_ID_PRODUCT, v->get());
+        }
+        break;
+    case V4_0::Tag::ATTESTATION_ID_SERIAL:
+        // TODO This tag is missing from 4.0 keymaster_tags.h
+        break;
+    case V4_0::Tag::ATTESTATION_ID_IMEI:
+        // TODO This tag is missing from 4.0 keymaster_tags.h
+        break;
+    case V4_0::Tag::ATTESTATION_ID_MEID:
+        // TODO This tag is missing from 4.0 keymaster_tags.h
+        break;
+    case V4_0::Tag::ATTESTATION_ID_MANUFACTURER:
+        if (auto v =
+                unwrapper(V4_0::authorizationValue(V4_0::TAG_ATTESTATION_ID_MANUFACTURER, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_ID_MANUFACTURER, v->get());
+        }
+        break;
+    case V4_0::Tag::ATTESTATION_ID_MODEL:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ATTESTATION_ID_MODEL, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_ID_MODEL, v->get());
+        }
+        break;
+    case V4_0::Tag::VENDOR_PATCHLEVEL:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_VENDOR_PATCHLEVEL, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_VENDOR_PATCHLEVEL, v->get());
+        }
+        break;
+    case V4_0::Tag::BOOT_PATCHLEVEL:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_BOOT_PATCHLEVEL, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_BOOT_PATCHLEVEL, v->get());
+        }
+        break;
+    case V4_0::Tag::ASSOCIATED_DATA:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_ASSOCIATED_DATA, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_ASSOCIATED_DATA, v->get());
+        }
+        break;
+    case V4_0::Tag::NONCE:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_NONCE, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_NONCE, v->get());
+        }
+        break;
+    case V4_0::Tag::MAC_LENGTH:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_MAC_LENGTH, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_MAC_LENGTH, v->get());
+        }
+        break;
+    case V4_0::Tag::RESET_SINCE_ID_ROTATION:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_RESET_SINCE_ID_ROTATION, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_RESET_SINCE_ID_ROTATION, v->get());
+        }
+        break;
+    case V4_0::Tag::CONFIRMATION_TOKEN:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_0::TAG_CONFIRMATION_TOKEN, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_CONFIRMATION_TOKEN, v->get());
+        }
+        break;
+    default:
+        break;
+    }
+
+    switch (static_cast<V4_1::Tag>(kp.tag)) {
+    case V4_1::Tag::EARLY_BOOT_ONLY:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_1::TAG_EARLY_BOOT_ONLY, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_EARLY_BOOT_ONLY, v->get());
+        }
+        break;
+    case V4_1::Tag::DEVICE_UNIQUE_ATTESTATION:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_1::TAG_DEVICE_UNIQUE_ATTESTATION, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_DEVICE_UNIQUE_ATTESTATION, v->get());
+        }
+        break;
+    case V4_1::Tag::IDENTITY_CREDENTIAL_KEY:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_1::TAG_IDENTITY_CREDENTIAL_KEY, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_IDENTITY_CREDENTIAL_KEY, v->get());
+        }
+        break;
+    case V4_1::Tag::STORAGE_KEY:
+        if (auto v = unwrapper(V4_0::authorizationValue(V4_1::TAG_STORAGE_KEY, kp))) {
+            return KMV1::makeKeyParameter(KMV1::TAG_STORAGE_KEY, v->get());
+        }
+        break;
+    default:
+        break;
+    }
+
+    return KMV1::makeKeyParameter(KMV1::TAG_INVALID);
+}
diff --git a/keystore2/src/km_compat/lib.rs b/keystore2/src/km_compat/lib.rs
index b6a6baf..36f1303 100644
--- a/keystore2/src/km_compat/lib.rs
+++ b/keystore2/src/km_compat/lib.rs
@@ -32,8 +32,8 @@
         Certificate::Certificate, Digest::Digest, ErrorCode::ErrorCode,
         HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::IKeyMintDevice,
         KeyCharacteristics::KeyCharacteristics, KeyFormat::KeyFormat, KeyParameter::KeyParameter,
-        KeyParameterArray::KeyParameterArray, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
-        SecurityLevel::SecurityLevel, Tag::Tag,
+        KeyParameterArray::KeyParameterArray, KeyParameterValue::KeyParameterValue,
+        KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, SecurityLevel::SecurityLevel, Tag::Tag,
     };
     use android_hardware_security_keymint::binder;
     use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
@@ -87,39 +87,40 @@
 
     fn generate_rsa_key(legacy: &dyn IKeyMintDevice, encrypt: bool, attest: bool) -> Vec<u8> {
         let mut kps = vec![
-            KeyParameter { tag: Tag::ALGORITHM, integer: Algorithm::RSA.0, ..Default::default() },
-            KeyParameter { tag: Tag::KEY_SIZE, integer: 2048, ..Default::default() },
+            KeyParameter {
+                tag: Tag::ALGORITHM,
+                value: KeyParameterValue::Algorithm(Algorithm::RSA),
+            },
+            KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(2048) },
             KeyParameter {
                 tag: Tag::RSA_PUBLIC_EXPONENT,
-                longInteger: 65537,
-                ..Default::default()
+                value: KeyParameterValue::LongInteger(65537),
             },
-            KeyParameter { tag: Tag::DIGEST, integer: Digest::SHA_2_256.0, ..Default::default() },
+            KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) },
             KeyParameter {
                 tag: Tag::PADDING,
-                integer: PaddingMode::RSA_PSS.0,
-                ..Default::default()
+                value: KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
             },
-            KeyParameter { tag: Tag::NO_AUTH_REQUIRED, boolValue: true, ..Default::default() },
-            KeyParameter { tag: Tag::PURPOSE, integer: KeyPurpose::SIGN.0, ..Default::default() },
+            KeyParameter { tag: Tag::NO_AUTH_REQUIRED, value: KeyParameterValue::BoolValue(true) },
+            KeyParameter {
+                tag: Tag::PURPOSE,
+                value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
+            },
         ];
         if encrypt {
             kps.push(KeyParameter {
                 tag: Tag::PURPOSE,
-                integer: KeyPurpose::ENCRYPT.0,
-                ..Default::default()
+                value: KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
             });
         }
         if attest {
             kps.push(KeyParameter {
                 tag: Tag::ATTESTATION_CHALLENGE,
-                blob: vec![42; 8],
-                ..Default::default()
+                value: KeyParameterValue::Blob(vec![42; 8]),
             });
             kps.push(KeyParameter {
                 tag: Tag::ATTESTATION_APPLICATION_ID,
-                blob: vec![42; 8],
-                ..Default::default()
+                value: KeyParameterValue::Blob(vec![42; 8]),
             });
         }
         let (blob, _, cert_chain) = generate_key(legacy, kps);
@@ -153,8 +154,10 @@
     #[test]
     fn test_import_key() {
         let legacy = get_device();
-        let kps =
-            [KeyParameter { tag: Tag::ALGORITHM, integer: Algorithm::AES.0, ..Default::default() }];
+        let kps = [KeyParameter {
+            tag: Tag::ALGORITHM,
+            value: KeyParameterValue::Algorithm(Algorithm::AES),
+        }];
         let kf = KeyFormat::RAW;
         let kd = [0; 16];
         let mut blob = ByteArray { data: vec![] };
@@ -212,20 +215,27 @@
 
     fn generate_aes_key(legacy: &dyn IKeyMintDevice) -> Vec<u8> {
         let kps = vec![
-            KeyParameter { tag: Tag::ALGORITHM, integer: Algorithm::AES.0, ..Default::default() },
-            KeyParameter { tag: Tag::KEY_SIZE, integer: 128, ..Default::default() },
-            KeyParameter { tag: Tag::BLOCK_MODE, integer: BlockMode::CBC.0, ..Default::default() },
-            KeyParameter { tag: Tag::PADDING, integer: PaddingMode::NONE.0, ..Default::default() },
-            KeyParameter { tag: Tag::NO_AUTH_REQUIRED, boolValue: true, ..Default::default() },
+            KeyParameter {
+                tag: Tag::ALGORITHM,
+                value: KeyParameterValue::Algorithm(Algorithm::AES),
+            },
+            KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) },
+            KeyParameter {
+                tag: Tag::BLOCK_MODE,
+                value: KeyParameterValue::BlockMode(BlockMode::CBC),
+            },
+            KeyParameter {
+                tag: Tag::PADDING,
+                value: KeyParameterValue::PaddingMode(PaddingMode::NONE),
+            },
+            KeyParameter { tag: Tag::NO_AUTH_REQUIRED, value: KeyParameterValue::BoolValue(true) },
             KeyParameter {
                 tag: Tag::PURPOSE,
-                integer: KeyPurpose::ENCRYPT.0,
-                ..Default::default()
+                value: KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
             },
             KeyParameter {
                 tag: Tag::PURPOSE,
-                integer: KeyPurpose::DECRYPT.0,
-                ..Default::default()
+                value: KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
             },
         ];
         let (blob, _, cert_chain) = generate_key(legacy, kps);
@@ -240,8 +250,14 @@
         extra_params: Option<Vec<KeyParameter>>,
     ) -> BeginResult {
         let mut kps = vec![
-            KeyParameter { tag: Tag::BLOCK_MODE, integer: BlockMode::CBC.0, ..Default::default() },
-            KeyParameter { tag: Tag::PADDING, integer: PaddingMode::NONE.0, ..Default::default() },
+            KeyParameter {
+                tag: Tag::BLOCK_MODE,
+                value: KeyParameterValue::BlockMode(BlockMode::CBC),
+            },
+            KeyParameter {
+                tag: Tag::PADDING,
+                value: KeyParameterValue::PaddingMode(PaddingMode::NONE),
+            },
         ];
         if let Some(mut extras) = extra_params {
             kps.append(&mut extras);
@@ -273,8 +289,7 @@
         let params = KeyParameterArray {
             params: vec![KeyParameter {
                 tag: Tag::ASSOCIATED_DATA,
-                blob: b"foobar".to_vec(),
-                ..Default::default()
+                value: KeyParameterValue::Blob(b"foobar".to_vec()),
             }],
         };
         let message = [42; 128];
diff --git a/keystore2/src/km_compat/parameter_conversion_test.cpp b/keystore2/src/km_compat/parameter_conversion_test.cpp
new file mode 100644
index 0000000..41be067
--- /dev/null
+++ b/keystore2/src/km_compat/parameter_conversion_test.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "km_compat_type_conversion.h"
+
+#define TEST_ENUM_CONVERSION(type, variant)                                                        \
+    ASSERT_EQ(KMV1::type::variant, convert(V4_0::type::variant));                                  \
+    ASSERT_EQ(V4_0::type::variant, convert(KMV1::type::variant))
+
+TEST(KmCompatTypeConversionTest, testEnumCoversion) {
+    TEST_ENUM_CONVERSION(KeyPurpose, ENCRYPT);
+    TEST_ENUM_CONVERSION(KeyPurpose, DECRYPT);
+    TEST_ENUM_CONVERSION(KeyPurpose, SIGN);
+    TEST_ENUM_CONVERSION(KeyPurpose, VERIFY);
+    TEST_ENUM_CONVERSION(KeyPurpose, WRAP_KEY);
+    TEST_ENUM_CONVERSION(Algorithm, RSA);
+    TEST_ENUM_CONVERSION(Algorithm, EC);
+    TEST_ENUM_CONVERSION(Algorithm, AES);
+    TEST_ENUM_CONVERSION(Algorithm, TRIPLE_DES);
+    TEST_ENUM_CONVERSION(Algorithm, HMAC);
+    TEST_ENUM_CONVERSION(Digest, NONE);
+    TEST_ENUM_CONVERSION(Digest, MD5);
+    TEST_ENUM_CONVERSION(Digest, SHA1);
+    TEST_ENUM_CONVERSION(Digest, SHA_2_224);
+    TEST_ENUM_CONVERSION(Digest, SHA_2_256);
+    TEST_ENUM_CONVERSION(Digest, SHA_2_384);
+    TEST_ENUM_CONVERSION(Digest, SHA_2_512);
+    TEST_ENUM_CONVERSION(EcCurve, P_224);
+    TEST_ENUM_CONVERSION(EcCurve, P_256);
+    TEST_ENUM_CONVERSION(EcCurve, P_384);
+    TEST_ENUM_CONVERSION(EcCurve, P_521);
+    TEST_ENUM_CONVERSION(BlockMode, ECB);
+    TEST_ENUM_CONVERSION(BlockMode, CBC);
+    TEST_ENUM_CONVERSION(BlockMode, CTR);
+    TEST_ENUM_CONVERSION(BlockMode, GCM);
+    TEST_ENUM_CONVERSION(PaddingMode, NONE);
+    TEST_ENUM_CONVERSION(PaddingMode, RSA_OAEP);
+    TEST_ENUM_CONVERSION(PaddingMode, RSA_PSS);
+    TEST_ENUM_CONVERSION(PaddingMode, RSA_PKCS1_1_5_ENCRYPT);
+    TEST_ENUM_CONVERSION(PaddingMode, RSA_PKCS1_1_5_SIGN);
+    TEST_ENUM_CONVERSION(PaddingMode, PKCS7);
+    TEST_ENUM_CONVERSION(HardwareAuthenticatorType, PASSWORD);
+    TEST_ENUM_CONVERSION(HardwareAuthenticatorType, FINGERPRINT);
+    TEST_ENUM_CONVERSION(SecurityLevel, SOFTWARE);
+    TEST_ENUM_CONVERSION(SecurityLevel, TRUSTED_ENVIRONMENT);
+    TEST_ENUM_CONVERSION(SecurityLevel, STRONGBOX);
+    TEST_ENUM_CONVERSION(KeyOrigin, GENERATED);
+    TEST_ENUM_CONVERSION(KeyOrigin, DERIVED);
+    TEST_ENUM_CONVERSION(KeyOrigin, IMPORTED);
+    TEST_ENUM_CONVERSION(KeyOrigin, GENERATED);
+    TEST_ENUM_CONVERSION(KeyOrigin, SECURELY_IMPORTED);
+
+    // RESERVED and UNKNOWN correspond but changed their names.
+    ASSERT_EQ(KMV1::KeyOrigin::RESERVED, convert(V4_0::KeyOrigin::UNKNOWN));
+    ASSERT_EQ(V4_0::KeyOrigin::UNKNOWN, convert(KMV1::KeyOrigin::RESERVED));
+}
+
+#define TEST_KEY_PARAMETER_CONVERSION_V4_0(tag)                                                    \
+    do {                                                                                           \
+        auto kmv1_param = KMV1::makeKeyParameter(                                                  \
+            KMV1::tag, KMV1::TypedTag2ValueType<decltype(KMV1::tag)>::type{});                     \
+        auto legacy_param = V4_0::makeKeyParameter(                                                \
+            V4_0::tag, V4_0::TypedTag2ValueType<decltype(V4_0::tag)>::type{});                     \
+        ASSERT_EQ(legacy_param, convertKeyParameterToLegacy(kmv1_param));                          \
+        ASSERT_EQ(kmv1_param, convertKeyParameterFromLegacy(legacy_param));                        \
+    } while (false)
+
+#define TEST_KEY_PARAMETER_CONVERSION_V4_1(tag)                                                    \
+    do {                                                                                           \
+        auto kmv1_param = KMV1::makeKeyParameter(                                                  \
+            KMV1::tag, KMV1::TypedTag2ValueType<decltype(KMV1::tag)>::type{});                     \
+        auto legacy_param = V4_0::makeKeyParameter(                                                \
+            V4_1::tag, V4_0::TypedTag2ValueType<decltype(V4_1::tag)>::type{});                     \
+        ASSERT_EQ(legacy_param, convertKeyParameterToLegacy(kmv1_param));                          \
+        ASSERT_EQ(kmv1_param, convertKeyParameterFromLegacy(legacy_param));                        \
+    } while (false)
+
+TEST(KmCompatTypeConversionTest, testKeyParameterConversion) {
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ACTIVE_DATETIME);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ALGORITHM);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ALLOW_WHILE_ON_BODY);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_APPLICATION_DATA);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_APPLICATION_ID);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ASSOCIATED_DATA);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_APPLICATION_ID);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_CHALLENGE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_ID_BRAND);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_ID_DEVICE);
+    //    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_ID_IMEI);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_ID_MANUFACTURER);
+    //    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_ID_MEID);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_ID_PRODUCT);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_ID_MODEL);
+    //    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ATTESTATION_ID_SERIAL);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_AUTH_TIMEOUT);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_BLOCK_MODE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_BOOTLOADER_ONLY);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_BOOT_PATCHLEVEL);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_CALLER_NONCE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_CONFIRMATION_TOKEN);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_CREATION_DATETIME);
+    TEST_KEY_PARAMETER_CONVERSION_V4_1(TAG_DEVICE_UNIQUE_ATTESTATION);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_DIGEST);
+    TEST_KEY_PARAMETER_CONVERSION_V4_1(TAG_EARLY_BOOT_ONLY);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_EC_CURVE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_HARDWARE_TYPE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_1(TAG_IDENTITY_CREDENTIAL_KEY);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_INCLUDE_UNIQUE_ID);
+    //    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_INVALID);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_KEY_SIZE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_MAC_LENGTH);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_MAX_USES_PER_BOOT);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_MIN_MAC_LENGTH);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_MIN_SECONDS_BETWEEN_OPS);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_NONCE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_NO_AUTH_REQUIRED);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ORIGIN);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ORIGINATION_EXPIRE_DATETIME);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_OS_PATCHLEVEL);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_OS_VERSION);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_PADDING);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_PURPOSE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_RESET_SINCE_ID_ROTATION);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ROLLBACK_RESISTANCE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_ROOT_OF_TRUST);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_RSA_PUBLIC_EXPONENT);
+    TEST_KEY_PARAMETER_CONVERSION_V4_1(TAG_STORAGE_KEY);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_TRUSTED_CONFIRMATION_REQUIRED);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_UNIQUE_ID);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_UNLOCKED_DEVICE_REQUIRED);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_USAGE_EXPIRE_DATETIME);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_USER_AUTH_TYPE);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_USER_ID);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_USER_SECURE_ID);
+    TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_VENDOR_PATCHLEVEL);
+}