KM 4: Add Root-of-Trust test cases
This patch is a squash of following patches:
- aosp/2582033
- aosp/2603248
Bug: 255344624
Test: VtsHalKeymasterV4_0TargetTest
Change-Id: I46e62ab9031d3745f99bd214f9e579e80edc9128
Merged-In: I46e62ab9031d3745f99bd214f9e579e80edc9128
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.