From 4f64c22809d12453dab0aab728601359fb720b6a Mon Sep 17 00:00:00 2001 From: Selene Huang Date: Tue, 13 Apr 2021 19:54:36 -0700 Subject: [PATCH] Added 12 various attestation related vts tests. - Check for app id only if challenge is provided. - Verify self sign certificate works for RSA and Ecdsa. - Verified attestation is generated for encryption keys too. - Verify no attestation is generated for symetric keys. - Verify app id is always required when attestation challenge is provided to the new key generation. - Verify app id is ignored when challenge is missing. - Verify app id length is properly encoded. - Added vts tests for various attestation success and fail cases. Test: atest VtsAidlKeyMintTargetTest Change-Id: If29249b0913fd9c2f91d20188ca5cfbaa04bead8 --- .../vts/functional/KeyMintAidlTestBase.cpp | 12 +- .../aidl/vts/functional/KeyMintTest.cpp | 427 +++++++++++++++++- 2 files changed, 429 insertions(+), 10 deletions(-) diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index 3da048449b..bde05f1d11 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -883,16 +883,20 @@ bool verify_attestation_record(const string& challenge, // if (error != ErrorCode::OK) return false; EXPECT_GE(att_attestation_version, 3U); + vector appId(app_id.begin(), app_id.end()); - expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, - vector(app_id.begin(), app_id.end())); + // check challenge and app id only if we expects a non-fake certificate + if (challenge.length() > 0) { + EXPECT_EQ(challenge.length(), att_challenge.size()); + EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length())); + + expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, appId); + } EXPECT_GE(att_keymaster_version, 4U); EXPECT_EQ(security_level, att_keymaster_security_level); EXPECT_EQ(security_level, att_attestation_security_level); - EXPECT_EQ(challenge.length(), att_challenge.size()); - EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length())); char property_value[PROPERTY_VALUE_MAX] = {}; // TODO(b/136282179): When running under VTS-on-GSI the TEE-backed diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp index 2d28845b0b..09cdab1a48 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -359,10 +359,10 @@ TEST_P(NewKeyGenerationTest, Rsa) { * have correct characteristics. */ TEST_P(NewKeyGenerationTest, RsaWithAttestation) { - for (auto key_size : ValidKeySizes(Algorithm::RSA)) { - auto challenge = "hello"; - auto app_id = "foo"; + auto challenge = "hello"; + auto app_id = "foo"; + for (auto key_size : ValidKeySizes(Algorithm::RSA)) { vector key_blob; vector key_characteristics; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() @@ -469,6 +469,163 @@ TEST_P(NewKeyGenerationTest, RsaWithRpkAttestation) { } } +/* + * NewKeyGenerationTest.RsaEncryptionWithAttestation + * + * Verifies that keymint attestation for RSA encryption keys with challenge and + * app id is also successful. + */ +TEST_P(NewKeyGenerationTest, RsaEncryptionWithAttestation) { + auto key_size = 2048; + auto challenge = "hello"; + auto app_id = "foo"; + + vector key_blob; + vector key_characteristics; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(key_size, 65537) + .Padding(PaddingMode::NONE) + .AttestationChallenge(challenge) + .AttestationApplicationId(app_id) + .Authorization(TAG_NO_AUTH_REQUIRED) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); + + ASSERT_GT(key_blob.size(), 0U); + AuthorizationSet auths; + for (auto& entry : key_characteristics) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + + EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED)); + EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT)); + + // Verify that App data and ROT are NOT included. + EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST)); + EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA)); + + // Check that some unexpected tags/values are NOT present. + EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN)); + EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY)); + + EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301U)); + + auto os_ver = auths.GetTagValue(TAG_OS_VERSION); + ASSERT_TRUE(os_ver); + EXPECT_EQ(*os_ver, os_version()); + + AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U)); + + EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_)); + ASSERT_GT(cert_chain_.size(), 0); + + AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics); + AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics); + EXPECT_TRUE(verify_attestation_record(challenge, app_id, // + sw_enforced, hw_enforced, SecLevel(), + cert_chain_[0].encodedCertificate)); + + CheckedDeleteKey(&key_blob); +} + +/* + * NewKeyGenerationTest.RsaWithSelfSign + * + * Verifies that attesting to RSA key generation is successful, and returns + * self signed certificate if no challenge is provided. And signing etc + * works as expected. + */ +TEST_P(NewKeyGenerationTest, RsaWithSelfSign) { + for (auto key_size : ValidKeySizes(Algorithm::RSA)) { + vector key_blob; + vector key_characteristics; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(key_size, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); + + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U)); + + EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_)); + ASSERT_EQ(cert_chain_.size(), 1); + + CheckedDeleteKey(&key_blob); + } +} + +/* + * NewKeyGenerationTest.RsaWithAttestationMissAppId + * + * Verifies that attesting to RSA checks for missing app ID. + */ +TEST_P(NewKeyGenerationTest, RsaWithAttestationMissAppId) { + auto challenge = "hello"; + vector key_blob; + vector key_characteristics; + + ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .AttestationChallenge(challenge) + .Authorization(TAG_NO_AUTH_REQUIRED) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); +} + +/* + * NewKeyGenerationTest.RsaWithAttestationAppIdIgnored + * + * Verifies that attesting to RSA ignores app id if challenge is missing. + */ +TEST_P(NewKeyGenerationTest, RsaWithAttestationAppIdIgnored) { + auto key_size = 2048; + auto app_id = "foo"; + + vector key_blob; + vector key_characteristics; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(key_size, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .AttestationApplicationId(app_id) + .Authorization(TAG_NO_AUTH_REQUIRED) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); + + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U)); + + EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_)); + ASSERT_EQ(cert_chain_.size(), 1); + + CheckedDeleteKey(&key_blob); +} + /* * NewKeyGenerationTest.LimitedUsageRsa * @@ -516,10 +673,10 @@ TEST_P(NewKeyGenerationTest, LimitedUsageRsa) { * resulting keys have correct characteristics and attestation. */ TEST_P(NewKeyGenerationTest, LimitedUsageRsaWithAttestation) { - for (auto key_size : ValidKeySizes(Algorithm::RSA)) { - auto challenge = "hello"; - auto app_id = "foo"; + auto challenge = "hello"; + auto app_id = "foo"; + for (auto key_size : ValidKeySizes(Algorithm::RSA)) { vector key_blob; vector key_characteristics; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() @@ -627,6 +784,188 @@ TEST_P(NewKeyGenerationTest, Ecdsa) { } } +/* + * NewKeyGenerationTest.EcdsaAttestation + * + * Verifies that for all Ecdsa key sizes, if challenge and app id is provided, + * an attestation will be generated. + */ +TEST_P(NewKeyGenerationTest, EcdsaAttestation) { + auto challenge = "hello"; + auto app_id = "foo"; + + for (auto key_size : ValidKeySizes(Algorithm::EC)) { + vector key_blob; + vector key_characteristics; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(key_size) + .Digest(Digest::NONE) + .AttestationChallenge(challenge) + .AttestationApplicationId(app_id) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + + EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_)); + ASSERT_GT(cert_chain_.size(), 0); + + AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics); + AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics); + EXPECT_TRUE(verify_attestation_record(challenge, app_id, // + sw_enforced, hw_enforced, SecLevel(), + cert_chain_[0].encodedCertificate)); + + CheckedDeleteKey(&key_blob); + } +} + +/* + * NewKeyGenerationTest.EcdsaSelfSignAttestation + * + * Verifies that if no challenge is provided to an Ecdsa key generation, then + * the key will generate a self signed attestation. + */ +TEST_P(NewKeyGenerationTest, EcdsaSelfSignAttestation) { + for (auto key_size : ValidKeySizes(Algorithm::EC)) { + vector key_blob; + vector key_characteristics; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .EcdsaSigningKey(key_size) + .Digest(Digest::NONE) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + + EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_)); + ASSERT_EQ(cert_chain_.size(), 1); + + AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics); + AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics); + + CheckedDeleteKey(&key_blob); + } +} + +/* + * NewKeyGenerationTest.EcdsaAttestationRequireAppId + * + * Verifies that if attestation challenge is provided to Ecdsa key generation, then + * app id must also be provided or else it will fail. + */ +TEST_P(NewKeyGenerationTest, EcdsaAttestationRequireAppId) { + auto challenge = "hello"; + vector key_blob; + vector key_characteristics; + + ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, + GenerateKey(AuthorizationSetBuilder() + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::NONE) + .AttestationChallenge(challenge) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); +} + +/* + * NewKeyGenerationTest.EcdsaIgnoreAppId + * + * Verifies that if no challenge is provided to the Ecdsa key generation, then + * any appid will be ignored, and keymint will generate a self sign certificate. + */ +TEST_P(NewKeyGenerationTest, EcdsaIgnoreAppId) { + auto app_id = "foo"; + + for (auto key_size : ValidKeySizes(Algorithm::EC)) { + vector key_blob; + vector key_characteristics; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .EcdsaSigningKey(key_size) + .Digest(Digest::NONE) + .AttestationApplicationId(app_id) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); + + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + + EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_)); + ASSERT_EQ(cert_chain_.size(), 1); + + AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics); + AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics); + + CheckedDeleteKey(&key_blob); + } +} + +/* + * NewKeyGenerationTest.AttestationApplicationIDLengthProperlyEncoded + * + * Verifies that the Attestation Application ID software enforced tag has a proper length encoding. + * Some implementations break strict encoding rules by encoding a length between 127 and 256 in one + * byte. Proper DER encoding specifies that for lengths greater than 127, one byte should be used + * to specify how many following bytes will be used to encode the length. + */ +TEST_P(NewKeyGenerationTest, AttestationApplicationIDLengthProperlyEncoded) { + auto challenge = "hello"; + auto key_size = 256; + std::vector app_id_lengths{143, 258}; + + for (uint32_t length : app_id_lengths) { + const string app_id(length, 'a'); + vector key_blob; + vector key_characteristics; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(key_size) + .Digest(Digest::NONE) + .AttestationChallenge(challenge) + .AttestationApplicationId(app_id) + .SetDefaultValidity(), + &key_blob, &key_characteristics)); + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + + EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_)); + ASSERT_GT(cert_chain_.size(), 0); + + AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics); + AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics); + EXPECT_TRUE(verify_attestation_record(challenge, app_id, // + sw_enforced, hw_enforced, SecLevel(), + cert_chain_[0].encodedCertificate)); + + CheckedDeleteKey(&key_blob); + } +} + /* * NewKeyGenerationTest.LimitedUsageEcdsa * @@ -788,6 +1127,41 @@ TEST_P(NewKeyGenerationTest, Hmac) { } } +/* + * NewKeyGenerationTest.HmacNoAttestation + * + * Verifies that for Hmac key generation, no attestation will be generated even if challenge + * and app id are provided. + */ +TEST_P(NewKeyGenerationTest, HmacNoAttestation) { + auto challenge = "hello"; + auto app_id = "foo"; + + for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) { + vector key_blob; + vector key_characteristics; + constexpr size_t key_size = 128; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(key_size) + .Digest(digest) + .AttestationChallenge(challenge) + .AttestationApplicationId(app_id) + .Authorization(TAG_MIN_MAC_LENGTH, 128), + &key_blob, &key_characteristics)); + + ASSERT_GT(key_blob.size(), 0U); + ASSERT_EQ(cert_chain_.size(), 0); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + + CheckedDeleteKey(&key_blob); + } +} + /* * NewKeyGenerationTest.LimitedUsageHmac * @@ -922,6 +1296,47 @@ TEST_P(NewKeyGenerationTest, HmacDigestNone) { .Authorization(TAG_MIN_MAC_LENGTH, 128))); } +/* + * NewKeyGenerationTest.AesNoAttestation + * + * Verifies that attestation parameters to AES keys are ignored and generateKey + * will succeed. + */ +TEST_P(NewKeyGenerationTest, AesNoAttestation) { + auto challenge = "hello"; + auto app_id = "foo"; + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .EcbMode() + .Padding(PaddingMode::PKCS7) + .AttestationChallenge(challenge) + .AttestationApplicationId(app_id))); + + ASSERT_EQ(cert_chain_.size(), 0); +} + +/* + * NewKeyGenerationTest.TripleDesNoAttestation + * + * Verifies that attesting parameters to 3DES keys are ignored and generate key + * will be successful. No attestation should be generated. + */ +TEST_P(NewKeyGenerationTest, TripleDesNoAttestation) { + auto challenge = "hello"; + auto app_id = "foo"; + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::ECB) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE) + .AttestationChallenge(challenge) + .AttestationApplicationId(app_id))); + ASSERT_EQ(cert_chain_.size(), 0); +} + INSTANTIATE_KEYMINT_AIDL_TEST(NewKeyGenerationTest); typedef KeyMintAidlTestBase SigningOperationsTest;