From e0fb4d0ce5ad87bc729e57677fae5e1aa8586f85 Mon Sep 17 00:00:00 2001 From: Tri Vo Date: Sat, 15 Jul 2023 17:10:24 -0400 Subject: [PATCH] KeyMint: Add Root-of-Trust test cases This patch is a squash of following patches: - aosp/2514097 - aosp/2535086 - aosp/2576910 Bug: 255344624 Test: VtsKeyMintAidlTargetTest Change-Id: I8b34a94c11d7cc174821483f624fd083ca1763ac Merged-In: I8b34a94c11d7cc174821483f624fd083ca1763ac --- .../keymint/aidl/vts/functional/Android.bp | 4 + .../vts/functional/BootloaderStateTest.cpp | 158 ++++++++++++++++++ .../vts/functional/KeyMintAidlTestBase.cpp | 42 ++--- .../aidl/vts/functional/KeyMintAidlTestBase.h | 1 + 4 files changed, 184 insertions(+), 21 deletions(-) create mode 100644 security/keymint/aidl/vts/functional/BootloaderStateTest.cpp diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp index f30e29cd4c..cfc7fb5f7b 100644 --- a/security/keymint/aidl/vts/functional/Android.bp +++ b/security/keymint/aidl/vts/functional/Android.bp @@ -38,8 +38,11 @@ cc_defaults { ], 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 @@ cc_test { ], 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 0000000000..a709b4181c --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 key_blob; + vector 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 attestedVbKey_; + VerifiedBoot attestedVbState_; + bool attestedBootloaderState_; + vector 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 digest256(AVB_SHA256_DIGEST_SIZE); + vector 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 d2d964afa5..15693acafe 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -108,27 +108,6 @@ bool KeyCharacteristicsBasicallyValid(SecurityLevel secLevel, 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 @@ X509_Ptr parse_cert_blob(const vector& blob) { 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 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 129c7378cf..2489ab2085 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h @@ -382,6 +382,7 @@ bool verify_attestation_record(int aidl_version, // string bin2hex(const vector& data); X509_Ptr parse_cert_blob(const vector& blob); +ASN1_OCTET_STRING* get_attestation_record(X509* certificate); vector make_name_from_str(const string& name); void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode, vector* payload_value);