Files
Open_Ultra_SAST/benchmarks/pairs/vfc/openssl-cve-2020-25659/fixed.c
T

241 lines
7.3 KiB
C
Raw Normal View History

/* Provenance: openssl/openssl rsa_ossl_private_decrypt (fixed).
* repo: openssl/openssl
* commit: 7fc67e0a33102aa47bbaa56533eeecb98c0450f7
* parent: 1ca61aa56090356bbdbb16cf48916fbd9886c78d
* commit_url: https://github.com/openssl/openssl/commit/7fc67e0a33102aa47bbaa56533eeecb98c0450f7
* cve: CVE-2020-25659
* license: OpenSSL License
* function: rsa_ossl_private_decrypt
* relpath: crypto/rsa/rsa_ossl.c
*/
static int rsa_ossl_private_decrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
BIGNUM *f, *ret;
int j, num = 0, r = -1;
unsigned char *buf = NULL;
unsigned char d_hash[SHA256_DIGEST_LENGTH] = {0};
HMAC_CTX *hmac = NULL;
unsigned int md_len = SHA256_DIGEST_LENGTH;
unsigned char kdk[SHA256_DIGEST_LENGTH] = {0};
BN_CTX *ctx = NULL;
int local_blinding = 0;
EVP_MD *md = NULL;
/*
* Used only if the blinding structure is shared. A non-NULL unblind
* instructs rsa_blinding_convert() and rsa_blinding_invert() to store
* the unblinding factor outside the blinding structure.
*/
BIGNUM *unblind = NULL;
BN_BLINDING *blinding = NULL;
if ((ctx = BN_CTX_new_ex(rsa->libctx)) == NULL)
goto err;
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
ret = BN_CTX_get(ctx);
if (ret == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB);
goto err;
}
num = BN_num_bytes(rsa->n);
buf = OPENSSL_malloc(num);
if (buf == NULL)
goto err;
/*
* This check was for equality but PGP does evil things and chops off the
* top '0' bytes
*/
if (flen > num) {
ERR_raise(ERR_LIB_RSA, RSA_R_DATA_GREATER_THAN_MOD_LEN);
goto err;
}
if (flen < 1) {
ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL);
goto err;
}
/* make data into a big number */
if (BN_bin2bn(from, (int)flen, f) == NULL)
goto err;
if (BN_ucmp(f, rsa->n) >= 0) {
ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) {
blinding = rsa_get_blinding(rsa, &local_blinding, ctx);
if (blinding == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
}
if (blinding != NULL) {
if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) {
ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB);
goto err;
}
if (!rsa_blinding_convert(blinding, f, unblind, ctx))
goto err;
}
/* do the decrypt */
if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
(rsa->version == RSA_ASN1_VERSION_MULTI) ||
((rsa->p != NULL) &&
(rsa->q != NULL) &&
(rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx))
goto err;
} else {
BIGNUM *d = BN_new();
if (d == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB);
goto err;
}
if (rsa->d == NULL) {
ERR_raise(ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY);
BN_free(d);
goto err;
}
BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
if (rsa->flags & RSA_FLAG_CACHE_PUBLIC)
if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, rsa->lock,
rsa->n, ctx)) {
BN_free(d);
goto err;
}
if (!rsa->meth->bn_mod_exp(ret, f, d, rsa->n, ctx,
rsa->_method_mod_n)) {
BN_free(d);
goto err;
}
/* We MUST free d before any further use of rsa->d */
BN_free(d);
}
if (blinding)
if (!rsa_blinding_invert(blinding, ret, unblind, ctx))
goto err;
/*
* derive the Key Derivation Key from private exponent and public
* ciphertext
*/
if (!(rsa->flags & RSA_FLAG_EXT_PKEY)) {
/*
* because we use d as a handle to rsa->d we need to keep it local and
* free before any further use of rsa->d
*/
BIGNUM *d = BN_new();
if (d == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
if (rsa->d == NULL) {
ERR_raise(ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY);
BN_free(d);
goto err;
}
BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
if (BN_bn2binpad(d, buf, num) < 0) {
ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
BN_free(d);
goto err;
}
BN_free(d);
/*
* we use hardcoded hash so that migrating between versions that use
* different hash doesn't provide a Bleichenbacher oracle:
* if the attacker can see that different versions return different
* messages for the same ciphertext, they'll know that the message is
* syntethically generated, which means that the padding check failed
*/
md = EVP_MD_fetch(rsa->libctx, "sha256", NULL);
if (md == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
if (EVP_Digest(buf, num, d_hash, NULL, md, NULL) <= 0) {
ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
hmac = HMAC_CTX_new();
if (hmac == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
if (HMAC_Init_ex(hmac, d_hash, sizeof(d_hash), md, NULL) <= 0) {
ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
if (flen < num) {
memset(buf, 0, num - flen);
if (HMAC_Update(hmac, buf, num - flen) <= 0) {
ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
}
if (HMAC_Update(hmac, from, flen) <= 0) {
ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
md_len = SHA256_DIGEST_LENGTH;
if (HMAC_Final(hmac, kdk, &md_len) <= 0) {
ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
}
j = BN_bn2binpad(ret, buf, num);
if (j < 0)
goto err;
switch (padding) {
case RSA_PKCS1_PADDING:
if (rsa->flags & RSA_FLAG_EXT_PKEY)
r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num);
else
r = ossl_rsa_padding_check_PKCS1_type_2(rsa->libctx, to, num, buf, j, num, kdk);
break;
case RSA_PKCS1_OAEP_PADDING:
r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0);
break;
case RSA_NO_PADDING:
memcpy(to, buf, (r = j));
break;
default:
ERR_raise(ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
#ifndef FIPS_MODULE
/*
* This trick doesn't work in the FIPS provider because libcrypto manages
* the error stack. Instead we opt not to put an error on the stack at all
* in case of padding failure in the FIPS provider.
*/
ERR_raise(ERR_LIB_RSA, RSA_R_PADDING_CHECK_FAILED);
err_clear_last_constant_time(1 & ~constant_time_msb(r));
#endif
err:
HMAC_CTX_free(hmac);
EVP_MD_free(md);
BN_CTX_end(ctx);
BN_CTX_free(ctx);
OPENSSL_clear_free(buf, num);
return r;
}