rsa.c revision d3b2efc749bec3b757d5f018cf78c9a09fa29cb3
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* RSA provider for the Kernel Cryptographic Framework (KCF)
*/
#include <sys/sysmacros.h>
#define _SHA2_IMPL
#include <sha1/sha1_impl.h>
#include <sha2/sha2_impl.h>
#define _RSA_FIPS_POST
#include <rsa/rsa_impl.h>
extern struct mod_ops mod_cryptoops;
/*
* Module linkage information for the kernel.
*/
static struct modlcrypto modlcrypto = {
"RSA Kernel SW Provider"
};
static struct modlinkage modlinkage = {
(void *)&modlcrypto,
};
/*
* CSPI information (entry points, provider info, etc.)
*/
typedef enum rsa_mech_type {
RSA_PKCS_MECH_INFO_TYPE, /* SUN_CKM_RSA_PKCS */
RSA_X_509_MECH_INFO_TYPE, /* SUN_CKM_RSA_X_509 */
MD5_RSA_PKCS_MECH_INFO_TYPE, /* SUN_MD5_RSA_PKCS */
SHA1_RSA_PKCS_MECH_INFO_TYPE, /* SUN_SHA1_RSA_PKCS */
SHA256_RSA_PKCS_MECH_INFO_TYPE, /* SUN_SHA256_RSA_PKCS */
SHA384_RSA_PKCS_MECH_INFO_TYPE, /* SUN_SHA384_RSA_PKCS */
SHA512_RSA_PKCS_MECH_INFO_TYPE /* SUN_SHA512_RSA_PKCS */
/*
* Context for RSA_PKCS and RSA_X_509 mechanisms.
*/
typedef struct rsa_ctx {
} rsa_ctx_t;
/*
* Context for MD5_RSA_PKCS and SHA*_RSA_PKCS mechanisms.
*/
typedef struct digest_rsa_ctx {
union {
} dctx_u;
/*
* Mechanism info structure passed to KCF during registration.
*/
static crypto_mech_info_t rsa_mech_info_tab[] = {
/* RSA_PKCS */
/* RSA_X_509 */
/* MD5_RSA_PKCS */
/* SHA1_RSA_PKCS */
/* SHA256_RSA_PKCS */
/* SHA384_RSA_PKCS */
/* SHA512_RSA_PKCS */
};
#define RSA_VALID_MECH(mech) \
/* operations are in-place if the output buffer is NULL */
static crypto_control_ops_t rsa_control_ops = {
};
/*
* The RSA mechanisms do not have multiple-part cipher operations.
* So, the update and final routines are set to NULL.
*/
static crypto_cipher_ops_t rsa_cipher_ops = {
NULL,
NULL,
NULL,
NULL,
};
/*
* We use the same routine for sign_init and sign_recover_init fields
* as they do the same thing. Same holds for sign and sign_recover fields,
* and sign_atomic and sign_recover_atomic fields.
*/
static crypto_sign_ops_t rsa_sign_ops = {
};
static int rsa_verify_recover_atomic(crypto_provider_handle_t,
/*
* We use the same routine (rsa_sign_verify_common_init) for verify_init
* and verify_recover_init fields as they do the same thing.
*/
static crypto_verify_ops_t rsa_verify_ops = {
};
static int rsa_free_context(crypto_ctx_t *);
static crypto_ctx_ops_t rsa_ctx_ops = {
NULL,
};
static void rsa_POST(int *);
static crypto_fips140_ops_t rsa_fips140_ops = {
};
static crypto_ops_t rsa_crypto_ops = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static crypto_provider_info_t rsa_prov_info = {
"RSA Software Provider",
{&modlinkage},
NULL,
sizeof (rsa_mech_info_tab)/sizeof (crypto_mech_info_t),
};
crypto_data_t *, crypto_data_t *, int);
crypto_data_t *, crypto_data_t *, int);
crypto_data_t *, crypto_data_t *, int);
crypto_data_t *, crypto_data_t *, int);
/* EXPORT DELETE START */
int, uchar_t *, int, int);
uchar_t *, int);
/* EXPORT DELETE END */
int
_init(void)
{
int ret;
return (ret);
/* Register with KCF. If the registration fails, remove the module. */
(void) mod_remove(&modlinkage);
return (EACCES);
}
return (0);
}
int
_fini(void)
{
/* Unregister from KCF if module is registered */
if (rsa_prov_handle != NULL) {
return (EBUSY);
}
return (mod_remove(&modlinkage));
}
int
{
}
/* ARGSUSED */
static void
{
}
static int
{
int rv = CRYPTO_FAILED;
/* EXPORT DELETE START */
if (!RSA_VALID_MECH(mechanism))
return (CRYPTO_MECHANISM_INVALID);
/*
* We only support RSA keys that are passed as a list of
* object attributes.
*/
return (CRYPTO_KEY_TYPE_INCONSISTENT);
}
&modulus_len)) != CRYPTO_SUCCESS) {
return (rv);
}
if (modulus_len < MIN_RSA_KEYLENGTH_IN_BYTES ||
return (CRYPTO_KEY_SIZE_RANGE);
/* EXPORT DELETE END */
return (rv);
}
void
{
int i = 0;
while (i < len)
}
/*
* This function guarantees to return non-zero random numbers.
* random_get_pseudo_bytes(), may return zeros.
*/
int
{
int rv;
size_t i = 0;
return (rv);
/*
* Walk through the returned random numbers pointed by ran_out,
* and look for any random number which is zero.
* If we find zero, call random_get_pseudo_bytes() to generate
* another 32 random numbers pool. Replace any zeros in ran_out[]
* from the random number in pool.
*/
while (i < ran_len) {
if (ran_out[i] != 0) {
i++;
continue;
}
/*
* Note that it is 'while' so we are guaranteed a
* non-zero value on exit.
*/
if (ebc == 0) {
/* refresh extrarand */
extrarand_len = sizeof (extrarand);
extrarand_len)) != 0) {
return (rv);
}
ebc = extrarand_len;
}
/* Replace zero with byte from extrarand. */
-- ebc;
/*
* the next pass through the loop.
*/
}
return (CRYPTO_SUCCESS);
}
static int
{
int len;
case CRYPTO_DATA_RAW:
case CRYPTO_DATA_UIO:
case CRYPTO_DATA_MBLK:
}
return (CRYPTO_FAILED);
}
/* ARGSUSED */
static int
{
int rv;
int kmflag;
return (rv);
/*
* Allocate a RSA context.
*/
return (CRYPTO_HOST_MEMORY);
kmflag)) != CRYPTO_SUCCESS) {
return (rv);
}
return (CRYPTO_SUCCESS);
}
/* ARGSUSED */
static int
{
int rv;
/*
* Note on the KM_SLEEP flag passed to the routine below -
* rsa_encrypt() is a single-part encryption routine which is
* always synchronous, we can safely pass KM_SLEEP here.
*/
if (rv != CRYPTO_BUFFER_TOO_SMALL)
(void) rsa_free_context(ctx);
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
return (rv);
}
static int
{
else
}
return (CRYPTO_SUCCESS);
}
static int
{
int rv = CRYPTO_FAILED;
/* EXPORT DELETE START */
int plen;
&modulus_len)) != CRYPTO_SUCCESS) {
return (rv);
}
if (mech_type == RSA_PKCS_MECH_INFO_TYPE) {
return (CRYPTO_DATA_LEN_RANGE);
} else {
if (plen > modulus_len)
return (CRYPTO_DATA_LEN_RANGE);
}
/*
* Output buf len must not be less than RSA modulus size.
*/
return (CRYPTO_BUFFER_TOO_SMALL);
}
!= CRYPTO_SUCCESS)
return (rv);
if (mech_type == RSA_PKCS_MECH_INFO_TYPE) {
if (rv != CRYPTO_SUCCESS)
return (rv);
} else {
}
if (rv == CRYPTO_SUCCESS) {
/* copy out to ciphertext */
return (rv);
}
/* EXPORT DELETE END */
return (rv);
}
/* EXPORT DELETE START */
static int
{
int rv;
if (is_public) {
return (rv);
} else {
/*
* SUN_CKA_PRIVATE_EXPONENT is a required attribute for a
* RSA secret key. See the comments in core_rsa_decrypt
* routine which calls this routine with a private key.
*/
return (rv);
}
&modulus_len)) != CRYPTO_SUCCESS) {
return (rv);
}
return (CRYPTO_HOST_MEMORY);
/* psize and qsize for RSA_key_init is in bits. */
goto clean1;
}
/* Size for big_init is in BIG_CHUNK_TYPE words. */
goto clean2;
}
/* Convert octet string exponent to big integer format. */
/* Convert octet string modulus to big integer format. */
/* Convert octet string input data to big integer format. */
goto clean3;
}
/* Perform RSA computation on big integer input data. */
!= BIG_OK) {
goto clean3;
}
/* Convert the big integer output data to octet string. */
/*
* Should not free modulus and expo as both are just pointers
* to an attribute value buffer from the caller.
*/
big_finish(&msg);
return (rv);
}
/* EXPORT DELETE END */
/* ARGSUSED */
static int
{
int rv;
/* See the comments on KM_SLEEP flag in rsa_encrypt() */
if (rv != CRYPTO_BUFFER_TOO_SMALL)
(void) rsa_free_context(ctx);
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
return (rv);
}
static int
{
int rv = CRYPTO_FAILED;
/* EXPORT DELETE START */
int plain_len;
&modulus_len)) != CRYPTO_SUCCESS) {
return (rv);
}
/*
* Ciphertext length must be equal to RSA modulus size.
*/
return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
!= CRYPTO_SUCCESS)
return (rv);
if (rv == CRYPTO_SUCCESS) {
if (mech_type == RSA_PKCS_MECH_INFO_TYPE) {
/* Strip off the PKCS block formatting data. */
&plain_len);
if (rv != CRYPTO_SUCCESS)
return (rv);
}
return (CRYPTO_BUFFER_TOO_SMALL);
}
if ((rv = crypto_put_output_data(
return (rv);
}
/* EXPORT DELETE END */
return (rv);
}
/* EXPORT DELETE START */
static int
{
int rv;
&modulus_len)) != CRYPTO_SUCCESS) {
return (rv);
}
/*
* The following attributes are not required to be
* present in a RSA secret key. If any of them is not present
* we call the encrypt routine with a flag indicating use of
* private exponent (d). Note that SUN_CKA_PRIVATE_EXPONENT is
* a required attribute for a RSA secret key.
*/
!= CRYPTO_SUCCESS) ||
!= CRYPTO_SUCCESS) ||
!= CRYPTO_SUCCESS) ||
!= CRYPTO_SUCCESS) ||
!= CRYPTO_SUCCESS)) {
}
return (CRYPTO_HOST_MEMORY);
/* psize and qsize for RSA_key_init is in bits. */
goto clean1;
}
/* Size for big_init is in BIG_CHUNK_TYPE words. */
goto clean2;
}
/* Convert octet string input data to big integer format. */
/* Convert octet string modulus to big integer format. */
goto clean3;
}
/* Convert the rest of private key attributes to big integer format. */
goto clean3;
}
/* Perform RSA computation on big integer input data. */
goto clean3;
}
/* Convert the big integer output data to octet string. */
/*
* Should not free modulus and friends as they are just pointers
* to an attribute value buffer from the caller.
*/
big_finish(&msg);
return (rv);
}
/* EXPORT DELETE END */
/* ARGSUSED */
static int
{
int rv;
int kmflag;
return (rv);
/*
* Allocate a RSA context.
*/
break;
default:
break;
}
return (CRYPTO_HOST_MEMORY);
kmflag)) != CRYPTO_SUCCESS) {
break;
default:
break;
}
return (rv);
}
break;
break;
break;
break;
break;
}
return (CRYPTO_SUCCESS);
}
#define SHA1_DIGEST_SIZE 20
#define MD5_DIGEST_SIZE 16
static int
{
int rv = CRYPTO_FAILED;
/* EXPORT DELETE START */
/* The der_data size is enough for MD5 also */
if (mech_type == RSA_PKCS_MECH_INFO_TYPE ||
return (CRYPTO_MECHANISM_INVALID);
/*
* We need to do the BUFFER_TOO_SMALL check before digesting
* the data. No check is needed for verify as signature is not
* an output argument for verify.
*/
if (flag & CRYPTO_DO_SIGN) {
return (rv);
}
return (CRYPTO_BUFFER_TOO_SMALL);
}
}
if (mech_type == MD5_RSA_PKCS_MECH_INFO_TYPE)
else if (mech_type == SHA1_RSA_PKCS_MECH_INFO_TYPE)
else
if (rv != CRYPTO_SUCCESS)
return (rv);
/*
* Prepare the DER encoding of the DigestInfo value as follows:
* MD5: MD5_DER_PREFIX || H
* SHA-1: SHA1_DER_PREFIX || H
*
* See rsa_impl.c for more details.
*/
switch (mech_type) {
break;
break;
break;
break;
break;
}
/*
* Now, we are ready to sign or verify the DER_ENCODED data.
*/
if (flag & CRYPTO_DO_SIGN)
else
/* EXPORT DELETE END */
return (rv);
}
static int
{
int rv = CRYPTO_FAILED;
/* EXPORT DELETE START */
int dlen;
&modulus_len)) != CRYPTO_SUCCESS) {
return (rv);
}
switch (mech_type) {
case RSA_PKCS_MECH_INFO_TYPE:
return (CRYPTO_DATA_LEN_RANGE);
break;
case RSA_X_509_MECH_INFO_TYPE:
if (dlen > modulus_len)
return (CRYPTO_DATA_LEN_RANGE);
break;
}
return (CRYPTO_BUFFER_TOO_SMALL);
}
!= CRYPTO_SUCCESS)
return (rv);
switch (mech_type) {
case RSA_PKCS_MECH_INFO_TYPE:
/*
* Add PKCS padding to the input data to format a block
* type "01" encryption block.
*/
if (rv != CRYPTO_SUCCESS)
return (rv);
break;
case RSA_X_509_MECH_INFO_TYPE:
break;
}
kmflag);
if (rv == CRYPTO_SUCCESS) {
/* copy out to signature */
return (rv);
}
/* EXPORT DELETE END */
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
/* See the comments on KM_SLEEP flag in rsa_encrypt() */
break;
default:
break;
}
if (rv != CRYPTO_BUFFER_TOO_SMALL)
(void) rsa_free_context(ctx);
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
if (mech_type == RSA_PKCS_MECH_INFO_TYPE ||
return (CRYPTO_MECHANISM_INVALID);
if (mech_type == MD5_RSA_PKCS_MECH_INFO_TYPE)
else if (mech_type == SHA1_RSA_PKCS_MECH_INFO_TYPE)
else
return (rv);
}
static int
{
int rv;
if (rv != CRYPTO_BUFFER_TOO_SMALL)
(void) rsa_free_context(ctx);
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
return (rv);
else {
break;
break;
break;
break;
break;
}
}
return (rv);
}
static int
{
int rv = CRYPTO_FAILED;
/* EXPORT DELETE START */
&modulus_len)) != CRYPTO_SUCCESS) {
return (rv);
}
return (CRYPTO_SIGNATURE_LEN_RANGE);
!= CRYPTO_SUCCESS)
return (rv);
if (rv != CRYPTO_SUCCESS)
return (rv);
if (mech_type == RSA_X_509_MECH_INFO_TYPE) {
} else {
int data_len = modulus_len;
/*
* Strip off the encoded padding bytes in front of the
* recovered data, then compare the recovered data with
* the original data.
*/
if (rv != CRYPTO_SUCCESS)
return (rv);
return (CRYPTO_SIGNATURE_LEN_RANGE);
- data_len)) != 0)
}
/* EXPORT DELETE END */
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
/* See the comments on KM_SLEEP flag in rsa_encrypt() */
break;
default:
break;
}
if (rv != CRYPTO_BUFFER_TOO_SMALL)
(void) rsa_free_context(ctx);
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
break;
break;
break;
default:
return (CRYPTO_MECHANISM_INVALID);
}
return (rv);
}
static int
{
int rv;
if (rv != CRYPTO_BUFFER_TOO_SMALL)
(void) rsa_free_context(ctx);
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
return (rv);
else {
break;
break;
break;
break;
break;
}
}
return (rv);
}
static int
{
int rv = CRYPTO_FAILED;
/* EXPORT DELETE START */
int data_len;
&modulus_len)) != CRYPTO_SUCCESS) {
return (rv);
}
return (CRYPTO_SIGNATURE_LEN_RANGE);
!= CRYPTO_SUCCESS)
return (rv);
if (rv != CRYPTO_SUCCESS)
return (rv);
if (mech_type == RSA_PKCS_MECH_INFO_TYPE) {
/*
* Strip off the encoded padding bytes in front of the
* recovered data, then compare the recovered data with
* the original data.
*/
if (rv != CRYPTO_SUCCESS)
return (rv);
}
return (CRYPTO_BUFFER_TOO_SMALL);
}
return (rv);
/* EXPORT DELETE END */
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
/* See the comments on KM_SLEEP flag in rsa_encrypt() */
if (rv != CRYPTO_BUFFER_TOO_SMALL)
(void) rsa_free_context(ctx);
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
return (rv);
}
/*
* RSA Power-Up Self-Test
*/
void
{
*rc = fips_rsa_post();
}