diff options
-rw-r--r-- | aes_key.cpp | 35 | ||||
-rw-r--r-- | aes_key.h | 5 | ||||
-rw-r--r-- | aes_operation.cpp | 41 | ||||
-rw-r--r-- | android_keymaster_test.cpp | 376 | ||||
-rw-r--r-- | android_keymaster_test_utils.cpp | 19 | ||||
-rw-r--r-- | android_keymaster_test_utils.h | 4 | ||||
-rw-r--r-- | ec_keymaster0_key.cpp | 6 | ||||
-rw-r--r-- | hmac_key.cpp | 57 | ||||
-rw-r--r-- | hmac_key.h | 4 | ||||
-rw-r--r-- | hmac_operation.cpp | 70 | ||||
-rw-r--r-- | hmac_operation.h | 5 | ||||
-rw-r--r-- | include/keymaster/keymaster_tags.h | 1 | ||||
-rw-r--r-- | keymaster_enforcement.cpp | 3 | ||||
-rw-r--r-- | rsa_keymaster0_key.cpp | 6 | ||||
-rw-r--r-- | symmetric_key.cpp | 10 | ||||
-rw-r--r-- | symmetric_key.h | 2 |
16 files changed, 476 insertions, 168 deletions
diff --git a/aes_key.cpp b/aes_key.cpp index bc940df..92ea66e 100644 --- a/aes_key.cpp +++ b/aes_key.cpp @@ -48,6 +48,18 @@ keymaster_error_t AesKeyFactory::LoadKey(const KeymasterKeyBlob& key_material, if (!key) return KM_ERROR_OUTPUT_PARAMETER_NULL; + uint32_t min_mac_length = 0; + if (hw_enforced.Contains(TAG_BLOCK_MODE, KM_MODE_GCM) || + sw_enforced.Contains(TAG_BLOCK_MODE, KM_MODE_GCM)) { + + if (!hw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length) && + !sw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length)) { + + LOG_E("AES-GCM key must have KM_TAG_MIN_MAC_LENGTH", 0); + return KM_ERROR_INVALID_KEY_BLOB; + } + } + keymaster_error_t error = KM_ERROR_OK; key->reset(new (std::nothrow) AesKey(key_material, hw_enforced, sw_enforced, &error)); if (!key->get()) @@ -55,4 +67,27 @@ keymaster_error_t AesKeyFactory::LoadKey(const KeymasterKeyBlob& key_material, return error; } +keymaster_error_t AesKeyFactory::validate_algorithm_specific_new_key_params( + const AuthorizationSet& key_description) const { + if (key_description.Contains(TAG_BLOCK_MODE, KM_MODE_GCM)) { + uint32_t min_tag_length; + if (!key_description.GetTagValue(TAG_MIN_MAC_LENGTH, &min_tag_length)) + return KM_ERROR_MISSING_MIN_MAC_LENGTH; + + if (min_tag_length % 8 != 0) + return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH; + + if (min_tag_length < kMinGcmTagLength || min_tag_length > kMaxGcmTagLength) + return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH; + } else { + // Not GCM + if (key_description.find(TAG_MIN_MAC_LENGTH) != -1) { + LOG_W("KM_TAG_MIN_MAC_LENGTH found for non AES-GCM key", 0); + return KM_ERROR_INVALID_TAG; + } + } + + return KM_ERROR_OK; +} + } // namespace keymaster @@ -23,6 +23,9 @@ namespace keymaster { +const size_t kMinGcmTagLength = 12 * 8; +const size_t kMaxGcmTagLength = 16 * 8; + class AesKeyFactory : public SymmetricKeyFactory { public: AesKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {} @@ -40,6 +43,8 @@ class AesKeyFactory : public SymmetricKeyFactory { bool key_size_supported(size_t key_size_bits) const override { return key_size_bits == 128 || key_size_bits == 192 || key_size_bits == 256; } + keymaster_error_t validate_algorithm_specific_new_key_params( + const AuthorizationSet& key_description) const override; }; class AesKey : public SymmetricKey { diff --git a/aes_operation.cpp b/aes_operation.cpp index bf18041..c3bc662 100644 --- a/aes_operation.cpp +++ b/aes_operation.cpp @@ -50,6 +50,33 @@ inline bool allows_padding(keymaster_block_mode_t block_mode) { return false; } +static keymaster_error_t GetAndValidateGcmTagLength(const AuthorizationSet& begin_params, + const AuthorizationSet& key_params, + size_t* tag_length) { + uint32_t tag_length_bits; + if (!begin_params.GetTagValue(TAG_MAC_LENGTH, &tag_length_bits)) { + return KM_ERROR_MISSING_MAC_LENGTH; + } + + uint32_t min_tag_length_bits; + if (!key_params.GetTagValue(TAG_MIN_MAC_LENGTH, &min_tag_length_bits)) { + LOG_E("AES GCM key must have KM_TAG_MIN_MAC_LENGTH", 0); + return KM_ERROR_INVALID_KEY_BLOB; + } + + if (tag_length_bits % 8 != 0 || tag_length_bits > kMaxGcmTagLength || + tag_length_bits < kMinGcmTagLength) { + return KM_ERROR_UNSUPPORTED_MAC_LENGTH; + } + + if (tag_length_bits < min_tag_length_bits) { + return KM_ERROR_INVALID_MAC_LENGTH; + } + + *tag_length = tag_length_bits / 8; + return KM_ERROR_OK; +} + Operation* AesOperationFactory::CreateOperation(const Key& key, const AuthorizationSet& begin_params, keymaster_error_t* error) { @@ -83,22 +110,16 @@ Operation* AesOperationFactory::CreateOperation(const Key& key, size_t tag_length = 0; if (block_mode == KM_MODE_GCM) { - uint32_t tag_length_bits; - if (!begin_params.GetTagValue(TAG_MAC_LENGTH, &tag_length_bits)) { - *error = KM_ERROR_MISSING_MAC_LENGTH; - return nullptr; - } - tag_length = tag_length_bits / 8; - if (tag_length_bits % 8 != 0 || tag_length > GCM_MAX_TAG_LENGTH || - tag_length < GCM_MIN_TAG_LENGTH) { - *error = KM_ERROR_UNSUPPORTED_MAC_LENGTH; + *error = GetAndValidateGcmTagLength(begin_params, key.authorizations(), &tag_length); + if (*error != KM_ERROR_OK) { return nullptr; } } keymaster_padding_t padding; - if (!GetAndValidatePadding(begin_params, key, &padding, error)) + if (!GetAndValidatePadding(begin_params, key, &padding, error)) { return nullptr; + } if (!allows_padding(block_mode) && padding != KM_PAD_NONE) { LOG_E("Mode does not support padding", 0); *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE; diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp index c0d6bb7..3e9d125 100644 --- a/android_keymaster_test.cpp +++ b/android_keymaster_test.cpp @@ -325,7 +325,6 @@ class NewKeyGeneration : public Keymaster1Test { EXPECT_FALSE(contains(auths, TAG_AUTH_TIMEOUT, 301)); // Now check that unspecified, defaulted tags are correct. - EXPECT_TRUE(contains(auths, TAG_ORIGIN, KM_ORIGIN_GENERATED)); EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME)); } }; @@ -438,8 +437,61 @@ TEST_P(NewKeyGeneration, EcdsaAllValidSizes) { } TEST_P(NewKeyGeneration, HmacSha256) { - ASSERT_EQ(KM_ERROR_OK, - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_256))); + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacMultipleDigests) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA1) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacDigestNone) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacSha256TooShortMacLength) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 48))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacSha256NonIntegralOctetMacLength) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 130))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacSha256TooLongMacLength) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 384))); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } @@ -759,94 +811,67 @@ TEST_P(SigningOperationsTest, AesEcbSign) { } TEST_P(SigningOperationsTest, HmacSha1Success) { - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA1)); + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA1) + .Authorization(TAG_MIN_MAC_LENGTH, 160)); string message = "12345678901234567890123456789012"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA1, 160); + MacMessage(message, &signature, 160); ASSERT_EQ(20U, signature.size()); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } TEST_P(SigningOperationsTest, HmacSha224Success) { - ASSERT_EQ(KM_ERROR_OK, - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_224))); + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_224) + .Authorization(TAG_MIN_MAC_LENGTH, 160))); string message = "12345678901234567890123456789012"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_224, 224); + MacMessage(message, &signature, 224); ASSERT_EQ(28U, signature.size()); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } TEST_P(SigningOperationsTest, HmacSha256Success) { - ASSERT_EQ(KM_ERROR_OK, - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_256))); + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))); string message = "12345678901234567890123456789012"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_256, 256); + MacMessage(message, &signature, 256); ASSERT_EQ(32U, signature.size()); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } TEST_P(SigningOperationsTest, HmacSha384Success) { - ASSERT_EQ(KM_ERROR_OK, - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_384))); + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_384) + .Authorization(TAG_MIN_MAC_LENGTH, 384))); string message = "12345678901234567890123456789012"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_384, 384); + MacMessage(message, &signature, 384); ASSERT_EQ(48U, signature.size()); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } TEST_P(SigningOperationsTest, HmacSha512Success) { - ASSERT_EQ(KM_ERROR_OK, - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_512))); - string message = "12345678901234567890123456789012"; - string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_512, 512); - ASSERT_EQ(64U, signature.size()); - - EXPECT_EQ(0, GetParam()->keymaster0_calls()); -} - -TEST_P(SigningOperationsTest, HmacAnyDigestSuccess) { - ASSERT_EQ(KM_ERROR_OK, - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_NONE))); - string message = "12345678901234567890123456789012"; - string signature; - - size_t len; - keymaster_digest_t* digests; - ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC, - KM_PURPOSE_SIGN, &digests, &len)); - for (size_t i = 0; i < len; ++i) - MacMessage(message, &signature, digests[i], 128 /* small MAC to work with all digests */); - free(digests); - - // Ensure that we can't actually try to do an HMAC with no digest - AuthorizationSet begin_params(client_params()); - begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); - begin_params.push_back(TAG_MAC_LENGTH, 128); - EXPECT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params)); - - EXPECT_EQ(0, GetParam()->keymaster0_calls()); -} - -TEST_P(SigningOperationsTest, HmacLengthInKey) { - // TODO(swillden): unified API should generate an error on key generation. ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() .HmacKey(128) - .Digest(KM_DIGEST_SHA_2_256) - .Authorization(TAG_MAC_LENGTH, 20))); + .Digest(KM_DIGEST_SHA_2_512) + .Authorization(TAG_MIN_MAC_LENGTH, 512))); string message = "12345678901234567890123456789012"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_256, 240); - // Size in key was ignored. - ASSERT_EQ(30U, signature.size()); + MacMessage(message, &signature, 512); + ASSERT_EQ(64U, signature.size()); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } @@ -1098,18 +1123,29 @@ TEST_P(SigningOperationsTest, HmacRfc4231TestCase7) { } TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) { - ASSERT_EQ(KM_ERROR_OK, - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_256))); + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))); AuthorizationSet begin_params(client_params()); begin_params.push_back(TAG_MAC_LENGTH, 264); begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); - ASSERT_EQ(KM_ERROR_OK, + ASSERT_EQ(KM_ERROR_UNSUPPORTED_MAC_LENGTH, + BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_MAC_LENGTH, 120); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + ASSERT_EQ(KM_ERROR_INVALID_MAC_LENGTH, BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */)); - string message = "1234567890123456789012345678901"; - string result; - size_t input_consumed; - ASSERT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); - ASSERT_EQ(KM_ERROR_UNSUPPORTED_MAC_LENGTH, FinishOperation(&result)); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } @@ -1448,81 +1484,92 @@ TEST_P(VerificationOperationsTest, EcdsaSha256Success) { } TEST_P(VerificationOperationsTest, HmacSha1Success) { - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA1)); + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA1) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); string message = "123456789012345678901234567890123456789012345678"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA1, 160); - VerifyMessage(message, signature, KM_DIGEST_SHA1); + MacMessage(message, &signature, 160); + VerifyMac(message, signature); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } TEST_P(VerificationOperationsTest, HmacSha224Success) { - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_224)); + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_224) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); string message = "123456789012345678901234567890123456789012345678"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_224, 224); - VerifyMessage(message, signature, KM_DIGEST_SHA_2_224); + MacMessage(message, &signature, 224); + VerifyMac(message, signature); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } TEST_P(VerificationOperationsTest, HmacSha256Success) { - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_256)); + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); string message = "123456789012345678901234567890123456789012345678"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_256, 256); - VerifyMessage(message, signature, KM_DIGEST_SHA_2_256); + MacMessage(message, &signature, 256); + VerifyMac(message, signature); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } -TEST_P(VerificationOperationsTest, HmacSha384Success) { - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_384)); +TEST_P(VerificationOperationsTest, HmacSha256TooShortMac) { + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); string message = "123456789012345678901234567890123456789012345678"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_384, 384); - VerifyMessage(message, signature, KM_DIGEST_SHA_2_384); + MacMessage(message, &signature, 256); + + // Shorten to 128 bits, should still work. + signature.resize(128 / 8); + VerifyMac(message, signature); + + // Drop one more byte. + signature.resize(signature.length() - 1); + + AuthorizationSet begin_params(client_params()); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, FinishOperation(signature, &result)); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } -TEST_P(VerificationOperationsTest, HmacSha512Success) { - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_SHA_2_512)); +TEST_P(VerificationOperationsTest, HmacSha384Success) { + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_384) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); string message = "123456789012345678901234567890123456789012345678"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_512, 512); - VerifyMessage(message, signature, KM_DIGEST_SHA_2_512); + MacMessage(message, &signature, 384); + VerifyMac(message, signature); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } -TEST_P(VerificationOperationsTest, HmacAnyDigestSuccess) { - ASSERT_EQ(KM_ERROR_OK, - GenerateKey(AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_NONE))); - string message = "12345678901234567890123456789012"; +TEST_P(VerificationOperationsTest, HmacSha512Success) { + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_512) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); + string message = "123456789012345678901234567890123456789012345678"; string signature; - - size_t len; - keymaster_digest_t* digests; - ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC, - KM_PURPOSE_SIGN, &digests, &len)); - for (size_t i = 0; i < len; ++i) { - MacMessage(message, &signature, digests[i], 128 /* small MAC to work with all digests */); - VerifyMessage(message, signature, digests[i]); - if (len > 1) { - size_t wrong_digest_index = (i == 0) ? 1 : 0; - AuthorizationSet begin_params(client_params()); - begin_params.push_back(TAG_DIGEST, digests[wrong_digest_index]); - begin_params.push_back(TAG_MAC_LENGTH, 128); - EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); - string output; - size_t input_consumed; - EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &output, &input_consumed)); - EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &output)); - } - } - free(digests); + MacMessage(message, &signature, 512); + VerifyMac(message, signature); EXPECT_EQ(0, GetParam()->keymaster0_calls()); } @@ -1626,7 +1673,10 @@ TEST_P(ImportKeyTest, RsaSuccess) { TAG_RSA_PUBLIC_EXPONENT, 65537U)); // And values provided by AndroidKeymaster - EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); + if (GetParam()->algorithm_in_hardware(KM_ALGORITHM_RSA)) + EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN)); + else + EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME)); string message(1024 / 8, 'a'); @@ -1709,7 +1759,10 @@ TEST_P(ImportKeyTest, EcdsaSuccess) { TAG_KEY_SIZE, 256)); // And values provided by AndroidKeymaster - EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); + if (GetParam()->algorithm_in_hardware(KM_ALGORITHM_EC)) + EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN)); + else + EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME)); string message(32, 'a'); @@ -1738,7 +1791,10 @@ TEST_P(ImportKeyTest, EcdsaSizeSpecified) { TAG_KEY_SIZE, 256)); // And values provided by AndroidKeymaster - EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); + if (GetParam()->algorithm_in_hardware(KM_ALGORITHM_EC)) + EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN)); + else + EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME)); string message(32, 'a'); @@ -1787,7 +1843,7 @@ TEST_P(ImportKeyTest, HmacSha256KeySuccess) { ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() .HmacKey(sizeof(key_data) * 8) .Digest(KM_DIGEST_SHA_2_256) - .Authorization(TAG_MAC_LENGTH, 32), + .Authorization(TAG_MIN_MAC_LENGTH, 256), KM_KEY_FORMAT_RAW, key)); EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); @@ -1795,7 +1851,7 @@ TEST_P(ImportKeyTest, HmacSha256KeySuccess) { string message = "Hello World!"; string signature; - MacMessage(message, &signature, KM_DIGEST_SHA_2_256, 32); + MacMessage(message, &signature, 256); VerifyMessage(message, signature, KM_DIGEST_SHA_2_256); EXPECT_EQ(0, GetParam()->keymaster0_calls()); @@ -1916,7 +1972,7 @@ TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) { TEST_P(EncryptionOperationsTest, RsaOaepUnauthorizedDigest) { ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() - .RsaEncryptionKey(512, 3) + .RsaEncryptionKey(512, 3) .Padding(KM_PAD_RSA_OAEP) .Digest(KM_DIGEST_SHA_2_256))); string message = "Hello World!"; @@ -2115,10 +2171,11 @@ TEST_P(EncryptionOperationsTest, EcdsaEncrypt) { } TEST_P(EncryptionOperationsTest, HmacEncrypt) { - ASSERT_EQ( - KM_ERROR_OK, - GenerateKey( - AuthorizationSetBuilder().HmacKey(128).Digest(KM_DIGEST_NONE).Padding(KM_PAD_NONE))); + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT)); ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT)); @@ -2552,7 +2609,8 @@ TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) { ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) - .Authorization(TAG_PADDING, KM_PAD_NONE))); + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); string aad = "foobar"; string message = "123456789012345678901234567890123456"; AuthorizationSet begin_params(client_params()); @@ -2590,6 +2648,70 @@ TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) { EXPECT_EQ(0, GetParam()->keymaster0_calls()); } +TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 96); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, + BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + string ciphertext; + size_t input_consumed; + AuthorizationSet update_out_params; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + + // Grab nonce + EXPECT_NE(-1, begin_out_params.find(TAG_NONCE)); + begin_params.Reinitialize(client_params()); + begin_params.push_back(begin_out_params); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 96); + + // Decrypt. + EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) { uint8_t nonce[] = { 0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f, @@ -2622,7 +2744,8 @@ TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) { .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) .Authorization(TAG_PADDING, KM_PAD_NONE) - .Authorization(TAG_CALLER_NONCE), + .Authorization(TAG_CALLER_NONCE) + .Authorization(TAG_MIN_MAC_LENGTH, 128), KM_KEY_FORMAT_RAW, good_key_str)); EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed)); @@ -2637,7 +2760,8 @@ TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) { ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) - .Authorization(TAG_PADDING, KM_PAD_NONE), + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128), KM_KEY_FORMAT_RAW, bad_key_str)); EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed)); @@ -2650,7 +2774,8 @@ TEST_P(EncryptionOperationsTest, AesGcmAadNoData) { ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) - .Authorization(TAG_PADDING, KM_PAD_NONE))); + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); string aad = "123456789012345678"; string empty_message; AuthorizationSet begin_params(client_params()); @@ -2692,7 +2817,8 @@ TEST_P(EncryptionOperationsTest, AesGcmIncremental) { ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) - .Authorization(TAG_PADDING, KM_PAD_NONE))); + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); AuthorizationSet begin_params(client_params()); begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); begin_params.push_back(TAG_PADDING, KM_PAD_NONE); @@ -2761,7 +2887,8 @@ TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) { ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) - .Authorization(TAG_PADDING, KM_PAD_NONE))); + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); string message = "123456789012345678901234567890123456"; AuthorizationSet begin_params(client_params()); begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); @@ -2811,7 +2938,8 @@ TEST_P(EncryptionOperationsTest, AesGcmBadAad) { ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) - .Authorization(TAG_PADDING, KM_PAD_NONE))); + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); string message = "12345678901234567890123456789012"; AuthorizationSet begin_params(client_params()); begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); @@ -2857,7 +2985,8 @@ TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) { ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) - .Authorization(TAG_PADDING, KM_PAD_NONE))); + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); string message = "12345678901234567890123456789012"; AuthorizationSet begin_params(client_params()); begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); @@ -2897,7 +3026,8 @@ TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) { ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() .AesEncryptionKey(128) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) - .Authorization(TAG_PADDING, KM_PAD_NONE))); + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); string aad = "foobar"; string message = "123456789012345678901234567890123456"; AuthorizationSet begin_params(client_params()); diff --git a/android_keymaster_test_utils.cpp b/android_keymaster_test_utils.cpp index 36d856e..dacc413 100644 --- a/android_keymaster_test_utils.cpp +++ b/android_keymaster_test_utils.cpp @@ -383,12 +383,10 @@ void Keymaster1Test::SignMessage(const string& message, string* signature, EXPECT_GT(signature->size(), 0U); } -void Keymaster1Test::MacMessage(const string& message, string* signature, keymaster_digest_t digest, - size_t mac_length) { +void Keymaster1Test::MacMessage(const string& message, string* signature, size_t mac_length) { SCOPED_TRACE("SignMessage"); AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_))); input_params.push_back(TAG_MAC_LENGTH, mac_length); - input_params.push_back(TAG_DIGEST, digest); AuthorizationSet update_params; AuthorizationSet output_params; *signature = @@ -419,6 +417,11 @@ void Keymaster1Test::VerifyMessage(const string& message, const string& signatur &output_params); } +void Keymaster1Test::VerifyMac(const string& message, const string& signature) { + SCOPED_TRACE("VerifyMac"); + ProcessMessage(KM_PURPOSE_VERIFY, message, signature); +} + string Keymaster1Test::EncryptMessage(const string& message, keymaster_padding_t padding, string* generated_nonce) { SCOPED_TRACE("EncryptMessage"); @@ -577,11 +580,13 @@ keymaster_error_t Keymaster1Test::ExportKey(keymaster_key_format_t format, strin void Keymaster1Test::CheckHmacTestVector(string key, string message, keymaster_digest_t digest, string expected_mac) { - ASSERT_EQ(KM_ERROR_OK, - ImportKey(AuthorizationSetBuilder().HmacKey(key.size() * 8).Digest(digest), - KM_KEY_FORMAT_RAW, key)); + ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() + .HmacKey(key.size() * 8) + .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8) + .Digest(digest), + KM_KEY_FORMAT_RAW, key)); string signature; - MacMessage(message, &signature, digest, expected_mac.size() * 8); + MacMessage(message, &signature, expected_mac.size() * 8); EXPECT_EQ(expected_mac, signature) << "Test vector didn't match for digest " << (int)digest; } diff --git a/android_keymaster_test_utils.h b/android_keymaster_test_utils.h index c32460e..3d9e26a 100644 --- a/android_keymaster_test_utils.h +++ b/android_keymaster_test_utils.h @@ -221,13 +221,13 @@ class Keymaster1Test : public testing::TestWithParam<InstanceCreatorPtr> { void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest); void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest, keymaster_padding_t padding); - void MacMessage(const std::string& message, std::string* signature, keymaster_digest_t digest, - size_t mac_length); + void MacMessage(const std::string& message, std::string* signature, size_t mac_length); void VerifyMessage(const std::string& message, const std::string& signature, keymaster_digest_t digest); void VerifyMessage(const std::string& message, const std::string& signature, keymaster_digest_t digest, keymaster_padding_t padding); + void VerifyMac(const std::string& message, const std::string& signature); std::string EncryptMessage(const std::string& message, keymaster_padding_t padding, std::string* generated_nonce = NULL); diff --git a/ec_keymaster0_key.cpp b/ec_keymaster0_key.cpp index 08e4434..8cea462 100644 --- a/ec_keymaster0_key.cpp +++ b/ec_keymaster0_key.cpp @@ -58,8 +58,9 @@ keymaster_error_t EcdsaKeymaster0KeyFactory::GenerateKey(const AuthorizationSet& // context_->CreateKeyBlob doesn't put them in sw_enforced. hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC); hw_enforced->push_back(TAG_KEY_SIZE, key_size); + hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN); - return context_->CreateKeyBlob(key_description, KM_ORIGIN_GENERATED, key_material, key_blob, + return context_->CreateKeyBlob(key_description, KM_ORIGIN_UNKNOWN, key_material, key_blob, hw_enforced, sw_enforced); } @@ -89,8 +90,9 @@ keymaster_error_t EcdsaKeymaster0KeyFactory::ImportKey( // context_->CreateKeyBlob doesn't put them in sw_enforced. hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC); hw_enforced->push_back(TAG_KEY_SIZE, key_size); + hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN); - return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, imported_hw_key, + return context_->CreateKeyBlob(authorizations, KM_ORIGIN_UNKNOWN, imported_hw_key, output_key_blob, hw_enforced, sw_enforced); } diff --git a/hmac_key.cpp b/hmac_key.cpp index 2e814a6..91455e3 100644 --- a/hmac_key.cpp +++ b/hmac_key.cpp @@ -46,6 +46,13 @@ keymaster_error_t HmacKeyFactory::LoadKey(const KeymasterKeyBlob& key_material, if (!key) return KM_ERROR_OUTPUT_PARAMETER_NULL; + uint32_t min_mac_length; + if (!hw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length) && + !sw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length)) { + LOG_E("HMAC key must have KM_TAG_MIN_MAC_LENGTH", 0); + return KM_ERROR_INVALID_KEY_BLOB; + } + keymaster_error_t error; key->reset(new (std::nothrow) HmacKey(key_material, hw_enforced, sw_enforced, &error)); if (!key->get()) @@ -53,4 +60,54 @@ keymaster_error_t HmacKeyFactory::LoadKey(const KeymasterKeyBlob& key_material, return error; } +keymaster_error_t HmacKeyFactory::validate_algorithm_specific_new_key_params( + const AuthorizationSet& key_description) const { + uint32_t min_mac_length_bits; + if (!key_description.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length_bits)) + return KM_ERROR_MISSING_MIN_MAC_LENGTH; + + keymaster_digest_t digest; + if (!key_description.GetTagValue(TAG_DIGEST, &digest)) { + LOG_E("%d digests specified for HMAC key", key_description.GetTagCount(TAG_DIGEST)); + return KM_ERROR_UNSUPPORTED_DIGEST; + } + + size_t hash_size_bits = 0; + switch (digest) { + case KM_DIGEST_NONE: + return KM_ERROR_UNSUPPORTED_DIGEST; + case KM_DIGEST_MD5: + hash_size_bits = 128; + break; + case KM_DIGEST_SHA1: + hash_size_bits = 160; + break; + case KM_DIGEST_SHA_2_224: + hash_size_bits = 224; + break; + case KM_DIGEST_SHA_2_256: + hash_size_bits = 256; + break; + case KM_DIGEST_SHA_2_384: + hash_size_bits = 384; + break; + case KM_DIGEST_SHA_2_512: + hash_size_bits = 512; + break; + }; + + if (hash_size_bits == 0) { + // digest was not matched + return KM_ERROR_UNSUPPORTED_DIGEST; + } + + if (min_mac_length_bits % 8 != 0 || min_mac_length_bits > hash_size_bits) + return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH; + + if (min_mac_length_bits < kMinHmacLengthBits) + return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH; + + return KM_ERROR_OK; +} + } // namespace keymaster @@ -21,6 +21,8 @@ namespace keymaster { +const size_t kMinHmacLengthBits = 64; + class HmacKeyFactory : public SymmetricKeyFactory { public: HmacKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {} @@ -37,6 +39,8 @@ class HmacKeyFactory : public SymmetricKeyFactory { return key_size_bits > 0 && key_size_bits % 8 == 00 && key_size_bits <= 2048 /* Some RFC test cases require >1024-bit keys */; } + keymaster_error_t validate_algorithm_specific_new_key_params( + const AuthorizationSet& key_description) const override; }; class HmacKey : public SymmetricKey { diff --git a/hmac_operation.cpp b/hmac_operation.cpp index b1437c4..6b3117e 100644 --- a/hmac_operation.cpp +++ b/hmac_operation.cpp @@ -21,8 +21,8 @@ #include <openssl/evp.h> #include <openssl/hmac.h> +#include "hmac_key.h" #include "openssl_err.h" -#include "symmetric_key.h" #if defined(OPENSSL_IS_BORINGSSL) #include <openssl/mem.h> @@ -36,22 +36,39 @@ namespace keymaster { Operation* HmacOperationFactory::CreateOperation(const Key& key, const AuthorizationSet& begin_params, keymaster_error_t* error) { - uint32_t tag_length = 0; - begin_params.GetTagValue(TAG_MAC_LENGTH, &tag_length); - if (tag_length % 8 != 0) { - LOG_E("MAC length %d nod a multiple of 8 bits", tag_length); - *error = KM_ERROR_UNSUPPORTED_MAC_LENGTH; + uint32_t min_mac_length_bits; + if (!key.authorizations().GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length_bits)) { + LOG_E("HMAC key must have KM_TAG_MIN_MAC_LENGTH", 0); + *error = KM_ERROR_INVALID_KEY_BLOB; return nullptr; } + uint32_t mac_length_bits = UINT32_MAX; + if (begin_params.GetTagValue(TAG_MAC_LENGTH, &mac_length_bits)) { + if (purpose() == KM_PURPOSE_VERIFY) { + LOG_E("MAC length may not be specified for verify", 0); + *error = KM_ERROR_INVALID_ARGUMENT; + return nullptr; + } + } else { + if (purpose() == KM_PURPOSE_SIGN) { + *error = KM_ERROR_MISSING_MAC_LENGTH; + return nullptr; + } + } + keymaster_digest_t digest; - if (!GetAndValidateDigest(begin_params, key, &digest, error)) + if (!key.authorizations().GetTagValue(TAG_DIGEST, &digest)) { + LOG_E("%d digests found in HMAC key authorizations; must be exactly 1", + begin_params.GetTagCount(TAG_DIGEST)); + *error = KM_ERROR_INVALID_KEY_BLOB; return nullptr; + } const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key); - UniquePtr<HmacOperation> op( - new (std::nothrow) HmacOperation(purpose(), symmetric_key->key_data(), - symmetric_key->key_data_size(), digest, tag_length / 8)); + UniquePtr<HmacOperation> op(new (std::nothrow) HmacOperation( + purpose(), symmetric_key->key_data(), symmetric_key->key_data_size(), digest, + mac_length_bits / 8, min_mac_length_bits / 8)); if (!op.get()) *error = KM_ERROR_MEMORY_ALLOCATION_FAILED; else @@ -72,8 +89,10 @@ const keymaster_digest_t* HmacOperationFactory::SupportedDigests(size_t* digest_ } HmacOperation::HmacOperation(keymaster_purpose_t purpose, const uint8_t* key_data, - size_t key_data_size, keymaster_digest_t digest, size_t tag_length) - : Operation(purpose), error_(KM_ERROR_OK), tag_length_(tag_length) { + size_t key_data_size, keymaster_digest_t digest, size_t mac_length, + size_t min_mac_length) + : Operation(purpose), error_(KM_ERROR_OK), mac_length_(mac_length), + min_mac_length_(min_mac_length) { // Initialize CTX first, so dtor won't crash even if we error out later. HMAC_CTX_init(&ctx_); @@ -105,6 +124,17 @@ HmacOperation::HmacOperation(keymaster_purpose_t purpose, const uint8_t* key_dat return; } + if (purpose == KM_PURPOSE_SIGN) { + if (mac_length > EVP_MD_size(md) || mac_length < kMinHmacLengthBits / 8) { + error_ = KM_ERROR_UNSUPPORTED_MAC_LENGTH; + return; + } + if (mac_length < min_mac_length) { + error_ = KM_ERROR_INVALID_MAC_LENGTH; + return; + } + } + HMAC_Init_ex(&ctx_, key_data, key_data_size, md, NULL /* engine */); } @@ -140,17 +170,21 @@ keymaster_error_t HmacOperation::Finish(const AuthorizationSet& /* additional_pa switch (purpose()) { case KM_PURPOSE_SIGN: - if (tag_length_ > digest_len) + if (mac_length_ > digest_len) return KM_ERROR_UNSUPPORTED_MAC_LENGTH; - if (!output->reserve(tag_length_) || !output->write(digest, tag_length_)) + if (!output->reserve(mac_length_) || !output->write(digest, mac_length_)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; return KM_ERROR_OK; - case KM_PURPOSE_VERIFY: - if (signature.available_read() > digest_len) - return KM_ERROR_INVALID_INPUT_LENGTH; - if (CRYPTO_memcmp(signature.peek_read(), digest, signature.available_read()) != 0) + case KM_PURPOSE_VERIFY: { + size_t siglen = signature.available_read(); + if (siglen > digest_len || siglen < kMinHmacLengthBits / 8) + return KM_ERROR_UNSUPPORTED_MAC_LENGTH; + if (siglen < min_mac_length_) + return KM_ERROR_INVALID_MAC_LENGTH; + if (CRYPTO_memcmp(signature.peek_read(), digest, siglen) != 0) return KM_ERROR_VERIFICATION_FAILED; return KM_ERROR_OK; + } default: return KM_ERROR_UNSUPPORTED_PURPOSE; } diff --git a/hmac_operation.h b/hmac_operation.h index ad59a16..9c2d59b 100644 --- a/hmac_operation.h +++ b/hmac_operation.h @@ -26,7 +26,7 @@ namespace keymaster { class HmacOperation : public Operation { public: HmacOperation(keymaster_purpose_t purpose, const uint8_t* key_data, size_t key_data_size, - keymaster_digest_t digest, size_t tag_length); + keymaster_digest_t digest, size_t mac_length, size_t min_mac_length); ~HmacOperation(); virtual keymaster_error_t Begin(const AuthorizationSet& input_params, @@ -44,7 +44,8 @@ class HmacOperation : public Operation { private: HMAC_CTX ctx_; keymaster_error_t error_; - size_t tag_length_; + const size_t mac_length_; + const size_t min_mac_length_; }; /** diff --git a/include/keymaster/keymaster_tags.h b/include/keymaster/keymaster_tags.h index e62c2cc..21d6966 100644 --- a/include/keymaster/keymaster_tags.h +++ b/include/keymaster/keymaster_tags.h @@ -162,6 +162,7 @@ DEFINE_KEYMASTER_TAG(KM_INVALID, TAG_INVALID); DEFINE_KEYMASTER_TAG(KM_UINT, TAG_KEY_SIZE); DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAC_LENGTH); DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_CALLER_NONCE); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_MAC_LENGTH); DEFINE_KEYMASTER_TAG(KM_ULONG, TAG_RSA_PUBLIC_EXPONENT); DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ACTIVE_DATETIME); DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ORIGINATION_EXPIRE_DATETIME); diff --git a/keymaster_enforcement.cpp b/keymaster_enforcement.cpp index 9752438..4d0aaef 100644 --- a/keymaster_enforcement.cpp +++ b/keymaster_enforcement.cpp @@ -286,7 +286,7 @@ keymaster_error_t KeymasterEnforcement::AuthorizeBegin(const keymaster_purpose_t case KM_TAG_APPLICATION_DATA: return KM_ERROR_INVALID_KEY_BLOB; - /* Tags used for cryptographic parameters. */ + /* Tags used for cryptographic parameters in keygen. Nothing to enforce. */ case KM_TAG_PURPOSE: case KM_TAG_ALGORITHM: case KM_TAG_KEY_SIZE: @@ -295,6 +295,7 @@ keymaster_error_t KeymasterEnforcement::AuthorizeBegin(const keymaster_purpose_t case KM_TAG_MAC_LENGTH: case KM_TAG_PADDING: case KM_TAG_NONCE: + case KM_TAG_MIN_MAC_LENGTH: /* Tags not used for operations. */ case KM_TAG_BLOB_USAGE_REQUIREMENTS: diff --git a/rsa_keymaster0_key.cpp b/rsa_keymaster0_key.cpp index f882f94..3afd024 100644 --- a/rsa_keymaster0_key.cpp +++ b/rsa_keymaster0_key.cpp @@ -67,8 +67,9 @@ keymaster_error_t RsaKeymaster0KeyFactory::GenerateKey(const AuthorizationSet& k hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA); hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent); hw_enforced->push_back(TAG_KEY_SIZE, key_size); + hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN); - return context_->CreateKeyBlob(key_description, KM_ORIGIN_GENERATED, key_material, key_blob, + return context_->CreateKeyBlob(key_description, KM_ORIGIN_UNKNOWN, key_material, key_blob, hw_enforced, sw_enforced); } @@ -101,8 +102,9 @@ keymaster_error_t RsaKeymaster0KeyFactory::ImportKey( hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA); hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent); hw_enforced->push_back(TAG_KEY_SIZE, key_size); + hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN); - return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, imported_hw_key, + return context_->CreateKeyBlob(authorizations, KM_ORIGIN_UNKNOWN, imported_hw_key, output_key_blob, hw_enforced, sw_enforced); } diff --git a/symmetric_key.cpp b/symmetric_key.cpp index 3d8424c..1d51e3a 100644 --- a/symmetric_key.cpp +++ b/symmetric_key.cpp @@ -43,12 +43,16 @@ keymaster_error_t SymmetricKeyFactory::GenerateKey(const AuthorizationSet& key_d !key_size_supported(key_size_bits)) return KM_ERROR_UNSUPPORTED_KEY_SIZE; + keymaster_error_t error = validate_algorithm_specific_new_key_params(key_description); + if (error != KM_ERROR_OK) + return error; + size_t key_data_size = key_size_bits / 8; KeymasterKeyBlob key_material(key_data_size); if (!key_material.key_material) return KM_ERROR_MEMORY_ALLOCATION_FAILED; - keymaster_error_t error = context_->GenerateRandom(key_material.writable_data(), key_data_size); + error = context_->GenerateRandom(key_material.writable_data(), key_data_size); if (error != KM_ERROR_OK) { LOG_E("Error generating %d bit symmetric key", key_size_bits); return error; @@ -76,6 +80,10 @@ keymaster_error_t SymmetricKeyFactory::ImportKey(const AuthorizationSet& key_des authorizations.push_back(TAG_KEY_SIZE, key_size_bits); } + keymaster_error_t error = validate_algorithm_specific_new_key_params(key_description); + if (error != KM_ERROR_OK) + return error; + if (!key_size_supported(key_size_bits)) return KM_ERROR_UNSUPPORTED_KEY_SIZE; diff --git a/symmetric_key.h b/symmetric_key.h index fd61b37..47f3329 100644 --- a/symmetric_key.h +++ b/symmetric_key.h @@ -45,6 +45,8 @@ class SymmetricKeyFactory : public KeyFactory { private: virtual bool key_size_supported(size_t key_size_bits) const = 0; + virtual keymaster_error_t + validate_algorithm_specific_new_key_params(const AuthorizationSet& key_description) const = 0; const keymaster_key_format_t* NoFormats(size_t* format_count) const { *format_count = 0; |