Support all digests for RSA.

Also switch to using the EVP APIs where possible for RSA ops.

Change-Id: I092a5c7598073980d36ce5137cfe17f0499a10b9
diff --git a/rsa_operation.cpp b/rsa_operation.cpp
index 55ff1b3..3d50ba9 100644
--- a/rsa_operation.cpp
+++ b/rsa_operation.cpp
@@ -31,18 +31,25 @@
 static const int MIN_PSS_SALT_LEN = 8 /* salt len */ + 2 /* overhead */;
 
 /* static */
-RSA* RsaOperationFactory::GetRsaKey(const Key& key, keymaster_error_t* error) {
+EVP_PKEY* RsaOperationFactory::GetRsaKey(const Key& key, keymaster_error_t* error) {
     const RsaKey* rsa_key = static_cast<const RsaKey*>(&key);
     assert(rsa_key);
     if (!rsa_key || !rsa_key->key()) {
         *error = KM_ERROR_UNKNOWN_ERROR;
-        return NULL;
+        return nullptr;
     }
-    RSA_up_ref(rsa_key->key());
-    return rsa_key->key();
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+    if (!rsa_key->InternalToEvp(pkey.get())) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+    return pkey.release();
 }
 
-static const keymaster_digest_t supported_digests[] = {KM_DIGEST_NONE, KM_DIGEST_SHA_2_256};
+static const keymaster_digest_t supported_digests[] = {
+    KM_DIGEST_NONE,      KM_DIGEST_MD5,       KM_DIGEST_SHA1,     KM_DIGEST_SHA_2_224,
+    KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
 static const keymaster_padding_t supported_sig_padding[] = {KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN,
                                                             KM_PAD_RSA_PSS};
 
@@ -63,13 +70,15 @@
                                                          keymaster_error_t* error) {
     keymaster_padding_t padding;
     keymaster_digest_t digest;
-    RSA* rsa;
     if (!GetAndValidateDigest(begin_params, key, &digest, error) ||
-        !GetAndValidatePadding(begin_params, key, &padding, error) ||
-        !(rsa = GetRsaKey(key, error)))
-        return NULL;
+        !GetAndValidatePadding(begin_params, key, &padding, error))
+        return nullptr;
 
-    Operation* op = InstantiateOperation(digest, padding, rsa);
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> rsa(GetRsaKey(key, error));
+    if (!rsa.get())
+        return nullptr;
+
+    Operation* op = InstantiateOperation(digest, padding, rsa.release());
     if (!op)
         *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
     return op;
@@ -82,12 +91,14 @@
                                                         const AuthorizationSet& begin_params,
                                                         keymaster_error_t* error) {
     keymaster_padding_t padding;
-    RSA* rsa;
-    if (!GetAndValidatePadding(begin_params, key, &padding, error) ||
-        !(rsa = GetRsaKey(key, error)))
-        return NULL;
+    if (!GetAndValidatePadding(begin_params, key, &padding, error))
+        return nullptr;
 
-    Operation* op = InstantiateOperation(padding, rsa);
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> rsa(GetRsaKey(key, error));
+    if (!rsa.get())
+        return nullptr;
+
+    Operation* op = InstantiateOperation(padding, rsa.release());
     if (!op)
         *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
     return op;
@@ -107,7 +118,7 @@
 
 RsaOperation::~RsaOperation() {
     if (rsa_key_ != NULL)
-        RSA_free(rsa_key_);
+        EVP_PKEY_free(rsa_key_);
 }
 
 keymaster_error_t RsaOperation::Update(const AuthorizationSet& /* additional_params */,
@@ -134,76 +145,119 @@
     return KM_ERROR_OK;
 }
 
+keymaster_error_t RsaOperation::SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx) {
+    keymaster_error_t error;
+    int openssl_padding = GetOpensslPadding(&error);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, openssl_padding) <= 0)
+        return TranslateLastOpenSslError();
+    return KM_ERROR_OK;
+}
+
 RsaDigestingOperation::RsaDigestingOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
-                                             keymaster_padding_t padding, RSA* key)
+                                             keymaster_padding_t padding, EVP_PKEY* key)
     : RsaOperation(purpose, padding, key), digest_(digest), digest_algorithm_(NULL) {
     EVP_MD_CTX_init(&digest_ctx_);
 }
 RsaDigestingOperation::~RsaDigestingOperation() {
     EVP_MD_CTX_cleanup(&digest_ctx_);
-    memset_s(digest_buf_, 0, sizeof(digest_buf_));
-}
-
-keymaster_error_t RsaDigestingOperation::Begin(const AuthorizationSet& /* input_params */,
-                                               AuthorizationSet* /* output_params */) {
-    if (require_digest() && digest_ == KM_DIGEST_NONE)
-        return KM_ERROR_INCOMPATIBLE_DIGEST;
-    return InitDigest();
-}
-
-keymaster_error_t RsaDigestingOperation::Update(const AuthorizationSet& additional_params,
-                                                const Buffer& input, Buffer* output,
-                                                size_t* input_consumed) {
-    if (digest_ == KM_DIGEST_NONE)
-        return RsaOperation::Update(additional_params, input, output, input_consumed);
-    else
-        return UpdateDigest(input, input_consumed);
 }
 
 keymaster_error_t RsaDigestingOperation::InitDigest() {
+    if (digest_ == KM_DIGEST_NONE) {
+        if (require_digest())
+            return KM_ERROR_INCOMPATIBLE_DIGEST;
+        return KM_ERROR_OK;
+    }
+
     switch (digest_) {
     case KM_DIGEST_NONE:
         return KM_ERROR_OK;
+    case KM_DIGEST_MD5:
+        digest_algorithm_ = EVP_md5();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA1:
+        digest_algorithm_ = EVP_sha1();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_224:
+        digest_algorithm_ = EVP_sha224();
+        return KM_ERROR_OK;
     case KM_DIGEST_SHA_2_256:
         digest_algorithm_ = EVP_sha256();
-        break;
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_384:
+        digest_algorithm_ = EVP_sha384();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_512:
+        digest_algorithm_ = EVP_sha512();
+        return KM_ERROR_OK;
     default:
         return KM_ERROR_UNSUPPORTED_DIGEST;
     }
-
-    if (!EVP_DigestInit_ex(&digest_ctx_, digest_algorithm_, NULL /* engine */)) {
-        int err = ERR_get_error();
-        LOG_E("Failed to initialize digest: %d %s", err, ERR_error_string(err, NULL));
-        return KM_ERROR_UNKNOWN_ERROR;
-    }
-    return KM_ERROR_OK;
 }
 
-keymaster_error_t RsaDigestingOperation::UpdateDigest(const Buffer& input, size_t* input_consumed) {
-    if (!EVP_DigestUpdate(&digest_ctx_, input.peek_read(), input.available_read())) {
-        int err = ERR_get_error();
-        LOG_E("Failed to update digest: %d %s", err, ERR_error_string(err, NULL));
-        return KM_ERROR_UNKNOWN_ERROR;
+const size_t PSS_OVERHEAD = 2;
+const size_t MIN_SALT_SIZE = 8;
+
+int RsaDigestingOperation::GetOpensslPadding(keymaster_error_t* error) {
+    *error = KM_ERROR_OK;
+    switch (padding_) {
+    case KM_PAD_NONE:
+        return RSA_NO_PADDING;
+    case KM_PAD_RSA_PKCS1_1_5_SIGN:
+
+        return RSA_PKCS1_PADDING;
+    case KM_PAD_RSA_PSS:
+        if (digest_ == KM_DIGEST_NONE) {
+            *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+            return -1;
+        }
+        if (EVP_MD_size(digest_algorithm_) + PSS_OVERHEAD + MIN_SALT_SIZE >
+            (size_t)EVP_PKEY_size(rsa_key_)) {
+            *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+            return -1;
+        }
+        return RSA_PKCS1_PSS_PADDING;
+    default:
+        return -1;
     }
+}
+
+keymaster_error_t RsaSignOperation::Begin(const AuthorizationSet& /* input_params */,
+                                          AuthorizationSet* /* output_params */) {
+    keymaster_error_t error = InitDigest();
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE)
+        return KM_ERROR_OK;
+
+    EVP_PKEY_CTX* pkey_ctx;
+    if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
+                           rsa_key_) != 1)
+        return TranslateLastOpenSslError();
+    return SetRsaPaddingInEvpContext(pkey_ctx);
+}
+
+keymaster_error_t RsaSignOperation::Update(const AuthorizationSet& additional_params,
+                                           const Buffer& input, Buffer* output,
+                                           size_t* input_consumed) {
+    if (digest_ == KM_DIGEST_NONE)
+        // Just buffer the data.
+        return RsaOperation::Update(additional_params, input, output, input_consumed);
+
+    if (EVP_DigestSignUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
+        return TranslateLastOpenSslError();
     *input_consumed = input.available_read();
     return KM_ERROR_OK;
 }
 
-keymaster_error_t RsaDigestingOperation::FinishDigest(unsigned* digest_size) {
-    assert(digest_algorithm_ != NULL);
-    if (!EVP_DigestFinal_ex(&digest_ctx_, digest_buf_, digest_size)) {
-        int err = ERR_get_error();
-        LOG_E("Failed to finalize digest: %d %s", err, ERR_error_string(err, NULL));
-        return KM_ERROR_UNKNOWN_ERROR;
-    }
-    assert(*digest_size == static_cast<unsigned>(EVP_MD_size(digest_algorithm_)));
-    return KM_ERROR_OK;
-}
-
 keymaster_error_t RsaSignOperation::Finish(const AuthorizationSet& /* additional_params */,
                                            const Buffer& /* signature */, Buffer* output) {
     assert(output);
-    output->Reinitialize(RSA_size(rsa_key_));
+
     if (digest_ == KM_DIGEST_NONE)
         return SignUndigested(output);
     else
@@ -211,15 +265,23 @@
 }
 
 keymaster_error_t RsaSignOperation::SignUndigested(Buffer* output) {
+    UniquePtr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(rsa_key_)));
+    if (!rsa.get())
+        return TranslateLastOpenSslError();
+
+    if (!output->Reinitialize(RSA_size(rsa.get())))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
     int bytes_encrypted;
     switch (padding_) {
     case KM_PAD_NONE:
         bytes_encrypted = RSA_private_encrypt(data_.available_read(), data_.peek_read(),
-                                              output->peek_write(), rsa_key_, RSA_NO_PADDING);
+                                              output->peek_write(), rsa.get(), RSA_NO_PADDING);
         break;
     case KM_PAD_RSA_PKCS1_1_5_SIGN:
+        // Does PKCS1 padding without digesting even make sense?  Dunno.  We'll support it.
         bytes_encrypted = RSA_private_encrypt(data_.available_read(), data_.peek_read(),
-                                              output->peek_write(), rsa_key_, RSA_PKCS1_PADDING);
+                                              output->peek_write(), rsa.get(), RSA_PKCS1_PADDING);
         break;
     default:
         return KM_ERROR_UNSUPPORTED_PADDING_MODE;
@@ -232,57 +294,45 @@
 }
 
 keymaster_error_t RsaSignOperation::SignDigested(Buffer* output) {
-    unsigned digest_size = 0;
-    keymaster_error_t error = FinishDigest(&digest_size);
-    if (error != KM_ERROR_OK)
-        return error;
+    size_t siglen;
+    if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1)
+        return TranslateLastOpenSslError();
 
-    UniquePtr<uint8_t[]> padded_digest;
-    switch (padding_) {
-    case KM_PAD_NONE:
-        LOG_E("Digesting requires padding", 0);
-        return KM_ERROR_INCOMPATIBLE_PADDING_MODE;
-    case KM_PAD_RSA_PKCS1_1_5_SIGN:
-        return PrivateEncrypt(digest_buf_, digest_size, RSA_PKCS1_PADDING, output);
-    case KM_PAD_RSA_PSS:
-        // OpenSSL doesn't verify that the key is large enough for the digest size.  This can cause
-        // a segfault in some cases, and in others can result in a unsafely-small salt.
-        if ((unsigned)RSA_size(rsa_key_) < MIN_PSS_SALT_LEN + digest_size) {
-            LOG_E("%d-byte too small for PSS padding and %d-byte digest", RSA_size(rsa_key_),
-                  digest_size);
-            // TODO(swillden): Add a better return code for this.
-            return KM_ERROR_INCOMPATIBLE_DIGEST;
-        }
-
-        if ((error = PssPadDigest(&padded_digest)) != KM_ERROR_OK)
-            return error;
-        return PrivateEncrypt(padded_digest.get(), RSA_size(rsa_key_), RSA_NO_PADDING, output);
-    default:
-        return KM_ERROR_UNSUPPORTED_PADDING_MODE;
-    }
-}
-
-keymaster_error_t RsaSignOperation::PssPadDigest(UniquePtr<uint8_t[]>* padded_digest) {
-    padded_digest->reset(new uint8_t[RSA_size(rsa_key_)]);
-    if (!padded_digest->get())
+    if (!output->Reinitialize(siglen))
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
-    if (!RSA_padding_add_PKCS1_PSS_mgf1(rsa_key_, padded_digest->get(), digest_buf_,
-                                        digest_algorithm_, NULL,
-                                        -2 /* Indicates maximum salt length */)) {
-        LOG_E("%s", "Failed to apply PSS padding");
-        return KM_ERROR_UNKNOWN_ERROR;
-    }
+    if (EVP_DigestSignFinal(&digest_ctx_, output->peek_write(), &siglen) <= 0)
+        return TranslateLastOpenSslError();
+    output->advance_write(siglen);
+
     return KM_ERROR_OK;
 }
 
-keymaster_error_t RsaSignOperation::PrivateEncrypt(uint8_t* to_encrypt, size_t len,
-                                                   int openssl_padding, Buffer* output) {
-    int bytes_encrypted =
-        RSA_private_encrypt(len, to_encrypt, output->peek_write(), rsa_key_, openssl_padding);
-    if (bytes_encrypted <= 0)
-        return KM_ERROR_UNKNOWN_ERROR;
-    output->advance_write(bytes_encrypted);
+keymaster_error_t RsaVerifyOperation::Begin(const AuthorizationSet& /* input_params */,
+                                            AuthorizationSet* /* output_params */) {
+    keymaster_error_t error = InitDigest();
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE)
+        return KM_ERROR_OK;
+
+    EVP_PKEY_CTX* pkey_ctx;
+    if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, NULL, rsa_key_) != 1)
+        return TranslateLastOpenSslError();
+    return SetRsaPaddingInEvpContext(pkey_ctx);
+}
+
+keymaster_error_t RsaVerifyOperation::Update(const AuthorizationSet& additional_params,
+                                             const Buffer& input, Buffer* output,
+                                             size_t* input_consumed) {
+    if (digest_ == KM_DIGEST_NONE)
+        // Just buffer the data.
+        return RsaOperation::Update(additional_params, input, output, input_consumed);
+
+    if (EVP_DigestVerifyUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
+        return TranslateLastOpenSslError();
+    *input_consumed = input.available_read();
     return KM_ERROR_OK;
 }
 
@@ -295,37 +345,20 @@
 }
 
 keymaster_error_t RsaVerifyOperation::VerifyUndigested(const Buffer& signature) {
-    return DecryptAndMatch(signature, data_.peek_read(), data_.available_read());
-}
+    UniquePtr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(rsa_key_)));
+    if (!rsa.get())
+        return KM_ERROR_UNKNOWN_ERROR;
 
-keymaster_error_t RsaVerifyOperation::VerifyDigested(const Buffer& signature) {
-    unsigned digest_size = 0;
-    keymaster_error_t error = FinishDigest(&digest_size);
-    if (error != KM_ERROR_OK)
-        return error;
-    return DecryptAndMatch(signature, digest_buf_, digest_size);
-}
-
-keymaster_error_t RsaVerifyOperation::DecryptAndMatch(const Buffer& signature,
-                                                      const uint8_t* to_match, size_t len) {
-#ifdef OPENSSL_IS_BORINGSSL
-    size_t key_len = RSA_size(rsa_key_);
-#else
-    size_t key_len = (size_t)RSA_size(rsa_key_);
-#endif
-
+    size_t key_len = RSA_size(rsa.get());
     int openssl_padding;
     switch (padding_) {
     case KM_PAD_NONE:
-        if (len != key_len)
+        if (data_.available_read() != key_len)
             return KM_ERROR_INVALID_INPUT_LENGTH;
-        if (len != signature.available_read())
+        if (data_.available_read() != signature.available_read())
             return KM_ERROR_VERIFICATION_FAILED;
         openssl_padding = RSA_NO_PADDING;
         break;
-    case KM_PAD_RSA_PSS:  // Do a raw decrypt for PSS
-        openssl_padding = RSA_NO_PADDING;
-        break;
     case KM_PAD_RSA_PKCS1_1_5_SIGN:
         openssl_padding = RSA_PKCS1_PADDING;
         break;
@@ -335,67 +368,65 @@
 
     UniquePtr<uint8_t[]> decrypted_data(new uint8_t[key_len]);
     int bytes_decrypted = RSA_public_decrypt(signature.available_read(), signature.peek_read(),
-                                             decrypted_data.get(), rsa_key_, openssl_padding);
+                                             decrypted_data.get(), rsa.get(), openssl_padding);
     if (bytes_decrypted < 0)
         return KM_ERROR_VERIFICATION_FAILED;
 
-    if (padding_ == KM_PAD_RSA_PSS &&
-        RSA_verify_PKCS1_PSS_mgf1(rsa_key_, to_match, digest_algorithm_, NULL, decrypted_data.get(),
-                                  -2 /* salt length recovered from signature */))
-        return KM_ERROR_OK;
-    else if (padding_ != KM_PAD_RSA_PSS && memcmp_s(decrypted_data.get(), to_match, len) == 0)
-        return KM_ERROR_OK;
-
-    return KM_ERROR_VERIFICATION_FAILED;
+    if (memcmp_s(decrypted_data.get(), data_.peek_read(), data_.available_read()) != 0)
+        return KM_ERROR_VERIFICATION_FAILED;
+    return KM_ERROR_OK;
 }
 
-const int OAEP_PADDING_OVERHEAD = 42;
-const int PKCS1_PADDING_OVERHEAD = 11;
+keymaster_error_t RsaVerifyOperation::VerifyDigested(const Buffer& signature) {
+    if (!EVP_DigestVerifyFinal(&digest_ctx_, signature.peek_read(), signature.available_read()))
+        return KM_ERROR_VERIFICATION_FAILED;
+    return KM_ERROR_OK;
+}
+
+int RsaCryptOperation::GetOpensslPadding(keymaster_error_t* error) {
+    *error = KM_ERROR_OK;
+    switch (padding_) {
+    case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+        return RSA_PKCS1_PADDING;
+    case KM_PAD_RSA_OAEP:
+        return RSA_PKCS1_OAEP_PADDING;
+    default:
+        return -1;
+    }
+}
+
+struct EVP_PKEY_CTX_Delete {
+    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
 
 keymaster_error_t RsaEncryptOperation::Finish(const AuthorizationSet& /* additional_params */,
                                               const Buffer& /* signature */, Buffer* output) {
     assert(output);
-    int openssl_padding;
 
-#if defined(OPENSSL_IS_BORINGSSL)
-    size_t key_len = RSA_size(rsa_key_);
-#else
-    size_t key_len = (size_t)RSA_size(rsa_key_);
-#endif
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(
+        EVP_PKEY_CTX_new(rsa_key_, nullptr /* engine */));
+    if (!ctx.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
-    size_t message_size = data_.available_read();
-    switch (padding_) {
-    case KM_PAD_RSA_OAEP:
-        openssl_padding = RSA_PKCS1_OAEP_PADDING;
-        if (message_size + OAEP_PADDING_OVERHEAD > key_len) {
-            LOG_E("Cannot encrypt %d bytes with %d-byte key and OAEP padding",
-                  data_.available_read(), key_len);
-            return KM_ERROR_INVALID_INPUT_LENGTH;
-        }
-        break;
-    case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
-        openssl_padding = RSA_PKCS1_PADDING;
-        if (message_size + PKCS1_PADDING_OVERHEAD > key_len) {
-            LOG_E("Cannot encrypt %d bytes with %d-byte key and PKCS1 padding",
-                  data_.available_read(), key_len);
-            return KM_ERROR_INVALID_INPUT_LENGTH;
-        }
-        break;
-    default:
-        LOG_E("Padding mode %d not supported", padding_);
-        return KM_ERROR_UNSUPPORTED_PADDING_MODE;
-    }
+    if (EVP_PKEY_encrypt_init(ctx.get()) <= 0)
+        return TranslateLastOpenSslError();
 
-    output->Reinitialize(RSA_size(rsa_key_));
-    int bytes_encrypted = RSA_public_encrypt(data_.available_read(), data_.peek_read(),
-                                             output->peek_write(), rsa_key_, openssl_padding);
+    keymaster_error_t error = SetRsaPaddingInEvpContext(ctx.get());
+    if (error != KM_ERROR_OK)
+        return error;
 
-    if (bytes_encrypted < 0) {
-        LOG_E("Error %d encrypting data with RSA", ERR_get_error());
-        return KM_ERROR_UNKNOWN_ERROR;
-    }
-    assert(bytes_encrypted == (int)RSA_size(rsa_key_));
-    output->advance_write(bytes_encrypted);
+    size_t outlen;
+    if (EVP_PKEY_encrypt(ctx.get(), nullptr /* out */, &outlen, data_.peek_read(),
+                         data_.available_read()) <= 0)
+        return TranslateLastOpenSslError();
+
+    if (!output->Reinitialize(outlen))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (EVP_PKEY_encrypt(ctx.get(), output->peek_write(), &outlen, data_.peek_read(),
+                         data_.available_read()) <= 0)
+        return TranslateLastOpenSslError();
+    output->advance_write(outlen);
 
     return KM_ERROR_OK;
 }
@@ -403,28 +434,31 @@
 keymaster_error_t RsaDecryptOperation::Finish(const AuthorizationSet& /* additional_params */,
                                               const Buffer& /* signature */, Buffer* output) {
     assert(output);
-    int openssl_padding;
-    switch (padding_) {
-    case KM_PAD_RSA_OAEP:
-        openssl_padding = RSA_PKCS1_OAEP_PADDING;
-        break;
-    case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
-        openssl_padding = RSA_PKCS1_PADDING;
-        break;
-    default:
-        LOG_E("Padding mode %d not supported", padding_);
-        return KM_ERROR_UNSUPPORTED_PADDING_MODE;
-    }
 
-    output->Reinitialize(RSA_size(rsa_key_));
-    int bytes_decrypted = RSA_private_decrypt(data_.available_read(), data_.peek_read(),
-                                              output->peek_write(), rsa_key_, openssl_padding);
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(
+        EVP_PKEY_CTX_new(rsa_key_, nullptr /* engine */));
+    if (!ctx.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
-    if (bytes_decrypted < 0) {
-        LOG_E("Error %d decrypting data with RSA", ERR_get_error());
-        return KM_ERROR_UNKNOWN_ERROR;
-    }
-    output->advance_write(bytes_decrypted);
+    if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
+        return TranslateLastOpenSslError();
+
+    keymaster_error_t error = SetRsaPaddingInEvpContext(ctx.get());
+    if (error != KM_ERROR_OK)
+        return error;
+
+    size_t outlen;
+    if (EVP_PKEY_decrypt(ctx.get(), nullptr /* out */, &outlen, data_.peek_read(),
+                         data_.available_read()) <= 0)
+        return TranslateLastOpenSslError();
+
+    if (!output->Reinitialize(outlen))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (EVP_PKEY_decrypt(ctx.get(), output->peek_write(), &outlen, data_.peek_read(),
+                         data_.available_read()) <= 0)
+        return TranslateLastOpenSslError();
+    output->advance_write(outlen);
 
     return KM_ERROR_OK;
 }