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