Merge "identity: Fix attestation and documentation problems."
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 730b601..702334d 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -55,7 +55,7 @@
      * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * will be returned.
      *
-     * @return the unencrypted key-pair in PKCS#8 format.
+     * @return the private key, in DER format as specified in RFC 5915.
      */
     byte[] createEphemeralKeyPair();
 
@@ -88,10 +88,10 @@
      * The setRequestedNamespaces() and setVerificationToken() methods will be called before
      * this method is called.
      *
-     * This method be called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
-     * createAuthChallenge() and before startRetrieveEntry(). This method call is followed by
-     * multiple calls of startRetrieveEntryValue(), retrieveEntryValue(), and finally
-     * finishRetrieval().
+     * This method is called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
+     * createAuthChallenge() (note that those calls are optional) and before startRetrieveEntry().
+     * This method call is followed by multiple calls of startRetrieveEntryValue(),
+     * retrieveEntryValue(), and finally finishRetrieval().
      *
      * It is permissible to perform data retrievals multiple times using the same instance (e.g.
      * startRetrieval(), then multiple calls of startRetrieveEntryValue(), retrieveEntryValue(),
@@ -343,12 +343,13 @@
      *
      *  - signature: must be set to ECDSA.
      *
-     *  - subject: CN shall be set to "Android Identity Credential Authentication Key".
+     *  - subject: CN shall be set to "Android Identity Credential Authentication Key". (fixed
+     *    value: same on all certs)
      *
-     *  - issuer: shall be set to "credentialStoreName (credentialStoreAuthorName)" using the
-     *    values returned in HardwareInformation.
+     *  - issuer: CN shall be set to "Android Identity Credential Key". (fixed value:
+     *    same on all certs)
      *
-     *  - validity: should be from current time and one year in the future.
+     *  - validity: should be from current time and one year in the future (365 days).
      *
      *  - subjectPublicKeyInfo: must contain attested public key.
      *
diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
index 297fd1d..c48cb66 100644
--- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -37,12 +37,12 @@
      *
      *  - signature: must be set to ECDSA.
      *
-     *  - subject: CN shall be set to "Android Identity Credential Key".
+     *  - subject: CN shall be set to "Android Identity Credential Key". (fixed value:
+     *    same on all certs)
      *
-     *  - issuer: shall be set to "credentialStoreName (credentialStoreAuthorName)" using the
-     *    values returned in HardwareInformation.
+     *  - issuer: Same as the subject field of the batch attestation key.
      *
-     *  - validity: should be from current time and expire at the same time as the
+     *  - validity: Should be set to current time and expire at the same time as the
      *    attestation batch certificate used.
      *
      *  - subjectPublicKeyInfo: must contain attested public key.
@@ -55,19 +55,14 @@
      *
      *  - The attestationSecurityLevel field must be set to either Software (0),
      *    TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
-     *    implemented. Only the default AOSP implementation of this HAL may use
-     *    value 0 (additionally, this implementation must not be used on production
-     *    devices).
+     *    implemented.
      *
-     *  - The keymasterVersion field in the attestation extension must be set to (10*major + minor)
-     *    where major and minor are the Identity Credential interface major and minor versions.
-     *    Specifically for this version of the interface (1.0) this value is 10.
+     *  - The keymasterVersion field in the attestation extension must be set to the.
+     *    same value as used for Android Keystore keys.
      *
      *  - The keymasterSecurityLevel field in the attestation extension must be set to
      *    either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
-     *    the Trusted Application backing the HAL implementation is implemented. Only
-     *    the default AOSP implementation of this HAL may use value 0 (additionally, this
-     *    implementation must not be used on production devices)
+     *    the Trusted Application backing the HAL implementation is implemented.
      *
      *  - The attestationChallenge field must be set to the passed-in challenge.
      *
@@ -81,7 +76,8 @@
      *
      *    - Tag::IDENTITY_CREDENTIAL_KEY which indicates that the key is an Identity
      *      Credential key (which can only sign/MAC very specific messages) and not an Android
-     *      Keystore key (which can be used to sign/MAC anything).
+     *      Keystore key (which can be used to sign/MAC anything). This must not be set
+     *      for test credentials.
      *
      *    - Tag::PURPOSE must be set to SIGN
      *
@@ -95,10 +91,13 @@
      *
      *    - Tag::EC_CURVE must be set to P_256
      *
-     * Additional authorizations may be needed in the softwareEnforced and teeEnforced
-     * fields - the above is not an exhaustive list. Specifically, authorizations containing
-     * information about the root of trust, OS version, verified boot state, and so on should
-     * be included.
+     *    - Tag::ROOT_OF_TRUST must be set
+     *
+     *    - Tag::OS_VERSION and Tag::OS_PATCHLEVEL must be set
+     *
+     * Additional authorizations may be appear in the softwareEnforced and teeEnforced
+     * fields. For example if the device has a boot or vendor partitions, then BOOT_PATCHLEVEL
+     * and VENDOR_PATCHLEVEL should be set.
      *
      * Since the chain is required to be generated using Keymaster Attestation, the returned
      * certificate chain has the following properties:
@@ -112,8 +111,8 @@
      * As with any user of attestation, the Issuing Authority (as a relying party) wishing
      * to issue a credential to a device using these APIs, must carefully examine the
      * returned certificate chain for all of the above (and more). In particular, the Issuing
-     * Authority should check the root of trust, verified boot state, patch level,
-     * application id, etc.
+     * Authority should check the root of trust (which include verified boot state), patch level,
+     * attestation application id, etc.
      *
      * This all depends on the needs of the Issuing Authority and the kind of credential but
      * in general an Issuing Authority should never issue a credential to a device without
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
index 87d9a93..dfcd4f5 100644
--- a/identity/aidl/default/IdentityCredential.cpp
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -272,6 +272,7 @@
         const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
         const vector<uint8_t>& signingKeyBlob, const vector<uint8_t>& sessionTranscript,
         const vector<uint8_t>& readerSignature, const vector<int32_t>& requestCounts) {
+    std::unique_ptr<cppbor::Item> sessionTranscriptItem;
     if (sessionTranscript.size() > 0) {
         auto [item, _, message] = cppbor::parse(sessionTranscript);
         if (item == nullptr) {
@@ -279,7 +280,7 @@
                     IIdentityCredentialStore::STATUS_INVALID_DATA,
                     "SessionTranscript contains invalid CBOR"));
         }
-        sessionTranscriptItem_ = std::move(item);
+        sessionTranscriptItem = std::move(item);
     }
     if (numStartRetrievalCalls_ > 0) {
         if (sessionTranscript_ != sessionTranscript) {
@@ -319,7 +320,7 @@
         vector<uint8_t> encodedReaderAuthentication =
                 cppbor::Array()
                         .add("ReaderAuthentication")
-                        .add(sessionTranscriptItem_->clone())
+                        .add(std::move(sessionTranscriptItem))
                         .add(cppbor::Semantic(24, itemsRequestBytes))
                         .encode();
         vector<uint8_t> encodedReaderAuthenticationBytes =
@@ -776,13 +777,6 @@
     optional<vector<uint8_t>> mac;
     if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 &&
         readerPublicKey_.size() > 0) {
-        cppbor::Array array;
-        array.add("DeviceAuthentication");
-        array.add(sessionTranscriptItem_->clone());
-        array.add(docType_);
-        array.add(cppbor::Semantic(24, encodedDeviceNameSpaces));
-        vector<uint8_t> deviceAuthenticationBytes = cppbor::Semantic(24, array.encode()).encode();
-
         vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
         optional<vector<uint8_t>> signingKey =
                 support::decryptAes128Gcm(storageKey_, signingKeyBlob_, docTypeAsBlob);
@@ -792,31 +786,15 @@
                     "Error decrypting signingKeyBlob"));
         }
 
-        optional<vector<uint8_t>> sharedSecret =
-                support::ecdh(readerPublicKey_, signingKey.value());
-        if (!sharedSecret) {
-            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_FAILED, "Error doing ECDH"));
-        }
-
-        // Mix-in SessionTranscriptBytes
         vector<uint8_t> sessionTranscriptBytes = cppbor::Semantic(24, sessionTranscript_).encode();
-        vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
-        std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
-                  std::back_inserter(sharedSecretWithSessionTranscriptBytes));
-
-        vector<uint8_t> salt = {0x00};
-        vector<uint8_t> info = {};
-        optional<vector<uint8_t>> derivedKey =
-                support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
-        if (!derivedKey) {
+        optional<vector<uint8_t>> eMacKey =
+                support::calcEMacKey(signingKey.value(), readerPublicKey_, sessionTranscriptBytes);
+        if (!eMacKey) {
             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_FAILED,
-                    "Error deriving key from shared secret"));
+                    IIdentityCredentialStore::STATUS_FAILED, "Error calculating EMacKey"));
         }
-
-        mac = support::coseMac0(derivedKey.value(), {},      // payload
-                                deviceAuthenticationBytes);  // detached content
+        mac = support::calcMac(sessionTranscript_, docType_, encodedDeviceNameSpaces,
+                               eMacKey.value());
         if (!mac) {
             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                     IIdentityCredentialStore::STATUS_FAILED, "Error MACing data"));
@@ -830,9 +808,9 @@
 
 ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
         vector<uint8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
-    string serialDecimal = "0";  // TODO: set serial to something unique
-    string issuer = "Android Open Source Project";
-    string subject = "Android IdentityCredential Reference Implementation";
+    string serialDecimal = "1";
+    string issuer = "Android Identity Credential Key";
+    string subject = "Android Identity Credential Authentication Key";
     time_t validityNotBefore = time(nullptr);
     time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
 
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
index a82531d..a8a6409 100644
--- a/identity/aidl/default/IdentityCredential.h
+++ b/identity/aidl/default/IdentityCredential.h
@@ -103,7 +103,6 @@
     map<int32_t, int> profileIdToAccessCheckResult_;
     vector<uint8_t> signingKeyBlob_;
     vector<uint8_t> sessionTranscript_;
-    std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
     vector<uint8_t> itemsRequest_;
     vector<int32_t> requestCountsRemaining_;
     map<string, set<string>> requestedNameSpacesAndNames_;
diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
index fea289b..141b4de 100644
--- a/identity/aidl/default/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -74,7 +74,7 @@
     vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end());
 
     optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair =
-            support::createEcKeyPairAndAttestation(challenge, appId);
+            support::createEcKeyPairAndAttestation(challenge, appId, testCredential_);
     if (!keyAttestationPair) {
         LOG(ERROR) << "Error creating credentialKey and attestation";
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index c1f44e7..03966de 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -9,7 +9,6 @@
         "VtsIWritableIdentityCredentialTests.cpp",
         "VtsIdentityTestUtils.cpp",
         "VtsAttestationTests.cpp",
-        "VtsAttestationParserSupport.cpp",
         "UserAuthTests.cpp",
         "ReaderAuthTests.cpp",
     ],
@@ -20,13 +19,14 @@
     static_libs: [
         "libcppbor",
         "libkeymaster_portable",
-        "libsoft_attestation_cert",
         "libpuresoftkeymasterdevice",
         "android.hardware.keymaster@4.0",
         "android.hardware.identity-support-lib",
         "android.hardware.identity-cpp",
         "android.hardware.keymaster-cpp",
         "android.hardware.keymaster-ndk_platform",
+        "libkeymaster4support",
+        "libkeymaster4_1support",
     ],
     test_suites: [
         "general-tests",
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.cpp b/identity/aidl/vts/VtsAttestationParserSupport.cpp
deleted file mode 100644
index 71fe733..0000000
--- a/identity/aidl/vts/VtsAttestationParserSupport.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2019, 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 "VtsAttestationParserSupport.h"
-
-#include <aidl/Gtest.h>
-#include <map>
-
-namespace android::hardware::identity::test_utils {
-
-using std::endl;
-using std::map;
-using std::optional;
-using std::string;
-using std::vector;
-
-using ::android::sp;
-using ::android::String16;
-using ::android::binder::Status;
-
-using ::keymaster::ASN1_OBJECT_Ptr;
-using ::keymaster::AuthorizationSet;
-using ::keymaster::EVP_PKEY_Ptr;
-using ::keymaster::kAttestionRecordOid;
-using ::keymaster::TAG_ATTESTATION_APPLICATION_ID;
-using ::keymaster::TAG_IDENTITY_CREDENTIAL_KEY;
-using ::keymaster::TAG_INCLUDE_UNIQUE_ID;
-using ::keymaster::TypedTag;
-using ::keymaster::X509_Ptr;
-
-using support::certificateChainSplit;
-
-optional<keymaster_cert_chain_t> AttestationCertificateParser::certificateChainToKeymasterChain(
-        const vector<Certificate>& certificates) {
-    if (certificates.size() <= 0) {
-        return {};
-    }
-
-    keymaster_cert_chain_t kCert;
-    kCert.entry_count = certificates.size();
-    kCert.entries = (keymaster_blob_t*)malloc(sizeof(keymaster_blob_t) * kCert.entry_count);
-
-    int index = 0;
-    for (const auto& c : certificates) {
-        kCert.entries[index].data_length = c.encodedCertificate.size();
-        uint8_t* data = (uint8_t*)malloc(c.encodedCertificate.size());
-
-        memcpy(data, c.encodedCertificate.data(), c.encodedCertificate.size());
-        kCert.entries[index].data = (const uint8_t*)data;
-        index++;
-    }
-
-    return kCert;
-}
-
-bool AttestationCertificateParser::parse() {
-    optional<keymaster_cert_chain_t> cert_chain = certificateChainToKeymasterChain(origCertChain_);
-    if (!cert_chain) {
-        return false;
-    }
-
-    if (cert_chain.value().entry_count < 3) {
-        return false;
-    }
-
-    if (!verifyChain(cert_chain.value())) {
-        return false;
-    }
-
-    if (!verifyAttestationRecord(cert_chain.value().entries[0])) {
-        return false;
-    }
-
-    keymaster_free_cert_chain(&cert_chain.value());
-    return true;
-}
-
-ASN1_OCTET_STRING* AttestationCertificateParser::getAttestationRecord(X509* certificate) {
-    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1));
-    if (!oid.get()) return nullptr;
-
-    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1);
-    if (location == -1) return nullptr;
-
-    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
-    if (!attest_rec_ext) return nullptr;
-
-    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
-    return attest_rec;
-}
-
-X509* AttestationCertificateParser::parseCertBlob(const keymaster_blob_t& blob) {
-    const uint8_t* p = blob.data;
-    return d2i_X509(nullptr, &p, blob.data_length);
-}
-
-bool AttestationCertificateParser::verifyAttestationRecord(
-        const keymaster_blob_t& attestation_cert) {
-    X509_Ptr cert(parseCertBlob(attestation_cert));
-    if (!cert.get()) {
-        return false;
-    }
-
-    ASN1_OCTET_STRING* attest_rec = getAttestationRecord(cert.get());
-    if (!attest_rec) {
-        return false;
-    }
-
-    keymaster_blob_t att_unique_id = {};
-    keymaster_blob_t att_challenge;
-    keymaster_error_t ret = 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_hw_enforced_,
-            &att_unique_id);
-    if (ret) {
-        return false;
-    }
-
-    att_challenge_.assign(att_challenge.data, att_challenge.data + att_challenge.data_length);
-    return true;
-}
-
-uint32_t AttestationCertificateParser::getKeymasterVersion() {
-    return att_keymaster_version_;
-}
-
-uint32_t AttestationCertificateParser::getAttestationVersion() {
-    return att_attestation_version_;
-}
-
-vector<uint8_t> AttestationCertificateParser::getAttestationChallenge() {
-    return att_challenge_;
-}
-
-keymaster_security_level_t AttestationCertificateParser::getKeymasterSecurityLevel() {
-    return att_keymaster_security_level_;
-}
-
-keymaster_security_level_t AttestationCertificateParser::getAttestationSecurityLevel() {
-    return att_attestation_security_level_;
-}
-
-// Verify the Attestation certificates are correctly chained.
-bool AttestationCertificateParser::verifyChain(const keymaster_cert_chain_t& chain) {
-    for (size_t i = 0; i < chain.entry_count - 1; ++i) {
-        keymaster_blob_t& key_cert_blob = chain.entries[i];
-        keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];
-
-        X509_Ptr key_cert(parseCertBlob(key_cert_blob));
-        X509_Ptr signing_cert(parseCertBlob(signing_cert_blob));
-        if (!key_cert.get() || !signing_cert.get()) {
-            return false;
-        }
-
-        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
-        if (!signing_pubkey.get()) return false;
-
-        if (X509_verify(key_cert.get(), signing_pubkey.get()) != 1) {
-            return false;
-        }
-
-        if (i + 1 == chain.entry_count - 1) {
-            // Last entry is self-signed.
-            if (X509_verify(signing_cert.get(), signing_pubkey.get()) != 1) {
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
-}  // namespace android::hardware::identity::test_utils
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.h b/identity/aidl/vts/VtsAttestationParserSupport.h
deleted file mode 100644
index 7c7e1b6..0000000
--- a/identity/aidl/vts/VtsAttestationParserSupport.h
+++ /dev/null
@@ -1,122 +0,0 @@
-
-/*
- * Copyright 2019, 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 VTS_ATTESTATION_PARSER_SUPPORT_H
-#define VTS_ATTESTATION_PARSER_SUPPORT_H
-
-//#include <aidl/Gtest.h>
-#include <android/hardware/identity/IIdentityCredentialStore.h>
-#include <android/hardware/identity/support/IdentityCredentialSupport.h>
-#include <android/hardware/keymaster/4.0/types.h>
-#include <hardware/keymaster_defs.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster/contexts/pure_soft_keymaster_context.h>
-#include <keymaster/contexts/soft_attestation_cert.h>
-#include <keymaster/keymaster_tags.h>
-#include <keymaster/km_openssl/attestation_utils.h>
-#include <vector>
-
-namespace android::hardware::identity::test_utils {
-
-using ::std::optional;
-using ::std::string;
-using ::std::vector;
-
-using ::keymaster::AuthorizationSet;
-using ::keymaster::TypedTag;
-
-class AttestationCertificateParser {
-  public:
-    AttestationCertificateParser(const vector<Certificate>& certChain)
-        : origCertChain_(certChain) {}
-
-    bool parse();
-
-    uint32_t getKeymasterVersion();
-    uint32_t getAttestationVersion();
-    vector<uint8_t> getAttestationChallenge();
-    keymaster_security_level_t getKeymasterSecurityLevel();
-    keymaster_security_level_t getAttestationSecurityLevel();
-
-    template <keymaster_tag_t Tag>
-    bool getSwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
-        if (att_sw_enforced_.GetTagValue(tag)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    template <keymaster_tag_t Tag>
-    bool getHwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
-        if (att_hw_enforced_.GetTagValue(tag)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    template <keymaster_tag_t Tag>
-    optional<vector<uint8_t>> getHwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
-        keymaster_blob_t blob;
-        if (att_hw_enforced_.GetTagValue(tag, &blob)) {
-            return {};
-        }
-
-        vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
-        return ret;
-    }
-
-    template <keymaster_tag_t Tag>
-    optional<vector<uint8_t>> getSwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
-        keymaster_blob_t blob;
-        if (!att_sw_enforced_.GetTagValue(tag, &blob)) {
-            return {};
-        }
-
-        vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
-        return ret;
-    }
-
-  private:
-    // Helper functions.
-    bool verifyChain(const keymaster_cert_chain_t& chain);
-
-    ASN1_OCTET_STRING* getAttestationRecord(X509* certificate);
-
-    X509* parseCertBlob(const keymaster_blob_t& blob);
-
-    bool verifyAttestationRecord(const keymaster_blob_t& attestation_cert);
-
-    optional<keymaster_cert_chain_t> certificateChainToKeymasterChain(
-            const vector<Certificate>& certificates);
-
-    // Private variables.
-    vector<Certificate> origCertChain_;
-    AuthorizationSet att_sw_enforced_;
-    AuthorizationSet att_hw_enforced_;
-    uint32_t att_attestation_version_;
-    uint32_t att_keymaster_version_;
-    keymaster_security_level_t att_attestation_security_level_;
-    keymaster_security_level_t att_keymaster_security_level_;
-    vector<uint8_t> att_challenge_;
-};
-
-}  // namespace android::hardware::identity::test_utils
-
-#endif  // VTS_ATTESTATION_PARSER_SUPPORT_H
diff --git a/identity/aidl/vts/VtsAttestationTests.cpp b/identity/aidl/vts/VtsAttestationTests.cpp
index 673d08b..5529853 100644
--- a/identity/aidl/vts/VtsAttestationTests.cpp
+++ b/identity/aidl/vts/VtsAttestationTests.cpp
@@ -29,7 +29,6 @@
 #include <future>
 #include <map>
 
-#include "VtsAttestationParserSupport.h"
 #include "VtsIdentityTestUtils.h"
 
 namespace android::hardware::identity {
@@ -44,7 +43,6 @@
 using ::android::String16;
 using ::android::binder::Status;
 
-using test_utils::AttestationCertificateParser;
 using test_utils::setupWritableCredential;
 using test_utils::validateAttestationCertificate;
 
@@ -61,38 +59,12 @@
     sp<IIdentityCredentialStore> credentialStore_;
 };
 
-TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeEmptyId) {
-    Status result;
-
-    HardwareInformation hwInfo;
-    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
-    sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
-
-    string challenge = "NotSoRandomChallenge";
-    vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
-    vector<Certificate> attestationCertificate;
-    vector<uint8_t> attestationApplicationId = {};
-
-    result = writableCredential->getAttestationCertificate(
-            attestationApplicationId, attestationChallenge, &attestationCertificate);
-
-    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
-                               << endl;
-
-    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
-                                               attestationApplicationId, hwInfo));
-}
-
 TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeNonemptyId) {
     Status result;
 
-    HardwareInformation hwInfo;
-    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_,
+                                        false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
     vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
@@ -106,18 +78,16 @@
     ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                                << endl;
 
-    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
-                                               attestationApplicationId, hwInfo));
+    validateAttestationCertificate(attestationCertificate, attestationChallenge,
+                                   attestationApplicationId, false);
 }
 
 TEST_P(VtsAttestationTests, verifyAttestationWithVeryShortChallengeAndId) {
     Status result;
 
-    HardwareInformation hwInfo;
-    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_,
+                                        false /* testCredential */));
 
     string challenge = "c";
     vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
@@ -131,8 +101,8 @@
     ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                                << endl;
 
-    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
-                                               attestationApplicationId, hwInfo));
+    validateAttestationCertificate(attestationCertificate, attestationChallenge,
+                                   attestationApplicationId, false);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VtsAttestationTests);
diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
index 500b79f..cdecb97 100644
--- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
+++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
@@ -174,16 +174,17 @@
 
     string cborPretty;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    true /* testCredential */));
 
     string challenge = "attestationChallenge";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {1} /* atteestationApplicationId */);
     ASSERT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
-    EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate,
-                                               attData.attestationChallenge,
-                                               attData.attestationApplicationId, hwInfo));
+    validateAttestationCertificate(attData.attestationCertificate, attData.attestationChallenge,
+                                   attData.attestationApplicationId, true);
 
     // This is kinda of a hack but we need to give the size of
     // ProofOfProvisioning that we'll expect to receive.
@@ -368,6 +369,7 @@
     optional<vector<uint8_t>> signingPubKey =
             support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
     EXPECT_TRUE(signingPubKey);
+    test_utils::verifyAuthKeyCertificate(signingKeyCertificate.encodedCertificate);
 
     // Since we're using a test-credential we know storageKey meaning we can get the
     // private key. Do this, derive the public key from it, and check this matches what
@@ -418,9 +420,9 @@
     }
 
     vector<uint8_t> mac;
-    vector<uint8_t> deviceNameSpacesBytes;
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+    vector<uint8_t> deviceNameSpacesEncoded;
+    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ(
             "{\n"
             "  'PersonalData' : {\n"
@@ -435,37 +437,19 @@
             "  },\n"
             "}",
             cborPretty);
-    // The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType,
-    // deviceNameSpacesBytes] so build up that structure
-    cppbor::Array deviceAuthentication;
-    deviceAuthentication.add("DeviceAuthentication");
-    deviceAuthentication.add(sessionTranscript.clone());
 
     string docType = "org.iso.18013-5.2019.mdl";
-    deviceAuthentication.add(docType);
-    deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
-    vector<uint8_t> deviceAuthenticationBytes =
-            cppbor::Semantic(24, deviceAuthentication.encode()).encode();
-    // Derive the key used for MACing.
     optional<vector<uint8_t>> readerEphemeralPrivateKey =
             support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
-    optional<vector<uint8_t>> sharedSecret =
-            support::ecdh(signingPubKey.value(), readerEphemeralPrivateKey.value());
-    ASSERT_TRUE(sharedSecret);
-    // Mix-in SessionTranscriptBytes
-    vector<uint8_t> sessionTranscriptBytes =
-            cppbor::Semantic(24, sessionTranscript.encode()).encode();
-    vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
-    std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
-              std::back_inserter(sharedSecretWithSessionTranscriptBytes));
-    vector<uint8_t> salt = {0x00};
-    vector<uint8_t> info = {};
-    optional<vector<uint8_t>> derivedKey =
-            support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
-    ASSERT_TRUE(derivedKey);
+    optional<vector<uint8_t>> eMacKey = support::calcEMacKey(
+            readerEphemeralPrivateKey.value(),                           // Private Key
+            signingPubKey.value(),                                       // Public Key
+            cppbor::Semantic(24, sessionTranscript.encode()).encode());  // SessionTranscriptBytes
     optional<vector<uint8_t>> calculatedMac =
-            support::coseMac0(derivedKey.value(), {},      // payload
-                              deviceAuthenticationBytes);  // detached content
+            support::calcMac(sessionTranscript.encode(),  // SessionTranscript
+                             docType,                     // DocType
+                             deviceNameSpacesEncoded,     // DeviceNamespaces
+                             eMacKey.value());            // EMacKey
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
 
@@ -480,18 +464,14 @@
                                 signingKeyBlob, sessionTranscriptEncoded, {},  // readerSignature,
                                 testEntriesEntryCounts)
                         .isOk());
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ("{}", cborPretty);
     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
-    deviceAuthentication = cppbor::Array();
-    deviceAuthentication.add("DeviceAuthentication");
-    deviceAuthentication.add(sessionTranscript.clone());
-    deviceAuthentication.add(docType);
-    deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
-    deviceAuthenticationBytes = cppbor::Semantic(24, deviceAuthentication.encode()).encode();
-    calculatedMac = support::coseMac0(derivedKey.value(), {},      // payload
-                                      deviceAuthenticationBytes);  // detached content
+    calculatedMac = support::calcMac(sessionTranscript.encode(),  // SessionTranscript
+                                     docType,                     // DocType
+                                     deviceNameSpacesEncoded,     // DeviceNamespaces
+                                     eMacKey.value());            // EMacKey
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
 
@@ -506,18 +486,14 @@
                                 signingKeyBlob, sessionTranscriptEncoded, {},  // readerSignature,
                                 testEntriesEntryCounts)
                         .isOk());
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ("{}", cborPretty);
     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
-    deviceAuthentication = cppbor::Array();
-    deviceAuthentication.add("DeviceAuthentication");
-    deviceAuthentication.add(sessionTranscript.clone());
-    deviceAuthentication.add(docType);
-    deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
-    deviceAuthenticationBytes = cppbor::Semantic(24, deviceAuthentication.encode()).encode();
-    calculatedMac = support::coseMac0(derivedKey.value(), {},      // payload
-                                      deviceAuthenticationBytes);  // detached content
+    calculatedMac = support::calcMac(sessionTranscript.encode(),  // SessionTranscript
+                                     docType,                     // DocType
+                                     deviceNameSpacesEncoded,     // DeviceNamespaces
+                                     eMacKey.value());            // EMacKey
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
 }
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index 8c35952..56e17ba 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -61,7 +61,8 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     vector<uint8_t> attestationChallenge;
     vector<Certificate> attestationCertificate;
@@ -82,12 +83,13 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
     vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
     vector<Certificate> attestationCertificate;
-    vector<uint8_t> attestationApplicationId = {};
+    vector<uint8_t> attestationApplicationId = {1};
 
     result = writableCredential->getAttestationCertificate(
             attestationApplicationId, attestationChallenge, &attestationCertificate);
@@ -95,27 +97,27 @@
     EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                                << endl;
 
-    EXPECT_TRUE(test_utils::validateAttestationCertificate(
-            attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo));
+    test_utils::validateAttestationCertificate(attestationCertificate, attestationChallenge,
+                                               attestationApplicationId, false);
 }
 
 TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) {
     Status result;
 
-    HardwareInformation hwInfo;
-    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge1";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
-    ASSERT_TRUE(test_utils::validateAttestationCertificate(
-            attData.attestationCertificate, attData.attestationChallenge,
-            attData.attestationApplicationId, hwInfo));
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {1} /* atteestationApplicationId */);
+    test_utils::validateAttestationCertificate(attData.attestationCertificate,
+                                               attData.attestationChallenge,
+                                               attData.attestationApplicationId, false);
 
     string challenge2 = "NotSoRandomChallenge2";
-    test_utils::AttestationData attData2(writableCredential, challenge2, {});
+    test_utils::AttestationData attData2(writableCredential, challenge2,
+                                         {} /* atteestationApplicationId */);
     EXPECT_FALSE(attData2.result.isOk()) << attData2.result.exceptionCode() << "; "
                                          << attData2.result.exceptionMessage() << endl;
     EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, attData2.result.exceptionCode());
@@ -125,7 +127,8 @@
 TEST_P(IdentityCredentialTests, verifyStartPersonalization) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // First call should go through
     const vector<int32_t> entryCounts = {2, 4};
@@ -147,7 +150,8 @@
 TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // Verify minimal number of profile count and entry count
     const vector<int32_t> entryCounts = {1, 1};
@@ -160,7 +164,8 @@
 TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // Verify minimal number of profile count and entry count
     const vector<int32_t> entryCounts = {1};
@@ -173,7 +178,8 @@
 TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // Verify set a large number of profile count and entry count is ok
     const vector<int32_t> entryCounts = {3000};
@@ -186,7 +192,8 @@
 TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // Enter mismatched entry and profile numbers
     const vector<int32_t> entryCounts = {5, 6};
@@ -224,7 +231,8 @@
 TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     const vector<int32_t> entryCounts = {3, 6};
     writableCredential->setExpectedProofOfProvisioningSize(123456);
@@ -283,10 +291,12 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge1";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {} /* atteestationApplicationId */);
     EXPECT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
@@ -294,7 +304,7 @@
     ASSERT_TRUE(readerCertificate1);
 
     const vector<int32_t> entryCounts = {1u};
-    size_t expectedPoPSize = 186 + readerCertificate1.value().size();
+    size_t expectedPoPSize = 185 + readerCertificate1.value().size();
     // OK to fail, not available in v1 HAL
     writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
     result = writableCredential->startPersonalization(1, entryCounts);
@@ -308,7 +318,7 @@
     ASSERT_TRUE(secureProfiles);
 
     const vector<test_utils::TestEntryData> testEntries1 = {
-            {"Name Space", "Last name", string("Turing"), vector<int32_t>{0, 1}},
+            {"Name Space", "Last name", string("Turing"), vector<int32_t>{1}},
     };
 
     map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
@@ -347,11 +357,11 @@
             "      {\n"
             "        'name' : 'Last name',\n"
             "        'value' : 'Turing',\n"
-            "        'accessControlProfiles' : [0, 1, ],\n"
+            "        'accessControlProfiles' : [1, ],\n"
             "      },\n"
             "    ],\n"
             "  },\n"
-            "  true,\n"
+            "  false,\n"
             "]",
             cborPretty);
 
@@ -370,10 +380,12 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {} /* atteestationApplicationId */);
     EXPECT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
@@ -510,7 +522,7 @@
             "      },\n"
             "    ],\n"
             "  },\n"
-            "  true,\n"
+            "  false,\n"
             "]",
             cborPretty);
 
@@ -529,10 +541,12 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {} /* atteestationApplicationId */);
     ASSERT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
@@ -591,10 +605,12 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {} /* atteestationApplicationId */);
     ASSERT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
@@ -667,7 +683,8 @@
 
 TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) {
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     const vector<int32_t> entryCounts = {1};
     writableCredential->setExpectedProofOfProvisioningSize(123456);
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp
index b6ed80f..3b10651 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.cpp
+++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp
@@ -14,13 +14,17 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VtsIdentityTestUtils"
+
 #include "VtsIdentityTestUtils.h"
 
 #include <aidl/Gtest.h>
+#include <android-base/logging.h>
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymasterV4_1/attestation_record.h>
+#include <charconv>
 #include <map>
 
-#include "VtsAttestationParserSupport.h"
-
 namespace android::hardware::identity::test_utils {
 
 using std::endl;
@@ -32,15 +36,15 @@
 using ::android::sp;
 using ::android::String16;
 using ::android::binder::Status;
+using ::keymaster::X509_Ptr;
 
 bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
-                             sp<IIdentityCredentialStore>& credentialStore) {
+                             sp<IIdentityCredentialStore>& credentialStore, bool testCredential) {
     if (credentialStore == nullptr) {
         return false;
     }
 
     string docType = "org.iso.18013-5.2019.mdl";
-    bool testCredential = true;
     Status result = credentialStore->createCredential(docType, testCredential, &writableCredential);
 
     if (result.isOk() && writableCredential != nullptr) {
@@ -178,63 +182,269 @@
     }
 }
 
-bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
-                                    const vector<uint8_t>& expectedChallenge,
-                                    const vector<uint8_t>& expectedAppId,
-                                    const HardwareInformation& hwInfo) {
-    AttestationCertificateParser certParser_(inputCertificates);
-    bool ret = certParser_.parse();
-    EXPECT_TRUE(ret);
-    if (!ret) {
+string x509NameToRfc2253String(X509_NAME* name) {
+    char* buf;
+    size_t bufSize;
+    BIO* bio;
+
+    bio = BIO_new(BIO_s_mem());
+    X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+    bufSize = BIO_get_mem_data(bio, &buf);
+    string ret = string(buf, bufSize);
+    BIO_free(bio);
+
+    return ret;
+}
+
+int parseDigits(const char** s, int numDigits) {
+    int result;
+    auto [_, ec] = std::from_chars(*s, *s + numDigits, result);
+    if (ec != std::errc()) {
+        LOG(ERROR) << "Error parsing " << numDigits << " digits "
+                   << " from " << s;
+        return 0;
+    }
+    *s += numDigits;
+    return result;
+}
+
+bool parseAsn1Time(const ASN1_TIME* asn1Time, time_t* outTime) {
+    struct tm tm;
+
+    memset(&tm, '\0', sizeof(tm));
+    const char* timeStr = (const char*)asn1Time->data;
+    const char* s = timeStr;
+    if (asn1Time->type == V_ASN1_UTCTIME) {
+        tm.tm_year = parseDigits(&s, 2);
+        if (tm.tm_year < 70) {
+            tm.tm_year += 100;
+        }
+    } else if (asn1Time->type == V_ASN1_GENERALIZEDTIME) {
+        tm.tm_year = parseDigits(&s, 4) - 1900;
+        tm.tm_year -= 1900;
+    } else {
+        LOG(ERROR) << "Unsupported ASN1_TIME type " << asn1Time->type;
+        return false;
+    }
+    tm.tm_mon = parseDigits(&s, 2) - 1;
+    tm.tm_mday = parseDigits(&s, 2);
+    tm.tm_hour = parseDigits(&s, 2);
+    tm.tm_min = parseDigits(&s, 2);
+    tm.tm_sec = parseDigits(&s, 2);
+    // This may need to be updated if someone create certificates using +/- instead of Z.
+    //
+    if (*s != 'Z') {
+        LOG(ERROR) << "Expected Z in string '" << timeStr << "' at offset " << (s - timeStr);
         return false;
     }
 
-    // As per the IC HAL, the version of the Identity
-    // Credential HAL is 1.0 - and this is encoded as major*10 + minor. This field is used by
-    // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
-    // and integers greater or equal than 41 (for KM starting with 4.1).
-    //
-    // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
-    // version isn't errornously returned.
-    EXPECT_LE(10, certParser_.getKeymasterVersion());
-    EXPECT_GT(40, certParser_.getKeymasterVersion());
-    EXPECT_LE(3, certParser_.getAttestationVersion());
-
-    // Verify the app id matches to whatever we set it to be.
-    optional<vector<uint8_t>> appId =
-            certParser_.getSwEnforcedBlob(::keymaster::TAG_ATTESTATION_APPLICATION_ID);
-    if (appId) {
-        EXPECT_EQ(expectedAppId.size(), appId.value().size());
-        EXPECT_EQ(0, memcmp(expectedAppId.data(), appId.value().data(), expectedAppId.size()));
-    } else {
-        // app id not found
-        EXPECT_EQ(0, expectedAppId.size());
+    time_t t = timegm(&tm);
+    if (t == -1) {
+        LOG(ERROR) << "Error converting broken-down time to time_t";
+        return false;
     }
-
-    EXPECT_TRUE(certParser_.getHwEnforcedBool(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
-    EXPECT_FALSE(certParser_.getHwEnforcedBool(::keymaster::TAG_INCLUDE_UNIQUE_ID));
-
-    // Verify the challenge always matches in size and data of what is passed
-    // in.
-    vector<uint8_t> attChallenge = certParser_.getAttestationChallenge();
-    EXPECT_EQ(expectedChallenge.size(), attChallenge.size());
-    EXPECT_EQ(0, memcmp(expectedChallenge.data(), attChallenge.data(), expectedChallenge.size()));
-
-    // Ensure the attestation conveys that it's implemented in secure hardware (with carve-out
-    // for the reference implementation which cannot be implemented in secure hardware).
-    if (hwInfo.credentialStoreName == "Identity Credential Reference Implementation" &&
-        hwInfo.credentialStoreAuthorName == "Google") {
-        EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getKeymasterSecurityLevel());
-        EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getAttestationSecurityLevel());
-
-    } else {
-        // Actual devices should use TrustedEnvironment or StrongBox.
-        EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getKeymasterSecurityLevel());
-        EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getAttestationSecurityLevel());
-    }
+    *outTime = t;
     return true;
 }
 
+void validateAttestationCertificate(const vector<Certificate>& credentialKeyCertChain,
+                                    const vector<uint8_t>& expectedChallenge,
+                                    const vector<uint8_t>& expectedAppId, bool isTestCredential) {
+    ASSERT_GE(credentialKeyCertChain.size(), 2);
+
+    vector<uint8_t> certBytes = credentialKeyCertChain[0].encodedCertificate;
+    const uint8_t* certData = certBytes.data();
+    X509_Ptr cert = X509_Ptr(d2i_X509(nullptr, &certData, certBytes.size()));
+
+    vector<uint8_t> batchCertBytes = credentialKeyCertChain[1].encodedCertificate;
+    const uint8_t* batchCertData = batchCertBytes.data();
+    X509_Ptr batchCert = X509_Ptr(d2i_X509(nullptr, &batchCertData, batchCertBytes.size()));
+
+    // First get some values from the batch certificate which is checked
+    // against the top-level certificate (subject, notAfter)
+    //
+
+    X509_NAME* batchSubject = X509_get_subject_name(batchCert.get());
+    ASSERT_NE(nullptr, batchSubject);
+    time_t batchNotAfter;
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(batchCert.get()), &batchNotAfter));
+
+    // Check all the requirements from IWritableIdentityCredential::getAttestationCertificate()...
+    //
+
+    //  - version: INTEGER 2 (means v3 certificate).
+    EXPECT_EQ(2, X509_get_version(cert.get()));
+
+    //  - serialNumber: INTEGER 1 (fixed value: same on all certs).
+    EXPECT_EQ(1, ASN1_INTEGER_get(X509_get_serialNumber(cert.get())));
+
+    //  - signature: must be set to ECDSA.
+    EXPECT_EQ(NID_ecdsa_with_SHA256, X509_get_signature_nid(cert.get()));
+
+    //  - subject: CN shall be set to "Android Identity Credential Key". (fixed value:
+    //    same on all certs)
+    X509_NAME* subject = X509_get_subject_name(cert.get());
+    ASSERT_NE(nullptr, subject);
+    EXPECT_EQ("CN=Android Identity Credential Key", x509NameToRfc2253String(subject));
+
+    //  - issuer: Same as the subject field of the batch attestation key.
+    X509_NAME* issuer = X509_get_issuer_name(cert.get());
+    ASSERT_NE(nullptr, issuer);
+    EXPECT_EQ(x509NameToRfc2253String(batchSubject), x509NameToRfc2253String(issuer));
+
+    //  - validity: Should be from current time and expire at the same time as the
+    //    attestation batch certificate used.
+    //
+    //  Allow for 10 seconds drift to account for the time drift between Secure HW
+    //  and this environment plus the difference between when the certificate was
+    //  created and until now
+    //
+    time_t notBefore;
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notBefore(cert.get()), &notBefore));
+    uint64_t now = time(nullptr);
+    int64_t diffSecs = now - notBefore;
+    int64_t allowDriftSecs = 10;
+    EXPECT_LE(-allowDriftSecs, diffSecs);
+    EXPECT_GE(allowDriftSecs, diffSecs);
+
+    time_t notAfter;
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(cert.get()), &notAfter));
+    EXPECT_EQ(notAfter, batchNotAfter);
+
+    auto [err, attRec] = keymaster::V4_1::parse_attestation_record(certBytes);
+    ASSERT_EQ(keymaster::V4_1::ErrorCode::OK, err);
+
+    //  - subjectPublicKeyInfo: must contain attested public key.
+
+    //  - The attestationVersion field in the attestation extension must be at least 3.
+    EXPECT_GE(attRec.attestation_version, 3);
+
+    //  - The attestationSecurityLevel field must be set to either Software (0),
+    //    TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
+    //    implemented.
+    EXPECT_GE(attRec.attestation_security_level,
+              keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+    //  - The keymasterVersion field in the attestation extension must be set to the.
+    //    same value as used for Android Keystore keys.
+    //
+    // Nothing to check here...
+
+    //  - The keymasterSecurityLevel field in the attestation extension must be set to
+    //    either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
+    //    the Trusted Application backing the HAL implementation is implemented.
+    EXPECT_GE(attRec.keymaster_security_level, keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+    //  - The attestationChallenge field must be set to the passed-in challenge.
+    EXPECT_EQ(expectedChallenge.size(), attRec.attestation_challenge.size());
+    EXPECT_TRUE(memcmp(expectedChallenge.data(), attRec.attestation_challenge.data(),
+                       attRec.attestation_challenge.size()) == 0);
+
+    //  - The uniqueId field must be empty.
+    EXPECT_EQ(attRec.unique_id.size(), 0);
+
+    //  - The softwareEnforced field in the attestation extension must include
+    //    Tag::ATTESTATION_APPLICATION_ID which must be set to the bytes of the passed-in
+    //    attestationApplicationId.
+    EXPECT_TRUE(attRec.software_enforced.Contains(keymaster::V4_0::TAG_ATTESTATION_APPLICATION_ID,
+                                                  expectedAppId));
+
+    //  - The teeEnforced field in the attestation extension must include
+    //
+    //    - Tag::IDENTITY_CREDENTIAL_KEY which indicates that the key is an Identity
+    //      Credential key (which can only sign/MAC very specific messages) and not an Android
+    //      Keystore key (which can be used to sign/MAC anything). This must not be set
+    //      for test credentials.
+    bool hasIcKeyTag =
+            attRec.hardware_enforced.Contains(static_cast<android::hardware::keymaster::V4_0::Tag>(
+                    keymaster::V4_1::Tag::IDENTITY_CREDENTIAL_KEY));
+    if (isTestCredential) {
+        EXPECT_FALSE(hasIcKeyTag);
+    } else {
+        EXPECT_TRUE(hasIcKeyTag);
+    }
+
+    //    - Tag::PURPOSE must be set to SIGN
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_PURPOSE,
+                                                  keymaster::V4_0::KeyPurpose::SIGN));
+
+    //    - Tag::KEY_SIZE must be set to the appropriate key size, in bits (e.g. 256)
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_KEY_SIZE, 256));
+
+    //    - Tag::ALGORITHM must be set to EC
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_ALGORITHM,
+                                                  keymaster::V4_0::Algorithm::EC));
+
+    //    - Tag::NO_AUTH_REQUIRED must be set
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_NO_AUTH_REQUIRED));
+
+    //    - Tag::DIGEST must be include SHA_2_256
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_DIGEST,
+                                                  keymaster::V4_0::Digest::SHA_2_256));
+
+    //    - Tag::EC_CURVE must be set to P_256
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_EC_CURVE,
+                                                  keymaster::V4_0::EcCurve::P_256));
+
+    //    - Tag::ROOT_OF_TRUST must be set
+    //
+    EXPECT_GE(attRec.root_of_trust.security_level,
+              keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+    //    - Tag::OS_VERSION and Tag::OS_PATCHLEVEL must be set
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_OS_VERSION));
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_OS_PATCHLEVEL));
+
+    // TODO: we could retrieve osVersion and osPatchLevel from Android itself and compare it
+    // with what was reported in the certificate.
+}
+
+void verifyAuthKeyCertificate(const vector<uint8_t>& authKeyCertChain) {
+    const uint8_t* data = authKeyCertChain.data();
+    auto cert = X509_Ptr(d2i_X509(nullptr, &data, authKeyCertChain.size()));
+
+    //  - version: INTEGER 2 (means v3 certificate).
+    EXPECT_EQ(X509_get_version(cert.get()), 2);
+
+    //  - serialNumber: INTEGER 1 (fixed value: same on all certs).
+    EXPECT_EQ(ASN1_INTEGER_get(X509_get_serialNumber(cert.get())), 1);
+
+    //  - signature: must be set to ECDSA.
+    EXPECT_EQ(X509_get_signature_nid(cert.get()), NID_ecdsa_with_SHA256);
+
+    //  - subject: CN shall be set to "Android Identity Credential Authentication Key". (fixed
+    //    value: same on all certs)
+    X509_NAME* subject = X509_get_subject_name(cert.get());
+    ASSERT_NE(subject, nullptr);
+    EXPECT_EQ(x509NameToRfc2253String(subject),
+              "CN=Android Identity Credential Authentication Key");
+
+    //  - issuer: CN shall be set to "Android Identity Credential Key". (fixed value:
+    //    same on all certs)
+    X509_NAME* issuer = X509_get_issuer_name(cert.get());
+    ASSERT_NE(issuer, nullptr);
+    EXPECT_EQ(x509NameToRfc2253String(issuer), "CN=Android Identity Credential Key");
+
+    //  - subjectPublicKeyInfo: must contain attested public key.
+
+    //  - validity: should be from current time and one year in the future (365 days).
+    time_t notBefore, notAfter;
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(cert.get()), &notAfter));
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notBefore(cert.get()), &notBefore));
+
+    //  Allow for 10 seconds drift to account for the time drift between Secure HW
+    //  and this environment plus the difference between when the certificate was
+    //  created and until now
+    //
+    uint64_t now = time(nullptr);
+    int64_t diffSecs = now - notBefore;
+    int64_t allowDriftSecs = 10;
+    EXPECT_LE(-allowDriftSecs, diffSecs);
+    EXPECT_GE(allowDriftSecs, diffSecs);
+    constexpr uint64_t kSecsInOneYear = 365 * 24 * 60 * 60;
+    EXPECT_EQ(notBefore + kSecsInOneYear, notAfter);
+}
+
 vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries) {
     vector<RequestNamespace> ret;
     RequestNamespace curNs;
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.h b/identity/aidl/vts/VtsIdentityTestUtils.h
index 673b736..85c24f8 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.h
+++ b/identity/aidl/vts/VtsIdentityTestUtils.h
@@ -34,8 +34,8 @@
 
 struct AttestationData {
     AttestationData(sp<IWritableIdentityCredential>& writableCredential, string challenge,
-                    vector<uint8_t> applicationId)
-        : attestationApplicationId(applicationId) {
+                    vector<uint8_t> attestationAppId)
+        : attestationApplicationId(attestationAppId) {
         // ASSERT_NE(writableCredential, nullptr);
 
         if (!challenge.empty()) {
@@ -94,7 +94,7 @@
 };
 
 bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
-                             sp<IIdentityCredentialStore>& credentialStore);
+                             sp<IIdentityCredentialStore>& credentialStore, bool testCredential);
 
 optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal);
 
@@ -111,13 +111,17 @@
 
 void setImageData(vector<uint8_t>& image);
 
-bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
+void validateAttestationCertificate(const vector<Certificate>& credentialKeyCertChain,
                                     const vector<uint8_t>& expectedChallenge,
-                                    const vector<uint8_t>& expectedAppId,
-                                    const HardwareInformation& hwInfo);
+                                    const vector<uint8_t>& expectedAppId, bool isTestCredential);
 
 vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries);
 
+// Verifies that the X.509 certificate for a just created authentication key
+// is valid.
+//
+void verifyAuthKeyCertificate(const vector<uint8_t>& authKeyCertChain);
+
 }  // namespace android::hardware::identity::test_utils
 
 #endif  // VTS_IDENTITY_TEST_UTILS_H
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index f7ec7c5..3aa5bb6 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -35,6 +35,9 @@
 using ::std::vector;
 using ::std::pair;
 
+// The semantic tag for a bstr which includes Encoded CBOR (RFC 7049, section 2.4)
+const int kSemanticTagEncodedCbor = 24;
+
 // ---------------------------------------------------------------------------
 // Miscellaneous utilities.
 // ---------------------------------------------------------------------------
@@ -108,45 +111,47 @@
 // ---------------------------------------------------------------------------
 // EC crypto functionality / abstraction (only supports P-256).
 // ---------------------------------------------------------------------------
+
 // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
-// PKCS#8 encoded key-pair.  Also generates an attestation
-// certificate using the |challenge| and |applicationId|, and returns the generated
-// certificate in X.509 certificate chain format.
+// DER encoded private key.  Also generates an attestation using the |challenge|
+// and |applicationId|, and returns the generated certificate chain.
 //
-// The attestation time fields used will be the current time, and expires in one year.
+// The notBeffore field will be the current time and the notAfter will be the same
+// same time as the batch certificate.
 //
 // The first parameter of the return value is the keyPair generated, second return in
 // the pair is the attestation certificate generated.
-optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
-        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
-
-// Like createEcKeyPairAndAttestation() but allows you to choose the public key.
 //
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+        bool isTestCredential);
+
+// (TODO: remove when no longer used by 3rd party.)
 optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
         const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
         const vector<uint8_t>& applicationId);
 
 // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
-// PKCS#8 encoded key-pair.
+// private key in DER format (as specified in RFC 5915).
 //
 optional<vector<uint8_t>> createEcKeyPair();
 
-// For an EC key |keyPair| encoded in PKCS#8 format, extracts the public key in
+// For an EC key |keyPair| encoded in DER format, extracts the public key in
 // uncompressed point form.
 //
 optional<vector<uint8_t>> ecKeyPairGetPublicKey(const vector<uint8_t>& keyPair);
 
-// For an EC key |keyPair| encoded in PKCS#8 format, extracts the private key as
+// For an EC key |keyPair| encoded in DER format, extracts the private key as
 // an EC uncompressed key.
 //
 optional<vector<uint8_t>> ecKeyPairGetPrivateKey(const vector<uint8_t>& keyPair);
 
-// Creates a PKCS#8 encoded key-pair from a private key (which must be uncompressed,
-// e.g. 32 bytes). The public key is derived from the given private key..
+// Creates a DER encoded representation from a private key (which must be uncompressed,
+// e.g. 32 bytes).
 //
 optional<vector<uint8_t>> ecPrivateKeyToKeyPair(const vector<uint8_t>& privateKey);
 
-// For an EC key |keyPair| encoded in PKCS#8 format, creates a PKCS#12 structure
+// For an EC key |keyPair| encoded in DER format, creates a PKCS#12 structure
 // with the key-pair (not using a password to encrypt the data). The public key
 // in the created structure is included as a certificate, using the given fields
 // |serialDecimal|, |issuer|, |subject|, |validityNotBefore|, and
@@ -209,6 +214,13 @@
 //
 optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate);
 
+// Extracts notBefore and notAfter from the top-most certificate in |certificateChain
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Returns notBefore and notAfter in that order.
+//
+optional<pair<time_t, time_t>> certificateGetValidity(const vector<uint8_t>& x509Certificate);
+
 // Generates a X.509 certificate for |publicKey| (which must be in the format
 // returned by ecKeyPairGetPublicKey()).
 //
@@ -351,6 +363,15 @@
 // Utility functions specific to IdentityCredential.
 // ---------------------------------------------------------------------------
 
+optional<vector<uint8_t>> calcMac(const vector<uint8_t>& sessionTranscriptEncoded,
+                                  const string& docType,
+                                  const vector<uint8_t>& deviceNameSpacesEncoded,
+                                  const vector<uint8_t>& eMacKey);
+
+optional<vector<uint8_t>> calcEMacKey(const vector<uint8_t>& privateKey,
+                                      const vector<uint8_t>& publicKey,
+                                      const vector<uint8_t>& sessionTranscriptBytes);
+
 // Returns the testing AES-128 key where all bits are set to 0.
 const vector<uint8_t>& getTestHardwareBoundKey();
 
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 747f182..fbf3ab1 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -44,6 +44,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <charconv>
 
 #include <cppbor.h>
 #include <cppbor_parse.h>
@@ -870,16 +871,97 @@
     return hmac;
 }
 
+int parseDigits(const char** s, int numDigits) {
+    int result;
+    auto [_, ec] = std::from_chars(*s, *s + numDigits, result);
+    if (ec != std::errc()) {
+        LOG(ERROR) << "Error parsing " << numDigits << " digits "
+                   << " from " << s;
+        return 0;
+    }
+    *s += numDigits;
+    return result;
+}
+
+bool parseAsn1Time(const ASN1_TIME* asn1Time, time_t* outTime) {
+    struct tm tm;
+
+    memset(&tm, '\0', sizeof(tm));
+    const char* timeStr = (const char*)asn1Time->data;
+    const char* s = timeStr;
+    if (asn1Time->type == V_ASN1_UTCTIME) {
+        tm.tm_year = parseDigits(&s, 2);
+        if (tm.tm_year < 70) {
+            tm.tm_year += 100;
+        }
+    } else if (asn1Time->type == V_ASN1_GENERALIZEDTIME) {
+        tm.tm_year = parseDigits(&s, 4) - 1900;
+        tm.tm_year -= 1900;
+    } else {
+        LOG(ERROR) << "Unsupported ASN1_TIME type " << asn1Time->type;
+        return false;
+    }
+    tm.tm_mon = parseDigits(&s, 2) - 1;
+    tm.tm_mday = parseDigits(&s, 2);
+    tm.tm_hour = parseDigits(&s, 2);
+    tm.tm_min = parseDigits(&s, 2);
+    tm.tm_sec = parseDigits(&s, 2);
+    // This may need to be updated if someone create certificates using +/- instead of Z.
+    //
+    if (*s != 'Z') {
+        LOG(ERROR) << "Expected Z in string '" << timeStr << "' at offset " << (s - timeStr);
+        return false;
+    }
+
+    time_t t = timegm(&tm);
+    if (t == -1) {
+        LOG(ERROR) << "Error converting broken-down time to time_t";
+        return false;
+    }
+    *outTime = t;
+    return true;
+}
+
 // Generates the attestation certificate with the parameters passed in.  Note
 // that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in
 // milli seconds since epoch.  We are setting them to milliseconds due to
 // requirement in AuthorizationSet KM_DATE fields.  The certificate created is
 // actually in seconds.
-optional<vector<vector<uint8_t>>> createAttestation(const EVP_PKEY* key,
-                                                    const vector<uint8_t>& applicationId,
-                                                    const vector<uint8_t>& challenge,
-                                                    uint64_t activeTimeMilliSeconds,
-                                                    uint64_t expireTimeMilliSeconds) {
+//
+// If 0 is passed for expiration time, the expiration time from batch
+// certificate will be used.
+//
+optional<vector<vector<uint8_t>>> createAttestation(
+        const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge,
+        uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds, bool isTestCredential) {
+    const keymaster_cert_chain_t* attestation_chain =
+            ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
+    if (attestation_chain == nullptr) {
+        LOG(ERROR) << "Error getting attestation chain";
+        return {};
+    }
+    if (expireTimeMilliSeconds == 0) {
+        if (attestation_chain->entry_count < 1) {
+            LOG(ERROR) << "Expected at least one entry in attestation chain";
+            return {};
+        }
+        keymaster_blob_t* bcBlob = &(attestation_chain->entries[0]);
+        const uint8_t* bcData = bcBlob->data;
+        auto bc = X509_Ptr(d2i_X509(nullptr, &bcData, bcBlob->data_length));
+        time_t bcNotAfter;
+        if (!parseAsn1Time(X509_get0_notAfter(bc.get()), &bcNotAfter)) {
+            LOG(ERROR) << "Error getting notAfter from batch certificate";
+            return {};
+        }
+        expireTimeMilliSeconds = bcNotAfter * 1000;
+    }
+    const keymaster_key_blob_t* attestation_signing_key =
+            ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
+    if (attestation_signing_key == nullptr) {
+        LOG(ERROR) << "Error getting attestation key";
+        return {};
+    }
+
     ::keymaster::AuthorizationSet auth_set(
             ::keymaster::AuthorizationSetBuilder()
                     .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(),
@@ -901,7 +983,7 @@
     ::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization(
             ::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds));
 
-    ::keymaster::AuthorizationSet hwEnforced(
+    ::keymaster::AuthorizationSetBuilder hwEnforcedBuilder =
             ::keymaster::AuthorizationSetBuilder()
                     .Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN)
                     .Authorization(::keymaster::TAG_KEY_SIZE, 256)
@@ -909,34 +991,29 @@
                     .Authorization(::keymaster::TAG_NO_AUTH_REQUIRED)
                     .Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256)
                     .Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256)
-                    .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
+                    .Authorization(::keymaster::TAG_OS_VERSION, 42)
+                    .Authorization(::keymaster::TAG_OS_PATCHLEVEL, 43);
 
-    const keymaster_cert_chain_t* attestation_chain =
-            ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
-
-    if (attestation_chain == nullptr) {
-        LOG(ERROR) << "Error getting attestation chain";
-        return {};
+    // Only include TAG_IDENTITY_CREDENTIAL_KEY if it's not a test credential
+    if (!isTestCredential) {
+        hwEnforcedBuilder.Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY);
     }
-
-    const keymaster_key_blob_t* attestation_signing_key =
-            ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
-    if (attestation_signing_key == nullptr) {
-        LOG(ERROR) << "Error getting attestation key";
-        return {};
-    }
+    ::keymaster::AuthorizationSet hwEnforced(hwEnforcedBuilder);
 
     keymaster_error_t error;
     ::keymaster::CertChainPtr cert_chain_out;
-    ::keymaster::PureSoftKeymasterContext context;
 
-    // set identity version to 10 per hal requirements specified in IWriteableCredential.hal
-    // For now, the identity version in the attestation is set in the keymaster
-    // version field in the portable keymaster lib, which is a bit misleading.
-    uint identity_version = 10;
-    error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context,
-                                          identity_version, *attestation_chain,
-                                          *attestation_signing_key, &cert_chain_out);
+    // Pretend to be implemented in a trusted environment just so we can pass
+    // the VTS tests. Of course, this is a pretend-only game since hopefully no
+    // relying party is ever going to trust our batch key and those keys above
+    // it.
+    //
+    ::keymaster::PureSoftKeymasterContext context(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
+
+    error = generate_attestation_from_EVP_with_subject_name(
+            key, swEnforced, hwEnforced, auth_set, context, ::keymaster::kCurrentKeymasterVersion,
+            *attestation_chain, *attestation_signing_key, "Android Identity Credential Key",
+            &cert_chain_out);
 
     if (KM_ERROR_OK != error || !cert_chain_out) {
         LOG(ERROR) << "Error generate attestation from EVP key" << error;
@@ -957,7 +1034,8 @@
 }
 
 optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
-        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+        bool isTestCredential) {
     auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new());
     auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new());
     auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
@@ -978,12 +1056,11 @@
         return {};
     }
 
-    uint64_t now = time(nullptr);
-    uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
-    uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+    uint64_t nowMs = time(nullptr) * 1000;
+    uint64_t expireTimeMs = 0;  // Set to same as batch certificate
 
-    optional<vector<vector<uint8_t>>> attestationCert =
-            createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+    optional<vector<vector<uint8_t>>> attestationCert = createAttestation(
+            pkey.get(), applicationId, challenge, nowMs, expireTimeMs, isTestCredential);
     if (!attestationCert) {
         LOG(ERROR) << "Error create attestation from key and challenge";
         return {};
@@ -1031,14 +1108,12 @@
         return {};
     }
 
-    uint64_t now = (std::chrono::duration_cast<std::chrono::nanoseconds>(
-                    std::chrono::system_clock::now().time_since_epoch()).
-                    count()/ 1000000000);
-    uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
-    uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+    uint64_t nowMs = time(nullptr) * 1000;
+    uint64_t expireTimeMs = 0;  // Set to same as batch certificate
 
     optional<vector<vector<uint8_t>>> attestationCert =
-            createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+            createAttestation(pkey.get(), applicationId, challenge, nowMs, expireTimeMs,
+                              false /* isTestCredential */);
     if (!attestationCert) {
         LOG(ERROR) << "Error create attestation from key and challenge";
         return {};
@@ -1646,6 +1721,32 @@
     return std::make_pair(tbsCertificateOffset, tbsCertificateSize);
 }
 
+optional<pair<time_t, time_t>> certificateGetValidity(const vector<uint8_t>& x509Certificate) {
+    vector<X509_Ptr> certs;
+    if (!parseX509Certificates(x509Certificate, certs)) {
+        LOG(ERROR) << "Error parsing certificates";
+        return {};
+    }
+    if (certs.size() < 1) {
+        LOG(ERROR) << "No certificates in chain";
+        return {};
+    }
+
+    time_t notBefore;
+    time_t notAfter;
+    if (!parseAsn1Time(X509_get0_notBefore(certs[0].get()), &notBefore)) {
+        LOG(ERROR) << "Error parsing notBefore";
+        return {};
+    }
+
+    if (!parseAsn1Time(X509_get0_notAfter(certs[0].get()), &notAfter)) {
+        LOG(ERROR) << "Error parsing notAfter";
+        return {};
+    }
+
+    return std::make_pair(notBefore, notAfter);
+}
+
 optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate) {
     vector<X509_Ptr> certs;
     if (!parseX509Certificates(x509Certificate, certs)) {
@@ -2218,6 +2319,49 @@
 // Utility functions specific to IdentityCredential.
 // ---------------------------------------------------------------------------
 
+optional<vector<uint8_t>> calcEMacKey(const vector<uint8_t>& privateKey,
+                                      const vector<uint8_t>& publicKey,
+                                      const vector<uint8_t>& sessionTranscriptBytes) {
+    optional<vector<uint8_t>> sharedSecret = support::ecdh(publicKey, privateKey);
+    if (!sharedSecret) {
+        LOG(ERROR) << "Error performing ECDH";
+        return {};
+    }
+    vector<uint8_t> salt = support::sha256(sessionTranscriptBytes);
+    vector<uint8_t> info = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
+    optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
+    if (!derivedKey) {
+        LOG(ERROR) << "Error performing HKDF";
+        return {};
+    }
+    return derivedKey.value();
+}
+
+optional<vector<uint8_t>> calcMac(const vector<uint8_t>& sessionTranscriptEncoded,
+                                  const string& docType,
+                                  const vector<uint8_t>& deviceNameSpacesEncoded,
+                                  const vector<uint8_t>& eMacKey) {
+    auto [sessionTranscriptItem, _, errMsg] = cppbor::parse(sessionTranscriptEncoded);
+    if (sessionTranscriptItem == nullptr) {
+        LOG(ERROR) << "Error parsing sessionTranscriptEncoded: " << errMsg;
+        return {};
+    }
+    // The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType,
+    // deviceNameSpacesBytes] so build up that structure
+    cppbor::Array deviceAuthentication =
+            cppbor::Array()
+                    .add("DeviceAuthentication")
+                    .add(std::move(sessionTranscriptItem))
+                    .add(docType)
+                    .add(cppbor::Semantic(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
+    vector<uint8_t> deviceAuthenticationBytes =
+            cppbor::Semantic(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
+    optional<vector<uint8_t>> calculatedMac =
+            support::coseMac0(eMacKey, {},                 // payload
+                              deviceAuthenticationBytes);  // detached content
+    return calculatedMac;
+}
+
 vector<vector<uint8_t>> chunkVector(const vector<uint8_t>& content, size_t maxChunkSize) {
     vector<vector<uint8_t>> ret;
 
diff --git a/identity/support/tests/IdentityCredentialSupportTest.cpp b/identity/support/tests/IdentityCredentialSupportTest.cpp
index c356549..266f263 100644
--- a/identity/support/tests/IdentityCredentialSupportTest.cpp
+++ b/identity/support/tests/IdentityCredentialSupportTest.cpp
@@ -436,6 +436,300 @@
             support::cborPrettyPrint(mac.value()));
 }
 
+// Generates a private key in DER format for a small value of 'd'.
+//
+// Used for test vectors.
+//
+vector<uint8_t> p256PrivateKeyFromD(uint8_t d) {
+    vector<uint8_t> privateUncompressed;
+    privateUncompressed.resize(32);
+    privateUncompressed[31] = d;
+    optional<vector<uint8_t>> privateKey = support::ecPrivateKeyToKeyPair(privateUncompressed);
+    return privateKey.value();
+}
+
+std::pair<vector<uint8_t>, vector<uint8_t>> p256PrivateKeyGetXandY(
+        const vector<uint8_t> privateKey) {
+    optional<vector<uint8_t>> publicUncompressed = support::ecKeyPairGetPublicKey(privateKey);
+    vector<uint8_t> x = vector<uint8_t>(publicUncompressed.value().begin() + 1,
+                                        publicUncompressed.value().begin() + 33);
+    vector<uint8_t> y = vector<uint8_t>(publicUncompressed.value().begin() + 33,
+                                        publicUncompressed.value().begin() + 65);
+    return std::make_pair(x, y);
+}
+
+const cppbor::Item* findValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    // TODO: Need cast until libcppbor's Map::get() is marked as const
+    auto [item, found] = ((cppbor::Map*)map)->get(keyValue);
+    if (!found) {
+        return nullptr;
+    }
+    return item.get();
+}
+
+const cppbor::Array* findArrayValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    const cppbor::Item* item = findValueForTstr(map, keyValue);
+    if (item == nullptr) {
+        return nullptr;
+    }
+    return item->asArray();
+}
+
+const cppbor::Map* findMapValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    const cppbor::Item* item = findValueForTstr(map, keyValue);
+    if (item == nullptr) {
+        return nullptr;
+    }
+    return item->asMap();
+}
+
+const cppbor::Semantic* findSemanticValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    const cppbor::Item* item = findValueForTstr(map, keyValue);
+    if (item == nullptr) {
+        return nullptr;
+    }
+    return item->asSemantic();
+}
+
+const std::string findStringValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    const cppbor::Item* item = findValueForTstr(map, keyValue);
+    if (item == nullptr) {
+        return nullptr;
+    }
+    const cppbor::Tstr* tstr = item->asTstr();
+    if (tstr == nullptr) {
+        return "";
+    }
+    return tstr->value();
+}
+
+TEST(IdentityCredentialSupport, testVectors_18013_5) {
+    // This is a test against known vectors for ISO 18013-5.
+    //
+    // The objective of this test is to verify that support::calcEMacKey() and
+    // support::calcMac() agree with the given test vectors.
+    //
+
+    // We're given static device key:
+    //
+    //     x: 28412803729898893058558238221310261427084375743576167377786533380249859400145
+    //     y: 65403602826180996396520286939226973026599920614829401631985882360676038096704
+    //     d: 11
+    //
+    vector<uint8_t> deviceKey = p256PrivateKeyFromD(11);
+    auto [deviceKeyX, deviceKeyY] = p256PrivateKeyGetXandY(deviceKey);
+    EXPECT_EQ(support::encodeHex(deviceKeyX),
+              "3ed113b7883b4c590638379db0c21cda16742ed0255048bf433391d374bc21d1");
+    EXPECT_EQ(support::encodeHex(deviceKeyY),
+              "9099209accc4c8a224c843afa4f4c68a090d04da5e9889dae2f8eefce82a3740");
+
+    // We're given Ephemeral reader key:
+    //
+    //   x: 59535862115950685744176693329402396749019581632805653266809849538337418304154
+    //   y: 53776829996815113213100700404832701936765102413212294632483274374518863708344
+    //   d: 20
+    //
+    vector<uint8_t> ephemeralReaderKey = p256PrivateKeyFromD(20);
+    auto [ephemeralReaderKeyX, ephemeralReaderKeyY] = p256PrivateKeyGetXandY(ephemeralReaderKey);
+    EXPECT_EQ(support::encodeHex(ephemeralReaderKeyX),
+              "83a01a9378395bab9bcd6a0ad03cc56d56e6b19250465a94a234dc4c6b28da9a");
+    EXPECT_EQ(support::encodeHex(ephemeralReaderKeyY),
+              "76e49b6de2f73234ae6a5eb9d612b75c9f2202bb6923f54ff8240aaa86f640b8");
+    vector<uint8_t> ephemeralReaderKeyPublic =
+            support::ecKeyPairGetPublicKey(ephemeralReaderKey).value();
+
+    // We're given SessionEstablishment.
+    //
+    //   SessionEstablishment = {
+    //     "eReaderKey" : EReaderKeyBytes,
+    //     "data" : bstr ; Encrypted mdoc request
+    //   }
+    //
+    // Fish out EReaderKey from this.
+    //
+    // Note that the test vector below is incorrect insofar that it uses
+    // "eReaderKeyBytes" instead of just "eReaderKey". This will be corrected in
+    // the future.
+    //
+    optional<vector<uint8_t>> sessionEstablishmentEncoded = support::decodeHex(
+            "a26f655265616465724b65794279746573d818584ba40102200121582083a01a9378395bab9bcd6a0ad03c"
+            "c56d56e6b19250465a94a234dc4c6b28da9a22582076e49b6de2f73234ae6a5eb9d612b75c9f2202bb6923"
+            "f54ff8240aaa86f640b864646174615902d945b31040c57491acb6d46a71f6c1f67a0b837df1bda9089fd0"
+            "3d0b1fdac3eeb2874a4ef6f90c97d03397186ba00a91102faae7e992e15f761d5662c3c37e3c6c2cfd2ebc"
+            "0bf59dbb8795e377bd7dd353230a41ba2d82294b45871a39b42ca531f26b52f46e356fbaf5075c8fd5b8b0"
+            "8a0df4a1d2e1bdd2e5d69169c1efbb51e393e608d833d325bebfbccb2e15ec08f94b264582fa7b93f7cebc"
+            "aa69f4f0cac2744d4fe35b04df26b2ae69273eed33024949080c1c95a6ef046beede959e9494297dd770af"
+            "4ac6fdd56783aa012555c213dc05cf0f41d1c95119720fcfe1621027f80e2ddd56ea3c1fc596f7b2579333"
+            "5a887ec788092b4a69d23b6219e27d0249b50b3fdcb95b5227007689362e0416b3bae3dae7cb56b4394666"
+            "4e3a3f60dce8d0b678fcd754bebf87bd2b0278dd782d952488a46f2874e34c2dd97bb74084a62b850e9719"
+            "252cd1dca7dbf1858193f6cf093cb3735312bbe1138cf29d8f350e285923f8ef07065299926720b42264e8"
+            "fd5d4b133e72f47c4e999ea689c353f8b41e50a59838e1a0d09eca4a557f77a9c389a0591ad1639119ce86"
+            "edc3320130480ee5101effae6066e8c85aac9ead2ae83e49c1e508aab02f753decbb522ea2200d62fd5d26"
+            "094bd35100bffaa1cdc6af9f7e9cfe7b63da6b5671cd5ac2cf5da450c72addc64cde441f3b7f7fdaf930ad"
+            "1e13388e8a7308d8ca4607e59e082db431a232e7e12cb692baeb4b2127e110ff24cea322ffdbc2e4d9c4c6"
+            "bed27753137d07897c8613627a799a560cf1a2d1edb3de029442862940a5ed7785eea8b6ace93aa6af0792"
+            "fd82877f62d07b757d0179ecbb7347004ecc9c0690d41f75f188cb17ffd2cec2ad8c9675466bb33b737a2a"
+            "e7592b2dcb8132aced2e572266f3f5413a5f9d6d4339a1e4662622af2e7e157a4ea3bfd5c4247e2ec91d8c"
+            "5c3c17427d5edfae673d0e0f782a8d40fa805fd8bc82ae3cb21a65cdad863e02309f6b01d1753fa884b778"
+            "f6e019a2004d8964deeb11f1fd478fcb");
+    ASSERT_TRUE(sessionEstablishmentEncoded);
+    auto [sessionEstablishmentItem, _se, _se2] = cppbor::parse(sessionEstablishmentEncoded.value());
+    const cppbor::Map* sessionEstablishment = sessionEstablishmentItem->asMap();
+    ASSERT_NE(sessionEstablishment, nullptr);
+    const cppbor::Semantic* eReaderKeyBytes =
+            findSemanticValueForTstr(sessionEstablishment, "eReaderKeyBytes");
+    ASSERT_NE(eReaderKeyBytes, nullptr);
+    ASSERT_EQ(eReaderKeyBytes->value(), 24);
+    const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->child()->asBstr();
+    ASSERT_NE(eReaderKeyBstr, nullptr);
+    vector<uint8_t> eReaderKeyEncoded = eReaderKeyBstr->value();
+    // TODO: verify this agrees with ephemeralReaderKeyX and ephemeralReaderKeyY
+
+    // We're given DeviceEngagement.
+    //
+    vector<uint8_t> deviceEngagementEncoded =
+            support::decodeHex(
+                    "a20063312e30018201d818584ba401022001215820cef66d6b2a3a993e591214d1ea223fb545ca"
+                    "6c471c48306e4c36069404c5723f225820878662a229aaae906e123cdd9d3b4c10590ded29fe75"
+                    "1eeeca34bbaa44af0773")
+                    .value();
+
+    // Now calculate SessionTranscriptBytes. It is defined as
+    //
+    //   SessionTranscript = [
+    //      DeviceEngagementBytes,
+    //      EReaderKeyBytes,
+    //      Handover
+    //   ]
+    //
+    //   SessionTranscriptBytes = #6.24(bstr .cbor SessionTranscript)
+    //
+    cppbor::Array sessionTranscript;
+    sessionTranscript.add(cppbor::Semantic(24, deviceEngagementEncoded));
+    sessionTranscript.add(cppbor::Semantic(24, eReaderKeyEncoded));
+    sessionTranscript.add(cppbor::Null());
+    vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
+    vector<uint8_t> sessionTranscriptBytes =
+            cppbor::Semantic(24, sessionTranscriptEncoded).encode();
+
+    // The expected EMacKey is 4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2
+    //
+    // Verify that support::calcEMacKey() gets the same result.
+    //
+    optional<vector<uint8_t>> eMacKey =
+            support::calcEMacKey(support::ecKeyPairGetPrivateKey(deviceKey).value(),  // private key
+                                 ephemeralReaderKeyPublic,                            // public key
+                                 sessionTranscriptBytes);  // sessionTranscriptBytes
+    ASSERT_TRUE(eMacKey);
+    ASSERT_EQ(support::encodeHex(eMacKey.value()),
+              "4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2");
+
+    // Also do it the other way around
+    //
+    optional<vector<uint8_t>> eMacKey2 = support::calcEMacKey(
+            support::ecKeyPairGetPrivateKey(ephemeralReaderKey).value(),  // private key
+            support::ecKeyPairGetPublicKey(deviceKey).value(),            // public key
+            sessionTranscriptBytes);                                      // sessionTranscriptBytes
+    ASSERT_TRUE(eMacKey2);
+    ASSERT_EQ(support::encodeHex(eMacKey2.value()),
+              "4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2");
+
+    // We're given DeviceResponse
+    //
+    vector<uint8_t> deviceResponseEncoded =
+            support::decodeHex(
+                    "a36776657273696f6e63312e3069646f63756d656e747381a367646f6354797065756f72672e69"
+                    "736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d6553706163"
+                    "6573a2716f72672e69736f2e31383031332e352e3181d8185863a4686469676573744944016672"
+                    "616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e9"
+                    "71656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456"
+                    "616c756563446f656b636f6d2e6578616d706c6581d8185864a468646967657374494401667261"
+                    "6e646f6d5820218ecf13521b53f4b96abaebe56417afec0e4c91fc8fb26086cd1e5cdc1a94ff71"
+                    "656c656d656e744964656e7469666965726f616e6f746865725f656c656d656e746c656c656d65"
+                    "6e7456616c75650a6a697373756572417574688443a10126a118215901d2308201ce30820174a0"
+                    "0302010202141f7d44f4f107c5ee3f566049cf5d72de294b0d23300a06082a8648ce3d04030230"
+                    "233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e17"
+                    "0d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504"
+                    "030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106"
+                    "082a8648ce3d03010703420004301d9e502dc7e05da85da026a7ae9aa0fac9db7d52a95b3e3e3f"
+                    "9aa0a1b45b8b6551b6f6b3061223e0d23c026b017d72298d9ae46887ca61d58db6aea17ee267a3"
+                    "8187308184301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c"
+                    "0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e04160414"
+                    "7bef4db59a1ffb07592bfc57f4743b8a73aea792300e0603551d0f0101ff040403020780301506"
+                    "03551d250101ff040b3009060728818c5d050102300a06082a8648ce3d04030203480030450220"
+                    "21d52fb1fbda80e5bfda1e8dfb1bc7bf0acb7261d5c9ff54425af76eb21571c602210082bf301f"
+                    "89e0a2cb9ca9c9050352de80b47956764f7a3e07bf6a8cd87528a3b55901d2d8185901cda66776"
+                    "657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c75"
+                    "6544696765737473a2716f72672e69736f2e31383031332e352e31a20058203b22af1126771f02"
+                    "f0ea0d546d4ee3c5b51637381154f5211b79daf5f9facaa8015820f2cba0ce3cde5df901a3da75"
+                    "13a4d7f7225fdfe5a306544529bf3dbcce655ca06b636f6d2e6578616d706c65a200582072636d"
+                    "ddc282424a63499f4b3927aaa3b74da7b9c0134178bf735e949e4a761e01582006322d3cbe6603"
+                    "876bdacc5b6679b51b0fc53d029c244fd5ea719d9028459c916d6465766963654b6579496e666f"
+                    "a1696465766963654b6579a4010220012158203ed113b7883b4c590638379db0c21cda16742ed0"
+                    "255048bf433391d374bc21d12258209099209accc4c8a224c843afa4f4c68a090d04da5e9889da"
+                    "e2f8eefce82a374067646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c"
+                    "76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a"
+                    "30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c"
+                    "6964556e74696cc074323032312d31302d30315431333a33303a30325a5840273ec1b59817d571"
+                    "b5a2c5c0ab0ea213d42acb18547fd7097afcc888a22ecbb863c6461ce0e240880895b4aaa84308"
+                    "784571c7be7aa3a2e7e3a2ea1a145ed1966c6465766963655369676e6564a26a6e616d65537061"
+                    "636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f6582009"
+                    "da7c964ac004ec36ec64edd0c1abf50c03433c215c3ddb144768abcdf20a60667374617475730"
+                    "0")
+                    .value();
+    auto [deviceResponseItem, _, _2] = cppbor::parse(deviceResponseEncoded);
+    const cppbor::Map* deviceResponse = deviceResponseItem->asMap();
+    ASSERT_NE(deviceResponse, nullptr);
+    const cppbor::Array* documents = findArrayValueForTstr(deviceResponse, "documents");
+    ASSERT_NE(documents, nullptr);
+    ASSERT_EQ(documents->size(), 1);
+    const cppbor::Map* document = ((*documents)[0])->asMap();
+    ASSERT_NE(document, nullptr);
+
+    // Get docType
+    string docType = findStringValueForTstr(document, "docType");
+    ASSERT_EQ(docType, "org.iso.18013.5.1.mDL");
+
+    // Drill down...
+    const cppbor::Map* deviceSigned = findMapValueForTstr(document, "deviceSigned");
+    ASSERT_NE(deviceSigned, nullptr);
+
+    // Dig out the encoded form of DeviceNameSpaces
+    //
+    const cppbor::Semantic* deviceNameSpacesBytes =
+            findSemanticValueForTstr(deviceSigned, "nameSpaces");
+    ASSERT_NE(deviceNameSpacesBytes, nullptr);
+    ASSERT_EQ(deviceNameSpacesBytes->value(), 24);
+    const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->child()->asBstr();
+    ASSERT_NE(deviceNameSpacesBstr, nullptr);
+    vector<uint8_t> deviceNameSpacesEncoded = deviceNameSpacesBstr->value();
+
+    // (For this version of 18013-5, DeviceNameSpaces is always supposed to be empty, check that.)
+    EXPECT_EQ(deviceNameSpacesEncoded, cppbor::Map().encode());
+
+    const cppbor::Map* deviceAuth = findMapValueForTstr(deviceSigned, "deviceAuth");
+    ASSERT_NE(deviceAuth, nullptr);
+    // deviceMac is is the COSE_Mac0.. dig out the encoded form to check that
+    // support::calcMac() gives exactly the same bytes.
+    //
+    const cppbor::Array* deviceMac = findArrayValueForTstr(deviceAuth, "deviceMac");
+    ASSERT_NE(deviceMac, nullptr);
+    vector<uint8_t> deviceMacEncoded = deviceMac->encode();
+
+    // Now we calculate what it should be..
+    optional<vector<uint8_t>> calculatedMac =
+            support::calcMac(sessionTranscriptEncoded,  // SessionTranscript
+                             docType,                   // DocType
+                             deviceNameSpacesEncoded,   // DeviceNamespaces
+                             eMacKey.value());          // EMacKey
+    ASSERT_TRUE(calculatedMac);
+
+    // ... and hopefully it's the same!
+    ASSERT_EQ(calculatedMac.value().size(), deviceMacEncoded.size());
+    EXPECT_TRUE(memcmp(calculatedMac.value().data(), deviceMacEncoded.data(),
+                       deviceMacEncoded.size()) == 0);
+}
+
 }  // namespace identity
 }  // namespace hardware
 }  // namespace android
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
index 598b6b5..207a7e8 100644
--- a/keymaster/4.1/support/attestation_record.cpp
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -102,6 +102,7 @@
     ASN1_INTEGER* boot_patchlevel;
     ASN1_NULL* early_boot_only;
     ASN1_NULL* device_unique_attestation;
+    ASN1_NULL* identity_credential_key;
 } KM_AUTH_LIST;
 
 ASN1_SEQUENCE(KM_AUTH_LIST) = {
@@ -145,6 +146,8 @@
         ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
         ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
                      TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential_key, ASN1_NULL,
+                     TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
 } ASN1_SEQUENCE_END(KM_AUTH_LIST);
 IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
 
@@ -285,6 +288,7 @@
     copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
     copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
     copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+    copyAuthTag(record->identity_credential_key, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
 
     return ErrorCode::OK;
 }
@@ -327,7 +331,10 @@
 
     p = attest_rec->data;
     KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length));
-    if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}};
+    if (!record.get()) {
+        LOG(ERROR) << "Unable to get key description";
+        return {ErrorCode::UNKNOWN_ERROR, {}};
+    }
 
     AttestationRecord result;
 
@@ -352,10 +359,12 @@
     if (error != ErrorCode::OK) return {error, {}};
 
     KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+    SecurityLevel root_of_trust_security_level = SecurityLevel::TRUSTED_ENVIRONMENT;
     if (record->tee_enforced && record->tee_enforced->root_of_trust) {
         root_of_trust = record->tee_enforced->root_of_trust;
     } else if (record->software_enforced && record->software_enforced->root_of_trust) {
         root_of_trust = record->software_enforced->root_of_trust;
+        root_of_trust_security_level = SecurityLevel::SOFTWARE;
     } else {
         LOG(ERROR) << AT << " Failed root of trust parsing";
         return {ErrorCode::INVALID_ARGUMENT, {}};
@@ -373,6 +382,7 @@
     rot.verified_boot_state = static_cast<keymaster_verified_boot_t>(
             ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
     rot.device_locked = root_of_trust->device_locked;
+    rot.security_level = root_of_trust_security_level;
 
     auto& vb_hash = root_of_trust->verified_boot_hash;
     if (!vb_hash) {