diff options
Diffstat (limited to 'usr/src/common/crypto/rsa/rsa_impl.c')
-rw-r--r-- | usr/src/common/crypto/rsa/rsa_impl.c | 545 |
1 files changed, 440 insertions, 105 deletions
diff --git a/usr/src/common/crypto/rsa/rsa_impl.c b/usr/src/common/crypto/rsa/rsa_impl.c index 220fe0be83..f6e637fe68 100644 --- a/usr/src/common/crypto/rsa/rsa_impl.c +++ b/usr/src/common/crypto/rsa/rsa_impl.c @@ -18,9 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -29,16 +29,18 @@ */ #include <sys/types.h> -#include "rsa_impl.h" +#include <bignum.h> #ifdef _KERNEL #include <sys/param.h> #else #include <strings.h> #include <cryptoutil.h> -#include "softRandom.h" #endif +#include <sys/crypto/common.h> +#include "rsa_impl.h" + /* * DER encoding T of the DigestInfo values for MD5, SHA1, and SHA2 * from PKCS#1 v2.1: RSA Cryptography Standard Section 9.2 Note 1 @@ -77,8 +79,32 @@ const CK_BYTE SHA512_DER_PREFIX[SHA2_DER_PREFIX_Len] = {0x30, 0x51, 0x30, 0x0d, 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); + } +} + /* psize and qsize are in bits */ -BIG_ERR_CODE +static BIG_ERR_CODE RSA_key_init(RSAkey *key, int psize, int qsize) { BIG_ERR_CODE err = BIG_OK; @@ -142,8 +168,7 @@ ret1: return (err); } - -void +static void RSA_key_finish(RSAkey *key) { @@ -165,162 +190,472 @@ RSA_key_finish(RSAkey *key) } - /* - * To create a block type "02" encryption block for RSA PKCS encryption - * process. - * - * The RSA PKCS Padding before encryption is in the following format: - * +------+--------------------+----+-----------------------------+ - * |0x0002| 8 bytes or more RN |0x00| DATA | - * +------+--------------------+----+-----------------------------+ - * + * Generate RSA key */ -CK_RV -soft_encrypt_rsa_pkcs_encode(uint8_t *databuf, - size_t datalen, uint8_t *padbuf, size_t padbuflen) +static CK_RV +generate_rsa_key(RSAkey *key, int psize, int qsize, BIGNUM *pubexp, + int (*rfunc)(void *, size_t)) { + CK_RV rv = CKR_OK; /* EXPORT DELETE START */ - size_t padlen; - CK_RV rv; - - padlen = padbuflen - datalen; - if (padlen < MIN_PKCS1_PADLEN) { - return (CKR_DATA_LEN_RANGE); + 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; + + /* + * Note: It is not really necessary to compute e, it is in pubexp: + * (void) big_copy(&(key->e), pubexp); + */ + + 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); } - /* Pad with 0x0002+non-zero pseudorandom numbers+0x00. */ - padbuf[0] = 0x00; - padbuf[1] = 0x02; + rf = rfunc; + if (rf == NULL) { #ifdef _KERNEL - rv = knzero_random_generator(padbuf + 2, padbuflen - 3); + rf = (int (*)(void *, size_t))random_get_pseudo_bytes; #else - rv = CKR_OK; - if (pkcs11_get_nzero_urandom(padbuf + 2, padbuflen - 3) < 0) - rv = CKR_DEVICE_ERROR; + rf = pkcs11_get_urandom; #endif - if (rv != CKR_OK) { - return (rv); } - padbuf[padlen - 1] = 0x00; - bcopy(databuf, padbuf + padlen, datalen); +nextp: + if ((brv = big_random(&a, psize, rf)) != BIG_OK) { + goto ret; + } + + if ((brv = big_nextprime_pos(&b, &a)) != BIG_OK) { + goto ret; + } + /* b now contains the potential prime p */ + + (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; + } + /* c now contains the potential prime q */ + + if ((brv = big_mul(&g, &b, &c)) != BIG_OK) { + goto ret; + } + if (big_bitlength(&g) != size) { + goto nextp; + } + /* g now contains the potential modulus n */ + + (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); + + /* pairwise consistency check: decrypt and encrypt restores value */ + 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) { + /* this should not happen */ + 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); /* EXPORT DELETE END */ - return (CKR_OK); + return (rv); } - -/* - * The RSA PKCS Padding after decryption is in the following format: - * +------+--------------------+----+-----------------------------+ - * |0x0002| 8 bytes or more RN |0x00| DATA | - * +------+--------------------+----+-----------------------------+ - * - * 'padbuf' points to the recovered message which is the modulus - * length. As a result, 'plen' is changed to hold the actual data length. - */ CK_RV -soft_decrypt_rsa_pkcs_decode(uint8_t *padbuf, int *plen) +rsa_genkey_pair(RSAbytekey *bkey) { + /* + * NOTE: Whomever originally wrote this function swapped p and q. + * This table shows the mapping between name convention used here + * versus what is used in most texts that describe RSA key generation. + * This function: Standard convention: + * -------------- -------------------- + * modulus, n -same- + * prime 1, q prime 1, p + * prime 2, p prime 2, q + * private exponent, d -same- + * public exponent, e -same- + * exponent 1, d mod (q-1) d mod (p-1) + * exponent 2, d mod (p-1) d mod (q-1) + * coefficient, p^-1 mod q q^-1 mod p + * + * Also notice the struct member for coefficient is named .pinvmodq + * rather than .qinvmodp, reflecting the switch. + * + * The code here wasn't unswapped, because "it works". Further, + * p and q are interchangeable as long as exponent 1 and 2 and + * the coefficient are kept straight too. This note is here to + * make the reader aware of the switcheroo. + */ + CK_RV rv = CKR_OK; /* EXPORT DELETE START */ - int i; + BIGNUM public_exponent = {0}; + RSAkey rsakey; + uint32_t modulus_bytes; + + if (bkey == NULL) + return (CKR_ARGUMENTS_BAD); + + /* Must have modulus bits set */ + if (bkey->modulus_bits == 0) + return (CKR_ARGUMENTS_BAD); - /* Check to see if the recovered data is padded is 0x0002. */ - if (padbuf[0] != 0x00 || padbuf[1] != 0x02) { - return (CKR_ENCRYPTED_DATA_INVALID); + /* Must have public exponent set */ + if (bkey->pubexpo_bytes == 0 || bkey->pubexpo == NULL) + return (CKR_ARGUMENTS_BAD); + + /* Note: modulus_bits may not be same as (8 * sizeof (modulus)) */ + modulus_bytes = CRYPTO_BITS2BYTES(bkey->modulus_bits); + + /* Modulus length needs to be between min key size and max key size. */ + if ((modulus_bytes < MIN_RSA_KEYLENGTH_IN_BYTES) || + (modulus_bytes > MAX_RSA_KEYLENGTH_IN_BYTES)) { + return (CKR_KEY_SIZE_RANGE); } - /* Remove all the random bits up to 0x00 (= NULL char) */ - for (i = 2; (*plen - i) > 0; i++) { - if (padbuf[i] == 0x00) { - i++; - if (i < MIN_PKCS1_PADLEN) { - return (CKR_ENCRYPTED_DATA_INVALID); - } - *plen -= i; + /* + * Initialize the RSA key. + */ + if (RSA_key_init(&rsakey, modulus_bytes * 4, modulus_bytes * 4) != + BIG_OK) { + return (CKR_HOST_MEMORY); + } - return (CKR_OK); - } + /* Create a public exponent in bignum format. */ + 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); + + /* Generate RSA key pair. */ + 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); + + /* modulus_bytes = rsakey.n.len * (int)sizeof (BIG_CHUNK_TYPE); */ + 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); /* EXPORT DELETE END */ - return (CKR_ENCRYPTED_DATA_INVALID); + return (rv); } /* - * To create a block type "01" block for RSA PKCS signature process. - * - * The RSA PKCS Padding before Signing is in the following format: - * +------+--------------+----+-----------------------------+ - * |0x0001| 0xFFFF.......|0x00| DATA | - * +------+--------------+----+-----------------------------+ + * RSA encrypt operation */ CK_RV -soft_sign_rsa_pkcs_encode(uint8_t *pData, size_t dataLen, uint8_t *data, - size_t mbit_l) +rsa_encrypt(RSAbytekey *bkey, uchar_t *in, uint32_t in_len, uchar_t *out) { + CK_RV rv = CKR_OK; /* EXPORT DELETE START */ - size_t padlen; + BIGNUM msg; + RSAkey rsakey; + uint32_t modulus_bytes; + + if (bkey == NULL) + return (CKR_ARGUMENTS_BAD); - padlen = mbit_l - dataLen; - if (padlen < MIN_PKCS1_PADLEN) { - return (CKR_DATA_LEN_RANGE); + /* Must have modulus and public exponent set */ + if (bkey->modulus_bits == 0 || bkey->modulus == NULL || + bkey->pubexpo_bytes == 0 || bkey->pubexpo == NULL) + return (CKR_ARGUMENTS_BAD); + + /* Note: modulus_bits may not be same as (8 * sizeof (modulus)) */ + modulus_bytes = CRYPTO_BITS2BYTES(bkey->modulus_bits); + + if (bkey->pubexpo_bytes > modulus_bytes) { + return (CKR_KEY_SIZE_RANGE); } - padlen -= 3; - data[0] = 0x00; - data[1] = 0x01; -#ifdef _KERNEL - kmemset(data + 2, 0xFF, padlen); -#else - (void) memset(data + 2, 0xFF, padlen); -#endif - data[padlen + 2] = 0x00; - bcopy(pData, data + padlen + 3, dataLen); + /* psize and qsize for RSA_key_init is in bits. */ + if (RSA_key_init(&rsakey, modulus_bytes * 4, modulus_bytes * 4) != + BIG_OK) { + return (CKR_HOST_MEMORY); + } + + /* Size for big_init is in BIG_CHUNK_TYPE words. */ + if (big_init(&msg, CHARLEN2BIGNUMLEN(in_len)) != BIG_OK) { + rv = CKR_HOST_MEMORY; + goto clean2; + } + bytestring2bignum(&msg, in, in_len); + + /* Convert public exponent and modulus to big integer format. */ + 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; + } + + /* Perform RSA computation on big integer input data. */ + if (big_modexp(&msg, &msg, &(rsakey.e), &(rsakey.n), NULL) != + BIG_OK) { + rv = CKR_HOST_MEMORY; + goto clean3; + } + + /* Convert the big integer output data to octet string. */ + bignum2bytestring(out, &msg, modulus_bytes); + +clean3: + big_finish(&msg); +clean2: + RSA_key_finish(&rsakey); /* EXPORT DELETE END */ - return (CKR_OK); + return (rv); } - +/* + * RSA decrypt operation + */ CK_RV -soft_verify_rsa_pkcs_decode(uint8_t *data, int *mbit_l) +rsa_decrypt(RSAbytekey *bkey, uchar_t *in, uint32_t in_len, uchar_t *out) { + CK_RV rv = CKR_OK; /* EXPORT DELETE START */ - int i; + BIGNUM msg; + RSAkey rsakey; + uint32_t modulus_bytes; + + if (bkey == NULL) + return (CKR_ARGUMENTS_BAD); + + /* Must have modulus, prime1, prime2, expo1, expo2, and coeff set */ + 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); + + /* Note: modulus_bits may not be same as (8 * sizeof (modulus)) */ + modulus_bytes = CRYPTO_BITS2BYTES(bkey->modulus_bits); + + /* psize and qsize for RSA_key_init is in bits. */ + if (RSA_key_init(&rsakey, CRYPTO_BYTES2BITS(bkey->prime2_bytes), + CRYPTO_BYTES2BITS(bkey->prime1_bytes)) != BIG_OK) { + return (CKR_HOST_MEMORY); + } - /* Check to see if the padding of recovered data starts with 0x0001. */ - if ((data[0] != 0x00) || (data[1] != 0x01)) { - return (CKR_SIGNATURE_INVALID); + /* Size for big_init is in BIG_CHUNK_TYPE words. */ + if (big_init(&msg, CHARLEN2BIGNUMLEN(in_len)) != BIG_OK) { + rv = CKR_HOST_MEMORY; + goto clean3; } - /* Check to see if the recovered data is padded with 0xFFF...00. */ - for (i = 2; i < *mbit_l; i++) { - if (data[i] == 0x00) { - i++; - if (i < MIN_PKCS1_PADLEN) { - return (CKR_SIGNATURE_INVALID); - } - *mbit_l -= i; + /* Convert octet string input data to big integer format. */ + bytestring2bignum(&msg, in, in_len); - return (CKR_OK); - } else if (data[i] != 0xFF) { - return (CKR_SIGNATURE_INVALID); - } + /* Convert octet string modulus to big integer format. */ + bytestring2bignum(&(rsakey.n), bkey->modulus, modulus_bytes); + + if (big_cmp_abs(&msg, &(rsakey.n)) > 0) { + rv = CKR_DATA_LEN_RANGE; + goto clean4; } + /* Convert the rest of private key attributes to big integer format. */ + 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; + } + + /* Perform RSA computation on big integer input data. */ + 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; + } + + /* Convert the big integer output data to octet string. */ + bignum2bytestring(out, &msg, modulus_bytes); + +clean4: + big_finish(&msg); +clean3: + RSA_key_finish(&rsakey); + /* EXPORT DELETE END */ - return (CKR_SIGNATURE_INVALID); + return (rv); } |