#include <stdio.h>
#include <string.h>
#include <openssl/opensslconf.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include "bn_local.h"
#include "err_local.h"
#include "rsa_local.h"
static int
rsa_public_encrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
BIGNUM *f, *ret;
int i, j, k, num = 0, r = -1;
unsigned char *buf = NULL;
BN_CTX *ctx = NULL;
if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS) {
RSAerror(RSA_R_MODULUS_TOO_LARGE);
return -1;
}
if (BN_ucmp(rsa->n, rsa->e) <= 0) {
RSAerror(RSA_R_BAD_E_VALUE);
return -1;
}
if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS) {
if (BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) {
RSAerror(RSA_R_BAD_E_VALUE);
return -1;
}
}
if ((ctx = BN_CTX_new()) == NULL)
goto err;
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
ret = BN_CTX_get(ctx);
num = BN_num_bytes(rsa->n);
buf = malloc(num);
if (f == NULL || ret == NULL || buf == NULL) {
RSAerror(ERR_R_MALLOC_FAILURE);
goto err;
}
switch (padding) {
case RSA_PKCS1_PADDING:
i = RSA_padding_add_PKCS1_type_2(buf, num, from, flen);
break;
#ifndef OPENSSL_NO_SHA
case RSA_PKCS1_OAEP_PADDING:
i = RSA_padding_add_PKCS1_OAEP(buf, num, from, flen, NULL, 0);
break;
#endif
case RSA_NO_PADDING:
i = RSA_padding_add_none(buf, num, from, flen);
break;
default:
RSAerror(RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
if (i <= 0)
goto err;
if (BN_bin2bn(buf, num, f) == NULL)
goto err;
if (BN_ucmp(f, rsa->n) >= 0) {
RSAerror(RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n,
CRYPTO_LOCK_RSA, rsa->n, ctx))
goto err;
}
if (!rsa->meth->bn_mod_exp(ret, f, rsa->e, rsa->n, ctx,
rsa->_method_mod_n))
goto err;
j = BN_num_bytes(ret);
i = BN_bn2bin(ret, &(to[num - j]));
for (k = 0; k < num - i; k++)
to[k] = 0;
r = num;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
freezero(buf, num);
return r;
}
static BN_BLINDING *
rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx)
{
BN_BLINDING *ret;
int got_write_lock = 0;
CRYPTO_r_lock(CRYPTO_LOCK_RSA);
if (rsa->blinding == NULL) {
CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
CRYPTO_w_lock(CRYPTO_LOCK_RSA);
got_write_lock = 1;
if (rsa->blinding == NULL)
rsa->blinding = RSA_setup_blinding(rsa, ctx);
}
if ((ret = rsa->blinding) == NULL)
goto err;
if ((*local = BN_BLINDING_is_local(ret)) == 0) {
if (rsa->mt_blinding == NULL) {
if (!got_write_lock) {
CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
CRYPTO_w_lock(CRYPTO_LOCK_RSA);
got_write_lock = 1;
}
if (rsa->mt_blinding == NULL)
rsa->mt_blinding = RSA_setup_blinding(rsa, ctx);
}
ret = rsa->mt_blinding;
}
err:
if (got_write_lock)
CRYPTO_w_unlock(CRYPTO_LOCK_RSA);
else
CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
return ret;
}
static int
rsa_blinding_convert(BN_BLINDING *b, BIGNUM *f, BIGNUM *unblind, BN_CTX *ctx)
{
if (unblind == NULL)
return BN_BLINDING_convert(f, NULL, b, ctx);
else {
int ret;
CRYPTO_w_lock(CRYPTO_LOCK_RSA_BLINDING);
ret = BN_BLINDING_convert(f, unblind, b, ctx);
CRYPTO_w_unlock(CRYPTO_LOCK_RSA_BLINDING);
return ret;
}
}
static int
rsa_blinding_invert(BN_BLINDING *b, BIGNUM *f, BIGNUM *unblind, BN_CTX *ctx)
{
return BN_BLINDING_invert(f, unblind, b, ctx);
}
static int
rsa_private_encrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
BIGNUM *f, *ret, *res;
int i, j, k, num = 0, r = -1;
unsigned char *buf = NULL;
BN_CTX *ctx = NULL;
int local_blinding = 0;
BIGNUM *unblind = NULL;
BN_BLINDING *blinding = NULL;
if ((ctx = BN_CTX_new()) == NULL)
goto err;
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
ret = BN_CTX_get(ctx);
num = BN_num_bytes(rsa->n);
buf = malloc(num);
if (f == NULL || ret == NULL || buf == NULL) {
RSAerror(ERR_R_MALLOC_FAILURE);
goto err;
}
switch (padding) {
case RSA_PKCS1_PADDING:
i = RSA_padding_add_PKCS1_type_1(buf, num, from, flen);
break;
case RSA_X931_PADDING:
i = RSA_padding_add_X931(buf, num, from, flen);
break;
case RSA_NO_PADDING:
i = RSA_padding_add_none(buf, num, from, flen);
break;
default:
RSAerror(RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
if (i <= 0)
goto err;
if (BN_bin2bn(buf, num, f) == NULL)
goto err;
if (BN_ucmp(f, rsa->n) >= 0) {
RSAerror(RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n,
CRYPTO_LOCK_RSA, rsa->n, ctx))
goto err;
}
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) {
blinding = rsa_get_blinding(rsa, &local_blinding, ctx);
if (blinding == NULL) {
RSAerror(ERR_R_INTERNAL_ERROR);
goto err;
}
}
if (blinding != NULL) {
if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) {
RSAerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (!rsa_blinding_convert(blinding, f, unblind, ctx))
goto err;
}
if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
(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_init(&d);
BN_with_flags(&d, rsa->d, BN_FLG_CONSTTIME);
if (!rsa->meth->bn_mod_exp(ret, f, &d, rsa->n, ctx,
rsa->_method_mod_n)) {
goto err;
}
}
if (blinding)
if (!rsa_blinding_invert(blinding, ret, unblind, ctx))
goto err;
if (padding == RSA_X931_PADDING) {
if (!BN_sub(f, rsa->n, ret))
goto err;
if (BN_cmp(ret, f) > 0)
res = f;
else
res = ret;
} else
res = ret;
j = BN_num_bytes(res);
i = BN_bn2bin(res, &(to[num - j]));
for (k = 0; k < num - i; k++)
to[k] = 0;
r = num;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
freezero(buf, num);
return r;
}
static int
rsa_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 *p;
unsigned char *buf = NULL;
BN_CTX *ctx = NULL;
int local_blinding = 0;
BIGNUM *unblind = NULL;
BN_BLINDING *blinding = NULL;
if ((ctx = BN_CTX_new()) == NULL)
goto err;
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
ret = BN_CTX_get(ctx);
num = BN_num_bytes(rsa->n);
buf = malloc(num);
if (!f || !ret || !buf) {
RSAerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (flen > num) {
RSAerror(RSA_R_DATA_GREATER_THAN_MOD_LEN);
goto err;
}
if (BN_bin2bn(from, (int)flen, f) == NULL)
goto err;
if (BN_ucmp(f, rsa->n) >= 0) {
RSAerror(RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n,
CRYPTO_LOCK_RSA, rsa->n, ctx))
goto err;
}
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) {
blinding = rsa_get_blinding(rsa, &local_blinding, ctx);
if (blinding == NULL) {
RSAerror(ERR_R_INTERNAL_ERROR);
goto err;
}
}
if (blinding != NULL) {
if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) {
RSAerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (!rsa_blinding_convert(blinding, f, unblind, ctx))
goto err;
}
if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
(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_init(&d);
BN_with_flags(&d, rsa->d, BN_FLG_CONSTTIME);
if (!rsa->meth->bn_mod_exp(ret, f, &d, rsa->n, ctx,
rsa->_method_mod_n)) {
goto err;
}
}
if (blinding)
if (!rsa_blinding_invert(blinding, ret, unblind, ctx))
goto err;
p = buf;
j = BN_bn2bin(ret, p);
switch (padding) {
case RSA_PKCS1_PADDING:
r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num);
break;
#ifndef OPENSSL_NO_SHA
case RSA_PKCS1_OAEP_PADDING:
r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0);
break;
#endif
case RSA_NO_PADDING:
r = RSA_padding_check_none(to, num, buf, j, num);
break;
default:
RSAerror(RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
if (r < 0)
RSAerror(RSA_R_PADDING_CHECK_FAILED);
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
freezero(buf, num);
return r;
}
static int
rsa_public_decrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
BIGNUM *f, *ret;
int i, num = 0, r = -1;
unsigned char *p;
unsigned char *buf = NULL;
BN_CTX *ctx = NULL;
if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS) {
RSAerror(RSA_R_MODULUS_TOO_LARGE);
return -1;
}
if (BN_ucmp(rsa->n, rsa->e) <= 0) {
RSAerror(RSA_R_BAD_E_VALUE);
return -1;
}
if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS) {
if (BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) {
RSAerror(RSA_R_BAD_E_VALUE);
return -1;
}
}
if ((ctx = BN_CTX_new()) == NULL)
goto err;
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
ret = BN_CTX_get(ctx);
num = BN_num_bytes(rsa->n);
buf = malloc(num);
if (!f || !ret || !buf) {
RSAerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (flen > num) {
RSAerror(RSA_R_DATA_GREATER_THAN_MOD_LEN);
goto err;
}
if (BN_bin2bn(from, flen, f) == NULL)
goto err;
if (BN_ucmp(f, rsa->n) >= 0) {
RSAerror(RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n,
CRYPTO_LOCK_RSA, rsa->n, ctx))
goto err;
}
if (!rsa->meth->bn_mod_exp(ret, f, rsa->e, rsa->n, ctx,
rsa->_method_mod_n))
goto err;
if (padding == RSA_X931_PADDING && (ret->d[0] & 0xf) != 12)
if (!BN_sub(ret, rsa->n, ret))
goto err;
p = buf;
i = BN_bn2bin(ret, p);
switch (padding) {
case RSA_PKCS1_PADDING:
r = RSA_padding_check_PKCS1_type_1(to, num, buf, i, num);
break;
case RSA_X931_PADDING:
r = RSA_padding_check_X931(to, num, buf, i, num);
break;
case RSA_NO_PADDING:
r = RSA_padding_check_none(to, num, buf, i, num);
break;
default:
RSAerror(RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
if (r < 0)
RSAerror(RSA_R_PADDING_CHECK_FAILED);
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
freezero(buf, num);
return r;
}
static int
rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
{
BIGNUM *r1, *m1, *vrfy;
BIGNUM dmp1, dmq1, c, pr1;
int ret = 0;
BN_CTX_start(ctx);
r1 = BN_CTX_get(ctx);
m1 = BN_CTX_get(ctx);
vrfy = BN_CTX_get(ctx);
if (r1 == NULL || m1 == NULL || vrfy == NULL) {
RSAerror(ERR_R_MALLOC_FAILURE);
goto err;
}
{
BIGNUM p, q;
BN_init(&p);
BN_init(&q);
BN_with_flags(&p, rsa->p, BN_FLG_CONSTTIME);
BN_with_flags(&q, rsa->q, BN_FLG_CONSTTIME);
if (rsa->flags & RSA_FLAG_CACHE_PRIVATE) {
if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_p,
CRYPTO_LOCK_RSA, &p, ctx) ||
!BN_MONT_CTX_set_locked(&rsa->_method_mod_q,
CRYPTO_LOCK_RSA, &q, ctx)) {
goto err;
}
}
}
if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n,
CRYPTO_LOCK_RSA, rsa->n, ctx))
goto err;
}
BN_init(&c);
BN_with_flags(&c, I, BN_FLG_CONSTTIME);
if (!BN_mod_ct(r1, &c, rsa->q, ctx))
goto err;
BN_init(&dmq1);
BN_with_flags(&dmq1, rsa->dmq1, BN_FLG_CONSTTIME);
if (!rsa->meth->bn_mod_exp(m1, r1, &dmq1, rsa->q, ctx,
rsa->_method_mod_q))
goto err;
BN_init(&c);
BN_with_flags(&c, I, BN_FLG_CONSTTIME);
if (!BN_mod_ct(r1, &c, rsa->p, ctx))
goto err;
BN_init(&dmp1);
BN_with_flags(&dmp1, rsa->dmp1, BN_FLG_CONSTTIME);
if (!rsa->meth->bn_mod_exp(r0, r1, &dmp1, rsa->p, ctx,
rsa->_method_mod_p))
goto err;
if (!BN_sub(r0, r0, m1))
goto err;
if (BN_is_negative(r0))
if (!BN_add(r0, r0, rsa->p))
goto err;
if (!BN_mul(r1, r0, rsa->iqmp, ctx))
goto err;
BN_init(&pr1);
BN_with_flags(&pr1, r1, BN_FLG_CONSTTIME);
if (!BN_mod_ct(r0, &pr1, rsa->p, ctx))
goto err;
if (BN_is_negative(r0))
if (!BN_add(r0, r0, rsa->p))
goto err;
if (!BN_mul(r1, r0, rsa->q, ctx))
goto err;
if (!BN_add(r0, r1, m1))
goto err;
if (rsa->e && rsa->n) {
if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx,
rsa->_method_mod_n))
goto err;
if (!BN_sub(vrfy, vrfy, I))
goto err;
if (!BN_mod_ct(vrfy, vrfy, rsa->n, ctx))
goto err;
if (BN_is_negative(vrfy))
if (!BN_add(vrfy, vrfy, rsa->n))
goto err;
if (!BN_is_zero(vrfy)) {
BIGNUM d;
BN_init(&d);
BN_with_flags(&d, rsa->d, BN_FLG_CONSTTIME);
if (!rsa->meth->bn_mod_exp(r0, I, &d, rsa->n, ctx,
rsa->_method_mod_n)) {
goto err;
}
}
}
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
}
static int
rsa_init(RSA *rsa)
{
rsa->flags |= RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE;
return 1;
}
static int
rsa_finish(RSA *rsa)
{
BN_MONT_CTX_free(rsa->_method_mod_n);
BN_MONT_CTX_free(rsa->_method_mod_p);
BN_MONT_CTX_free(rsa->_method_mod_q);
return 1;
}
static const RSA_METHOD rsa_pkcs1_meth = {
.name = "OpenSSL PKCS#1 RSA",
.rsa_pub_enc = rsa_public_encrypt,
.rsa_pub_dec = rsa_public_decrypt,
.rsa_priv_enc = rsa_private_encrypt,
.rsa_priv_dec = rsa_private_decrypt,
.rsa_mod_exp = rsa_mod_exp,
.bn_mod_exp = BN_mod_exp_mont_ct,
.init = rsa_init,
.finish = rsa_finish,
};
const RSA_METHOD *
RSA_PKCS1_OpenSSL(void)
{
return &rsa_pkcs1_meth;
}
LCRYPTO_ALIAS(RSA_PKCS1_OpenSSL);
const RSA_METHOD *
RSA_PKCS1_SSLeay(void)
{
return RSA_PKCS1_OpenSSL();
}
LCRYPTO_ALIAS(RSA_PKCS1_SSLeay);
int
RSA_bits(const RSA *r)
{
return BN_num_bits(r->n);
}
LCRYPTO_ALIAS(RSA_bits);
int
RSA_size(const RSA *r)
{
return BN_num_bytes(r->n);
}
LCRYPTO_ALIAS(RSA_size);
int
RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
return rsa->meth->rsa_pub_enc(flen, from, to, rsa, padding);
}
LCRYPTO_ALIAS(RSA_public_encrypt);
int
RSA_private_encrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
return rsa->meth->rsa_priv_enc(flen, from, to, rsa, padding);
}
LCRYPTO_ALIAS(RSA_private_encrypt);
int
RSA_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
return rsa->meth->rsa_priv_dec(flen, from, to, rsa, padding);
}
LCRYPTO_ALIAS(RSA_private_decrypt);
int
RSA_public_decrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
return rsa->meth->rsa_pub_dec(flen, from, to, rsa, padding);
}
LCRYPTO_ALIAS(RSA_public_decrypt);
int
RSA_flags(const RSA *r)
{
return r == NULL ? 0 : r->meth->flags;
}
LCRYPTO_ALIAS(RSA_flags);