From a676c3b4eff557889cfb8e2b20f2275a459d5646 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Mon, 14 Jun 2021 14:46:02 +0100 Subject: [PATCH 1/2] KeyMint VTS: improve attestation tests Check that the various ATTESTATION_ID_* tags are included if they have the correct value, and that keygen fails if they have an invalid value. Also update attestation tags to include vendor/boot patchlevel if they're available. (They always should be, but fixing that is a separate task.) Bug: 190757200 Test: VtsAidlKeyMintTargetTest Merged-In: Ibaed7364c6d08c0982e2a9fb6cb864ae42cf39fe Change-Id: Ibaed7364c6d08c0982e2a9fb6cb864ae42cf39fe --- .../aidl/vts/functional/AttestKeyTest.cpp | 122 +++++++++++- .../DeviceUniqueAttestationTest.cpp | 182 +++++++++++++++--- .../aidl/vts/functional/KeyMintAidlTestBase.h | 11 ++ 3 files changed, 288 insertions(+), 27 deletions(-) diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp index ae2becdf9b..a3127237ac 100644 --- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp +++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp @@ -556,7 +556,7 @@ TEST_P(AttestKeyTest, AllEcCurves) { .EcdsaSigningKey(curve) .AttestKey() .SetDefaultValidity(), - {} /* attestation siging key */, &attest_key.keyBlob, + {} /* attestation signing key */, &attest_key.keyBlob, &attest_key_characteristics, &attest_key_cert_chain)); ASSERT_GT(attest_key_cert_chain.size(), 0); @@ -640,7 +640,7 @@ TEST_P(AttestKeyTest, AttestWithNonAttestKey) { ErrorCode::OK, GenerateKey( AuthorizationSetBuilder().EcdsaSigningKey(EcCurve::P_256).SetDefaultValidity(), - {} /* attestation siging key */, &non_attest_key.keyBlob, + {} /* attestation signing key */, &non_attest_key.keyBlob, &non_attest_key_characteristics, &non_attest_key_cert_chain)); ASSERT_GT(non_attest_key_cert_chain.size(), 0); @@ -662,6 +662,124 @@ TEST_P(AttestKeyTest, AttestWithNonAttestKey) { &attested_key_cert_chain)); } +TEST_P(AttestKeyTest, EcdsaAttestationID) { + // Create attestation key. + AttestationKey attest_key; + vector attest_key_characteristics; + vector attest_key_cert_chain; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .EcdsaSigningKey(EcCurve::P_256) + .AttestKey() + .SetDefaultValidity(), + {} /* attestation signing key */, &attest_key.keyBlob, + &attest_key_characteristics, &attest_key_cert_chain)); + attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key"); + ASSERT_GT(attest_key_cert_chain.size(), 0); + EXPECT_EQ(attest_key_cert_chain.size(), 1); + EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)); + + // Collection of valid attestation ID tags. + auto attestation_id_tags = AuthorizationSetBuilder(); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER, + "ro.product.manufacturer"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model"); + + for (const KeyParameter& tag : attestation_id_tags) { + SCOPED_TRACE(testing::Message() << "+tag-" << tag); + // Use attestation key to sign an ECDSA key, but include an attestation ID field. + AuthorizationSetBuilder builder = AuthorizationSetBuilder() + .EcdsaSigningKey(EcCurve::P_256) + .Authorization(TAG_NO_AUTH_REQUIRED) + .AttestationChallenge("challenge") + .AttestationApplicationId("foo") + .SetDefaultValidity(); + builder.push_back(tag); + vector attested_key_blob; + vector attested_key_characteristics; + vector attested_key_cert_chain; + auto result = GenerateKey(builder, attest_key, &attested_key_blob, + &attested_key_characteristics, &attested_key_cert_chain); + if (result == ErrorCode::CANNOT_ATTEST_IDS) { + continue; + } + + ASSERT_EQ(result, ErrorCode::OK); + + CheckedDeleteKey(&attested_key_blob); + + AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics); + AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics); + + // The attested key characteristics will not contain APPLICATION_ID_* fields (their + // spec definitions all have "Must never appear in KeyCharacteristics"), but the + // attestation extension should contain them, so make sure the extra tag is added. + hw_enforced.push_back(tag); + + EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced, + SecLevel(), + attested_key_cert_chain[0].encodedCertificate)); + } + CheckedDeleteKey(&attest_key.keyBlob); +} + +TEST_P(AttestKeyTest, EcdsaAttestationMismatchID) { + // Create attestation key. + AttestationKey attest_key; + vector attest_key_characteristics; + vector attest_key_cert_chain; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .EcdsaSigningKey(EcCurve::P_256) + .AttestKey() + .SetDefaultValidity(), + {} /* attestation signing key */, &attest_key.keyBlob, + &attest_key_characteristics, &attest_key_cert_chain)); + attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key"); + ASSERT_GT(attest_key_cert_chain.size(), 0); + EXPECT_EQ(attest_key_cert_chain.size(), 1); + EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)); + + // Collection of invalid attestation ID tags. + auto attestation_id_tags = + AuthorizationSetBuilder() + .Authorization(TAG_ATTESTATION_ID_BRAND, "bogus-brand") + .Authorization(TAG_ATTESTATION_ID_DEVICE, "devious-device") + .Authorization(TAG_ATTESTATION_ID_PRODUCT, "punctured-product") + .Authorization(TAG_ATTESTATION_ID_SERIAL, "suspicious-serial") + .Authorization(TAG_ATTESTATION_ID_IMEI, "invalid-imei") + .Authorization(TAG_ATTESTATION_ID_MEID, "mismatching-meid") + .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "malformed-manufacturer") + .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model"); + vector key_blob; + vector key_characteristics; + + for (const KeyParameter& invalid_tag : attestation_id_tags) { + SCOPED_TRACE(testing::Message() << "+tag-" << invalid_tag); + + // Use attestation key to sign an ECDSA key, but include an invalid + // attestation ID field. + AuthorizationSetBuilder builder = AuthorizationSetBuilder() + .EcdsaSigningKey(EcCurve::P_256) + .Authorization(TAG_NO_AUTH_REQUIRED) + .AttestationChallenge("challenge") + .AttestationApplicationId("foo") + .SetDefaultValidity(); + builder.push_back(invalid_tag); + vector attested_key_blob; + vector attested_key_characteristics; + vector attested_key_cert_chain; + auto result = GenerateKey(builder, attest_key, &attested_key_blob, + &attested_key_characteristics, &attested_key_cert_chain); + + ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG) + << "result = " << result; + } + CheckedDeleteKey(&attest_key.keyBlob); +} + INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest); } // namespace aidl::android::hardware::security::keymint::test diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp index 732d9ebadd..a3ed3ad4a0 100644 --- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp +++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp @@ -29,7 +29,7 @@ class DeviceUniqueAttestationTest : public KeyMintAidlTestBase { protected: void CheckUniqueAttestationResults(const vector& key_blob, const vector& key_characteristics, - const AuthorizationSet& hw_enforced, int key_size) { + const AuthorizationSet& hw_enforced) { ASSERT_GT(cert_chain_.size(), 0); if (KeyMintAidlTestBase::dump_Attestations) { @@ -40,8 +40,6 @@ class DeviceUniqueAttestationTest : public KeyMintAidlTestBase { AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); - EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) << "Key size missing"; - // The device-unique attestation chain should contain exactly two certificates: // * The leaf with the attestation extension. // * A self-signed root, signed using the device-unique key. @@ -136,17 +134,32 @@ TEST_P(DeviceUniqueAttestationTest, RsaDeviceUniqueAttestation) { ASSERT_EQ(ErrorCode::OK, result); - AuthorizationSet hw_enforced = AuthorizationSetBuilder() - .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) - .Authorization(TAG_NO_AUTH_REQUIRED) - .RsaSigningKey(2048, 65537) - .Digest(Digest::SHA_2_256) - .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) - .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) - .Authorization(TAG_OS_VERSION, os_version()) - .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()); + AuthorizationSetBuilder hw_enforced = + AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) + .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) + .Authorization(TAG_OS_VERSION, os_version()) + .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()); - CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced, key_size); + // Any patchlevels attached to the key should also be present in the attestation extension. + AuthorizationSet auths; + for (const auto& entry : key_characteristics) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL); + if (vendor_pl) { + hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl); + } + auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL); + if (boot_pl) { + hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl); + } + + CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced); } /* @@ -160,11 +173,10 @@ TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestation) { vector key_blob; vector key_characteristics; - int key_size = 256; auto result = GenerateKey(AuthorizationSetBuilder() .Authorization(TAG_NO_AUTH_REQUIRED) - .EcdsaSigningKey(256) + .EcdsaSigningKey(EcCurve::P_256) .Digest(Digest::SHA_2_256) .Authorization(TAG_INCLUDE_UNIQUE_ID) .AttestationChallenge("challenge") @@ -176,17 +188,137 @@ TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestation) { if (result == ErrorCode::CANNOT_ATTEST_IDS) return; ASSERT_EQ(ErrorCode::OK, result); - AuthorizationSet hw_enforced = AuthorizationSetBuilder() - .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) - .Authorization(TAG_NO_AUTH_REQUIRED) - .EcdsaSigningKey(EcCurve::P_256) - .Digest(Digest::SHA_2_256) - .Authorization(TAG_EC_CURVE, EcCurve::P_256) - .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) - .Authorization(TAG_OS_VERSION, os_version()) - .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()); + AuthorizationSetBuilder hw_enforced = + AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) + .Authorization(TAG_OS_VERSION, os_version()) + .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()); + // Any patchlevels attached to the key should also be present in the attestation extension. + AuthorizationSet auths; + for (const auto& entry : key_characteristics) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL); + if (vendor_pl) { + hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl); + } + auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL); + if (boot_pl) { + hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl); + } - CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced, key_size); + CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced); +} + +/* + * DeviceUniqueAttestationTest.EcdsaDeviceUniqueAttestationID + * + * Verifies that device unique attestation can include IDs that do match the + * local device. + */ +TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationID) { + if (SecLevel() != SecurityLevel::STRONGBOX) return; + + // Collection of valid attestation ID tags. + auto attestation_id_tags = AuthorizationSetBuilder(); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER, + "ro.product.manufacturer"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model"); + vector key_blob; + vector key_characteristics; + + for (const KeyParameter& tag : attestation_id_tags) { + SCOPED_TRACE(testing::Message() << "+tag-" << tag); + AuthorizationSetBuilder builder = AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID) + .AttestationChallenge("challenge") + .AttestationApplicationId("foo") + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION); + builder.push_back(tag); + auto result = GenerateKey(builder, &key_blob, &key_characteristics); + + // It is optional for Strong box to support DeviceUniqueAttestation. + if (result == ErrorCode::CANNOT_ATTEST_IDS) return; + ASSERT_EQ(ErrorCode::OK, result); + + AuthorizationSetBuilder hw_enforced = + AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) + .Authorization(TAG_OS_VERSION, os_version()) + .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()); + // Expect the specified tag to be present in the attestation extension. + hw_enforced.push_back(tag); + // Any patchlevels attached to the key should also be present in the attestation extension. + AuthorizationSet auths; + for (const auto& entry : key_characteristics) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL); + if (vendor_pl) { + hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl); + } + auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL); + if (boot_pl) { + hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl); + } + CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced); + } +} + +/* + * DeviceUniqueAttestationTest.EcdsaDeviceUniqueAttestationMismatchID + * + * Verifies that device unique attestation rejects attempts to attest to IDs that + * don't match the local device. + */ +TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) { + if (SecLevel() != SecurityLevel::STRONGBOX) return; + + // Collection of invalid attestation ID tags. + auto attestation_id_tags = + AuthorizationSetBuilder() + .Authorization(TAG_ATTESTATION_ID_BRAND, "bogus-brand") + .Authorization(TAG_ATTESTATION_ID_DEVICE, "devious-device") + .Authorization(TAG_ATTESTATION_ID_PRODUCT, "punctured-product") + .Authorization(TAG_ATTESTATION_ID_SERIAL, "suspicious-serial") + .Authorization(TAG_ATTESTATION_ID_IMEI, "invalid-imei") + .Authorization(TAG_ATTESTATION_ID_MEID, "mismatching-meid") + .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "malformed-manufacturer") + .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model"); + vector key_blob; + vector key_characteristics; + + for (const KeyParameter& invalid_tag : attestation_id_tags) { + SCOPED_TRACE(testing::Message() << "+tag-" << invalid_tag); + AuthorizationSetBuilder builder = AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID) + .AttestationChallenge("challenge") + .AttestationApplicationId("foo") + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION); + // Add the tag that doesn't match the local device's real ID. + builder.push_back(invalid_tag); + auto result = GenerateKey(builder, &key_blob, &key_characteristics); + + ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG); + } } INSTANTIATE_KEYMINT_AIDL_TEST(DeviceUniqueAttestationTest); diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h index 4d31fa4d36..82f192aa49 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -313,6 +314,16 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam { long challenge_; }; +// If the given property is available, add it to the tag set under the given tag ID. +template +void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag ttag, + const char* prop) { + std::string prop_value = ::android::base::GetProperty(prop, /* default= */ ""); + if (!prop_value.empty()) { + tags->Authorization(ttag, prop_value.data(), prop_value.size()); + } +} + vector build_serial_blob(const uint64_t serial_int); void verify_subject(const X509* cert, const string& subject, bool self_signed); void verify_serial(X509* cert, const uint64_t expected_serial); From e3cdcb2410ba4fb4ad25f4a20072c6fd2485d9b6 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Tue, 15 Jun 2021 10:11:12 +0100 Subject: [PATCH 2/2] KeyMaster VTS: improve attestation tests Check that the various ATTESTATION_ID_* tags are included if they have the correct value, and that keygen fails if they have an invalid value. Also fix the support libraries to add the missing fields to the ASN.1 schema and fix the existing ordering. Bug: 190757200 Test: VtsHalKeymasterV4_1TargetTest, VtsHalKeymasterV4_0TargetTest Merged-In: I11d28d71676d44ebdc79b25b2eb70947022bb1cf Ignore-AOSP-First: to be cross-merged manually Change-Id: I5e19880bbc9e2e667f1204bdc2247ae53a3dada7 --- keymaster/4.0/support/attestation_record.cpp | 111 +++++++++++------ .../functional/keymaster_hidl_hal_test.cpp | 101 +++++++++++++++ keymaster/4.1/support/attestation_record.cpp | 48 ++++++-- .../include/keymasterV4_1/keymaster_tags.h | 8 ++ .../DeviceUniqueAttestationTest.cpp | 115 +++++++++++++++++- .../4.1/vts/functional/Keymaster4_1HidlTest.h | 16 +++ 6 files changed, 350 insertions(+), 49 deletions(-) diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp index bc294bd35b..342b3e2525 100644 --- a/keymaster/4.0/support/attestation_record.cpp +++ b/keymaster/4.0/support/attestation_record.cpp @@ -71,6 +71,7 @@ typedef struct km_auth_list { ASN1_INTEGER_SET* padding; ASN1_INTEGER* ec_curve; ASN1_INTEGER* rsa_public_exponent; + ASN1_NULL* rollback_resistance; ASN1_INTEGER* active_date_time; ASN1_INTEGER* origination_expire_date_time; ASN1_INTEGER* usage_expire_date_time; @@ -78,56 +79,84 @@ typedef struct km_auth_list { ASN1_INTEGER* user_auth_type; ASN1_INTEGER* auth_timeout; ASN1_NULL* allow_while_on_body; + ASN1_NULL* trusted_user_presence_required; + ASN1_NULL* trusted_confirmation_required; + ASN1_NULL* unlocked_device_required; ASN1_NULL* all_applications; ASN1_OCTET_STRING* application_id; ASN1_INTEGER* creation_date_time; ASN1_INTEGER* origin; - ASN1_NULL* rollback_resistance; KM_ROOT_OF_TRUST* root_of_trust; ASN1_INTEGER* os_version; ASN1_INTEGER* os_patchlevel; ASN1_OCTET_STRING* attestation_application_id; - ASN1_NULL* trusted_user_presence_required; - ASN1_NULL* trusted_confirmation_required; - ASN1_NULL* unlocked_device_required; + ASN1_OCTET_STRING* attestation_id_brand; + ASN1_OCTET_STRING* attestation_id_device; + ASN1_OCTET_STRING* attestation_id_product; + ASN1_OCTET_STRING* attestation_id_serial; + ASN1_OCTET_STRING* attestation_id_imei; + ASN1_OCTET_STRING* attestation_id_meid; + ASN1_OCTET_STRING* attestation_id_manufacturer; + ASN1_OCTET_STRING* attestation_id_model; ASN1_INTEGER* vendor_patchlevel; ASN1_INTEGER* boot_patchlevel; } KM_AUTH_LIST; ASN1_SEQUENCE(KM_AUTH_LIST) = { - ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()), - ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()), - ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER, - TAG_RSA_PUBLIC_EXPONENT.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL, TAG_ROLLBACK_RESISTANCE.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER, - TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER, - TAG_USAGE_EXPIRE_DATETIME.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, TAG_ALLOW_WHILE_ON_BODY.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL, - TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL, - TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL, - TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, TAG_CREATION_DATETIME.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER, TAG_VENDOR_PATCHLEVEL.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING, - TAG_ATTESTATION_APPLICATION_ID.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER, + TAG_RSA_PUBLIC_EXPONENT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL, + TAG_ROLLBACK_RESISTANCE.maskedTag()), + + ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER, + TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER, + TAG_USAGE_EXPIRE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, + TAG_ALLOW_WHILE_ON_BODY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL, + TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL, + TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL, + TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, + TAG_CREATION_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING, + TAG_ATTESTATION_APPLICATION_ID.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_BRAND.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_DEVICE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_PRODUCT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_SERIAL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_IMEI.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_MEID.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_MANUFACTURER.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_MODEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER, + TAG_VENDOR_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()), } ASN1_SEQUENCE_END(KM_AUTH_LIST); IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST); @@ -259,6 +288,14 @@ static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list); copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list); copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list); + copyAuthTag(record->attestation_id_brand, TAG_ATTESTATION_ID_BRAND, auth_list); + copyAuthTag(record->attestation_id_device, TAG_ATTESTATION_ID_DEVICE, auth_list); + copyAuthTag(record->attestation_id_product, TAG_ATTESTATION_ID_PRODUCT, auth_list); + copyAuthTag(record->attestation_id_serial, TAG_ATTESTATION_ID_SERIAL, auth_list); + copyAuthTag(record->attestation_id_imei, TAG_ATTESTATION_ID_IMEI, auth_list); + copyAuthTag(record->attestation_id_meid, TAG_ATTESTATION_ID_MEID, auth_list); + copyAuthTag(record->attestation_id_manufacturer, TAG_ATTESTATION_ID_MANUFACTURER, auth_list); + copyAuthTag(record->attestation_id_model, TAG_ATTESTATION_ID_MODEL, auth_list); copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list); copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list); copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED, 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 9e37ed0a44..01c502c586 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -96,6 +96,18 @@ bool contains(hidl_vec& set, TypedTag) { return count > 0; } +// If the given property is available, add it to the tag set under the given tag ID. +template +void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag ttag, + const char* prop) { + char value[PROPERTY_VALUE_MAX]; + int len = property_get(prop, value, /* default = */ ""); + if (len > 0) { + tags->Authorization(ttag, reinterpret_cast(value), + static_cast(len)); + } +} + constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // @@ -4408,6 +4420,95 @@ TEST_P(AttestationTest, EcAttestation) { SecLevel(), cert_chain[0])); } +/* + * AttestationTest.EcAttestationID + * + * Verifies that attesting to EC keys with correct attestation ID fields works and generates the + * expected output. + */ +TEST_P(AttestationTest, EcAttestationID) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID))); + + // Collection of valid attestation ID tags. + auto attestation_id_tags = AuthorizationSetBuilder(); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER, + "ro.product.manufacturer"); + add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model"); + + for (const KeyParameter& tag : attestation_id_tags) { + AuthorizationSetBuilder builder = + AuthorizationSetBuilder() + .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")); + // Include one of the (valid) attestation ID tags. + builder.push_back(tag); + hidl_vec> cert_chain; + auto result = AttestKey(builder, &cert_chain); + if (result == ErrorCode::CANNOT_ATTEST_IDS) { + continue; + } + + ASSERT_EQ(ErrorCode::OK, result); + EXPECT_GE(cert_chain.size(), 2U); + + std::vector expected_hw_enforced = key_characteristics_.hardwareEnforced; + expected_hw_enforced.push_back(tag); + + EXPECT_TRUE(verify_attestation_record( + "challenge", "foo", key_characteristics_.softwareEnforced, + hidl_vec(expected_hw_enforced), SecLevel(), cert_chain[0])); + } +} + +/* + * AttestationTest.EcAttestationMismatchID + * + * Verifies that attesting to EC keys with incorrect attestation ID fields fails. + */ +TEST_P(AttestationTest, EcAttestationMismatchID) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID))); + + // Collection of invalid attestation ID tags. + std::string invalid = "completely-invalid"; + auto invalid_tags = + AuthorizationSetBuilder() + .Authorization(V4_0::TAG_ATTESTATION_ID_BRAND, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_DEVICE, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_PRODUCT, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_SERIAL, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_IMEI, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_MEID, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_MANUFACTURER, invalid.data(), + invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_MODEL, invalid.data(), invalid.size()); + + for (const KeyParameter& invalid_tag : invalid_tags) { + AuthorizationSetBuilder builder = + AuthorizationSetBuilder() + .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")); + // Include one of the invalid attestation ID tags. + builder.push_back(invalid_tag); + hidl_vec> cert_chain; + auto result = AttestKey(builder, &cert_chain); + + EXPECT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG) + << "result: " << static_cast(result); + } +} + /* * AttestationTest.EcAttestationRequiresAttestationAppId * diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp index 207a7e8264..15230d5def 100644 --- a/keymaster/4.1/support/attestation_record.cpp +++ b/keymaster/4.1/support/attestation_record.cpp @@ -79,6 +79,8 @@ typedef struct km_auth_list { ASN1_INTEGER_SET* padding; ASN1_INTEGER* ec_curve; ASN1_INTEGER* rsa_public_exponent; + ASN1_NULL* rollback_resistance; + ASN1_NULL* early_boot_only; ASN1_INTEGER* active_date_time; ASN1_INTEGER* origination_expire_date_time; ASN1_INTEGER* usage_expire_date_time; @@ -86,21 +88,27 @@ typedef struct km_auth_list { ASN1_INTEGER* user_auth_type; ASN1_INTEGER* auth_timeout; ASN1_NULL* allow_while_on_body; + ASN1_NULL* trusted_user_presence_required; + ASN1_NULL* trusted_confirmation_required; + ASN1_NULL* unlocked_device_required; ASN1_NULL* all_applications; ASN1_OCTET_STRING* application_id; ASN1_INTEGER* creation_date_time; ASN1_INTEGER* origin; - ASN1_NULL* rollback_resistance; KM_ROOT_OF_TRUST* root_of_trust; ASN1_INTEGER* os_version; ASN1_INTEGER* os_patchlevel; ASN1_OCTET_STRING* attestation_application_id; - ASN1_NULL* trusted_user_presence_required; - ASN1_NULL* trusted_confirmation_required; - ASN1_NULL* unlocked_device_required; + ASN1_OCTET_STRING* attestation_id_brand; + ASN1_OCTET_STRING* attestation_id_device; + ASN1_OCTET_STRING* attestation_id_product; + ASN1_OCTET_STRING* attestation_id_serial; + ASN1_OCTET_STRING* attestation_id_imei; + ASN1_OCTET_STRING* attestation_id_meid; + ASN1_OCTET_STRING* attestation_id_manufacturer; + ASN1_OCTET_STRING* attestation_id_model; ASN1_INTEGER* vendor_patchlevel; ASN1_INTEGER* boot_patchlevel; - ASN1_NULL* early_boot_only; ASN1_NULL* device_unique_attestation; ASN1_NULL* identity_credential_key; } KM_AUTH_LIST; @@ -116,6 +124,7 @@ ASN1_SEQUENCE(KM_AUTH_LIST) = { TAG_RSA_PUBLIC_EXPONENT.maskedTag()), ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL, TAG_ROLLBACK_RESISTANCE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()), ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()), ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER, TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()), @@ -138,12 +147,27 @@ ASN1_SEQUENCE(KM_AUTH_LIST) = { ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()), ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()), ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING, + TAG_ATTESTATION_APPLICATION_ID.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_BRAND.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_DEVICE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_PRODUCT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_SERIAL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_IMEI.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_MEID.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_MANUFACTURER.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_MODEL.maskedTag()), ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER, TAG_VENDOR_PATCHLEVEL.maskedTag()), ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()), - ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING, - TAG_ATTESTATION_APPLICATION_ID.maskedTag()), - 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, @@ -279,6 +303,14 @@ static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list); copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list); copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list); + copyAuthTag(record->attestation_id_brand, TAG_ATTESTATION_ID_BRAND, auth_list); + copyAuthTag(record->attestation_id_device, TAG_ATTESTATION_ID_DEVICE, auth_list); + copyAuthTag(record->attestation_id_product, TAG_ATTESTATION_ID_PRODUCT, auth_list); + copyAuthTag(record->attestation_id_serial, TAG_ATTESTATION_ID_SERIAL, auth_list); + copyAuthTag(record->attestation_id_imei, TAG_ATTESTATION_ID_IMEI, auth_list); + copyAuthTag(record->attestation_id_meid, TAG_ATTESTATION_ID_MEID, auth_list); + copyAuthTag(record->attestation_id_manufacturer, TAG_ATTESTATION_ID_MANUFACTURER, auth_list); + copyAuthTag(record->attestation_id_model, TAG_ATTESTATION_ID_MODEL, auth_list); copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list); copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list); copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED, diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h index 40eb1426ef..e8db56a85c 100644 --- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h +++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h @@ -53,6 +53,14 @@ using V4_0::TAG_APPLICATION_ID; using V4_0::TAG_ASSOCIATED_DATA; using V4_0::TAG_ATTESTATION_APPLICATION_ID; using V4_0::TAG_ATTESTATION_CHALLENGE; +using V4_0::TAG_ATTESTATION_ID_BRAND; +using V4_0::TAG_ATTESTATION_ID_DEVICE; +using V4_0::TAG_ATTESTATION_ID_IMEI; +using V4_0::TAG_ATTESTATION_ID_MANUFACTURER; +using V4_0::TAG_ATTESTATION_ID_MEID; +using V4_0::TAG_ATTESTATION_ID_MODEL; +using V4_0::TAG_ATTESTATION_ID_PRODUCT; +using V4_0::TAG_ATTESTATION_ID_SERIAL; using V4_0::TAG_AUTH_TIMEOUT; using V4_0::TAG_BLOB_USAGE_REQUIREMENTS; using V4_0::TAG_BLOCK_MODE; diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp index 3d97daf274..4a57f44dd9 100644 --- a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp +++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp @@ -27,6 +27,8 @@ #include #include +using android::hardware::keymaster::V4_0::test::add_tag_from_prop; + // Not to dump the attestation by default. Can enable by specify the parameter // "--dump_attestations" on lunching VTS static bool dumpAttestations = false; @@ -173,10 +175,15 @@ void check_attestation_record(AttestationRecord attestation, const HidlBuf& chal attestation.software_enforced.Sort(); attestation.hardware_enforced.Sort(); - EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(attestation.software_enforced)) - << DIFFERENCE(expected_sw_enforced, attestation.software_enforced); - EXPECT_EQ(filter_tags(expected_hw_enforced), filter_tags(attestation.hardware_enforced)) - << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced); + expected_sw_enforced = filter_tags(expected_sw_enforced); + expected_hw_enforced = filter_tags(expected_hw_enforced); + AuthorizationSet attestation_sw_enforced = filter_tags(attestation.software_enforced); + AuthorizationSet attestation_hw_enforced = filter_tags(attestation.hardware_enforced); + + EXPECT_EQ(expected_sw_enforced, attestation_sw_enforced) + << DIFFERENCE(expected_sw_enforced, attestation_sw_enforced); + EXPECT_EQ(expected_hw_enforced, attestation_hw_enforced) + << DIFFERENCE(expected_hw_enforced, attestation_hw_enforced); } X509_Ptr parse_cert_blob(const std::vector& blob) { @@ -342,6 +349,106 @@ TEST_P(DeviceUniqueAttestationTest, Ecdsa) { SecLevel()); } +TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationID) { + if (SecLevel() != SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID)))); + + // Collection of valid attestation ID tags. + auto attestation_id_tags = AuthorizationSetBuilder(); + add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_BRAND, "ro.product.brand"); + add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_DEVICE, "ro.product.device"); + add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_PRODUCT, "ro.product.name"); + add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_SERIAL, "ro.serial"); + add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_MANUFACTURER, + "ro.product.manufacturer"); + add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_MODEL, "ro.product.model"); + + for (const KeyParameter& tag : attestation_id_tags) { + hidl_vec> cert_chain; + HidlBuf challenge("challenge"); + HidlBuf app_id("foo"); + AuthorizationSetBuilder builder = + AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_ATTESTATION_CHALLENGE, challenge) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id); + builder.push_back(tag); + ErrorCode result = convert(AttestKey(builder, &cert_chain)); + + // It is optional for Strong box to support DeviceUniqueAttestation. + if (result == ErrorCode::CANNOT_ATTEST_IDS) return; + + ASSERT_EQ(ErrorCode::OK, result); + EXPECT_EQ(2U, cert_chain.size()); + if (dumpAttestations) { + for (auto cert_ : cert_chain) dumpContent(bin2hex(cert_)); + } + auto [err, attestation] = parse_attestation_record(cert_chain[0]); + ASSERT_EQ(ErrorCode::OK, err); + + AuthorizationSetBuilder hw_enforced = + AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED) + .Authorization(TAG_OS_VERSION, os_version()) + .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()); + hw_enforced.push_back(tag); + check_attestation_record( + attestation, challenge, + /* sw_enforced */ + AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id), + hw_enforced, SecLevel()); + } +} + +TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) { + if (SecLevel() != SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID)))); + + // Collection of invalid attestation ID tags. + std::string invalid = "completely-invalid"; + auto attestation_id_tags = + AuthorizationSetBuilder() + .Authorization(V4_0::TAG_ATTESTATION_ID_BRAND, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_DEVICE, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_PRODUCT, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_SERIAL, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_IMEI, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_MEID, invalid.data(), invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_MANUFACTURER, invalid.data(), + invalid.size()) + .Authorization(V4_0::TAG_ATTESTATION_ID_MODEL, invalid.data(), invalid.size()); + + for (const KeyParameter& invalid_tag : attestation_id_tags) { + hidl_vec> cert_chain; + HidlBuf challenge("challenge"); + HidlBuf app_id("foo"); + AuthorizationSetBuilder builder = + AuthorizationSetBuilder() + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION) + .Authorization(TAG_ATTESTATION_CHALLENGE, challenge) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id); + builder.push_back(invalid_tag); + ErrorCode result = convert(AttestKey(builder, &cert_chain)); + + EXPECT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG) + << "result: " << static_cast(result); + } +} + INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest); } // namespace test diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h index f8c1fad233..670ccfbeaf 100644 --- a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h +++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h @@ -18,6 +18,8 @@ #include +#include + #include #include @@ -159,3 +161,17 @@ bool contains(hidl_vec& set, TypedTag typedTag) { android::hardware::PrintInstanceNameToString) } // namespace android::hardware::keymaster::V4_1::test + +namespace android::hardware::keymaster::V4_0::test { + +// If the given property is available, add it to the tag set under the given tag ID. +template +void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag ttag, + const char* prop) { + std::string prop_value = ::android::base::GetProperty(prop, /* default= */ ""); + if (!prop_value.empty()) { + tags->Authorization(ttag, prop_value.data(), prop_value.size()); + } +} + +} // namespace android::hardware::keymaster::V4_0::test