Validating key characteristics of generated/imported keys.
Updated VTS tests to verify mgf-digests in key characteristics of
RSA-OAEP keys. Added new tests to import RSA-OAEP keys with
mgf-digests and verified imported key characteristics.
Bug: 279721313
Test: atest VtsAidlKeyMintTargetTest
Change-Id: I06474a85c9e77fded264031ff5636f2c35bee6b4
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index c25c9ac..214e563 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -82,7 +82,7 @@
string imei = ::android::base::Trim(out[0]);
if (imei.compare("null") == 0) {
- LOG(ERROR) << "Error in getting IMEI from Telephony service: value is null. Cmd: " << cmd;
+ LOG(WARNING) << "Failed to get IMEI from Telephony service: value is null. Cmd: " << cmd;
return "";
}
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index b2fd08e..56a1d58 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -2042,6 +2042,27 @@
return retval;
}
+void assert_mgf_digests_present_in_key_characteristics(
+ const vector<KeyCharacteristics>& key_characteristics,
+ std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests) {
+ AuthorizationSet auths;
+ for (auto& entry : key_characteristics) {
+ auths.push_back(AuthorizationSet(entry.authorizations));
+ }
+ for (auto digest : expected_mgf_digests) {
+ ASSERT_TRUE(auths.Contains(TAG_RSA_OAEP_MGF_DIGEST, digest));
+ }
+}
+
+bool is_mgf_digest_present(const vector<KeyCharacteristics>& key_characteristics,
+ android::hardware::security::keymint::Digest expected_mgf_digest) {
+ AuthorizationSet auths;
+ for (auto& entry : key_characteristics) {
+ auths.push_back(AuthorizationSet(entry.authorizations));
+ }
+ return auths.Contains(TAG_RSA_OAEP_MGF_DIGEST, expected_mgf_digest);
+}
+
namespace {
void check_cose_key(const vector<uint8_t>& data, bool testMode) {
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index aa3069a..780cd3e 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -429,6 +429,11 @@
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
ASN1_OCTET_STRING* get_attestation_record(X509* certificate);
vector<uint8_t> make_name_from_str(const string& name);
+void assert_mgf_digests_present_in_key_characteristics(
+ const vector<KeyCharacteristics>& key_characteristics,
+ std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests);
+bool is_mgf_digest_present(const vector<KeyCharacteristics>& key_characteristics,
+ android::hardware::security::keymint::Digest expected_mgf_digest);
void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
vector<uint8_t>* payload_value);
void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index c534a37..667c87d 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -3430,7 +3430,6 @@
* Verifies ECDSA signature/verification for all digests and required curves.
*/
TEST_P(SigningOperationsTest, EcdsaAllDigestsAndCurves) {
-
string message = "1234567890";
string corrupt_message = "2234567890";
for (auto curve : ValidCurves()) {
@@ -4727,6 +4726,102 @@
}
}
+/*
+ * ImportKeyTest.RsaOaepMGFDigestSuccess
+ *
+ * Include MGF-Digest explicitly in import key authorization list.
+ * Test should import RSA key with OAEP padding and mgf-digests and verify that imported key
+ * should have the correct characteristics.
+ */
+TEST_P(ImportKeyTest, RsaOaepMGFDigestSuccess) {
+ auto mgf_digests = ValidDigests(false /* withNone */, true /* withMD5 */);
+ size_t key_size = 2048;
+
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .OaepMGFDigest(mgf_digests)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(key_size, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, rsa_2048_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+ CheckCryptoParam(TAG_KEY_SIZE, key_size);
+ CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_OAEP);
+ CheckOrigin();
+
+ // Make sure explicitly specified mgf-digests exist in key characteristics.
+ assert_mgf_digests_present_in_key_characteristics(key_characteristics_, mgf_digests);
+
+ string message = "Hello";
+
+ for (auto digest : mgf_digests) {
+ SCOPED_TRACE(testing::Message() << "digest-" << digest);
+ auto params = AuthorizationSetBuilder()
+ .Authorization(TAG_RSA_OAEP_MGF_DIGEST, digest)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP);
+ string ciphertext1 = LocalRsaEncryptMessage(message, params);
+ if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+ EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+ string ciphertext2 = LocalRsaEncryptMessage(message, params);
+ if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+ EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+ // OAEP randomizes padding so every result should be different (with astronomically high
+ // probability).
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ string plaintext1 = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext1) << "RSA-OAEP failed with digest " << digest;
+ string plaintext2 = DecryptMessage(ciphertext2, params);
+ EXPECT_EQ(message, plaintext2) << "RSA-OAEP failed with digest " << digest;
+
+ // Decrypting corrupted ciphertext should fail.
+ size_t offset_to_corrupt = ciphertext1.size() - 1;
+ char corrupt_byte = ~ciphertext1[offset_to_corrupt];
+ ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string result;
+ EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_EQ(0U, result.size());
+ }
+}
+
+/*
+ * ImportKeyTest.RsaOaepMGFDigestDefaultSuccess
+ *
+ * Don't specify MGF-Digest explicitly in import key authorization list.
+ * Test should import RSA key with OAEP padding and default mgf-digest (SHA1) and
+ * verify that imported key should have the correct characteristics. Default
+ * mgf-digest shouldn't be included in key charecteristics.
+ */
+TEST_P(ImportKeyTest, RsaOaepMGFDigestDefaultSuccess) {
+ size_t key_size = 2048;
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(key_size, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_OAEP)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, rsa_2048_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+ CheckCryptoParam(TAG_KEY_SIZE, key_size);
+ CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_OAEP);
+ CheckOrigin();
+
+ // Make sure default mgf-digest (SHA1) is not included in Key characteristics.
+ ASSERT_FALSE(is_mgf_digest_present(key_characteristics_, Digest::SHA1));
+}
+
INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest);
auto wrapped_key = hex2str(
@@ -5152,16 +5247,19 @@
*/
TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
auto digests = ValidDigests(false /* withNone */, true /* withMD5 */);
+ auto mgf_digest = Digest::SHA1;
size_t key_size = 2048; // Need largish key for SHA-512 test.
- ASSERT_EQ(ErrorCode::OK,
- GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaEncryptionKey(key_size, 65537)
- .Padding(PaddingMode::RSA_OAEP)
- .Digest(digests)
- .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA1)
- .SetDefaultValidity()));
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(key_size, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(digests)
+ .Authorization(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest)
+ .SetDefaultValidity()));
+
+ // Make sure explicitly specified mgf-digest exist in key characteristics.
+ ASSERT_TRUE(is_mgf_digest_present(key_characteristics_, mgf_digest));
string message = "Hello";
@@ -5341,6 +5439,9 @@
.Digest(Digest::SHA_2_256)
.SetDefaultValidity()));
+ // Make sure default mgf-digest (SHA1) is not included in Key characteristics.
+ ASSERT_FALSE(is_mgf_digest_present(key_characteristics_, Digest::SHA1));
+
// Do local RSA encryption using the default MGF digest of SHA-1.
string message = "Hello";
auto params =
@@ -5375,14 +5476,19 @@
*/
TEST_P(EncryptionOperationsTest, RsaOaepMGFDigestDefaultFail) {
size_t key_size = 2048;
- ASSERT_EQ(ErrorCode::OK,
- GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA_2_256)
- .RsaEncryptionKey(key_size, 65537)
- .Padding(PaddingMode::RSA_OAEP)
- .Digest(Digest::SHA_2_256)
- .SetDefaultValidity()));
+ auto mgf_digest = Digest::SHA_2_256;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest)
+ .RsaEncryptionKey(key_size, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256)
+ .SetDefaultValidity()));
+
+ // Make sure explicitly specified mgf-digest exist in key characteristics.
+ ASSERT_TRUE(is_mgf_digest_present(key_characteristics_, mgf_digest));
+ // Make sure default mgf-digest is not included in key characteristics.
+ ASSERT_FALSE(is_mgf_digest_present(key_characteristics_, Digest::SHA1));
// Do local RSA encryption using the default MGF digest of SHA-1.
string message = "Hello";
@@ -5406,14 +5512,17 @@
* with incompatible MGF digest.
*/
TEST_P(EncryptionOperationsTest, RsaOaepWithMGFIncompatibleDigest) {
- ASSERT_EQ(ErrorCode::OK,
- GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA_2_256)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaEncryptionKey(2048, 65537)
- .Padding(PaddingMode::RSA_OAEP)
- .Digest(Digest::SHA_2_256)
- .SetDefaultValidity()));
+ auto mgf_digest = Digest::SHA_2_256;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256)
+ .SetDefaultValidity()));
+ // Make sure explicitly specified mgf-digest exist in key characteristics.
+ ASSERT_TRUE(is_mgf_digest_present(key_characteristics_, mgf_digest));
+
string message = "Hello World!";
auto params = AuthorizationSetBuilder()
@@ -5430,14 +5539,17 @@
* with unsupported MGF digest.
*/
TEST_P(EncryptionOperationsTest, RsaOaepWithMGFUnsupportedDigest) {
- ASSERT_EQ(ErrorCode::OK,
- GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA_2_256)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaEncryptionKey(2048, 65537)
- .Padding(PaddingMode::RSA_OAEP)
- .Digest(Digest::SHA_2_256)
- .SetDefaultValidity()));
+ auto mgf_digest = Digest::SHA_2_256;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(2048, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256)
+ .SetDefaultValidity()));
+ // Make sure explicitly specified mgf-digest exist in key characteristics.
+ ASSERT_TRUE(is_mgf_digest_present(key_characteristics_, mgf_digest));
+
string message = "Hello World!";
auto params = AuthorizationSetBuilder()