dca_dsa.c revision 3096:015752f52084
112115Sdyson/* 212115Sdyson * CDDL HEADER START 312115Sdyson * 412115Sdyson * The contents of this file are subject to the terms of the 512115Sdyson * Common Development and Distribution License (the "License"). 612115Sdyson * You may not use this file except in compliance with the License. 712115Sdyson * 812115Sdyson * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 912115Sdyson * or http://www.opensolaris.org/os/licensing. 1012115Sdyson * See the License for the specific language governing permissions 1112115Sdyson * and limitations under the License. 1212115Sdyson * 1312115Sdyson * When distributing Covered Code, include this CDDL HEADER in each 1412115Sdyson * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1512115Sdyson * If applicable, add the following below this CDDL HEADER, with the 1612115Sdyson * fields enclosed by brackets "[]" replaced with your own identifying 1712115Sdyson * information: Portions Copyright [yyyy] [name of copyright owner] 1812115Sdyson * 1912115Sdyson * CDDL HEADER END 2012115Sdyson */ 2112115Sdyson 2212115Sdyson/* 2312115Sdyson * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2412115Sdyson * Use is subject to license terms. 2512115Sdyson */ 2612115Sdyson 2712115Sdyson#pragma ident "%Z%%M% %I% %E% SMI" 2812115Sdyson 2912115Sdyson/* 3012115Sdyson * Deimos - cryptographic acceleration based upon Broadcom 582x. 3112115Sdyson */ 3212115Sdyson 3312115Sdyson#include <sys/types.h> 3412115Sdyson#include <sys/ddi.h> 3512115Sdyson#include <sys/sunddi.h> 3612115Sdyson#include <sys/kmem.h> 3712115Sdyson#include <sys/crypto/spi.h> 3812115Sdyson#include <sys/crypto/dca.h> 3912115Sdyson 4060041Sphk/* 4112115Sdyson * DSA implementation. 4212115Sdyson */ 4312115Sdyson 4412115Sdysonstatic void dca_dsa_sign_done(dca_request_t *, int); 4560041Sphkstatic void dca_dsa_verify_done(dca_request_t *, int); 4612115Sdyson 4731561Sbde 4834924Sbdeint dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 4912115Sdyson crypto_req_handle_t req); 5012115Sdysonint dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 5112115Sdyson crypto_req_handle_t req); 5212115Sdysonint dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 5312115Sdyson crypto_key_t *key, int kmflag, int mode); 5412115Sdyson 5512115Sdyson 5612115Sdysonint 5712115Sdysondca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 5812115Sdyson crypto_req_handle_t req) 5912115Sdyson{ 6012115Sdyson dca_request_t *reqp = ctx->cc_provider_private; 6112115Sdyson dca_t *dca = ctx->cc_provider; 6212115Sdyson int err; 6312115Sdyson int rv = CRYPTO_QUEUED; 6412115Sdyson caddr_t kaddr; 6512115Sdyson size_t buflen; 6612115Sdyson 6712115Sdyson buflen = dca_length(data); 6812115Sdyson if (buflen != SHA1LEN) { 6912115Sdyson DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN); 7012115Sdyson rv = CRYPTO_DATA_LEN_RANGE; 7112115Sdyson goto errout; 7212115Sdyson } 7312115Sdyson 7412115Sdyson /* Return length needed to store the output. */ 7512115Sdyson if (dca_length(sig) < DSASIGLEN) { 7612115Sdyson DBG(dca, DWARN, 7712115Sdyson "dca_dsa_sign: output buffer too short (%d < %d)", 7812115Sdyson dca_length(sig), DSASIGLEN); 7912115Sdyson sig->cd_length = DSASIGLEN; 8012115Sdyson rv = CRYPTO_BUFFER_TOO_SMALL; 8112115Sdyson goto errout; 8212115Sdyson } 8312115Sdyson 8412115Sdyson /* 8512115Sdyson * Don't change the data values of the data crypto_data_t structure 8612115Sdyson * yet. Only reset the sig cd_length to zero before writing to it. 8712115Sdyson */ 8812115Sdyson 8912115Sdyson reqp->dr_job_stat = DS_DSASIGN; 9012115Sdyson reqp->dr_byte_stat = -1; 9112115Sdyson reqp->dr_in = data; 9212115Sdyson reqp->dr_out = sig; 9312115Sdyson reqp->dr_callback = dca_dsa_sign_done; 9412115Sdyson 9512115Sdyson reqp->dr_kcf_req = req; 9612115Sdyson /* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */ 9712115Sdyson err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1); 9812115Sdyson if (err != CRYPTO_SUCCESS) { 9912115Sdyson DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed"); 10012115Sdyson rv = err; 10112115Sdyson goto errout; 10212115Sdyson } 10312115Sdyson 10412115Sdyson 10512115Sdyson /* sync the input buffer */ 10612115Sdyson (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN, 10712115Sdyson DDI_DMA_SYNC_FORDEV); 10812115Sdyson if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 10912115Sdyson DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 11012115Sdyson reqp->destroy = TRUE; 11112115Sdyson rv = CRYPTO_DEVICE_ERROR; 11212115Sdyson goto errout; 11312115Sdyson } 11412115Sdyson 11512115Sdyson reqp->dr_in_paddr = reqp->dr_ibuf_paddr; 11612115Sdyson reqp->dr_in_next = 0; 11712115Sdyson reqp->dr_in_len = SHA1LEN; 11812115Sdyson reqp->dr_pkt_length = buflen; 11912115Sdyson 12012115Sdyson /* 12112115Sdyson * The output requires *two* buffers, r followed by s. 12212115Sdyson */ 12312115Sdyson kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset; 12412115Sdyson 12512115Sdyson /* r */ 12612115Sdyson reqp->dr_out_paddr = reqp->dr_obuf_paddr; 12712115Sdyson reqp->dr_out_len = DSAPARTLEN; 12812115Sdyson reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset; 12912115Sdyson 13012115Sdyson /* s */ 13112115Sdyson PUTDESC32(reqp, kaddr, DESC_BUFADDR, 13212115Sdyson reqp->dr_obuf_paddr + DSAPARTLEN); 13312115Sdyson PUTDESC32(reqp, kaddr, DESC_NEXT, 0); 13424492Sbde PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 13524492Sbde PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 13612115Sdyson 13712115Sdyson /* schedule the work by doing a submit */ 13812115Sdyson rv = dca_start(dca, reqp, MCR2, 1); 13912115Sdyson 14012115Sdysonerrout: 14112115Sdyson 14212115Sdyson if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) 14312115Sdyson (void) dca_free_context(ctx); 14412115Sdyson 14512115Sdyson return (rv); 14612115Sdyson} 14712115Sdyson 14812115Sdysonstatic void 14912115Sdysondca_dsa_sign_done(dca_request_t *reqp, int errno) 15012115Sdyson{ 15112115Sdyson if (errno == CRYPTO_SUCCESS) { 15212115Sdyson (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN, 15312115Sdyson DDI_DMA_SYNC_FORKERNEL); 15412115Sdyson if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah, 15512115Sdyson DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 15612115Sdyson reqp->destroy = TRUE; 15712115Sdyson errno = CRYPTO_DEVICE_ERROR; 15812115Sdyson goto errout; 15912115Sdyson } 16012115Sdyson /* 16112115Sdyson * Set the sig cd_length to zero so it's ready to take the 16212115Sdyson * signature. Have already confirmed its size is adequate. 16312115Sdyson */ 16412115Sdyson reqp->dr_out->cd_length = 0; 16543301Sdillon errno = dca_scatter(reqp->dr_obuf_kaddr, 16612115Sdyson reqp->dr_out, DSAPARTLEN, 1); 16712115Sdyson if (errno != CRYPTO_SUCCESS) { 16812115Sdyson DBG(reqp->dr_dca, DWARN, 16924492Sbde "dca_dsa_sign_done: dca_scatter() failed"); 17012115Sdyson goto errout; 17112115Sdyson } 17212115Sdyson errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN, 17312115Sdyson reqp->dr_out, DSAPARTLEN, 1); 17412115Sdyson if (errno != CRYPTO_SUCCESS) { 17512115Sdyson DBG(reqp->dr_dca, DWARN, 17612115Sdyson "dca_dsa_sign_done: dca_scatter() failed"); 17712115Sdyson } 17812115Sdyson } 17912115Sdysonerrout: 18012115Sdyson ASSERT(reqp->dr_kcf_req != NULL); 18112115Sdyson 18212115Sdyson /* notify framework that request is completed */ 18312115Sdyson crypto_op_notification(reqp->dr_kcf_req, errno); 18412115Sdyson DBG(reqp->dr_dca, DINTR, 18512115Sdyson "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification", 18612115Sdyson errno); 18712115Sdyson 18812115Sdyson /* 18912115Sdyson * For non-atomic operations, reqp will be freed in the kCF 19012115Sdyson * callback function since it may be needed again if 19112115Sdyson * CRYPTO_BUFFER_TOO_SMALL is returned to kCF 19212115Sdyson */ 19312115Sdyson if (reqp->dr_ctx.atomic) { 19443301Sdillon crypto_ctx_t ctx; 19543301Sdillon ctx.cc_provider_private = reqp; 19612115Sdyson dca_dsactxfree(&ctx); 19712115Sdyson } 19812115Sdyson} 19912115Sdyson 20012115Sdysonint 20112115Sdysondca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 20212115Sdyson crypto_req_handle_t req) 20312115Sdyson{ 20412115Sdyson dca_request_t *reqp = ctx->cc_provider_private; 20543301Sdillon dca_t *dca = ctx->cc_provider; 20612115Sdyson int err; 20712115Sdyson int rv = CRYPTO_QUEUED; 20812115Sdyson caddr_t kaddr; 20912115Sdyson 21012115Sdyson /* Impossible for verify to be an in-place operation. */ 21112115Sdyson if (sig == NULL) { 21212115Sdyson rv = CRYPTO_ARGUMENTS_BAD; 21312115Sdyson goto errout; 21412115Sdyson } 21512115Sdyson 21612115Sdyson if (dca_length(data) != SHA1LEN) { 21712115Sdyson DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN); 21812115Sdyson rv = CRYPTO_DATA_LEN_RANGE; 21912115Sdyson goto errout; 22012115Sdyson } 22112115Sdyson 22212115Sdyson if (dca_length(sig) != DSASIGLEN) { 22312115Sdyson DBG(dca, DWARN, "dca_dsa_verify: signature length != %d", 22412115Sdyson DSASIGLEN); 22512115Sdyson rv = CRYPTO_SIGNATURE_LEN_RANGE; 22612115Sdyson goto errout; 22712115Sdyson } 22812115Sdyson 22912115Sdyson /* Don't change the data & sig values for verify. */ 23012115Sdyson 23112115Sdyson reqp->dr_job_stat = DS_DSAVERIFY; 23212115Sdyson reqp->dr_byte_stat = -1; 23312115Sdyson 23412115Sdyson /* 23512115Sdyson * Grab h, r and s. 23612115Sdyson */ 23712115Sdyson err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1); 23812115Sdyson if (err != CRYPTO_SUCCESS) { 23912115Sdyson DBG(dca, DWARN, 24012115Sdyson "dca_dsa_vrfy: dca_gather() failed for h"); 24112115Sdyson rv = err; 24212115Sdyson goto errout; 24312115Sdyson } 24443301Sdillon err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1); 24543301Sdillon if (err != CRYPTO_SUCCESS) { 24612115Sdyson DBG(dca, DWARN, 24712115Sdyson "dca_dsa_vrfy: dca_gather() failed for r"); 24812115Sdyson rv = err; 24912115Sdyson goto errout; 25012115Sdyson } 25112115Sdyson err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN, 25212115Sdyson DSAPARTLEN, 1); 25312115Sdyson if (err != CRYPTO_SUCCESS) { 25412115Sdyson DBG(dca, DWARN, 25512115Sdyson "dca_dsa_vrfy: dca_gather() failed for s"); 25612115Sdyson rv = err; 25743301Sdillon goto errout; 25812115Sdyson } 25912115Sdyson /* 26012115Sdyson * As dca_gather() increments the cd_offset and decrements 26112115Sdyson * the cd_length as it copies the data rewind the values ready for 26212115Sdyson * the final compare. 26312115Sdyson */ 26412115Sdyson sig->cd_offset -= (DSAPARTLEN * 2); 26512115Sdyson sig->cd_length += (DSAPARTLEN * 2); 26612115Sdyson /* sync the input buffer */ 26712115Sdyson (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN, 26812115Sdyson DDI_DMA_SYNC_FORDEV); 26912115Sdyson 27012115Sdyson if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 27112115Sdyson DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 27212115Sdyson reqp->destroy = TRUE; 27312115Sdyson rv = CRYPTO_DEVICE_ERROR; 27412115Sdyson goto errout; 27512115Sdyson } 27612115Sdyson 27712115Sdyson reqp->dr_in = data; 27812115Sdyson reqp->dr_out = sig; 27943301Sdillon reqp->dr_kcf_req = req; 28043301Sdillon reqp->dr_flags |= DR_SCATTER | DR_GATHER; 28112115Sdyson reqp->dr_callback = dca_dsa_verify_done; 28212115Sdyson 28312115Sdyson /* 28412115Sdyson * Input requires three buffers. m, followed by r, followed by s. 28512115Sdyson * In order to deal with things cleanly, we reverse the signature 28612115Sdyson * into the buffer and then fix up the pointers. 28712115Sdyson */ 28812115Sdyson reqp->dr_pkt_length = SHA1LEN; 28912115Sdyson 29012115Sdyson reqp->dr_in_paddr = reqp->dr_ibuf_paddr; 29112115Sdyson reqp->dr_in_len = SHA1LEN; 29212115Sdyson reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset; 29312115Sdyson 29412115Sdyson reqp->dr_out_paddr = reqp->dr_obuf_paddr; 29512115Sdyson reqp->dr_out_len = DSAPARTLEN; 29612115Sdyson reqp->dr_out_next = 0; 29712115Sdyson 29812115Sdyson /* setup 1st chain for r */ 29912115Sdyson kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset; 30012115Sdyson PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN); 30112115Sdyson PUTDESC32(reqp, kaddr, DESC_NEXT, 30212115Sdyson reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE); 30312115Sdyson PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 30412115Sdyson PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 30512115Sdyson 30612115Sdyson /* and 2nd chain for s */ 30712115Sdyson kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE; 30812115Sdyson PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + 30912115Sdyson SHA1LEN + DSAPARTLEN); 31012115Sdyson PUTDESC32(reqp, kaddr, DESC_NEXT, 0); 31112115Sdyson PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 31212115Sdyson PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 31312115Sdyson 31412115Sdyson /* schedule the work by doing a submit */ 31512115Sdyson rv = dca_start(dca, reqp, MCR2, 1); 316 317errout: 318 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) { 319 (void) dca_free_context(ctx); 320 } 321 return (rv); 322} 323 324static void 325dca_dsa_verify_done(dca_request_t *reqp, int errno) 326{ 327 if (errno == CRYPTO_SUCCESS) { 328 int count = DSAPARTLEN; 329 crypto_data_t *sig = reqp->dr_out; 330 caddr_t daddr; 331 332 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, count, 333 DDI_DMA_SYNC_FORKERNEL); 334 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah, 335 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 336 reqp->destroy = TRUE; 337 errno = CRYPTO_DEVICE_ERROR; 338 goto errout; 339 } 340 341 /* Can only handle a contiguous data buffer currently. */ 342 if (dca_sgcheck(reqp->dr_dca, sig, DCA_SG_CONTIG)) { 343 errno = CRYPTO_SIGNATURE_INVALID; 344 goto errout; 345 } 346 347 if ((daddr = dca_bufdaddr(sig)) == NULL) { 348 errno = CRYPTO_ARGUMENTS_BAD; 349 goto errout; 350 } 351 352 if (dca_bcmp_reverse(daddr, reqp->dr_obuf_kaddr, 353 DSAPARTLEN) != 0) { 354 /* VERIFY FAILED */ 355 errno = CRYPTO_SIGNATURE_INVALID; 356 } 357 } 358errout: 359 ASSERT(reqp->dr_kcf_req != NULL); 360 361 /* notify framework that request is completed */ 362 363 crypto_op_notification(reqp->dr_kcf_req, errno); 364 DBG(reqp->dr_dca, DINTR, 365 "dca_dsa_verify_done: rtn 0x%x to kef via crypto_op_notification", 366 errno); 367 368 /* 369 * For non-atomic operations, reqp will be freed in the kCF 370 * callback function since it may be needed again if 371 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF 372 */ 373 if (reqp->dr_ctx.atomic) { 374 crypto_ctx_t ctx; 375 ctx.cc_provider_private = reqp; 376 dca_dsactxfree(&ctx); 377 } 378} 379 380/* ARGSUSED */ 381int 382dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 383 crypto_key_t *key, int kmflag, int mode) 384{ 385 crypto_object_attribute_t *attr; 386 unsigned plen = 0, qlen = 0, glen = 0, xlen = 0; 387 uchar_t *p, *q, *g, *x; 388 dca_request_t *reqp = NULL; 389 dca_t *dca = (dca_t *)ctx->cc_provider; 390 int rv = CRYPTO_SUCCESS; 391 unsigned pbits, padjlen; 392 uint16_t ctxlen; 393 caddr_t kaddr; 394 395 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) { 396 dca_error(dca, 397 "dca_dsainit: unable to allocate request for DSA"); 398 rv = CRYPTO_HOST_MEMORY; 399 goto errout; 400 } 401 402 ctx->cc_provider_private = reqp; 403 reqp->dr_ctx.ctx_cm_type = mechanism->cm_type; 404 405 if ((attr = dca_get_key_attr(key)) == NULL) { 406 DBG(NULL, DWARN, "dca_dsainit: key attributes missing"); 407 rv = CRYPTO_KEY_TYPE_INCONSISTENT; 408 goto errout; 409 } 410 411 /* Prime */ 412 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_PRIME, 413 (void *) &p, &plen)) { 414 DBG(NULL, DWARN, "dca_dsainit: prime key value not present"); 415 rv = CRYPTO_ARGUMENTS_BAD; 416 goto errout; 417 } 418 419 /* Subprime */ 420 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_SUBPRIME, 421 (void *) &q, &qlen)) { 422 DBG(NULL, DWARN, "dca_dsainit: subprime key value not present"); 423 rv = CRYPTO_ARGUMENTS_BAD; 424 goto errout; 425 } 426 427 /* Base */ 428 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_BASE, 429 (void *) &g, &glen)) { 430 DBG(NULL, DWARN, "dca_dsainit: base key value not present"); 431 rv = CRYPTO_ARGUMENTS_BAD; 432 goto errout; 433 } 434 435 /* Value */ 436 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_VALUE, 437 (void *) &x, &xlen)) { 438 DBG(NULL, DWARN, "dca_dsainit: value key not present"); 439 rv = CRYPTO_ARGUMENTS_BAD; 440 goto errout; 441 } 442 443 if (plen == 0 || qlen == 0 || glen == 0 || xlen == 0) { 444 rv = CRYPTO_ARGUMENTS_BAD; 445 goto errout; 446 } 447 448 if (plen > DSA_MAX_KEY_LEN) { 449 /* maximum 1Kbit key */ 450 DBG(NULL, DWARN, "dca_dsainit: maximum 1Kbit key (%d)", plen); 451 rv = CRYPTO_KEY_SIZE_RANGE; 452 goto errout; 453 } 454 455 if (qlen > DSAPARTLEN) { 456 DBG(NULL, DWARN, "dca_dsainit: q is too long (%d)", qlen); 457 rv = CRYPTO_KEY_SIZE_RANGE; 458 goto errout; 459 } 460 461 if (mode == DCA_DSA_SIGN && xlen > DSAPARTLEN) { 462 DBG(NULL, DWARN, 463 "dca_dsainit: private key is too long (%d)", xlen); 464 rv = CRYPTO_KEY_SIZE_RANGE; 465 goto errout; 466 } 467 468 /* 469 * Setup the key partion of the request. 470 */ 471 472 pbits = dca_bitlen(p, plen); 473 padjlen = dca_padfull(pbits); 474 475 /* accounts for leading context words */ 476 if (mode == DCA_DSA_SIGN) { 477 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 2) + 478 DSAPARTLEN; 479 PUTCTX16(reqp, CTX_CMD, CMD_DSASIGN); 480 } else { 481 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 3); 482 PUTCTX16(reqp, CTX_CMD, CMD_DSAVERIFY); 483 } 484 485 PUTCTX16(reqp, CTX_LENGTH, ctxlen); 486 PUTCTX16(reqp, CTX_DSAMSGTYPE, CTX_DSAMSGTYPE_SHA1); 487 PUTCTX16(reqp, CTX_DSARSVD, 0); 488 if (mode == DCA_DSA_SIGN) 489 PUTCTX16(reqp, CTX_DSARNG, CTX_DSARNG_GEN); 490 else 491 PUTCTX16(reqp, CTX_DSARNG, 0); 492 PUTCTX16(reqp, CTX_DSAPLEN, pbits); 493 494 kaddr = reqp->dr_ctx_kaddr + CTX_DSABIGNUMS; 495 496 /* store the bignums */ 497 dca_reverse(q, kaddr, qlen, DSAPARTLEN); 498 kaddr += DSAPARTLEN; 499 500 dca_reverse(p, kaddr, plen, padjlen); 501 kaddr += padjlen; 502 503 dca_reverse(g, kaddr, glen, padjlen); 504 kaddr += padjlen; 505 506 if (mode == DCA_DSA_SIGN) { 507 dca_reverse(x, kaddr, xlen, DSAPARTLEN); 508 kaddr += DSAPARTLEN; 509 } else { 510 dca_reverse(x, kaddr, xlen, padjlen); 511 kaddr += padjlen; 512 } 513 514 return (CRYPTO_SUCCESS); 515 516errout: 517 518 dca_dsactxfree(ctx); 519 return (rv); 520} 521 522void 523dca_dsactxfree(void *arg) 524{ 525 crypto_ctx_t *ctx = (crypto_ctx_t *)arg; 526 dca_request_t *reqp = ctx->cc_provider_private; 527 528 if (reqp == NULL) 529 return; 530 531 reqp->dr_ctx.ctx_cm_type = 0; 532 reqp->dr_ctx.atomic = 0; 533 if (reqp->destroy) 534 dca_destroyreq(reqp); 535 else 536 dca_freereq(reqp); 537 538 ctx->cc_provider_private = NULL; 539} 540 541int 542dca_dsaatomic(crypto_provider_handle_t provider, 543 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 544 crypto_key_t *key, crypto_data_t *data, crypto_data_t *sig, 545 int kmflag, crypto_req_handle_t req, int mode) 546{ 547 crypto_ctx_t ctx; /* on the stack */ 548 int rv; 549 550 ctx.cc_provider = provider; 551 ctx.cc_session = session_id; 552 553 rv = dca_dsainit(&ctx, mechanism, key, kmflag, mode); 554 if (rv != CRYPTO_SUCCESS) { 555 DBG(NULL, DWARN, "dca_dsaatomic: dca_dsainit() failed"); 556 return (rv); 557 } 558 559 /* 560 * Set the atomic flag so that the hardware callback function 561 * will free the context. 562 */ 563 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1; 564 565 if (mode == DCA_DSA_SIGN) { 566 rv = dca_dsa_sign(&ctx, data, sig, req); 567 } else { 568 ASSERT(mode == DCA_DSA_VRFY); 569 rv = dca_dsa_verify(&ctx, data, sig, req); 570 } 571 572 /* 573 * The context will be freed in the hardware callback function if it 574 * is queued 575 */ 576 if (rv != CRYPTO_QUEUED) 577 dca_dsactxfree(&ctx); 578 579 return (rv); 580} 581