dca_rsa.c revision 88f8b78a88cbdc6d8c1af5c3e54bc49d25095c98
/*
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Deimos - cryptographic acceleration based upon Broadcom 582x.
*/
static void dca_rsaverifydone(dca_request_t *, int);
static void dca_rsadone(dca_request_t *, int);
/* Exported function prototypes */
crypto_req_handle_t, int);
void dca_rsactxfree(void *);
int, crypto_req_handle_t, int);
/* Local function prototypes */
int private);
{
int rv = CRYPTO_QUEUED;
int len;
/*
* In-place operations (in == out) are indicated by having a
* NULL output. In this case set the out to point to the in.
* Note that this only works for CKM_RSA_X_509 without any padding
*/
if (!out) {
}
/* We don't support non-contiguous buffers for RSA */
goto errout;
}
/* Extracting the key attributes is now done in dca_rsainit(). */
mode == DCA_RSA_SIGNR) {
/*
* Return length needed to store the output.
* For sign, sign-recover, and encrypt, the output buffer
* should not be smaller than modlen since PKCS or X_509
* padding will be applied
*/
"dca_rsastart: output buffer too short (%d < %d)",
goto errout;
}
}
/* The input length should not be bigger than the modulus */
goto errout;
}
/*
* For decryption, verify, and verifyRecover, the input length should
* not be less than the modulus
*/
goto errout;
}
/*
* For decryption and verifyRecover, the output buffer should not
* be less than the modulus
*/
mode == DCA_RSA_VRFYR) &&
goto errout;
}
/* For decrypt and verify, the input should not be less than output */
goto errout;
}
goto errout;
}
"dca_rsastart: input larger (numerically) than modulus!");
goto errout;
}
if (mode == DCA_RSA_VRFY)
else
mode == DCA_RSA_SIGNR) {
/*
* Needs to pad appropriately for encrypt, sign, and
* sign_recover
*/
goto errout;
goto errout;
}
}
/*
* Since the max RSA input size is 256 bytes (2048 bits), the firstx
* page (at least 4096 bytes) in the pre-mapped buffer is large enough.
* Therefore, we use this first page for RSA.
*/
reqp->dr_in_next = 0;
reqp->dr_out_next = 0;
/* schedule the work by doing a submit */
(void) dca_free_context(ctx);
return (rv);
}
void
{
if (errno == CRYPTO_SUCCESS) {
DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
goto errout;
}
/*
* Needs to unpad appropriately for decrypt, verify,
* and verify_recover
*/
/* check for bad data errors */
if (errno != CRYPTO_SUCCESS &&
errno != CRYPTO_BUFFER_TOO_SMALL) {
goto errout;
}
}
if (errno == CRYPTO_BUFFER_TOO_SMALL) {
goto errout;
}
/* Reset the output data length */
if ((errno = dca_x509_unpadding(
goto errout;
}
}
"dca_rsadone: reqp->dr_out is bad");
goto errout;
}
/*
* Note that there may be some number of null bytes
* at the end of the source (result), but we don't care
* about them -- they are place holders only and are
* truncated here.
*/
}
/* notify framework that request is completed */
"dca_rsadone: returning 0x%x to the kef via crypto_op_notification",
errno);
/*
* For non-atomic operations, reqp will be freed in the kCF
* callback function since it may be needed again if
* CRYPTO_BUFFER_TOO_SMALL is returned to kCF
*/
}
}
void
{
if (errno == CRYPTO_SUCCESS) {
char scratch[RSA_MAX_KEY_LEN];
/*
* ASSUMPTION: the signature length was already
* checked on the way in, and it is a valid length.
*/
DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
goto errout;
}
/*
* Needs to unpad appropriately for decrypt, verify,
* and verify_recover
*/
/* check for bad data errors */
if (errno != CRYPTO_SUCCESS &&
errno != CRYPTO_BUFFER_TOO_SMALL) {
goto errout;
}
}
if (errno == CRYPTO_BUFFER_TOO_SMALL) {
goto errout;
}
/* Reset the output data length */
if ((errno = dca_x509_unpadding(
goto errout;
}
}
goto errout;
}
outsz) != 0) {
/* VERIFY FAILED */
}
}
/* notify framework that request is completed */
"dca_rsaverifydone: rtn 0x%x to the kef via crypto_op_notification",
errno);
/*
* For non-atomic operations, reqp will be freed in the kCF
* callback function since it may be needed again if
* CRYPTO_BUFFER_TOO_SMALL is returned to kCF
*/
}
}
/*
* Setup either a public or a private RSA key for subsequent uses
*/
int
{
unsigned expname = 0;
void *attrdata;
int rv;
uchar_t *p;
uchar_t *q;
unsigned explen = 0;
unsigned plen = 0;
unsigned qlen = 0;
unsigned dplen = 0;
unsigned dqlen = 0;
unsigned pinvlen = 0;
"dca_rsainit: unable to allocate request for RSA");
goto errout;
}
/*
* Key type can be either RAW, or REFERENCE, or ATTR_LIST (VALUE).
* Only ATTR_LIST is supported on Deimos for RSA.
*/
goto errout;
}
/*
* RSA public key has only public exponent. RSA private key must have
* private exponent. However, it may also have public exponent.
* Thus, the existance of a private exponent indicates a private key.
*/
if (!expname) {
goto errout;
}
/* Modulus */
goto errout;
}
goto errout;
}
NULL) {
goto errout;
}
/* Exponent */
goto errout;
}
goto errout;
}
/* Lookup private attributes */
if (expname == CKA_PRIVATE_EXPONENT) {
/* Prime 1 */
CKA_PRIME_1, (void **)&q, &qlen);
/* Prime 2 */
CKA_PRIME_2, (void **)&p, &plen);
/* Exponent 1 */
/* Exponent 2 */
/* Coefficient */
}
goto errout;
}
}
if (pqfix) {
} else {
}
if (pqfix) {
/*
* NOTE: chip's notion of p vs. q is reversed from
* PKCS#11. We use the chip's notion in our variable
* naming.
*/
/* write out the context structure */
/* exponent and modulus length in bits!!! */
/* store the bignums */
} else {
/* write out the context structure */
/* exponent and modulus length in bits!!! */
/* store the bignums */
modfix);
}
if (rv != CRYPTO_SUCCESS)
return (rv);
}
void
dca_rsactxfree(void *arg)
{
return;
else
}
int
{
int rv;
if (rv != CRYPTO_SUCCESS) {
/* The content of ctx should have been freed already */
return (rv);
}
/*
* Set the atomic flag so that the hardware callback function
* will free the context.
*/
/*
* The context will be freed in the hardware callback function if it
* is queued
*/
if (rv != CRYPTO_QUEUED)
return (rv);
}
/*
* For RSA_PKCS padding and unpadding:
* 1. The minimum padding is 11 bytes.
* 2. The first and the last bytes must 0.
* 3. The second byte is 1 for private and 2 for public keys.
* 4. Pad with 0xff for private and non-zero random for public keys.
*/
static int
{
int i;
"dca_pkcs1_padding: tlen: %d, flen: %d: private: %d\n",
return (CRYPTO_DATA_LEN_RANGE);
if (private) {
/* Padding for private encrypt */
buf[i] = (unsigned char) 0xff;
}
} else {
/* Padding for public encrypt */
return (CRYPTO_RANDOM_NO_RNG);
}
return (CRYPTO_QUEUED);
}
static int
{
int i;
const unsigned char *p;
unsigned char type;
if (*(p--) != 0)
/* It is ok if the data length is 0 after removing the padding */
type = *(p--);
if (type == 01) {
for (i = flen - 3; i >= 0; i--) {
if (*p != 0xff) {
if (*p == '\0') {
p--;
break;
} else {
return decrypt_error_code(mode,
}
}
p--;
}
} else if (type == 02) {
for (i = flen - 3; i >= 0; i--) {
if (*p == '\0') {
p--;
break;
}
p--;
}
} else {
}
/* i < 0 means did not find the end of the padding */
if (i < 0)
if (i > *tlen) {
*tlen = i;
return (CRYPTO_BUFFER_TOO_SMALL);
}
if (flen - i < 11)
return decrypt_error_code(mode,
/* Return the unpadded length to the caller */
*tlen = i;
return (CRYPTO_SUCCESS);
}
/*
* For RSA_X_509 padding and unpadding, pad all 0s before actual data.
* Note that the data will be in reverse order.
*/
static int
{
return (CRYPTO_QUEUED);
}
/* ARGSUSED */
static int
{
int i;
const unsigned char *p;
if (*(--p) != 0)
return (CRYPTO_SIGNATURE_INVALID);
}
return (CRYPTO_SUCCESS);
}
{
switch (mode) {
case DCA_RSA_DEC:
return (decrypt);
case DCA_RSA_VRFY:
case DCA_RSA_VRFYR:
return (verify);
default:
return (def);
}
}