/* * 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 * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include "softGlobal.h" #include "softSession.h" #include "softObject.h" #include "softOps.h" #include "softRSA.h" #include "softMAC.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; 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); RSAbytekey k; if (realpublic) { rv = soft_get_public_value(key, CKA_PUBLIC_EXPONENT, expo, &expo_len); if (rv != CKR_OK) { goto clean1; } } else { rv = soft_get_private_value(key, CKA_PRIVATE_EXPONENT, expo, &expo_len); if (rv != CKR_OK) { goto clean1; } } rv = soft_get_public_value(key, CKA_MODULUS, modulus, &modulus_len); if (rv != CKR_OK) { goto clean1; } k.modulus = modulus; k.modulus_bits = CRYPTO_BYTES2BITS(modulus_len); k.pubexpo = expo; k.pubexpo_bytes = expo_len; k.rfunc = NULL; rv = rsa_encrypt(&k, in, in_len, out); clean1: 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; 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); RSAbytekey k; rv = soft_get_private_value(key, CKA_MODULUS, modulus, &modulus_len); if (rv != CKR_OK) { goto clean1; } rv = soft_get_private_value(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_value(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_value(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_value(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_value(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; } k.modulus = modulus; k.modulus_bits = CRYPTO_BYTES2BITS(modulus_len); k.prime1 = prime1; k.prime1_bytes = prime1_len; k.prime2 = prime2; k.prime2_bytes = prime2_len; k.expo1 = expo1; k.expo1_bytes = expo1_len; k.expo2 = expo2; k.expo2_bytes = expo2_len; k.coeff = coef; k.coeff_bytes = coef_len; k.rfunc = NULL; rv = rsa_decrypt(&k, in, in_len, out); clean1: 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_value(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 = pkcs1_encode(PKCS1_ENCRYPT, 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_value(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) { size_t plain_len = modulus_len; size_t num_padding; /* Strip off the PKCS block formatting data. */ rv = pkcs1_decode(PKCS1_DECRYPT, 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; digest_mech.pParameter = pMechanism->pParameter; digest_mech.ulParameterLen = pMechanism->ulParameterLen; 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_value(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 = pkcs1_encode(PKCS1_SIGN, 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_value(key, CKA_MODULUS, modulus, &modulus_len); if (rv != CKR_OK) { goto clean_exit; } if (ulDataLen == 0) { rv = CKR_DATA_LEN_RANGE; 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. */ size_t data_len = modulus_len; rv = pkcs1_decode(PKCS1_VERIFY, plain_data, &data_len); if (rv != CKR_OK) { goto clean_exit; } if ((CK_ULONG)data_len != ulDataLen) { rv = CKR_DATA_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, CK_ATTRIBUTE_TYPE type, uchar_t *buf, uint32_t buflen, boolean_t public) { CK_RV rv = CKR_OK; biginteger_t *dst = NULL; biginteger_t src; switch (type) { case CKA_MODULUS: if (public) dst = OBJ_PUB_RSA_MOD(key); else dst = OBJ_PRI_RSA_MOD(key); break; case CKA_PUBLIC_EXPONENT: if (public) dst = OBJ_PUB_RSA_PUBEXPO(key); else dst = OBJ_PRI_RSA_PUBEXPO(key); break; case CKA_PRIVATE_EXPONENT: dst = OBJ_PRI_RSA_PRIEXPO(key); break; case CKA_PRIME_1: dst = OBJ_PRI_RSA_PRIME1(key); break; case CKA_PRIME_2: dst = OBJ_PRI_RSA_PRIME2(key); break; case CKA_EXPONENT_1: dst = OBJ_PRI_RSA_EXPO1(key); break; case CKA_EXPONENT_2: dst = OBJ_PRI_RSA_EXPO2(key); break; case CKA_COEFFICIENT: dst = OBJ_PRI_RSA_COEF(key); break; } /* Note: no explanation found for why this is needed */ while (buf[0] == 0) { /* remove proceeding 0x00 */ buf++; buflen--; } if ((rv = dup_bigint_attr(&src, buf, buflen)) != CKR_OK) goto cleanexit; /* Copy the attribute in the key object. */ copy_bigint_attr(&src, dst); cleanexit: return (rv); } CK_RV soft_rsa_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey) { CK_RV rv = CKR_OK; CK_ATTRIBUTE template; uchar_t modulus[MAX_KEY_ATTR_BUFLEN]; uint32_t modulus_len; uchar_t pub_expo[MAX_KEY_ATTR_BUFLEN]; uint32_t pub_expo_len = sizeof (pub_expo); uchar_t private_exponent[MAX_KEY_ATTR_BUFLEN]; uint32_t private_exponent_len = sizeof (private_exponent); uchar_t prime1[MAX_KEY_ATTR_BUFLEN]; uint32_t prime1_len = sizeof (prime1); uchar_t prime2[MAX_KEY_ATTR_BUFLEN]; uint32_t prime2_len = sizeof (prime2); uchar_t exponent1[MAX_KEY_ATTR_BUFLEN]; uint32_t exponent1_len = sizeof (exponent1); uchar_t exponent2[MAX_KEY_ATTR_BUFLEN]; uint32_t exponent2_len = sizeof (exponent2); uchar_t coefficient[MAX_KEY_ATTR_BUFLEN]; uint32_t coefficient_len = sizeof (coefficient); RSAbytekey k; 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) { free(template.pValue); goto clean0; } #ifdef __sparcv9 /* LINTED */ modulus_len = (uint32_t)(*((CK_ULONG *)(template.pValue))); #else /* !__sparcv9 */ modulus_len = *((CK_ULONG *)(template.pValue)); #endif /* __sparcv9 */ free(template.pValue); rv = soft_get_public_value(pubkey, CKA_PUBLIC_EXPONENT, pub_expo, &pub_expo_len); if (rv != CKR_OK) { goto clean0; } /* Inputs to RSA key pair generation */ k.modulus_bits = modulus_len; /* save modulus len in bits */ modulus_len = CRYPTO_BITS2BYTES(modulus_len); /* convert to bytes */ k.modulus = modulus; k.pubexpo = pub_expo; k.pubexpo_bytes = pub_expo_len; k.rfunc = (IS_TOKEN_OBJECT(pubkey) || IS_TOKEN_OBJECT(prikey)) ? pkcs11_get_random : pkcs11_get_urandom; /* Outputs from RSA key pair generation */ k.privexpo = private_exponent; k.privexpo_bytes = private_exponent_len; k.prime1 = prime1; k.prime1_bytes = prime1_len; k.prime2 = prime2; k.prime2_bytes = prime2_len; k.expo1 = exponent1; k.expo1_bytes = exponent1_len; k.expo2 = exponent2; k.expo2_bytes = exponent2_len; k.coeff = coefficient; k.coeff_bytes = coefficient_len; rv = rsa_genkey_pair(&k); if (rv != CKR_OK) { goto clean0; } /* * Add modulus in public template, and add all eight key fields * in private template. */ if ((rv = soft_genRSAkey_set_attribute(pubkey, CKA_MODULUS, modulus, CRYPTO_BITS2BYTES(k.modulus_bits), B_TRUE)) != CKR_OK) { goto clean0; } if ((rv = soft_genRSAkey_set_attribute(prikey, CKA_MODULUS, modulus, CRYPTO_BITS2BYTES(k.modulus_bits), B_FALSE)) != CKR_OK) { goto clean0; } if ((rv = soft_genRSAkey_set_attribute(prikey, CKA_PRIVATE_EXPONENT, private_exponent, k.privexpo_bytes, B_FALSE)) != CKR_OK) { goto clean0; } if ((rv = soft_genRSAkey_set_attribute(prikey, CKA_PUBLIC_EXPONENT, pub_expo, k.pubexpo_bytes, B_FALSE)) != CKR_OK) { goto clean0; } if ((rv = soft_genRSAkey_set_attribute(prikey, CKA_PRIME_1, prime1, k.prime1_bytes, B_FALSE)) != CKR_OK) { goto clean0; } if ((rv = soft_genRSAkey_set_attribute(prikey, CKA_PRIME_2, prime2, k.prime2_bytes, B_FALSE)) != CKR_OK) { goto clean0; } if ((rv = soft_genRSAkey_set_attribute(prikey, CKA_EXPONENT_1, exponent1, k.expo1_bytes, B_FALSE)) != CKR_OK) { goto clean0; } if ((rv = soft_genRSAkey_set_attribute(prikey, CKA_EXPONENT_2, exponent2, k.expo2_bytes, B_FALSE)) != CKR_OK) { goto clean0; } if ((rv = soft_genRSAkey_set_attribute(prikey, CKA_COEFFICIENT, coefficient, k.coeff_bytes, B_FALSE)) != CKR_OK) { goto clean0; } clean0: return (rv); } CK_ULONG get_rsa_sha1_prefix(CK_MECHANISM_PTR mech, CK_BYTE_PTR *prefix) { if (mech->pParameter == NULL) { *prefix = (CK_BYTE *)SHA1_DER_PREFIX; return (SHA1_DER_PREFIX_Len); } *prefix = (CK_BYTE *)SHA1_DER_PREFIX_OID; return (SHA1_DER_PREFIX_OID_Len); } 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); CK_ULONG der_len; CK_BYTE_PTR der_prefix; rv = soft_get_private_value(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 by setting it to: * _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: der_len = get_rsa_sha1_prefix(&(session_p->digest.mech), &der_prefix); (void) memcpy(der_data, der_prefix, der_len); (void) memcpy(der_data + der_len, hash, hash_len); der_data_len = der_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; CK_ULONG der_len; CK_BYTE_PTR der_prefix; 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: der_len = get_rsa_sha1_prefix(&(session_p->digest.mech), &der_prefix); (void) memcpy(der_data, der_prefix, der_len); (void) memcpy(der_data + der_len, hash, hash_len); der_data_len = der_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_value(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. */ size_t data_len = modulus_len; rv = pkcs1_decode(PKCS1_VERIFY, 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); }