#include <sys/types.h>
#include <bignum.h>
#ifdef _KERNEL
#include <sys/param.h>
#else
#include <strings.h>
#include <cryptoutil.h>
#endif
#include <sys/crypto/common.h>
#include "rsa_impl.h"
const CK_BYTE MD5_DER_PREFIX[MD5_DER_PREFIX_Len] = {0x30, 0x20, 0x30, 0x0c,
0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00,
0x04, 0x10};
const CK_BYTE SHA1_DER_PREFIX[SHA1_DER_PREFIX_Len] = {0x30, 0x21, 0x30,
0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14};
const CK_BYTE SHA1_DER_PREFIX_OID[SHA1_DER_PREFIX_OID_Len] = {0x30, 0x1f, 0x30,
0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14};
const CK_BYTE SHA256_DER_PREFIX[SHA2_DER_PREFIX_Len] = {0x30, 0x31, 0x30, 0x0d,
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20};
const CK_BYTE SHA384_DER_PREFIX[SHA2_DER_PREFIX_Len] = {0x30, 0x41, 0x30, 0x0d,
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
0x00, 0x04, 0x30};
const CK_BYTE SHA512_DER_PREFIX[SHA2_DER_PREFIX_Len] = {0x30, 0x51, 0x30, 0x0d,
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40};
const CK_BYTE DEFAULT_PUB_EXPO[DEFAULT_PUB_EXPO_Len] = { 0x01, 0x00, 0x01 };
static CK_RV
convert_rv(BIG_ERR_CODE err)
{
switch (err) {
case BIG_OK:
return (CKR_OK);
case BIG_NO_MEM:
return (CKR_HOST_MEMORY);
case BIG_NO_RANDOM:
return (CKR_DEVICE_ERROR);
case BIG_INVALID_ARGS:
return (CKR_ARGUMENTS_BAD);
case BIG_DIV_BY_0:
default:
return (CKR_GENERAL_ERROR);
}
}
static BIG_ERR_CODE
RSA_key_init(RSAkey *key, int psize, int qsize)
{
BIG_ERR_CODE err = BIG_OK;
int plen, qlen, nlen;
plen = BITLEN2BIGNUMLEN(psize);
qlen = BITLEN2BIGNUMLEN(qsize);
nlen = plen + qlen;
key->size = psize + qsize;
if ((err = big_init(&(key->p), plen)) != BIG_OK)
return (err);
if ((err = big_init(&(key->q), qlen)) != BIG_OK)
goto ret1;
if ((err = big_init(&(key->n), nlen)) != BIG_OK)
goto ret2;
if ((err = big_init(&(key->d), nlen)) != BIG_OK)
goto ret3;
if ((err = big_init(&(key->e), nlen)) != BIG_OK)
goto ret4;
if ((err = big_init(&(key->dmodpminus1), plen)) != BIG_OK)
goto ret5;
if ((err = big_init(&(key->dmodqminus1), qlen)) != BIG_OK)
goto ret6;
if ((err = big_init(&(key->pinvmodq), qlen)) != BIG_OK)
goto ret7;
if ((err = big_init(&(key->p_rr), plen)) != BIG_OK)
goto ret8;
if ((err = big_init(&(key->q_rr), qlen)) != BIG_OK)
goto ret9;
if ((err = big_init(&(key->n_rr), nlen)) != BIG_OK)
goto ret10;
return (BIG_OK);
ret10:
big_finish(&(key->q_rr));
ret9:
big_finish(&(key->p_rr));
ret8:
big_finish(&(key->pinvmodq));
ret7:
big_finish(&(key->dmodqminus1));
ret6:
big_finish(&(key->dmodpminus1));
ret5:
big_finish(&(key->e));
ret4:
big_finish(&(key->d));
ret3:
big_finish(&(key->n));
ret2:
big_finish(&(key->q));
ret1:
big_finish(&(key->p));
return (err);
}
static void
RSA_key_finish(RSAkey *key)
{
big_finish(&(key->n_rr));
big_finish(&(key->q_rr));
big_finish(&(key->p_rr));
big_finish(&(key->pinvmodq));
big_finish(&(key->dmodqminus1));
big_finish(&(key->dmodpminus1));
big_finish(&(key->e));
big_finish(&(key->d));
big_finish(&(key->n));
big_finish(&(key->q));
big_finish(&(key->p));
}
static CK_RV
generate_rsa_key(RSAkey *key, int psize, int qsize, BIGNUM *pubexp,
int (*rfunc)(void *, size_t))
{
CK_RV rv = CKR_OK;
int (*rf)(void *, size_t);
BIGNUM a, b, c, d, e, f, g, h;
int len, keylen, size;
BIG_ERR_CODE brv = BIG_OK;
size = psize + qsize;
keylen = BITLEN2BIGNUMLEN(size);
len = keylen * 2 + 1;
key->size = size;
a.malloced = 0;
b.malloced = 0;
c.malloced = 0;
d.malloced = 0;
e.malloced = 0;
f.malloced = 0;
g.malloced = 0;
h.malloced = 0;
if ((big_init(&a, len) != BIG_OK) ||
(big_init(&b, len) != BIG_OK) ||
(big_init(&c, len) != BIG_OK) ||
(big_init(&d, len) != BIG_OK) ||
(big_init(&e, len) != BIG_OK) ||
(big_init(&f, len) != BIG_OK) ||
(big_init(&g, len) != BIG_OK) ||
(big_init(&h, len) != BIG_OK)) {
big_finish(&h);
big_finish(&g);
big_finish(&f);
big_finish(&e);
big_finish(&d);
big_finish(&c);
big_finish(&b);
big_finish(&a);
return (CKR_HOST_MEMORY);
}
rf = rfunc;
if (rf == NULL) {
#ifdef _KERNEL
rf = (int (*)(void *, size_t))random_get_pseudo_bytes;
#else
rf = pkcs11_get_urandom;
#endif
}
nextp:
if ((brv = big_random(&a, psize, rf)) != BIG_OK) {
goto ret;
}
if ((brv = big_nextprime_pos(&b, &a)) != BIG_OK) {
goto ret;
}
(void) big_sub_pos(&a, &b, &big_One);
if ((brv = big_ext_gcd_pos(&f, &d, &g, pubexp, &a)) != BIG_OK) {
goto ret;
}
if (big_cmp_abs(&f, &big_One) != 0) {
goto nextp;
}
if ((brv = big_random(&c, qsize, rf)) != BIG_OK) {
goto ret;
}
nextq:
(void) big_add(&a, &c, &big_Two);
if (big_bitlength(&a) != qsize) {
goto nextp;
}
if (big_cmp_abs(&a, &b) == 0) {
goto nextp;
}
if ((brv = big_nextprime_pos(&c, &a)) != BIG_OK) {
goto ret;
}
if ((brv = big_mul(&g, &b, &c)) != BIG_OK) {
goto ret;
}
if (big_bitlength(&g) != size) {
goto nextp;
}
(void) big_sub_pos(&a, &b, &big_One);
(void) big_sub_pos(&d, &c, &big_One);
if ((brv = big_mul(&a, &a, &d)) != BIG_OK) {
goto ret;
}
if ((brv = big_ext_gcd_pos(&f, &d, &h, pubexp, &a)) != BIG_OK) {
goto ret;
}
if (big_cmp_abs(&f, &big_One) != 0) {
goto nextq;
} else {
(void) big_copy(&e, pubexp);
}
if (d.sign == -1) {
if ((brv = big_add(&d, &d, &a)) != BIG_OK) {
goto ret;
}
}
(void) big_copy(&(key->p), &b);
(void) big_copy(&(key->q), &c);
(void) big_copy(&(key->n), &g);
(void) big_copy(&(key->d), &d);
(void) big_copy(&(key->e), &e);
if ((brv = big_ext_gcd_pos(&a, &f, &h, &b, &c)) != BIG_OK) {
goto ret;
}
if (f.sign == -1) {
if ((brv = big_add(&f, &f, &c)) != BIG_OK) {
goto ret;
}
}
(void) big_copy(&(key->pinvmodq), &f);
(void) big_sub(&a, &b, &big_One);
if ((brv = big_div_pos(&a, &f, &d, &a)) != BIG_OK) {
goto ret;
}
(void) big_copy(&(key->dmodpminus1), &f);
(void) big_sub(&a, &c, &big_One);
if ((brv = big_div_pos(&a, &f, &d, &a)) != BIG_OK) {
goto ret;
}
(void) big_copy(&(key->dmodqminus1), &f);
if ((brv = big_random(&h, size, rf)) != BIG_OK) {
goto ret;
}
if ((brv = big_div_pos(&a, &h, &h, &g)) != BIG_OK) {
goto ret;
}
if ((brv = big_modexp(&a, &h, &d, &g, NULL)) != BIG_OK) {
goto ret;
}
if ((brv = big_modexp(&b, &a, &e, &g, NULL)) != BIG_OK) {
goto ret;
}
if (big_cmp_abs(&b, &h) != 0) {
rv = generate_rsa_key(key, psize, qsize, pubexp, rf);
goto ret1;
} else {
brv = BIG_OK;
}
ret:
rv = convert_rv(brv);
ret1:
big_finish(&h);
big_finish(&g);
big_finish(&f);
big_finish(&e);
big_finish(&d);
big_finish(&c);
big_finish(&b);
big_finish(&a);
return (rv);
}
CK_RV
rsa_genkey_pair(RSAbytekey *bkey)
{
CK_RV rv = CKR_OK;
BIGNUM public_exponent = {0};
RSAkey rsakey;
uint32_t modulus_bytes;
if (bkey == NULL)
return (CKR_ARGUMENTS_BAD);
if (bkey->modulus_bits == 0)
return (CKR_ARGUMENTS_BAD);
if (bkey->pubexpo_bytes == 0 || bkey->pubexpo == NULL)
return (CKR_ARGUMENTS_BAD);
modulus_bytes = CRYPTO_BITS2BYTES(bkey->modulus_bits);
if ((modulus_bytes < MIN_RSA_KEYLENGTH_IN_BYTES) ||
(modulus_bytes > MAX_RSA_KEYLENGTH_IN_BYTES)) {
return (CKR_KEY_SIZE_RANGE);
}
if (RSA_key_init(&rsakey, modulus_bytes * 4, modulus_bytes * 4) !=
BIG_OK) {
return (CKR_HOST_MEMORY);
}
if (big_init(&public_exponent,
CHARLEN2BIGNUMLEN(bkey->pubexpo_bytes)) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean1;
}
bytestring2bignum(&public_exponent, bkey->pubexpo, bkey->pubexpo_bytes);
if ((rv = generate_rsa_key(&rsakey,
modulus_bytes * 4, modulus_bytes * 4, &public_exponent,
bkey->rfunc)) != CKR_OK) {
big_finish(&public_exponent);
goto clean1;
}
big_finish(&public_exponent);
bignum2bytestring(bkey->modulus, &(rsakey.n), modulus_bytes);
bkey->privexpo_bytes = rsakey.d.len * (int)sizeof (BIG_CHUNK_TYPE);
bignum2bytestring(bkey->privexpo, &(rsakey.d), bkey->privexpo_bytes);
bkey->pubexpo_bytes = rsakey.e.len * (int)sizeof (BIG_CHUNK_TYPE);
bignum2bytestring(bkey->pubexpo, &(rsakey.e), bkey->pubexpo_bytes);
bkey->prime1_bytes = rsakey.q.len * (int)sizeof (BIG_CHUNK_TYPE);
bignum2bytestring(bkey->prime1, &(rsakey.q), bkey->prime1_bytes);
bkey->prime2_bytes = rsakey.p.len * (int)sizeof (BIG_CHUNK_TYPE);
bignum2bytestring(bkey->prime2, &(rsakey.p), bkey->prime2_bytes);
bkey->expo1_bytes =
rsakey.dmodqminus1.len * (int)sizeof (BIG_CHUNK_TYPE);
bignum2bytestring(bkey->expo1, &(rsakey.dmodqminus1),
bkey->expo1_bytes);
bkey->expo2_bytes =
rsakey.dmodpminus1.len * (int)sizeof (BIG_CHUNK_TYPE);
bignum2bytestring(bkey->expo2,
&(rsakey.dmodpminus1), bkey->expo2_bytes);
bkey->coeff_bytes =
rsakey.pinvmodq.len * (int)sizeof (BIG_CHUNK_TYPE);
bignum2bytestring(bkey->coeff, &(rsakey.pinvmodq), bkey->coeff_bytes);
clean1:
RSA_key_finish(&rsakey);
return (rv);
}
CK_RV
rsa_encrypt(RSAbytekey *bkey, uchar_t *in, uint32_t in_len, uchar_t *out)
{
CK_RV rv = CKR_OK;
BIGNUM msg;
RSAkey rsakey;
uint32_t modulus_bytes;
if (bkey == NULL)
return (CKR_ARGUMENTS_BAD);
if (bkey->modulus_bits == 0 || bkey->modulus == NULL ||
bkey->pubexpo_bytes == 0 || bkey->pubexpo == NULL)
return (CKR_ARGUMENTS_BAD);
modulus_bytes = CRYPTO_BITS2BYTES(bkey->modulus_bits);
if (bkey->pubexpo_bytes > modulus_bytes) {
return (CKR_KEY_SIZE_RANGE);
}
if (RSA_key_init(&rsakey, modulus_bytes * 4, modulus_bytes * 4) !=
BIG_OK) {
return (CKR_HOST_MEMORY);
}
if (big_init(&msg, CHARLEN2BIGNUMLEN(in_len)) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean2;
}
bytestring2bignum(&msg, in, in_len);
bytestring2bignum(&(rsakey.e), bkey->pubexpo, bkey->pubexpo_bytes);
bytestring2bignum(&(rsakey.n), bkey->modulus, modulus_bytes);
if (big_cmp_abs(&msg, &(rsakey.n)) > 0) {
rv = CKR_DATA_LEN_RANGE;
goto clean3;
}
if (big_modexp(&msg, &msg, &(rsakey.e), &(rsakey.n), NULL) !=
BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean3;
}
bignum2bytestring(out, &msg, modulus_bytes);
clean3:
big_finish(&msg);
clean2:
RSA_key_finish(&rsakey);
return (rv);
}
CK_RV
rsa_decrypt(RSAbytekey *bkey, uchar_t *in, uint32_t in_len, uchar_t *out)
{
CK_RV rv = CKR_OK;
BIGNUM msg;
RSAkey rsakey;
uint32_t modulus_bytes;
if (bkey == NULL)
return (CKR_ARGUMENTS_BAD);
if (bkey->modulus_bits == 0 || bkey->modulus == NULL ||
bkey->prime1_bytes == 0 || bkey->prime1 == NULL ||
bkey->prime2_bytes == 0 || bkey->prime2 == NULL ||
bkey->expo1_bytes == 0 || bkey->expo1 == NULL ||
bkey->expo2_bytes == 0 || bkey->expo2 == NULL ||
bkey->coeff_bytes == 0 || bkey->coeff == NULL)
return (CKR_ARGUMENTS_BAD);
modulus_bytes = CRYPTO_BITS2BYTES(bkey->modulus_bits);
if (RSA_key_init(&rsakey, CRYPTO_BYTES2BITS(bkey->prime2_bytes),
CRYPTO_BYTES2BITS(bkey->prime1_bytes)) != BIG_OK) {
return (CKR_HOST_MEMORY);
}
if (big_init(&msg, CHARLEN2BIGNUMLEN(in_len)) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean3;
}
bytestring2bignum(&msg, in, in_len);
bytestring2bignum(&(rsakey.n), bkey->modulus, modulus_bytes);
if (big_cmp_abs(&msg, &(rsakey.n)) > 0) {
rv = CKR_DATA_LEN_RANGE;
goto clean4;
}
bytestring2bignum(&(rsakey.q), bkey->prime1, bkey->prime1_bytes);
bytestring2bignum(&(rsakey.p), bkey->prime2, bkey->prime2_bytes);
bytestring2bignum(&(rsakey.dmodqminus1),
bkey->expo1, bkey->expo1_bytes);
bytestring2bignum(&(rsakey.dmodpminus1),
bkey->expo2, bkey->expo2_bytes);
bytestring2bignum(&(rsakey.pinvmodq),
bkey->coeff, bkey->coeff_bytes);
if ((big_cmp_abs(&(rsakey.dmodpminus1), &(rsakey.p)) > 0) ||
(big_cmp_abs(&(rsakey.dmodqminus1), &(rsakey.q)) > 0) ||
(big_cmp_abs(&(rsakey.pinvmodq), &(rsakey.q)) > 0)) {
rv = CKR_KEY_SIZE_RANGE;
goto clean4;
}
if (big_modexp_crt(&msg, &msg, &(rsakey.dmodpminus1),
&(rsakey.dmodqminus1), &(rsakey.p), &(rsakey.q),
&(rsakey.pinvmodq), NULL, NULL) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean4;
}
bignum2bytestring(out, &msg, modulus_bytes);
clean4:
big_finish(&msg);
clean3:
RSA_key_finish(&rsakey);
return (rv);
}