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;
}