diff options
5 files changed, 194 insertions, 0 deletions
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp index e46aeee12c..cdcaaf33f4 100644 --- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp +++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp @@ -1014,6 +1014,14 @@ TEST_P(AttestKeyTest, EcdsaAttestationMismatchID) { .Authorization(TAG_ATTESTATION_ID_MEID, "mismatching-meid") .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "malformed-manufacturer") .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model"); + + // TODO(b/262255219): Remove this condition when StrongBox supports 2nd IMEI attestation. + if (SecLevel() != SecurityLevel::STRONGBOX) { + if (isSecondImeiIdAttestationRequired()) { + attestation_id_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, + "invalid-second-imei"); + } + } vector<uint8_t> key_blob; vector<KeyCharacteristics> key_characteristics; @@ -1042,6 +1050,178 @@ TEST_P(AttestKeyTest, EcdsaAttestationMismatchID) { CheckedDeleteKey(&attest_key.keyBlob); } +TEST_P(AttestKeyTest, SecondIMEIAttestationIDSuccess) { + if (is_gsi_image()) { + // GSI sets up a standard set of device identifiers that may not match + // the device identifiers held by the device. + GTEST_SKIP() << "Test not applicable under GSI"; + } + + // TODO(b/262255219): Remove this condition when StrongBox supports 2nd IMEI attestation. + if (SecLevel() == SecurityLevel::STRONGBOX) { + GTEST_SKIP() << "Test not applicable for SecurityLevel::STRONGBOX"; + } + + // Skip the test if there is no second IMEI exists. + string second_imei = get_imei(1); + if (second_imei.empty() || second_imei.compare("null") == 0) { + GTEST_SKIP() << "Test not applicable as there is no second IMEI"; + } + + if (!isSecondImeiIdAttestationRequired()) { + GTEST_SKIP() << "Test not applicable for KeyMint-Version < 3 or first-api-level < 34"; + } + + // Create attestation key. + AttestationKey attest_key; + vector<KeyCharacteristics> attest_key_characteristics; + vector<Certificate> attest_key_cert_chain; + ASSERT_EQ(ErrorCode::OK, + GenerateAttestKey(AuthorizationSetBuilder() + .EcdsaKey(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"); + EXPECT_EQ(attest_key_cert_chain.size(), 1); + EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)); + + // 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(); + // b/264979486 - second imei doesn't depend on first imei. + // Add second IMEI as attestation id without adding first IMEI as + // attestation id. + builder.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, second_imei.data(), second_imei.size()); + + vector<uint8_t> attested_key_blob; + vector<KeyCharacteristics> attested_key_characteristics; + vector<Certificate> 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 && !isDeviceIdAttestationRequired()) { + GTEST_SKIP() + << "Test not applicable as device does not support SECOND-IMEI ID attestation."; + } + + ASSERT_EQ(result, ErrorCode::OK); + + device_id_attestation_vsr_check(result); + + 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. + vector<uint8_t> imei_blob(second_imei.data(), second_imei.data() + second_imei.size()); + KeyParameter imei_tag = Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, imei_blob); + hw_enforced.push_back(imei_tag); + + EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced, + hw_enforced, SecLevel(), + attested_key_cert_chain[0].encodedCertificate)); + + CheckedDeleteKey(&attest_key.keyBlob); +} + +TEST_P(AttestKeyTest, MultipleIMEIAttestationIDSuccess) { + if (is_gsi_image()) { + // GSI sets up a standard set of device identifiers that may not match + // the device identifiers held by the device. + GTEST_SKIP() << "Test not applicable under GSI"; + } + + // TODO(b/262255219): Remove this condition when StrongBox supports 2nd IMEI attestation. + if (SecLevel() == SecurityLevel::STRONGBOX) { + GTEST_SKIP() << "Test not applicable for SecurityLevel::STRONGBOX"; + } + + // Skip the test if there is no first IMEI exists. + string imei = get_imei(0); + if (imei.empty() || imei.compare("null") == 0) { + GTEST_SKIP() << "Test not applicable as there is no first IMEI"; + } + + // Skip the test if there is no second IMEI exists. + string second_imei = get_imei(1); + if (second_imei.empty() || second_imei.compare("null") == 0) { + GTEST_SKIP() << "Test not applicable as there is no second IMEI"; + } + + if (!isSecondImeiIdAttestationRequired()) { + GTEST_SKIP() << "Test not applicable for KeyMint-Version < 3 or first-api-level < 34"; + } + + // Create attestation key. + AttestationKey attest_key; + vector<KeyCharacteristics> attest_key_characteristics; + vector<Certificate> attest_key_cert_chain; + ASSERT_EQ(ErrorCode::OK, + GenerateAttestKey(AuthorizationSetBuilder() + .EcdsaKey(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"); + EXPECT_EQ(attest_key_cert_chain.size(), 1); + EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)); + + // Use attestation key to sign an ECDSA key, but include both IMEI attestation ID fields. + AuthorizationSetBuilder builder = AuthorizationSetBuilder() + .EcdsaSigningKey(EcCurve::P_256) + .Authorization(TAG_NO_AUTH_REQUIRED) + .AttestationChallenge("challenge") + .AttestationApplicationId("foo") + .SetDefaultValidity(); + builder.Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size()); + builder.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, second_imei.data(), second_imei.size()); + + vector<uint8_t> attested_key_blob; + vector<KeyCharacteristics> attested_key_characteristics; + vector<Certificate> 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 && !isDeviceIdAttestationRequired()) { + GTEST_SKIP() << "Test not applicable as device does not support IMEI ID attestation."; + } + + ASSERT_EQ(result, ErrorCode::OK); + + device_id_attestation_vsr_check(result); + + 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. + vector<uint8_t> imei_blob(imei.data(), imei.data() + imei.size()); + KeyParameter imei_tag = Authorization(TAG_ATTESTATION_ID_IMEI, imei_blob); + hw_enforced.push_back(imei_tag); + vector<uint8_t> sec_imei_blob(second_imei.data(), second_imei.data() + second_imei.size()); + KeyParameter sec_imei_tag = Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, sec_imei_blob); + hw_enforced.push_back(sec_imei_tag); + + EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced, + hw_enforced, SecLevel(), + attested_key_cert_chain[0].encodedCertificate)); + + CheckedDeleteKey(&attest_key.keyBlob); +} + INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest); } // 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 588a1d44a0..ebea8b27a8 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -217,6 +217,14 @@ bool KeyMintAidlTestBase::isDeviceIdAttestationRequired() { return AidlVersion() >= 2 || property_get_int32("ro.vendor.api_level", 0) >= 33; } +/** + * An API to determine second IMEI ID attestation is required or not, + * which is supported for KeyMint version 3 or first_api_level greater than 33. + */ +bool KeyMintAidlTestBase::isSecondImeiIdAttestationRequired() { + return AidlVersion() >= 3 && property_get_int32("ro.vendor.api_level", 0) > 33; +} + bool KeyMintAidlTestBase::Curve25519Supported() { // Strongbox never supports curve 25519. if (SecLevel() == SecurityLevel::STRONGBOX) { diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h index fae9459171..7c11b951a7 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h @@ -85,6 +85,7 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> { uint32_t boot_patch_level(const vector<KeyCharacteristics>& key_characteristics); uint32_t boot_patch_level(); bool isDeviceIdAttestationRequired(); + bool isSecondImeiIdAttestationRequired(); bool Curve25519Supported(); diff --git a/security/keymint/support/attestation_record.cpp b/security/keymint/support/attestation_record.cpp index 2462228a6e..5a26611197 100644 --- a/security/keymint/support/attestation_record.cpp +++ b/security/keymint/support/attestation_record.cpp @@ -105,6 +105,7 @@ typedef struct km_auth_list { ASN1_INTEGER* boot_patchlevel; ASN1_NULL* device_unique_attestation; ASN1_NULL* identity_credential; + ASN1_OCTET_STRING* attestation_id_second_imei; } KM_AUTH_LIST; ASN1_SEQUENCE(KM_AUTH_LIST) = { @@ -170,6 +171,8 @@ ASN1_SEQUENCE(KM_AUTH_LIST) = { TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()), ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL, TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_second_imei, ASN1_OCTET_STRING, + TAG_ATTESTATION_ID_SECOND_IMEI.maskedTag()), } ASN1_SEQUENCE_END(KM_AUTH_LIST); IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST); @@ -323,6 +326,7 @@ static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list); copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list); copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list); + copyAuthTag(record->attestation_id_second_imei, TAG_ATTESTATION_ID_SECOND_IMEI, auth_list); return ErrorCode::OK; } diff --git a/security/keymint/support/include/keymint_support/keymint_tags.h b/security/keymint/support/include/keymint_support/keymint_tags.h index 5b2a6f32e1..823899a0a3 100644 --- a/security/keymint/support/include/keymint_support/keymint_tags.h +++ b/security/keymint/support/include/keymint_support/keymint_tags.h @@ -77,6 +77,7 @@ DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE); DECLARE_TYPED_TAG(ATTESTATION_ID_BRAND); DECLARE_TYPED_TAG(ATTESTATION_ID_DEVICE); DECLARE_TYPED_TAG(ATTESTATION_ID_IMEI); +DECLARE_TYPED_TAG(ATTESTATION_ID_SECOND_IMEI); DECLARE_TYPED_TAG(ATTESTATION_ID_MANUFACTURER); DECLARE_TYPED_TAG(ATTESTATION_ID_MEID); DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT); |