Change KeyParameters to use a union.

This CL updates AndroidKeyMintDevice to use the new unionized
KeyParameters.

Test: VtsAidlKeyMintTargetTest
Change-Id: I2be1a192d26d44c99a33a8daf41937264ba5ab63
diff --git a/ng/KeyMintUtils.cpp b/ng/KeyMintUtils.cpp
index 5238f6e..c5a2d63 100644
--- a/ng/KeyMintUtils.cpp
+++ b/ng/KeyMintUtils.cpp
@@ -14,12 +14,89 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "android.hardware.security.keymint-impl"
+#include <android-base/logging.h>
+
 #include "KeyMintUtils.h"
 
-namespace aidl::android::hardware::security::keymint {
+namespace aidl::android::hardware::security::keymint::km_utils {
 
 using namespace ::keymaster;
 
+namespace {
+
+KeyParameter kmEnumParam2Aidl(const keymaster_key_param_t& param) {
+    switch (param.tag) {
+    case KM_TAG_PURPOSE:
+        return KeyParameter{Tag::PURPOSE, KeyParameterValue::make<KeyParameterValue::keyPurpose>(
+                                              static_cast<KeyPurpose>(param.enumerated))};
+    case KM_TAG_ALGORITHM:
+        return KeyParameter{Tag::ALGORITHM, KeyParameterValue::make<KeyParameterValue::algorithm>(
+                                                static_cast<Algorithm>(param.enumerated))};
+    case KM_TAG_BLOCK_MODE:
+        return KeyParameter{Tag::BLOCK_MODE, KeyParameterValue::make<KeyParameterValue::blockMode>(
+                                                 static_cast<BlockMode>(param.enumerated))};
+    case KM_TAG_DIGEST:
+        return KeyParameter{Tag::DIGEST, KeyParameterValue::make<KeyParameterValue::digest>(
+                                             static_cast<Digest>(param.enumerated))};
+    case KM_TAG_PADDING:
+        return KeyParameter{Tag::PADDING, KeyParameterValue::make<KeyParameterValue::paddingMode>(
+                                              static_cast<PaddingMode>(param.enumerated))};
+    case KM_TAG_EC_CURVE:
+        return KeyParameter{Tag::EC_CURVE, KeyParameterValue::make<KeyParameterValue::ecCurve>(
+                                               static_cast<EcCurve>(param.enumerated))};
+    case KM_TAG_USER_AUTH_TYPE:
+        return KeyParameter{Tag::USER_AUTH_TYPE,
+                            KeyParameterValue::make<KeyParameterValue::hardwareAuthenticatorType>(
+                                static_cast<HardwareAuthenticatorType>(param.enumerated))};
+    case KM_TAG_ORIGIN:
+        return KeyParameter{Tag::ORIGIN, KeyParameterValue::make<KeyParameterValue::origin>(
+                                             static_cast<KeyOrigin>(param.enumerated))};
+    case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+    case KM_TAG_KDF:
+    default:
+        return KeyParameter{Tag::INVALID, false};
+    }
+}
+
+keymaster_key_param_t kInvalidTag{.tag = KM_TAG_INVALID, .integer = 0};
+
+template <KeyParameterValue::Tag aidl_tag>
+keymaster_key_param_t aidlEnumVal2Km(keymaster_tag_t km_tag, const KeyParameterValue& value) {
+    return value.getTag() == aidl_tag
+               ? keymaster_param_enum(km_tag, static_cast<uint32_t>(value.get<aidl_tag>()))
+               : kInvalidTag;
+}
+
+keymaster_key_param_t aidlEnumParam2Km(const KeyParameter& param) {
+    auto tag = km_utils::legacy_enum_conversion(param.tag);
+    switch (tag) {
+    case KM_TAG_PURPOSE:
+        return aidlEnumVal2Km<KeyParameterValue::keyPurpose>(tag, param.value);
+    case KM_TAG_ALGORITHM:
+        return aidlEnumVal2Km<KeyParameterValue::algorithm>(tag, param.value);
+    case KM_TAG_BLOCK_MODE:
+        return aidlEnumVal2Km<KeyParameterValue::blockMode>(tag, param.value);
+    case KM_TAG_DIGEST:
+        return aidlEnumVal2Km<KeyParameterValue::digest>(tag, param.value);
+    case KM_TAG_PADDING:
+        return aidlEnumVal2Km<KeyParameterValue::paddingMode>(tag, param.value);
+    case KM_TAG_EC_CURVE:
+        return aidlEnumVal2Km<KeyParameterValue::ecCurve>(tag, param.value);
+    case KM_TAG_USER_AUTH_TYPE:
+        return aidlEnumVal2Km<KeyParameterValue::hardwareAuthenticatorType>(tag, param.value);
+    case KM_TAG_ORIGIN:
+        return aidlEnumVal2Km<KeyParameterValue::origin>(tag, param.value);
+    case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+    case KM_TAG_KDF:
+    default:
+        CHECK(false) << "Unknown or unused enum tag: Something is broken";
+        return keymaster_param_enum(tag, false);
+    }
+}
+
+}  // namespace
+
 vector<uint8_t> authToken2AidlVec(const HardwareAuthToken& token) {
     static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
                           sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
@@ -44,90 +121,112 @@
     return result;
 }
 
-// TODO(seleneh): This needs to be modified depends on how aidl support for union came out to
-// be.
 vector<KeyParameter> kmParamSet2Aidl(const keymaster_key_param_set_t& set) {
     vector<KeyParameter> result;
     if (set.length == 0 || set.params == nullptr) return result;
 
-    result.resize(set.length);
+    result.reserve(set.length);
     keymaster_key_param_t* params = set.params;
     for (size_t i = 0; i < set.length; ++i) {
-        auto tag = params[i].tag;
-        result[i].tag = legacy_enum_conversion(tag);
-        switch (typeFromTag(tag)) {
+        auto tag = legacy_enum_conversion(params[i].tag);
+        switch (typeFromTag(params[i].tag)) {
         case KM_ENUM:
         case KM_ENUM_REP:
-            result[i].integer = params[i].enumerated;
+            result.push_back(kmEnumParam2Aidl(params[i]));
             break;
         case KM_UINT:
         case KM_UINT_REP:
-            result[i].integer = params[i].integer;
+            result.push_back(KeyParameter{
+                tag, KeyParameterValue::make<KeyParameterValue::integer>(params[i].integer)});
             break;
         case KM_ULONG:
         case KM_ULONG_REP:
-            result[i].longInteger = params[i].long_integer;
+            result.push_back(KeyParameter{
+                tag,
+                KeyParameterValue::make<KeyParameterValue::longInteger>(params[i].long_integer)});
             break;
         case KM_DATE:
-            result[i].longInteger = params[i].date_time;
+            result.push_back(KeyParameter{
+                tag, KeyParameterValue::make<KeyParameterValue::dateTime>(params[i].date_time)});
             break;
         case KM_BOOL:
-            result[i].boolValue = params[i].boolean;
+            result.push_back(KeyParameter{tag, params[i].boolean});
             break;
         case KM_BIGNUM:
         case KM_BYTES:
-            result[i].blob.assign(params[i].blob.data,
-                                  params[i].blob.data + params[i].blob.data_length);
+            result.push_back(
+                {tag, KeyParameterValue::make<KeyParameterValue::blob>(std::vector(
+                          params[i].blob.data, params[i].blob.data + params[i].blob.data_length))});
             break;
         case KM_INVALID:
         default:
-            params[i].tag = KM_TAG_INVALID;
-            /* just skip */
+            CHECK(false) << "Unknown or unused enum tag: Something is broken";
+            result.push_back(KeyParameter{tag, false});
             break;
         }
     }
     return result;
 }
 
-// TODO(seleneh): This needs to be modified depends on how aidl support for union came out to
-// be.
 keymaster_key_param_set_t aidlKeyParams2Km(const vector<KeyParameter>& keyParams) {
     keymaster_key_param_set_t set;
 
-    set.params = new keymaster_key_param_t[keyParams.size()];
+    set.params = static_cast<keymaster_key_param_t*>(
+        malloc(keyParams.size() * sizeof(keymaster_key_param_t)));
     set.length = keyParams.size();
 
     for (size_t i = 0; i < keyParams.size(); ++i) {
-        auto tag = legacy_enum_conversion(keyParams[i].tag);
+        const auto& param = keyParams[i];
+        auto tag = legacy_enum_conversion(param.tag);
         switch (typeFromTag(tag)) {
+
         case KM_ENUM:
         case KM_ENUM_REP:
-            set.params[i] = keymaster_param_enum(tag, keyParams[i].integer);
+            set.params[i] = aidlEnumParam2Km(param);
             break;
+
         case KM_UINT:
         case KM_UINT_REP:
-            set.params[i] = keymaster_param_int(tag, keyParams[i].integer);
+            set.params[i] =
+                param.value.getTag() == KeyParameterValue::integer
+                    ? keymaster_param_int(tag, param.value.get<KeyParameterValue::integer>())
+                    : kInvalidTag;
             break;
+
         case KM_ULONG:
         case KM_ULONG_REP:
-            set.params[i] = keymaster_param_long(tag, keyParams[i].longInteger);
+            set.params[i] =
+                param.value.getTag() == KeyParameterValue::longInteger
+                    ? keymaster_param_long(tag, param.value.get<KeyParameterValue::longInteger>())
+                    : kInvalidTag;
             break;
+
         case KM_DATE:
-            set.params[i] = keymaster_param_date(tag, keyParams[i].longInteger);
+            set.params[i] =
+                param.value.getTag() == KeyParameterValue::dateTime
+                    ? keymaster_param_date(tag, param.value.get<KeyParameterValue::dateTime>())
+                    : kInvalidTag;
             break;
+
         case KM_BOOL:
-            if (keyParams[i].boolValue)
-                set.params[i] = keymaster_param_bool(tag);
-            else
-                set.params[i].tag = KM_TAG_INVALID;
+            set.params[i] = keymaster_param_bool(tag);
             break;
+
         case KM_BIGNUM:
         case KM_BYTES:
-            set.params[i] =
-                keymaster_param_blob(tag, keyParams[i].blob.data(), keyParams[i].blob.size());
+            if (param.value.getTag() == KeyParameterValue::blob) {
+                const auto& value = param.value.get<KeyParameterValue::blob>();
+                uint8_t* copy = static_cast<uint8_t*>(malloc(value.size()));
+                std::copy(value.begin(), value.end(), copy);
+                set.params[i] = keymaster_param_blob(tag, copy, value.size());
+            } else {
+                set.params[i] = kInvalidTag;
+            }
             break;
+
         case KM_INVALID:
         default:
+            CHECK(false) << "Invalid tag: Something is broken";
             set.params[i].tag = KM_TAG_INVALID;
             /* just skip */
             break;
@@ -137,4 +236,4 @@
     return set;
 }
 
-}  // namespace aidl::android::hardware::security::keymint
+}  // namespace aidl::android::hardware::security::keymint::km_utils