Merge "Convert all comments into "doxygen-ready" comments." into oc-dev
diff --git a/bluetooth/1.0/IBluetoothHci.hal b/bluetooth/1.0/IBluetoothHci.hal
index 8722616..7996ac3 100644
--- a/bluetooth/1.0/IBluetoothHci.hal
+++ b/bluetooth/1.0/IBluetoothHci.hal
@@ -18,7 +18,7 @@
 
 import IBluetoothHciCallbacks;
 
-/*
+/**
  * The Host Controller Interface (HCI) is the layer defined by the Bluetooth
  * specification between the software that runs on the host and the Bluetooth
  * controller chip. This boundary is the natural choice for a Hardware
diff --git a/bluetooth/1.0/IBluetoothHciCallbacks.hal b/bluetooth/1.0/IBluetoothHciCallbacks.hal
index 15db1ce..b22fa34 100644
--- a/bluetooth/1.0/IBluetoothHciCallbacks.hal
+++ b/bluetooth/1.0/IBluetoothHciCallbacks.hal
@@ -16,7 +16,7 @@
 
 package android.hardware.bluetooth@1.0;
 
-/* The interface from the Bluetooth Controller to the stack. */
+/** The interface from the Bluetooth Controller to the stack. */
 interface IBluetoothHciCallbacks {
     /**
      * Invoked when the Bluetooth controller initialization has been
diff --git a/ir/1.0/IConsumerIr.hal b/ir/1.0/IConsumerIr.hal
index f9e6316..0881dfb 100644
--- a/ir/1.0/IConsumerIr.hal
+++ b/ir/1.0/IConsumerIr.hal
@@ -17,7 +17,7 @@
 package android.hardware.ir@1.0;
 
 interface IConsumerIr {
-    /*
+    /**
      * transmit() sends an IR pattern at a given carrierFreq.
      *
      * The pattern is alternating series of carrier on and off periods measured in
@@ -30,7 +30,7 @@
      */
     transmit(int32_t carrierFreq, vec<int32_t> pattern) generates (bool success);
 
-    /*
+    /**
      * getCarrierFreqs() enumerates which frequencies the IR transmitter supports.
      *
      * returns: On success, true and a vector of all supported frequency
diff --git a/keymaster/3.0/default/KeymasterDevice.cpp b/keymaster/3.0/default/KeymasterDevice.cpp
index 720b946..6b4524b 100644
--- a/keymaster/3.0/default/KeymasterDevice.cpp
+++ b/keymaster/3.0/default/KeymasterDevice.cpp
@@ -698,14 +698,21 @@
     return legacy_enum_conversion(keymaster_device_->abort(keymaster_device_, operationHandle));
 }
 
-IKeymasterDevice* HIDL_FETCH_IKeymasterDevice(const char* /* name */) {
+IKeymasterDevice* HIDL_FETCH_IKeymasterDevice(const char* name) {
     keymaster2_device_t* dev = nullptr;
 
-    uint32_t version;
-    bool supports_ec;
-    bool supports_all_digests;
-    auto rc = keymaster_device_initialize(&dev, &version, &supports_ec, &supports_all_digests);
-    if (rc) return nullptr;
+    ALOGI("Fetching keymaster device name %s", name);
+
+    uint32_t version = -1;
+    bool supports_ec = false;
+    bool supports_all_digests = false;
+
+    if (name && strcmp(name, "softwareonly") == 0) {
+        dev = (new SoftKeymasterDevice(new SoftwareOnlyHidlKeymasterContext))->keymaster2_device();
+    } else if (name && strcmp(name, "default") == 0) {
+        auto rc = keymaster_device_initialize(&dev, &version, &supports_ec, &supports_all_digests);
+        if (rc) return nullptr;
+    }
 
     auto kmrc = ::keymaster::ConfigureDevice(dev);
     if (kmrc != KM_ERROR_OK) {
diff --git a/keymaster/3.0/vts/functional/Android.mk b/keymaster/3.0/vts/functional/Android.mk
new file mode 100644
index 0000000..1b29cde
--- /dev/null
+++ b/keymaster/3.0/vts/functional/Android.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2017 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := keymaster_hidl_hal_test
+LOCAL_SRC_FILES := \
+        authorization_set.cpp \
+        attestation_record.cpp \
+        key_param_output.cpp \
+        keymaster_hidl_hal_test.cpp \
+        keystore_tags_utils.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+        android.hardware.keymaster@3.0 \
+        libcrypto \
+        libhidlbase \
+        liblog \
+        libsoftkeymasterdevice \
+        libutils \
+
+LOCAL_STATIC_LIBRARIES := \
+        VtsHalHidlTargetTestBase \
+
+include $(BUILD_NATIVE_TEST)
diff --git a/keymaster/3.0/vts/functional/attestation_record.cpp b/keymaster/3.0/vts/functional/attestation_record.cpp
new file mode 100644
index 0000000..6cdd44c
--- /dev/null
+++ b/keymaster/3.0/vts/functional/attestation_record.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2016 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 "attestation_record.h"
+
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include "openssl_utils.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+
+struct stack_st_ASN1_TYPE_Delete {
+    void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+    void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+    void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+    ASN1_OCTET_STRING* verified_boot_key;
+    ASN1_BOOLEAN* device_locked;
+    ASN1_ENUMERATED* verified_boot_state;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+    ASN1_INTEGER_SET* purpose;
+    ASN1_INTEGER* algorithm;
+    ASN1_INTEGER* key_size;
+    ASN1_INTEGER_SET* digest;
+    ASN1_INTEGER_SET* padding;
+    ASN1_INTEGER_SET* kdf;
+    ASN1_INTEGER* ec_curve;
+    ASN1_INTEGER* rsa_public_exponent;
+    ASN1_INTEGER* active_date_time;
+    ASN1_INTEGER* origination_expire_date_time;
+    ASN1_INTEGER* usage_expire_date_time;
+    ASN1_NULL* no_auth_required;
+    ASN1_INTEGER* user_auth_type;
+    ASN1_INTEGER* auth_timeout;
+    ASN1_NULL* allow_while_on_body;
+    ASN1_NULL* all_applications;
+    ASN1_OCTET_STRING* application_id;
+    ASN1_INTEGER* creation_date_time;
+    ASN1_INTEGER* origin;
+    ASN1_NULL* rollback_resistant;
+    KM_ROOT_OF_TRUST* root_of_trust;
+    ASN1_INTEGER* os_version;
+    ASN1_INTEGER* os_patchlevel;
+    ASN1_OCTET_STRING* attestation_application_id;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+                 TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+                 TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+                 TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, TAG_CREATION_DATETIME.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+    ASN1_INTEGER* attestation_version;
+    ASN1_ENUMERATED* attestation_security_level;
+    ASN1_INTEGER* keymaster_version;
+    ASN1_ENUMERATED* keymaster_security_level;
+    ASN1_OCTET_STRING* attestation_challenge;
+    KM_AUTH_LIST* software_enforced;
+    KM_AUTH_LIST* tee_enforced;
+    ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+    for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+        auth_list->push_back(
+            ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+    }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+    if (!asn1_int) return;
+    auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+    BIGNUM* value = BN_new();
+    BIGNUM_Ptr one(BN_new());
+    BN_one(one.get());
+    BN_lshift(value, one.get(), 32);
+    return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+    static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+                  "This implementation only supports 32 and 64-bit BN_ULONG");
+    if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+        BIGNUM_Ptr uint_max(construct_uint_max());
+        BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+        BN_CTX_Ptr ctx(BN_CTX_new());
+        BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+        return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+    } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+        return BN_get_word(num);
+    } else {
+        return 0;
+    }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_null) return;
+    auth_list->push_back(ttag);
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_string) return;
+    hidl_vec<uint8_t> buf;
+    buf.setToExternal(asn1_string->data, asn1_string->length);
+    auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+    if (!record) return ErrorCode::OK;
+
+    copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+    copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+    copyAuthTag(record->all_applications, TAG_ALL_APPLICATIONS, auth_list);
+    copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+    copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+    copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+    copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+    copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+    copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+    copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+    copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+    copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+    copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+    copyAuthTag(record->padding, TAG_PADDING, auth_list);
+    copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+    copyAuthTag(record->rollback_resistant, TAG_ROLLBACK_RESISTANT, auth_list);
+    copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+    copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+
+    return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                   uint32_t* attestation_version,  //
+                                   SecurityLevel* attestation_security_level,
+                                   uint32_t* keymaster_version,
+                                   SecurityLevel* keymaster_security_level,
+                                   hidl_vec<uint8_t>* attestation_challenge,
+                                   AuthorizationSet* software_enforced,
+                                   AuthorizationSet* tee_enforced,  //
+                                   hidl_vec<uint8_t>* unique_id) {
+    const uint8_t* p = asn1_key_desc;
+    KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
+    if (!record.get()) return ErrorCode::UNKNOWN_ERROR;
+
+    *attestation_version = ASN1_INTEGER_get(record->attestation_version);
+    *attestation_security_level =
+        static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+    *keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+    *keymaster_security_level =
+        static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+    attestation_challenge->setToExternal(record->attestation_challenge->data,
+                                         record->attestation_challenge->length);
+
+    unique_id->setToExternal(record->unique_id->data, record->unique_id->length);
+
+    ErrorCode error = extract_auth_list(record->software_enforced, software_enforced);
+    if (error != ErrorCode::OK) return error;
+
+    return extract_auth_list(record->tee_enforced, tee_enforced);
+}
+
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/3.0/vts/functional/attestation_record.h b/keymaster/3.0/vts/functional/attestation_record.h
new file mode 100644
index 0000000..a042055
--- /dev/null
+++ b/keymaster/3.0/vts/functional/attestation_record.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_30_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
+#define HARDWARE_INTERFACES_KEYMASTER_30_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
+
+#include "authorization_set.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+
+/**
+ * The OID for Android attestation records.  For the curious, it breaks down as follows:
+ *
+ * 1 = ISO
+ * 3 = org
+ * 6 = DoD (Huh? OIDs are weird.)
+ * 1 = IANA
+ * 4 = Private
+ * 1 = Enterprises
+ * 11129 = Google
+ * 2 = Google security
+ * 1 = certificate extension
+ * 17 = Android attestation extension.
+ */
+static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
+
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                   uint32_t* attestation_version,  //
+                                   SecurityLevel* attestation_security_level,
+                                   uint32_t* keymaster_version,
+                                   SecurityLevel* keymaster_security_level,
+                                   hidl_vec<uint8_t>* attestation_challenge,
+                                   AuthorizationSet* software_enforced,
+                                   AuthorizationSet* tee_enforced,  //
+                                   hidl_vec<uint8_t>* unique_id);
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_30_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
diff --git a/keymaster/3.0/vts/functional/authorization_set.cpp b/keymaster/3.0/vts/functional/authorization_set.cpp
new file mode 100644
index 0000000..303f7e7
--- /dev/null
+++ b/keymaster/3.0/vts/functional/authorization_set.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2014 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 "authorization_set.h"
+
+#include <assert.h>
+#include <istream>
+#include <limits>
+#include <ostream>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <new>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+
+inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) return a.tag < b.tag;
+    int retval;
+    switch (typeFromTag(a.tag)) {
+    case TagType::INVALID:
+    case TagType::BOOL:
+        return false;
+    case TagType::ENUM:
+    case TagType::ENUM_REP:
+    case TagType::UINT:
+    case TagType::UINT_REP:
+        return a.f.integer < b.f.integer;
+    case TagType::ULONG:
+    case TagType::ULONG_REP:
+        return a.f.longInteger < b.f.longInteger;
+    case TagType::DATE:
+        return a.f.dateTime < b.f.dateTime;
+    case TagType::BIGNUM:
+    case TagType::BYTES:
+        // Handle the empty cases.
+        if (a.blob.size() == 0) return b.blob.size() != 0;
+        if (b.blob.size() == 0) return false;
+
+        retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+        if (retval == 0) {
+            // One is the prefix of the other, so the longer wins
+            return a.blob.size() < b.blob.size();
+        } else {
+            return retval < 0;
+        }
+    }
+    return false;
+}
+
+inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) return false;
+
+    switch (typeFromTag(a.tag)) {
+    case TagType::INVALID:
+    case TagType::BOOL:
+        return true;
+    case TagType::ENUM:
+    case TagType::ENUM_REP:
+    case TagType::UINT:
+    case TagType::UINT_REP:
+        return a.f.integer == b.f.integer;
+    case TagType::ULONG:
+    case TagType::ULONG_REP:
+        return a.f.longInteger == b.f.longInteger;
+    case TagType::DATE:
+        return a.f.dateTime == b.f.dateTime;
+    case TagType::BIGNUM:
+    case TagType::BYTES:
+        if (a.blob.size() != b.blob.size()) return false;
+        return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
+    }
+    return false;
+}
+
+void AuthorizationSet::Sort() {
+    std::sort(data_.begin(), data_.end(), keyParamLess);
+}
+
+void AuthorizationSet::Deduplicate() {
+    if (data_.empty()) return;
+
+    Sort();
+    std::vector<KeyParameter> result;
+
+    auto curr = data_.begin();
+    auto prev = curr++;
+    for (; curr != data_.end(); ++prev, ++curr) {
+        if (prev->tag == Tag::INVALID) continue;
+
+        if (!keyParamEqual(*prev, *curr)) {
+            result.emplace_back(std::move(*prev));
+        }
+    }
+    result.emplace_back(std::move(*prev));
+
+    std::swap(data_, result);
+}
+
+void AuthorizationSet::Union(const AuthorizationSet& other) {
+    data_.insert(data_.end(), other.data_.begin(), other.data_.end());
+    Deduplicate();
+}
+
+void AuthorizationSet::Subtract(const AuthorizationSet& other) {
+    Deduplicate();
+
+    auto i = other.begin();
+    while (i != other.end()) {
+        int pos = -1;
+        do {
+            pos = find(i->tag, pos);
+            if (pos != -1 && keyParamEqual(*i, data_[pos])) {
+                data_.erase(data_.begin() + pos);
+                break;
+            }
+        } while (pos != -1);
+        ++i;
+    }
+}
+
+int AuthorizationSet::find(Tag tag, int begin) const {
+    auto iter = data_.begin() + (1 + begin);
+
+    while (iter != data_.end() && iter->tag != tag)
+        ++iter;
+
+    if (iter != data_.end()) return iter - data_.begin();
+    return -1;
+}
+
+bool AuthorizationSet::erase(int index) {
+    auto pos = data_.begin() + index;
+    if (pos != data_.end()) {
+        data_.erase(pos);
+        return true;
+    }
+    return false;
+}
+
+KeyParameter& AuthorizationSet::operator[](int at) {
+    return data_[at];
+}
+
+const KeyParameter& AuthorizationSet::operator[](int at) const {
+    return data_[at];
+}
+
+void AuthorizationSet::Clear() {
+    data_.clear();
+}
+
+size_t AuthorizationSet::GetTagCount(Tag tag) const {
+    size_t count = 0;
+    for (int pos = -1; (pos = find(tag, pos)) != -1;)
+        ++count;
+    return count;
+}
+
+NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
+    int pos = find(tag);
+    if (pos == -1) return {};
+    return data_[pos];
+}
+
+/**
+ * Persistent format is:
+ * | 32 bit indirect_size         |
+ * --------------------------------
+ * | indirect_size bytes of data  | this is where the blob data is stored
+ * --------------------------------
+ * | 32 bit element_count         | number of entries
+ * | 32 bit elements_size         | total bytes used by entries (entries have variable length)
+ * --------------------------------
+ * | elementes_size bytes of data | where the elements are stored
+ */
+
+/**
+ * Persistent format of blobs and bignums:
+ * | 32 bit tag             |
+ * | 32 bit blob_length     |
+ * | 32 bit indirect_offset |
+ */
+
+struct OutStreams {
+    std::ostream& indirect;
+    std::ostream& elements;
+};
+
+OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
+    uint32_t buffer;
+
+    // write blob_length
+    auto blob_length = blob.size();
+    if (blob_length > std::numeric_limits<uint32_t>::max()) {
+        out.elements.setstate(std::ios_base::badbit);
+        return out;
+    }
+    buffer = blob_length;
+    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+    // write indirect_offset
+    auto offset = out.indirect.tellp();
+    if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
+        static_cast<uint32_t>((std::numeric_limits<uint32_t>::max() - offset)) <
+            blob_length) {  // overflow check
+        out.elements.setstate(std::ios_base::badbit);
+        return out;
+    }
+    buffer = offset;
+    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+    // write blob to indirect stream
+    if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
+
+    return out;
+}
+
+template <typename T> OutStreams& serializeParamValue(OutStreams& out, const T& value) {
+    out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
+    return out;
+}
+
+OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
+    // skip invalid entries.
+    return out;
+}
+template <typename T> OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
+    out.elements.write(reinterpret_cast<const char*>(&param.tag), sizeof(int32_t));
+    return serializeParamValue(out, accessTagValue(ttag, param));
+}
+
+template <typename... T> struct choose_serializer;
+template <typename... Tags> struct choose_serializer<MetaList<Tags...>> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        return choose_serializer<Tags...>::serialize(out, param);
+    }
+};
+template <> struct choose_serializer<> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_serializer<TypedTag<tag_type, tag>, Tail...> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        if (param.tag == tag) {
+            return V3_0::serialize(TypedTag<tag_type, tag>(), out, param);
+        } else {
+            return choose_serializer<Tail...>::serialize(out, param);
+        }
+    }
+};
+
+OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+    return choose_serializer<all_tags_t>::serialize(out, param);
+}
+
+std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
+    std::stringstream indirect;
+    std::stringstream elements;
+    OutStreams streams = {indirect, elements};
+    for (const auto& param : params) {
+        serialize(streams, param);
+    }
+    if (indirect.bad() || elements.bad()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    auto pos = indirect.tellp();
+    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    uint32_t indirect_size = pos;
+    pos = elements.tellp();
+    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    uint32_t elements_size = pos;
+    uint32_t element_count = params.size();
+
+    out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
+
+    pos = out.tellp();
+    if (indirect_size) out << indirect.rdbuf();
+    assert(out.tellp() - pos == indirect_size);
+
+    out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
+    out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
+
+    pos = out.tellp();
+    if (elements_size) out << elements.rdbuf();
+    assert(out.tellp() - pos == elements_size);
+
+    return out;
+}
+
+struct InStreams {
+    std::istream& indirect;
+    std::istream& elements;
+};
+
+InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
+    uint32_t blob_length = 0;
+    uint32_t offset = 0;
+    in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
+    blob->resize(blob_length);
+    in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
+    in.indirect.seekg(offset);
+    in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
+    return in;
+}
+
+template <typename T> InStreams& deserializeParamValue(InStreams& in, T* value) {
+    in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
+    return in;
+}
+
+InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
+    // there should be no invalid KeyParamaters but if handle them as zero sized.
+    return in;
+}
+
+template <typename T> InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
+    return deserializeParamValue(in, &accessTagValue(ttag, *param));
+}
+
+template <typename... T> struct choose_deserializer;
+template <typename... Tags> struct choose_deserializer<MetaList<Tags...>> {
+    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+        return choose_deserializer<Tags...>::deserialize(in, param);
+    }
+};
+template <> struct choose_deserializer<> {
+    static InStreams& deserialize(InStreams& in, KeyParameter*) {
+        // encountered an unknown tag -> fail parsing
+        in.elements.setstate(std::ios_base::badbit);
+        return in;
+    }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
+    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+        if (param->tag == tag) {
+            return V3_0::deserialize(TypedTag<tag_type, tag>(), in, param);
+        } else {
+            return choose_deserializer<Tail...>::deserialize(in, param);
+        }
+    }
+};
+
+InStreams& deserialize(InStreams& in, KeyParameter* param) {
+    in.elements.read(reinterpret_cast<char*>(&param->tag), sizeof(Tag));
+    return choose_deserializer<all_tags_t>::deserialize(in, param);
+}
+
+std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
+    uint32_t indirect_size = 0;
+    in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
+    std::string indirect_buffer(indirect_size, '\0');
+    if (indirect_buffer.size() != indirect_size) {
+        in.setstate(std::ios_base::badbit);
+        return in;
+    }
+    in.read(&indirect_buffer[0], indirect_buffer.size());
+
+    uint32_t element_count = 0;
+    in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
+    uint32_t elements_size = 0;
+    in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
+
+    std::string elements_buffer(elements_size, '\0');
+    if (elements_buffer.size() != elements_size) {
+        in.setstate(std::ios_base::badbit);
+        return in;
+    }
+    in.read(&elements_buffer[0], elements_buffer.size());
+
+    if (in.bad()) return in;
+
+    // TODO write one-shot stream buffer to avoid copying here
+    std::stringstream indirect(indirect_buffer);
+    std::stringstream elements(elements_buffer);
+    InStreams streams = {indirect, elements};
+
+    params->resize(element_count);
+
+    for (uint32_t i = 0; i < element_count; ++i) {
+        deserialize(streams, &(*params)[i]);
+    }
+    return in;
+}
+
+void AuthorizationSet::Serialize(std::ostream* out) const {
+    serialize(*out, data_);
+}
+
+void AuthorizationSet::Deserialize(std::istream* in) {
+    deserialize(*in, &data_);
+}
+
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/3.0/vts/functional/authorization_set.h b/keymaster/3.0/vts/functional/authorization_set.h
new file mode 100644
index 0000000..5f92d81
--- /dev/null
+++ b/keymaster/3.0/vts/functional/authorization_set.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_30_VTS_FUNCTIONAL_AUTHORIZATION_SET_H_
+#define HARDWARE_INTERFACES_KEYMASTER_30_VTS_FUNCTIONAL_AUTHORIZATION_SET_H_
+
+#include "keymaster_tags.h"
+
+#include <utility>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+
+class AuthorizationSetBuilder;
+
+/**
+ * An ordered collection of KeyParameters. It provides memory ownership and some convenient
+ * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters.
+ * For serialization, wrap the backing store of this structure in a hidl_vec<KeyParameter>.
+ */
+class AuthorizationSet {
+  public:
+    typedef KeyParameter value_type;
+
+    /**
+     * Construct an empty, dynamically-allocated, growable AuthorizationSet.
+     */
+    AuthorizationSet(){};
+
+    // Copy constructor.
+    AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
+
+    // Move constructor.
+    AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {}
+
+    // Constructor from hidl_vec<KeyParameter>
+    AuthorizationSet(const hidl_vec<KeyParameter>& other) { *this = other; }
+
+    // Copy assignment.
+    AuthorizationSet& operator=(const AuthorizationSet& other) {
+        data_ = other.data_;
+        return *this;
+    }
+
+    // Move assignment.
+    AuthorizationSet& operator=(AuthorizationSet&& other) {
+        data_ = std::move(other.data_);
+        return *this;
+    }
+
+    AuthorizationSet& operator=(const hidl_vec<KeyParameter>& other) {
+        if (other.size() > 0) {
+            data_.resize(other.size());
+            for (size_t i = 0; i < data_.size(); ++i) {
+                /* This makes a deep copy even of embedded blobs.
+                 * See assignment operator/copy constructor of hidl_vec.*/
+                data_[i] = other[i];
+            }
+        }
+        return *this;
+    }
+
+    /**
+     * Clear existing authorization set data
+     */
+    void Clear();
+
+    ~AuthorizationSet() = default;
+
+    /**
+     * Returns the size of the set.
+     */
+    size_t size() const { return data_.size(); }
+
+    /**
+     * Returns true if the set is empty.
+     */
+    bool empty() const { return size() == 0; }
+
+    /**
+     * Returns the data in the set, directly. Be careful with this.
+     */
+    const KeyParameter* data() const { return data_.data(); }
+
+    /**
+     * Sorts the set
+     */
+    void Sort();
+
+    /**
+     * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
+     * AuthorizationSetBuilder).
+     */
+    void Deduplicate();
+
+    /**
+     * Adds all elements from \p set that are not already present in this AuthorizationSet.  As a
+     * side-effect, if \p set is not null this AuthorizationSet will end up sorted.
+     */
+    void Union(const AuthorizationSet& set);
+
+    /**
+     * Removes all elements in \p set from this AuthorizationSet.
+     */
+    void Subtract(const AuthorizationSet& set);
+
+    /**
+     * Returns the offset of the next entry that matches \p tag, starting from the element after \p
+     * begin.  If not found, returns -1.
+     */
+    int find(Tag tag, int begin = -1) const;
+
+    /**
+     * Removes the entry at the specified index. Returns true if successful, false if the index was
+     * out of bounds.
+     */
+    bool erase(int index);
+
+    /**
+     * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
+     */
+    std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); }
+
+    /**
+     * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
+     */
+    std::vector<KeyParameter>::const_iterator end() const { return data_.end(); }
+
+    /**
+     * Returns the nth element of the set.
+     * Like for std::vector::operator[] there is no range check performed. Use of out of range
+     * indices is undefined.
+     */
+    KeyParameter& operator[](int n);
+
+    /**
+     * Returns the nth element of the set.
+     * Like for std::vector::operator[] there is no range check performed. Use of out of range
+     * indices is undefined.
+     */
+    const KeyParameter& operator[](int n) const;
+
+    /**
+     * Returns true if the set contains at least one instance of \p tag
+     */
+    bool Contains(Tag tag) const { return find(tag) != -1; }
+
+    template <typename T> bool Contains(T tag) const { return find(tag) != -1; }
+
+    template <TagType tag_type, Tag tag, typename ValueT>
+    bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
+        for (const auto& param : data_) {
+            auto entry = authorizationValue(ttag, param);
+            if (entry.isOk() && static_cast<ValueT>(entry.value()) == value) return true;
+        }
+        return false;
+    }
+    /**
+     * Returns the number of \p tag entries.
+     */
+    size_t GetTagCount(Tag tag) const;
+
+    template <typename T>
+    inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const {
+        auto entry = GetEntry(tag);
+        if (entry.isOk()) return authorizationValue(tag, entry.value());
+        return {};
+    }
+
+    void push_back(const KeyParameter& param) { data_.push_back(param); }
+    void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); }
+
+    void push_back(const AuthorizationSet& set) {
+        for (auto& entry : set) {
+            push_back(entry);
+        }
+    }
+
+    void push_back(AuthorizationSet&& set) {
+        move(set.begin(), set.end());
+        set.Clear();
+    }
+
+    template <Tag tag>
+    void push_back(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data, size_t data_length) {
+        hidl_vec<uint8_t> new_blob;
+        new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
+        push_back(ttag, std::move(new_blob));
+    }
+
+    /**
+     * Append the tag and enumerated value to the set.
+     * "val" may be exactly one parameter unless a boolean parameter is added.
+     * In this case "val" is omitted. This condition is checked at compile time by Authorization()
+     */
+    template <typename TypedTagT, typename... Value> void push_back(TypedTagT tag, Value&&... val) {
+        push_back(Authorization(tag, std::forward<Value>(val)...));
+    }
+
+    template <typename Iterator> void push_back(Iterator begin, Iterator end) {
+        while (begin != end) {
+            push_back(*begin);
+            ++begin;
+        }
+    }
+
+    template <typename Iterator> void move(Iterator begin, Iterator end) {
+        std::move(begin, end, std::back_inserter(data_));
+    }
+
+    hidl_vec<KeyParameter> hidl_data() const {
+        hidl_vec<KeyParameter> result;
+        result.setToExternal(const_cast<KeyParameter*>(data()), size());
+        return result;
+    }
+
+    void Serialize(std::ostream* out) const;
+    void Deserialize(std::istream* in);
+
+  private:
+    NullOr<const KeyParameter&> GetEntry(Tag tag) const;
+
+    std::vector<KeyParameter> data_;
+};
+
+class AuthorizationSetBuilder : public AuthorizationSet {
+  public:
+    template <typename TagType, typename... ValueType>
+    AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) {
+        push_back(ttag, std::forward<ValueType>(value)...);
+        return *this;
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data,
+                                           size_t data_length) {
+        hidl_vec<uint8_t> new_blob;
+        new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
+        push_back(ttag, std::move(new_blob));
+        return *this;
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data,
+                                           size_t data_length) {
+        return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+    }
+
+    AuthorizationSetBuilder& Authorizations(AuthorizationSet&& set);
+    AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set);
+
+    AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
+    AuthorizationSetBuilder& EcdsaKey(EcCurve curve);
+    AuthorizationSetBuilder& AesKey(uint32_t key_size);
+    AuthorizationSetBuilder& HmacKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
+    AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve);
+    AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& SigningKey();
+    AuthorizationSetBuilder& EncryptionKey();
+    AuthorizationSetBuilder& NoDigestOrPadding();
+    AuthorizationSetBuilder& EcbMode();
+
+    AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> block_modes);
+    AuthorizationSetBuilder& Digest(std::initializer_list<Digest> digests);
+    AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> padding_modes);
+
+    // The following forwarding templates enable BlockMode,Digest and Padding to be called with a
+    // variable number of arguments; no need to wrap them in braces to make them an initalizer_list.
+    template <typename... T> AuthorizationSetBuilder& BlockMode(T&&... a) {
+        return BlockMode({std::forward<T>(a)...});
+    }
+    template <typename... T> AuthorizationSetBuilder& Digest(T&&... a) {
+        return Digest({std::forward<T>(a)...});
+    }
+    template <typename... T> AuthorizationSetBuilder& Padding(T&&... a) {
+        return Padding({std::forward<T>(a)...});
+    }
+};
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::Authorizations(AuthorizationSet&& set) {
+    move(set.begin(), set.end());
+    set.Clear();
+    return *this;
+}
+
+inline AuthorizationSetBuilder&
+AuthorizationSetBuilder::Authorizations(const AuthorizationSet& set) {
+    push_back(set.begin(), set.end());
+    return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
+                                                                uint64_t public_exponent) {
+    Authorization(TAG_ALGORITHM, Algorithm::RSA);
+    Authorization(TAG_KEY_SIZE, key_size);
+    Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+    return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::EC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(EcCurve curve) {
+    Authorization(TAG_ALGORITHM, Algorithm::EC);
+    Authorization(TAG_EC_CURVE, curve);
+    return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::AES);
+    return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::HMAC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
+                                                                       uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder&
+AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return EncryptionKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
+    EcdsaKey(key_size);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(EcCurve curve) {
+    EcdsaKey(curve);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
+    AesKey(key_size);
+    return EncryptionKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
+    Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
+    return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
+    Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT);
+    return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
+    Authorization(TAG_DIGEST, Digest::NONE);
+    return Authorization(TAG_PADDING, PaddingMode::NONE);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
+    return BlockMode(BlockMode::ECB);
+}
+
+inline AuthorizationSetBuilder&
+AuthorizationSetBuilder::BlockMode(std::initializer_list<V3_0::BlockMode> block_modes) {
+    for (auto block_mode : block_modes) {
+        Authorization(TAG_BLOCK_MODE, block_mode);
+    }
+    return *this;
+}
+
+inline AuthorizationSetBuilder&
+AuthorizationSetBuilder::Digest(std::initializer_list<V3_0::Digest> digests) {
+    for (auto digest : digests) {
+        Authorization(TAG_DIGEST, digest);
+    }
+    return *this;
+}
+
+inline AuthorizationSetBuilder&
+AuthorizationSetBuilder::Padding(std::initializer_list<V3_0::PaddingMode> padding_modes) {
+    for (auto padding : padding_modes) {
+        Authorization(TAG_PADDING, padding);
+    }
+    return *this;
+}
+
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_30_VTS_FUNCTIONAL_AUTHORIZATION_SET_H_
diff --git a/keymaster/3.0/vts/functional/key_param_output.cpp b/keymaster/3.0/vts/functional/key_param_output.cpp
new file mode 100644
index 0000000..fc9f685
--- /dev/null
+++ b/keymaster/3.0/vts/functional/key_param_output.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 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 "key_param_output.h"
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+
+namespace keymaster {
+namespace V3_0 {
+
+::std::ostream& operator<<(::std::ostream& os, const hidl_vec<KeyParameter>& set) {
+    if (set.size() == 0) {
+        os << "(Empty)" << ::std::endl;
+    } else {
+        os << "\n";
+        for (size_t i = 0; i < set.size(); ++i)
+            os << set[i] << ::std::endl;
+    }
+    return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, ErrorCode value) {
+    return os << (int)value;
+}
+
+::std::ostream& operator<<(::std::ostream& os, Digest value) {
+    return os << stringify(value);
+}
+
+::std::ostream& operator<<(::std::ostream& os, Algorithm value) {
+    return os << stringify(value);
+}
+
+::std::ostream& operator<<(::std::ostream& os, BlockMode value) {
+    return os << stringify(value);
+}
+
+::std::ostream& operator<<(::std::ostream& os, PaddingMode value) {
+    return os << stringify(value);
+}
+
+::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) {
+    return os << stringify(value);
+}
+
+::std::ostream& operator<<(::std::ostream& os, KeyPurpose value) {
+    return os << stringify(value);
+}
+
+::std::ostream& operator<<(::std::ostream& os, EcCurve value) {
+    return os << stringify(value);
+}
+
+::std::ostream& operator<<(::std::ostream& os, const KeyParameter& param) {
+    os << stringifyTag(param.tag) << ": ";
+    switch (typeFromTag(param.tag)) {
+    case TagType::INVALID:
+        return os << " Invalid";
+    case TagType::UINT_REP:
+    case TagType::UINT:
+        return os << param.f.integer;
+    case TagType::ENUM_REP:
+    case TagType::ENUM:
+        switch (param.tag) {
+        case Tag::ALGORITHM:
+            return os << param.f.algorithm;
+        case Tag::BLOCK_MODE:
+            return os << param.f.blockMode;
+        case Tag::PADDING:
+            return os << param.f.paddingMode;
+        case Tag::DIGEST:
+            return os << param.f.digest;
+        case Tag::EC_CURVE:
+            return os << (int)param.f.ecCurve;
+        case Tag::ORIGIN:
+            return os << param.f.origin;
+        case Tag::BLOB_USAGE_REQUIREMENTS:
+            return os << (int)param.f.keyBlobUsageRequirements;
+        case Tag::PURPOSE:
+            return os << param.f.purpose;
+        default:
+            return os << " UNKNOWN ENUM " << param.f.integer;
+        }
+    case TagType::ULONG_REP:
+    case TagType::ULONG:
+        return os << param.f.longInteger;
+    case TagType::DATE:
+        return os << param.f.dateTime;
+    case TagType::BOOL:
+        return os << "true";
+    case TagType::BIGNUM:
+        os << " Bignum: ";
+        for (size_t i = 0; i < param.blob.size(); ++i) {
+            os << ::std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+        }
+        return os;
+    case TagType::BYTES:
+        os << " Bytes: ";
+        for (size_t i = 0; i < param.blob.size(); ++i) {
+            os << ::std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+        }
+        return os;
+    }
+    return os << "UNKNOWN TAG TYPE!";
+}
+
+::std::ostream& operator<<(::std::ostream& os, const KeyCharacteristics& chars) {
+    return os << "SW: " << chars.softwareEnforced << ::std::endl
+              << "TEE: " << chars.teeEnforced << ::std::endl;
+}
+
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/3.0/vts/functional/key_param_output.h b/keymaster/3.0/vts/functional/key_param_output.h
new file mode 100644
index 0000000..5edec2d
--- /dev/null
+++ b/keymaster/3.0/vts/functional/key_param_output.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 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 <iostream>
+
+#include <android/hardware/keymaster/3.0/types.h>
+
+#include "keymaster_tags.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+
+template <typename ValueT>
+::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) {
+    if (!value.isOk()) {
+        os << "(value not present)";
+    } else {
+        os << value.value();
+    }
+    return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const hidl_vec<KeyParameter>& set);
+::std::ostream& operator<<(::std::ostream& os, BlockMode value);
+::std::ostream& operator<<(::std::ostream& os, Digest value);
+::std::ostream& operator<<(::std::ostream& os, EcCurve value);
+::std::ostream& operator<<(::std::ostream& os, ErrorCode value);
+::std::ostream& operator<<(::std::ostream& os, PaddingMode value);
+::std::ostream& operator<<(::std::ostream& os, const KeyCharacteristics& value);
+::std::ostream& operator<<(::std::ostream& os, const KeyParameter& value);
+
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
new file mode 100644
index 0000000..92266b5
--- /dev/null
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -0,0 +1,3909 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keymaster_hidl_hal_test"
+#include <cutils/log.h>
+
+#include <iostream>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+#include <android/hardware/keymaster/3.0/types.h>
+
+#include <cutils/properties.h>
+
+#include <keymaster/keymaster_configuration.h>
+
+#include "authorization_set.h"
+#include "key_param_output.h"
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "attestation_record.h"
+#include "openssl_utils.h"
+
+using ::android::sp;
+
+using ::std::string;
+
+// This service_name will be passed to getService when retrieving the keymaster service to test.  To
+// change it from "default" specify the selected service name on the command line.  The first
+// non-gtest argument will be used as the service name.
+string service_name = "default";
+
+namespace android {
+namespace hardware {
+
+template <typename T> bool operator==(const hidl_vec<T>& a, const hidl_vec<T>& b) {
+    if (a.size() != b.size()) {
+        return false;
+    }
+    for (size_t i = 0; i < a.size(); ++i) {
+        if (a[i] != b[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+namespace keymaster {
+namespace V3_0 {
+
+bool operator==(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) {
+        return false;
+    }
+
+    switch (a.tag) {
+
+    /* Boolean tags */
+    case Tag::INVALID:
+    case Tag::CALLER_NONCE:
+    case Tag::INCLUDE_UNIQUE_ID:
+    case Tag::ECIES_SINGLE_HASH_MODE:
+    case Tag::BOOTLOADER_ONLY:
+    case Tag::NO_AUTH_REQUIRED:
+    case Tag::ALLOW_WHILE_ON_BODY:
+    case Tag::EXPORTABLE:
+    case Tag::ALL_APPLICATIONS:
+    case Tag::ROLLBACK_RESISTANT:
+    case Tag::RESET_SINCE_ID_ROTATION:
+        return true;
+
+    /* Integer tags */
+    case Tag::KEY_SIZE:
+    case Tag::MIN_MAC_LENGTH:
+    case Tag::MIN_SECONDS_BETWEEN_OPS:
+    case Tag::MAX_USES_PER_BOOT:
+    case Tag::ALL_USERS:
+    case Tag::USER_ID:
+    case Tag::OS_VERSION:
+    case Tag::OS_PATCHLEVEL:
+    case Tag::MAC_LENGTH:
+    case Tag::AUTH_TIMEOUT:
+        return a.f.integer == b.f.integer;
+
+    /* Long integer tags */
+    case Tag::RSA_PUBLIC_EXPONENT:
+    case Tag::USER_SECURE_ID:
+        return a.f.longInteger == b.f.longInteger;
+
+    /* Date-time tags */
+    case Tag::ACTIVE_DATETIME:
+    case Tag::ORIGINATION_EXPIRE_DATETIME:
+    case Tag::USAGE_EXPIRE_DATETIME:
+    case Tag::CREATION_DATETIME:
+        return a.f.dateTime == b.f.dateTime;
+
+    /* Bytes tags */
+    case Tag::APPLICATION_ID:
+    case Tag::APPLICATION_DATA:
+    case Tag::ROOT_OF_TRUST:
+    case Tag::UNIQUE_ID:
+    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::ASSOCIATED_DATA:
+    case Tag::NONCE:
+    case Tag::AUTH_TOKEN:
+        return a.blob == b.blob;
+
+    /* Enum tags */
+    case Tag::PURPOSE:
+        return a.f.purpose == b.f.purpose;
+    case Tag::ALGORITHM:
+        return a.f.algorithm == b.f.algorithm;
+    case Tag::BLOCK_MODE:
+        return a.f.blockMode == b.f.blockMode;
+    case Tag::DIGEST:
+        return a.f.digest == b.f.digest;
+    case Tag::PADDING:
+        return a.f.paddingMode == b.f.paddingMode;
+    case Tag::EC_CURVE:
+        return a.f.ecCurve == b.f.ecCurve;
+    case Tag::BLOB_USAGE_REQUIREMENTS:
+        return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
+    case Tag::USER_AUTH_TYPE:
+        return a.f.integer == b.f.integer;
+    case Tag::ORIGIN:
+        return a.f.origin == b.f.origin;
+
+    /* Unsupported tags */
+    case Tag::KDF:
+        return false;
+    }
+}
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+
+bool operator==(const KeyCharacteristics& a, const KeyCharacteristics& b) {
+    // This isn't very efficient. Oh, well.
+    AuthorizationSet a_sw(a.softwareEnforced);
+    AuthorizationSet b_sw(b.softwareEnforced);
+    AuthorizationSet a_tee(b.teeEnforced);
+    AuthorizationSet b_tee(b.teeEnforced);
+
+    a_sw.Sort();
+    b_sw.Sort();
+    a_tee.Sort();
+    b_tee.Sort();
+
+    return a_sw == b_sw && a_tee == b_sw;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
+    if (set.size() == 0)
+        os << "(Empty)" << ::std::endl;
+    else {
+        os << "\n";
+        for (size_t i = 0; i < set.size(); ++i)
+            os << set[i] << ::std::endl;
+    }
+    return os;
+}
+
+namespace test {
+namespace {
+
+template <TagType tag_type, Tag tag, typename ValueT>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) {
+    size_t count = std::count_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+        return param.tag == tag && accessTagValue(ttag, param) == expected_value;
+    });
+    return count == 1;
+}
+
+template <TagType tag_type, Tag tag>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag<tag_type, tag>) {
+    size_t count = std::count_if(set.begin(), set.end(),
+                                 [&](const KeyParameter& param) { return param.tag == tag; });
+    return count > 0;
+}
+
+constexpr char hex_value[256] = {0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 1,  2,  3,  4,  5,  6,  7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'a'..'f'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+string hex2str(string a) {
+    string b;
+    size_t num = a.size() / 2;
+    b.resize(num);
+    for (size_t i = 0; i < num; i++) {
+        b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+    }
+    return b;
+}
+
+string rsa_key = hex2str("30820275020100300d06092a864886f70d01010105000482025f3082025b"
+                         "02010002818100c6095409047d8634812d5a218176e45c41d60a75b13901"
+                         "f234226cffe776521c5a77b9e389417b71c0b6a44d13afe4e4a2805d46c9"
+                         "da2935adb1ff0c1f24ea06e62b20d776430a4d435157233c6f916783c30e"
+                         "310fcbd89b85c2d56771169785ac12bca244abda72bfb19fc44d27c81e1d"
+                         "92de284f4061edfd99280745ea6d2502030100010281801be0f04d9cae37"
+                         "18691f035338308e91564b55899ffb5084d2460e6630257e05b3ceab0297"
+                         "2dfabcd6ce5f6ee2589eb67911ed0fac16e43a444b8c861e544a05933657"
+                         "72f8baf6b22fc9e3c5f1024b063ac080a7b2234cf8aee8f6c47bbf4fd3ac"
+                         "e7240290bef16c0b3f7f3cdd64ce3ab5912cf6e32f39ab188358afcccd80"
+                         "81024100e4b49ef50f765d3b24dde01aceaaf130f2c76670a91a61ae08af"
+                         "497b4a82be6dee8fcdd5e3f7ba1cfb1f0c926b88f88c92bfab137fba2285"
+                         "227b83c342ff7c55024100ddabb5839c4c7f6bf3d4183231f005b31aa58a"
+                         "ffdda5c79e4cce217f6bc930dbe563d480706c24e9ebfcab28a6cdefd324"
+                         "b77e1bf7251b709092c24ff501fd91024023d4340eda3445d8cd26c14411"
+                         "da6fdca63c1ccd4b80a98ad52b78cc8ad8beb2842c1d280405bc2f6c1bea"
+                         "214a1d742ab996b35b63a82a5e470fa88dbf823cdd02401b7b57449ad30d"
+                         "1518249a5f56bb98294d4b6ac12ffc86940497a5a5837a6cf946262b4945"
+                         "26d328c11e1126380fde04c24f916dec250892db09a6d77cdba351024077"
+                         "62cd8f4d050da56bd591adb515d24d7ccd32cca0d05f866d583514bd7324"
+                         "d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3"
+                         "3492d6");
+
+string ec_key = hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+                        "6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032"
+                        "99986481f3a4d859a14403420004bf85d7720d07c25461683bc648b4778a"
+                        "9a14dd8a024e3bdd8c7ddd9ab2b528bbc7aa1b51f14ebbbb0bd0ce21bcc4"
+                        "1c6eb00083cf3376d11fd44949e0b2183bfe");
+
+struct RSA_Delete {
+    void operator()(RSA* p) { RSA_free(p); }
+};
+
+X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) {
+    const uint8_t* p = blob.data();
+    return d2i_X509(nullptr, &p, blob.size());
+}
+
+bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain) {
+    for (size_t i = 0; i < chain.size() - 1; ++i) {
+        auto& key_cert_blob = chain[i];
+        auto& signing_cert_blob = chain[i + 1];
+
+        X509_Ptr key_cert(parse_cert_blob(key_cert_blob));
+        X509_Ptr signing_cert(parse_cert_blob(signing_cert_blob));
+        EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
+        if (!key_cert.get() || !signing_cert.get()) return false;
+
+        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+        EXPECT_TRUE(!!signing_pubkey.get());
+        if (!signing_pubkey.get()) return false;
+
+        EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
+            << "Verification of certificate " << i << " failed";
+    }
+
+    return true;
+}
+
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    EXPECT_TRUE(!!oid.get());
+    if (!oid.get()) return nullptr;
+
+    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    EXPECT_NE(-1, location);
+    if (location == -1) return nullptr;
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+    EXPECT_TRUE(!!attest_rec_ext);
+    if (!attest_rec_ext) return nullptr;
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    EXPECT_TRUE(!!attest_rec);
+    return attest_rec;
+}
+
+bool tag_in_list(const KeyParameter& entry) {
+    // Attestations don't contain everything in key authorization lists, so we need to filter
+    // the key lists to produce the lists that we expect to match the attestations.
+    auto tag_list = {
+        Tag::USER_ID, Tag::INCLUDE_UNIQUE_ID, Tag::BLOB_USAGE_REQUIREMENTS,
+        Tag::EC_CURVE /* Tag::EC_CURVE will be included by KM2 implementations */,
+    };
+    return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end();
+}
+
+AuthorizationSet filter_tags(const AuthorizationSet& set) {
+    AuthorizationSet filtered;
+    std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
+    return filtered;
+}
+
+std::string make_string(const uint8_t* data, size_t length) {
+    return std::string(reinterpret_cast<const char*>(data), length);
+}
+
+template <size_t N> std::string make_string(const uint8_t (&a)[N]) {
+    return make_string(a, N);
+}
+
+class HidlBuf : public hidl_vec<uint8_t> {
+    typedef hidl_vec<uint8_t> super;
+
+  public:
+    HidlBuf() {}
+    HidlBuf(const super& other) : super(other) {}
+    HidlBuf(super&& other) : super(std::move(other)) {}
+    explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
+
+    HidlBuf& operator=(const super& other) {
+        super::operator=(other);
+        return *this;
+    }
+
+    HidlBuf& operator=(super&& other) {
+        super::operator=(std::move(other));
+        return *this;
+    }
+
+    HidlBuf& operator=(const string& other) {
+        resize(other.size());
+        for (size_t i = 0; i < other.size(); ++i) {
+            (*this)[i] = static_cast<uint8_t>(other[i]);
+        }
+        return *this;
+    }
+
+    string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
+};
+
+constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
+
+}  // namespace
+
+class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+  public:
+    void TearDown() override {
+        if (key_blob_.size()) {
+            EXPECT_EQ(ErrorCode::OK, DeleteKey());
+        }
+        AbortIfNeeded();
+    }
+
+    // SetUpTestCase runs only once per test case, not once per test.
+    static void SetUpTestCase() {
+        keymaster_ = IKeymasterDevice::getService(service_name);
+        ASSERT_NE(keymaster_, nullptr);
+
+        ASSERT_TRUE(
+            keymaster_
+                ->getHardwareFeatures([&](bool isSecure, bool supportsEc, bool supportsSymmetric,
+                                          bool supportsAttestation, bool supportsAllDigests,
+                                          const hidl_string& name, const hidl_string& author) {
+                    is_secure_ = isSecure;
+                    supports_ec_ = supportsEc;
+                    supports_symmetric_ = supportsSymmetric;
+                    supports_attestation_ = supportsAttestation;
+                    supports_all_digests_ = supportsAllDigests;
+                    name_ = name;
+                    author_ = author;
+                })
+                .isOk());
+
+        os_version_ = ::keymaster::GetOsVersion();
+        os_patch_level_ = ::keymaster::GetOsPatchlevel();
+    }
+
+    static void TearDownTestCase() { keymaster_.clear(); }
+
+    static IKeymasterDevice& keymaster() { return *keymaster_; }
+    static uint32_t os_version() { return os_version_; }
+    static uint32_t os_patch_level() { return os_patch_level_; }
+
+    AuthorizationSet UserAuths() { return AuthorizationSetBuilder().Authorization(TAG_USER_ID, 7); }
+
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
+                          KeyCharacteristics* key_characteristics) {
+        EXPECT_NE(key_blob, nullptr);
+        EXPECT_NE(key_characteristics, nullptr);
+        EXPECT_EQ(0U, key_blob->size());
+
+        ErrorCode error;
+        EXPECT_TRUE(keymaster_
+                        ->generateKey(key_desc.hidl_data(),
+                                      [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+                                          const KeyCharacteristics& hidl_key_characteristics) {
+                                          error = hidl_error;
+                                          *key_blob = hidl_key_blob;
+                                          *key_characteristics = hidl_key_characteristics;
+                                      })
+                        .isOk());
+        // On error, blob & characteristics should be empty.
+        if (error != ErrorCode::OK) {
+            EXPECT_EQ(0U, key_blob->size());
+            EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
+                           key_characteristics->teeEnforced.size()));
+        }
+        return error;
+    }
+
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc) {
+        return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+    }
+
+    ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                        const string& key_material, HidlBuf* key_blob,
+                        KeyCharacteristics* key_characteristics) {
+        ErrorCode error;
+        EXPECT_TRUE(keymaster_
+                        ->importKey(key_desc.hidl_data(), format, HidlBuf(key_material),
+                                    [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+                                        const KeyCharacteristics& hidl_key_characteristics) {
+                                        error = hidl_error;
+                                        *key_blob = hidl_key_blob;
+                                        *key_characteristics = hidl_key_characteristics;
+                                    })
+                        .isOk());
+        // On error, blob & characteristics should be empty.
+        if (error != ErrorCode::OK) {
+            EXPECT_EQ(0U, key_blob->size());
+            EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
+                           key_characteristics->teeEnforced.size()));
+        }
+        return error;
+    }
+
+    ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                        const string& key_material) {
+        return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_);
+    }
+
+    ErrorCode ExportKey(KeyFormat format, const HidlBuf& key_blob, const HidlBuf& client_id,
+                        const HidlBuf& app_data, HidlBuf* key_material) {
+        ErrorCode error;
+        EXPECT_TRUE(
+            keymaster_
+                ->exportKey(format, key_blob, client_id, app_data,
+                            [&](ErrorCode hidl_error_code, const HidlBuf& hidl_key_material) {
+                                error = hidl_error_code;
+                                *key_material = hidl_key_material;
+                            })
+                .isOk());
+        // On error, blob should be empty.
+        if (error != ErrorCode::OK) {
+            EXPECT_EQ(0U, key_material->size());
+        }
+        return error;
+    }
+
+    ErrorCode ExportKey(KeyFormat format, HidlBuf* key_material) {
+        HidlBuf client_id, app_data;
+        return ExportKey(format, key_blob_, client_id, app_data, key_material);
+    }
+
+    ErrorCode DeleteKey(HidlBuf* key_blob) {
+        ErrorCode error = keymaster_->deleteKey(*key_blob);
+        *key_blob = HidlBuf();
+        return error;
+    }
+
+    ErrorCode DeleteKey() { return DeleteKey(&key_blob_); }
+
+    ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
+                                 const HidlBuf& app_data, KeyCharacteristics* key_characteristics) {
+        ErrorCode error;
+        keymaster_->getKeyCharacteristics(
+            key_blob, client_id, app_data,
+            [&](ErrorCode hidl_error, const KeyCharacteristics& hidl_key_characteristics) {
+                error = hidl_error, *key_characteristics = hidl_key_characteristics;
+            });
+        return error;
+    }
+
+    ErrorCode GetCharacteristics(const HidlBuf& key_blob, KeyCharacteristics* key_characteristics) {
+        HidlBuf client_id, app_data;
+        return GetCharacteristics(key_blob, client_id, app_data, key_characteristics);
+    }
+
+    ErrorCode Begin(KeyPurpose purpose, const HidlBuf& key_blob, const AuthorizationSet& in_params,
+                    AuthorizationSet* out_params, OperationHandle* op_handle) {
+        SCOPED_TRACE("Begin");
+        ErrorCode error;
+        OperationHandle saved_handle = *op_handle;
+        EXPECT_TRUE(
+            keymaster_
+                ->begin(purpose, key_blob, in_params.hidl_data(),
+                        [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
+                            uint64_t hidl_op_handle) {
+                            error = hidl_error;
+                            *out_params = hidl_out_params;
+                            *op_handle = hidl_op_handle;
+                        })
+                .isOk());
+        if (error != ErrorCode::OK) {
+            // Some implementations may modify *op_handle on error.
+            *op_handle = saved_handle;
+        }
+        return error;
+    }
+
+    ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+                    AuthorizationSet* out_params) {
+        SCOPED_TRACE("Begin");
+        EXPECT_EQ(kOpHandleSentinel, op_handle_);
+        return Begin(purpose, key_blob_, in_params, out_params, &op_handle_);
+    }
+
+    ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params) {
+        SCOPED_TRACE("Begin");
+        AuthorizationSet out_params;
+        ErrorCode error = Begin(purpose, in_params, &out_params);
+        EXPECT_TRUE(out_params.empty());
+        return error;
+    }
+
+    ErrorCode Update(OperationHandle op_handle, const AuthorizationSet& in_params,
+                     const string& input, AuthorizationSet* out_params, string* output,
+                     size_t* input_consumed) {
+        SCOPED_TRACE("Update");
+        ErrorCode error;
+        EXPECT_TRUE(keymaster_
+                        ->update(op_handle, in_params.hidl_data(), HidlBuf(input),
+                                 [&](ErrorCode hidl_error, uint32_t hidl_input_consumed,
+                                     const hidl_vec<KeyParameter>& hidl_out_params,
+                                     const HidlBuf& hidl_output) {
+                                     error = hidl_error;
+                                     out_params->push_back(AuthorizationSet(hidl_out_params));
+                                     output->append(hidl_output.to_string());
+                                     *input_consumed = hidl_input_consumed;
+                                 })
+                        .isOk());
+        return error;
+    }
+
+    ErrorCode Update(const string& input, string* out, size_t* input_consumed) {
+        SCOPED_TRACE("Update");
+        AuthorizationSet out_params;
+        ErrorCode error = Update(op_handle_, AuthorizationSet() /* in_params */, input, &out_params,
+                                 out, input_consumed);
+        EXPECT_TRUE(out_params.empty());
+        return error;
+    }
+
+    ErrorCode Finish(OperationHandle op_handle, const AuthorizationSet& in_params,
+                     const string& input, const string& signature, AuthorizationSet* out_params,
+                     string* output) {
+        SCOPED_TRACE("Finish");
+        ErrorCode error;
+        EXPECT_TRUE(
+            keymaster_
+                ->finish(op_handle, in_params.hidl_data(), HidlBuf(input), HidlBuf(signature),
+                         [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
+                             const HidlBuf& hidl_output) {
+                             error = hidl_error;
+                             *out_params = hidl_out_params;
+                             output->append(hidl_output.to_string());
+                         })
+                .isOk());
+        op_handle_ = kOpHandleSentinel;  // So dtor doesn't Abort().
+        return error;
+    }
+
+    ErrorCode Finish(const string& message, string* output) {
+        SCOPED_TRACE("Finish");
+        AuthorizationSet out_params;
+        string finish_output;
+        ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message,
+                                 "" /* signature */, &out_params, output);
+        if (error != ErrorCode::OK) {
+            return error;
+        }
+        EXPECT_EQ(0U, out_params.size());
+        return error;
+    }
+
+    ErrorCode Finish(const string& message, const string& signature, string* output) {
+        SCOPED_TRACE("Finish");
+        AuthorizationSet out_params;
+        ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message, signature,
+                                 &out_params, output);
+        op_handle_ = kOpHandleSentinel;  // So dtor doesn't Abort().
+        if (error != ErrorCode::OK) {
+            return error;
+        }
+        EXPECT_EQ(0U, out_params.size());
+        return error;
+    }
+
+    ErrorCode Abort(OperationHandle op_handle) {
+        SCOPED_TRACE("Abort");
+        auto retval = keymaster_->abort(op_handle);
+        EXPECT_TRUE(retval.isOk());
+        return retval;
+    }
+
+    void AbortIfNeeded() {
+        SCOPED_TRACE("AbortIfNeeded");
+        if (op_handle_ != kOpHandleSentinel) {
+            EXPECT_EQ(ErrorCode::OK, Abort(op_handle_));
+            op_handle_ = kOpHandleSentinel;
+        }
+    }
+
+    ErrorCode AttestKey(const HidlBuf& key_blob, const AuthorizationSet& attest_params,
+                        hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
+        SCOPED_TRACE("AttestKey");
+        ErrorCode error;
+        keymaster_->attestKey(
+            key_blob, attest_params.hidl_data(),
+            [&](ErrorCode hidl_error, const hidl_vec<hidl_vec<uint8_t>>& hidl_cert_chain) {
+                error = hidl_error;
+                *cert_chain = hidl_cert_chain;
+            });
+        return error;
+    }
+
+    ErrorCode AttestKey(const AuthorizationSet& attest_params,
+                        hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
+        SCOPED_TRACE("AttestKey");
+        return AttestKey(key_blob_, attest_params, cert_chain);
+    }
+
+    string ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const string& message,
+                          const AuthorizationSet& in_params, AuthorizationSet* out_params) {
+        SCOPED_TRACE("ProcessMessage");
+        AuthorizationSet begin_out_params;
+        EXPECT_EQ(ErrorCode::OK,
+                  Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_));
+
+        string unused;
+        AuthorizationSet finish_params;
+        AuthorizationSet finish_out_params;
+        string output;
+        EXPECT_EQ(ErrorCode::OK,
+                  Finish(op_handle_, finish_params, message, unused, &finish_out_params, &output));
+        op_handle_ = kOpHandleSentinel;
+
+        out_params->push_back(begin_out_params);
+        out_params->push_back(finish_out_params);
+        return output;
+    }
+
+    string SignMessage(const HidlBuf& key_blob, const string& message,
+                       const AuthorizationSet& params) {
+        SCOPED_TRACE("SignMessage");
+        AuthorizationSet out_params;
+        string signature = ProcessMessage(key_blob, KeyPurpose::SIGN, message, params, &out_params);
+        EXPECT_TRUE(out_params.empty());
+        return signature;
+    }
+
+    string SignMessage(const string& message, const AuthorizationSet& params) {
+        SCOPED_TRACE("SignMessage");
+        return SignMessage(key_blob_, message, params);
+    }
+
+    string MacMessage(const string& message, Digest digest, size_t mac_length) {
+        SCOPED_TRACE("MacMessage");
+        return SignMessage(
+            key_blob_, message,
+            AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
+    }
+
+    void CheckHmacTestVector(const string& key, const string& message, Digest digest,
+                             const string& expected_mac) {
+        SCOPED_TRACE("CheckHmacTestVector");
+        ASSERT_EQ(ErrorCode::OK,
+                  ImportKey(AuthorizationSetBuilder()
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .HmacKey(key.size() * 8)
+                                .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
+                                .Digest(digest),
+                            KeyFormat::RAW, key));
+        string signature = MacMessage(message, digest, expected_mac.size() * 8);
+        EXPECT_EQ(expected_mac, signature) << "Test vector didn't match for digest " << (int)digest;
+        DeleteKey();
+    }
+
+    void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message,
+                               const string& expected_ciphertext) {
+        SCOPED_TRACE("CheckAesCtrTestVector");
+        ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .AesEncryptionKey(key.size() * 8)
+                                               .BlockMode(BlockMode::CTR)
+                                               .Authorization(TAG_CALLER_NONCE)
+                                               .Padding(PaddingMode::NONE),
+                                           KeyFormat::RAW, key));
+
+        auto params = AuthorizationSetBuilder()
+                          .Authorization(TAG_NONCE, nonce.data(), nonce.size())
+                          .BlockMode(BlockMode::CTR)
+                          .Padding(PaddingMode::NONE);
+        AuthorizationSet out_params;
+        string ciphertext = EncryptMessage(key_blob_, message, params, &out_params);
+        EXPECT_EQ(expected_ciphertext, ciphertext);
+    }
+
+    void VerifyMessage(const HidlBuf& key_blob, const string& message, const string& signature,
+                       const AuthorizationSet& params) {
+        SCOPED_TRACE("VerifyMessage");
+        AuthorizationSet begin_out_params;
+        ASSERT_EQ(ErrorCode::OK,
+                  Begin(KeyPurpose::VERIFY, key_blob, params, &begin_out_params, &op_handle_));
+
+        string unused;
+        AuthorizationSet finish_params;
+        AuthorizationSet finish_out_params;
+        string output;
+        EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, signature,
+                                        &finish_out_params, &output));
+        op_handle_ = kOpHandleSentinel;
+        EXPECT_TRUE(output.empty());
+    }
+
+    void VerifyMessage(const string& message, const string& signature,
+                       const AuthorizationSet& params) {
+        SCOPED_TRACE("VerifyMessage");
+        VerifyMessage(key_blob_, message, signature, params);
+    }
+
+    string EncryptMessage(const HidlBuf& key_blob, const string& message,
+                          const AuthorizationSet& in_params, AuthorizationSet* out_params) {
+        SCOPED_TRACE("EncryptMessage");
+        return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params);
+    }
+
+    string EncryptMessage(const string& message, const AuthorizationSet& params,
+                          AuthorizationSet* out_params) {
+        SCOPED_TRACE("EncryptMessage");
+        return EncryptMessage(key_blob_, message, params, out_params);
+    }
+
+    string EncryptMessage(const string& message, const AuthorizationSet& params) {
+        SCOPED_TRACE("EncryptMessage");
+        AuthorizationSet out_params;
+        string ciphertext = EncryptMessage(message, params, &out_params);
+        EXPECT_TRUE(out_params.empty())
+            << "Output params should be empty. Contained: " << out_params;
+        return ciphertext;
+    }
+
+    string DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
+                          const AuthorizationSet& params) {
+        SCOPED_TRACE("DecryptMessage");
+        AuthorizationSet out_params;
+        string plaintext =
+            ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params);
+        EXPECT_TRUE(out_params.empty());
+        return plaintext;
+    }
+
+    string DecryptMessage(const string& ciphertext, const AuthorizationSet& params) {
+        SCOPED_TRACE("DecryptMessage");
+        return DecryptMessage(key_blob_, ciphertext, params);
+    }
+
+    template <TagType tag_type, Tag tag, typename ValueT>
+    void CheckKm0CryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
+        SCOPED_TRACE("CheckKm0CryptoParam");
+        if (is_secure_) {
+            EXPECT_TRUE(contains(key_characteristics_.teeEnforced, ttag, expected));
+            EXPECT_FALSE(contains(key_characteristics_.softwareEnforced, ttag));
+        } else {
+            EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, ttag, expected));
+            EXPECT_FALSE(contains(key_characteristics_.teeEnforced, ttag));
+        }
+    }
+
+    template <TagType tag_type, Tag tag, typename ValueT>
+    void CheckKm1CryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
+        SCOPED_TRACE("CheckKm1CryptoParam");
+        if (is_secure_ && supports_symmetric_) {
+            EXPECT_TRUE(contains(key_characteristics_.teeEnforced, ttag, expected));
+            EXPECT_FALSE(contains(key_characteristics_.softwareEnforced, ttag));
+        } else {
+            EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, ttag, expected));
+            EXPECT_FALSE(contains(key_characteristics_.teeEnforced, ttag));
+        }
+    }
+
+    template <TagType tag_type, Tag tag, typename ValueT>
+    void CheckKm2CryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
+        SCOPED_TRACE("CheckKm2CryptoParam");
+        if (supports_attestation_) {
+            EXPECT_TRUE(contains(key_characteristics_.teeEnforced, ttag, expected));
+            EXPECT_FALSE(contains(key_characteristics_.softwareEnforced, ttag));
+        } else if (!supports_symmetric_ /* KM version < 1 or SW */) {
+            EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, ttag, expected));
+            EXPECT_FALSE(contains(key_characteristics_.teeEnforced, ttag));
+        }
+    }
+
+    void CheckOrigin() {
+        SCOPED_TRACE("CheckOrigin");
+        if (is_secure_ && supports_symmetric_) {
+            EXPECT_TRUE(
+                contains(key_characteristics_.teeEnforced, TAG_ORIGIN, KeyOrigin::IMPORTED));
+        } else if (is_secure_) {
+            EXPECT_TRUE(contains(key_characteristics_.teeEnforced, TAG_ORIGIN, KeyOrigin::UNKNOWN));
+        } else {
+            EXPECT_TRUE(
+                contains(key_characteristics_.softwareEnforced, TAG_ORIGIN, KeyOrigin::IMPORTED));
+        }
+    }
+
+    static bool IsSecure() { return is_secure_; }
+    static bool SupportsEc() { return supports_ec_; }
+    static bool SupportsSymmetric() { return supports_symmetric_; }
+    static bool SupportsAllDigests() { return supports_all_digests_; }
+    static bool SupportsAttestation() { return supports_attestation_; }
+
+    static bool Km2Profile() {
+        return SupportsAttestation() && SupportsAllDigests() && SupportsSymmetric() &&
+               SupportsEc() && IsSecure();
+    }
+
+    static bool Km1Profile() {
+        return !SupportsAttestation() && SupportsSymmetric() && SupportsEc() && IsSecure();
+    }
+
+    static bool Km0Profile() {
+        return !SupportsAttestation() && !SupportsAllDigests() && !SupportsSymmetric() &&
+               IsSecure();
+    }
+
+    static bool SwOnlyProfile() {
+        return !SupportsAttestation() && !SupportsAllDigests() && !SupportsSymmetric() &&
+               !SupportsEc() && !IsSecure();
+    }
+
+    HidlBuf key_blob_;
+    KeyCharacteristics key_characteristics_;
+    OperationHandle op_handle_ = kOpHandleSentinel;
+
+  private:
+    static sp<IKeymasterDevice> keymaster_;
+    static uint32_t os_version_;
+    static uint32_t os_patch_level_;
+
+    static bool is_secure_;
+    static bool supports_ec_;
+    static bool supports_symmetric_;
+    static bool supports_attestation_;
+    static bool supports_all_digests_;
+    static hidl_string name_;
+    static hidl_string author_;
+};
+
+uint32_t expected_keymaster_version() {
+    if (!KeymasterHidlTest::IsSecure()) return 2;  // SW is KM2
+
+    uint32_t keymaster_version = 0;
+    if (KeymasterHidlTest::SupportsSymmetric()) keymaster_version = 1;
+    if (KeymasterHidlTest::SupportsAttestation()) keymaster_version = 2;
+    return keymaster_version;
+}
+
+bool verify_attestation_record(const string& challenge, AuthorizationSet expected_sw_enforced,
+                               AuthorizationSet expected_tee_enforced,
+                               const hidl_vec<uint8_t>& attestation_cert) {
+
+    X509_Ptr cert(parse_cert_blob(attestation_cert));
+    EXPECT_TRUE(!!cert.get());
+    if (!cert.get()) return false;
+
+    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+    EXPECT_TRUE(!!attest_rec);
+    if (!attest_rec) return false;
+
+    AuthorizationSet att_sw_enforced;
+    AuthorizationSet att_tee_enforced;
+    uint32_t att_attestation_version;
+    uint32_t att_keymaster_version;
+    SecurityLevel att_attestation_security_level;
+    SecurityLevel att_keymaster_security_level;
+    HidlBuf att_challenge;
+    HidlBuf att_unique_id;
+    EXPECT_EQ(ErrorCode::OK,
+              parse_attestation_record(attest_rec->data,                 //
+                                       attest_rec->length,               //
+                                       &att_attestation_version,         //
+                                       &att_attestation_security_level,  //
+                                       &att_keymaster_version,           //
+                                       &att_keymaster_security_level,    //
+                                       &att_challenge,                   //
+                                       &att_sw_enforced,                 //
+                                       &att_tee_enforced,                //
+                                       &att_unique_id));
+
+    EXPECT_EQ(1U, att_attestation_version);
+    EXPECT_EQ(expected_keymaster_version(), att_keymaster_version);
+    EXPECT_EQ(KeymasterHidlTest::IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT
+                                            : SecurityLevel::SOFTWARE,
+              att_keymaster_security_level);
+    EXPECT_EQ(KeymasterHidlTest::SupportsAttestation() ? SecurityLevel::TRUSTED_ENVIRONMENT
+                                                       : SecurityLevel::SOFTWARE,
+              att_attestation_security_level);
+
+    EXPECT_EQ(challenge.length(), att_challenge.size());
+    EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
+
+    att_sw_enforced.Sort();
+    expected_sw_enforced.Sort();
+    EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(att_sw_enforced));
+
+    att_tee_enforced.Sort();
+    expected_tee_enforced.Sort();
+    EXPECT_EQ(filter_tags(expected_tee_enforced), filter_tags(att_tee_enforced));
+
+    return true;
+}
+
+sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
+uint32_t KeymasterHidlTest::os_version_;
+uint32_t KeymasterHidlTest::os_patch_level_;
+bool KeymasterHidlTest::is_secure_;
+bool KeymasterHidlTest::supports_ec_;
+bool KeymasterHidlTest::supports_symmetric_;
+bool KeymasterHidlTest::supports_all_digests_;
+bool KeymasterHidlTest::supports_attestation_;
+hidl_string KeymasterHidlTest::name_;
+hidl_string KeymasterHidlTest::author_;
+
+typedef KeymasterHidlTest KeymasterVersionTest;
+
+/*
+ * KeymasterVersionTest.SensibleFeatures:
+ *
+ * Queries keymaster to find the set of features it supports. Fails if the combination doesn't
+ * correspond to any well-defined keymaster version.
+ */
+TEST_F(KeymasterVersionTest, SensibleFeatures) {
+    EXPECT_TRUE(Km2Profile() || Km1Profile() || Km0Profile() || SwOnlyProfile())
+        << "Keymaster feature set doesn't fit any reasonable profile.  Reported features:"
+        << "SupportsAttestation [" << SupportsAttestation() << "], "
+        << "SupportsSymmetric [" << SupportsSymmetric() << "], "
+        << "SupportsAllDigests [" << SupportsAllDigests() << "], "
+        << "SupportsEc [" << SupportsEc() << "], "
+        << "IsSecure [" << IsSecure() << "]";
+}
+
+class NewKeyGenerationTest : public KeymasterHidlTest {
+  protected:
+    void CheckBaseParams(const KeyCharacteristics& keyCharacteristics) {
+        // TODO(swillden): Distinguish which params should be in which auth list.
+
+        AuthorizationSet auths(keyCharacteristics.teeEnforced);
+        auths.push_back(AuthorizationSet(keyCharacteristics.softwareEnforced));
+
+        EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+
+        EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
+        EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY));
+        EXPECT_TRUE(auths.Contains(TAG_USER_ID, 7))
+            << "User ID should be 7, was " << auths.GetTagValue(TAG_USER_ID);
+
+        // Verify that App ID, App data and ROT are NOT included.
+        EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
+        EXPECT_FALSE(auths.Contains(TAG_APPLICATION_ID));
+        EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA));
+
+        // Check that some unexpected tags/values are NOT present.
+        EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT));
+        EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
+        EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301));
+
+        // Now check that unspecified, defaulted tags are correct.
+        EXPECT_TRUE(auths.Contains(TAG_CREATION_DATETIME));
+
+        if (SupportsAttestation()) {
+            EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version()))
+                << "OS version is " << os_version() << " key reported "
+                << auths.GetTagValue(TAG_OS_VERSION);
+            EXPECT_TRUE(auths.Contains(TAG_OS_PATCHLEVEL, os_patch_level()))
+                << "OS patch level is " << os_patch_level() << " key reported "
+                << auths.GetTagValue(TAG_OS_PATCHLEVEL);
+        }
+    }
+};
+
+/*
+ * NewKeyGenerationTest.Rsa
+ *
+ * Verifies that keymaster can generate all required RSA key sizes, and that the resulting keys have
+ * correct characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Rsa) {
+    for (auto key_size : {1024, 2048, 3072, 4096}) {
+        HidlBuf key_blob;
+        KeyCharacteristics key_characteristics;
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(key_size, 3)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorizations(UserAuths()),
+                                             &key_blob, &key_characteristics));
+
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+
+        AuthorizationSet crypto_params;
+        if (IsSecure()) {
+            crypto_params = key_characteristics.teeEnforced;
+        } else {
+            crypto_params = key_characteristics.softwareEnforced;
+        }
+
+        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size));
+        EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 3));
+
+        EXPECT_EQ(ErrorCode::OK, DeleteKey(&key_blob));
+    }
+}
+
+/*
+ * NewKeyGenerationTest.RsaNoDefaultSize
+ *
+ * Verifies that failing to specify a key size for RSA key generation returns UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, RsaNoDefaultSize) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_ALGORITHM, Algorithm::RSA)
+                              .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)
+                              .SigningKey()));
+}
+
+/*
+ * NewKeyGenerationTest.Ecdsa
+ *
+ * Verifies that keymaster can generate all required EC key sizes, and that the resulting keys have
+ * correct characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Ecdsa) {
+    for (auto key_size : {224, 256, 384, 521}) {
+        HidlBuf key_blob;
+        KeyCharacteristics key_characteristics;
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .EcdsaSigningKey(key_size)
+                                                 .Digest(Digest::NONE)
+                                                 .Authorizations(UserAuths()),
+                                             &key_blob, &key_characteristics));
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+
+        AuthorizationSet crypto_params;
+        if (IsSecure()) {
+            crypto_params = key_characteristics.teeEnforced;
+        } else {
+            crypto_params = key_characteristics.softwareEnforced;
+        }
+
+        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size));
+
+        EXPECT_EQ(ErrorCode::OK, DeleteKey(&key_blob));
+    }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaDefaultSize
+ *
+ * Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaDefaultSize) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                              .SigningKey()
+                              .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaInvalidSize
+ *
+ * Verifies that failing to specify an invalid key size for EC key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaInvalidSize) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaMismatchKeySize
+ *
+ * Verifies that specifying mismatched key size and curve for EC key generation returns
+ * INVALID_ARGUMENT.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+    ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
+              GenerateKey(AuthorizationSetBuilder()
+                              .EcdsaSigningKey(224)
+                              .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+                              .Digest(Digest::NONE)))
+        << "(Possibly b/36233343)";
+}
+
+TEST_F(NewKeyGenerationTest, EcdsaAllValidSizes) {
+    size_t valid_sizes[] = {224, 256, 384, 521};
+    for (size_t size : valid_sizes) {
+        EXPECT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(Digest::NONE)))
+            << "Failed to generate size: " << size;
+        DeleteKey();
+    }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAllValidCurves
+ *
+ * Verifies that keymaster supports all required EC curves.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaAllValidCurves) {
+    EcCurve curves[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
+    for (auto curve : curves) {
+        EXPECT_EQ(
+            ErrorCode::OK,
+            GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(curve).Digest(Digest::SHA_2_512)))
+            << "Failed to generate key on curve: " << curve;
+        DeleteKey();
+    }
+}
+
+/*
+ * NewKeyGenerationTest.Hmac
+ *
+ * Verifies that keymaster supports all required digests, and that the resulting keys have correct
+ * characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Hmac) {
+    for (auto digest : {Digest::MD5, Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256,
+                        Digest::SHA_2_384, Digest::SHA_2_512}) {
+        HidlBuf key_blob;
+        KeyCharacteristics key_characteristics;
+        constexpr size_t key_size = 128;
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .HmacKey(key_size)
+                                                 .Digest(digest)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                                 .Authorizations(UserAuths()),
+                                             &key_blob, &key_characteristics));
+
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+
+        AuthorizationSet teeEnforced = key_characteristics.teeEnforced;
+        AuthorizationSet softwareEnforced = key_characteristics.softwareEnforced;
+        if (SupportsAttestation() || SupportsAllDigests()) {
+            // Either KM2, which must support all, or KM1 that claims full support
+            EXPECT_TRUE(teeEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+            EXPECT_TRUE(teeEnforced.Contains(TAG_KEY_SIZE, key_size));
+        } else if (SupportsSymmetric()) {
+            if (digest == Digest::SHA1 || digest == Digest::SHA_2_256) {
+                // KM1 must support SHA1 and SHA256 in hardware
+                EXPECT_TRUE(teeEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+                EXPECT_TRUE(teeEnforced.Contains(TAG_KEY_SIZE, key_size));
+            } else {
+                // Othere digests may or may not be supported
+                EXPECT_TRUE(teeEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC) ||
+                            softwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+                EXPECT_TRUE(teeEnforced.Contains(TAG_KEY_SIZE, key_size) ||
+                            softwareEnforced.Contains(TAG_KEY_SIZE, key_size));
+            }
+        } else {
+            // KM0 and SW KM do all digests in SW.
+            EXPECT_TRUE(softwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+            EXPECT_TRUE(softwareEnforced.Contains(TAG_KEY_SIZE, key_size));
+        }
+
+        EXPECT_EQ(ErrorCode::OK, DeleteKey(&key_blob));
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckKeySizes
+ *
+ * Verifies that keymaster supports all key sizes, and rejects all invalid key sizes.
+ */
+TEST_F(NewKeyGenerationTest, HmacCheckKeySizes) {
+    for (size_t key_size = 0; key_size <= 512; ++key_size) {
+        if (key_size < 64 || key_size % 8 != 0) {
+            // To keep this test from being very slow, we only test a random fraction of non-byte
+            // key sizes.  We test only ~10% of such cases. Since there are 392 of them, we expect
+            // to run ~40 of them in each run.
+            if (key_size % 8 == 0 || random() % 10 == 0) {
+                EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+                          GenerateKey(AuthorizationSetBuilder()
+                                          .HmacKey(key_size)
+                                          .Digest(Digest::SHA_2_256)
+                                          .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+                    << "HMAC key size " << key_size << " invalid (Possibly b/33462346)";
+            }
+        } else {
+            EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                     .HmacKey(key_size)
+                                                     .Digest(Digest::SHA_2_256)
+                                                     .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+            DeleteKey();
+        }
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckMinMacLengths
+ *
+ * Verifies that keymaster supports all required MAC lengths and rejects all invalid lengths.  This
+ * test is probabilistic in order to keep the runtime down, but any failure prints out the specific
+ * MAC length that failed, so reproducing a failed run will be easy.
+ */
+TEST_F(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+    for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
+        if (min_mac_length < 64 || min_mac_length % 8 != 0) {
+            // To keep this test from being very long, we only test a random fraction of non-byte
+            // lengths.  We test only ~10% of such cases. Since there are 172 of them, we expect to
+            // run ~17 of them in each run.
+            if (min_mac_length % 8 == 0 || random() % 10 == 0) {
+                EXPECT_EQ(ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH,
+                          GenerateKey(AuthorizationSetBuilder()
+                                          .HmacKey(128)
+                                          .Digest(Digest::SHA_2_256)
+                                          .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+                    << "HMAC min mac length " << min_mac_length << " invalid.";
+            }
+        } else {
+            EXPECT_EQ(ErrorCode::OK,
+                      GenerateKey(AuthorizationSetBuilder()
+                                      .HmacKey(128)
+                                      .Digest(Digest::SHA_2_256)
+                                      .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)));
+            DeleteKey();
+        }
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacMultipleDigests
+ *
+ * Verifies that keymaster rejects HMAC key generation with multiple specified digest algorithms.
+ */
+TEST_F(NewKeyGenerationTest, HmacMultipleDigests) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(Digest::SHA1)
+                              .Digest(Digest::SHA_2_256)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+/*
+ * NewKeyGenerationTest.HmacDigestNone
+ *
+ * Verifies that keymaster rejects HMAC key generation with no digest or Digest::NONE
+ */
+TEST_F(NewKeyGenerationTest, HmacDigestNone) {
+    ASSERT_EQ(
+        ErrorCode::UNSUPPORTED_DIGEST,
+        GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(Digest::NONE)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+typedef KeymasterHidlTest GetKeyCharacteristicsTest;
+
+/*
+ * GetKeyCharacteristicsTest.HmacDigestNone
+ *
+ * Verifies that getKeyCharacteristics functions, and that generated and retrieved key
+ * characteristics match.
+ */
+TEST_F(GetKeyCharacteristicsTest, SimpleRsa) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(256, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+
+    KeyCharacteristics retrieved_chars;
+    ASSERT_EQ(ErrorCode::OK, GetCharacteristics(key_blob_, &retrieved_chars));
+
+    AuthorizationSet gen_sw = key_characteristics_.softwareEnforced;
+    AuthorizationSet gen_tee = key_characteristics_.teeEnforced;
+    AuthorizationSet retrieved_sw = retrieved_chars.softwareEnforced;
+    AuthorizationSet retrieved_tee = retrieved_chars.teeEnforced;
+
+    EXPECT_EQ(gen_sw, retrieved_sw);
+    EXPECT_EQ(gen_tee, retrieved_tee);
+}
+
+typedef KeymasterHidlTest SigningOperationsTest;
+
+/*
+ * SigningOperationsTest.RsaSuccess
+ *
+ * Verifies that raw RSA signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+    string message = "12345678901234567890123456789012";
+    string signature = SignMessage(
+        message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha256Success
+ *
+ * Verifies that RSA-PSS signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPssSha256Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Padding(PaddingMode::RSA_PSS)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature = SignMessage(
+        message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS));
+}
+
+/*
+ * SigningOperationsTest.RsaPaddingNoneDoesNotAllowOther
+ *
+ * Verifies that keymaster rejects signature operations that specify a padding mode when the key
+ * supports only unpadded operations.
+ */
+TEST_F(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1Sha256Success
+ *
+ * Verifies that digested RSA-PKCS1 signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1Sha256Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(1024, 'a');
+    string signature = SignMessage(message, AuthorizationSetBuilder()
+                                                .Digest(Digest::SHA_2_256)
+                                                .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestSuccess
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(53, 'a');
+    string signature = SignMessage(
+        message,
+        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestTooLarge
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(129, 'a');
+
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string signature;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha512TooSmallKey
+ *
+ * Verifies that undigested RSA-PSS signature operations fail with the correct error code when
+ * used with a key that is too small for the message.
+ *
+ * A PSS-padded message is of length salt_size + digest_size + 16 (sizes in bits), and the keymaster
+ * specification requires that salt_size == digest_size, so the message will be digest_size * 2 +
+ * 16. Such a message can only be signed by a given key if the key is at least that size. This test
+ * uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large for a
+ * 1024-bit key.
+ */
+TEST_F(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::SHA_2_512)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PSS)));
+    EXPECT_EQ(
+        ErrorCode::INCOMPATIBLE_DIGEST,
+        Begin(KeyPurpose::SIGN,
+              AuthorizationSetBuilder().Digest(Digest::SHA_2_512).Padding(PaddingMode::RSA_PSS)))
+        << "(Possibly b/33346750)";
+}
+
+/*
+ * SigningOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_F(SigningOperationsTest, RsaNoPaddingTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    // One byte too long
+    string message(1024 / 8 + 1, 'a');
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+
+    // Very large message that should exceed the transfer buffer size of any reasonable TEE.
+    message = string(128 * 1024, 'a');
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+}
+
+/*
+ * SigningOperationsTest.RsaAbort
+ *
+ * Verifies that operations can be aborted correctly.  Uses an RSA signing operation for the test,
+ * but the behavior should be algorithm and purpose-independent.
+ */
+TEST_F(SigningOperationsTest, RsaAbort) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::NONE)));
+
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+    EXPECT_EQ(ErrorCode::OK, Abort(op_handle_));
+
+    // Another abort should fail
+    EXPECT_EQ(ErrorCode::INVALID_OPERATION_HANDLE, Abort(op_handle_));
+
+    // Set to sentinel, so TearDown() doesn't try to abort again.
+    op_handle_ = kOpHandleSentinel;
+}
+
+/*
+ * SigningOperationsTest.RsaUnsupportedPadding
+ *
+ * Verifies that RSA operations fail with the correct error (but key gen succeeds) when used with a
+ * padding mode inappropriate for RSA.
+ */
+TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Digest(Digest::SHA_2_256 /* supported digest */)
+                                             .Padding(PaddingMode::PKCS7)));
+    ASSERT_EQ(
+        ErrorCode::UNSUPPORTED_PADDING_MODE,
+        Begin(KeyPurpose::SIGN,
+              AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::PKCS7)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA PSS operations fail when no digest is used.  PSS requires a digest.
+ */
+TEST_F(SigningOperationsTest, RsaNoDigest) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::RSA_PSS)));
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PSS)));
+
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA operations fail when no padding mode is specified.  PaddingMode::NONE is
+ * supported in some cases (as validated in other tests), but a mode must be specified.
+ */
+TEST_F(SigningOperationsTest, RsaNoPadding) {
+    // Padding must be specified
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaKey(1024, 3)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .SigningKey()
+                                             .Digest(Digest::NONE)));
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PADDING_MODE,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaShortMessage
+ *
+ * Verifies that raw RSA signatures succeed with a message shorter than the key size.
+ */
+TEST_F(SigningOperationsTest, RsaTooShortMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+
+    // Barely shorter
+    string message(1024 / 8 - 1, 'a');
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+
+    // Much shorter
+    message = "a";
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaSignWithEncryptionKey
+ *
+ * Verifies that RSA encryption keys cannot be used to sign.
+ */
+TEST_F(SigningOperationsTest, RsaSignWithEncryptionKey) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaSignTooLargeMessage
+ *
+ * Verifies that attempting a raw signature of a message which is the same length as the key, but
+ * numerically larger than the public modulus, fails with the correct error.
+ */
+TEST_F(SigningOperationsTest, RsaSignTooLargeMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+
+    // Largest possible message will always be larger than the public modulus.
+    string message(1024 / 8, static_cast<char>(0xff));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                                         .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                         .Digest(Digest::NONE)
+                                                         .Padding(PaddingMode::NONE)));
+    string signature;
+    ASSERT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllSizesAndHashes
+ *
+ * Verifies that ECDSA operations succeed with all possible key sizes and hashes.
+ */
+TEST_F(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+    for (auto key_size : {224, 256, 384, 521}) {
+        for (auto digest : {
+                 Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+                 Digest::SHA_2_512,
+             }) {
+            ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                                              .EcdsaSigningKey(key_size)
+                                              .Digest(digest));
+            EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with size " << key_size
+                                            << " and digest " << digest;
+            if (error != ErrorCode::OK) continue;
+
+            string message(1024, 'a');
+            if (digest == Digest::NONE) message.resize(key_size / 8);
+            SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+            DeleteKey();
+        }
+    }
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllCurves
+ *
+ * Verifies that ECDSA operations succeed with all possible curves.
+ */
+TEST_F(SigningOperationsTest, EcdsaAllCurves) {
+    for (auto curve : {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}) {
+        ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(Digest::SHA_2_256));
+        EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+        if (error != ErrorCode::OK) continue;
+
+        string message(1024, 'a');
+        SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+        DeleteKey();
+    }
+}
+
+/*
+ * SigningOperationsTest.EcdsaNoDigestHugeData
+ *
+ * Verifies that ECDSA operations support very large messages, even without digesting.  This should
+ * work because ECDSA actually only signs the leftmost L_n bits of the message, however large it may
+ * be.  Not using digesting is a bad idea, but in some cases digesting is done by the framework.
+ */
+TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(224)
+                                             .Digest(Digest::NONE)));
+    string message(64 * 1024, 'a');
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE));
+}
+
+/*
+ * SigningOperationsTest.AesEcbSign
+ *
+ * Verifies that attempts to use AES keys to sign fail in the correct way.
+ */
+TEST_F(SigningOperationsTest, AesEcbSign) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .SigningKey()
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)))
+        << "(Possibly b/36252957)";
+
+    AuthorizationSet out_params;
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+              Begin(KeyPurpose::SIGN, AuthorizationSet() /* in_params */, &out_params))
+        << "(Possibly b/36233187)";
+
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+              Begin(KeyPurpose::VERIFY, AuthorizationSet() /* in_params */, &out_params))
+        << "(Possibly b/36233187)";
+}
+
+/*
+ * SigningOperationsTest.HmacAllDigests
+ *
+ * Verifies that HMAC works with all digests.
+ */
+TEST_F(SigningOperationsTest, HmacAllDigests) {
+    for (auto digest : {Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+                        Digest::SHA_2_512}) {
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .HmacKey(128)
+                                                 .Digest(digest)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 160)))
+            << "Failed to create HMAC key with digest " << digest;
+        string message = "12345678901234567890123456789012";
+        string signature = MacMessage(message, digest, 160);
+        EXPECT_EQ(160U / 8U, signature.size())
+            << "Failed to sign with HMAC key with digest " << digest;
+        DeleteKey();
+    }
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooLargeMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the digest
+ * size.
+ */
+TEST_F(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .HmacKey(128)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+    AuthorizationSet output_params;
+    EXPECT_EQ(
+        ErrorCode::UNSUPPORTED_MAC_LENGTH,
+        Begin(
+            KeyPurpose::SIGN, key_blob_,
+            AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 264),
+            &output_params, &op_handle_));
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooSmallMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
+ * specified minimum MAC length.
+ */
+TEST_F(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .HmacKey(128)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    AuthorizationSet output_params;
+    EXPECT_EQ(
+        ErrorCode::INVALID_MAC_LENGTH,
+        Begin(
+            KeyPurpose::SIGN, key_blob_,
+            AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 120),
+            &output_params, &op_handle_));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase3
+ *
+ * Validates against the test vectors from RFC 4231 test case 3.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase3) {
+    string key(20, 0xaa);
+    string message(50, 0xdd);
+    uint8_t sha_224_expected[] = {
+        0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a,
+        0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea,
+    };
+    uint8_t sha_256_expected[] = {
+        0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8,
+        0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8,
+        0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
+    };
+    uint8_t sha_384_expected[] = {
+        0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
+        0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+        0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
+        0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27,
+    };
+    uint8_t sha_512_expected[] = {
+        0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c,
+        0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8,
+        0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22,
+        0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37,
+        0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase5
+ *
+ * Validates against the test vectors from RFC 4231 test case 5.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase5) {
+    string key(20, 0x0c);
+    string message = "Test With Truncation";
+
+    uint8_t sha_224_expected[] = {
+        0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37,
+        0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8,
+    };
+    uint8_t sha_256_expected[] = {
+        0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
+        0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b,
+    };
+    uint8_t sha_384_expected[] = {
+        0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23,
+        0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97,
+    };
+    uint8_t sha_512_expected[] = {
+        0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53,
+        0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase6
+ *
+ * Validates against the test vectors from RFC 4231 test case 6.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase6) {
+    string key(131, 0xaa);
+    string message = "Test Using Larger Than Block-Size Key - Hash Key First";
+
+    uint8_t sha_224_expected[] = {
+        0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d,
+        0xbc, 0xe2, 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, 0x3f, 0xa6, 0x87, 0x0e,
+    };
+    uint8_t sha_256_expected[] = {
+        0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
+        0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
+        0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
+    };
+    uint8_t sha_384_expected[] = {
+        0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a,
+        0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+        0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab,
+        0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52,
+    };
+    uint8_t sha_512_expected[] = {
+        0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd,
+        0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b,
+        0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25,
+        0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73,
+        0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase7
+ *
+ * Validates against the test vectors from RFC 4231 test case 7.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase7) {
+    string key(131, 0xaa);
+    string message = "This is a test using a larger than block-size key and a larger than "
+                     "block-size data. The key needs to be hashed before being used by the HMAC "
+                     "algorithm.";
+
+    uint8_t sha_224_expected[] = {
+        0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3,
+        0x9d, 0xbd, 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, 0xf6, 0xf5, 0x65, 0xd1,
+    };
+    uint8_t sha_256_expected[] = {
+        0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f,
+        0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07,
+        0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
+    };
+    uint8_t sha_384_expected[] = {
+        0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25,
+        0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+        0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31,
+        0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e,
+    };
+    uint8_t sha_512_expected[] = {
+        0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e,
+        0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5,
+        0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82,
+        0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb,
+        0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+typedef KeymasterHidlTest VerificationOperationsTest;
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies that a simple RSA signature/verification sequence succeeds.
+ */
+TEST_F(VerificationOperationsTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature = SignMessage(
+        message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+    VerifyMessage(message, signature,
+                  AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies RSA signature/verification for all padding modes and digests.
+ */
+TEST_F(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+    Digest digest = Digest::SHA_2_256;
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                              .RsaSigningKey(2048, 3)
+                              .Digest(Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+                                      Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512)
+                              .Padding(PaddingMode::NONE)
+                              .Padding(PaddingMode::RSA_PSS)
+                              .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+
+    string message(128, 'a');
+    string corrupt_message(message);
+    ++corrupt_message[corrupt_message.size() / 2];
+
+    for (auto padding :
+         {PaddingMode::NONE, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN}) {
+
+        for (auto digest : {Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+                            Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512}) {
+            if (padding == PaddingMode::NONE && digest != Digest::NONE) {
+                // Digesting only makes sense with padding.
+                continue;
+            }
+
+            if (padding == PaddingMode::RSA_PSS && digest == Digest::NONE) {
+                // PSS requires digesting.
+                continue;
+            }
+
+            string signature =
+                SignMessage(message, AuthorizationSetBuilder().Digest(digest).Padding(padding));
+            VerifyMessage(message, signature,
+                          AuthorizationSetBuilder().Digest(digest).Padding(padding));
+
+            if (digest != Digest::NONE) {
+                // Verify with OpenSSL.
+                HidlBuf pubkey;
+                ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey));
+
+                const uint8_t* p = pubkey.data();
+                EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+                ASSERT_TRUE(pkey.get());
+
+                EVP_MD_CTX digest_ctx;
+                EVP_MD_CTX_init(&digest_ctx);
+                EVP_PKEY_CTX* pkey_ctx;
+                const EVP_MD* md = openssl_digest(digest);
+                ASSERT_NE(md, nullptr);
+                EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md, nullptr /* engine */,
+                                                  pkey.get()));
+
+                switch (padding) {
+                case PaddingMode::RSA_PSS:
+                    EXPECT_GT(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING), 0);
+                    EXPECT_GT(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, EVP_MD_size(md)), 0);
+                    break;
+                case PaddingMode::RSA_PKCS1_1_5_SIGN:
+                    // PKCS1 is the default; don't need to set anything.
+                    break;
+                default:
+                    FAIL();
+                    break;
+                }
+
+                EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
+                EXPECT_EQ(1, EVP_DigestVerifyFinal(
+                                 &digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+                                 signature.size()));
+                EVP_MD_CTX_cleanup(&digest_ctx);
+            }
+
+            // Corrupt signature shouldn't verify.
+            string corrupt_signature(signature);
+            ++corrupt_signature[corrupt_signature.size() / 2];
+
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY,
+                            AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+            string result;
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result));
+
+            // Corrupt message shouldn't verify
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY,
+                            AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result));
+        }
+    }
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies ECDSA signature/verification for all digests and curves.
+ */
+TEST_F(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+    auto digests = {
+        Digest::NONE,      Digest::SHA1,      Digest::SHA_2_224,
+        Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
+    };
+
+    string message = "1234567890";
+    string corrupt_message = "2234567890";
+    for (auto curve : {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}) {
+        ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(digests));
+        EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate key for EC curve " << curve;
+        if (error != ErrorCode::OK) {
+            continue;
+        }
+
+        for (auto digest : digests) {
+            string signature = SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+            VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(digest));
+
+            // Verify with OpenSSL
+            if (digest != Digest::NONE) {
+                HidlBuf pubkey;
+                ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey))
+                    << curve << ' ' << digest;
+
+                const uint8_t* p = pubkey.data();
+                EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+                ASSERT_TRUE(pkey.get());
+
+                EVP_MD_CTX digest_ctx;
+                EVP_MD_CTX_init(&digest_ctx);
+                EVP_PKEY_CTX* pkey_ctx;
+                const EVP_MD* md = openssl_digest(digest);
+
+                EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md, nullptr /* engine */,
+                                                  pkey.get()))
+                    << curve << ' ' << digest;
+
+                EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()))
+                    << curve << ' ' << digest;
+
+                EXPECT_EQ(1, EVP_DigestVerifyFinal(
+                                 &digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+                                 signature.size()))
+                    << curve << ' ' << digest;
+
+                EVP_MD_CTX_cleanup(&digest_ctx);
+            }
+
+            // Corrupt signature shouldn't verify.
+            string corrupt_signature(signature);
+            ++corrupt_signature[corrupt_signature.size() / 2];
+
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+                << curve << ' ' << digest;
+
+            string result;
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result))
+                << curve << ' ' << digest;
+
+            // Corrupt message shouldn't verify
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+                << curve << ' ' << digest;
+
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result))
+                << curve << ' ' << digest;
+        }
+
+        ASSERT_EQ(ErrorCode::OK, DeleteKey());
+    }
+}
+
+/*
+ * VerificationOperationsTest.HmacSigningKeyCannotVerify
+ *
+ * Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
+ */
+TEST_F(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+    string key_material = "HelloThisIsAKey";
+
+    HidlBuf signing_key, verification_key;
+    KeyCharacteristics signing_key_chars, verification_key_chars;
+    EXPECT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+                            .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                            .Digest(Digest::SHA1)
+                            .Authorization(TAG_MIN_MAC_LENGTH, 160),
+                        KeyFormat::RAW, key_material, &signing_key, &signing_key_chars));
+    EXPECT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+                            .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+                            .Digest(Digest::SHA1)
+                            .Authorization(TAG_MIN_MAC_LENGTH, 160),
+                        KeyFormat::RAW, key_material, &verification_key, &verification_key_chars));
+
+    string message = "This is a message.";
+    string signature = SignMessage(
+        signing_key, message,
+        AuthorizationSetBuilder().Digest(Digest::SHA1).Authorization(TAG_MAC_LENGTH, 160));
+
+    // Signing key should not work.
+    AuthorizationSet out_params;
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              Begin(KeyPurpose::VERIFY, signing_key, AuthorizationSetBuilder().Digest(Digest::SHA1),
+                    &out_params, &op_handle_));
+
+    // Verification key should work.
+    VerifyMessage(verification_key, message, signature,
+                  AuthorizationSetBuilder().Digest(Digest::SHA1));
+
+    EXPECT_EQ(ErrorCode::OK, DeleteKey(&signing_key));
+    EXPECT_EQ(ErrorCode::OK, DeleteKey(&verification_key));
+}
+
+typedef KeymasterHidlTest ExportKeyTest;
+
+/*
+ * ExportKeyTest.RsaUnsupportedKeyFormat
+ *
+ * Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
+ */
+TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(256, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+    HidlBuf export_data;
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::PKCS8, &export_data));
+}
+
+/*
+ * ExportKeyTest.RsaCorruptedKeyBlob
+ *
+ * Verifies that attempting to export RSA keys from corrupted key blobs fails.  This is essentially
+ * a poor-man's key blob fuzzer.
+ */
+// Disabled due to b/33385206
+TEST_F(ExportKeyTest, DISABLED_RsaCorruptedKeyBlob) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(256, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+    for (size_t i = 0; i < key_blob_.size(); ++i) {
+        HidlBuf corrupted(key_blob_);
+        ++corrupted[i];
+
+        HidlBuf export_data;
+        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                  ExportKey(KeyFormat::X509, corrupted, HidlBuf(), HidlBuf(), &export_data))
+            << "Blob corrupted at offset " << i << " erroneously accepted as valid";
+    }
+}
+
+/*
+ * ExportKeyTest.RsaCorruptedKeyBlob
+ *
+ * Verifies that attempting to export ECDSA keys from corrupted key blobs fails.  This is
+ * essentially a poor-man's key blob fuzzer.
+ */
+// Disabled due to b/33385206
+TEST_F(ExportKeyTest, DISABLED_EcCorruptedKeyBlob) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(EcCurve::P_256)
+                                             .Digest(Digest::NONE)));
+    for (size_t i = 0; i < key_blob_.size(); ++i) {
+        HidlBuf corrupted(key_blob_);
+        ++corrupted[i];
+
+        HidlBuf export_data;
+        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                  ExportKey(KeyFormat::X509, corrupted, HidlBuf(), HidlBuf(), &export_data))
+            << "Blob corrupted at offset " << i << " erroneously accepted as valid";
+    }
+}
+
+/*
+ * ExportKeyTest.AesKeyUnexportable
+ *
+ * Verifies that attempting to export AES keys fails in the expected way.
+ */
+TEST_F(ExportKeyTest, AesKeyUnexportable) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .EcbMode()
+                                             .Padding(PaddingMode::NONE)));
+
+    HidlBuf export_data;
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::X509, &export_data));
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::PKCS8, &export_data));
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::RAW, &export_data));
+}
+typedef KeymasterHidlTest ImportKeyTest;
+
+/*
+ * ImportKeyTest.RsaSuccess
+ *
+ * Verifies that importing and using an RSA key pair works correctly.
+ */
+TEST_F(ImportKeyTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .RsaSigningKey(1024, 65537)
+                                           .Digest(Digest::SHA_2_256)
+                                           .Padding(PaddingMode::RSA_PSS),
+                                       KeyFormat::PKCS8, rsa_key));
+
+    CheckKm0CryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+    CheckKm0CryptoParam(TAG_KEY_SIZE, 1024U);
+    CheckKm0CryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+    CheckKm1CryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckKm1CryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
+    CheckOrigin();
+
+    string message(1024 / 8, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.RsaKeySizeMismatch
+ *
+ * Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .RsaSigningKey(2048 /* Doesn't match key */, 65537)
+                            .Digest(Digest::NONE)
+                            .Padding(PaddingMode::NONE),
+                        KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.RsaPublicExponentMismatch
+ *
+ * Verifies that importing an RSA key pair with a public exponent that doesn't match the key fails
+ * in the correct way.
+ */
+TEST_F(ImportKeyTest, RsaPublicExponentMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .RsaSigningKey(1024, 3 /* Doesn't match key */)
+                            .Digest(Digest::NONE)
+                            .Padding(PaddingMode::NONE),
+                        KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaSuccess
+ *
+ * Verifies that importing and using an ECDSA key pair works correctly.
+ */
+TEST_F(ImportKeyTest, EcdsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .EcdsaSigningKey(256)
+                                           .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_key))
+        << "(Possibly b/33945114)";
+
+    CheckKm0CryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckKm0CryptoParam(TAG_KEY_SIZE, 256U);
+    CheckKm1CryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckKm2CryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaSizeMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .EcdsaSigningKey(224 /* Doesn't match key */)
+                            .Digest(Digest::NONE),
+                        KeyFormat::PKCS8, ec_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaCurveMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, EcdsaCurveMismatch) {
+    if (SupportsSymmetric() && !SupportsAttestation()) {
+        // KM1 hardware doesn't know about curves
+        return;
+    }
+
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
+                            .Digest(Digest::NONE),
+                        KeyFormat::PKCS8, ec_key))
+        << "(Possibly b/36233241)";
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an AES key works.
+ */
+TEST_F(ImportKeyTest, AesSuccess) {
+    string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .AesEncryptionKey(key.size() * 8)
+                                           .EcbMode()
+                                           .Padding(PaddingMode::PKCS7),
+                                       KeyFormat::RAW, key));
+
+    CheckKm1CryptoParam(TAG_ALGORITHM, Algorithm::AES);
+    CheckKm1CryptoParam(TAG_KEY_SIZE, 128U);
+    CheckKm1CryptoParam(TAG_PADDING, PaddingMode::PKCS7);
+    CheckKm1CryptoParam(TAG_BLOCK_MODE, BlockMode::ECB);
+    CheckOrigin();
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    string ciphertext = EncryptMessage(message, params);
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an HMAC key works.
+ */
+TEST_F(ImportKeyTest, HmacKeySuccess) {
+    string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .HmacKey(key.size() * 8)
+                                           .Digest(Digest::SHA_2_256)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 256),
+                                       KeyFormat::RAW, key));
+
+    CheckKm1CryptoParam(TAG_ALGORITHM, Algorithm::HMAC);
+    CheckKm1CryptoParam(TAG_KEY_SIZE, 128U);
+    CheckKm1CryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckOrigin();
+
+    string message = "Hello World!";
+    string signature = MacMessage(message, Digest::SHA_2_256, 256);
+    VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+}
+
+typedef KeymasterHidlTest EncryptionOperationsTest;
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingSuccess
+ *
+ * Verifies that raw RSA encryption works.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = string(1024 / 8, 'a');
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext2.size());
+
+    // Unpadded RSA is deterministic
+    EXPECT_EQ(ciphertext1, ciphertext2);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingShortMessage
+ *
+ * Verifies that raw RSA encryption of short messages works.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = "1";
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+
+    string ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext.size());
+
+    string expected_plaintext = string(1024 / 8 - 1, 0) + message;
+    string plaintext = DecryptMessage(ciphertext, params);
+
+    EXPECT_EQ(expected_plaintext, plaintext);
+
+    // Degenerate case, encrypting a numeric 1 yields 0x00..01 as the ciphertext.
+    message = static_cast<char>(1);
+    ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext.size());
+    EXPECT_EQ(ciphertext, string(1024 / 8 - 1, 0) + message);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA encryption of too-long messages fails in the expected way.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message(1024 / 8 + 1, 'a');
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected way.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::NONE)));
+
+    HidlBuf exported;
+    ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &exported));
+
+    const uint8_t* p = exported.data();
+    EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size()));
+    RSA_Ptr rsa(EVP_PKEY_get1_RSA(pkey.get()));
+
+    size_t modulus_len = BN_num_bytes(rsa->n);
+    ASSERT_EQ(1024U / 8, modulus_len);
+    std::unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]);
+    BN_bn2bin(rsa->n, modulus_buf.get());
+
+    // The modulus is too big to encrypt.
+    string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+
+    // One smaller than the modulus is okay.
+    BN_sub(rsa->n, rsa->n, BN_value_one());
+    modulus_len = BN_num_bytes(rsa->n);
+    ASSERT_EQ(1024U / 8, modulus_len);
+    BN_bn2bin(rsa->n, modulus_buf.get());
+    message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+    EXPECT_EQ(ErrorCode::OK, Finish(message, &result));
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepSuccess
+ *
+ * Verifies that RSA-OAEP encryption operations work, with all digests.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
+    auto digests = {Digest::MD5,       Digest::SHA1,      Digest::SHA_2_224,
+                    Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
+
+    size_t key_size = 2048;  // Need largish key for SHA-512 test.
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(key_size, 3)
+                                             .Padding(PaddingMode::RSA_OAEP)
+                                             .Digest(digests)));
+
+    string message = "Hello";
+
+    for (auto digest : digests) {
+        auto params = AuthorizationSetBuilder().Digest(digest).Padding(PaddingMode::RSA_OAEP);
+        string ciphertext1 = EncryptMessage(message, params);
+        if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+        EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+        string ciphertext2 = EncryptMessage(message, params);
+        EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+        // OAEP randomizes padding so every result should be different (with astronomically high
+        // probability).
+        EXPECT_NE(ciphertext1, ciphertext2);
+
+        string plaintext1 = DecryptMessage(ciphertext1, params);
+        EXPECT_EQ(message, plaintext1) << "RSA-OAEP failed with digest " << digest;
+        string plaintext2 = DecryptMessage(ciphertext2, params);
+        EXPECT_EQ(message, plaintext2) << "RSA-OAEP failed with digest " << digest;
+
+        // Decrypting corrupted ciphertext should fail.
+        size_t offset_to_corrupt = random() % ciphertext1.size();
+        char corrupt_byte;
+        do {
+            corrupt_byte = static_cast<char>(random() % 256);
+        } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+        ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+        string result;
+        EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+        EXPECT_EQ(0U, result.size());
+    }
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
+ * without a digest.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_OAEP)
+                                             .Digest(Digest::NONE)));
+    string message = "Hello World!";
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt with a
+ * different digest than was used to encrypt.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_OAEP)
+                                             .Digest(Digest::SHA_2_256, Digest::SHA_2_224)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(
+        message,
+        AuthorizationSetBuilder().Digest(Digest::SHA_2_224).Padding(PaddingMode::RSA_OAEP));
+
+    EXPECT_EQ(
+        ErrorCode::OK,
+        Begin(KeyPurpose::DECRYPT,
+              AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_OAEP)));
+    string result;
+    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepTooLarge
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
+ * too-large message.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepTooLarge) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_OAEP)
+                                             .Digest(Digest::SHA1)));
+    constexpr size_t digest_size = 160 /* SHA1 */ / 8;
+    constexpr size_t oaep_overhead = 2 * digest_size + 2;
+    string message(1024 / 8 - oaep_overhead + 1, 'a');
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::ENCRYPT,
+                    AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::SHA1)));
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1Success
+ *
+ * Verifies that RSA PKCS encryption/decrypts works.
+ */
+TEST_F(EncryptionOperationsTest, RsaPkcs1Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext2.size());
+
+    // PKCS1 v1.5 randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Decrypting corrupted ciphertext should fail.
+    size_t offset_to_corrupt = random() % ciphertext1.size();
+    char corrupt_byte;
+    do {
+        corrupt_byte = static_cast<char>(random() % 256);
+    } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+    ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string result;
+    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1TooLarge
+ *
+ * Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
+ */
+TEST_F(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+    string message(1024 / 8 - 10, 'a');
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.EcdsaEncrypt
+ *
+ * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, EcdsaEncrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(224)
+                                             .Digest(Digest::NONE)));
+    auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params))
+        << "(Possibly b/33543625)";
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params))
+        << "(Possibly b/33543625)";
+}
+
+/*
+ * EncryptionOperationsTest.HmacEncrypt
+ *
+ * Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, HmacEncrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .HmacKey(128)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    auto params = AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128);
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params))
+        << "(Possibly b/33543625)";
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params))
+        << "(Possibly b/33543625)";
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES ECB mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), params);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // ECB is deterministic.
+    EXPECT_EQ(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesWrongMode) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    EXPECT_EQ(
+        ErrorCode::INCOMPATIBLE_BLOCK_MODE,
+        Begin(KeyPurpose::ENCRYPT,
+              AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbNoPaddingWrongInputSize
+ *
+ * Verifies that AES encryption fails in the correct way when provided an input that is not a
+ * multiple of the block size and no padding is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+    // Message is slightly shorter than two blocks.
+    string message(16 * 2 - 1, 'a');
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &ciphertext));
+    EXPECT_EQ(0U, ciphertext.size());
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7Padding
+ *
+ * Verifies that AES PKCS7 padding works for any message length.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    // Try various message lengths; all should work.
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        string ciphertext = EncryptMessage(message, params);
+        EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, params);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbWrongPadding
+ *
+ * Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
+ * specified.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbWrongPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    // Try various message lengths; all should fail
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that AES decryption fails in the correct way when the padding is corrupted.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    string message = "a";
+    string ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(16U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext));
+}
+
+HidlBuf CopyIv(const AuthorizationSet& set) {
+    auto iv = set.GetTagValue(TAG_NONCE);
+    EXPECT_TRUE(iv.isOk());
+    return iv.value();
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrRoundTripSuccess
+ *
+ * Verifies that AES CTR mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+
+    string message = "123";
+    AuthorizationSet out_params;
+    string ciphertext1 = EncryptMessage(message, params, &out_params);
+    HidlBuf iv1 = CopyIv(out_params);
+    EXPECT_EQ(16U, iv1.size());
+
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    out_params.Clear();
+    string ciphertext2 = EncryptMessage(message, params, &out_params);
+    HidlBuf iv2 = CopyIv(out_params);
+    EXPECT_EQ(16U, iv2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    auto params_iv1 =
+        AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv1);
+    auto params_iv2 =
+        AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv2);
+
+    string plaintext = DecryptMessage(ciphertext1, params_iv1);
+    EXPECT_EQ(message, plaintext);
+    plaintext = DecryptMessage(ciphertext2, params_iv2);
+    EXPECT_EQ(message, plaintext);
+
+    // Using the wrong IV will result in a "valid" decryption, but the data will be garbage.
+    plaintext = DecryptMessage(ciphertext1, params_iv2);
+    EXPECT_NE(message, plaintext);
+    plaintext = DecryptMessage(ciphertext2, params_iv1);
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesIncremental
+ *
+ * Verifies that AES works, all modes, when provided data in various size increments.
+ */
+TEST_F(EncryptionOperationsTest, AesIncremental) {
+    auto block_modes = {
+        BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
+    };
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(block_modes)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    for (int increment = 1; increment <= 240; ++increment) {
+        for (auto block_mode : block_modes) {
+            string message(240, 'a');
+            auto params = AuthorizationSetBuilder()
+                              .BlockMode(block_mode)
+                              .Padding(PaddingMode::NONE)
+                              .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+
+            AuthorizationSet output_params;
+            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+            string ciphertext;
+            size_t input_consumed;
+            string to_send;
+            for (size_t i = 0; i < message.size(); i += increment) {
+                to_send.append(message.substr(i, increment));
+                EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
+                to_send = to_send.substr(input_consumed);
+
+                switch (block_mode) {
+                case BlockMode::ECB:
+                case BlockMode::CBC:
+                    // Implementations must take as many blocks as possible, leaving less than
+                    // a block.
+                    EXPECT_LE(to_send.length(), 16U);
+                    break;
+                case BlockMode::GCM:
+                case BlockMode::CTR:
+                    // Implementations must always take all the data.
+                    EXPECT_EQ(0U, to_send.length());
+                    break;
+                }
+            }
+            EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
+
+            switch (block_mode) {
+            case BlockMode::GCM:
+                EXPECT_EQ(message.size() + 16, ciphertext.size());
+                break;
+            case BlockMode::CTR:
+                EXPECT_EQ(message.size(), ciphertext.size());
+                break;
+            case BlockMode::CBC:
+            case BlockMode::ECB:
+                EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+                break;
+            }
+
+            auto iv = output_params.GetTagValue(TAG_NONCE);
+            switch (block_mode) {
+            case BlockMode::CBC:
+            case BlockMode::GCM:
+            case BlockMode::CTR:
+                ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
+                EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
+                params.push_back(TAG_NONCE, iv.value());
+                break;
+
+            case BlockMode::ECB:
+                EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
+                break;
+            }
+
+            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+                << "Decrypt begin() failed for block mode " << block_mode;
+
+            string plaintext;
+            for (size_t i = 0; i < ciphertext.size(); i += increment) {
+                to_send.append(ciphertext.substr(i, increment));
+                EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
+                to_send = to_send.substr(input_consumed);
+            }
+            ErrorCode error = Finish(to_send, &plaintext);
+            ASSERT_EQ(ErrorCode::OK, error)
+                << "Decryption failed for block mode " << block_mode << " and increment "
+                << increment << " (Possibly b/33584622)";
+            if (error == ErrorCode::OK) {
+                ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
+                                              << block_mode << " and increment " << increment;
+            }
+        }
+    }
+}
+
+struct AesCtrSp80038aTestVector {
+    const char* key;
+    const char* nonce;
+    const char* plaintext;
+    const char* ciphertext;
+};
+
+// These test vectors are taken from
+// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5.
+static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
+    // AES-128
+    {
+        "2b7e151628aed2a6abf7158809cf4f3c", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
+        "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
+    },
+    // AES-192
+    {
+        "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
+        "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
+    },
+    // AES-256
+    {
+        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
+        "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5"
+        "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
+    },
+};
+
+/*
+ * EncryptionOperationsTest.AesCtrSp80038aTestVector
+ *
+ * Verifies AES CTR implementation against SP800-38A test vectors.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+    for (size_t i = 0; i < 3; i++) {
+        const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
+        const string key = hex2str(test.key);
+        const string nonce = hex2str(test.nonce);
+        const string plaintext = hex2str(test.plaintext);
+        const string ciphertext = hex2str(test.ciphertext);
+        CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrIncompatiblePaddingMode
+ *
+ * Verifies that keymaster rejects use of CTR mode with PKCS7 padding in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                             .Padding(PaddingMode::PKCS7)));
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                             .Authorization(TAG_CALLER_NONCE)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::CTR)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_NONCE, HidlBuf(string(1, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CTR)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf(string(15, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CTR)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf(string(17, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_F(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext1 = EncryptMessage(message, params, &out_params);
+    HidlBuf iv1 = CopyIv(out_params);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    out_params.Clear();
+
+    string ciphertext2 = EncryptMessage(message, params, &out_params);
+    HidlBuf iv2 = CopyIv(out_params);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    params.push_back(TAG_NONCE, iv1);
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonce
+ *
+ * Verifies that AES caller-provided nonces work correctly.
+ */
+TEST_F(EncryptionOperationsTest, AesCallerNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                             .Authorization(TAG_CALLER_NONCE)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+
+    // Don't specify nonce, should get a random one.
+    AuthorizationSetBuilder params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+    params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should also work.
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CBC)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf("abcdefghijklmnop"));
+    out_params.Clear();
+    ciphertext = EncryptMessage(message, params, &out_params);
+
+    // Decrypt with correct nonce.
+    plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Try with wrong nonce.
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CBC)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf("aaaaaaaaaaaaaaaa"));
+    plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonceProhibited
+ *
+ * Verifies that caller-provided nonces are not permitted when not specified in the key
+ * authorizations.
+ */
+TEST_F(EncryptionOperationsTest, AesCallerNonceProhibited) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+
+    // Don't specify nonce, should get a random one.
+    AuthorizationSetBuilder params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+    params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should fail
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CBC)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf("abcdefghijklmnop"));
+    out_params.Clear();
+    EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED, Begin(KeyPurpose::ENCRYPT, params, &out_params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmRoundTripSuccess
+ *
+ * Verifies that AES GCM mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params))
+        << "Begin encrypt";
+    string ciphertext;
+    AuthorizationSet update_out_params;
+    ASSERT_EQ(ErrorCode::OK,
+              Finish(op_handle_, update_params, message, "", &update_out_params, &ciphertext));
+
+    // Grab nonce
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt";
+    string plaintext;
+    size_t input_consumed;
+    ASSERT_EQ(ErrorCode::OK, Update(op_handle_, update_params, ciphertext, &update_out_params,
+                                    &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext));
+
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTag
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmTooShortTag) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string message = "123456789012345678901234567890123456";
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 96);
+
+    EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTagOnDecrypt
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    EXPECT_EQ(1U, begin_out_params.size());
+    ASSERT_TRUE(begin_out_params.GetTagValue(TAG_NONCE).isOk());
+
+    AuthorizationSet finish_out_params;
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+
+    params = AuthorizationSetBuilder()
+                 .Authorizations(begin_out_params)
+                 .BlockMode(BlockMode::GCM)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_MAC_LENGTH, 96);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptKey
+ *
+ * Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmCorruptKey) {
+    string nonce = {
+        0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
+    };
+    string ciphertext = {
+        0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc, 0xd2, 0xcb, 0x16,
+        0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78, 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a,
+        0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d, 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76,
+        0x76, 0x5e, 0xfb, 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd,
+        0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0,
+    };
+
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128)
+                      .Authorization(TAG_NONCE, nonce.data(), nonce.size());
+
+    auto import_params = AuthorizationSetBuilder()
+                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                             .AesEncryptionKey(128)
+                             .BlockMode(BlockMode::GCM)
+                             .Padding(PaddingMode::NONE)
+                             .Authorization(TAG_CALLER_NONCE)
+                             .Authorization(TAG_MIN_MAC_LENGTH, 128);
+
+    // Import correct key and decrypt
+    string key = {
+        0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+        0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+    };
+    ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(ErrorCode::OK, DeleteKey());
+
+    // Corrupt key and attempt to decrypt
+    key[0] = 0;
+    ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
+    EXPECT_EQ(ErrorCode::OK, DeleteKey());
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadNoData
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data, but no data to
+ * encrypt.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmAadNoData) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "1234567890123456";
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, "" /* input */, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+    EXPECT_TRUE(finish_out_params.empty());
+
+    // Grab nonce
+    params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, ciphertext, "" /* signature */,
+                                    &finish_out_params, &plaintext))
+        << "(Possibly b/33615032)";
+
+    EXPECT_TRUE(finish_out_params.empty());
+
+    EXPECT_EQ("", plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmMultiPartAad
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data in multiple chunks.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmMultiPartAad) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "123456789012345678901234567890123456";
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+    AuthorizationSet begin_out_params;
+
+    auto update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+    // No data, AAD only.
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, "" /* input */, &update_out_params,
+                                    &ciphertext, &input_consumed));
+    EXPECT_EQ(0U, input_consumed);
+    EXPECT_EQ(0U, ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    // AAD and data.
+    EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, message, &update_out_params,
+                                    &ciphertext, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    EXPECT_EQ(ErrorCode::OK, Finish("" /* input */, &ciphertext));
+
+    // Grab nonce.
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt
+    update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foofoo", (size_t)6);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, update_params, ciphertext, "" /* signature */,
+                                    &update_out_params, &plaintext));
+    EXPECT_TRUE(update_out_params.empty());
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadOutOfOrder
+ *
+ * Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "123456789012345678901234567890123456";
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+    AuthorizationSet begin_out_params;
+
+    auto update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+    // No data, AAD only.
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, "" /* input */, &update_out_params,
+                                    &ciphertext, &input_consumed));
+    EXPECT_EQ(0U, input_consumed);
+    EXPECT_EQ(0U, ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    // AAD and data.
+    EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, message, &update_out_params,
+                                    &ciphertext, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    // More AAD
+    EXPECT_EQ(ErrorCode::INVALID_TAG, Update(op_handle_, update_params, "", &update_out_params,
+                                             &ciphertext, &input_consumed));
+
+    op_handle_ = kOpHandleSentinel;
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmBadAad
+ *
+ * Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmBadAad) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "12345678901234567890123456789012";
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+
+    // Grab nonce
+    begin_params.push_back(begin_out_params);
+
+    finish_params = AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA,
+                                                            "barfoo" /* Wrong AAD */, (size_t)6);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+              Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+                     &plaintext));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmWrongNonce
+ *
+ * Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmWrongNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "12345678901234567890123456789012";
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+
+    // Wrong nonce
+    begin_params.push_back(TAG_NONCE, HidlBuf("123456789012"));
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+              Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+                     &plaintext));
+
+    // With wrong nonce, should have gotten garbage plaintext (or none).
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptTag
+ *
+ * Verifies that AES GCM decryption fails correctly when the tag is wrong.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmCorruptTag) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "1234567890123456";
+    string message = "123456789012345678901234567890123456";
+
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+    EXPECT_TRUE(finish_out_params.empty());
+
+    // Corrupt tag
+    ++(*ciphertext.rbegin());
+
+    // Grab nonce
+    params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+              Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+                     &plaintext));
+    EXPECT_TRUE(finish_out_params.empty());
+}
+
+typedef KeymasterHidlTest MaxOperationsTest;
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with AES keys.
+ */
+TEST_F(MaxOperationsTest, TestLimitAes) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .EcbMode()
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+    string message = "1234567890123456";
+
+    auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE);
+
+    EncryptMessage(message, params);
+    EncryptMessage(message, params);
+    EncryptMessage(message, params);
+
+    // Fourth time should fail.
+    EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with RSA keys.
+ */
+TEST_F(MaxOperationsTest, TestLimitRsa) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .NoDigestOrPadding()
+                                             .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+    string message = "1234567890123456";
+
+    auto params = AuthorizationSetBuilder().NoDigestOrPadding();
+
+    SignMessage(message, params);
+    SignMessage(message, params);
+    SignMessage(message, params);
+
+    // Fourth time should fail.
+    EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
+}
+
+typedef KeymasterHidlTest AddEntropyTest;
+
+/*
+ * AddEntropyTest.AddEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up.  There's no way to test that entropy is
+ * actually added.
+ */
+TEST_F(AddEntropyTest, AddEntropy) {
+    EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf("foo")));
+}
+
+/*
+ * AddEntropyTest.AddEmptyEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
+ */
+TEST_F(AddEntropyTest, AddEmptyEntropy) {
+    EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf()));
+}
+
+/*
+ * AddEntropyTest.AddLargeEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
+ */
+TEST_F(AddEntropyTest, AddLargeEntropy) {
+    EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(16 * 1024, 'a'))));
+}
+
+typedef KeymasterHidlTest AttestationTest;
+
+/*
+ * AttestationTest.RsaAttestation
+ *
+ * Verifies that attesting to RSA keys works and generates the expected output.
+ */
+TEST_F(AttestationTest, RsaAttestation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::OK, AttestKey(AuthorizationSetBuilder().Authorization(
+                                           TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")),
+                                       &cert_chain));
+    EXPECT_GE(cert_chain.size(), 2U);
+    EXPECT_TRUE(verify_chain(cert_chain));
+    EXPECT_TRUE(verify_attestation_record("challenge",                            //
+                                          key_characteristics_.softwareEnforced,  //
+                                          key_characteristics_.teeEnforced,       //
+                                          cert_chain[0]));
+}
+
+/*
+ * AttestationTest.EcAttestation
+ *
+ * Verifies that attesting to EC keys works and generates the expected output.
+ */
+TEST_F(AttestationTest, EcAttestation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(EcCurve::P_256)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::OK, AttestKey(AuthorizationSetBuilder().Authorization(
+                                           TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")),
+                                       &cert_chain));
+    EXPECT_GE(cert_chain.size(), 2U);
+    EXPECT_TRUE(verify_chain(cert_chain));
+
+    EXPECT_TRUE(verify_attestation_record("challenge",                            //
+                                          key_characteristics_.softwareEnforced,  //
+                                          key_characteristics_.teeEnforced,       //
+                                          cert_chain[0]));
+}
+
+/*
+ * AttestationTest.AesAttestation
+ *
+ * Verifies that attesting to AES keys fails in the expected way.
+ */
+TEST_F(AttestationTest, AesAttestation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .EcbMode()
+                                             .Padding(PaddingMode::PKCS7)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_ALGORITHM,
+              AttestKey(AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE,
+                                                                HidlBuf("challenge")),
+                        &cert_chain));
+}
+
+/*
+ * AttestationTest.HmacAttestation
+ *
+ * Verifies that attesting to HMAC keys fails in the expected way.
+ */
+TEST_F(AttestationTest, HmacAttestation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .HmacKey(128)
+                                             .EcbMode()
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_ALGORITHM,
+              AttestKey(AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE,
+                                                                HidlBuf("challenge")),
+                        &cert_chain));
+}
+
+}  // namespace test
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    if (argc == 2) {
+        ALOGI("Running keymaster VTS against service \"%s\"", argv[1]);
+        service_name = argv[1];
+    }
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/keymaster/3.0/vts/functional/keymaster_tags.h b/keymaster/3.0/vts/functional/keymaster_tags.h
new file mode 100644
index 0000000..f241ef1
--- /dev/null
+++ b/keymaster/3.0/vts/functional/keymaster_tags.h
@@ -0,0 +1,450 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
+#define SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
+
+/**
+ * This header contains various definitions that make working with keymaster tags safer and easier.
+ *
+ * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose
+ * of making it impossible to make certain classes of mistakes when operating on keymaster
+ * authorizations.  For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE
+ * and then to assign Algorithm::RSA to algorithm element of its union. But because the user
+ * must choose the union field, there could be a mismatch which the compiler has now way to
+ * diagnose.
+ *
+ * The machinery in this header solves these problems by describing which union field corresponds
+ * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a
+ * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG,
+ * we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal.
+ *
+ * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance
+ * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag
+ * to its value c++ type and the correct union element of KeyParameter. This is done by means of
+ * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping
+ * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a
+ * reference to the correct element of KeyParameter.
+ * E.g.:
+ *      given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)"
+ *      yields a reference to param.f.purpose
+ * If used in an assignment the compiler can now check the compatibility of the assigned value.
+ *
+ * For convenience we also provide the constructor like function Authorization().
+ * Authorization takes a typed tag and a value and checks at compile time whether the value given
+ * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the
+ * given tag and value and returns it by value.
+ *
+ * The second convenience function, authorizationValue, allows access to the KeyParameter value in
+ * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped
+ * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped
+ * reference.
+ * E.g.:
+ *      auto param = Authorization(TAG_ALGORITM, Algorithm::RSA);
+ *      auto value1 = authorizationValue(TAG_PURPOSE, param);
+ *      auto value2 = authorizationValue(TAG_ALGORITM, param);
+ * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access.
+ */
+
+#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
+#include <hardware/hw_auth_token.h>
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+
+// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have.  We
+// need these old values to be able to support old keys that use them.
+static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
+static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;
+
+constexpr TagType typeFromTag(Tag tag) {
+    return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000));
+}
+
+/**
+ * TypedTag is a templatized version of Tag, which provides compile-time checking of keymaster tag
+ * types. Instances are convertible to Tag, so they can be used wherever Tag is expected, and
+ * because they encode the tag type it's possible to create function overloads that only operate on
+ * tags with a particular type.
+ */
+template <TagType tag_type, Tag tag> struct TypedTag {
+    inline TypedTag() {
+        // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+        // 'tag_type'.  Attempting to instantiate a tag with the wrong type will result in a compile
+        // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+        static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type");
+    }
+    constexpr operator Tag() { return tag; }
+    constexpr long maskedTag() {
+        return static_cast<long>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0x0fffffff));
+    }
+};
+
+template <Tag tag> struct Tag2TypedTag { typedef TypedTag<typeFromTag(tag), tag> type; };
+
+template <Tag tag> struct Tag2String;
+
+#define _TAGS_STRINGIFY(x) #x
+#define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x)
+
+#define DECLARE_TYPED_TAG(name)                                                                    \
+    typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t;                                 \
+    extern TAG_##name##_t TAG_##name;                                                              \
+    template <> struct Tag2String<Tag::name> {                                                     \
+        static const char* value() { return "Tag::" TAGS_STRINGIFY(name); }                        \
+    }
+
+DECLARE_TYPED_TAG(INVALID);
+DECLARE_TYPED_TAG(KEY_SIZE);
+DECLARE_TYPED_TAG(MAC_LENGTH);
+DECLARE_TYPED_TAG(CALLER_NONCE);
+DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
+DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
+DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE);
+DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
+DECLARE_TYPED_TAG(ACTIVE_DATETIME);
+DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
+DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
+DECLARE_TYPED_TAG(ALL_USERS);
+DECLARE_TYPED_TAG(USER_ID);
+DECLARE_TYPED_TAG(USER_SECURE_ID);
+DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
+DECLARE_TYPED_TAG(AUTH_TIMEOUT);
+DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
+DECLARE_TYPED_TAG(ALL_APPLICATIONS);
+DECLARE_TYPED_TAG(APPLICATION_ID);
+DECLARE_TYPED_TAG(APPLICATION_DATA);
+DECLARE_TYPED_TAG(CREATION_DATETIME);
+DECLARE_TYPED_TAG(ROLLBACK_RESISTANT);
+DECLARE_TYPED_TAG(ROOT_OF_TRUST);
+DECLARE_TYPED_TAG(ASSOCIATED_DATA);
+DECLARE_TYPED_TAG(NONCE);
+DECLARE_TYPED_TAG(AUTH_TOKEN);
+DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
+DECLARE_TYPED_TAG(OS_VERSION);
+DECLARE_TYPED_TAG(OS_PATCHLEVEL);
+DECLARE_TYPED_TAG(UNIQUE_ID);
+DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
+DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
+DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
+
+DECLARE_TYPED_TAG(PURPOSE);
+DECLARE_TYPED_TAG(ALGORITHM);
+DECLARE_TYPED_TAG(BLOCK_MODE);
+DECLARE_TYPED_TAG(DIGEST);
+DECLARE_TYPED_TAG(PADDING);
+DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
+DECLARE_TYPED_TAG(ORIGIN);
+DECLARE_TYPED_TAG(USER_AUTH_TYPE);
+DECLARE_TYPED_TAG(KDF);
+DECLARE_TYPED_TAG(EC_CURVE);
+
+template <typename... Elems> struct MetaList {};
+
+using all_tags_t = MetaList<
+    TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
+    TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t,
+    TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t,
+    TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t,
+    TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t,
+    TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t,
+    TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t,
+    TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
+    TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t,
+    TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
+    TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>;
+
+/* implementation in keystore_utils.cpp */
+extern const char* stringifyTag(Tag tag);
+
+template <typename TypedTagType> struct TypedTag2ValueType;
+
+#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name)                                              \
+    template <Tag tag> struct TypedTag2ValueType<TypedTag<tag_type, tag>> {                        \
+        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type;                    \
+    };                                                                                             \
+    template <Tag tag>                                                                             \
+    inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param)                 \
+        ->const decltype(param.field_name)& {                                                      \
+        return param.field_name;                                                                   \
+    }                                                                                              \
+    template <Tag tag>                                                                             \
+    inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param)                       \
+        ->decltype(param.field_name)& {                                                            \
+        return param.field_name;                                                                   \
+    }
+
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)
+
+#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name)                                        \
+    template <> struct TypedTag2ValueType<decltype(typed_tag)> {                                   \
+        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type;                    \
+    };                                                                                             \
+    inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param)                     \
+        ->const decltype(param.field_name)& {                                                      \
+        return param.field_name;                                                                   \
+    }                                                                                              \
+    inline auto accessTagValue(decltype(typed_tag), KeyParameter& param)                           \
+        ->decltype(param.field_name)& {                                                            \
+        return param.field_name;                                                                   \
+    }
+
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType)
+
+template <TagType tag_type, Tag tag, typename ValueT>
+inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
+    KeyParameter param;
+    param.tag = tag;
+    param.f.longInteger = 0;
+    accessTagValue(ttag, param) = std::forward<ValueT>(value);
+    return param;
+}
+
+// the boolean case
+template <Tag tag> inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
+    KeyParameter param;
+    param.tag = tag;
+    param.f.boolValue = true;
+    return param;
+}
+
+template <typename... Pack> struct FirstOrNoneHelper;
+template <typename First> struct FirstOrNoneHelper<First> { typedef First type; };
+template <> struct FirstOrNoneHelper<> {
+    struct type {};
+};
+
+template <typename... Pack> using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type;
+
+template <TagType tag_type, Tag tag, typename... Args>
+inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) {
+    static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0),
+                  "TagType::BOOL Authorizations do not take parameters. Presence is truth.");
+    static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1),
+                  "Authorization other then TagType::BOOL take exactly one parameter.");
+    static_assert(
+        tag_type == TagType::BOOL ||
+            std::is_convertible<std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>,
+                                typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value,
+        "Invalid argument type for given tag.");
+
+    return makeKeyParameter(ttag, std::forward<Args>(args)...);
+}
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ */
+template <typename ValueT> class NullOr {
+    template <typename T> struct reference_initializer {
+        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
+    };
+    template <typename T> struct pointer_initializer {
+        static T init() { return nullptr; }
+    };
+    template <typename T> struct value_initializer {
+        static T init() { return T(); }
+    };
+    template <typename T>
+    using initializer_t =
+        std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>,
+                           std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>,
+                                              value_initializer<T>>>;
+
+  public:
+    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
+    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+
+    bool isOk() const { return !null_; }
+
+    const ValueT& value() const & { return value_; }
+    ValueT& value() & { return value_; }
+    ValueT&& value() && { return std::move(value_); }
+
+  private:
+    ValueT value_;
+    bool null_;
+};
+
+template <typename T> std::remove_reference_t<T> NullOrOr(NullOr<T>&& v) {
+    if (v.isOk()) return v;
+    return {};
+}
+
+template <typename Head, typename... Tail>
+std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
+    if (head.isOk()) return head;
+    return NullOrOr(std::forward<Tail>(tail)...);
+}
+
+template <typename Default, typename Wrapped>
+std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
+    static_assert(std::is_convertible<std::remove_reference_t<Default>,
+                                      std::remove_reference_t<Wrapped>>::value,
+                  "Type of default value must match the type wrapped by NullOr");
+    if (optional.isOk()) return optional.value();
+    return def;
+}
+
+template <TagType tag_type, Tag tag>
+inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&>
+authorizationValue(TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
+    if (tag != param.tag) return {};
+    return accessTagValue(ttag, param);
+}
+
+inline const char* stringify(Digest digest) {
+    switch (digest) {
+    case Digest::NONE:
+        return "None";
+    case Digest::MD5:
+        return "Md5";
+    case Digest::SHA1:
+        return "Sha1";
+    case Digest::SHA_2_224:
+        return "Sha224";
+    case Digest::SHA_2_256:
+        return "Sha256";
+    case Digest::SHA_2_384:
+        return "Sha384";
+    case Digest::SHA_2_512:
+        return "Sha512";
+    }
+    return "UNKNOWN DIGEST!";
+}
+
+inline const char* stringify(Algorithm algorithm) {
+    switch (algorithm) {
+    case Algorithm::RSA:
+        return "Rsa";
+    case Algorithm::EC:
+        return "Ec";
+    case Algorithm::AES:
+        return "Aes";
+    case Algorithm::HMAC:
+        return "Hmac";
+    }
+    return "UNKNOWN ALGORITHM";
+}
+
+inline const char* stringify(BlockMode block_mode) {
+    switch (block_mode) {
+    case BlockMode::ECB:
+        return "Ecb";
+    case BlockMode::CBC:
+        return "Cbc";
+    case BlockMode::CTR:
+        return "Ctr";
+    case BlockMode::GCM:
+        return "Gcm";
+    }
+    return "UNKNOWN BLOCK MODE";
+}
+
+inline const char* stringify(PaddingMode padding) {
+    switch (padding) {
+    case PaddingMode::NONE:
+        return "None";
+    case PaddingMode::RSA_OAEP:
+        return "RsaOaep";
+    case PaddingMode::RSA_PSS:
+        return "RsaPss";
+    case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+        return "RsaPkcs115Encrypt";
+    case PaddingMode::RSA_PKCS1_1_5_SIGN:
+        return "RsaPkcs115Sign";
+    case PaddingMode::PKCS7:
+        return "Pkcs7";
+    }
+    return "UNKNOWN PADDING MODE";
+}
+
+inline const char* stringify(KeyOrigin origin) {
+    switch (origin) {
+    case KeyOrigin::GENERATED:
+        return "Generated";
+    case KeyOrigin::DERIVED:
+        return "Derived";
+    case KeyOrigin::IMPORTED:
+        return "Imported";
+    case KeyOrigin::UNKNOWN:
+        return "UNKNOWN (keymaster0 didn't record it)";
+    }
+    return "UNKOWN KEY ORIGIN VALUE";
+}
+
+inline const char* stringify(KeyPurpose purpose) {
+    switch (purpose) {
+    case KeyPurpose::ENCRYPT:
+        return "Encrypt";
+    case KeyPurpose::DECRYPT:
+        return "Decrypt";
+    case KeyPurpose::SIGN:
+        return "Sign";
+    case KeyPurpose::VERIFY:
+        return "Verify";
+    case KeyPurpose::DERIVE_KEY:
+        return "DeriveKey";
+    case KeyPurpose::WRAP_KEY:
+        return "WrapKey";
+    };
+    return "UNKNOWN KEY PURPOSE";
+}
+
+inline const char* stringify(EcCurve curve) {
+    switch (curve) {
+    case EcCurve::P_224:
+        return "P_224";
+    case EcCurve::P_256:
+        return "P_256";
+    case EcCurve::P_384:
+        return "P_384";
+    case EcCurve::P_521:
+        return "P_521";
+    }
+    return "UNKNOWN EC CURVE";
+}
+
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
diff --git a/keymaster/3.0/vts/functional/keystore_tags_utils.cpp b/keymaster/3.0/vts/functional/keystore_tags_utils.cpp
new file mode 100644
index 0000000..8dd99db
--- /dev/null
+++ b/keymaster/3.0/vts/functional/keystore_tags_utils.cpp
@@ -0,0 +1,50 @@
+/*
+**
+** Copyright 2016, 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 "keymaster_tags.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+
+template <typename TagList> struct TagStringifier;
+
+template <typename... Tags> struct TagStringifier<MetaList<Tags...>> {
+    template <TagType tag_type, Tag tag>
+    static TypedTag<tag_type, tag> chooseString(TypedTag<tag_type, tag> ttag, Tag runtime_tag,
+                                                const char** result) {
+        if (tag == runtime_tag) {
+            *result = Tag2String<tag>::value();
+        }
+        return ttag;
+    }
+    static const char* stringify(Tag tag) {
+        const char* result = "unknown tag";
+        [](Tags&&...) {}(chooseString(Tags(), tag, &result)...);
+        return result;
+    }
+};
+
+const char* stringifyTag(Tag tag) {
+    return TagStringifier<all_tags_t>::stringify(tag);
+}
+
+}  // namespace V3_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/3.0/vts/functional/openssl_utils.h b/keymaster/3.0/vts/functional/openssl_utils.h
new file mode 100644
index 0000000..2eba9ba
--- /dev/null
+++ b/keymaster/3.0/vts/functional/openssl_utils.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 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.
+ */
+
+template <typename T, void (*F)(T*)> struct UniquePtrDeleter {
+    void operator()(T* p) const { F(p); }
+};
+
+typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete;
+
+#define MAKE_OPENSSL_PTR_TYPE(type)                                                                \
+    typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
+
+MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
+MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
+MAKE_OPENSSL_PTR_TYPE(RSA)
+MAKE_OPENSSL_PTR_TYPE(X509)
+MAKE_OPENSSL_PTR_TYPE(BN_CTX)
+
+typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;
+
+inline const EVP_MD* openssl_digest(android::hardware::keymaster::V3_0::Digest digest) {
+    switch (digest) {
+    case android::hardware::keymaster::V3_0::Digest::NONE:
+        return nullptr;
+    case android::hardware::keymaster::V3_0::Digest::MD5:
+        return EVP_md5();
+    case android::hardware::keymaster::V3_0::Digest::SHA1:
+        return EVP_sha1();
+    case android::hardware::keymaster::V3_0::Digest::SHA_2_224:
+        return EVP_sha224();
+    case android::hardware::keymaster::V3_0::Digest::SHA_2_256:
+        return EVP_sha256();
+    case android::hardware::keymaster::V3_0::Digest::SHA_2_384:
+        return EVP_sha384();
+    case android::hardware::keymaster::V3_0::Digest::SHA_2_512:
+        return EVP_sha512();
+    }
+    return nullptr;
+}
diff --git a/nfc/1.0/INfc.hal b/nfc/1.0/INfc.hal
index c6e1511..74b69a0 100644
--- a/nfc/1.0/INfc.hal
+++ b/nfc/1.0/INfc.hal
@@ -19,7 +19,7 @@
 import INfcClientCallback;
 
 interface INfc {
-    /*
+    /**
      * Opens the NFC controller device and performs initialization.
      * This may include patch download and other vendor-specific initialization.
      *
@@ -37,7 +37,7 @@
     @callflow(next={"write", "coreInitialized", "prediscover", "powerCycle", "controlGranted"})
     open(INfcClientCallback clientCallback) generates (NfcStatus status);
 
-    /*
+    /**
      * Performs an NCI write.
      *
      * This method may queue writes and return immediately. The only
@@ -49,7 +49,7 @@
                     "controlGranted"})
     write(NfcData data) generates (uint32_t retval);
 
-    /*
+    /**
      * coreInitialized() is called after the CORE_INIT_RSP is received from the
      * NFCC. At this time, the HAL can do any chip-specific configuration.
      *
@@ -62,7 +62,7 @@
     @callflow(next={"write", "prediscover", "close"})
     coreInitialized(NfcData data) generates (NfcStatus status);
 
-    /*
+    /**
      * prediscover is called every time before starting RF discovery.
      * It is a good place to do vendor-specific configuration that must be
      * performed every time RF discovery is about to be started.
@@ -76,7 +76,7 @@
     @callflow(next={"write", "close", "coreInitialized", "powerCycle", "controlGranted"})
     prediscover() generates (NfcStatus status);
 
-    /*
+    /**
      * Close the NFC controller. Should free all resources.
      *
      * @return NfcStatus::OK on success and NfcStatus::FAILED on error.
@@ -84,7 +84,7 @@
     @exit
     close() generates (NfcStatus status);
 
-    /*
+    /**
      * Grant HAL the exclusive control to send NCI commands.
      * Called in response to NfcEvent.REQUEST_CONTROL.
      * Must only be called when there are no NCI commands pending.
@@ -95,7 +95,7 @@
     @callflow(next={"write", "close", "prediscover", "coreInitialized", "powerCycle"})
     controlGranted() generates (NfcStatus status);
 
-     /*
+     /**
      * Restart controller by power cyle;
      * NfcEvent.OPEN_CPLT will notify when operation is complete.
      *
diff --git a/nfc/1.0/INfcClientCallback.hal b/nfc/1.0/INfcClientCallback.hal
index a56cc09..9972ada 100644
--- a/nfc/1.0/INfcClientCallback.hal
+++ b/nfc/1.0/INfcClientCallback.hal
@@ -17,13 +17,13 @@
 package android.hardware.nfc@1.0;
 
 interface INfcClientCallback {
-    /*
+    /**
      * The callback passed in from the NFC stack that the HAL
      * can use to pass events back to the stack.
      */
     sendEvent(NfcEvent event, NfcStatus status);
 
-    /*
+    /**
      * The callback passed in from the NFC stack that the HAL
      * can use to pass incomming data to the stack.
      */
diff --git a/radio/1.0/IRadio.hal b/radio/1.0/IRadio.hal
index 0b1bf40..2976290 100644
--- a/radio/1.0/IRadio.hal
+++ b/radio/1.0/IRadio.hal
@@ -19,7 +19,7 @@
 import IRadioResponse;
 import IRadioIndication;
 
-/*
+/**
  * This interface is used by telephony & telecom to talk to cellular radio.
  * All the functions have minimum one parameter:
  * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
@@ -27,7 +27,7 @@
  * serial to different methods), multiple responses (one for each method call) must still be served.
  */
 interface IRadio {
-    /*
+    /**
      * Set response functions for radio requests & radio indications.
      *
      * @param radioResponse Object containing response functions
@@ -36,7 +36,7 @@
     setResponseFunctions(IRadioResponse radioResponse,
             IRadioIndication radioIndication);
 
-    /*
+    /**
      * Requests status of the ICC card
      *
      * @param serial Serial number of request.
@@ -46,7 +46,7 @@
      */
     oneway getIccCardStatus(int32_t serial);
 
-    /*
+    /**
      * Supplies ICC PIN. Only called if CardStatus has AppState.PIN state
      *
      * @param serial Serial number of request.
@@ -58,7 +58,7 @@
      */
     oneway supplyIccPinForApp(int32_t serial, string pin, string aid);
 
-    /*
+    /**
      * Supplies ICC PUK and new PIN.
      *
      * @param serial Serial number of request.
@@ -71,7 +71,7 @@
      */
     oneway supplyIccPukForApp(int32_t serial, string puk, string pin, string aid);
 
-    /*
+    /**
      * Supplies ICC PIN2. Only called following operation where SIM_PIN2 was
      * returned as a a failure from a previous operation.
      *
@@ -84,7 +84,7 @@
      */
     oneway supplyIccPin2ForApp(int32_t serial, string pin2, string aid);
 
-    /*
+    /**
      * Supplies ICC PUK2 and new PIN2.
      *
      * @param serial Serial number of request.
@@ -98,7 +98,7 @@
     oneway supplyIccPuk2ForApp(int32_t serial, string puk2, string pin2,
             string aid);
 
-    /*
+    /**
      * Supplies old ICC PIN and new PIN.
      *
      * @param serial Serial number of request.
@@ -112,7 +112,7 @@
     oneway changeIccPinForApp(int32_t serial, string oldPin, string newPin,
             string aid);
 
-    /*
+    /**
      * Supplies old ICC PIN2 and new PIN2.
      *
      * @param serial Serial number of request.
@@ -126,7 +126,7 @@
     oneway changeIccPin2ForApp(int32_t serial, string oldPin2, string newPin2,
             string aid);
 
-    /*
+    /**
      * Requests that network personalization be deactivated
      *
      * @param serial Serial number of request.
@@ -137,7 +137,7 @@
      */
     oneway supplyNetworkDepersonalization(int32_t serial, string netPin);
 
-    /*
+    /**
      * Requests current call list
      *
      * @param serial Serial number of request.
@@ -147,7 +147,7 @@
      */
     oneway getCurrentCalls(int32_t serial);
 
-    /*
+    /**
      * Initiate voice call.
      * This method is never used for supplementary service codes
      *
@@ -159,7 +159,7 @@
      */
     oneway dial(int32_t serial, Dial dialInfo);
 
-    /*
+    /**
      * Get the SIM IMSI
      * Only valid when radio state is "RADIO_STATE_ON"
      *
@@ -171,7 +171,7 @@
      */
     oneway getImsiForApp(int32_t serial, string aid);
 
-    /*
+    /**
      * Hang up a specific line (like AT+CHLD=1x)
      * After this HANGUP request returns, Radio must show the connection is NOT
      * active anymore in next requestGetCurrentCalls query.
@@ -184,7 +184,7 @@
      */
     oneway hangup(int32_t serial, int32_t gsmIndex);
 
-    /*
+    /**
      * Hang up waiting or held (like AT+CHLD=0)
      * After this HANGUP request returns, Radio must show the connection is NOT
      * active anymore in next getCurrentCalls() query.
@@ -196,7 +196,7 @@
      */
     oneway hangupWaitingOrBackground(int32_t serial);
 
-    /*
+    /**
      * Hang up waiting or held (like AT+CHLD=1)
      * After this HANGUP request returns, Radio must show the connection is NOT
      * active anymore in next getCurrentCalls query.
@@ -208,7 +208,7 @@
      */
     oneway hangupForegroundResumeBackground(int32_t serial);
 
-    /*
+    /**
      * Switch waiting or holding call and active call (like AT+CHLD=2)
      * State transitions must be as follows:
      *
@@ -229,7 +229,7 @@
      */
     oneway switchWaitingOrHoldingAndActive(int32_t serial);
 
-    /*
+    /**
      * Conference holding and active (like AT+CHLD=3)
      *
      * @param serial Serial number of request.
@@ -239,7 +239,7 @@
      */
     oneway conference(int32_t serial);
 
-    /*
+    /**
      * Send UDUB (user determined user busy) to ringing or
      * waiting call answer)
      *
@@ -250,7 +250,7 @@
      */
     oneway rejectCall(int32_t serial);
 
-    /*
+    /**
      * Requests the failure cause code for the most recently terminated call.
      *
      * @param serial Serial number of request.
@@ -260,7 +260,7 @@
      */
     oneway getLastCallFailCause(int32_t serial);
 
-    /*
+    /**
      * Requests current signal strength and associated information.
      * Must succeed if radio is on.
      *
@@ -270,7 +270,7 @@
      */
     oneway getSignalStrength(int32_t serial);
 
-    /*
+    /**
      * Request current voice registration state
      *
      * @param serial Serial number of request.
@@ -279,7 +279,7 @@
      */
     oneway getVoiceRegistrationState(int32_t serial);
 
-    /*
+    /**
      * Request current data registration state
      *
      * @param serial Serial number of request.
@@ -288,7 +288,7 @@
      */
     oneway getDataRegistrationState(int32_t serial);
 
-    /*
+    /**
      * Request current operator ONS or EONS
      *
      * @param serial Serial number of request.
@@ -297,7 +297,7 @@
      */
     oneway getOperator(int32_t serial);
 
-    /*
+    /**
      * Toggle radio on and off (for "airplane" mode)
      * If the radio is turned off/on the radio modem subsystem
      * is expected return to an initialized state. For instance,
@@ -311,7 +311,7 @@
      */
     oneway setRadioPower(int32_t serial, bool on);
 
-    /*
+    /**
      * Send a DTMF tone
      *
      * If the implementation is currently playing a tone requested via
@@ -325,7 +325,7 @@
      */
     oneway sendDtmf(int32_t serial, string s);
 
-    /*
+    /**
      * Send an SMS message
      *
      * @param serial Serial number of request.
@@ -339,7 +339,7 @@
      */
     oneway sendSms(int32_t serial, GsmSmsMessage message);
 
-    /*
+    /**
      * Send an SMS message. Identical to sendSms,
      * except that more messages are expected to be sent soon. If possible,
      * keep SMS relay protocol link open (eg TS 27.005 AT+CMMS command)
@@ -355,7 +355,7 @@
      */
     oneway sendSMSExpectMore(int32_t serial, GsmSmsMessage message);
 
-    /*
+    /**
      * Setup a packet data connection. If DataCallResponse.status
      * return DataCallFailCause:NONE it is added to the list of data calls and a
      * unsolDataCallListChanged() is sent. The call remains in the
@@ -391,7 +391,7 @@
             DataProfileInfo dataProfileInfo, bool modemCognitive, bool roamingAllowed,
             bool isRoaming);
 
-    /*
+    /**
      * Request ICC I/O operation.
      * This is similar to the TS 27.007 "restricted SIM" operation
      * where it assumes all of the EF selection must be done by the
@@ -411,7 +411,7 @@
      */
     oneway iccIOForApp(int32_t serial, IccIo iccIo);
 
-    /*
+    /**
      * Send a USSD message.
      *
      * If a USSD session already exists, the message must be sent in the
@@ -434,7 +434,7 @@
      */
     oneway sendUssd(int32_t serial, string ussd);
 
-    /*
+    /**
      * Cancel the current USSD session if one exists.
      *
      * @param serial Serial number of request.
@@ -443,7 +443,7 @@
      */
     oneway cancelPendingUssd(int32_t serial);
 
-    /*
+    /**
      * Gets current CLIR status
      *
      * @param serial Serial number of request.
@@ -452,7 +452,7 @@
      */
     oneway getClir(int32_t serial);
 
-    /*
+    /**
      * Set current CLIR status
      *
      * @param serial Serial number of request.
@@ -462,7 +462,7 @@
      */
     oneway setClir(int32_t serial, int32_t status);
 
-    /*
+    /**
      * Request call forward status.
      *
      * @param serial Serial number of request.
@@ -473,7 +473,7 @@
     oneway getCallForwardStatus(int32_t serial,
             CallForwardInfo callInfo);
 
-    /*
+    /**
      * Configure call forward rule
      *
      * @param serial Serial number of request.
@@ -483,7 +483,7 @@
      */
     oneway setCallForward(int32_t serial, CallForwardInfo callInfo);
 
-    /*
+    /**
      * Query current call waiting state
      *
      * @param serial Serial number of request.
@@ -493,7 +493,7 @@
      */
     oneway getCallWaiting(int32_t serial, int32_t serviceClass);
 
-    /*
+    /**
      * Configure current call waiting state
      *
      * @param serial Serial number of request.
@@ -505,7 +505,7 @@
     oneway setCallWaiting(int32_t serial, bool enable,
             int32_t serviceClass);
 
-    /*
+    /**
      * Acknowledge successful or failed receipt of SMS previously indicated
      * via unsolResponseNewSms
      *
@@ -521,7 +521,7 @@
     oneway acknowledgeLastIncomingGsmSms(int32_t serial, bool success,
             SmsAcknowledgeFailCause cause);
 
-    /*
+    /**
      * Answer incoming call
      * Must not be called for WAITING calls.
      * switchWaitingOrHoldingAndActive() must be used in this case
@@ -533,7 +533,7 @@
      */
     oneway acceptCall(int32_t serial);
 
-    /*
+    /**
      * Deactivate packet data connection and remove from the
      * data call list if RadioError:NONE is returned. Any other return
      * values must also try to remove the call from the list. An
@@ -551,7 +551,7 @@
     oneway deactivateDataCall(int32_t serial, int32_t cid,
             bool reasonRadioShutDown);
 
-    /*
+    /**
      * Query the status of a facility lock state
      *
      * @param serial Serial number of request.
@@ -567,7 +567,7 @@
     oneway getFacilityLockForApp(int32_t serial, string facility,
             string password, int32_t serviceClass, string appId);
 
-    /*
+    /**
      * Enable/disable one facility lock
      *
      * @param serial Serial number of request.
@@ -585,7 +585,7 @@
     oneway setFacilityLockForApp(int32_t serial, string facility, bool lockState,
             string password, int32_t serviceClass, string appId);
 
-    /*
+    /**
      * Change call barring facility password
      *
      * @param serial Serial number of request.
@@ -598,7 +598,7 @@
     oneway setBarringPassword(int32_t serial, string facility,
             string oldPassword, string newPassword);
 
-    /*
+    /**
      * Query current network selection mode
      *
      * @param serial Serial number of request.
@@ -607,7 +607,7 @@
      */
     oneway getNetworkSelectionMode(int32_t serial);
 
-    /*
+    /**
      * Specify that the network must be selected automatically.
      * This request must not respond until the new operator is selected and registered.
      *
@@ -617,7 +617,7 @@
      */
     oneway setNetworkSelectionModeAutomatic(int32_t serial);
 
-    /*
+    /**
      * Manually select a specified network.
      * This request must not respond until the new operator is selected and registered.
      *
@@ -628,7 +628,7 @@
      */
     oneway setNetworkSelectionModeManual(int32_t serial, string operatorNumeric);
 
-    /*
+    /**
      * Scans for available networks
      *
      * @param serial Serial number of request.
@@ -637,7 +637,7 @@
      */
     oneway getAvailableNetworks(int32_t serial);
 
-    /*
+    /**
      * Start playing a DTMF tone. Continue playing DTMF tone until
      * stopDtmf is received.
      * If a startDtmf() is received while a tone is currently playing,
@@ -650,7 +650,7 @@
      */
     oneway startDtmf(int32_t serial, string s);
 
-    /*
+    /**
      * Stop playing a currently playing DTMF tone.
      *
      * @param serial Serial number of request.
@@ -659,7 +659,7 @@
      */
     oneway stopDtmf(int32_t serial);
 
-    /*
+    /**
      * Return string value indicating baseband version, eg response from AT+CGMR
      *
      * @param serial Serial number of request.
@@ -668,7 +668,7 @@
      */
     oneway getBasebandVersion(int32_t serial);
 
-    /*
+    /**
      * Separate a party from a multiparty call placing the multiparty call
      * (less the specified party) on hold and leaving the specified party
      * as the only other member of the current (active) call
@@ -686,7 +686,7 @@
      */
     oneway separateConnection(int32_t serial, int32_t gsmIndex);
 
-    /*
+    /**
      * Turn on or off uplink (microphone) mute.
      * Must only be sent while voice call is active.
      * Must always be reset to "disable mute" when a new voice call is initiated
@@ -698,7 +698,7 @@
      */
     oneway setMute(int32_t serial, bool enable);
 
-    /*
+    /**
      * Queries the current state of the uplink mute setting
      *
      * @param serial Serial number of request.
@@ -707,7 +707,7 @@
      */
     oneway getMute(int32_t serial);
 
-    /*
+    /**
      * Queries the status of the CLIP supplementary service
      * (for MMI code "*#30#")
      *
@@ -717,7 +717,7 @@
      */
     oneway getClip(int32_t serial);
 
-    /*
+    /**
      * Returns the data call list. An entry is added when a
      * setupDataCall() is issued and removed on a
      * deactivateDataCall(). The list is emptied when
@@ -729,7 +729,7 @@
      */
     oneway getDataCallList(int32_t serial);
 
-    /*
+    /**
      * Enables/disables supplementary service related notifications from the network.
      * Notifications are reported via unsolSuppSvcNotification().
      *
@@ -740,7 +740,7 @@
      */
     oneway setSuppServiceNotifications(int32_t serial, bool enable);
 
-    /*
+    /**
      * Stores a SMS message to SIM memory.
      *
      * @param serial Serial number of request.
@@ -750,7 +750,7 @@
      */
     oneway writeSmsToSim(int32_t serial, SmsWriteArgs smsWriteArgs);
 
-    /*
+    /**
      * Deletes a SMS message from SIM memory.
      *
      * @param serial Serial number of request.
@@ -760,7 +760,7 @@
      */
     oneway deleteSmsOnSim(int32_t serial, int32_t index);
 
-    /*
+    /**
      * Assign a specified band for RF configuration.
      *
      * @param serial Serial number of request.
@@ -770,7 +770,7 @@
      */
     oneway setBandMode(int32_t serial, RadioBandMode mode);
 
-    /*
+    /**
      * Get the list of band modes supported by RF.
      *
      * @param serial Serial number of request.
@@ -779,7 +779,7 @@
      */
     oneway getAvailableBandModes(int32_t serial);
 
-    /*
+    /**
      * Requests to send a SAT/USAT envelope command to SIM.
      * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111
      *
@@ -790,7 +790,7 @@
      */
     oneway sendEnvelope(int32_t serial, string command);
 
-    /*
+    /**
      * Requests to send a terminal response to SIM for a received proactive command
      *
      * @param serial Serial number of request.
@@ -801,7 +801,7 @@
      */
     oneway sendTerminalResponseToSim(int32_t serial, string commandResponse);
 
-    /*
+    /**
      * When STK application gets stkCallSetup(), the call actually has
      * been initialized by mobile device already. (We could see the call has been in the 'call
      * list') So, STK application needs to accept/reject the call according to user
@@ -815,7 +815,7 @@
     oneway handleStkCallSetupRequestFromSim(int32_t serial,
             bool accept);
 
-    /*
+    /**
      * Connects the two calls and disconnects the subscriber from both calls.
      *
      * @param serial Serial number of request.
@@ -824,7 +824,7 @@
      */
     oneway explicitCallTransfer(int32_t serial);
 
-    /*
+    /**
      * Requests to set the preferred network type for searching and registering
      * (CS/PS domain, RAT, and operation mode)
      *
@@ -836,7 +836,7 @@
     oneway setPreferredNetworkType(int32_t serial,
             PreferredNetworkType nwType);
 
-    /*
+    /**
      * Query the preferred network type (CS/PS domain, RAT, and operation mode)
      * for searching and registering
      *
@@ -846,7 +846,7 @@
      */
     oneway getPreferredNetworkType(int32_t serial);
 
-    /*
+    /**
      * Request neighboring cell id in GSM network
      *
      * @param serial Serial number of request.
@@ -855,7 +855,7 @@
      */
     oneway getNeighboringCids(int32_t serial);
 
-    /*
+    /**
      * Enables/disables network state change notifications due to changes in
      * LAC and/or CID (for GSM) or BID/SID/NID/latitude/longitude (for CDMA).
      * Basically +CREG=2 vs. +CREG=1 (TS 27.007).
@@ -869,7 +869,7 @@
      */
     oneway setLocationUpdates(int32_t serial, bool enable);
 
-    /*
+    /**
      * Request to set the location where the CDMA subscription shall
      * be retrieved
      *
@@ -881,7 +881,7 @@
     oneway setCdmaSubscriptionSource(int32_t serial,
             CdmaSubscriptionSource cdmaSub);
 
-    /*
+    /**
      * Request to set the roaming preferences in CDMA
      *
      * @param serial Serial number of request.
@@ -892,7 +892,7 @@
     oneway setCdmaRoamingPreference(int32_t serial,
             CdmaRoamingType type);
 
-    /*
+    /**
      * Request the actual setting of the roaming preferences in CDMA in the modem
      *
      * @param serial Serial number of request.
@@ -901,7 +901,7 @@
      */
     oneway getCdmaRoamingPreference(int32_t serial);
 
-    /*
+    /**
      * Request to set the TTY mode
      *
      * @param serial Serial number of request.
@@ -911,7 +911,7 @@
      */
     oneway setTTYMode(int32_t serial, TtyMode mode);
 
-    /*
+    /**
      * Request the setting of TTY mode
      *
      * @param serial Serial number of request.
@@ -920,7 +920,7 @@
      */
     oneway getTTYMode(int32_t serial);
 
-    /*
+    /**
      * Request to set the preferred voice privacy mode used in voice scrambling.
      *
      * @param serial Serial number of request.
@@ -931,7 +931,7 @@
      */
     oneway setPreferredVoicePrivacy(int32_t serial, bool enable);
 
-    /*
+    /**
      * Request the setting of preferred voice privacy mode.
      *
      * @param serial Serial number of request.
@@ -940,7 +940,7 @@
      */
     oneway getPreferredVoicePrivacy(int32_t serial);
 
-    /*
+    /**
      * Send FLASH command
      *
      * @param serial Serial number of request.
@@ -950,7 +950,7 @@
      */
     oneway sendCDMAFeatureCode(int32_t serial, string featureCode);
 
-    /*
+    /**
      * Send DTMF string
      *
      * @param serial Serial number of request.
@@ -962,7 +962,7 @@
      */
     oneway sendBurstDtmf(int32_t serial, string dtmf, int32_t on, int32_t off);
 
-    /*
+    /**
      * Send a CDMA SMS message
      *
      * @param serial Serial number of request.
@@ -972,7 +972,7 @@
      */
     oneway sendCdmaSms(int32_t serial, CdmaSmsMessage sms);
 
-    /*
+    /**
      * Acknowledge the success or failure in the receipt of SMS
      * previously indicated via responseCdmaNewSms()
      *
@@ -983,7 +983,7 @@
      */
     oneway acknowledgeLastIncomingCdmaSms(int32_t serial, CdmaSmsAck smsAck);
 
-    /*
+    /**
      * Request the setting of GSM/WCDMA Cell Broadcast SMS config.
      *
      * @param serial Serial number of request.
@@ -992,7 +992,7 @@
      */
     oneway getGsmBroadcastConfig(int32_t serial);
 
-    /*
+    /**
      * Set GSM/WCDMA Cell Broadcast SMS config
      *
      * @param serial Serial number of request.
@@ -1002,7 +1002,7 @@
      */
     oneway setGsmBroadcastConfig(int32_t serial, vec<GsmBroadcastSmsConfigInfo> configInfo);
 
-    /*
+    /**
      * Enable or disable the reception of GSM/WCDMA Cell Broadcast SMS
      *
      * @param serial Serial number of request.
@@ -1013,7 +1013,7 @@
      */
     oneway setGsmBroadcastActivation(int32_t serial, bool activate);
 
-    /*
+    /**
      * Request the setting of CDMA Broadcast SMS config
      *
      * @param serial Serial number of request.
@@ -1022,7 +1022,7 @@
      */
     oneway getCdmaBroadcastConfig(int32_t serial);
 
-    /*
+    /**
      * Set CDMA Broadcast SMS config
      *
      * @param serial Serial number of request.
@@ -1032,7 +1032,7 @@
      */
     oneway setCdmaBroadcastConfig(int32_t serial, vec<CdmaBroadcastSmsConfigInfo> configInfo);
 
-    /*
+    /**
      * Enable or disable the reception of CDMA Cell Broadcast SMS
      *
      * @param serial Serial number of request.
@@ -1043,7 +1043,7 @@
      */
     oneway setCdmaBroadcastActivation(int32_t serial, bool activate);
 
-    /*
+    /**
      * Request the device MDN / H_SID / H_NID.
      * The request is only allowed when CDMA subscription is available. When CDMA
      * subscription is changed, application layer must re-issue the request to
@@ -1055,7 +1055,7 @@
      */
     oneway getCDMASubscription(int32_t serial);
 
-    /*
+    /**
      * Stores a CDMA SMS message to RUIM memory.
      *
      * @param serial Serial number of request.
@@ -1065,7 +1065,7 @@
      */
     oneway writeSmsToRuim(int32_t serial, CdmaSmsWriteArgs cdmaSms);
 
-    /*
+    /**
      * Deletes a CDMA SMS message from RUIM memory.
      *
      * @param serial Serial number of request.
@@ -1075,7 +1075,7 @@
      */
     oneway deleteSmsOnRuim(int32_t serial, int32_t index);
 
-    /*
+    /**
      * Request the device ESN / MEID / IMEI / IMEISV.
      * The request is always allowed and contains GSM and CDMA device identity.
      * When CDMA subscription is changed the ESN/MEID changes. The application
@@ -1087,7 +1087,7 @@
      */
     oneway getDeviceIdentity(int32_t serial);
 
-    /*
+    /**
      * Request the radio's system selection module to exit emergency
      * callback mode. Radio must not respond with SUCCESS until the modem has
      * completely exited from Emergency Callback Mode.
@@ -1098,7 +1098,7 @@
      */
     oneway exitEmergencyCallbackMode(int32_t serial);
 
-    /*
+    /**
      * Get the default Short Message Service Center address on the device.
      *
      * @param serial Serial number of request.
@@ -1107,7 +1107,7 @@
      */
     oneway getSmscAddress(int32_t serial);
 
-    /*
+    /**
      * Set the default Short Message Service Center address on the device.
      *
      * @param serial Serial number of request.
@@ -1117,7 +1117,7 @@
      */
     oneway setSmscAddress(int32_t serial, string smsc);
 
-    /*
+    /**
      * Indicates whether there is storage available for new SMS messages.
      *
      * @param serial Serial number of request.
@@ -1128,7 +1128,7 @@
      */
     oneway reportSmsMemoryStatus(int32_t serial, bool available);
 
-    /*
+    /**
      * Indicates that the StkService is running and is
      * ready to receive unsolicited stkXXXXX commands.
      *
@@ -1138,7 +1138,7 @@
      */
     oneway reportStkServiceIsRunning(int32_t serial);
 
-    /*
+    /**
      * Request to query the location where the CDMA subscription shall be retrieved.
      *
      * @param serial Serial number of request.
@@ -1147,7 +1147,7 @@
      */
     oneway getCdmaSubscriptionSource(int32_t serial);
 
-    /*
+    /**
      * Request the ISIM application on the UICC to perform AKA
      * challenge/response algorithm for IMS authentication
      *
@@ -1158,7 +1158,7 @@
      */
     oneway requestIsimAuthentication(int32_t serial, string challenge);
 
-    /*
+    /**
      * Acknowledge successful or failed receipt of SMS previously indicated
      * via unsol responseNewSms(), including acknowledgement TPDU to send
      * as the RP-User-Data element of the RP-ACK or RP-ERROR PDU.
@@ -1172,7 +1172,7 @@
      */
     oneway acknowledgeIncomingGsmSmsWithPdu(int32_t serial, bool success, string ackPdu);
 
-    /*
+    /**
      * Requests to send a SAT/USAT envelope command to SIM.
      * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111.
      *
@@ -1191,7 +1191,7 @@
      */
     oneway sendEnvelopeWithStatus(int32_t serial, string contents);
 
-    /*
+    /**
      * Query the radio technology type (3GPP/3GPP2) used for voice. Query is valid only
      * when radio state is not RADIO_STATE_UNAVAILABLE
      *
@@ -1201,7 +1201,7 @@
      */
     oneway getVoiceRadioTechnology(int32_t serial);
 
-    /*
+    /**
      * Request all of the current cell information known to the radio. The radio
      * must return list of all current cells, including the neighboring cells. If for a particular
      * cell information isn't known then the appropriate unknown value will be returned.
@@ -1213,7 +1213,7 @@
      */
     oneway getCellInfoList(int32_t serial);
 
-    /*
+    /**
      * Sets the minimum time between when unsolicited cellInfoList() must be invoked.
      * A value of 0, means invoke cellInfoList() when any of the reported
      * information changes. Setting the value to INT_MAX(0x7fffffff) means never issue
@@ -1226,7 +1226,7 @@
      */
     oneway setCellInfoListRate(int32_t serial, int32_t rate);
 
-    /*
+    /**
      * Set an apn to initial attach network
      *
      * @param serial Serial number of request.
@@ -1243,7 +1243,7 @@
     oneway setInitialAttachApn(int32_t serial, DataProfileInfo dataProfileInfo,
             bool modemCognitive, bool isRoaming);
 
-    /*
+    /**
      * Request current IMS registration state
      *
      * @param serial Serial number of request.
@@ -1252,7 +1252,7 @@
      */
     oneway getImsRegistrationState(int32_t serial);
 
-    /*
+    /**
      * Send a SMS message over IMS.
      * Based on the return error, caller decides to resend if sending sms
      * fails. SMS_SEND_FAIL_RETRY means retry, and other errors means no retry.
@@ -1265,7 +1265,7 @@
      */
     oneway sendImsSms(int32_t serial, ImsSmsMessage message);
 
-    /*
+    /**
      * Request APDU exchange on the basic channel. This command reflects TS 27.007
      * "generic SIM access" operation (+CSIM). The modem must ensure proper function
      * of GSM/CDMA, and filter commands appropriately. It must filter
@@ -1279,7 +1279,7 @@
      */
     oneway iccTransmitApduBasicChannel(int32_t serial, SimApdu message);
 
-    /*
+    /**
      * Open a new logical channel and select the given application. This command
      * reflects TS 27.007 "open logical channel" operation (+CCHO).
      *
@@ -1290,7 +1290,7 @@
      */
     oneway iccOpenLogicalChannel(int32_t serial, string aid);
 
-    /*
+    /**
      * Close a previously opened logical channel. This command reflects TS 27.007
      * "close logical channel" operation (+CCHC).
      *
@@ -1301,7 +1301,7 @@
      */
     oneway iccCloseLogicalChannel(int32_t serial, int32_t channelId);
 
-    /*
+    /**
      * Exchange APDUs with a UICC over a previously opened logical channel. This
      * command reflects TS 27.007 "generic logical channel access" operation
      * (+CGLA). The modem must filter channel management and SELECT by DF name
@@ -1314,7 +1314,7 @@
      */
     oneway iccTransmitApduLogicalChannel(int32_t serial, SimApdu message);
 
-    /*
+    /**
      * Read one of the radio NV items.
      * This is used for device configuration by some CDMA operators.
      *
@@ -1325,7 +1325,7 @@
      */
     oneway nvReadItem(int32_t serial, NvItem itemId);
 
-    /*
+    /**
      * Write one of the radio NV items.
      * This is used for device configuration by some CDMA operators.
      *
@@ -1336,7 +1336,7 @@
      */
     oneway nvWriteItem(int32_t serial, NvWriteItem item);
 
-    /*
+    /**
      * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
      * This is used for device configuration by some CDMA operators.
      *
@@ -1347,7 +1347,7 @@
      */
     oneway nvWriteCdmaPrl(int32_t serial, vec<uint8_t> prl);
 
-    /*
+    /**
      * Reset the radio NV configuration to the factory state.
      * This is used for device configuration by some CDMA operators.
      *
@@ -1358,7 +1358,7 @@
      */
     oneway nvResetConfig(int32_t serial, ResetNvType resetType);
 
-    /*
+    /**
      * Selection/de-selection of a subscription from a SIM card
      *
      * @param serial Serial number of request.
@@ -1368,7 +1368,7 @@
      */
     oneway setUiccSubscription(int32_t serial, SelectUiccSub uiccSub);
 
-    /*
+    /**
      * Tells the modem whether data calls are allowed or not
      *
      * @param serial Serial number of request.
@@ -1378,7 +1378,7 @@
      */
     oneway setDataAllowed(int32_t serial, bool allow);
 
-    /*
+    /**
      * Request all of the current hardware (modem and sim) associated with Radio.
      *
      * @param serial Serial number of request.
@@ -1387,7 +1387,7 @@
      */
     oneway getHardwareConfig(int32_t serial);
 
-    /*
+    /**
      * Returns the response of SIM Authentication through Radio challenge request.
      *
      * @param serial Serial number of request.
@@ -1401,7 +1401,7 @@
     oneway requestIccSimAuthentication(int32_t serial, int32_t authContext, string authData,
             string aid);
 
-    /*
+    /**
      * Set data profile in modem.
      * Modem must erase existed profiles from framework, and apply new profiles
      *
@@ -1416,7 +1416,7 @@
      */
     oneway setDataProfile(int32_t serial, vec<DataProfileInfo> profiles, bool isRoaming);
 
-    /*
+    /**
      * Device is shutting down. All further commands are ignored
      * and RADIO_NOT_AVAILABLE must be returned.
      *
@@ -1426,7 +1426,7 @@
      */
     oneway requestShutdown(int32_t serial);
 
-    /*
+    /**
      * Used to get phone radio capability.
      *
      * @param serial Serial number of request.
@@ -1435,7 +1435,7 @@
      */
     oneway getRadioCapability(int32_t serial);
 
-    /*
+    /**
      * Used to set the phones radio capability. Be VERY careful
      * using this request as it may cause some vendor modems to reset. Because
      * of the possible modem reset any radio commands after this one may not be
@@ -1448,7 +1448,7 @@
      */
     oneway setRadioCapability(int32_t serial, RadioCapability rc);
 
-    /*
+    /**
      * Start Link Capacity Estimate (LCE) service if supported by the radio.
      *
      * @param serial Serial number of request.
@@ -1459,7 +1459,7 @@
      */
     oneway startLceService(int32_t serial, int32_t reportInterval, bool pullMode);
 
-    /*
+    /**
      * Stop Link Capacity Estimate (LCE) service, the STOP operation must be
      * idempotent for the radio modem.
      *
@@ -1469,7 +1469,7 @@
      */
     oneway stopLceService(int32_t serial);
 
-    /*
+    /**
      * Pull LCE service for capacity information.
      *
      * @param serial Serial number of request.
@@ -1478,7 +1478,7 @@
      */
     oneway pullLceData(int32_t serial);
 
-    /*
+    /**
      * Get modem activity information for power consumption estimation.
      * Request clear-on-read statistics information that is used for
      * estimating the per-millisecond power consumption of the cellular
@@ -1490,7 +1490,7 @@
      */
     oneway getModemActivityInfo(int32_t serial);
 
-    /*
+    /**
      * Set carrier restrictions. Expected modem behavior:
      *  If never receives this command
      *  - Must allow all carriers
@@ -1514,7 +1514,7 @@
      */
     oneway setAllowedCarriers(int32_t serial, bool allAllowed, CarrierRestrictions carriers);
 
-    /*
+    /**
      * Get carrier restrictions.
      *
      * @param serial Serial number of request.
@@ -1523,7 +1523,7 @@
      */
     oneway getAllowedCarriers(int32_t serial);
 
-    /*
+    /**
      * Send the updated device state.
      * This is providing the device state information for the modem to perform power saving
      * strategies.
@@ -1536,7 +1536,7 @@
      */
     oneway sendDeviceState(int32_t serial, DeviceStateType deviceStateType, bool state);
 
-    /*
+    /**
      * Set the indication filter.
      * This is used to prevent unnecessary application processor wake up for power saving purposes
      * by suppressing the indications in certain scenarios.
@@ -1549,7 +1549,7 @@
      */
     oneway setIndicationFilter(int32_t serial, bitfield<IndicationFilter> indicationFilter);
 
-    /*
+    /**
      * Set SIM card power state.
      * Request is equivalent to inserting or removing the card.
      *
@@ -1563,7 +1563,7 @@
      */
     oneway setSimCardPower(int32_t serial, bool powerUp);
 
-    /*
+    /**
      * When response type received from a radio indication or radio response is
      * RadioIndicationType:UNSOLICITED_ACK_EXP or RadioResponseType:SOLICITED_ACK_EXP respectively,
      * acknowledge the receipt of those messages by sending responseAcknowledgement().
diff --git a/radio/1.0/IRadioIndication.hal b/radio/1.0/IRadioIndication.hal
index 0b95821..eb07226 100644
--- a/radio/1.0/IRadioIndication.hal
+++ b/radio/1.0/IRadioIndication.hal
@@ -16,11 +16,11 @@
 
 package android.hardware.radio@1.0;
 
-/*
+/**
  * Interface declaring unsolicited radio indications.
  */
 interface IRadioIndication {
-    /*
+    /**
      * Indicates when radio state changes.
      *
      * @param type Type of radio indication
@@ -28,7 +28,7 @@
      */
     oneway radioStateChanged(RadioIndicationType type, RadioState radioState);
 
-    /*
+    /**
      * Indicates when call state has changed.
      * Callee must invoke IRadio.getCurrentCalls()
      * Must be invoked on, for example,
@@ -41,7 +41,7 @@
      */
     oneway callStateChanged(RadioIndicationType type);
 
-    /*
+    /**
      * Indicates when voice or data network state changed
      * Callee must invoke IRadio.getVoiceRegistrationState(), IRadio.getDataRegistrationState(),
      * and IRadio.getOperator()
@@ -50,7 +50,7 @@
      */
     oneway networkStateChanged(RadioIndicationType type);
 
-    /*
+    /**
      * Indicates when new SMS is received.
      * Callee must subsequently confirm the receipt of the SMS with a
      * acknowledgeLastIncomingGsmSms()
@@ -64,7 +64,7 @@
      */
     oneway newSms(RadioIndicationType type, vec<uint8_t> pdu);
 
-    /*
+    /**
      * Indicates when new SMS Status Report is received.
      * Callee must subsequently confirm the receipt of the SMS with a
      * acknowledgeLastIncomingGsmSms()
@@ -78,7 +78,7 @@
      */
     oneway newSmsStatusReport(RadioIndicationType type, vec<uint8_t> pdu);
 
-    /*
+    /**
      * Indicates when new SMS has been stored on SIM card
      *
      * @param type Type of radio indication
@@ -86,7 +86,7 @@
      */
     oneway newSmsOnSim(RadioIndicationType type, int32_t recordNumber);
 
-    /*
+    /**
      * Indicates when a new USSD message is received.
      * The USSD session is assumed to persist if the type code is REQUEST, otherwise
      * the current session (if any) is assumed to have terminated.
@@ -97,7 +97,7 @@
      */
     oneway onUssd(RadioIndicationType type, UssdModeType modeType, string msg);
 
-    /*
+    /**
      * Indicates when radio has received a NITZ time message.
      *
      * @param type Type of radio indication
@@ -106,7 +106,7 @@
      */
     oneway nitzTimeReceived(RadioIndicationType type, string nitzTime, uint64_t receivedTime);
 
-    /*
+    /**
      * Indicates current signal strength of the radio.
      *
      * @param type Type of radio indication
@@ -114,7 +114,7 @@
      */
     oneway currentSignalStrength(RadioIndicationType type, SignalStrength signalStrength);
 
-    /*
+    /**
      * Indicates data call contexts have changed.
      *
      * @param type Type of radio indication
@@ -127,7 +127,7 @@
      */
     oneway dataCallListChanged(RadioIndicationType type, vec<SetupDataCallResult> dcList);
 
-    /*
+    /**
      * Reports supplementary service related notification from the network.
      *
      * @param type Type of radio indication
@@ -135,14 +135,14 @@
      */
     oneway suppSvcNotify(RadioIndicationType type, SuppSvcNotification suppSvc);
 
-    /*
+    /**
      * Indicates when STK session is terminated by SIM.
      *
      * @param type Type of radio indication
      */
     oneway stkSessionEnd(RadioIndicationType type);
 
-    /*
+    /**
      * Indicates when SIM issue a STK proactive command to applications
      *
      * @param type Type of radio indication
@@ -151,7 +151,7 @@
      */
     oneway stkProactiveCommand(RadioIndicationType type, string cmd);
 
-    /*
+    /**
      * Indicates when SIM notifies applcations some event happens.
      *
      * @param type Type of radio indication
@@ -162,7 +162,7 @@
      */
     oneway stkEventNotify(RadioIndicationType type, string cmd);
 
-    /*
+    /**
      * Indicates when SIM wants application to setup a voice call.
      *
      * @param type Type of radio indication
@@ -170,7 +170,7 @@
      */
     oneway stkCallSetup(RadioIndicationType type, int64_t timeout);
 
-    /*
+    /**
      * Indicates that SMS storage on the SIM is full. Sent when the network
      * attempts to deliver a new SMS message. Messages cannot be saved on the
      * SIM until space is freed. In particular, incoming Class 2 messages must not
@@ -180,7 +180,7 @@
      */
     oneway simSmsStorageFull(RadioIndicationType type);
 
-    /*
+    /**
      * Indicates that file(s) on the SIM have been updated, or the SIM
      * has been reinitialized.
      * Note: If the SIM state changes as a result of the SIM refresh (eg,
@@ -192,7 +192,7 @@
      */
     oneway simRefresh(RadioIndicationType type, SimRefreshResult refreshResult);
 
-    /*
+    /**
      * Ring indication for an incoming call (eg, RING or CRING event).
      * There must be at least one callRing() at the beginning
      * of a call and sending multiple is optional. If the system property
@@ -210,7 +210,7 @@
      */
     oneway callRing(RadioIndicationType type, bool isGsm, CdmaSignalInfoRecord record);
 
-    /*
+    /**
      * Indicates that SIM state changes.
      * Callee must invoke getIccCardStatus()
      *
@@ -218,7 +218,7 @@
      */
     oneway simStatusChanged(RadioIndicationType type);
 
-    /*
+    /**
      * Indicates when new CDMA SMS is received
      * Callee must subsequently confirm the receipt of the SMS with
      * acknowledgeLastIncomingCdmaSms()
@@ -230,7 +230,7 @@
      */
     oneway cdmaNewSms(RadioIndicationType type, CdmaSmsMessage msg);
 
-    /*
+    /**
      * Indicates when new Broadcast SMS is received
      *
      * @param type Type of radio indication
@@ -243,7 +243,7 @@
      */
     oneway newBroadcastSms(RadioIndicationType type, vec<uint8_t> data);
 
-    /*
+    /**
      * Indicates that SMS storage on the RUIM is full. Messages
      * cannot be saved on the RUIM until space is freed.
      *
@@ -251,7 +251,7 @@
      */
     oneway cdmaRuimSmsStorageFull(RadioIndicationType type);
 
-    /*
+    /**
      * Indicates a restricted state change (eg, for Domain Specific Access Control).
      * Radio must send this msg after radio off/on cycle no matter it is changed or not.
      *
@@ -260,7 +260,7 @@
      */
     oneway restrictedStateChanged(RadioIndicationType type, PhoneRestrictedState state);
 
-    /*
+    /**
      * Indicates that the radio system selection module has
      * autonomously entered emergency callback mode.
      *
@@ -268,7 +268,7 @@
      */
     oneway enterEmergencyCallbackMode(RadioIndicationType type);
 
-    /*
+    /**
      * Indicates when CDMA radio receives a call waiting indication.
      *
      * @param type Type of radio indication
@@ -276,7 +276,7 @@
      */
     oneway cdmaCallWaiting(RadioIndicationType type, CdmaCallWaiting callWaitingRecord);
 
-    /*
+    /**
      * Indicates when CDMA radio receives an update of the progress of an OTASP/OTAPA call.
      *
      * @param type Type of radio indication
@@ -284,7 +284,7 @@
      */
     oneway cdmaOtaProvisionStatus(RadioIndicationType type, CdmaOtaProvisionStatus status);
 
-   /*
+   /**
     * Indicates when CDMA radio receives one or more info recs.
     *
     * @param type Type of radio indication
@@ -292,7 +292,7 @@
     */
    oneway cdmaInfoRec(RadioIndicationType type, CdmaInformationRecords records);
 
-   /*
+   /**
     * Indicates that nework doesn't have in-band information, need to
     * play out-band tone.
     *
@@ -301,14 +301,14 @@
     */
    oneway indicateRingbackTone(RadioIndicationType type, bool start);
 
-   /*
+   /**
     * Indicates that framework/application must reset the uplink mute state.
     *
     * @param type Type of radio indication
     */
    oneway resendIncallMute(RadioIndicationType type);
 
-   /*
+   /**
     * Indicates when CDMA subscription source changed.
     *
     * @param type Type of radio indication
@@ -317,7 +317,7 @@
    oneway cdmaSubscriptionSourceChanged(RadioIndicationType type,
            CdmaSubscriptionSource cdmaSource);
 
-   /*
+   /**
     * Indicates when PRL (preferred roaming list) changes.
     *
     * @param type Type of radio indication
@@ -325,7 +325,7 @@
     */
    oneway cdmaPrlChanged(RadioIndicationType type, int32_t version);
 
-   /*
+   /**
     * Indicates when Emergency Callback Mode Ends.
     * Indicates that the radio system selection module has
     * proactively exited emergency callback mode.
@@ -334,14 +334,14 @@
     */
    oneway exitEmergencyCallbackMode(RadioIndicationType type);
 
-   /*
+   /**
     * Indicates the ril connects and returns the version
     *
     * @param type Type of radio indication
     */
    oneway rilConnected(RadioIndicationType type);
 
-   /*
+   /**
     * Indicates that voice technology has changed. Responds with new rat.
     *
     * @param type Type of radio indication
@@ -349,7 +349,7 @@
     */
    oneway voiceRadioTechChanged(RadioIndicationType type, RadioTechnology rat);
 
-   /*
+   /**
     * Same information as returned by getCellInfoList().
     *
     * @param type Type of radio indication
@@ -357,7 +357,7 @@
     */
    oneway cellInfoList(RadioIndicationType type, vec<CellInfo> records);
 
-   /*
+   /**
     * Indicates when IMS registration state has changed.
     * To get IMS registration state and IMS SMS format, callee needs to invoke
     * getImsRegistrationState()
@@ -366,7 +366,7 @@
     */
    oneway imsNetworkStateChanged(RadioIndicationType type);
 
-   /*
+   /**
     * Indicated when there is a change in subscription status.
     * This event must be sent in the following scenarios
     *  - subscription readiness at modem, which was selected by telephony layer
@@ -378,7 +378,7 @@
     */
    oneway subscriptionStatusChanged(RadioIndicationType type, bool activate);
 
-   /*
+   /**
     * Indicates when Single Radio Voice Call Continuity (SRVCC)
     * progress state has changed
     *
@@ -387,7 +387,7 @@
     */
    oneway srvccStateNotify(RadioIndicationType type, SrvccState state);
 
-   /*
+   /**
     * Indicates when the hardware configuration associated with the RILd changes.
     *
     * @param type Type of radio indication
@@ -395,7 +395,7 @@
     */
    oneway hardwareConfigChanged(RadioIndicationType type, vec<HardwareConfig> configs);
 
-   /*
+   /**
     * Sent when setRadioCapability() completes.
     * Returns the phone radio capability exactly as
     * getRadioCapability() and must be the
@@ -406,7 +406,7 @@
     */
    oneway radioCapabilityIndication(RadioIndicationType type, RadioCapability rc);
 
-   /*
+   /**
     * Indicates when Supplementary service(SS) response is received when DIAL/USSD/SS is changed to
     * SS by call control.
     *
@@ -414,7 +414,7 @@
     */
    oneway onSupplementaryServiceIndication(RadioIndicationType type, StkCcUnsolSsResult ss);
 
-   /*
+   /**
     * Indicates when there is an ALPHA from UICC during Call Control.
     *
     * @param type Type of radio indication
@@ -422,7 +422,7 @@
     */
    oneway stkCallControlAlphaNotify(RadioIndicationType type, string alpha);
 
-   /*
+   /**
     * Indicates when there is an incoming Link Capacity Estimate (LCE) info report.
     *
     * @param type Type of radio indication
@@ -430,7 +430,7 @@
     */
    oneway lceData(RadioIndicationType type, LceDataInfo lce);
 
-   /*
+   /**
     * Indicates when there is new Carrier PCO data received for a data call. Ideally
     * only new data must be forwarded, though this is not required. Multiple
     * boxes of carrier PCO data for a given call must result in a series of
@@ -441,7 +441,7 @@
     */
    oneway pcoData(RadioIndicationType type, PcoDataInfo pco);
 
-   /*
+   /**
     * Indicates when there is a modem reset.
     *
     * When modem restarts, one of the following radio state transitions must happen
diff --git a/radio/1.0/IRadioResponse.hal b/radio/1.0/IRadioResponse.hal
index 42e53a7..2ba210b 100644
--- a/radio/1.0/IRadioResponse.hal
+++ b/radio/1.0/IRadioResponse.hal
@@ -16,13 +16,13 @@
 
 package android.hardware.radio@1.0;
 
-/*
+/**
  * Interface declaring response functions to solicited radio requests.
  * Response functions defined in this interface are as per following convention:
  * <xyz>Response is response to IRadio.<xyz>
  */
 interface IRadioResponse {
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param cardStatus ICC card status as defined by CardStatus in types.hal
      *
@@ -31,7 +31,7 @@
      */
     oneway getIccCardStatusResponse(RadioResponseInfo info, CardStatus cardStatus);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
@@ -42,7 +42,7 @@
      */
     oneway supplyIccPinForAppResponse(RadioResponseInfo info, int32_t remainingRetries);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
@@ -53,7 +53,7 @@
      */
     oneway supplyIccPukForAppResponse(RadioResponseInfo info, int32_t remainingRetries);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
@@ -64,7 +64,7 @@
      */
     oneway supplyIccPin2ForAppResponse(RadioResponseInfo info, int32_t remainingRetries);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      * Valid errors returned:
@@ -74,7 +74,7 @@
      */
     oneway supplyIccPuk2ForAppResponse(RadioResponseInfo info, int32_t remainingRetries);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
@@ -85,7 +85,7 @@
      */
     oneway changeIccPinForAppResponse(RadioResponseInfo info, int32_t remainingRetries);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
@@ -96,7 +96,7 @@
      */
     oneway changeIccPin2ForAppResponse(RadioResponseInfo info, int32_t remainingRetries);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
@@ -107,7 +107,7 @@
      */
     oneway supplyNetworkDepersonalizationResponse(RadioResponseInfo info, int32_t remainingRetries);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param calls Current call list
      *
@@ -119,7 +119,7 @@
      */
     oneway getCurrentCallsResponse(RadioResponseInfo info, vec<Call> calls);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -144,7 +144,7 @@
      */
     oneway dialResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param imsi String containing the IMSI
      *
@@ -154,7 +154,7 @@
      */
     oneway getIMSIForAppResponse(RadioResponseInfo info, string imsi);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -169,7 +169,7 @@
      */
     oneway hangupConnectionResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -186,7 +186,7 @@
      */
     oneway hangupWaitingOrBackgroundResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -203,7 +203,7 @@
      */
     oneway hangupForegroundResumeBackgroundResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -220,7 +220,7 @@
      */
     oneway switchWaitingOrHoldingAndActiveResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -236,7 +236,7 @@
      */
     oneway conferenceResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -253,7 +253,7 @@
      */
     oneway rejectCallResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param failCauseInfo Contains LastCallFailCause and vendor cause code.
      *
@@ -297,7 +297,7 @@
     oneway getLastCallFailCauseResponse(RadioResponseInfo info,
             LastCallFailCauseInfo failCauseinfo);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param sigStrength Current signal strength
      *
@@ -307,7 +307,7 @@
      */
     oneway getSignalStrengthResponse(RadioResponseInfo info, SignalStrength sigStrength);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param voiceRegResponse Current Voice registration response as defined by VoiceRegStateResult
      *        in types.hal
@@ -319,7 +319,7 @@
     oneway getVoiceRegistrationStateResponse(RadioResponseInfo info,
             VoiceRegStateResult voiceRegResponse);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param dataRegResponse Current Data registration response as defined by DataRegStateResult in
      *        types.hal
@@ -331,7 +331,7 @@
     oneway getDataRegistrationStateResponse(RadioResponseInfo info,
             DataRegStateResult dataRegResponse);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param longName is long alpha ONS or EONS or empty string if unregistered
      * @param shortName is short alpha ONS or EONS or empty string if unregistered
@@ -344,7 +344,7 @@
     oneway getOperatorResponse(RadioResponseInfo info, string longName, string shortName,
             string numeric);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -354,7 +354,7 @@
      */
     oneway setRadioPowerResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -368,7 +368,7 @@
      */
     oneway sendDtmfResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param sms Response to sms sent as defined by SendSmsResult in types.hal
      *
@@ -391,7 +391,7 @@
      */
     oneway sendSmsResponse(RadioResponseInfo info, SendSmsResult sms);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param sms Response to sms sent as defined by SendSmsResult in types.hal
      *
@@ -415,7 +415,7 @@
      */
     oneway sendSMSExpectMoreResponse(RadioResponseInfo info, SendSmsResult sms);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param dcResponse SetupDataCallResult defined in types.hal
      *
@@ -430,7 +430,7 @@
      */
     oneway setupDataCallResponse(RadioResponseInfo info, SetupDataCallResult dcResponse);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param iccIo ICC io operation response as defined by IccIoResult in types.hal
      *
@@ -442,7 +442,7 @@
      */
     oneway iccIOForAppResponse(RadioResponseInfo info, IccIoResult iccIo);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -464,7 +464,7 @@
      */
     oneway sendUssdResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -479,7 +479,7 @@
      */
     oneway cancelPendingUssdResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param n is "n" parameter from TS 27.007 7.7
      * @param m is "m" parameter from TS 27.007 7.7
@@ -498,7 +498,7 @@
      */
     oneway getClirResponse(RadioResponseInfo info, int32_t n, int32_t m);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -513,7 +513,7 @@
      */
     oneway setClirResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param callForwardInfos points to a vector of CallForwardInfo, one for
      *        each distinct registered phone number.
@@ -541,7 +541,7 @@
     oneway getCallForwardStatusResponse(RadioResponseInfo info,
             vec<CallForwardInfo> callForwardInfos);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -560,7 +560,7 @@
      */
     oneway setCallForwardResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param enable If current call waiting state is disabled, enable = false else true
      * @param serviceClass If enable, then callWaitingResp[1]
@@ -584,7 +584,7 @@
      */
     oneway getCallWaitingResponse(RadioResponseInfo info, bool enable, int32_t serviceClass);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -602,7 +602,7 @@
      */
     oneway setCallWaitingResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -611,7 +611,7 @@
      */
     oneway acknowledgeLastIncomingGsmSmsResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -626,7 +626,7 @@
      */
     oneway acceptCallResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -635,7 +635,7 @@
      */
     oneway deactivateDataCallResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param response 0 is the TS 27.007 service class bit vector of
      *        services for which the specified barring facility
@@ -656,7 +656,7 @@
      */
     oneway getFacilityLockForAppResponse(RadioResponseInfo info, int32_t response);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param retry 0 is the number of retries remaining, or -1 if unknown
      *
@@ -675,7 +675,7 @@
      */
     oneway setFacilityLockForAppResponse(RadioResponseInfo info, int32_t retry);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -693,7 +693,7 @@
      */
     oneway setBarringPasswordResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param selection false for automatic selection, true for manual selection
      *
@@ -703,7 +703,7 @@
      */
     oneway getNetworkSelectionModeResponse(RadioResponseInfo info, bool manual);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -718,7 +718,7 @@
      */
     oneway setNetworkSelectionModeAutomaticResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -733,7 +733,7 @@
      */
     oneway setNetworkSelectionModeManualResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param networkInfos List of network operator information as OperatorInfos defined in
      *         types.hal
@@ -751,7 +751,7 @@
     oneway getAvailableNetworksResponse(RadioResponseInfo info,
             vec<OperatorInfo> networkInfos);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -767,7 +767,7 @@
      */
     oneway startDtmfResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -784,7 +784,7 @@
      */
     oneway stopDtmfResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param version string containing version string for log reporting
      *
@@ -795,7 +795,7 @@
      */
     oneway getBasebandVersionResponse(RadioResponseInfo info, string version);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -813,7 +813,7 @@
      */
     oneway separateConnectionResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -825,7 +825,7 @@
      */
     oneway setMuteResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param enable true for "mute enabled" and false for "mute disabled"
      *
@@ -840,7 +840,7 @@
      */
     oneway getMuteResponse(RadioResponseInfo info, bool enable);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param status indicates CLIP status
      *
@@ -856,7 +856,7 @@
      */
     oneway getClipResponse(RadioResponseInfo info, ClipStatus status);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param dcResponse List of DataCallResult as defined in types.hal
      *
@@ -866,7 +866,7 @@
      */
     oneway getDataCallListResponse(RadioResponseInfo info, vec<SetupDataCallResult> dcResponse);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -881,7 +881,7 @@
      */
     oneway setSuppServiceNotificationsResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param index record index where the message is stored
      *
@@ -901,7 +901,7 @@
      */
     oneway writeSmsToSimResponse(RadioResponseInfo info, int32_t index);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -916,7 +916,7 @@
      */
     oneway deleteSmsOnSimResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -926,7 +926,7 @@
      */
     oneway setBandModeResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param bandModes List of RadioBandMode listing supported modes
      *
@@ -937,7 +937,7 @@
      */
     oneway getAvailableBandModesResponse(RadioResponseInfo info, vec<RadioBandMode> bandModes);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param commandResponse SAT/USAT response in hexadecimal format
      *        string starting with first byte of response
@@ -950,7 +950,7 @@
      */
     oneway sendEnvelopeResponse(RadioResponseInfo info, string commandResponse);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -961,7 +961,7 @@
      */
     oneway sendTerminalResponseToSimResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -972,7 +972,7 @@
      */
     oneway handleStkCallSetupRequestFromSimResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -990,7 +990,7 @@
      */
     oneway explicitCallTransferResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1001,7 +1001,7 @@
      */
     oneway setPreferredNetworkTypeResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param nwType RadioPreferredNetworkType defined in types.hal
      *
@@ -1012,7 +1012,7 @@
     oneway getPreferredNetworkTypeResponse(RadioResponseInfo info,
             PreferredNetworkType nwType);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param cells Vector of neighboring radio cell
      *
@@ -1023,7 +1023,7 @@
      */
     oneway getNeighboringCidsResponse(RadioResponseInfo info, vec<NeighboringCell> cells);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1032,7 +1032,7 @@
      */
     oneway setLocationUpdatesResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1043,7 +1043,7 @@
      */
     oneway setCdmaSubscriptionSourceResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1052,7 +1052,7 @@
      */
     oneway setCdmaRoamingPreferenceResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param type CdmaRoamingType defined in types.hal
      *
@@ -1063,7 +1063,7 @@
      */
     oneway getCdmaRoamingPreferenceResponse(RadioResponseInfo info, CdmaRoamingType type);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1076,7 +1076,7 @@
      */
     oneway setTTYModeResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param mode TtyMode
      *
@@ -1090,7 +1090,7 @@
      */
     oneway getTTYModeResponse(RadioResponseInfo info, TtyMode mode);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1103,7 +1103,7 @@
      */
     oneway setPreferredVoicePrivacyResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param enable false for Standard Privacy Mode (Public Long Code Mask)
      *        true for Enhanced Privacy Mode (Private Long Code Mask)
@@ -1118,7 +1118,7 @@
      */
     oneway getPreferredVoicePrivacyResponse(RadioResponseInfo info, bool enable);
 
-    /*
+    /**
      * Response callback for IRadio.sendCDMAFeatureCode()
      *
      * @param info Response info struct containing response type, serial no. and error
@@ -1136,7 +1136,7 @@
      */
     oneway sendCDMAFeatureCodeResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1152,7 +1152,7 @@
      */
     oneway sendBurstDtmfResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param sms Sms result struct as defined by SendSmsResult in types.hal
      *
@@ -1176,7 +1176,7 @@
      */
     oneway sendCdmaSmsResponse(RadioResponseInfo info, SendSmsResult sms);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1195,7 +1195,7 @@
      */
     oneway acknowledgeLastIncomingCdmaSmsResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param configs Vector of GSM/WCDMA Cell broadcast configs
      *
@@ -1213,7 +1213,7 @@
     oneway getGsmBroadcastConfigResponse(RadioResponseInfo info,
             vec<GsmBroadcastSmsConfigInfo> configs);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1228,7 +1228,7 @@
      */
     oneway setGsmBroadcastConfigResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1243,7 +1243,7 @@
      */
     oneway setGsmBroadcastActivationResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param configs Vector of CDMA Broadcast SMS configs.
      *
@@ -1261,7 +1261,7 @@
     oneway getCdmaBroadcastConfigResponse(RadioResponseInfo info,
             vec<CdmaBroadcastSmsConfigInfo> configs);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1276,7 +1276,7 @@
      */
     oneway setCdmaBroadcastConfigResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1291,7 +1291,7 @@
      */
     oneway setCdmaBroadcastActivationResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param mdn MDN if CDMA subscription is available
      * @param hSid is a comma separated list of H_SID (Home SID) if
@@ -1309,7 +1309,7 @@
     oneway getCDMASubscriptionResponse(RadioResponseInfo info, string mdn, string hSid,
             string hNid, string min, string prl);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param index record index where the cmda sms message is stored
      *
@@ -1330,7 +1330,7 @@
      */
     oneway writeSmsToRuimResponse(RadioResponseInfo info, uint32_t index);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1345,7 +1345,7 @@
      */
     oneway deleteSmsOnRuimResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param imei IMEI if GSM subscription is available
      * @param imeisv IMEISV if GSM subscription is available
@@ -1363,7 +1363,7 @@
     oneway getDeviceIdentityResponse(RadioResponseInfo info, string imei, string imeisv,
             string esn, string meid);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1373,7 +1373,7 @@
      */
     oneway exitEmergencyCallbackModeResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param smsc Short Message Service Center address on the device
      *
@@ -1391,7 +1391,7 @@
      */
     oneway getSmscAddressResponse(RadioResponseInfo info, string smsc);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1407,7 +1407,7 @@
      */
     oneway setSmscAddressResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1422,7 +1422,7 @@
      */
     oneway reportSmsMemoryStatusResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1431,7 +1431,7 @@
      */
     oneway reportStkServiceIsRunningResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param source CDMA subscription source
      *
@@ -1442,7 +1442,7 @@
      */
     oneway getCdmaSubscriptionSourceResponse(RadioResponseInfo info, CdmaSubscriptionSource source);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param response response string of the challenge/response algo for ISIM auth in base64 format
      *
@@ -1452,7 +1452,7 @@
      */
     oneway requestIsimAuthenticationResponse(RadioResponseInfo info, string response);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1461,7 +1461,7 @@
      */
     oneway acknowledgeIncomingGsmSmsWithPduResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param iccIo IccIoResult as defined in types.hal corresponding to ICC IO response
      *
@@ -1473,7 +1473,7 @@
      */
     oneway sendEnvelopeWithStatusResponse(RadioResponseInfo info, IccIoResult iccIo);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param rat Current voice RAT
      *
@@ -1483,7 +1483,7 @@
      */
     oneway getVoiceRadioTechnologyResponse(RadioResponseInfo info, RadioTechnology rat);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param cellInfo List of current cell information known to radio
      *
@@ -1493,7 +1493,7 @@
      */
     oneway getCellInfoListResponse(RadioResponseInfo info, vec<CellInfo> cellInfo);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1502,7 +1502,7 @@
      */
     oneway setCellInfoListRateResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1512,7 +1512,7 @@
      */
     oneway setInitialAttachApnResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param isRegistered false = not registered, true = registered
      * @param ratFamily RadioTechnologyFamily as defined in types.hal. This value is valid only if
@@ -1525,7 +1525,7 @@
     oneway getImsRegistrationStateResponse(RadioResponseInfo info, bool isRegistered,
             RadioTechnologyFamily ratFamily);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param sms Response to sms sent as defined by SendSmsResult in types.hal
      *
@@ -1548,7 +1548,7 @@
      */
     oneway sendImsSmsResponse(RadioResponseInfo info, SendSmsResult sms);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param result IccIoResult as defined in types.hal
      *
@@ -1558,7 +1558,7 @@
      */
     oneway iccTransmitApduBasicChannelResponse(RadioResponseInfo info, IccIoResult result);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param channelId session id of the logical channel.
      * @param selectResponse Contains the select response for the open channel command with one
@@ -1573,7 +1573,7 @@
     oneway iccOpenLogicalChannelResponse(RadioResponseInfo info, int32_t channelId,
             vec<int8_t> selectResponse);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1582,7 +1582,7 @@
      */
     oneway iccCloseLogicalChannelResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param result IccIoResult as defined in types.hal
      *
@@ -1592,7 +1592,7 @@
      */
     oneway iccTransmitApduLogicalChannelResponse(RadioResponseInfo info, IccIoResult result);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param result string containing the contents of the NV item
      *
@@ -1602,7 +1602,7 @@
      */
     oneway nvReadItemResponse(RadioResponseInfo info, string result);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1611,7 +1611,7 @@
      */
     oneway nvWriteItemResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1620,7 +1620,7 @@
      */
     oneway nvWriteCdmaPrlResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1629,7 +1629,7 @@
      */
     oneway nvResetConfigResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1639,7 +1639,7 @@
      */
     oneway setUiccSubscriptionResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1648,7 +1648,7 @@
      */
     oneway setDataAllowedResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param config Array of HardwareConfig of the radio.
      *
@@ -1658,7 +1658,7 @@
      */
     oneway getHardwareConfigResponse(RadioResponseInfo info, vec<HardwareConfig> config);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param result IccIoResult as defined in types.hal
      *
@@ -1668,7 +1668,7 @@
      */
     oneway requestIccSimAuthenticationResponse(RadioResponseInfo info, IccIoResult result);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1678,7 +1678,7 @@
      */
     oneway setDataProfileResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1688,7 +1688,7 @@
      */
     oneway requestShutdownResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param rc Radio capability as defined by RadioCapability in types.hal
      *
@@ -1699,7 +1699,7 @@
      */
     oneway getRadioCapabilityResponse(RadioResponseInfo info, RadioCapability rc);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param rc Radio capability as defined by RadioCapability in types.hal used to
      *        feedback return status
@@ -1711,7 +1711,7 @@
      */
     oneway setRadioCapabilityResponse(RadioResponseInfo info, RadioCapability rc);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param statusInfo LceStatusInfo indicating LCE status
      *
@@ -1722,7 +1722,7 @@
      */
     oneway startLceServiceResponse(RadioResponseInfo info, LceStatusInfo statusInfo);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param statusInfo LceStatusInfo indicating LCE status
      *
@@ -1733,7 +1733,7 @@
      */
     oneway stopLceServiceResponse(RadioResponseInfo info, LceStatusInfo statusInfo);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param lceInfo LceDataInfo indicating LCE data as defined in types.hal
      *
@@ -1744,7 +1744,7 @@
      */
     oneway pullLceDataResponse(RadioResponseInfo info, LceDataInfo lceInfo);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param activityInfo modem activity information
      *
@@ -1754,7 +1754,7 @@
      */
     oneway getModemActivityInfoResponse(RadioResponseInfo info, ActivityStatsInfo activityInfo);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param numAllowed number of allowed carriers which have been set correctly.
      *        On success, it must match the length of list Carriers->allowedCarriers.
@@ -1768,7 +1768,7 @@
      */
     oneway setAllowedCarriersResponse(RadioResponseInfo info, int32_t numAllowed);
 
-    /*
+    /**
      * Expected modem behavior:
      *  Return list of allowed carriers, and if all carriers are allowed.
      *
@@ -1785,7 +1785,7 @@
     oneway getAllowedCarriersResponse(RadioResponseInfo info, bool allAllowed,
             CarrierRestrictions carriers);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1794,7 +1794,7 @@
      */
     oneway sendDeviceStateResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1804,7 +1804,7 @@
      */
     oneway setIndicationFilterResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -1816,7 +1816,7 @@
      */
     oneway setSimCardPowerResponse(RadioResponseInfo info);
 
-    /*
+    /**
      * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for
      * radio request which take long time to respond.
      * For more details, refer https://source.android.com/devices/tech/connect/ril.html
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index ad9f392..2224c8b 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -288,7 +288,7 @@
     WAITING,                              // MT call only
 };
 
-/*
+/**
  * User-to-User signaling Info activation types derived from 3GPP 23.087 v8.0
  */
 enum UusType : int32_t {
@@ -301,7 +301,7 @@
     TYPE3_NOT_REQUIRED,
 };
 
-/*
+/**
  * User-to-User Signaling Information data coding schemes. Possible values for
  * Octet 3 (Protocol Discriminator field) in the UUIE. The values have been
  * specified in section 10.5.4.25 of 3GPP TS 24.008
@@ -410,7 +410,8 @@
                                           // callback mode
     CDMA_ACCESS_BLOCKED = 1009,
 
-    /* OEM specific error codes. Used to distinguish error from
+    /**
+     * OEM specific error codes. Used to distinguish error from
      * CALL_FAIL_ERROR_UNSPECIFIED and help assist debugging */
     OEM_CAUSE_1 = 0xf001,
     OEM_CAUSE_2 = 0xf002,
@@ -526,7 +527,7 @@
     ERROR_UNSPECIFIED = 0xffff,
 };
 
-/*
+/**
  * Please note that registration state UNKNOWN is
  * treated as "out of service" in the Android telephony.
  * Registration state REG_DENIED must be returned if Location Update
@@ -1018,7 +1019,7 @@
     OTAPA_ABORTED
 };
 
-/* Names of the CDMA info records (C.S0005 section 3.7.5) */
+/** Names of the CDMA info records (C.S0005 section 3.7.5) */
 enum CdmaInfoRecName : int32_t {
     DISPLAY,
     CALLED_PARTY_NUMBER,
@@ -1033,7 +1034,7 @@
     T53_AUDIO_CONTROL
 };
 
-/* Redirecting Number Information Record as defined in C.S0005 section 3.7.5.11 */
+/** Redirecting Number Information Record as defined in C.S0005 section 3.7.5.11 */
 enum CdmaRedirectingReason : int32_t {
     UNKNOWN = 0,
     CALL_FORWARDING_BUSY = 1,
@@ -1187,7 +1188,7 @@
     vec<AppStatus> applications;          // size <= RadioConst:CARD_MAX_APPS
 };
 
-/*
+/**
  * User-to-User Signaling Information defined in 3GPP 23.087 v8.0
  */
 struct UusInfo {
@@ -1893,7 +1894,7 @@
                                           // For SIM_RESET result it is empty string.
 };
 
-/* CDMA Signal Information Record as defined in C.S0005 section 3.7.5.5 */
+/** CDMA Signal Information Record as defined in C.S0005 section 3.7.5.5 */
 struct CdmaSignalInfoRecord {
     bool isPresent;                       // true if signal information record is present
     int8_t signalType;                    // as defined 3.7.5.5-1
@@ -1911,7 +1912,7 @@
     CdmaCallWaitingNumberPlan numberPlan;
 };
 
-/*
+/**
  * Display Info Rec as defined in C.S0005 section 3.7.5.1
  * Extended Display Info Rec as defined in C.S0005 section 3.7.5.16
  * Note: the Extended Display info rec contains multiple records of the
@@ -1924,7 +1925,7 @@
     string alphaBuf;                      // Max length = RadioConst:CDMA_ALPHA_INFO_BUFFER_LENGTH
 };
 
-/*
+/**
  * Called Party Number Info Rec as defined in C.S0005 section 3.7.5.2
  * Calling Party Number Info Rec as defined in C.S0005 section 3.7.5.3
  * Connected Number Info Rec as defined in C.S0005 section 3.7.5.4
@@ -1942,7 +1943,7 @@
     CdmaRedirectingReason redirectingReason; // redirectingReason is set to UNKNOWN if not included
 };
 
-/* Line Control Information Record as defined in C.S0005 section 3.7.5.15 */
+/** Line Control Information Record as defined in C.S0005 section 3.7.5.15 */
 struct CdmaLineControlInfoRecord {
     uint8_t lineCtrlPolarityIncluded;
     uint8_t lineCtrlToggle;
@@ -1950,12 +1951,12 @@
     uint8_t lineCtrlPowerDenial;
 };
 
-/* T53 CLIR Information Record */
+/** T53 CLIR Information Record */
 struct CdmaT53ClirInfoRecord {
     uint8_t cause;
 };
 
-/* T53 Audio Control Information Record */
+/** T53 Audio Control Information Record */
 struct CdmaT53AudioControlInfoRecord {
     uint8_t upLink;
     uint8_t downLink;
diff --git a/radio/deprecated/1.0/IOemHookIndication.hal b/radio/deprecated/1.0/IOemHookIndication.hal
index 936779f..8636592 100644
--- a/radio/deprecated/1.0/IOemHookIndication.hal
+++ b/radio/deprecated/1.0/IOemHookIndication.hal
@@ -18,15 +18,15 @@
 
 import android.hardware.radio@1.0::types;
 
-/*
+/**
  * Interface declaring unsolicited oem hook indications.
  */
 interface IOemHookIndication {
-   /*
+   /**
     * This is for OEM specific use.
     *
     * @param type Type of radio indication
     * @param data data passed as raw bytes
     */
    oneway oemHookRaw(RadioIndicationType type, vec<uint8_t> data);
-};
\ No newline at end of file
+};
diff --git a/radio/deprecated/1.0/IOemHookResponse.hal b/radio/deprecated/1.0/IOemHookResponse.hal
index 4e49acc..e8e6445 100644
--- a/radio/deprecated/1.0/IOemHookResponse.hal
+++ b/radio/deprecated/1.0/IOemHookResponse.hal
@@ -18,13 +18,13 @@
 
 import android.hardware.radio@1.0::types;
 
-/*
+/**
  * Interface declaring response functions to solicited oem hook requests.
  * Response functions defined in this interface are as per following convention:
  * <xyz>Response is response to IOemHook.<xyz>
  */
 interface IOemHookResponse {
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param data data returned by oem
      *
@@ -36,7 +36,7 @@
      */
     oneway sendRequestRawResponse(RadioResponseInfo info, vec<uint8_t> data);
 
-    /*
+    /**
      * @param info Response info struct containing response type, serial no. and error
      * @param data data returned by oem
      *
@@ -47,4 +47,4 @@
      *   RadioError:OEM_ERROR_X
      */
     oneway sendRequestStringsResponse(RadioResponseInfo info, vec<string> data);
-};
\ No newline at end of file
+};
diff --git a/renderscript/1.0/IContext.hal b/renderscript/1.0/IContext.hal
index 2e386d2..43a09e1 100644
--- a/renderscript/1.0/IContext.hal
+++ b/renderscript/1.0/IContext.hal
@@ -32,7 +32,7 @@
 
 interface IContext {
 
-    /*
+    /**
      * TODO: Do we need to define "selectors"? It may be a property of the
      * "adapted allocation" that's returned.
      *
@@ -56,7 +56,7 @@
     allocationAdapterCreate(Type type, Allocation baseAlloc)
                  generates (AllocationAdapter subAlloc);
 
-    /*
+    /**
      * TODO: Need to relate "offset" back to the terminology in
      * allocationAdapterCreate() -- the latter uses the terms "selector" and
      * "selected value". Can we use consistent terminology? Are "offset" and
@@ -72,7 +72,7 @@
     @callflow(next={"*"})
     allocationAdapterOffset(AllocationAdapter alloc, vec<uint32_t> offsets);
 
-    /*
+    /**
      * TODO: add more explanation here.
      *
      * Returns the Type of the Allocation.
@@ -83,7 +83,7 @@
     @callflow(next={"*"})
     allocationGetType(Allocation allocation) generates (Type type);
 
-    /*
+    /**
      * TODO: more clarification needed describing if the pointer can be aliased
      * or if the data can outlive the allocation.
      *
@@ -102,7 +102,7 @@
                           bitfield<AllocationUsageType> usage, Ptr ptr)
                generates (Allocation allocation);
 
-    /*
+    /**
      * Creates an Allocation from a Bitmap.
      *
      * @param type Type describing data layout
@@ -118,7 +118,7 @@
                                bitfield<AllocationUsageType> usage)
                     generates (Allocation allocation);
 
-    /*
+    /**
      * Creates a Cubemapped Allocation from a Bitmap.
      *
      * @param type Type describing data layout
@@ -135,7 +135,7 @@
                                    bitfield<AllocationUsageType> usage)
                         generates (Allocation allocation);
 
-    /*
+    /**
      * Returns the handle to a raw buffer that is being managed by the screen
      * compositor. This operation is only valid for Allocations with
      * USAGE_IO_INPUT.
@@ -147,7 +147,7 @@
     allocationGetNativeWindow(Allocation allocation)
                    generates (NativeWindow nativeWindow);
 
-    /*
+    /**
      * TODO: more clarification needed
      *
      * Sets the NativeWindow of an Allocation. This operation is only valid
@@ -159,7 +159,7 @@
     @callflow(next={"*"})
     allocationSetNativeWindow(Allocation allocation, NativeWindow nativewindow);
 
-    /*
+    /**
      * Initialize BufferQueue with specified max number of buffers.
      *
      * @param alloc Allocation
@@ -168,7 +168,7 @@
     @callflow(next={"*"})
     allocationSetupBufferQueue(Allocation alloc, uint32_t numBuffer);
 
-    /*
+    /**
      * TODO: clearly define baseAlloc vs subAlloc
      *
      * Shares the BufferQueue with another Allocation. Both must be
@@ -181,7 +181,7 @@
     @callflow(next={"*"})
     allocationShareBufferQueue(Allocation baseAlloc, Allocation subAlloc);
 
-    /*
+    /**
      * Copies from the Allocation into a Bitmap. The bitmap must match the
      * dimensions of the Allocation.
      *
@@ -195,7 +195,7 @@
     @callflow(next={"*"})
     allocationCopyToBitmap(Allocation allocation, Ptr data, Size sizeBytes);
 
-    /*
+    /**
      * TODO: should we consolidate all [123]DWrite functions or [123]DRead
      * functions into the same API call? Our current plan is to be very similar
      * to the dispatch table API. How much should we deviate from the original
@@ -219,7 +219,7 @@
     allocation1DWrite(Allocation allocation, uint32_t offset, uint32_t lod,
                       uint32_t count, vec<uint8_t> data);
 
-    /*
+    /**
      * Copies a value into a single sub-Element of this Allocation.
      *
      * @param allocation Allocation to be updated
@@ -237,7 +237,7 @@
                            uint32_t z, uint32_t lod, vec<uint8_t> data,
                            Size compIdx);
 
-    /*
+    /**
      * Copies from an array into a rectangular region in this Allocation.
      *
      * When this HAL entry is executed, all Vec3 elements have been explicitly
@@ -262,7 +262,7 @@
                       uint32_t lod, AllocationCubemapFace face, uint32_t w,
                       uint32_t h, vec<uint8_t> data, Size stride);
 
-    /*
+    /**
      * Copies from an array into a 3D region in this Allocation.
      *
      * When this HAL entry is executed, all Vec3 elements have been explicitly
@@ -288,7 +288,7 @@
                       uint32_t zoff, uint32_t lod, uint32_t w, uint32_t h,
                       uint32_t d, vec<uint8_t> data, Size stride);
 
-    /*
+    /**
      * Generates a mipmap chain. This is only valid if the Type of the
      * Allocation includes mipmaps.
      *
@@ -304,7 +304,7 @@
     @callflow(next={"*"})
     allocationGenerateMipmaps(Allocation allocation);
 
-    /*
+    /**
      * Copies all of an Allocation's data into an array.
      *
      * All Vec3 elements of an Allocation are padded to be Vec4, so the data
@@ -320,7 +320,7 @@
     @callflow(next={"*"})
     allocationRead(Allocation allocation, Ptr data, Size sizeBytes);
 
-    /*
+    /**
      * Copies a 1D region of this Allocation into an array.
      *
      * All Vec3 elements of an Allocation are padded to be Vec4, so the data
@@ -342,7 +342,7 @@
     allocation1DRead(Allocation allocation, uint32_t xoff, uint32_t lod,
                      uint32_t count, Ptr data, Size sizeBytes);
 
-    /*
+    /**
      * Returns the value of a single sub-Element of this Allocation.
      *
      * HIDL is always running in Passthrough mode for RenderScript, so the
@@ -362,7 +362,7 @@
                           uint32_t z, uint32_t lod, Ptr data, Size sizeBytes,
                           Size compIdx);
 
-    /*
+    /**
      * Copies from a rectangular region in this Allocation to an array.
      *
      * All Vec3 elements of an Allocation are padded to be Vec4, so the data
@@ -391,7 +391,7 @@
                      uint32_t lod, AllocationCubemapFace face, uint32_t w,
                      uint32_t h, Ptr data, Size sizeBytes, Size stride);
 
-    /*
+    /**
      * Copies from a rectangular cuboid region in this Allocation to an array.
      *
      * All Vec3 elements of an Allocation are padded to be Vec4, so the data
@@ -421,7 +421,7 @@
                      uint32_t zoff, uint32_t lod, uint32_t w, uint32_t h,
                      uint32_t d, Ptr data, Size sizeBytes, Size stride);
 
-    /*
+    /**
      * Propagates changes from one usage of the Allocation to the other usages
      * of the Allocation.
      *
@@ -431,7 +431,7 @@
     @callflow(next={"*"})
     allocationSyncAll(Allocation allocation, AllocationUsageType usageType);
 
-    /*
+    /**
      * TODO: describe the functionality of resize1D better
      * TODO: original Java Doc description seems to contradict itself ("with
      * null contents and the region is otherwise undefined")
@@ -455,7 +455,7 @@
     @callflow(next={"*"})
     allocationResize1D(Allocation allocation, uint32_t dimX);
 
-    /*
+    /**
      * TODO: There are allocationCopy2DRange and 3DRange, but no 1DRange. Should
      * the interface be cleaned up more?
      *
@@ -483,7 +483,7 @@
                           uint32_t srcXoff, uint32_t srcYoff, uint32_t srcMip,
                           AllocationCubemapFace srcFace);
 
-    /*
+    /**
      * Copies a rectangular cuboid region into the allocation from another
      * Allocation.
      *
@@ -508,7 +508,7 @@
                           Allocation srcAlloc, uint32_t srcXoff,
                           uint32_t srcYoff, uint32_t srcZoff, uint32_t srcMip);
 
-    /*
+    /**
      * TODO: define buffer and output stream
      *
      * Sends a buffer to the output stream. The contents of the Allocation may
@@ -520,7 +520,7 @@
     @callflow(next={"*"})
     allocationIoSend(Allocation allocation);
 
-    /*
+    /**
      * Receives the latest input into the Allocation. This operation is only
      * valid if USAGE_IO_INPUT is set on the Allocation, otherwise an error
      * must be reported and no operations may be executed.
@@ -530,7 +530,7 @@
     @callflow(next={"*"})
     allocationIoReceive(Allocation allocation);
 
-    /*
+    /**
      * TODO: describe default values for lod, face, and z better.
      * TODO: what cases can invalidate the pointer? Resize? It should be
      * clarified that this method should always return a valid pointer, but the
@@ -560,7 +560,7 @@
                          AllocationCubemapFace face, uint32_t z)
               generates (Ptr dataPtr, Size stride);
 
-    /*
+    /**
      * Retrieves an Element's metadata from native code.
      *
      * @param element Element to be read
@@ -570,7 +570,7 @@
     elementGetNativeMetadata(Element element)
                   generates (vec<uint32_t> elemData);
 
-    /*
+    /**
      * TODO: define Sub-Element handles better.
      *
      * Retrieves an Element's sub Elements, specifically their identifiers,
@@ -587,7 +587,7 @@
                generates (vec<Element> ids, vec<string> names,
                           vec<Size> arraySizes);
 
-    /*
+    /**
      * TODO: can normalization flag be removed?
      *
      * Creates an Element.
@@ -602,7 +602,7 @@
     elementCreate(DataType dt, DataKind dk, bool norm, uint32_t size)
        generates (Element element);
 
-    /*
+    /**
      * Creates a complex Element.
      *
      * @param einsPtr Container of input Elements
@@ -615,7 +615,7 @@
                          vec<Size> arraySizesPtr)
               generates (Element element);
 
-    /*
+    /**
      * Retrives a Type's metadata from native code.
      *
      * @param type Type describing data layout
@@ -624,7 +624,7 @@
     @callflow(next={"*"})
     typeGetNativeMetadata(Type type) generates (vec<OpaqueHandle> metadata);
 
-    /*
+    /**
      * Creates a new Type.
      *
      * If Type is 1D, Y and Z must be 0. If Type is 2D, Z must be 0.
@@ -644,14 +644,14 @@
                bool mipmaps, bool faces, YuvFormat yuv)
     generates (Type type);
 
-    /*
+    /**
      * Destroys provided RenderScript context, including all objects created in
      * this context.
      */
     @exit
     contextDestroy();
 
-    /*
+    /**
      * TODO: provide overview of messaging model and figure out if this should
      * be part of HAL or not.
      * TODO: what is the "client" for purposes of this interface?
@@ -671,7 +671,7 @@
     contextGetMessage(Ptr data, Size size)
            generates (MessageToClientType messageType, Size receiveLen);
 
-    /*
+    /**
      * TODO: define subID better.
      *
      * Gets the metadata of a message to ensure entire message can be properly
@@ -687,7 +687,7 @@
             generates (MessageToClientType messageType, Size receiveLen,
                        uint32_t subID);
 
-    /*
+    /**
      * TODO: Define "previous commands" better
      * TODO: Is the message identifier the same as subID?
      *
@@ -702,7 +702,7 @@
     @callflow(next={"*"})
     contextSendMessage(uint32_t id, vec<uint8_t> data);
 
-    /*
+    /**
      * TODO: Can this be done automatically as part of context creation? What
      * happens if we perform message operations before doing this?
      *
@@ -713,7 +713,7 @@
     @callflow(next={"*"})
     contextInitToClient();
 
-    /*
+    /**
      * TODO: Why doesn't this happen automatically as part of context
      * destruction? What happens if the FIFO is not empty?
      *
@@ -722,7 +722,7 @@
     @callflow(next={"*"})
     contextDeinitToClient();
 
-    /*
+    /**
      * TODO: do we need to mark asynchronous operations in this interface
      * definition?
      *
@@ -732,14 +732,14 @@
     @callflow(next={"*"})
     contextFinish();
 
-    /*
+    /**
      * Prints the currently available debugging information about the state of
      * the RS context to the logcat.
      */
     @callflow(next={"*"})
     contextLog();
 
-    /*
+    /**
      * TODO: full path? relative path? Investigate further.
      *
      * Sets the cache directory of the context.
@@ -749,7 +749,7 @@
     @callflow(next={"*"})
     contextSetCacheDir(string cacheDir);
 
-    /*
+    /**
      * TODO: does this apply to the GPU as well?
      *
      * Changes the priority of the cpu worker threads for this context.
@@ -759,7 +759,7 @@
     @callflow(next={"*"})
     contextSetPriority(ThreadPriorities priority);
 
-    /*
+    /**
      * TODO: does this need to be part of the HAL? What if the object already
      * has a name?
      *
@@ -771,7 +771,7 @@
     @callflow(next={"*"})
     assignName(ObjectBase obj, string name);
 
-    /*
+    /**
      * TODO: what if the object has no name?
      *
      * Returns the name of an object.
@@ -782,7 +782,7 @@
     @callflow(next={"*"})
     getName(ObjectBase obj) generates (string name);
 
-    /*
+    /**
      * TODO: starting here we have a set of interfaces for use with
      * ScriptGroups. At the very least we should indicate for each one that's
      * what it's for. Should we include ScriptGroup in the interface names?
@@ -810,7 +810,7 @@
                   vec<ScriptFieldID> depFieldIDS)
        generates (Closure closure);
 
-    /*
+    /**
      * Creates a Closure which represents a function call to a invocable
      * function, combined with arguments and values for global variables.
      *
@@ -827,7 +827,7 @@
                         vec<int32_t> sizes)
              generates (Closure closure);
 
-    /*
+    /**
      * Sets the argument of a Closure at specified index and size to provided
      * value.
      *
@@ -839,7 +839,7 @@
     @callflow(next={"*"})
     closureSetArg(Closure closure, uint32_t index, Ptr value, int32_t size);
 
-    /*
+    /**
      * Sets a global variable in a Closure.
      *
      * @param closure Closure
@@ -851,7 +851,7 @@
     closureSetGlobal(Closure closure, ScriptFieldID fieldID, int64_t value,
                      int32_t size);
 
-    /*
+    /**
      * TODO: should slot be unsigned? (applies to other two ID interfaces, too)
      *
      * Creates a Script Kernel ID.
@@ -866,7 +866,7 @@
                          bitfield<MetadataSignatureBitval> sig)
               generates (ScriptKernelID scriptKernelID);
 
-    /*
+    /**
      * Creates a Script Invoke ID.
      *
      * @param script Script
@@ -877,7 +877,7 @@
     scriptInvokeIDCreate(Script script, int32_t slot)
               generates (ScriptInvokeID scriptInvokeID);
 
-    /*
+    /**
      * TODO: describe the return value better. What is it?
      *
      * Creates a Script Field ID.
@@ -890,7 +890,7 @@
     scriptFieldIDCreate(Script script, int32_t slot)
              generates (ScriptFieldID scriptFieldID);
 
-    /*
+    /**
      * TODO: add more description
      *
      * Creates a Script Group.
@@ -908,7 +908,7 @@
                       vec<Type> types)
            generates (ScriptGroup scriptGroup);
 
-    /*
+    /**
      * Creates a Script Group.
      *
      * @param name Name
@@ -920,7 +920,7 @@
     scriptGroup2Create(string name, string cacheDir, vec<Closure> closures)
             generates (ScriptGroup2 scriptGroup2);
 
-    /*
+    /**
      * TODO: if SetInput/Output corresponds to the Java API setInput() and
      * setOutput(), which are documented as deprecated in API 23, do we need to
      * support them? Or can we fallback to the CPU when they're used? Or can't
@@ -937,7 +937,7 @@
     @callflow(next={"*"})
     scriptGroupSetOutput(ScriptGroup sg, ScriptKernelID kid, Allocation alloc);
 
-    /*
+    /**
      * Sets an input of the Script Group. This specifies an Allocation to be
      * used for kernels that require an input Allocation provided from outside
      * of the Script Group.
@@ -949,7 +949,7 @@
     @callflow(next={"*"})
     scriptGroupSetInput(ScriptGroup sg, ScriptKernelID kid, Allocation alloc);
 
-    /*
+    /**
      * Executes a Script Group.
      *
      * @param sg Script Group to be executed.
@@ -957,7 +957,7 @@
     @callflow(next={"*"})
     scriptGroupExecute( ScriptGroup sg);
 
-    /*
+    /**
      * Frees any native resources associated with this object. The primary use
      * is to force immediate cleanup of resources when it is believed the GC
      * may not respond quickly enough.
@@ -967,7 +967,7 @@
     @callflow(next={"*"})
     objDestroy(ObjectBase obj);
 
-    /*
+    /**
      * Creates a Sampler.
      *
      * @param magFilter Magnification value for the filter
@@ -984,7 +984,7 @@
                   float aniso)
        generates (Sampler sampler);
 
-    /*
+    /**
      * Binds an Allocation to a global pointer in the Script.
      *
      * @param script Script to be bound to
@@ -994,7 +994,7 @@
     @callflow(next={"*"})
     scriptBindAllocation(Script script, Allocation allocation, uint32_t slot);
 
-    /*
+    /**
      * TODO: is this necessary?
      *
      * Sets the timezone of a Script.
@@ -1005,7 +1005,7 @@
     @callflow(next={"*"})
     scriptSetTimeZone(Script script, string timeZone);
 
-    /*
+    /**
      * TODO: can scriptInvoke be combined with scriptInvokeV?
      *
      * Launches an invokable function.
@@ -1016,7 +1016,7 @@
     @callflow(next={"*"})
     scriptInvoke(Script vs, uint32_t slot);
 
-    /*
+    /**
      * Invokes a Script with values.
      *
      * @param vs Script to be invoked
@@ -1026,7 +1026,7 @@
     @callflow(next={"*"})
     scriptInvokeV(Script vs, uint32_t slot, vec<uint8_t> data);
 
-    /*
+    /**
      * TODO: add documentation for params
      * TODO: Should we rename "ScriptCall" to "LaunchOptions"?
      *
@@ -1043,7 +1043,7 @@
     scriptForEach(Script vs, uint32_t slot, vec<Allocation> vains,
                   Allocation vaout, vec<uint8_t> params, Ptr sc);
 
-    /*
+    /**
      * Launches a Reduction kernel.
      *
      * @param vs Script
@@ -1056,7 +1056,7 @@
     scriptReduce(Script vs, uint32_t slot, vec<Allocation> vains,
                  Allocation vaout, Ptr sc);
 
-    /*
+    /**
      * Sets a Script's integer variable to a value.
      *
      * @param vs RenderScript Script
@@ -1066,7 +1066,7 @@
     @callflow(next={"*"})
     scriptSetVarI(Script vs, uint32_t slot, int32_t value);
 
-    /*
+    /**
      * Sets a Script's Object variable to a value
      *
      * @param vs RenderScript Script
@@ -1076,7 +1076,7 @@
     @callflow(next={"*"})
     scriptSetVarObj( Script vs,  uint32_t slot, ObjectBase obj);
 
-    /*
+    /**
      * Sets a Script's long variable to a value.
      *
      * @param vs RenderScript Script
@@ -1086,7 +1086,7 @@
     @callflow(next={"*"})
     scriptSetVarJ(Script vs, uint32_t slot, int64_t value);
 
-    /*
+    /**
      * Sets a Script's float variable to a value.
      *
      * @param vs RenderScript Script
@@ -1096,7 +1096,7 @@
     @callflow(next={"*"})
     scriptSetVarF(Script vs, uint32_t slot, float value);
 
-    /*
+    /**
      * Sets a Script's double variable to a value.
      *
      * @param vs RenderScript Script
@@ -1106,7 +1106,7 @@
     @callflow(next={"*"})
     scriptSetVarD(Script vs, uint32_t slot, double value);
 
-    /*
+    /**
      * Sets a Script's struct variable to a value.
      *
      * @param vs RenderScript Script
@@ -1116,7 +1116,7 @@
     @callflow(next={"*"})
     scriptSetVarV(Script vs, uint32_t slot, vec<uint8_t> data);
 
-    /*
+    /**
      * TODO: Why do we have typed setters but only untyped getter?
      *
      * Retrieves the value from a global variable in a script.
@@ -1130,7 +1130,7 @@
     scriptGetVarV(Script vs, uint32_t slot, Size len)
        generates (vec<uint8_t> data);
 
-    /*
+    /**
      * TODO: Is this a value to be replicated for each member of the array? Or
      * is there a representation for each separate member?
      *
@@ -1147,7 +1147,7 @@
     scriptSetVarVE(Script vs, uint32_t slot, vec<uint8_t> data, Element ve,
                    vec<uint32_t> dims);
 
-    /*
+    /**
      * TODO: is cacheDir redundant with createCache() function? Can we remove
      * it?
      * TODO: define resName more clearly
@@ -1163,7 +1163,7 @@
     scriptCCreate(string resName, string cacheDir, vec<uint8_t> text)
        generates (Script script);
 
-    /*
+    /**
      * Creates a RenderScript Intrinsic script.
      *
      * @param id Intrinsic Script identifier
diff --git a/renderscript/1.0/IDevice.hal b/renderscript/1.0/IDevice.hal
index 7b1b866..62ce521 100644
--- a/renderscript/1.0/IDevice.hal
+++ b/renderscript/1.0/IDevice.hal
@@ -21,7 +21,7 @@
 
 interface IDevice {
 
-    /*
+    /**
      * Creates a RenderScript context.
      *
      * @param sdkVersion Target RS API level
diff --git a/tests/baz/1.0/IBase.hal b/tests/baz/1.0/IBase.hal
index d5e3565..97b2db4 100644
--- a/tests/baz/1.0/IBase.hal
+++ b/tests/baz/1.0/IBase.hal
@@ -38,7 +38,7 @@
     };
 
     struct MoreThanOneArrayField {
-        /*
+        /**
          * Generated (Java) code used to redeclare the same variable name
          * multiple times in the same scope, this test ensures that that's no
          * longer the case.
diff --git a/tests/baz/1.0/types.hal b/tests/baz/1.0/types.hal
index 030dbe5..694b459 100644
--- a/tests/baz/1.0/types.hal
+++ b/tests/baz/1.0/types.hal
@@ -16,7 +16,7 @@
 
 package android.hardware.tests.baz@1.0;
 
-/*
+/**
  * Verify that introducing a typedef in types.hal does not mistakenly emit
  * a makefile section to create a dedicated ulong.java class as it used to.
  */
diff --git a/tests/msgq/1.0/IBenchmarkMsgQ.hal b/tests/msgq/1.0/IBenchmarkMsgQ.hal
index 81754a4..6ee3485 100644
--- a/tests/msgq/1.0/IBenchmarkMsgQ.hal
+++ b/tests/msgq/1.0/IBenchmarkMsgQ.hal
@@ -17,7 +17,7 @@
 package android.hardware.tests.msgq@1.0;
 
 interface IBenchmarkMsgQ {
-    /*
+    /**
      * This method requests the service to set up Synchronous read/write
      * wait-free FMQ with the client as reader.
      * @return ret Will be true if the setup was successful, false otherwise.
@@ -27,7 +27,7 @@
     configureClientInboxSyncReadWrite()
         generates(bool ret, fmq_sync<uint8_t> mqDescIn);
 
-    /*
+    /**
      * This method requests the service to set up Synchronous read/write
      * wait-free FMQ with the client as writer.
      * @return ret Will be true if the setup was successful, false otherwise.
@@ -37,7 +37,7 @@
     configureClientOutboxSyncReadWrite()
         generates(bool ret, fmq_sync<uint8_t> mqDescOut);
 
-    /*
+    /**
      * This method request the service to write into the FMQ.
      * @param count Number to messages to write.
      * @return ret Will be true if the write operation was successful,
@@ -45,14 +45,14 @@
      */
     requestWrite(int32_t count) generates (bool ret);
 
-    /*
+    /**
      * This method request the service to read from the FMQ.
      * @param count Number to messages to read.
      * @ret Will be true if the read operation was successful, false otherwise.
      */
     requestRead(int32_t count) generates (bool ret);
 
-    /*
+    /**
      * This method kicks off a benchmarking experiment where
      * the client writes a message into its outbox FMQ,
      * the service reads it and writes it into the client's
@@ -62,14 +62,14 @@
      */
     benchmarkPingPong(uint32_t numIter);
 
-    /*
+    /**
      * This method kicks off a benchmarking experiment where
      * the service writes into an FMQ and the client reads the same.
      * @param numIter The number of iterations to run the experiment.
      */
     benchmarkServiceWriteClientRead(uint32_t numIter);
 
-    /*
+    /**
      * This method sends a vector of time duration(in ns).
      * @param timeData vector of time instants measured by client.
      * Each entry is the number of ns between the epoch and a
diff --git a/tests/msgq/1.0/ITestMsgQ.hal b/tests/msgq/1.0/ITestMsgQ.hal
index dfb9be4..350e26d 100644
--- a/tests/msgq/1.0/ITestMsgQ.hal
+++ b/tests/msgq/1.0/ITestMsgQ.hal
@@ -22,7 +22,7 @@
         FMQ_NOT_FULL  = 1 << 1,
     };
 
-    /*
+    /**
      * This method requests the service to set up a synchronous read/write
      * wait-free FMQ with the client as reader.
      *
@@ -33,7 +33,7 @@
     configureFmqSyncReadWrite()
         generates(bool ret, fmq_sync<uint16_t> mqDesc);
 
-    /*
+    /**
      * This method requests the service to return an MQDescriptor to
      * an unsynchronized FMQ set up by the server. If 'configureFmq' is
      * true, then the server sets up a new unsynchronized FMQ. This
@@ -48,7 +48,7 @@
      */
     getFmqUnsyncWrite(bool configureFmq) generates(bool ret, fmq_unsync<uint16_t> mqDesc);
 
-    /*
+    /**
      * This method request the service to write into the synchronized read/write
      * flavor of the FMQ.
      *
@@ -58,7 +58,7 @@
      */
     requestWriteFmqSync(int32_t count) generates(bool ret);
 
-    /*
+    /**
      * This method request the service to read from the synchronized read/write
      * FMQ.
      *
@@ -68,7 +68,7 @@
      */
     requestReadFmqSync(int32_t count) generates(bool ret);
 
-    /*
+    /**
      * This method request the service to write into the unsynchronized flavor
      * of FMQ.
      *
@@ -78,7 +78,7 @@
      */
     requestWriteFmqUnsync(int32_t count) generates(bool ret);
 
-    /*
+    /**
      * This method request the service to read from the unsynchronized flavor of
      * FMQ.
      *
@@ -88,7 +88,7 @@
      */
     requestReadFmqUnsync(int32_t count) generates(bool ret);
 
-    /*
+    /**
      * This method requests the service to trigger a blocking read.
      *
      * @param count Number of messages to read.
@@ -96,7 +96,7 @@
      */
     oneway requestBlockingRead(int32_t count);
 
-    /*
+    /**
      * This method requests the service to trigger a blocking read using
      * default Event Flag notification bits defined by the MessageQueue class.
      *
@@ -105,7 +105,7 @@
      */
     oneway requestBlockingReadDefaultEventFlagBits(int32_t count);
 
-    /*
+    /**
      * This method requests the service to repeatedly trigger blocking reads.
      *
      * @param count Number of messages to read in a single blocking read.
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index 17aadee..1662312 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -589,10 +589,10 @@
  * Size limits for parameters used in the NAN interface.
  */
 enum NanParamSizeLimits : uint32_t {
-  /* Minimum length of Passphrase argument for data-path configuration */
+  /** Minimum length of Passphrase argument for data-path configuration */
   MIN_PASSPHRASE_LENGTH = 8,
 
-  /* Maximum length of Passphrase argument for data-path configuration */
+  /** Maximum length of Passphrase argument for data-path configuration */
   MAX_PASSPHRASE_LENGTH = 63,
 };
 
@@ -607,29 +607,29 @@
  */
 enum NanStatusType : uint32_t {
   SUCCESS = 0,
-  /* NAN Discovery Engine/Host driver failures */
+  /** NAN Discovery Engine/Host driver failures */
   INTERNAL_FAILURE = 1,
-  /* NAN OTA failures */
+  /** NAN OTA failures */
   PROTOCOL_FAILURE = 2,
-  /* The publish/subscribe discovery session id is invalid */
+  /** The publish/subscribe discovery session id is invalid */
   INVALID_SESSION_ID = 3,
-  /* Out of resources to fufill request */
+  /** Out of resources to fufill request */
   NO_RESOURCES_AVAILABLE = 4,
-  /* Invalid arguments passed */
+  /** Invalid arguments passed */
   INVALID_ARGS = 5,
-  /* Invalid peer id */
+  /** Invalid peer id */
   INVALID_PEER_ID = 6,
-  /* Invalid NAN data-path (ndp) id */
+  /** Invalid NAN data-path (ndp) id */
   INVALID_NDP_ID = 7,
-  /* Attempting to enable NAN when not available, e.g. wifi is disabled */
+  /** Attempting to enable NAN when not available, e.g. wifi is disabled */
   NAN_NOT_ALLOWED = 8,
-  /* Over the air ACK not received */
+  /** Over the air ACK not received */
   NO_OTA_ACK = 9,
-  /* Attempting to enable NAN when already enabled */
+  /** Attempting to enable NAN when already enabled */
   ALREADY_ENABLED = 10,
-  /* Can't queue tx followup message foor transmission */
+  /** Can't queue tx followup message foor transmission */
   FOLLOWUP_TX_QUEUE_FULL = 11,
-  /* Unsupported concurrency of NAN and another feature - NAN disabled */
+  /** Unsupported concurrency of NAN and another feature - NAN disabled */
   UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12
 };