summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--aes_key.cpp35
-rw-r--r--aes_key.h5
-rw-r--r--aes_operation.cpp41
-rw-r--r--android_keymaster_test.cpp376
-rw-r--r--android_keymaster_test_utils.cpp19
-rw-r--r--android_keymaster_test_utils.h4
-rw-r--r--ec_keymaster0_key.cpp6
-rw-r--r--hmac_key.cpp57
-rw-r--r--hmac_key.h4
-rw-r--r--hmac_operation.cpp70
-rw-r--r--hmac_operation.h5
-rw-r--r--include/keymaster/keymaster_tags.h1
-rw-r--r--keymaster_enforcement.cpp3
-rw-r--r--rsa_keymaster0_key.cpp6
-rw-r--r--symmetric_key.cpp10
-rw-r--r--symmetric_key.h2
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
diff --git a/aes_key.h b/aes_key.h
index dfc9578..9c58647 100644
--- a/aes_key.h
+++ b/aes_key.h
@@ -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
diff --git a/hmac_key.h b/hmac_key.h
index eaae54e..c877a12 100644
--- a/hmac_key.h
+++ b/hmac_key.h
@@ -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;