KeyMint VTS: local RSA encryption

Change RSA encryption (with public key) so it happens locally in the
test, rather than by invoking an ENCRYPT operation against KeyMint.

 - Specify MGF1 digest for OAEP mode as (now) required by AIDL spec.
 - Drop tests for too-long encryption inputs.
 - Adjust test comments to reflect decryption-only nature.
 - Change parameter checking tests to do so on DECRYPT rather than ENCRYPT.

Test: VtsAidlKeyMintTargetTest
Change-Id: I10c4beea28387eecfd0bc7c5dfd59a1b66fec21e
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 1a05ac8..8c4e0c3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -699,6 +699,101 @@
     }
 }
 
+string KeyMintAidlTestBase::LocalRsaEncryptMessage(const string& message,
+                                                   const AuthorizationSet& params) {
+    SCOPED_TRACE("LocalRsaEncryptMessage");
+
+    // Retrieve the public key from the leaf certificate.
+    if (cert_chain_.empty()) {
+        ADD_FAILURE() << "No public key available";
+        return "Failure";
+    }
+    X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+    EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
+    RSA_Ptr rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pub_key.get())));
+
+    // Retrieve relevant tags.
+    Digest digest = Digest::NONE;
+    Digest mgf_digest = Digest::NONE;
+    PaddingMode padding = PaddingMode::NONE;
+
+    auto digest_tag = params.GetTagValue(TAG_DIGEST);
+    if (digest_tag.has_value()) digest = digest_tag.value();
+    auto pad_tag = params.GetTagValue(TAG_PADDING);
+    if (pad_tag.has_value()) padding = pad_tag.value();
+    auto mgf_tag = params.GetTagValue(TAG_RSA_OAEP_MGF_DIGEST);
+    if (mgf_tag.has_value()) mgf_digest = mgf_tag.value();
+
+    const EVP_MD* md = openssl_digest(digest);
+    const EVP_MD* mgf_md = openssl_digest(mgf_digest);
+
+    // Set up encryption context.
+    EVP_PKEY_CTX_Ptr ctx(EVP_PKEY_CTX_new(pub_key.get(), /* engine= */ nullptr));
+    if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) {
+        ADD_FAILURE() << "Encryption init failed: " << ERR_peek_last_error();
+        return "Failure";
+    }
+
+    int rc = -1;
+    switch (padding) {
+        case PaddingMode::NONE:
+            rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+            break;
+        case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+            rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING);
+            break;
+        case PaddingMode::RSA_OAEP:
+            rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING);
+            break;
+        default:
+            break;
+    }
+    if (rc <= 0) {
+        ADD_FAILURE() << "Set padding failed: " << ERR_peek_last_error();
+        return "Failure";
+    }
+    if (padding == PaddingMode::RSA_OAEP) {
+        if (!EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), md)) {
+            ADD_FAILURE() << "Set digest failed: " << ERR_peek_last_error();
+            return "Failure";
+        }
+        if (!EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), mgf_md)) {
+            ADD_FAILURE() << "Set MGF digest failed: " << ERR_peek_last_error();
+            return "Failure";
+        }
+    }
+
+    // Determine output size.
+    size_t outlen;
+    if (EVP_PKEY_encrypt(ctx.get(), nullptr /* out */, &outlen,
+                         reinterpret_cast<const uint8_t*>(message.data()), message.size()) <= 0) {
+        ADD_FAILURE() << "Determine output size failed: " << ERR_peek_last_error();
+        return "Failure";
+    }
+
+    // Left-zero-pad the input if necessary.
+    const uint8_t* to_encrypt = reinterpret_cast<const uint8_t*>(message.data());
+    size_t to_encrypt_len = message.size();
+
+    std::unique_ptr<string> zero_padded_message;
+    if (padding == PaddingMode::NONE && to_encrypt_len < outlen) {
+        zero_padded_message.reset(new string(outlen, '\0'));
+        memcpy(zero_padded_message->data() + (outlen - to_encrypt_len), message.data(),
+               message.size());
+        to_encrypt = reinterpret_cast<const uint8_t*>(zero_padded_message->data());
+        to_encrypt_len = outlen;
+    }
+
+    // Do the encryption.
+    string output(outlen, '\0');
+    if (EVP_PKEY_encrypt(ctx.get(), reinterpret_cast<uint8_t*>(output.data()), &outlen, to_encrypt,
+                         to_encrypt_len) <= 0) {
+        ADD_FAILURE() << "Encryption failed: " << ERR_peek_last_error();
+        return "Failure";
+    }
+    return output;
+}
+
 string KeyMintAidlTestBase::EncryptMessage(const vector<uint8_t>& key_blob, const string& message,
                                            const AuthorizationSet& in_params,
                                            AuthorizationSet* out_params) {
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 1a14d47..d8f1bb3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -165,6 +165,7 @@
     void LocalVerifyMessage(const string& message, const string& signature,
                             const AuthorizationSet& params);
 
+    string LocalRsaEncryptMessage(const string& message, const AuthorizationSet& params);
     string EncryptMessage(const vector<uint8_t>& key_blob, const string& message,
                           const AuthorizationSet& in_params, AuthorizationSet* out_params);
     string EncryptMessage(const string& message, const AuthorizationSet& params,
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 2c0c459..7d366f1 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -3627,7 +3627,7 @@
 /*
  * EncryptionOperationsTest.RsaNoPaddingSuccess
  *
- * Verifies that raw RSA encryption works.
+ * Verifies that raw RSA decryption works.
  */
 TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
     for (uint64_t exponent : {3, 65537}) {
@@ -3639,10 +3639,10 @@
 
         string message = string(2048 / 8, 'a');
         auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
-        string ciphertext1 = EncryptMessage(message, params);
+        string ciphertext1 = LocalRsaEncryptMessage(message, params);
         EXPECT_EQ(2048U / 8, ciphertext1.size());
 
-        string ciphertext2 = EncryptMessage(message, params);
+        string ciphertext2 = LocalRsaEncryptMessage(message, params);
         EXPECT_EQ(2048U / 8, ciphertext2.size());
 
         // Unpadded RSA is deterministic
@@ -3655,7 +3655,7 @@
 /*
  * EncryptionOperationsTest.RsaNoPaddingShortMessage
  *
- * Verifies that raw RSA encryption of short messages works.
+ * Verifies that raw RSA decryption of short messages works.
  */
 TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -3667,76 +3667,47 @@
     string message = "1";
     auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
 
-    string ciphertext = EncryptMessage(message, params);
+    string ciphertext = LocalRsaEncryptMessage(message, params);
     EXPECT_EQ(2048U / 8, ciphertext.size());
 
     string expected_plaintext = string(2048U / 8 - 1, 0) + message;
     string plaintext = DecryptMessage(ciphertext, params);
 
     EXPECT_EQ(expected_plaintext, plaintext);
-
-    // Degenerate case, encrypting a numeric 1 yields 0x00..01 as the ciphertext.
-    message = static_cast<char>(1);
-    ciphertext = EncryptMessage(message, params);
-    EXPECT_EQ(2048U / 8, ciphertext.size());
-    EXPECT_EQ(ciphertext, string(2048U / 8 - 1, 0) + message);
 }
 
 /*
- * EncryptionOperationsTest.RsaNoPaddingTooLong
- *
- * Verifies that raw RSA encryption of too-long messages fails in the expected way.
- */
-TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .RsaEncryptionKey(2048, 65537)
-                                                 .Padding(PaddingMode::NONE)
-                                                 .SetDefaultValidity()));
-
-    string message(2048 / 8 + 1, 'a');
-
-    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
-
-    string result;
-    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
-}
-
-/*
- * EncryptionOperationsTest.RsaNoPaddingTooLarge
- *
- * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected
- * way.
- */
-// TODO(seleneh) add RsaNoPaddingTooLarge test back after decided and implemented new
-// version of ExportKey inside generateKey
-
-/*
  * EncryptionOperationsTest.RsaOaepSuccess
  *
- * Verifies that RSA-OAEP encryption operations work, with all digests.
+ * Verifies that RSA-OAEP decryption operations work, with all digests.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
     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()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .RsaEncryptionKey(key_size, 65537)
-                                                 .Padding(PaddingMode::RSA_OAEP)
-                                                 .Digest(digests)
-                                                 .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, Digest::SHA1)
+                                  .SetDefaultValidity()));
 
     string message = "Hello";
 
     for (auto digest : digests) {
-        auto params = AuthorizationSetBuilder().Digest(digest).Padding(PaddingMode::RSA_OAEP);
-        string ciphertext1 = EncryptMessage(message, params);
+        SCOPED_TRACE(testing::Message() << "digest-" << digest);
+
+        auto params = AuthorizationSetBuilder()
+                              .Digest(digest)
+                              .Padding(PaddingMode::RSA_OAEP)
+                              .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA1);
+        string ciphertext1 = LocalRsaEncryptMessage(message, params);
         if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
         EXPECT_EQ(key_size / 8, ciphertext1.size());
 
-        string ciphertext2 = EncryptMessage(message, params);
+        string ciphertext2 = LocalRsaEncryptMessage(message, params);
         EXPECT_EQ(key_size / 8, ciphertext2.size());
 
         // OAEP randomizes padding so every result should be different (with astronomically high
@@ -3766,7 +3737,7 @@
 /*
  * EncryptionOperationsTest.RsaOaepInvalidDigest
  *
- * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
+ * Verifies that RSA-OAEP decryption operations fail in the correct way when asked to operate
  * without a digest.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
@@ -3778,13 +3749,13 @@
                                                  .SetDefaultValidity()));
 
     auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::NONE);
-    EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, Begin(KeyPurpose::ENCRYPT, params));
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, Begin(KeyPurpose::DECRYPT, params));
 }
 
 /*
  * EncryptionOperationsTest.RsaOaepInvalidPadding
  *
- * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
+ * Verifies that RSA-OAEP decryption operations fail in the correct way when asked to operate
  * with a padding value that is only suitable for signing/verifying.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepInvalidPadding) {
@@ -3796,13 +3767,13 @@
                                                  .SetDefaultValidity()));
 
     auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PSS).Digest(Digest::NONE);
-    EXPECT_EQ(ErrorCode::UNSUPPORTED_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_PADDING_MODE, Begin(KeyPurpose::DECRYPT, params));
 }
 
 /*
  * EncryptionOperationsTest.RsaOaepDecryptWithWrongDigest
  *
- * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt
+ * Verifies that RSA-OAEP decryption operations fail in the correct way when asked to decrypt
  * with a different digest than was used to encrypt.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
@@ -3815,7 +3786,7 @@
                                                  .Digest(Digest::SHA_2_224, Digest::SHA_2_256)
                                                  .SetDefaultValidity()));
     string message = "Hello World!";
-    string ciphertext = EncryptMessage(
+    string ciphertext = LocalRsaEncryptMessage(
             message,
             AuthorizationSetBuilder().Digest(Digest::SHA_2_224).Padding(PaddingMode::RSA_OAEP));
 
@@ -3828,34 +3799,9 @@
 }
 
 /*
- * EncryptionOperationsTest.RsaOaepTooLarge
- *
- * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
- * too-large message.
- */
-TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .RsaEncryptionKey(2048, 65537)
-                                                 .Padding(PaddingMode::RSA_OAEP)
-                                                 .Digest(Digest::SHA_2_256)
-                                                 .SetDefaultValidity()));
-    constexpr size_t digest_size = 256 /* SHA_2_256 */ / 8;
-    constexpr size_t oaep_overhead = 2 * digest_size + 2;
-    string message(2048 / 8 - oaep_overhead + 1, 'a');
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder()
-                                                                .Padding(PaddingMode::RSA_OAEP)
-                                                                .Digest(Digest::SHA_2_256)));
-    string result;
-    ErrorCode error = Finish(message, &result);
-    EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
-    EXPECT_EQ(0U, result.size());
-}
-
-/*
  * EncryptionOperationsTest.RsaOaepWithMGFDigestSuccess
  *
- * Verifies that RSA-OAEP encryption operations work, with all SHA 256 digests and all type of MGF1
+ * Verifies that RSA-OAEP decryption operations work, with all SHA 256 digests and all type of MGF1
  * digests.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepWithMGFDigestSuccess) {
@@ -3877,11 +3823,11 @@
                               .Authorization(TAG_RSA_OAEP_MGF_DIGEST, digest)
                               .Digest(Digest::SHA_2_256)
                               .Padding(PaddingMode::RSA_OAEP);
-        string ciphertext1 = EncryptMessage(message, params);
+        string ciphertext1 = LocalRsaEncryptMessage(message, params);
         if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
         EXPECT_EQ(key_size / 8, ciphertext1.size());
 
-        string ciphertext2 = EncryptMessage(message, params);
+        string ciphertext2 = LocalRsaEncryptMessage(message, params);
         EXPECT_EQ(key_size / 8, ciphertext2.size());
 
         // OAEP randomizes padding so every result should be different (with astronomically high
@@ -3911,7 +3857,7 @@
 /*
  * EncryptionOperationsTest.RsaOaepWithMGFIncompatibleDigest
  *
- * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
+ * Verifies that RSA-OAEP decryption operations fail in the correct way when asked to operate
  * with incompatible MGF digest.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepWithMGFIncompatibleDigest) {
@@ -3929,7 +3875,7 @@
                           .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));
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_MGF_DIGEST, Begin(KeyPurpose::DECRYPT, params));
 }
 
 /*
@@ -3953,7 +3899,7 @@
                           .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));
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_MGF_DIGEST, Begin(KeyPurpose::DECRYPT, params));
 }
 
 /*
@@ -3970,10 +3916,10 @@
 
     string message = "Hello World!";
     auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
-    string ciphertext1 = EncryptMessage(message, params);
+    string ciphertext1 = LocalRsaEncryptMessage(message, params);
     EXPECT_EQ(2048U / 8, ciphertext1.size());
 
-    string ciphertext2 = EncryptMessage(message, params);
+    string ciphertext2 = LocalRsaEncryptMessage(message, params);
     EXPECT_EQ(2048U / 8, ciphertext2.size());
 
     // PKCS1 v1.5 randomizes padding so every result should be different.
@@ -3997,27 +3943,6 @@
 }
 
 /*
- * EncryptionOperationsTest.RsaPkcs1TooLarge
- *
- * Verifies that RSA PKCS encryption fails in the correct way when the message is too large.
- */
-TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .RsaEncryptionKey(2048, 65537)
-                                                 .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)
-                                                 .SetDefaultValidity()));
-    string message(2048 / 8 - 10, 'a');
-
-    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
-    string result;
-    ErrorCode error = Finish(message, &result);
-    EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
-    EXPECT_EQ(0U, result.size());
-}
-
-/*
  * EncryptionOperationsTest.EcdsaEncrypt
  *
  * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.