1*906Sgm89044 /* 2*906Sgm89044 * CDDL HEADER START 3*906Sgm89044 * 4*906Sgm89044 * The contents of this file are subject to the terms of the 5*906Sgm89044 * Common Development and Distribution License (the "License"). 6*906Sgm89044 * You may not use this file except in compliance with the License. 7*906Sgm89044 * 8*906Sgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*906Sgm89044 * or http://www.opensolaris.org/os/licensing. 10*906Sgm89044 * See the License for the specific language governing permissions 11*906Sgm89044 * and limitations under the License. 12*906Sgm89044 * 13*906Sgm89044 * When distributing Covered Code, include this CDDL HEADER in each 14*906Sgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*906Sgm89044 * If applicable, add the following below this CDDL HEADER, with the 16*906Sgm89044 * fields enclosed by brackets "[]" replaced with your own identifying 17*906Sgm89044 * information: Portions Copyright [yyyy] [name of copyright owner] 18*906Sgm89044 * 19*906Sgm89044 * CDDL HEADER END 20*906Sgm89044 */ 21*906Sgm89044 22*906Sgm89044 /* 23*906Sgm89044 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*906Sgm89044 * Use is subject to license terms. 25*906Sgm89044 */ 26*906Sgm89044 27*906Sgm89044 #pragma ident "%Z%%M% %I% %E% SMI" 28*906Sgm89044 29*906Sgm89044 /* 30*906Sgm89044 * Deimos - cryptographic acceleration based upon Broadcom 582x. 31*906Sgm89044 */ 32*906Sgm89044 33*906Sgm89044 #include <sys/types.h> 34*906Sgm89044 #include <sys/ddi.h> 35*906Sgm89044 #include <sys/sunddi.h> 36*906Sgm89044 #include <sys/kmem.h> 37*906Sgm89044 #include <sys/crypto/common.h> 38*906Sgm89044 #include <sys/crypto/spi.h> 39*906Sgm89044 #include <sys/crypto/ioctl.h> 40*906Sgm89044 #include <sys/crypto/dca.h> 41*906Sgm89044 42*906Sgm89044 /* 43*906Sgm89044 * DSA implementation. 44*906Sgm89044 */ 45*906Sgm89044 46*906Sgm89044 static void dca_dsa_sign_done(dca_request_t *, int); 47*906Sgm89044 static void dca_dsa_verify_done(dca_request_t *, int); 48*906Sgm89044 49*906Sgm89044 50*906Sgm89044 int dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 51*906Sgm89044 crypto_req_handle_t req); 52*906Sgm89044 int dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 53*906Sgm89044 crypto_req_handle_t req); 54*906Sgm89044 int dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 55*906Sgm89044 crypto_key_t *key, int kmflag, int mode); 56*906Sgm89044 57*906Sgm89044 58*906Sgm89044 int 59*906Sgm89044 dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 60*906Sgm89044 crypto_req_handle_t req) 61*906Sgm89044 { 62*906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 63*906Sgm89044 dca_t *dca = ctx->cc_provider; 64*906Sgm89044 int err; 65*906Sgm89044 int rv = CRYPTO_QUEUED; 66*906Sgm89044 caddr_t kaddr; 67*906Sgm89044 size_t buflen; 68*906Sgm89044 69*906Sgm89044 buflen = dca_length(data); 70*906Sgm89044 if (buflen != SHA1LEN) { 71*906Sgm89044 DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN); 72*906Sgm89044 rv = CRYPTO_DATA_LEN_RANGE; 73*906Sgm89044 goto errout; 74*906Sgm89044 } 75*906Sgm89044 76*906Sgm89044 /* Return length needed to store the output. */ 77*906Sgm89044 if (dca_length(sig) < DSASIGLEN) { 78*906Sgm89044 DBG(dca, DWARN, 79*906Sgm89044 "dca_dsa_sign: output buffer too short (%d < %d)", 80*906Sgm89044 dca_length(sig), DSASIGLEN); 81*906Sgm89044 sig->cd_length = DSASIGLEN; 82*906Sgm89044 rv = CRYPTO_BUFFER_TOO_SMALL; 83*906Sgm89044 goto errout; 84*906Sgm89044 } 85*906Sgm89044 86*906Sgm89044 /* 87*906Sgm89044 * Don't change the data values of the data crypto_data_t structure 88*906Sgm89044 * yet. Only reset the sig cd_length to zero before writing to it. 89*906Sgm89044 */ 90*906Sgm89044 91*906Sgm89044 reqp->dr_job_stat = DS_DSASIGN; 92*906Sgm89044 reqp->dr_byte_stat = -1; 93*906Sgm89044 reqp->dr_in = data; 94*906Sgm89044 reqp->dr_out = sig; 95*906Sgm89044 reqp->dr_callback = dca_dsa_sign_done; 96*906Sgm89044 97*906Sgm89044 reqp->dr_kcf_req = req; 98*906Sgm89044 /* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */ 99*906Sgm89044 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1); 100*906Sgm89044 if (err != CRYPTO_SUCCESS) { 101*906Sgm89044 DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed"); 102*906Sgm89044 rv = err; 103*906Sgm89044 goto errout; 104*906Sgm89044 } 105*906Sgm89044 106*906Sgm89044 107*906Sgm89044 /* sync the input buffer */ 108*906Sgm89044 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN, 109*906Sgm89044 DDI_DMA_SYNC_FORDEV); 110*906Sgm89044 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 111*906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 112*906Sgm89044 reqp->destroy = TRUE; 113*906Sgm89044 rv = CRYPTO_DEVICE_ERROR; 114*906Sgm89044 goto errout; 115*906Sgm89044 } 116*906Sgm89044 117*906Sgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_paddr; 118*906Sgm89044 reqp->dr_in_next = 0; 119*906Sgm89044 reqp->dr_in_len = SHA1LEN; 120*906Sgm89044 reqp->dr_pkt_length = buflen; 121*906Sgm89044 122*906Sgm89044 /* 123*906Sgm89044 * The output requires *two* buffers, r followed by s. 124*906Sgm89044 */ 125*906Sgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset; 126*906Sgm89044 127*906Sgm89044 /* r */ 128*906Sgm89044 reqp->dr_out_paddr = reqp->dr_obuf_paddr; 129*906Sgm89044 reqp->dr_out_len = DSAPARTLEN; 130*906Sgm89044 reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset; 131*906Sgm89044 132*906Sgm89044 /* s */ 133*906Sgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR, 134*906Sgm89044 reqp->dr_obuf_paddr + DSAPARTLEN); 135*906Sgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT, 0); 136*906Sgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 137*906Sgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 138*906Sgm89044 139*906Sgm89044 /* schedule the work by doing a submit */ 140*906Sgm89044 rv = dca_start(dca, reqp, MCR2, 1); 141*906Sgm89044 142*906Sgm89044 errout: 143*906Sgm89044 144*906Sgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) 145*906Sgm89044 (void) dca_free_context(ctx); 146*906Sgm89044 147*906Sgm89044 return (rv); 148*906Sgm89044 } 149*906Sgm89044 150*906Sgm89044 static void 151*906Sgm89044 dca_dsa_sign_done(dca_request_t *reqp, int errno) 152*906Sgm89044 { 153*906Sgm89044 if (errno == CRYPTO_SUCCESS) { 154*906Sgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN, 155*906Sgm89044 DDI_DMA_SYNC_FORKERNEL); 156*906Sgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah, 157*906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 158*906Sgm89044 reqp->destroy = TRUE; 159*906Sgm89044 errno = CRYPTO_DEVICE_ERROR; 160*906Sgm89044 goto errout; 161*906Sgm89044 } 162*906Sgm89044 /* 163*906Sgm89044 * Set the sig cd_length to zero so it's ready to take the 164*906Sgm89044 * signature. Have already confirmed its size is adequate. 165*906Sgm89044 */ 166*906Sgm89044 reqp->dr_out->cd_length = 0; 167*906Sgm89044 errno = dca_scatter(reqp->dr_obuf_kaddr, 168*906Sgm89044 reqp->dr_out, DSAPARTLEN, 1); 169*906Sgm89044 if (errno != CRYPTO_SUCCESS) { 170*906Sgm89044 DBG(reqp->dr_dca, DWARN, 171*906Sgm89044 "dca_dsa_sign_done: dca_scatter() failed"); 172*906Sgm89044 goto errout; 173*906Sgm89044 } 174*906Sgm89044 errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN, 175*906Sgm89044 reqp->dr_out, DSAPARTLEN, 1); 176*906Sgm89044 if (errno != CRYPTO_SUCCESS) { 177*906Sgm89044 DBG(reqp->dr_dca, DWARN, 178*906Sgm89044 "dca_dsa_sign_done: dca_scatter() failed"); 179*906Sgm89044 } 180*906Sgm89044 } 181*906Sgm89044 errout: 182*906Sgm89044 ASSERT(reqp->dr_kcf_req != NULL); 183*906Sgm89044 184*906Sgm89044 /* notify framework that request is completed */ 185*906Sgm89044 crypto_op_notification(reqp->dr_kcf_req, errno); 186*906Sgm89044 DBG(reqp->dr_dca, DINTR, 187*906Sgm89044 "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification", 188*906Sgm89044 errno); 189*906Sgm89044 190*906Sgm89044 /* 191*906Sgm89044 * For non-atomic operations, reqp will be freed in the kCF 192*906Sgm89044 * callback function since it may be needed again if 193*906Sgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF 194*906Sgm89044 */ 195*906Sgm89044 if (reqp->dr_ctx.atomic) { 196*906Sgm89044 crypto_ctx_t ctx; 197*906Sgm89044 ctx.cc_provider_private = reqp; 198*906Sgm89044 dca_dsactxfree(&ctx); 199*906Sgm89044 } 200*906Sgm89044 } 201*906Sgm89044 202*906Sgm89044 int 203*906Sgm89044 dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 204*906Sgm89044 crypto_req_handle_t req) 205*906Sgm89044 { 206*906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 207*906Sgm89044 dca_t *dca = ctx->cc_provider; 208*906Sgm89044 int err; 209*906Sgm89044 int rv = CRYPTO_QUEUED; 210*906Sgm89044 caddr_t kaddr; 211*906Sgm89044 212*906Sgm89044 /* Impossible for verify to be an in-place operation. */ 213*906Sgm89044 if (sig == NULL) { 214*906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 215*906Sgm89044 goto errout; 216*906Sgm89044 } 217*906Sgm89044 218*906Sgm89044 if (dca_length(data) != SHA1LEN) { 219*906Sgm89044 DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN); 220*906Sgm89044 rv = CRYPTO_DATA_LEN_RANGE; 221*906Sgm89044 goto errout; 222*906Sgm89044 } 223*906Sgm89044 224*906Sgm89044 if (dca_length(sig) != DSASIGLEN) { 225*906Sgm89044 DBG(dca, DWARN, "dca_dsa_verify: signature length != %d", 226*906Sgm89044 DSASIGLEN); 227*906Sgm89044 rv = CRYPTO_SIGNATURE_LEN_RANGE; 228*906Sgm89044 goto errout; 229*906Sgm89044 } 230*906Sgm89044 231*906Sgm89044 /* Don't change the data & sig values for verify. */ 232*906Sgm89044 233*906Sgm89044 reqp->dr_job_stat = DS_DSAVERIFY; 234*906Sgm89044 reqp->dr_byte_stat = -1; 235*906Sgm89044 236*906Sgm89044 /* 237*906Sgm89044 * Grab h, r and s. 238*906Sgm89044 */ 239*906Sgm89044 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1); 240*906Sgm89044 if (err != CRYPTO_SUCCESS) { 241*906Sgm89044 DBG(dca, DWARN, 242*906Sgm89044 "dca_dsa_vrfy: dca_gather() failed for h"); 243*906Sgm89044 rv = err; 244*906Sgm89044 goto errout; 245*906Sgm89044 } 246*906Sgm89044 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1); 247*906Sgm89044 if (err != CRYPTO_SUCCESS) { 248*906Sgm89044 DBG(dca, DWARN, 249*906Sgm89044 "dca_dsa_vrfy: dca_gather() failed for r"); 250*906Sgm89044 rv = err; 251*906Sgm89044 goto errout; 252*906Sgm89044 } 253*906Sgm89044 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN, 254*906Sgm89044 DSAPARTLEN, 1); 255*906Sgm89044 if (err != CRYPTO_SUCCESS) { 256*906Sgm89044 DBG(dca, DWARN, 257*906Sgm89044 "dca_dsa_vrfy: dca_gather() failed for s"); 258*906Sgm89044 rv = err; 259*906Sgm89044 goto errout; 260*906Sgm89044 } 261*906Sgm89044 /* 262*906Sgm89044 * As dca_gather() increments the cd_offset and decrements 263*906Sgm89044 * the cd_length as it copies the data rewind the values ready for 264*906Sgm89044 * the final compare. 265*906Sgm89044 */ 266*906Sgm89044 sig->cd_offset -= (DSAPARTLEN * 2); 267*906Sgm89044 sig->cd_length += (DSAPARTLEN * 2); 268*906Sgm89044 /* sync the input buffer */ 269*906Sgm89044 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN, 270*906Sgm89044 DDI_DMA_SYNC_FORDEV); 271*906Sgm89044 272*906Sgm89044 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 273*906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 274*906Sgm89044 reqp->destroy = TRUE; 275*906Sgm89044 rv = CRYPTO_DEVICE_ERROR; 276*906Sgm89044 goto errout; 277*906Sgm89044 } 278*906Sgm89044 279*906Sgm89044 reqp->dr_in = data; 280*906Sgm89044 reqp->dr_out = sig; 281*906Sgm89044 reqp->dr_kcf_req = req; 282*906Sgm89044 reqp->dr_flags |= DR_SCATTER | DR_GATHER; 283*906Sgm89044 reqp->dr_callback = dca_dsa_verify_done; 284*906Sgm89044 285*906Sgm89044 /* 286*906Sgm89044 * Input requires three buffers. m, followed by r, followed by s. 287*906Sgm89044 * In order to deal with things cleanly, we reverse the signature 288*906Sgm89044 * into the buffer and then fix up the pointers. 289*906Sgm89044 */ 290*906Sgm89044 reqp->dr_pkt_length = SHA1LEN; 291*906Sgm89044 292*906Sgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_paddr; 293*906Sgm89044 reqp->dr_in_len = SHA1LEN; 294*906Sgm89044 reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset; 295*906Sgm89044 296*906Sgm89044 reqp->dr_out_paddr = reqp->dr_obuf_paddr; 297*906Sgm89044 reqp->dr_out_len = DSAPARTLEN; 298*906Sgm89044 reqp->dr_out_next = 0; 299*906Sgm89044 300*906Sgm89044 /* setup 1st chain for r */ 301*906Sgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset; 302*906Sgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN); 303*906Sgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT, 304*906Sgm89044 reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE); 305*906Sgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 306*906Sgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 307*906Sgm89044 308*906Sgm89044 /* and 2nd chain for s */ 309*906Sgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE; 310*906Sgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + 311*906Sgm89044 SHA1LEN + DSAPARTLEN); 312*906Sgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT, 0); 313*906Sgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 314*906Sgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 315*906Sgm89044 316*906Sgm89044 /* schedule the work by doing a submit */ 317*906Sgm89044 rv = dca_start(dca, reqp, MCR2, 1); 318*906Sgm89044 319*906Sgm89044 errout: 320*906Sgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) { 321*906Sgm89044 (void) dca_free_context(ctx); 322*906Sgm89044 } 323*906Sgm89044 return (rv); 324*906Sgm89044 } 325*906Sgm89044 326*906Sgm89044 static void 327*906Sgm89044 dca_dsa_verify_done(dca_request_t *reqp, int errno) 328*906Sgm89044 { 329*906Sgm89044 if (errno == CRYPTO_SUCCESS) { 330*906Sgm89044 int count = DSAPARTLEN; 331*906Sgm89044 crypto_data_t *sig = reqp->dr_out; 332*906Sgm89044 caddr_t daddr; 333*906Sgm89044 334*906Sgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, count, 335*906Sgm89044 DDI_DMA_SYNC_FORKERNEL); 336*906Sgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah, 337*906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 338*906Sgm89044 reqp->destroy = TRUE; 339*906Sgm89044 errno = CRYPTO_DEVICE_ERROR; 340*906Sgm89044 goto errout; 341*906Sgm89044 } 342*906Sgm89044 343*906Sgm89044 /* Can only handle a contiguous data buffer currently. */ 344*906Sgm89044 if (dca_sgcheck(reqp->dr_dca, sig, DCA_SG_CONTIG)) { 345*906Sgm89044 errno = CRYPTO_SIGNATURE_INVALID; 346*906Sgm89044 goto errout; 347*906Sgm89044 } 348*906Sgm89044 349*906Sgm89044 if ((daddr = dca_bufdaddr(sig)) == NULL) { 350*906Sgm89044 errno = CRYPTO_ARGUMENTS_BAD; 351*906Sgm89044 goto errout; 352*906Sgm89044 } 353*906Sgm89044 354*906Sgm89044 if (dca_bcmp_reverse(daddr, reqp->dr_obuf_kaddr, 355*906Sgm89044 DSAPARTLEN) != 0) { 356*906Sgm89044 /* VERIFY FAILED */ 357*906Sgm89044 errno = CRYPTO_SIGNATURE_INVALID; 358*906Sgm89044 } 359*906Sgm89044 } 360*906Sgm89044 errout: 361*906Sgm89044 ASSERT(reqp->dr_kcf_req != NULL); 362*906Sgm89044 363*906Sgm89044 /* notify framework that request is completed */ 364*906Sgm89044 365*906Sgm89044 crypto_op_notification(reqp->dr_kcf_req, errno); 366*906Sgm89044 DBG(reqp->dr_dca, DINTR, 367*906Sgm89044 "dca_dsa_verify_done: rtn 0x%x to kef via crypto_op_notification", 368*906Sgm89044 errno); 369*906Sgm89044 370*906Sgm89044 /* 371*906Sgm89044 * For non-atomic operations, reqp will be freed in the kCF 372*906Sgm89044 * callback function since it may be needed again if 373*906Sgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF 374*906Sgm89044 */ 375*906Sgm89044 if (reqp->dr_ctx.atomic) { 376*906Sgm89044 crypto_ctx_t ctx; 377*906Sgm89044 ctx.cc_provider_private = reqp; 378*906Sgm89044 dca_dsactxfree(&ctx); 379*906Sgm89044 } 380*906Sgm89044 } 381*906Sgm89044 382*906Sgm89044 /* ARGSUSED */ 383*906Sgm89044 int 384*906Sgm89044 dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 385*906Sgm89044 crypto_key_t *key, int kmflag, int mode) 386*906Sgm89044 { 387*906Sgm89044 crypto_object_attribute_t *attr; 388*906Sgm89044 unsigned plen = 0, qlen = 0, glen = 0, xlen = 0; 389*906Sgm89044 uchar_t *p, *q, *g, *x; 390*906Sgm89044 dca_request_t *reqp = NULL; 391*906Sgm89044 dca_t *dca = (dca_t *)ctx->cc_provider; 392*906Sgm89044 int rv = CRYPTO_SUCCESS; 393*906Sgm89044 unsigned pbits, padjlen; 394*906Sgm89044 uint16_t ctxlen; 395*906Sgm89044 caddr_t kaddr; 396*906Sgm89044 397*906Sgm89044 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) { 398*906Sgm89044 dca_error(dca, 399*906Sgm89044 "dca_dsainit: unable to allocate request for DSA"); 400*906Sgm89044 rv = CRYPTO_HOST_MEMORY; 401*906Sgm89044 goto errout; 402*906Sgm89044 } 403*906Sgm89044 404*906Sgm89044 ctx->cc_provider_private = reqp; 405*906Sgm89044 reqp->dr_ctx.ctx_cm_type = mechanism->cm_type; 406*906Sgm89044 407*906Sgm89044 if ((attr = dca_get_key_attr(key)) == NULL) { 408*906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: key attributes missing"); 409*906Sgm89044 rv = CRYPTO_KEY_TYPE_INCONSISTENT; 410*906Sgm89044 goto errout; 411*906Sgm89044 } 412*906Sgm89044 413*906Sgm89044 /* Prime */ 414*906Sgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_PRIME, 415*906Sgm89044 (void *) &p, &plen)) { 416*906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: prime key value not present"); 417*906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 418*906Sgm89044 goto errout; 419*906Sgm89044 } 420*906Sgm89044 421*906Sgm89044 /* Subprime */ 422*906Sgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_SUBPRIME, 423*906Sgm89044 (void *) &q, &qlen)) { 424*906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: subprime key value not present"); 425*906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 426*906Sgm89044 goto errout; 427*906Sgm89044 } 428*906Sgm89044 429*906Sgm89044 /* Base */ 430*906Sgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_BASE, 431*906Sgm89044 (void *) &g, &glen)) { 432*906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: base key value not present"); 433*906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 434*906Sgm89044 goto errout; 435*906Sgm89044 } 436*906Sgm89044 437*906Sgm89044 /* Value */ 438*906Sgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_VALUE, 439*906Sgm89044 (void *) &x, &xlen)) { 440*906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: value key not present"); 441*906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 442*906Sgm89044 goto errout; 443*906Sgm89044 } 444*906Sgm89044 445*906Sgm89044 if (plen == 0 || qlen == 0 || glen == 0 || xlen == 0) { 446*906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 447*906Sgm89044 goto errout; 448*906Sgm89044 } 449*906Sgm89044 450*906Sgm89044 if (plen > DSA_MAX_KEY_LEN) { 451*906Sgm89044 /* maximum 1Kbit key */ 452*906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: maximum 1Kbit key (%d)", plen); 453*906Sgm89044 rv = CRYPTO_KEY_SIZE_RANGE; 454*906Sgm89044 goto errout; 455*906Sgm89044 } 456*906Sgm89044 457*906Sgm89044 if (qlen > DSAPARTLEN) { 458*906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: q is too long (%d)", qlen); 459*906Sgm89044 rv = CRYPTO_KEY_SIZE_RANGE; 460*906Sgm89044 goto errout; 461*906Sgm89044 } 462*906Sgm89044 463*906Sgm89044 if (mode == DCA_DSA_SIGN && xlen > DSAPARTLEN) { 464*906Sgm89044 DBG(NULL, DWARN, 465*906Sgm89044 "dca_dsainit: private key is too long (%d)", xlen); 466*906Sgm89044 rv = CRYPTO_KEY_SIZE_RANGE; 467*906Sgm89044 goto errout; 468*906Sgm89044 } 469*906Sgm89044 470*906Sgm89044 /* 471*906Sgm89044 * Setup the key partion of the request. 472*906Sgm89044 */ 473*906Sgm89044 474*906Sgm89044 pbits = dca_bitlen(p, plen); 475*906Sgm89044 padjlen = dca_padfull(pbits); 476*906Sgm89044 477*906Sgm89044 /* accounts for leading context words */ 478*906Sgm89044 if (mode == DCA_DSA_SIGN) { 479*906Sgm89044 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 2) + 480*906Sgm89044 DSAPARTLEN; 481*906Sgm89044 PUTCTX16(reqp, CTX_CMD, CMD_DSASIGN); 482*906Sgm89044 } else { 483*906Sgm89044 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 3); 484*906Sgm89044 PUTCTX16(reqp, CTX_CMD, CMD_DSAVERIFY); 485*906Sgm89044 } 486*906Sgm89044 487*906Sgm89044 PUTCTX16(reqp, CTX_LENGTH, ctxlen); 488*906Sgm89044 PUTCTX16(reqp, CTX_DSAMSGTYPE, CTX_DSAMSGTYPE_SHA1); 489*906Sgm89044 PUTCTX16(reqp, CTX_DSARSVD, 0); 490*906Sgm89044 if (mode == DCA_DSA_SIGN) 491*906Sgm89044 PUTCTX16(reqp, CTX_DSARNG, CTX_DSARNG_GEN); 492*906Sgm89044 else 493*906Sgm89044 PUTCTX16(reqp, CTX_DSARNG, 0); 494*906Sgm89044 PUTCTX16(reqp, CTX_DSAPLEN, pbits); 495*906Sgm89044 496*906Sgm89044 kaddr = reqp->dr_ctx_kaddr + CTX_DSABIGNUMS; 497*906Sgm89044 498*906Sgm89044 /* store the bignums */ 499*906Sgm89044 dca_reverse(q, kaddr, qlen, DSAPARTLEN); 500*906Sgm89044 kaddr += DSAPARTLEN; 501*906Sgm89044 502*906Sgm89044 dca_reverse(p, kaddr, plen, padjlen); 503*906Sgm89044 kaddr += padjlen; 504*906Sgm89044 505*906Sgm89044 dca_reverse(g, kaddr, glen, padjlen); 506*906Sgm89044 kaddr += padjlen; 507*906Sgm89044 508*906Sgm89044 if (mode == DCA_DSA_SIGN) { 509*906Sgm89044 dca_reverse(x, kaddr, xlen, DSAPARTLEN); 510*906Sgm89044 kaddr += DSAPARTLEN; 511*906Sgm89044 } else { 512*906Sgm89044 dca_reverse(x, kaddr, xlen, padjlen); 513*906Sgm89044 kaddr += padjlen; 514*906Sgm89044 } 515*906Sgm89044 516*906Sgm89044 return (CRYPTO_SUCCESS); 517*906Sgm89044 518*906Sgm89044 errout: 519*906Sgm89044 520*906Sgm89044 dca_dsactxfree(ctx); 521*906Sgm89044 return (rv); 522*906Sgm89044 } 523*906Sgm89044 524*906Sgm89044 void 525*906Sgm89044 dca_dsactxfree(void *arg) 526*906Sgm89044 { 527*906Sgm89044 crypto_ctx_t *ctx = (crypto_ctx_t *)arg; 528*906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 529*906Sgm89044 530*906Sgm89044 if (reqp == NULL) 531*906Sgm89044 return; 532*906Sgm89044 533*906Sgm89044 reqp->dr_ctx.ctx_cm_type = 0; 534*906Sgm89044 reqp->dr_ctx.atomic = 0; 535*906Sgm89044 if (reqp->destroy) 536*906Sgm89044 dca_destroyreq(reqp); 537*906Sgm89044 else 538*906Sgm89044 dca_freereq(reqp); 539*906Sgm89044 540*906Sgm89044 ctx->cc_provider_private = NULL; 541*906Sgm89044 } 542*906Sgm89044 543*906Sgm89044 int 544*906Sgm89044 dca_dsaatomic(crypto_provider_handle_t provider, 545*906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 546*906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *sig, 547*906Sgm89044 int kmflag, crypto_req_handle_t req, int mode) 548*906Sgm89044 { 549*906Sgm89044 crypto_ctx_t ctx; /* on the stack */ 550*906Sgm89044 int rv; 551*906Sgm89044 552*906Sgm89044 ctx.cc_provider = provider; 553*906Sgm89044 ctx.cc_session = session_id; 554*906Sgm89044 555*906Sgm89044 rv = dca_dsainit(&ctx, mechanism, key, kmflag, mode); 556*906Sgm89044 if (rv != CRYPTO_SUCCESS) { 557*906Sgm89044 DBG(NULL, DWARN, "dca_dsaatomic: dca_dsainit() failed"); 558*906Sgm89044 return (rv); 559*906Sgm89044 } 560*906Sgm89044 561*906Sgm89044 /* 562*906Sgm89044 * Set the atomic flag so that the hardware callback function 563*906Sgm89044 * will free the context. 564*906Sgm89044 */ 565*906Sgm89044 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1; 566*906Sgm89044 567*906Sgm89044 if (mode == DCA_DSA_SIGN) { 568*906Sgm89044 rv = dca_dsa_sign(&ctx, data, sig, req); 569*906Sgm89044 } else { 570*906Sgm89044 ASSERT(mode == DCA_DSA_VRFY); 571*906Sgm89044 rv = dca_dsa_verify(&ctx, data, sig, req); 572*906Sgm89044 } 573*906Sgm89044 574*906Sgm89044 /* 575*906Sgm89044 * The context will be freed in the hardware callback function if it 576*906Sgm89044 * is queued 577*906Sgm89044 */ 578*906Sgm89044 if (rv != CRYPTO_QUEUED) 579*906Sgm89044 dca_dsactxfree(&ctx); 580*906Sgm89044 581*906Sgm89044 return (rv); 582*906Sgm89044 } 583