From d22ec8418bec5781d8e72478c17bc34735070a15 Mon Sep 17 00:00:00 2001 From: Qi Wu Date: Thu, 26 Nov 2020 13:27:53 +0800 Subject: [PATCH] Add limited use keys related tag into KeyMint aidl. And add vts test to verify the tag appears in the key characteristics. also if the tag is enforced in the hardware, afer the usage of the key is exhausted, the key blob should be invalidated from the secure storage (such as RPMB partition). Bug: b/174140443 Test: atest VtsHalKeyMintV1_0TargetTest Change-Id: Ic65b855c5a8692ab8d1281dd46562ad0844ab1b0 --- .../hardware/security/keymint/Tag.aidl | 1 + .../hardware/security/keymint/Tag.aidl | 29 +++ .../aidl/vts/functional/KeyMintTest.cpp | 212 +++++++++++++++++- .../include/keymint_support/keymint_tags.h | 19 +- 4 files changed, 250 insertions(+), 11 deletions(-) diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl index ce12fed082..a6be6b1627 100644 --- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl +++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl @@ -42,6 +42,7 @@ enum Tag { USAGE_EXPIRE_DATETIME = 1610613138, MIN_SECONDS_BETWEEN_OPS = 805306771, MAX_USES_PER_BOOT = 805306772, + USAGE_COUNT_LIMIT = 805306773, USER_ID = 805306869, USER_SECURE_ID = -1610612234, NO_AUTH_REQUIRED = 1879048695, diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl index f92bf008ed..bc07235dc0 100644 --- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl +++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl @@ -332,6 +332,35 @@ enum Tag { */ MAX_USES_PER_BOOT = (3 << 28) /* TagType:UINT */ | 404, + /** + * Tag::USAGE_COUNT_LIMIT specifies the number of times that a key may be used. This can be + * used to limit the use of a key. + * + * The value is a 32-bit integer representing the current number of attempts left. + * + * When initializing a limited use key, the value of this tag represents the maximum usage + * limit for that key. After the key usage is exhausted, the key blob should be invalidated by + * finish() call. Any subsequent attempts to use the key must result in a failure with + * ErrorCode::INVALID_KEY_BLOB returned by IKeyMintDevice. + * + * At this point, if the caller specifies count > 1, it is not expected that any TEE will be + * able to enforce this feature in the hardware due to limited resources of secure + * storage. In this case, the tag with the value of maximum usage must be added to the key + * characteristics with SecurityLevel::SOFTWARE by the IKeyMintDevice. + * + * On the other hand, if the caller specifies count = 1, some TEEs may have the ability + * to enforce this feature in the hardware with its secure storage. If the IKeyMintDevice + * implementation can enforce this feature, the tag with value = 1 must be added to the key + * characteristics with the SecurityLevel of the IKeyMintDevice. If the IKeyMintDevice can't + * enforce this feature even when the count = 1, the tag must be added to the key + * characteristics with the SecurityLevel::SOFTWARE. + * + * When the key is attested, this tag with the same value must also be added to the attestation + * record. This tag must have the same SecurityLevel as the tag that is added to the key + * characteristics. + */ + USAGE_COUNT_LIMIT = (3 << 28) | 405, /* TagType:UINT */ + /** * Tag::USER_ID specifies the ID of the Android user that is permitted to use the key. * diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp index e7c94f37a0..8d1da81147 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -560,7 +560,7 @@ TEST_P(NewKeyGenerationTest, Rsa) { } /* - * NewKeyGenerationTest.Rsa + * NewKeyGenerationTest.RsaWithAttestation * * Verifies that keymint can generate all required RSA key sizes, and that the resulting keys * have correct characteristics. @@ -604,6 +604,45 @@ TEST_P(NewKeyGenerationTest, RsaWithAttestation) { } } +/* + * NewKeyGenerationTest.LimitedUsageRsa + * + * Verifies that KeyMint can generate all required RSA key sizes with limited usage, and that the + * resulting keys have correct characteristics. + */ +TEST_P(NewKeyGenerationTest, LimitedUsageRsa) { + 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_USAGE_COUNT_LIMIT, 1), + &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)); + + // Check the usage count limit tag appears in the authorizations. + AuthorizationSet auths; + for (auto& entry : key_characteristics) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) + << "key usage count limit " << 1U << " missing"; + + CheckedDeleteKey(&key_blob); + } +} + /* * NewKeyGenerationTest.NoInvalidRsaSizes * @@ -663,6 +702,43 @@ TEST_P(NewKeyGenerationTest, Ecdsa) { } } +/* + * NewKeyGenerationTest.LimitedUsageEcdsa + * + * Verifies that KeyMint can generate all required EC key sizes with limited usage, and that the + * resulting keys have correct characteristics. + */ +TEST_P(NewKeyGenerationTest, LimitedUsageEcdsa) { + 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) + .Authorization(TAG_USAGE_COUNT_LIMIT, 1), + &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"; + + // Check the usage count limit tag appears in the authorizations. + AuthorizationSet auths; + for (auto& entry : key_characteristics) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) + << "key usage count limit " << 1U << " missing"; + + CheckedDeleteKey(&key_blob); + } +} + /* * NewKeyGenerationTest.EcdsaDefaultSize * @@ -777,6 +853,44 @@ TEST_P(NewKeyGenerationTest, Hmac) { } } +/* + * NewKeyGenerationTest.LimitedUsageHmac + * + * Verifies that KeyMint supports all required digests with limited usage Hmac, and that the + * resulting keys have correct characteristics. + */ +TEST_P(NewKeyGenerationTest, LimitedUsageHmac) { + 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) + .Authorization(TAG_MIN_MAC_LENGTH, 128) + .Authorization(TAG_USAGE_COUNT_LIMIT, 1), + &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::HMAC)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + + // Check the usage count limit tag appears in the authorizations. + AuthorizationSet auths; + for (auto& entry : key_characteristics) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) + << "key usage count limit " << 1U << " missing"; + + CheckedDeleteKey(&key_blob); + } +} + /* * NewKeyGenerationTest.HmacCheckKeySizes * @@ -4151,7 +4265,7 @@ TEST_P(MaxOperationsTest, TestLimitAes) { } /* - * MaxOperationsTest.TestLimitAes + * MaxOperationsTest.TestLimitRsa * * Verifies that the max uses per boot tag works correctly with RSA keys. */ @@ -4178,6 +4292,100 @@ TEST_P(MaxOperationsTest, TestLimitRsa) { INSTANTIATE_KEYMINT_AIDL_TEST(MaxOperationsTest); +typedef KeyMintAidlTestBase UsageCountLimitTest; + +/* + * UsageCountLimitTest.TestLimitAes + * + * Verifies that the usage count limit tag works correctly with AES keys. + */ +TEST_P(UsageCountLimitTest, TestLimitAes) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .EcbMode() + .Padding(PaddingMode::NONE) + .Authorization(TAG_USAGE_COUNT_LIMIT, 1))); + + // Check the usage count limit tag appears in the authorizations. + AuthorizationSet auths; + for (auto& entry : key_characteristics_) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) + << "key usage count limit " << 1U << " missing"; + + string message = "1234567890123456"; + auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE); + + // First usage of AES key should work. + EncryptMessage(message, params); + + AuthorizationSet hardware_auths; + for (auto& entry : key_characteristics_) { + if (entry.securityLevel != SecurityLevel::SOFTWARE) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + } + if (hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) { + // Usage count limit tag is enforced by hardware. After using the key, the key blob + // must be invalidated from secure storage (such as RPMB partition). + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::ENCRYPT, params)); + } else { + // Usage count limit tag is enforced by software, keymint does nothing. + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params)); + } +} + +/* + * UsageCountLimitTest.TestLimitRsa + * + * Verifies that the usage count limit tag works correctly with RSA keys. + */ +TEST_P(UsageCountLimitTest, TestLimitRsa) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(1024, 65537) + .NoDigestOrPadding() + .Authorization(TAG_USAGE_COUNT_LIMIT, 1))); + + // Check the usage count limit tag appears in the authorizations. + AuthorizationSet auths; + for (auto& entry : key_characteristics_) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) + << "key usage count limit " << 1U << " missing"; + + string message = "1234567890123456"; + auto params = AuthorizationSetBuilder().NoDigestOrPadding(); + + // First usage of RSA key should work. + SignMessage(message, params); + + AuthorizationSet hardware_auths; + for (auto& entry : key_characteristics_) { + if (entry.securityLevel != SecurityLevel::SOFTWARE) { + auths.push_back(AuthorizationSet(entry.authorizations)); + } + } + + if (hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) { + // Usage count limit tag is enforced by hardware. After using the key, the key blob + // must be invalidated from secure storage (such as RPMB partition). + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::SIGN, params)); + } else { + // Usage count limit tag is enforced by software, keymint does nothing. + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params)); + } +} + +INSTANTIATE_KEYMINT_AIDL_TEST(UsageCountLimitTest); + typedef KeyMintAidlTestBase AddEntropyTest; /* diff --git a/security/keymint/support/include/keymint_support/keymint_tags.h b/security/keymint/support/include/keymint_support/keymint_tags.h index 76aecb71b5..8d2fe28b9b 100644 --- a/security/keymint/support/include/keymint_support/keymint_tags.h +++ b/security/keymint/support/include/keymint_support/keymint_tags.h @@ -119,6 +119,7 @@ DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED); DECLARE_TYPED_TAG(TRUSTED_USER_PRESENCE_REQUIRED); DECLARE_TYPED_TAG(UNIQUE_ID); DECLARE_TYPED_TAG(UNLOCKED_DEVICE_REQUIRED); +DECLARE_TYPED_TAG(USAGE_COUNT_LIMIT); DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME); DECLARE_TYPED_TAG(USER_AUTH_TYPE); DECLARE_TYPED_TAG(USER_ID); @@ -135,15 +136,15 @@ using all_tags_t = MetaList< TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t, TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, - TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_USER_ID_t, TAG_USER_SECURE_ID_t, - TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t, - TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, - TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_HARDWARE_TYPE_t, - TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t, - TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t, - TAG_ATTESTATION_APPLICATION_ID_t, TAG_ATTESTATION_ID_BRAND_t, TAG_ATTESTATION_ID_DEVICE_t, - TAG_ATTESTATION_ID_PRODUCT_t, TAG_ATTESTATION_ID_MANUFACTURER_t, TAG_ATTESTATION_ID_MODEL_t, - TAG_ATTESTATION_ID_SERIAL_t, TAG_ATTESTATION_ID_IMEI_t, TAG_ATTESTATION_ID_MEID_t, + TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_USAGE_COUNT_LIMIT_t, + TAG_USER_ID_t, TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, + TAG_ALLOW_WHILE_ON_BODY_t, TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t, + TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, + TAG_HARDWARE_TYPE_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, + TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, + TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_ATTESTATION_ID_BRAND_t, + TAG_ATTESTATION_ID_DEVICE_t, TAG_ATTESTATION_ID_PRODUCT_t, + TAG_ATTESTATION_ID_MANUFACTURER_t, TAG_ATTESTATION_ID_MODEL_t, TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t, TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t, TAG_TRUSTED_CONFIRMATION_REQUIRED_t,