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 5989cde00d..c876440d4b 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -562,7 +562,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. @@ -606,6 +606,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 * @@ -665,6 +704,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 * @@ -779,6 +855,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 * @@ -4153,7 +4267,7 @@ TEST_P(MaxOperationsTest, TestLimitAes) { } /* - * MaxOperationsTest.TestLimitAes + * MaxOperationsTest.TestLimitRsa * * Verifies that the max uses per boot tag works correctly with RSA keys. */ @@ -4180,6 +4294,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,