Merge changes I8b34a94c,I46e62ab9 into android13-tests-dev

* changes:
  KeyMint: Add Root-of-Trust test cases
  KM 4: Add Root-of-Trust test cases
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index f9a02ba..e1dfcfc 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -30,13 +30,17 @@
         "keymaster_hidl_hal_test.cpp",
     ],
     srcs: [
+        "BootloaderStateTest.cpp",
         "HmacKeySharingTest.cpp",
         "VerificationTokenTest.cpp",
         "keymaster_hidl_hal_test.cpp",
     ],
     static_libs: [
         "android.hardware.keymaster@4.0",
+        "libavb_user",
+        "libavb",
         "libcrypto_static",
+        "libfs_mgr",
         "libkeymaster4support",
         "libkeymaster4vtstest",
     ],
@@ -64,6 +68,7 @@
     ],
     static_libs: [
         "android.hardware.keymaster@4.0",
+        "libcrypto_static",
         "libkeymaster4support",
     ],
 }
diff --git a/keymaster/4.0/vts/functional/BootloaderStateTest.cpp b/keymaster/4.0/vts/functional/BootloaderStateTest.cpp
new file mode 100644
index 0000000..f874767
--- /dev/null
+++ b/keymaster/4.0/vts/functional/BootloaderStateTest.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2023 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 <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <android-base/properties.h>
+#include <fstab/fstab.h>
+#include <libavb/libavb.h>
+#include <libavb_user/avb_ops_user.h>
+
+#include "KeymasterHidlTest.h"
+
+namespace android::hardware::keymaster::V4_0::test {
+
+using ::std::string;
+using ::std::vector;
+
+// Since this test needs to talk to Keymaster HAL, it can only run as root. Thus,
+// bootloader can not be locked.
+// @CddTest = 9.10/C-0-2
+class BootloaderStateTest : public KeymasterHidlTest {
+  public:
+    virtual void SetUp() override {
+        KeymasterHidlTest::SetUp();
+
+        // Generate a key.
+        auto ec = GenerateKey(AuthorizationSetBuilder()
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .EcdsaSigningKey(EcCurve::P_256)
+                                      .Digest(Digest::SHA_2_256));
+        ASSERT_EQ(ec, ErrorCode::OK) << "Failed to generate key.";
+
+        // Generate attestation.
+        hidl_vec<hidl_vec<uint8_t>> cert_chain;
+        ec = AttestKey(AuthorizationSetBuilder()
+                               .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                               .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                       &cert_chain);
+        ASSERT_EQ(ec, ErrorCode::OK) << "Failed to generate attestation.";
+
+        X509_Ptr cert(parse_cert_blob(cert_chain[0]));
+        ASSERT_TRUE(cert.get()) << "Failed to parse certificate blob.";
+
+        ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+        ASSERT_TRUE(attest_rec) << "Failed to get attestation record.";
+
+        // Parse root of trust.
+        auto result = parse_root_of_trust(attest_rec->data, attest_rec->length, &attestedVbKey_,
+                                          &attestedVbState_, &attestedBootloaderState_,
+                                          &attestedVbmetaDigest_);
+        ASSERT_EQ(result, ErrorCode::OK) << "Failed to parse root of trust.";
+    }
+
+    hidl_vec<uint8_t> attestedVbKey_;
+    keymaster_verified_boot_t attestedVbState_;
+    bool attestedBootloaderState_;
+    hidl_vec<uint8_t> attestedVbmetaDigest_;
+};
+
+// Check that attested bootloader state is set to unlocked.
+TEST_P(BootloaderStateTest, BootloaderIsUnlocked) {
+    ASSERT_FALSE(attestedBootloaderState_)
+            << "This test runs as root. Bootloader must be unlocked.";
+}
+
+// Check that verified boot state is set to "unverified", i.e. "orange".
+TEST_P(BootloaderStateTest, VbStateIsUnverified) {
+    // Unlocked bootloader implies that verified boot state must be "unverified".
+    ASSERT_EQ(attestedVbState_, KM_VERIFIED_BOOT_UNVERIFIED)
+            << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
+
+    // AVB spec stipulates that bootloader must set "androidboot.verifiedbootstate" parameter
+    // on the kernel command-line. This parameter is exposed to userspace as
+    // "ro.boot.verifiedbootstate" property.
+    auto vbStateProp = ::android::base::GetProperty("ro.boot.verifiedbootstate", "");
+    ASSERT_EQ(vbStateProp, "orange")
+            << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
+}
+
+// Following error codes from avb_slot_data() mean that slot data was loaded
+// (even if verification failed).
+static inline bool avb_slot_data_loaded(AvbSlotVerifyResult result) {
+    switch (result) {
+        case AVB_SLOT_VERIFY_RESULT_OK:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+            return true;
+        default:
+            return false;
+    }
+}
+
+// Check that attested vbmeta digest is correct.
+TEST_P(BootloaderStateTest, VbmetaDigest) {
+    AvbSlotVerifyData* avbSlotData;
+    auto suffix = fs_mgr_get_slot_suffix();
+    const char* partitions[] = {nullptr};
+    auto avbOps = avb_ops_user_new();
+
+    // For VTS, devices run with vendor_boot-debug.img, which is not release key
+    // signed. Use AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR to bypass avb
+    // verification errors. This is OK since we only care about the digest for
+    // this test case.
+    auto result = avb_slot_verify(avbOps, partitions, suffix.c_str(),
+                                  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR,
+                                  AVB_HASHTREE_ERROR_MODE_EIO, &avbSlotData);
+    ASSERT_TRUE(avb_slot_data_loaded(result)) << "Failed to load avb slot data";
+
+    // Unfortunately, bootloader is not required to report the algorithm used
+    // to calculate the digest. There are only two supported options though,
+    // SHA256 and SHA512. Attested VBMeta digest must match one of these.
+    vector<uint8_t> digest256(AVB_SHA256_DIGEST_SIZE);
+    vector<uint8_t> digest512(AVB_SHA512_DIGEST_SIZE);
+
+    avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA256,
+                                                 digest256.data());
+    avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA512,
+                                                 digest512.data());
+
+    ASSERT_TRUE((attestedVbmetaDigest_ == digest256) || (attestedVbmetaDigest_ == digest512))
+            << "Attested digest does not match computed digest.";
+}
+
+INSTANTIATE_KEYMASTER_HIDL_TEST(BootloaderStateTest);
+
+}  // namespace android::hardware::keymaster::V4_0::test
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 315a4bd..e2ad0ef 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -841,6 +841,30 @@
     return {};
 }
 
+X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) {
+    const uint8_t* p = blob.data();
+    return d2i_X509(nullptr, &p, blob.size());
+}
+
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    EXPECT_TRUE(!!oid.get());
+    if (!oid.get()) return nullptr;
+
+    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
+    if (location == -1) return nullptr;
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+    EXPECT_TRUE(!!attest_rec_ext)
+            << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
+    if (!attest_rec_ext) return nullptr;
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
+    return attest_rec;
+}
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index ad30aa7..67829ec 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -22,7 +22,9 @@
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
 
+#include <keymasterV4_0/attestation_record.h>
 #include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/openssl_utils.h>
 
 namespace android {
 namespace hardware {
@@ -241,6 +243,11 @@
                              testing::ValuesIn(KeymasterHidlTest::build_params()), \
                              android::hardware::PrintInstanceNameToString)
 
+X509* parse_cert_blob(const hidl_vec<uint8_t>& blob);
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate);
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 728cc91..b709904 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -263,11 +263,6 @@
     void operator()(RSA* p) { RSA_free(p); }
 };
 
-X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) {
-    const uint8_t* p = blob.data();
-    return d2i_X509(nullptr, &p, blob.size());
-}
-
 bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain, const std::string& msg,
                   const std::string& signature) {
     {
@@ -337,27 +332,6 @@
     return true;
 }
 
-// Extract attestation record from cert. Returned object is still part of cert; don't free it
-// separately.
-ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
-    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
-    EXPECT_TRUE(!!oid.get());
-    if (!oid.get()) return nullptr;
-
-    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
-    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
-    if (location == -1) return nullptr;
-
-    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
-    EXPECT_TRUE(!!attest_rec_ext)
-        << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
-    if (!attest_rec_ext) return nullptr;
-
-    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
-    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
-    return attest_rec;
-}
-
 bool tag_in_list(const KeyParameter& entry) {
     // Attestations don't contain everything in key authorization lists, so we need to filter
     // the key lists to produce the lists that we expect to match the attestations.
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index f30e29c..cfc7fb5 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -38,8 +38,11 @@
     ],
     static_libs: [
         "android.hardware.security.secureclock-V1-ndk",
+        "libavb_user",
+        "libavb",
         "libcppbor_external",
         "libcppcose_rkp",
+        "libfs_mgr",
         "libjsoncpp",
         "libkeymint",
         "libkeymint_remote_prov_support",
@@ -57,6 +60,7 @@
     ],
     srcs: [
         "AttestKeyTest.cpp",
+        "BootloaderStateTest.cpp",
         "DeviceUniqueAttestationTest.cpp",
         "KeyMintTest.cpp",
         "SecureElementProvisioningTest.cpp",
diff --git a/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp b/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
new file mode 100644
index 0000000..a709b41
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keymint_1_bootloader_test"
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <android-base/properties.h>
+#include <android/binder_manager.h>
+#include <fstab/fstab.h>
+#include <libavb/libavb.h>
+#include <libavb_user/avb_ops_user.h>
+#include <remote_prov/remote_prov_utils.h>
+
+#include "KeyMintAidlTestBase.h"
+
+namespace aidl::android::hardware::security::keymint::test {
+
+using ::android::getAidlHalInstanceNames;
+using ::std::string;
+using ::std::vector;
+
+// Since this test needs to talk to KeyMint HAL, it can only run as root. Thus,
+// bootloader can not be locked.
+// @CddTest = 9.10/C-0-2
+class BootloaderStateTest : public KeyMintAidlTestBase {
+  public:
+    virtual void SetUp() override {
+        KeyMintAidlTestBase::SetUp();
+
+        // Generate a key with attestation.
+        vector<uint8_t> key_blob;
+        vector<KeyCharacteristics> key_characteristics;
+        AuthorizationSet keyDesc = AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .EcdsaSigningKey(EcCurve::P_256)
+                                           .AttestationChallenge("foo")
+                                           .AttestationApplicationId("bar")
+                                           .Digest(Digest::NONE)
+                                           .SetDefaultValidity();
+        auto result = GenerateKey(keyDesc, &key_blob, &key_characteristics);
+        // If factory provisioned attestation key is not supported by Strongbox,
+        // then create a key with self-signed attestation and use it as the
+        // attestation key instead.
+        if (SecLevel() == SecurityLevel::STRONGBOX &&
+            result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) {
+            result = GenerateKeyWithSelfSignedAttestKey(
+                    AuthorizationSetBuilder()
+                            .EcdsaKey(EcCurve::P_256)
+                            .AttestKey()
+                            .SetDefaultValidity(), /* attest key params */
+                    keyDesc, &key_blob, &key_characteristics);
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
+
+        // Parse attested AVB values.
+        X509_Ptr cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+        ASSERT_TRUE(cert.get());
+
+        ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+        ASSERT_TRUE(attest_rec);
+
+        auto error = parse_root_of_trust(attest_rec->data, attest_rec->length, &attestedVbKey_,
+                                         &attestedVbState_, &attestedBootloaderState_,
+                                         &attestedVbmetaDigest_);
+        ASSERT_EQ(error, ErrorCode::OK);
+    }
+
+    vector<uint8_t> attestedVbKey_;
+    VerifiedBoot attestedVbState_;
+    bool attestedBootloaderState_;
+    vector<uint8_t> attestedVbmetaDigest_;
+};
+
+// Check that attested bootloader state is set to unlocked.
+TEST_P(BootloaderStateTest, BootloaderIsUnlocked) {
+    ASSERT_FALSE(attestedBootloaderState_)
+            << "This test runs as root. Bootloader must be unlocked.";
+}
+
+// Check that verified boot state is set to "unverified", i.e. "orange".
+TEST_P(BootloaderStateTest, VbStateIsUnverified) {
+    // Unlocked bootloader implies that verified boot state must be "unverified".
+    ASSERT_EQ(attestedVbState_, VerifiedBoot::UNVERIFIED)
+            << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
+
+    // AVB spec stipulates that bootloader must set "androidboot.verifiedbootstate" parameter
+    // on the kernel command-line. This parameter is exposed to userspace as
+    // "ro.boot.verifiedbootstate" property.
+    auto vbStateProp = ::android::base::GetProperty("ro.boot.verifiedbootstate", "");
+    ASSERT_EQ(vbStateProp, "orange")
+            << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
+}
+
+// Following error codes from avb_slot_data() mean that slot data was loaded
+// (even if verification failed).
+static inline bool avb_slot_data_loaded(AvbSlotVerifyResult result) {
+    switch (result) {
+        case AVB_SLOT_VERIFY_RESULT_OK:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+            return true;
+        default:
+            return false;
+    }
+}
+
+// Check that attested vbmeta digest is correct.
+TEST_P(BootloaderStateTest, VbmetaDigest) {
+    AvbSlotVerifyData* avbSlotData;
+    auto suffix = fs_mgr_get_slot_suffix();
+    const char* partitions[] = {nullptr};
+    auto avbOps = avb_ops_user_new();
+
+    // For VTS, devices run with vendor_boot-debug.img, which is not release key
+    // signed. Use AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR to bypass avb
+    // verification errors. This is OK since we only care about the digest for
+    // this test case.
+    auto result = avb_slot_verify(avbOps, partitions, suffix.c_str(),
+                                  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR,
+                                  AVB_HASHTREE_ERROR_MODE_EIO, &avbSlotData);
+    ASSERT_TRUE(avb_slot_data_loaded(result)) << "Failed to load avb slot data";
+
+    // Unfortunately, bootloader is not required to report the algorithm used
+    // to calculate the digest. There are only two supported options though,
+    // SHA256 and SHA512. Attested VBMeta digest must match one of these.
+    vector<uint8_t> digest256(AVB_SHA256_DIGEST_SIZE);
+    vector<uint8_t> digest512(AVB_SHA512_DIGEST_SIZE);
+
+    avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA256,
+                                                 digest256.data());
+    avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA512,
+                                                 digest512.data());
+
+    ASSERT_TRUE((attestedVbmetaDigest_ == digest256) || (attestedVbmetaDigest_ == digest512))
+            << "Attested digest does not match computed digest.";
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(BootloaderStateTest);
+
+}  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index d2d964a..15693ac 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -108,27 +108,6 @@
     return true;
 }
 
-// Extract attestation record from cert. Returned object is still part of cert; don't free it
-// separately.
-ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
-    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
-    EXPECT_TRUE(!!oid.get());
-    if (!oid.get()) return nullptr;
-
-    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
-    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
-    if (location == -1) return nullptr;
-
-    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
-    EXPECT_TRUE(!!attest_rec_ext)
-            << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
-    if (!attest_rec_ext) return nullptr;
-
-    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
-    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
-    return attest_rec;
-}
-
 void check_attestation_version(uint32_t attestation_version, int32_t aidl_version) {
     // Version numbers in attestation extensions should be a multiple of 100.
     EXPECT_EQ(attestation_version % 100, 0);
@@ -1783,6 +1762,27 @@
     return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
 }
 
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    EXPECT_TRUE(!!oid.get());
+    if (!oid.get()) return nullptr;
+
+    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
+    if (location == -1) return nullptr;
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+    EXPECT_TRUE(!!attest_rec_ext)
+            << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
+    if (!attest_rec_ext) return nullptr;
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
+    return attest_rec;
+}
+
 vector<uint8_t> make_name_from_str(const string& name) {
     X509_NAME_Ptr x509_name(X509_NAME_new());
     EXPECT_TRUE(x509_name.get() != nullptr);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 129c737..2489ab2 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -382,6 +382,7 @@
 
 string bin2hex(const vector<uint8_t>& data);
 X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate);
 vector<uint8_t> make_name_from_str(const string& name);
 void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
                         vector<uint8_t>* payload_value);