softRSA.c revision f66d273d14eede3a1bb803a39414588d8f143a98
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* or http://www.opensolaris.org/os/licensing.
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <bignum.h>
#include "softGlobal.h"
#include "softSession.h"
#include "softObject.h"
#include "softOps.h"
#include "softRSA.h"
#include "softMAC.h"
#include "softRandom.h"
#include "softCrypt.h"
CK_RV
soft_rsa_encrypt(soft_object_t *key, CK_BYTE_PTR in, uint32_t in_len,
CK_BYTE_PTR out, int realpublic)
{
CK_RV rv = CKR_OK;
/* EXPORT DELETE START */
uchar_t expo[MAX_KEY_ATTR_BUFLEN];
uchar_t modulus[MAX_KEY_ATTR_BUFLEN];
uint32_t expo_len = sizeof (expo);
uint32_t modulus_len = sizeof (modulus);
BIGNUM msg;
RSAkey *rsakey;
if (realpublic) {
rv = soft_get_public_attr(key, CKA_PUBLIC_EXPONENT, expo,
&expo_len);
if (rv != CKR_OK) {
goto clean1;
}
} else {
rv = soft_get_private_attr(key, CKA_PRIVATE_EXPONENT, expo,
&expo_len);
if (rv != CKR_OK) {
goto clean1;
}
}
rv = soft_get_public_attr(key, CKA_MODULUS, modulus, &modulus_len);
if (rv != CKR_OK) {
goto clean1;
}
if (expo_len > modulus_len) {
rv = CKR_KEY_SIZE_RANGE;
goto clean1;
}
rsakey = calloc(1, sizeof (RSAkey));
if (rsakey == NULL) {
rv = CKR_HOST_MEMORY;
goto clean1;
}
if (RSA_key_init(rsakey, modulus_len * 4, modulus_len * 4) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean4;
}
/* Size for big_init is in (32-bit) words. */
if (big_init(&msg, (in_len + (int)sizeof (uint32_t) - 1) /
(int)sizeof (uint32_t)) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean5;
}
/* Convert octet string exponent to big integer format. */
bytestring2bignum(&(rsakey->e), expo, expo_len);
/* Convert octet string modulus to big integer format. */
bytestring2bignum(&(rsakey->n), modulus, modulus_len);
/* Convert octet string input data to big integer format. */
bytestring2bignum(&msg, (uchar_t *)in, in_len);
if (big_cmp_abs(&msg, &(rsakey->n)) > 0) {
rv = CKR_DATA_LEN_RANGE;
goto clean6;
}
/* 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 clean6;
}
/* Convert the big integer output data to octet string. */
bignum2bytestring((uchar_t *)out, &msg, modulus_len);
clean6:
big_finish(&msg);
clean5:
RSA_key_finish(rsakey);
clean4:
free(rsakey);
clean1:
/* EXPORT DELETE END */
return (rv);
}
CK_RV
soft_rsa_decrypt(soft_object_t *key, CK_BYTE_PTR in, uint32_t in_len,
CK_BYTE_PTR out)
{
CK_RV rv = CKR_OK;
/* EXPORT DELETE START */
uchar_t modulus[MAX_KEY_ATTR_BUFLEN];
uchar_t prime1[MAX_KEY_ATTR_BUFLEN];
uchar_t prime2[MAX_KEY_ATTR_BUFLEN];
uchar_t expo1[MAX_KEY_ATTR_BUFLEN];
uchar_t expo2[MAX_KEY_ATTR_BUFLEN];
uchar_t coef[MAX_KEY_ATTR_BUFLEN];
uint32_t modulus_len = sizeof (modulus);
uint32_t prime1_len = sizeof (prime1);
uint32_t prime2_len = sizeof (prime2);
uint32_t expo1_len = sizeof (expo1);
uint32_t expo2_len = sizeof (expo2);
uint32_t coef_len = sizeof (coef);
BIGNUM msg;
RSAkey *rsakey;
rv = soft_get_private_attr(key, CKA_MODULUS, modulus, &modulus_len);
if (rv != CKR_OK) {
goto clean1;
}
rv = soft_get_private_attr(key, CKA_PRIME_1, prime1, &prime1_len);
if ((prime1_len == 0) && (rv == CKR_OK)) {
rv = soft_rsa_encrypt(key, in, in_len, out, 0);
goto clean1;
} else {
if (rv != CKR_OK)
goto clean1;
}
rv = soft_get_private_attr(key, CKA_PRIME_2, prime2, &prime2_len);
if ((prime2_len == 0) && (rv == CKR_OK)) {
rv = soft_rsa_encrypt(key, in, in_len, out, 0);
goto clean1;
} else {
if (rv != CKR_OK)
goto clean1;
}
rv = soft_get_private_attr(key, CKA_EXPONENT_1, expo1, &expo1_len);
if ((expo1_len == 0) && (rv == CKR_OK)) {
rv = soft_rsa_encrypt(key, in, in_len, out, 0);
goto clean1;
} else {
if (rv != CKR_OK)
goto clean1;
}
rv = soft_get_private_attr(key, CKA_EXPONENT_2, expo2, &expo2_len);
if ((expo2_len == 0) && (rv == CKR_OK)) {
rv = soft_rsa_encrypt(key, in, in_len, out, 0);
goto clean1;
} else {
if (rv != CKR_OK)
goto clean1;
}
rv = soft_get_private_attr(key, CKA_COEFFICIENT, coef, &coef_len);
if ((coef_len == 0) && (rv == CKR_OK)) {
rv = soft_rsa_encrypt(key, in, in_len, out, 0);
goto clean1;
} else {
if (rv != CKR_OK)
goto clean1;
}
rsakey = calloc(1, sizeof (RSAkey));
if (rsakey == NULL) {
rv = CKR_HOST_MEMORY;
goto clean1;
}
/* psize and qsize for RSA_key_init is in bits. */
if (RSA_key_init(rsakey, prime2_len * 8, prime1_len * 8) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean8;
}
/* Size for big_init is in (32-bit) words. */
if (big_init(&msg, (in_len + (int)sizeof (uint32_t) - 1) /
(int)sizeof (uint32_t)) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean9;
}
/* Convert octet string input data to big integer format. */
bytestring2bignum(&msg, (uchar_t *)in, in_len);
/* Convert octet string modulus to big integer format. */
bytestring2bignum(&(rsakey->n), modulus, modulus_len);
if (big_cmp_abs(&msg, &(rsakey->n)) > 0) {
rv = CKR_DATA_LEN_RANGE;
goto clean10;
}
/* Convert the rest of private key attributes to big integer format. */
bytestring2bignum(&(rsakey->dmodpminus1), expo2, expo2_len);
bytestring2bignum(&(rsakey->dmodqminus1), expo1, expo1_len);
bytestring2bignum(&(rsakey->p), prime2, prime2_len);
bytestring2bignum(&(rsakey->q), prime1, prime1_len);
bytestring2bignum(&(rsakey->pinvmodq), coef, coef_len);
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 clean10;
}
/* 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 clean10;
}
/* Convert the big integer output data to octet string. */
bignum2bytestring((uchar_t *)out, &msg, modulus_len);
clean10:
big_finish(&msg);
clean9:
RSA_key_finish(rsakey);
clean8:
free(rsakey);
clean1:
/* EXPORT DELETE END */
return (rv);
}
/*
* Allocate a RSA context for the active encryption or decryption operation.
* This function is called without the session lock held.
*/
CK_RV
soft_rsa_crypt_init_common(soft_session_t *session_p,
CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
boolean_t encrypt)
{
soft_rsa_ctx_t *rsa_ctx;
soft_object_t *tmp_key = NULL;
CK_RV rv;
rsa_ctx = calloc(1, sizeof (soft_rsa_ctx_t));
if (rsa_ctx == NULL) {
return (CKR_HOST_MEMORY);
}
/*
* Make a copy of the encryption or decryption key, and save it
* in the RSA crypto context since it will be used later for
* encryption/decryption. We don't want to hold any object reference
* on this original key while doing encryption/decryption.
*/
(void) pthread_mutex_lock(&key_p->object_mutex);
rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH,
NULL);
if ((rv != CKR_OK) || (tmp_key == NULL)) {
/* Most likely we ran out of space. */
(void) pthread_mutex_unlock(&key_p->object_mutex);
free(rsa_ctx);
return (rv);
}
/* No need to hold the lock on the old object. */
(void) pthread_mutex_unlock(&key_p->object_mutex);
rsa_ctx->key = tmp_key;
(void) pthread_mutex_lock(&session_p->session_mutex);
if (encrypt) {
/* Called by C_EncryptInit. */
session_p->encrypt.context = rsa_ctx;
session_p->encrypt.mech.mechanism = pMechanism->mechanism;
} else {
/* Called by C_DecryptInit. */
session_p->decrypt.context = rsa_ctx;
session_p->decrypt.mech.mechanism = pMechanism->mechanism;
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (CKR_OK);
}
CK_RV
soft_rsa_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
CK_ULONG_PTR pulEncryptedLen, CK_MECHANISM_TYPE mechanism)
{
soft_rsa_ctx_t *rsa_ctx = session_p->encrypt.context;
soft_object_t *key = rsa_ctx->key;
uchar_t modulus[MAX_KEY_ATTR_BUFLEN];
uint32_t modulus_len = sizeof (modulus);
CK_BYTE plain_data[MAX_RSA_KEYLENGTH_IN_BYTES];
CK_BYTE cipher_data[MAX_RSA_KEYLENGTH_IN_BYTES];
CK_RV rv = CKR_OK;
rv = soft_get_public_attr(key, CKA_MODULUS, modulus, &modulus_len);
if (rv != CKR_OK) {
goto clean_exit;
}
if (pEncrypted == NULL) {
/*
* Application asks for the length of the output buffer
* to hold the ciphertext.
*/
*pulEncryptedLen = modulus_len;
rv = CKR_OK;
goto clean1;
}
if (mechanism == CKM_RSA_PKCS) {
/*
* Input data length needs to be <=
* modulus length-MIN_PKCS1_PADLEN.
*/
if (ulDataLen > ((CK_ULONG)modulus_len - MIN_PKCS1_PADLEN)) {
*pulEncryptedLen = modulus_len;
rv = CKR_DATA_LEN_RANGE;
goto clean_exit;
}
} else {
/* Input data length needs to be <= modulus length. */
if (ulDataLen > (CK_ULONG)modulus_len) {
*pulEncryptedLen = modulus_len;
rv = CKR_DATA_LEN_RANGE;
goto clean_exit;
}
}
/* Is the application-supplied buffer large enough? */
if (*pulEncryptedLen < (CK_ULONG)modulus_len) {
*pulEncryptedLen = modulus_len;
rv = CKR_BUFFER_TOO_SMALL;
goto clean1;
}
if (mechanism == CKM_RSA_PKCS) {
/*
* Add PKCS padding to the input data to format a block
* type "02" encryption block.
*/
rv = soft_encrypt_rsa_pkcs_encode(pData, ulDataLen, plain_data,
modulus_len);
if (rv != CKR_OK)
goto clean_exit;
} else {
/* Pad zeros for the leading bytes of the input data. */
(void) memset(plain_data, 0x0, modulus_len - ulDataLen);
(void) memcpy(&plain_data[modulus_len - ulDataLen], pData,
ulDataLen);
}
rv = soft_rsa_encrypt(key, plain_data, modulus_len, cipher_data, 1);
if (rv == CKR_OK) {
(void) memcpy(pEncrypted, cipher_data, modulus_len);
*pulEncryptedLen = modulus_len;
}
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
free(session_p->encrypt.context);
session_p->encrypt.context = NULL;
(void) pthread_mutex_unlock(&session_p->session_mutex);
soft_cleanup_object(key);
free(key);
clean1:
return (rv);
}
CK_RV
soft_rsa_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
CK_ULONG_PTR pulDataLen, CK_MECHANISM_TYPE mechanism)
{
soft_rsa_ctx_t *rsa_ctx = session_p->decrypt.context;
soft_object_t *key = rsa_ctx->key;
uchar_t modulus[MAX_KEY_ATTR_BUFLEN];
uint32_t modulus_len = sizeof (modulus);
CK_BYTE plain_data[MAX_RSA_KEYLENGTH_IN_BYTES];
CK_RV rv = CKR_OK;
rv = soft_get_private_attr(key, CKA_MODULUS, modulus, &modulus_len);
if (rv != CKR_OK) {
goto clean_exit;
}
if (ulEncryptedLen != (CK_ULONG)modulus_len) {
rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
goto clean_exit;
}
if (pData == NULL) {
/*
* Application asks for the length of the output buffer
* to hold the recovered data.
*/
*pulDataLen = modulus_len;
rv = CKR_OK;
goto clean1;
}
if (mechanism == CKM_RSA_X_509) {
if (*pulDataLen < (CK_ULONG)modulus_len) {
*pulDataLen = modulus_len;
rv = CKR_BUFFER_TOO_SMALL;
goto clean1;
}
}
rv = soft_rsa_decrypt(key, pEncrypted, modulus_len, plain_data);
if (rv != CKR_OK) {
goto clean_exit;
}
if (mechanism == CKM_RSA_PKCS) {
int plain_len = modulus_len;
uint32_t num_padding;
/* Strip off the PKCS block formatting data. */
rv = soft_decrypt_rsa_pkcs_decode(plain_data, &plain_len);
if (rv != CKR_OK)
goto clean_exit;
num_padding = modulus_len - plain_len;
if (ulEncryptedLen - num_padding > *pulDataLen) {
*pulDataLen = plain_len;
rv = CKR_BUFFER_TOO_SMALL;
goto clean1;
}
(void) memcpy(pData, &plain_data[num_padding], plain_len);
*pulDataLen = plain_len;
} else {
(void) memcpy(pData, plain_data, modulus_len);
*pulDataLen = modulus_len;
}
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
free(session_p->decrypt.context);
session_p->decrypt.context = NULL;
(void) pthread_mutex_unlock(&session_p->session_mutex);
soft_cleanup_object(key);
free(key);
clean1:
return (rv);
}
/*
* Allocate a RSA context for the active sign or verify operation.
* This function is called without the session lock held.
*/
CK_RV
soft_rsa_sign_verify_init_common(soft_session_t *session_p,
CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
boolean_t sign)
{
CK_RV rv = CKR_OK;
soft_rsa_ctx_t *rsa_ctx;
CK_MECHANISM digest_mech;
soft_object_t *tmp_key = NULL;
if (sign) {
if ((key_p->class != CKO_PRIVATE_KEY) ||
(key_p->key_type != CKK_RSA))
return (CKR_KEY_TYPE_INCONSISTENT);
} else {
if ((key_p->class != CKO_PUBLIC_KEY) ||
(key_p->key_type != CKK_RSA))
return (CKR_KEY_TYPE_INCONSISTENT);
}
switch (pMechanism->mechanism) {
case CKM_MD5_RSA_PKCS:
digest_mech.mechanism = CKM_MD5;
rv = soft_digest_init_internal(session_p, &digest_mech);
if (rv != CKR_OK)
return (rv);
break;
case CKM_SHA1_RSA_PKCS:
digest_mech.mechanism = CKM_SHA_1;
rv = soft_digest_init_internal(session_p, &digest_mech);
if (rv != CKR_OK)
return (rv);
break;
case CKM_SHA256_RSA_PKCS:
digest_mech.mechanism = CKM_SHA256;
rv = soft_digest_init_internal(session_p, &digest_mech);
if (rv != CKR_OK)
return (rv);
break;
case CKM_SHA384_RSA_PKCS:
digest_mech.mechanism = CKM_SHA384;
rv = soft_digest_init_internal(session_p, &digest_mech);
if (rv != CKR_OK)
return (rv);
break;
case CKM_SHA512_RSA_PKCS:
digest_mech.mechanism = CKM_SHA512;
rv = soft_digest_init_internal(session_p, &digest_mech);
if (rv != CKR_OK)
return (rv);
break;
}
rsa_ctx = malloc(sizeof (soft_rsa_ctx_t));
if (rsa_ctx == NULL) {
rv = CKR_HOST_MEMORY;
goto clean_exit;
}
(void) pthread_mutex_lock(&key_p->object_mutex);
rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH,
NULL);
if ((rv != CKR_OK) || (tmp_key == NULL)) {
/* Most likely we ran out of space. */
(void) pthread_mutex_unlock(&key_p->object_mutex);
free(rsa_ctx);
goto clean_exit;
}
/* No need to hold the lock on the old object. */
(void) pthread_mutex_unlock(&key_p->object_mutex);
rsa_ctx->key = tmp_key;
(void) pthread_mutex_lock(&session_p->session_mutex);
if (sign) {
session_p->sign.context = rsa_ctx;
session_p->sign.mech.mechanism = pMechanism->mechanism;
} else {
session_p->verify.context = rsa_ctx;
session_p->verify.mech.mechanism = pMechanism->mechanism;
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (CKR_OK);
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
if (session_p->digest.context != NULL) {
free(session_p->digest.context);
session_p->digest.context = NULL;
session_p->digest.flags = 0;
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}
CK_RV
soft_rsa_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
CK_ULONG_PTR pulSignedLen, CK_MECHANISM_TYPE mechanism)
{
CK_RV rv = CKR_OK;
soft_rsa_ctx_t *rsa_ctx = session_p->sign.context;
soft_object_t *key = rsa_ctx->key;
uchar_t modulus[MAX_KEY_ATTR_BUFLEN];
uint32_t modulus_len = sizeof (modulus);
CK_BYTE plain_data[MAX_RSA_KEYLENGTH_IN_BYTES];
CK_BYTE signed_data[MAX_RSA_KEYLENGTH_IN_BYTES];
rv = soft_get_private_attr(key, CKA_MODULUS, modulus, &modulus_len);
if (rv != CKR_OK) {
goto clean_exit;
}
if (pSigned == NULL) {
/* Application asks for the length of the output buffer. */
*pulSignedLen = modulus_len;
rv = CKR_OK;
goto clean1;
}
switch (mechanism) {
case CKM_RSA_PKCS:
/*
* Input data length needs to be <=
* modulus length-MIN_PKCS1_PADLEN.
*/
if (ulDataLen > ((CK_ULONG)modulus_len - MIN_PKCS1_PADLEN)) {
*pulSignedLen = modulus_len;
rv = CKR_DATA_LEN_RANGE;
goto clean_exit;
}
break;
case CKM_RSA_X_509:
/* Input data length needs to be <= modulus length. */
if (ulDataLen > (CK_ULONG)modulus_len) {
*pulSignedLen = modulus_len;
rv = CKR_DATA_LEN_RANGE;
goto clean_exit;
}
break;
}
/* Is the application-supplied buffer large enough? */
if (*pulSignedLen < (CK_ULONG)modulus_len) {
*pulSignedLen = modulus_len;
rv = CKR_BUFFER_TOO_SMALL;
goto clean1;
}
switch (mechanism) {
case CKM_RSA_PKCS:
case CKM_MD5_RSA_PKCS:
case CKM_SHA1_RSA_PKCS:
case CKM_SHA256_RSA_PKCS:
case CKM_SHA384_RSA_PKCS:
case CKM_SHA512_RSA_PKCS:
/*
* Add PKCS padding to the input data to format a block
* type "01" encryption block.
*/
rv = soft_sign_rsa_pkcs_encode(pData, ulDataLen, plain_data,
modulus_len);
if (rv != CKR_OK) {
goto clean_exit;
}
break;
case CKM_RSA_X_509:
/* Pad zeros for the leading bytes of the input data. */
(void) memset(plain_data, 0x0, modulus_len - ulDataLen);
(void) memcpy(&plain_data[modulus_len - ulDataLen], pData,
ulDataLen);
break;
}
/*
* Perform RSA encryption with the signer's RSA private key
* for signature process.
*/
rv = soft_rsa_decrypt(key, plain_data, modulus_len, signed_data);
if (rv == CKR_OK) {
(void) memcpy(pSigned, signed_data, modulus_len);
*pulSignedLen = modulus_len;
}
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
free(session_p->sign.context);
session_p->sign.context = NULL;
if (session_p->digest.context != NULL) {
free(session_p->digest.context);
session_p->digest.context = NULL;
session_p->digest.flags = 0;
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
soft_cleanup_object(key);
free(key);
clean1:
return (rv);
}
CK_RV
soft_rsa_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
CK_ULONG ulSignatureLen, CK_MECHANISM_TYPE mechanism)
{
CK_RV rv = CKR_OK;
soft_rsa_ctx_t *rsa_ctx = session_p->verify.context;
soft_object_t *key = rsa_ctx->key;
uchar_t modulus[MAX_KEY_ATTR_BUFLEN];
uint32_t modulus_len = sizeof (modulus);
CK_BYTE plain_data[MAX_RSA_KEYLENGTH_IN_BYTES];
rv = soft_get_public_attr(key, CKA_MODULUS, modulus, &modulus_len);
if (rv != CKR_OK) {
goto clean_exit;
}
if (ulSignatureLen != (CK_ULONG)modulus_len) {
rv = CKR_SIGNATURE_LEN_RANGE;
goto clean_exit;
}
/*
* Perform RSA decryption with the signer's RSA public key
* for verification process.
*/
rv = soft_rsa_encrypt(key, pSignature, modulus_len, plain_data, 1);
if (rv == CKR_OK) {
switch (mechanism) {
case CKM_RSA_PKCS:
case CKM_MD5_RSA_PKCS:
case CKM_SHA1_RSA_PKCS:
case CKM_SHA256_RSA_PKCS:
case CKM_SHA384_RSA_PKCS:
case CKM_SHA512_RSA_PKCS:
{
/*
* Strip off the encoded padding bytes in front of the
* recovered data, then compare the recovered data with
* the original data.
*/
int data_len = modulus_len;
rv = soft_verify_rsa_pkcs_decode(plain_data, &data_len);
if (rv != CKR_OK) {
goto clean_exit;
}
if ((CK_ULONG)data_len != ulDataLen) {
rv = CKR_SIGNATURE_LEN_RANGE;
goto clean_exit;
} else if (memcmp(pData,
&plain_data[modulus_len - data_len],
ulDataLen) != 0) {
rv = CKR_SIGNATURE_INVALID;
goto clean_exit;
}
break;
}
case CKM_RSA_X_509:
/*
* Strip off the encoded padding bytes in front of the
* recovered plain_data, then compare the input data
* with the recovered data.
*/
if (memcmp(pData,
plain_data + ulSignatureLen - ulDataLen,
ulDataLen) != 0) {
rv = CKR_SIGNATURE_INVALID;
goto clean_exit;
}
break;
}
}
if (rv == CKR_DATA_LEN_RANGE) {
if ((mechanism == CKM_MD5_RSA_PKCS) ||
(mechanism == CKM_SHA1_RSA_PKCS) ||
(mechanism == CKM_SHA256_RSA_PKCS) ||
(mechanism == CKM_SHA384_RSA_PKCS) ||
(mechanism == CKM_SHA512_RSA_PKCS))
rv = CKR_SIGNATURE_INVALID;
}
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
free(session_p->verify.context);
session_p->verify.context = NULL;
if (session_p->digest.context != NULL) {
free(session_p->digest.context);
session_p->digest.context = NULL;
session_p->digest.flags = 0;
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
soft_cleanup_object(key);
free(key);
return (rv);
}
CK_RV
soft_genRSAkey_set_attribute(soft_object_t *key, RSAkey *rsakey,
CK_ATTRIBUTE_TYPE type, uint32_t modulus_len, boolean_t public)
{
uchar_t *buf, *buf1;
uint32_t buflen;
CK_RV rv = CKR_OK;
biginteger_t *dst = NULL;
biginteger_t src;
/*
* Allocate the buffer used to store the value of key fields
* for bignum2bytestring. Since bignum only deals with a buffer
* whose size is multiple of 4, modulus_len is rounded up to be
* multiple of 4.
*/
if ((buf1 = malloc((modulus_len + 3) & ~3)) == NULL) {
rv = CKR_HOST_MEMORY;
goto cleanexit;
}
buf = buf1;
switch (type) {
case CKA_MODULUS:
buflen = rsakey->n.len * (int)sizeof (uint32_t);
bignum2bytestring(buf, &rsakey->n, buflen);
if (public)
dst = OBJ_PUB_RSA_MOD(key);
else
dst = OBJ_PRI_RSA_MOD(key);
break;
case CKA_PUBLIC_EXPONENT:
buflen = rsakey->e.len * (int)sizeof (uint32_t);
bignum2bytestring(buf, &rsakey->e, buflen);
if (public)
dst = OBJ_PUB_RSA_PUBEXPO(key);
else
dst = OBJ_PRI_RSA_PUBEXPO(key);
break;
case CKA_PRIVATE_EXPONENT:
buflen = rsakey->d.len * (int)sizeof (uint32_t);
bignum2bytestring(buf, &rsakey->d, buflen);
dst = OBJ_PRI_RSA_PRIEXPO(key);
break;
case CKA_PRIME_1:
buflen = rsakey->q.len * (int)sizeof (uint32_t);
bignum2bytestring(buf, &rsakey->q, buflen);
dst = OBJ_PRI_RSA_PRIME1(key);
break;
case CKA_PRIME_2:
buflen = rsakey->p.len * (int)sizeof (uint32_t);
bignum2bytestring(buf, &rsakey->p, buflen);
dst = OBJ_PRI_RSA_PRIME2(key);
break;
case CKA_EXPONENT_1:
buflen = rsakey->dmodqminus1.len * (int)sizeof (uint32_t);
bignum2bytestring(buf, &rsakey->dmodqminus1, buflen);
dst = OBJ_PRI_RSA_EXPO1(key);
break;
case CKA_EXPONENT_2:
buflen = rsakey->dmodpminus1.len * (int)sizeof (uint32_t);
bignum2bytestring(buf, &rsakey->dmodpminus1, buflen);
dst = OBJ_PRI_RSA_EXPO2(key);
break;
case CKA_COEFFICIENT:
buflen = rsakey->pinvmodq.len * (int)sizeof (uint32_t);
bignum2bytestring(buf, &rsakey->pinvmodq, buflen);
dst = OBJ_PRI_RSA_COEF(key);
break;
}
while (buf[0] == 0) { /* remove proceeding 0x00 */
buf++;
buflen--;
}
src.big_value_len = buflen;
if ((src.big_value = malloc(buflen)) == NULL) {
rv = CKR_HOST_MEMORY;
goto cleanexit;
}
(void) memcpy(src.big_value, buf, buflen);
/* Copy the attribute in the key object. */
copy_bigint_attr(&src, dst);
cleanexit:
free(buf1);
return (rv);
}
CK_RV
generate_rsa_key(RSAkey *key, int psize, int qsize, BIGNUM * pubexp,
boolean_t token_obj)
{
CK_RV rv = CKR_OK;
/* EXPORT DELETE START */
BIGNUM a, b, c, d, e, f, g, h;
int len, keylen, size;
BIG_ERR_CODE brv = BIG_OK;
size = psize + qsize;
keylen = (size + 31) / 32;
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);
}
nextp:
if ((brv = random_bignum(&a, psize, token_obj)) != BIG_OK) {
goto ret;
}
if ((brv = big_nextprime_pos(&b, &a)) != BIG_OK) {
goto ret;
}
(void) big_sub_pos(&a, &b, &One);
if ((brv = big_ext_gcd_pos(&f, &d, &g, pubexp, &a)) != BIG_OK) {
goto ret;
}
if (big_cmp_abs(&f, &One) != 0) {
goto nextp;
}
if ((brv = random_bignum(&c, qsize, token_obj)) != BIG_OK) {
goto ret;
}
nextq:
(void) big_add(&a, &c, &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, &One);
(void) big_sub_pos(&d, &c, &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, &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, &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, &One);
if ((brv = big_div_pos(&a, &f, &d, &a)) != BIG_OK) {
goto ret;
}
(void) big_copy(&(key->dmodqminus1), &f);
if ((brv = random_bignum(&h, size, token_obj)) != 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, token_obj);
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 (rv);
}
CK_RV
soft_rsa_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
{
CK_RV rv = CKR_OK;
uint32_t modulus_len;
uchar_t pub_expo[MAX_KEY_ATTR_BUFLEN];
uint32_t pub_expo_len = sizeof (pub_expo);
BIGNUM public_exponent = {0};
RSAkey rsakey = {0};
CK_ATTRIBUTE template;
if ((pubkey == NULL) || (prikey == NULL)) {
return (CKR_ARGUMENTS_BAD);
}
template.pValue = malloc(sizeof (CK_ULONG));
if (template.pValue == NULL) {
return (CKR_HOST_MEMORY);
}
template.ulValueLen = sizeof (CK_ULONG);
rv = get_ulong_attr_from_object(OBJ_PUB_RSA_MOD_BITS(pubkey),
&template);
if (rv != CKR_OK) {
goto clean0;
}
#ifdef __sparcv9
/* LINTED */
modulus_len = (uint32_t)(*((CK_ULONG *)(template.pValue)));
#else /* !__sparcv9 */
modulus_len = *((CK_ULONG *)(template.pValue));
#endif /* __sparcv9 */
/* Convert modulus length from bit length to byte length. */
modulus_len = (modulus_len + 7) / 8;
/* Modulus length needs to be between min key size and max key size. */
if ((modulus_len < MIN_RSA_KEYLENGTH_IN_BYTES) ||
(modulus_len > MAX_RSA_KEYLENGTH_IN_BYTES)) {
rv = CKR_ATTRIBUTE_VALUE_INVALID;
goto clean0;
}
rv = soft_get_public_attr(pubkey, CKA_PUBLIC_EXPONENT, pub_expo,
&pub_expo_len);
if (rv != CKR_OK) {
goto clean0;
}
/* Create a public exponent in bignum format. */
if (big_init(&public_exponent, (modulus_len + 3)/4) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean0;
}
bytestring2bignum(&public_exponent, pub_expo, pub_expo_len);
if (RSA_key_init(&rsakey, modulus_len * 4, modulus_len * 4) != BIG_OK) {
rv = CKR_HOST_MEMORY;
goto clean2;
}
/* Generate RSA key pair. */
if ((rv = generate_rsa_key(&rsakey, modulus_len * 4, modulus_len * 4,
&public_exponent, (IS_TOKEN_OBJECT(pubkey) ||
IS_TOKEN_OBJECT(prikey)))) != CKR_OK) {
goto clean3;
}
/*
* Add modulus in public template, and add all eight key fields
* in private template.
*/
if ((rv = soft_genRSAkey_set_attribute(pubkey, &rsakey,
CKA_MODULUS, modulus_len, B_TRUE)) != CKR_OK) {
goto clean3;
}
if ((rv = soft_genRSAkey_set_attribute(prikey, &rsakey,
CKA_MODULUS, modulus_len, B_FALSE)) != CKR_OK) {
goto clean3;
}
if ((rv = soft_genRSAkey_set_attribute(prikey, &rsakey,
CKA_PRIVATE_EXPONENT, modulus_len, B_FALSE)) != CKR_OK) {
goto clean3;
}
if ((rv = soft_genRSAkey_set_attribute(prikey, &rsakey,
CKA_PUBLIC_EXPONENT, modulus_len, B_FALSE)) != CKR_OK) {
goto clean3;
}
if ((rv = soft_genRSAkey_set_attribute(prikey, &rsakey,
CKA_PRIME_1, modulus_len, B_FALSE)) != CKR_OK) {
goto clean3;
}
if ((rv = soft_genRSAkey_set_attribute(prikey, &rsakey,
CKA_PRIME_2, modulus_len, B_FALSE)) != CKR_OK) {
goto clean3;
}
if ((rv = soft_genRSAkey_set_attribute(prikey, &rsakey,
CKA_EXPONENT_1, modulus_len, B_FALSE)) != CKR_OK) {
goto clean3;
}
if ((rv = soft_genRSAkey_set_attribute(prikey, &rsakey,
CKA_EXPONENT_2, modulus_len, B_FALSE)) != CKR_OK) {
goto clean3;
}
if ((rv = soft_genRSAkey_set_attribute(prikey, &rsakey,
CKA_COEFFICIENT, modulus_len, B_FALSE)) != CKR_OK) {
goto clean3;
}
clean3:
RSA_key_finish(&rsakey);
clean2:
big_finish(&public_exponent);
clean0:
free(template.pValue);
return (rv);
}
CK_RV
soft_rsa_digest_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
CK_ULONG_PTR pulSignedLen, CK_MECHANISM_TYPE mechanism, boolean_t Final)
{
CK_RV rv = CKR_OK;
CK_BYTE hash[SHA512_DIGEST_LENGTH]; /* space enough for all mechs */
CK_ULONG hash_len = SHA512_DIGEST_LENGTH;
/* space enough for all mechs */
CK_BYTE der_data[SHA512_DIGEST_LENGTH + SHA2_DER_PREFIX_Len];
CK_ULONG der_data_len;
soft_rsa_ctx_t *rsa_ctx = session_p->sign.context;
soft_object_t *key = rsa_ctx->key;
uchar_t modulus[MAX_KEY_ATTR_BUFLEN];
uint32_t modulus_len = sizeof (modulus);
rv = soft_get_private_attr(key, CKA_MODULUS, modulus, &modulus_len);
if (rv != CKR_OK) {
(void) pthread_mutex_lock(&session_p->session_mutex);
free(session_p->digest.context);
session_p->digest.context = NULL;
session_p->digest.flags = 0;
(void) pthread_mutex_unlock(&session_p->session_mutex);
soft_cleanup_object(key);
free(key);
goto clean1;
}
/* Check arguments before performing message digest. */
if (pSigned == NULL) {
/* Application asks for the length of the output buffer. */
*pulSignedLen = modulus_len;
rv = CKR_OK;
goto clean1;
}
/* Is the application-supplied buffer large enough? */
if (*pulSignedLen < (CK_ULONG)modulus_len) {
*pulSignedLen = modulus_len;
rv = CKR_BUFFER_TOO_SMALL;
goto clean1;
}
if (Final) {
rv = soft_digest_final(session_p, hash, &hash_len);
} else {
rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
}
if (rv != CKR_OK) {
/* free the signature key */
soft_cleanup_object(key);
free(key);
goto clean_exit;
}
/*
* Prepare the DER encoding of the DigestInfo value as follows:
* MD5: MD5_DER_PREFIX || H
* SHA-1: SHA1_DER_PREFIX || H
* SHA2: SHA2_DER_PREFIX || H
*
* See rsa_impl.c for more details.
*/
switch (session_p->digest.mech.mechanism) {
case CKM_MD5:
(void) memcpy(der_data, MD5_DER_PREFIX, MD5_DER_PREFIX_Len);
(void) memcpy(der_data + MD5_DER_PREFIX_Len, hash, hash_len);
der_data_len = MD5_DER_PREFIX_Len + hash_len;
break;
case CKM_SHA_1:
(void) memcpy(der_data, SHA1_DER_PREFIX, SHA1_DER_PREFIX_Len);
(void) memcpy(der_data + SHA1_DER_PREFIX_Len, hash, hash_len);
der_data_len = SHA1_DER_PREFIX_Len + hash_len;
break;
case CKM_SHA256:
(void) memcpy(der_data, SHA256_DER_PREFIX,
SHA2_DER_PREFIX_Len);
(void) memcpy(der_data + SHA2_DER_PREFIX_Len, hash, hash_len);
der_data_len = SHA2_DER_PREFIX_Len + hash_len;
break;
case CKM_SHA384:
(void) memcpy(der_data, SHA384_DER_PREFIX,
SHA2_DER_PREFIX_Len);
(void) memcpy(der_data + SHA2_DER_PREFIX_Len, hash, hash_len);
der_data_len = SHA2_DER_PREFIX_Len + hash_len;
break;
case CKM_SHA512:
(void) memcpy(der_data, SHA512_DER_PREFIX,
SHA2_DER_PREFIX_Len);
(void) memcpy(der_data + SHA2_DER_PREFIX_Len, hash, hash_len);
der_data_len = SHA2_DER_PREFIX_Len + hash_len;
break;
}
/*
* Now, we are ready to sign the DER_ENCODED data
* soft_rsa_sign_common() will free the signature key.
*/
rv = soft_rsa_sign_common(session_p, der_data, der_data_len,
pSigned, pulSignedLen, mechanism);
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
/* soft_digest_common() has freed the digest context */
session_p->digest.flags = 0;
(void) pthread_mutex_unlock(&session_p->session_mutex);
clean1:
return (rv);
}
CK_RV
soft_rsa_digest_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
CK_ULONG ulSignedLen, CK_MECHANISM_TYPE mechanism, boolean_t Final)
{
CK_RV rv = CKR_OK;
CK_BYTE hash[SHA512_DIGEST_LENGTH]; /* space for all mechs */
CK_ULONG hash_len = SHA512_DIGEST_LENGTH;
CK_BYTE der_data[SHA512_DIGEST_LENGTH + SHA2_DER_PREFIX_Len];
CK_ULONG der_data_len;
soft_rsa_ctx_t *rsa_ctx = session_p->verify.context;
soft_object_t *key = rsa_ctx->key;
if (Final) {
rv = soft_digest_final(session_p, hash, &hash_len);
} else {
rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
}
if (rv != CKR_OK) {
/* free the verification key */
soft_cleanup_object(key);
free(key);
goto clean_exit;
}
/*
* Prepare the DER encoding of the DigestInfo value as follows:
* MD5: MD5_DER_PREFIX || H
* SHA-1: SHA1_DER_PREFIX || H
* SHA2: SHA2_DER_PREFIX || H
*
* See rsa_impl.c for more details.
*/
switch (session_p->digest.mech.mechanism) {
case CKM_MD5:
(void) memcpy(der_data, MD5_DER_PREFIX, MD5_DER_PREFIX_Len);
(void) memcpy(der_data + MD5_DER_PREFIX_Len, hash, hash_len);
der_data_len = MD5_DER_PREFIX_Len + hash_len;
break;
case CKM_SHA_1:
(void) memcpy(der_data, SHA1_DER_PREFIX, SHA1_DER_PREFIX_Len);
(void) memcpy(der_data + SHA1_DER_PREFIX_Len, hash, hash_len);
der_data_len = SHA1_DER_PREFIX_Len + hash_len;
break;
case CKM_SHA256:
(void) memcpy(der_data, SHA256_DER_PREFIX,
SHA2_DER_PREFIX_Len);
(void) memcpy(der_data + SHA2_DER_PREFIX_Len, hash, hash_len);
der_data_len = SHA2_DER_PREFIX_Len + hash_len;
break;
case CKM_SHA384:
(void) memcpy(der_data, SHA384_DER_PREFIX,
SHA2_DER_PREFIX_Len);
(void) memcpy(der_data + SHA2_DER_PREFIX_Len, hash, hash_len);
der_data_len = SHA2_DER_PREFIX_Len + hash_len;
break;
case CKM_SHA512:
(void) memcpy(der_data, SHA512_DER_PREFIX,
SHA2_DER_PREFIX_Len);
(void) memcpy(der_data + SHA2_DER_PREFIX_Len, hash, hash_len);
der_data_len = SHA2_DER_PREFIX_Len + hash_len;
break;
}
/*
* Now, we are ready to verify the DER_ENCODED data using signature.
* soft_rsa_verify_common() will free the verification key.
*/
rv = soft_rsa_verify_common(session_p, der_data, der_data_len,
pSigned, ulSignedLen, mechanism);
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
/* soft_digest_common() has freed the digest context */
session_p->digest.flags = 0;
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}
CK_RV
soft_rsa_verify_recover(soft_session_t *session_p, CK_BYTE_PTR pSignature,
CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
{
CK_RV rv = CKR_OK;
soft_rsa_ctx_t *rsa_ctx = session_p->verify.context;
CK_MECHANISM_TYPE mechanism = session_p->verify.mech.mechanism;
soft_object_t *key = rsa_ctx->key;
uchar_t modulus[MAX_KEY_ATTR_BUFLEN];
uint32_t modulus_len = sizeof (modulus);
CK_BYTE plain_data[MAX_RSA_KEYLENGTH_IN_BYTES];
rv = soft_get_public_attr(key, CKA_MODULUS, modulus, &modulus_len);
if (rv != CKR_OK) {
goto clean_exit;
}
if (ulSignatureLen != (CK_ULONG)modulus_len) {
rv = CKR_SIGNATURE_LEN_RANGE;
goto clean_exit;
}
/*
* Perform RSA decryption with the signer's RSA public key
* for verification process.
*/
rv = soft_rsa_encrypt(key, pSignature, modulus_len, plain_data, 1);
if (rv == CKR_OK) {
switch (mechanism) {
case CKM_RSA_PKCS:
{
/*
* Strip off the encoded padding bytes in front of the
* recovered data.
*/
int data_len = modulus_len;
rv = soft_verify_rsa_pkcs_decode(plain_data, &data_len);
if (rv != CKR_OK) {
goto clean_exit;
}
/*
* If application asks for the length of the output
* buffer?
*/
if (pData == NULL) {
*pulDataLen = data_len;
rv = CKR_OK;
goto clean1;
}
/* Is the application-supplied buffer large enough? */
if (*pulDataLen < (CK_ULONG)data_len) {
*pulDataLen = data_len;
rv = CKR_BUFFER_TOO_SMALL;
goto clean1;
}
(void) memcpy(pData,
&plain_data[modulus_len - data_len], data_len);
*pulDataLen = data_len;
break;
}
case CKM_RSA_X_509:
/*
* If application asks for the length of the output
* buffer?
*/
if (pData == NULL) {
*pulDataLen = modulus_len;
rv = CKR_OK;
goto clean1;
}
/* Is the application-supplied buffer large enough? */
if (*pulDataLen < (CK_ULONG)modulus_len) {
*pulDataLen = modulus_len;
rv = CKR_BUFFER_TOO_SMALL;
goto clean1;
}
(void) memcpy(pData, plain_data, modulus_len);
*pulDataLen = modulus_len;
break;
}
}
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
free(session_p->verify.context);
session_p->verify.context = NULL;
(void) pthread_mutex_unlock(&session_p->session_mutex);
soft_cleanup_object(key);
free(key);
clean1:
return (rv);
}