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 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);