From 8b7455abb46f3c1bd6637f3be5a7c51ee929b584 Mon Sep 17 00:00:00 2001 From: Chirag Pathak Date: Mon, 21 Dec 2020 18:42:52 -0500 Subject: [PATCH] Add support and VTS test for RSA OAEP MGF1. Test: atest VtsAidlKeyMintV1_0TargetTest Bug: 160968519 Change-Id: I7093b26217b69ea36b4be8837b42cb9446887685 --- .../hardware/security/keymint/ErrorCode.aidl | 2 + .../hardware/security/keymint/Tag.aidl | 1 + .../hardware/security/keymint/ErrorCode.aidl | 2 + .../hardware/security/keymint/Tag.aidl | 16 +++ .../aidl/vts/functional/KeyMintTest.cpp | 101 ++++++++++++++++++ .../keymint/support/authorization_set.cpp | 8 ++ .../keymint_support/authorization_set.h | 1 + .../include/keymint_support/keymint_tags.h | 2 + 8 files changed, 133 insertions(+) diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl index cdcb08d5c7..8694b32aa9 100644 --- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl +++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl @@ -94,6 +94,8 @@ enum ErrorCode { ATTESTATION_IDS_NOT_PROVISIONED = -75, INVALID_OPERATION = -76, STORAGE_KEY_UNSUPPORTED = -77, + INCOMPATIBLE_MGF_DIGEST = -78, + UNSUPPORTED_MGF_DIGEST = -79, UNIMPLEMENTED = -100, VERSION_MISMATCH = -101, UNKNOWN_ERROR = -1000, diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl index 38eb6e693c..814405c8c4 100644 --- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl +++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl @@ -30,6 +30,7 @@ enum Tag { EC_CURVE = 268435466, RSA_PUBLIC_EXPONENT = 1342177480, INCLUDE_UNIQUE_ID = 1879048394, + RSA_OAEP_MGF_DIGEST = 536871115, BLOB_USAGE_REQUIREMENTS = 268435757, BOOTLOADER_ONLY = 1879048494, ROLLBACK_RESISTANCE = 1879048495, diff --git a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl index fb24ad1baa..b20601d4a1 100644 --- a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl +++ b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl @@ -99,6 +99,8 @@ enum ErrorCode { ATTESTATION_IDS_NOT_PROVISIONED = -75, INVALID_OPERATION = -76, STORAGE_KEY_UNSUPPORTED = -77, + INCOMPATIBLE_MGF_DIGEST = -78, + UNSUPPORTED_MGF_DIGEST = -79, UNIMPLEMENTED = -100, VERSION_MISMATCH = -101, diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl index 3bc3f16d89..9f41b4e957 100644 --- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl +++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl @@ -187,6 +187,22 @@ enum Tag { */ INCLUDE_UNIQUE_ID = (7 << 28) /* TagType:BOOL */ | 202, + /** + * Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with + * RSA encryption/decryption with OAEP padding. If the key characteristics supports OAEP + * and this tag is absent then SHA1 digest is selected by default for MGF1. + * + * This tag is repeatable for key generation/import. If this tag is present in the key + * characteristics with one or more values from @4.0::Digest, then for RSA cipher + * operations with OAEP Padding, the caller must specify a digest in the additionalParams + * argument of begin operation. If this tag is missing or the specified digest is not in + * the digests associated with the key then begin operation must fail with + * ErrorCode::INCOMPATIBLE_MGF_DIGEST. + * + * Must be hardware-enforced. + */ + RSA_OAEP_MGF_DIGEST = (2 << 28) /* TagType:ENUM_REP */ | 203, + /** * TODO(seleneh) this tag needs to be deleted from all codes. * diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp index 30601538dd..eeb74915dc 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -2055,6 +2055,107 @@ TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) { EXPECT_EQ(0U, result.size()); } +/* + * EncryptionOperationsTest.RsaOaepWithMGFDigestSuccess + * + * Verifies that RSA-OAEP encryption operations work, with all SHA 256 digests and all type of MGF1 + * digests. + */ +TEST_P(EncryptionOperationsTest, RsaOaepWithMGFDigestSuccess) { + auto digests = ValidDigests(false /* withNone */, true /* withMD5 */); + + size_t key_size = 2048; // Need largish key for SHA-512 test. + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .OaepMGFDigest(digests) + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(key_size, 65537) + .Padding(PaddingMode::RSA_OAEP) + .Digest(Digest::SHA_2_256))); + + string message = "Hello"; + + for (auto digest : digests) { + auto params = AuthorizationSetBuilder() + .Authorization(TAG_RSA_OAEP_MGF_DIGEST, digest) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP); + string ciphertext1 = EncryptMessage(message, params); + if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl; + EXPECT_EQ(key_size / 8, ciphertext1.size()); + + string ciphertext2 = EncryptMessage(message, params); + 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 = random() % ciphertext1.size(); + char corrupt_byte; + do { + corrupt_byte = static_cast(random() % 256); + } while (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()); + } +} + +/* + * EncryptionOperationsTest.RsaOaepWithMGFIncompatibleDigest + * + * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate + * 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))); + string message = "Hello World!"; + + auto params = AuthorizationSetBuilder() + .Padding(PaddingMode::RSA_OAEP) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA_2_224); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_MGF_DIGEST, Begin(KeyPurpose::ENCRYPT, params)); +} + +/* + * EncryptionOperationsTest.RsaOaepWithMGFUnsupportedDigest + * + * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate + * 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))); + string message = "Hello World!"; + + auto params = AuthorizationSetBuilder() + .Padding(PaddingMode::RSA_OAEP) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::NONE); + EXPECT_EQ(ErrorCode::UNSUPPORTED_MGF_DIGEST, Begin(KeyPurpose::ENCRYPT, params)); +} + /* * EncryptionOperationsTest.RsaPkcs1Success * diff --git a/security/keymint/support/authorization_set.cpp b/security/keymint/support/authorization_set.cpp index f98851cfa2..3d44dff27c 100644 --- a/security/keymint/support/authorization_set.cpp +++ b/security/keymint/support/authorization_set.cpp @@ -227,6 +227,14 @@ AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(std::vector& digests) { + for (auto digest : digests) { + push_back(TAG_RSA_OAEP_MGF_DIGEST, digest); + } + return *this; +} + AuthorizationSetBuilder& AuthorizationSetBuilder::Padding( std::initializer_list paddingModes) { for (auto paddingMode : paddingModes) { diff --git a/security/keymint/support/include/keymint_support/authorization_set.h b/security/keymint/support/include/keymint_support/authorization_set.h index 4ff170526a..596bb89c39 100644 --- a/security/keymint/support/include/keymint_support/authorization_set.h +++ b/security/keymint/support/include/keymint_support/authorization_set.h @@ -290,6 +290,7 @@ class AuthorizationSetBuilder : public AuthorizationSet { AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength); AuthorizationSetBuilder& BlockMode(std::initializer_list blockModes); + AuthorizationSetBuilder& OaepMGFDigest(const std::vector& digests); AuthorizationSetBuilder& Digest(std::vector digests); AuthorizationSetBuilder& Padding(std::initializer_list paddings); diff --git a/security/keymint/support/include/keymint_support/keymint_tags.h b/security/keymint/support/include/keymint_support/keymint_tags.h index d932b40b49..76aecb71b5 100644 --- a/security/keymint/support/include/keymint_support/keymint_tags.h +++ b/security/keymint/support/include/keymint_support/keymint_tags.h @@ -124,6 +124,7 @@ DECLARE_TYPED_TAG(USER_AUTH_TYPE); DECLARE_TYPED_TAG(USER_ID); DECLARE_TYPED_TAG(USER_SECURE_ID); DECLARE_TYPED_TAG(VENDOR_PATCHLEVEL); +DECLARE_TYPED_TAG(RSA_OAEP_MGF_DIGEST); #undef DECLARE_TYPED_TAG @@ -239,6 +240,7 @@ MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, paddingMode) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, keyPurpose) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, hardwareAuthenticatorType) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, securityLevel) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_RSA_OAEP_MGF_DIGEST, digest) #undef MAKE_TAG_ENUM_VALUE_ACCESSOR