xref: /titanic_41/usr/src/uts/common/crypto/io/dca_dsa.c (revision f317a3a3712d9b82387b437ac621db3733d8c804)
188f8b78aSgm89044 /*
288f8b78aSgm89044  * CDDL HEADER START
388f8b78aSgm89044  *
488f8b78aSgm89044  * The contents of this file are subject to the terms of the
588f8b78aSgm89044  * Common Development and Distribution License (the "License").
688f8b78aSgm89044  * You may not use this file except in compliance with the License.
788f8b78aSgm89044  *
888f8b78aSgm89044  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
988f8b78aSgm89044  * or http://www.opensolaris.org/os/licensing.
1088f8b78aSgm89044  * See the License for the specific language governing permissions
1188f8b78aSgm89044  * and limitations under the License.
1288f8b78aSgm89044  *
1388f8b78aSgm89044  * When distributing Covered Code, include this CDDL HEADER in each
1488f8b78aSgm89044  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1588f8b78aSgm89044  * If applicable, add the following below this CDDL HEADER, with the
1688f8b78aSgm89044  * fields enclosed by brackets "[]" replaced with your own identifying
1788f8b78aSgm89044  * information: Portions Copyright [yyyy] [name of copyright owner]
1888f8b78aSgm89044  *
1988f8b78aSgm89044  * CDDL HEADER END
2088f8b78aSgm89044  */
2188f8b78aSgm89044 
2288f8b78aSgm89044 /*
23*f317a3a3Skrishna  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2488f8b78aSgm89044  * Use is subject to license terms.
2588f8b78aSgm89044  */
2688f8b78aSgm89044 
2788f8b78aSgm89044 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2888f8b78aSgm89044 
2988f8b78aSgm89044 /*
3088f8b78aSgm89044  * Deimos - cryptographic acceleration based upon Broadcom 582x.
3188f8b78aSgm89044  */
3288f8b78aSgm89044 
3388f8b78aSgm89044 #include <sys/types.h>
3488f8b78aSgm89044 #include <sys/ddi.h>
3588f8b78aSgm89044 #include <sys/sunddi.h>
3688f8b78aSgm89044 #include <sys/kmem.h>
3788f8b78aSgm89044 #include <sys/crypto/spi.h>
3888f8b78aSgm89044 #include <sys/crypto/dca.h>
3988f8b78aSgm89044 
4088f8b78aSgm89044 /*
4188f8b78aSgm89044  * DSA implementation.
4288f8b78aSgm89044  */
4388f8b78aSgm89044 
4488f8b78aSgm89044 static void dca_dsa_sign_done(dca_request_t *, int);
4588f8b78aSgm89044 static void dca_dsa_verify_done(dca_request_t *, int);
4688f8b78aSgm89044 
4788f8b78aSgm89044 
4888f8b78aSgm89044 int dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
4988f8b78aSgm89044     crypto_req_handle_t req);
5088f8b78aSgm89044 int dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
5188f8b78aSgm89044     crypto_req_handle_t req);
5288f8b78aSgm89044 int dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
5388f8b78aSgm89044     crypto_key_t *key, int kmflag, int mode);
5488f8b78aSgm89044 
5588f8b78aSgm89044 
5688f8b78aSgm89044 int
dca_dsa_sign(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * sig,crypto_req_handle_t req)5788f8b78aSgm89044 dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
5888f8b78aSgm89044     crypto_req_handle_t req)
5988f8b78aSgm89044 {
6088f8b78aSgm89044 	dca_request_t	*reqp = ctx->cc_provider_private;
6188f8b78aSgm89044 	dca_t		*dca = ctx->cc_provider;
6288f8b78aSgm89044 	int		err;
6388f8b78aSgm89044 	int		rv = CRYPTO_QUEUED;
6488f8b78aSgm89044 	caddr_t		kaddr;
6588f8b78aSgm89044 	size_t		buflen;
6688f8b78aSgm89044 
6788f8b78aSgm89044 	buflen = dca_length(data);
6888f8b78aSgm89044 	if (buflen != SHA1LEN) {
6988f8b78aSgm89044 		DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN);
7088f8b78aSgm89044 		rv = CRYPTO_DATA_LEN_RANGE;
7188f8b78aSgm89044 		goto errout;
7288f8b78aSgm89044 	}
7388f8b78aSgm89044 
7488f8b78aSgm89044 	/* Return length needed to store the output. */
7588f8b78aSgm89044 	if (dca_length(sig) < DSASIGLEN) {
7688f8b78aSgm89044 		DBG(dca, DWARN,
7788f8b78aSgm89044 		    "dca_dsa_sign: output buffer too short (%d < %d)",
7888f8b78aSgm89044 		    dca_length(sig), DSASIGLEN);
7988f8b78aSgm89044 		sig->cd_length = DSASIGLEN;
8088f8b78aSgm89044 		rv = CRYPTO_BUFFER_TOO_SMALL;
8188f8b78aSgm89044 		goto errout;
8288f8b78aSgm89044 	}
8388f8b78aSgm89044 
8488f8b78aSgm89044 	/*
8588f8b78aSgm89044 	 * Don't change the data values of the data crypto_data_t structure
8688f8b78aSgm89044 	 * yet. Only reset the sig cd_length to zero before writing to it.
8788f8b78aSgm89044 	 */
8888f8b78aSgm89044 
8988f8b78aSgm89044 	reqp->dr_job_stat = DS_DSASIGN;
9088f8b78aSgm89044 	reqp->dr_byte_stat = -1;
9188f8b78aSgm89044 	reqp->dr_in = data;
9288f8b78aSgm89044 	reqp->dr_out = sig;
9388f8b78aSgm89044 	reqp->dr_callback = dca_dsa_sign_done;
9488f8b78aSgm89044 
9588f8b78aSgm89044 	reqp->dr_kcf_req = req;
9688f8b78aSgm89044 	/* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */
9788f8b78aSgm89044 	err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
9888f8b78aSgm89044 	if (err != CRYPTO_SUCCESS) {
9988f8b78aSgm89044 		DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed");
10088f8b78aSgm89044 		rv = err;
10188f8b78aSgm89044 		goto errout;
10288f8b78aSgm89044 	}
10388f8b78aSgm89044 
10488f8b78aSgm89044 
10588f8b78aSgm89044 	/* sync the input buffer */
10688f8b78aSgm89044 	(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN,
10788f8b78aSgm89044 		DDI_DMA_SYNC_FORDEV);
10888f8b78aSgm89044 	if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
10988f8b78aSgm89044 	    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
11088f8b78aSgm89044 		reqp->destroy = TRUE;
11188f8b78aSgm89044 		rv = CRYPTO_DEVICE_ERROR;
11288f8b78aSgm89044 		goto errout;
11388f8b78aSgm89044 	}
11488f8b78aSgm89044 
11588f8b78aSgm89044 	reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
11688f8b78aSgm89044 	reqp->dr_in_next = 0;
11788f8b78aSgm89044 	reqp->dr_in_len = SHA1LEN;
11888f8b78aSgm89044 	reqp->dr_pkt_length = buflen;
11988f8b78aSgm89044 
12088f8b78aSgm89044 	/*
12188f8b78aSgm89044 	 * The output requires *two* buffers, r followed by s.
12288f8b78aSgm89044 	 */
12388f8b78aSgm89044 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
12488f8b78aSgm89044 
12588f8b78aSgm89044 	/* r */
12688f8b78aSgm89044 	reqp->dr_out_paddr = reqp->dr_obuf_paddr;
12788f8b78aSgm89044 	reqp->dr_out_len = DSAPARTLEN;
12888f8b78aSgm89044 	reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset;
12988f8b78aSgm89044 
13088f8b78aSgm89044 	/* s */
13188f8b78aSgm89044 	PUTDESC32(reqp, kaddr, DESC_BUFADDR,
13288f8b78aSgm89044 	    reqp->dr_obuf_paddr + DSAPARTLEN);
13388f8b78aSgm89044 	PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
13488f8b78aSgm89044 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
13588f8b78aSgm89044 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
13688f8b78aSgm89044 
13788f8b78aSgm89044 	/* schedule the work by doing a submit */
13888f8b78aSgm89044 	rv = dca_start(dca, reqp, MCR2, 1);
13988f8b78aSgm89044 
14088f8b78aSgm89044 errout:
14188f8b78aSgm89044 
14288f8b78aSgm89044 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL)
14388f8b78aSgm89044 		(void) dca_free_context(ctx);
14488f8b78aSgm89044 
14588f8b78aSgm89044 	return (rv);
14688f8b78aSgm89044 }
14788f8b78aSgm89044 
14888f8b78aSgm89044 static void
dca_dsa_sign_done(dca_request_t * reqp,int errno)14988f8b78aSgm89044 dca_dsa_sign_done(dca_request_t *reqp, int errno)
15088f8b78aSgm89044 {
15188f8b78aSgm89044 	if (errno == CRYPTO_SUCCESS) {
15288f8b78aSgm89044 		(void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN,
15388f8b78aSgm89044 		    DDI_DMA_SYNC_FORKERNEL);
15488f8b78aSgm89044 		if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
15588f8b78aSgm89044 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
15688f8b78aSgm89044 			reqp->destroy = TRUE;
15788f8b78aSgm89044 			errno = CRYPTO_DEVICE_ERROR;
15888f8b78aSgm89044 			goto errout;
15988f8b78aSgm89044 		}
16088f8b78aSgm89044 		/*
16188f8b78aSgm89044 		 * Set the sig cd_length to zero so it's ready to take the
16288f8b78aSgm89044 		 * signature. Have already confirmed its size is adequate.
16388f8b78aSgm89044 		 */
16488f8b78aSgm89044 		reqp->dr_out->cd_length = 0;
16588f8b78aSgm89044 		errno = dca_scatter(reqp->dr_obuf_kaddr,
16688f8b78aSgm89044 		    reqp->dr_out, DSAPARTLEN, 1);
16788f8b78aSgm89044 		if (errno != CRYPTO_SUCCESS) {
16888f8b78aSgm89044 			DBG(reqp->dr_dca, DWARN,
16988f8b78aSgm89044 			    "dca_dsa_sign_done: dca_scatter() failed");
17088f8b78aSgm89044 			goto errout;
17188f8b78aSgm89044 		}
17288f8b78aSgm89044 		errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN,
17388f8b78aSgm89044 		    reqp->dr_out, DSAPARTLEN, 1);
17488f8b78aSgm89044 		if (errno != CRYPTO_SUCCESS) {
17588f8b78aSgm89044 			DBG(reqp->dr_dca, DWARN,
17688f8b78aSgm89044 			    "dca_dsa_sign_done: dca_scatter() failed");
17788f8b78aSgm89044 		}
17888f8b78aSgm89044 	}
17988f8b78aSgm89044 errout:
18088f8b78aSgm89044 	ASSERT(reqp->dr_kcf_req != NULL);
18188f8b78aSgm89044 
18288f8b78aSgm89044 	/* notify framework that request is completed */
18388f8b78aSgm89044 	crypto_op_notification(reqp->dr_kcf_req, errno);
18488f8b78aSgm89044 	DBG(reqp->dr_dca, DINTR,
18588f8b78aSgm89044 	    "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification",
18688f8b78aSgm89044 	    errno);
18788f8b78aSgm89044 
18888f8b78aSgm89044 	/*
18988f8b78aSgm89044 	 * For non-atomic operations, reqp will be freed in the kCF
19088f8b78aSgm89044 	 * callback function since it may be needed again if
19188f8b78aSgm89044 	 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
19288f8b78aSgm89044 	 */
19388f8b78aSgm89044 	if (reqp->dr_ctx.atomic) {
19488f8b78aSgm89044 		crypto_ctx_t ctx;
19588f8b78aSgm89044 		ctx.cc_provider_private = reqp;
19688f8b78aSgm89044 		dca_dsactxfree(&ctx);
19788f8b78aSgm89044 	}
19888f8b78aSgm89044 }
19988f8b78aSgm89044 
20088f8b78aSgm89044 int
dca_dsa_verify(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * sig,crypto_req_handle_t req)20188f8b78aSgm89044 dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
20288f8b78aSgm89044     crypto_req_handle_t req)
20388f8b78aSgm89044 {
20488f8b78aSgm89044 	dca_request_t	*reqp = ctx->cc_provider_private;
20588f8b78aSgm89044 	dca_t		*dca = ctx->cc_provider;
20688f8b78aSgm89044 	int		err;
20788f8b78aSgm89044 	int		rv = CRYPTO_QUEUED;
20888f8b78aSgm89044 	caddr_t		kaddr;
20988f8b78aSgm89044 
21088f8b78aSgm89044 	/* Impossible for verify to be an in-place operation. */
21188f8b78aSgm89044 	if (sig == NULL) {
21288f8b78aSgm89044 		rv = CRYPTO_ARGUMENTS_BAD;
21388f8b78aSgm89044 		goto errout;
21488f8b78aSgm89044 	}
21588f8b78aSgm89044 
21688f8b78aSgm89044 	if (dca_length(data) != SHA1LEN) {
21788f8b78aSgm89044 		DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN);
21888f8b78aSgm89044 		rv = CRYPTO_DATA_LEN_RANGE;
21988f8b78aSgm89044 		goto errout;
22088f8b78aSgm89044 	}
22188f8b78aSgm89044 
22288f8b78aSgm89044 	if (dca_length(sig) != DSASIGLEN) {
22388f8b78aSgm89044 		DBG(dca, DWARN, "dca_dsa_verify: signature length != %d",
22488f8b78aSgm89044 		    DSASIGLEN);
22588f8b78aSgm89044 		rv = CRYPTO_SIGNATURE_LEN_RANGE;
22688f8b78aSgm89044 		goto errout;
22788f8b78aSgm89044 	}
22888f8b78aSgm89044 
22988f8b78aSgm89044 	/* Don't change the data & sig values for verify. */
23088f8b78aSgm89044 
23188f8b78aSgm89044 	reqp->dr_job_stat = DS_DSAVERIFY;
23288f8b78aSgm89044 	reqp->dr_byte_stat = -1;
23388f8b78aSgm89044 
23488f8b78aSgm89044 	/*
23588f8b78aSgm89044 	 * Grab h, r and s.
23688f8b78aSgm89044 	 */
23788f8b78aSgm89044 	err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
23888f8b78aSgm89044 	if (err != CRYPTO_SUCCESS) {
23988f8b78aSgm89044 		DBG(dca, DWARN,
24088f8b78aSgm89044 		    "dca_dsa_vrfy: dca_gather() failed for h");
24188f8b78aSgm89044 		rv = err;
24288f8b78aSgm89044 		goto errout;
24388f8b78aSgm89044 	}
24488f8b78aSgm89044 	err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1);
24588f8b78aSgm89044 	if (err != CRYPTO_SUCCESS) {
24688f8b78aSgm89044 		DBG(dca, DWARN,
24788f8b78aSgm89044 		    "dca_dsa_vrfy: dca_gather() failed for r");
24888f8b78aSgm89044 		rv = err;
24988f8b78aSgm89044 		goto errout;
25088f8b78aSgm89044 	}
25188f8b78aSgm89044 	err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN,
25288f8b78aSgm89044 	    DSAPARTLEN, 1);
25388f8b78aSgm89044 	if (err != CRYPTO_SUCCESS) {
25488f8b78aSgm89044 		DBG(dca, DWARN,
25588f8b78aSgm89044 		    "dca_dsa_vrfy: dca_gather() failed for s");
25688f8b78aSgm89044 		rv = err;
25788f8b78aSgm89044 		goto errout;
25888f8b78aSgm89044 	}
25988f8b78aSgm89044 	/*
26088f8b78aSgm89044 	 * As dca_gather() increments the cd_offset and decrements
26188f8b78aSgm89044 	 * the cd_length as it copies the data rewind the values ready for
26288f8b78aSgm89044 	 * the final compare.
26388f8b78aSgm89044 	 */
26488f8b78aSgm89044 	sig->cd_offset -= (DSAPARTLEN * 2);
26588f8b78aSgm89044 	sig->cd_length += (DSAPARTLEN * 2);
26688f8b78aSgm89044 	/* sync the input buffer */
26788f8b78aSgm89044 	(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN,
26888f8b78aSgm89044 	    DDI_DMA_SYNC_FORDEV);
26988f8b78aSgm89044 
27088f8b78aSgm89044 	if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
27188f8b78aSgm89044 	    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
27288f8b78aSgm89044 		reqp->destroy = TRUE;
27388f8b78aSgm89044 		rv = CRYPTO_DEVICE_ERROR;
27488f8b78aSgm89044 		goto errout;
27588f8b78aSgm89044 	}
27688f8b78aSgm89044 
27788f8b78aSgm89044 	reqp->dr_in = data;
27888f8b78aSgm89044 	reqp->dr_out = sig;
27988f8b78aSgm89044 	reqp->dr_kcf_req = req;
28088f8b78aSgm89044 	reqp->dr_flags |= DR_SCATTER | DR_GATHER;
28188f8b78aSgm89044 	reqp->dr_callback = dca_dsa_verify_done;
28288f8b78aSgm89044 
28388f8b78aSgm89044 	/*
28488f8b78aSgm89044 	 * Input requires three buffers.  m, followed by r, followed by s.
28588f8b78aSgm89044 	 * In order to deal with things cleanly, we reverse the signature
28688f8b78aSgm89044 	 * into the buffer and then fix up the pointers.
28788f8b78aSgm89044 	 */
28888f8b78aSgm89044 	reqp->dr_pkt_length = SHA1LEN;
28988f8b78aSgm89044 
29088f8b78aSgm89044 	reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
29188f8b78aSgm89044 	reqp->dr_in_len = SHA1LEN;
29288f8b78aSgm89044 	reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset;
29388f8b78aSgm89044 
29488f8b78aSgm89044 	reqp->dr_out_paddr = reqp->dr_obuf_paddr;
29588f8b78aSgm89044 	reqp->dr_out_len = DSAPARTLEN;
29688f8b78aSgm89044 	reqp->dr_out_next = 0;
29788f8b78aSgm89044 
29888f8b78aSgm89044 	/* setup 1st chain for r */
29988f8b78aSgm89044 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
30088f8b78aSgm89044 	PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN);
30188f8b78aSgm89044 	PUTDESC32(reqp, kaddr, DESC_NEXT,
30288f8b78aSgm89044 	    reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE);
30388f8b78aSgm89044 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
30488f8b78aSgm89044 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
30588f8b78aSgm89044 
30688f8b78aSgm89044 	/* and 2nd chain for s */
30788f8b78aSgm89044 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE;
30888f8b78aSgm89044 	PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr +
30988f8b78aSgm89044 	    SHA1LEN + DSAPARTLEN);
31088f8b78aSgm89044 	PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
31188f8b78aSgm89044 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
31288f8b78aSgm89044 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
31388f8b78aSgm89044 
31488f8b78aSgm89044 	/* schedule the work by doing a submit */
31588f8b78aSgm89044 	rv = dca_start(dca, reqp, MCR2, 1);
31688f8b78aSgm89044 
31788f8b78aSgm89044 errout:
31888f8b78aSgm89044 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
31988f8b78aSgm89044 		(void) dca_free_context(ctx);
32088f8b78aSgm89044 	}
32188f8b78aSgm89044 	return (rv);
32288f8b78aSgm89044 }
32388f8b78aSgm89044 
32488f8b78aSgm89044 static void
dca_dsa_verify_done(dca_request_t * reqp,int errno)32588f8b78aSgm89044 dca_dsa_verify_done(dca_request_t *reqp, int errno)
32688f8b78aSgm89044 {
32788f8b78aSgm89044 	if (errno == CRYPTO_SUCCESS) {
32888f8b78aSgm89044 		int		count = DSAPARTLEN;
32988f8b78aSgm89044 		crypto_data_t	*sig = reqp->dr_out;
33088f8b78aSgm89044 		caddr_t		daddr;
33188f8b78aSgm89044 
33288f8b78aSgm89044 		(void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, count,
33388f8b78aSgm89044 		    DDI_DMA_SYNC_FORKERNEL);
33488f8b78aSgm89044 		if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
33588f8b78aSgm89044 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
33688f8b78aSgm89044 			reqp->destroy = TRUE;
33788f8b78aSgm89044 			errno = CRYPTO_DEVICE_ERROR;
33888f8b78aSgm89044 			goto errout;
33988f8b78aSgm89044 		}
34088f8b78aSgm89044 
34188f8b78aSgm89044 		/* Can only handle a contiguous data buffer currently. */
34288f8b78aSgm89044 		if (dca_sgcheck(reqp->dr_dca, sig, DCA_SG_CONTIG)) {
34388f8b78aSgm89044 			errno = CRYPTO_SIGNATURE_INVALID;
34488f8b78aSgm89044 			goto errout;
34588f8b78aSgm89044 		}
34688f8b78aSgm89044 
34788f8b78aSgm89044 		if ((daddr = dca_bufdaddr(sig)) == NULL) {
34888f8b78aSgm89044 			errno = CRYPTO_ARGUMENTS_BAD;
34988f8b78aSgm89044 			goto errout;
35088f8b78aSgm89044 		}
35188f8b78aSgm89044 
35288f8b78aSgm89044 		if (dca_bcmp_reverse(daddr, reqp->dr_obuf_kaddr,
35388f8b78aSgm89044 		    DSAPARTLEN) != 0) {
35488f8b78aSgm89044 			/* VERIFY FAILED */
35588f8b78aSgm89044 			errno = CRYPTO_SIGNATURE_INVALID;
35688f8b78aSgm89044 		}
35788f8b78aSgm89044 	}
35888f8b78aSgm89044 errout:
35988f8b78aSgm89044 	ASSERT(reqp->dr_kcf_req != NULL);
36088f8b78aSgm89044 
36188f8b78aSgm89044 	/* notify framework that request is completed */
36288f8b78aSgm89044 
36388f8b78aSgm89044 	crypto_op_notification(reqp->dr_kcf_req, errno);
36488f8b78aSgm89044 	DBG(reqp->dr_dca, DINTR,
36588f8b78aSgm89044 	    "dca_dsa_verify_done: rtn 0x%x to kef via crypto_op_notification",
36688f8b78aSgm89044 	    errno);
36788f8b78aSgm89044 
36888f8b78aSgm89044 	/*
36988f8b78aSgm89044 	 * For non-atomic operations, reqp will be freed in the kCF
37088f8b78aSgm89044 	 * callback function since it may be needed again if
37188f8b78aSgm89044 	 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
37288f8b78aSgm89044 	 */
37388f8b78aSgm89044 	if (reqp->dr_ctx.atomic) {
37488f8b78aSgm89044 		crypto_ctx_t ctx;
37588f8b78aSgm89044 		ctx.cc_provider_private = reqp;
37688f8b78aSgm89044 		dca_dsactxfree(&ctx);
37788f8b78aSgm89044 	}
37888f8b78aSgm89044 }
37988f8b78aSgm89044 
38088f8b78aSgm89044 /* ARGSUSED */
38188f8b78aSgm89044 int
dca_dsainit(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag,int mode)38288f8b78aSgm89044 dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
38388f8b78aSgm89044     crypto_key_t *key, int kmflag, int mode)
38488f8b78aSgm89044 {
38588f8b78aSgm89044 	crypto_object_attribute_t	*attr;
38688f8b78aSgm89044 	unsigned			plen = 0, qlen = 0, glen = 0, xlen = 0;
38788f8b78aSgm89044 	uchar_t				*p, *q, *g, *x;
38888f8b78aSgm89044 	dca_request_t			*reqp = NULL;
38988f8b78aSgm89044 	dca_t				*dca = (dca_t *)ctx->cc_provider;
39088f8b78aSgm89044 	int				rv = CRYPTO_SUCCESS;
39188f8b78aSgm89044 	unsigned			pbits, padjlen;
39288f8b78aSgm89044 	uint16_t			ctxlen;
39388f8b78aSgm89044 	caddr_t				kaddr;
39488f8b78aSgm89044 
39588f8b78aSgm89044 	if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) {
39688f8b78aSgm89044 		dca_error(dca,
39788f8b78aSgm89044 		    "dca_dsainit: unable to allocate request for DSA");
39888f8b78aSgm89044 		rv = CRYPTO_HOST_MEMORY;
39988f8b78aSgm89044 		goto errout;
40088f8b78aSgm89044 	}
40188f8b78aSgm89044 
40288f8b78aSgm89044 	ctx->cc_provider_private = reqp;
40388f8b78aSgm89044 	reqp->dr_ctx.ctx_cm_type = mechanism->cm_type;
40488f8b78aSgm89044 
40588f8b78aSgm89044 	if ((attr = dca_get_key_attr(key)) == NULL) {
40688f8b78aSgm89044 		DBG(NULL, DWARN, "dca_dsainit: key attributes missing");
40788f8b78aSgm89044 		rv = CRYPTO_KEY_TYPE_INCONSISTENT;
40888f8b78aSgm89044 		goto errout;
40988f8b78aSgm89044 	}
41088f8b78aSgm89044 
41188f8b78aSgm89044 	/* Prime */
41288f8b78aSgm89044 	if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_PRIME,
41388f8b78aSgm89044 	    (void *) &p, &plen)) {
41488f8b78aSgm89044 		DBG(NULL, DWARN, "dca_dsainit: prime key value not present");
41588f8b78aSgm89044 		rv = CRYPTO_ARGUMENTS_BAD;
41688f8b78aSgm89044 		goto errout;
41788f8b78aSgm89044 	}
41888f8b78aSgm89044 
41988f8b78aSgm89044 	/* Subprime */
42088f8b78aSgm89044 	if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_SUBPRIME,
42188f8b78aSgm89044 	    (void *) &q, &qlen)) {
42288f8b78aSgm89044 		DBG(NULL, DWARN, "dca_dsainit: subprime key value not present");
42388f8b78aSgm89044 		rv = CRYPTO_ARGUMENTS_BAD;
42488f8b78aSgm89044 		goto errout;
42588f8b78aSgm89044 	}
42688f8b78aSgm89044 
42788f8b78aSgm89044 	/* Base */
42888f8b78aSgm89044 	if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_BASE,
42988f8b78aSgm89044 	    (void *) &g, &glen)) {
43088f8b78aSgm89044 		DBG(NULL, DWARN, "dca_dsainit: base key value not present");
43188f8b78aSgm89044 		rv = CRYPTO_ARGUMENTS_BAD;
43288f8b78aSgm89044 		goto errout;
43388f8b78aSgm89044 	}
43488f8b78aSgm89044 
43588f8b78aSgm89044 	/* Value */
43688f8b78aSgm89044 	if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_VALUE,
43788f8b78aSgm89044 	    (void *) &x, &xlen)) {
43888f8b78aSgm89044 		DBG(NULL, DWARN, "dca_dsainit: value key not present");
43988f8b78aSgm89044 		rv = CRYPTO_ARGUMENTS_BAD;
44088f8b78aSgm89044 		goto errout;
44188f8b78aSgm89044 	}
44288f8b78aSgm89044 
44388f8b78aSgm89044 	if (plen == 0 || qlen == 0 || glen == 0 || xlen == 0) {
44488f8b78aSgm89044 		rv = CRYPTO_ARGUMENTS_BAD;
44588f8b78aSgm89044 		goto errout;
44688f8b78aSgm89044 	}
44788f8b78aSgm89044 
44888f8b78aSgm89044 	if (plen > DSA_MAX_KEY_LEN) {
44988f8b78aSgm89044 		/* maximum 1Kbit key */
45088f8b78aSgm89044 		DBG(NULL, DWARN, "dca_dsainit: maximum 1Kbit key (%d)", plen);
45188f8b78aSgm89044 		rv = CRYPTO_KEY_SIZE_RANGE;
45288f8b78aSgm89044 		goto errout;
45388f8b78aSgm89044 	}
45488f8b78aSgm89044 
45588f8b78aSgm89044 	if (qlen > DSAPARTLEN) {
45688f8b78aSgm89044 		DBG(NULL, DWARN, "dca_dsainit: q is too long (%d)", qlen);
45788f8b78aSgm89044 		rv = CRYPTO_KEY_SIZE_RANGE;
45888f8b78aSgm89044 		goto errout;
45988f8b78aSgm89044 	}
46088f8b78aSgm89044 
46188f8b78aSgm89044 	if (mode == DCA_DSA_SIGN && xlen > DSAPARTLEN) {
46288f8b78aSgm89044 		DBG(NULL, DWARN,
46388f8b78aSgm89044 		    "dca_dsainit: private key is too long (%d)", xlen);
46488f8b78aSgm89044 		rv = CRYPTO_KEY_SIZE_RANGE;
46588f8b78aSgm89044 		goto errout;
46688f8b78aSgm89044 	}
46788f8b78aSgm89044 
46888f8b78aSgm89044 	/*
46988f8b78aSgm89044 	 * Setup the key partion of the request.
47088f8b78aSgm89044 	 */
47188f8b78aSgm89044 
47288f8b78aSgm89044 	pbits = dca_bitlen(p, plen);
47388f8b78aSgm89044 	padjlen = dca_padfull(pbits);
47488f8b78aSgm89044 
47588f8b78aSgm89044 	/* accounts for leading context words */
47688f8b78aSgm89044 	if (mode == DCA_DSA_SIGN) {
47788f8b78aSgm89044 		ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 2) +
47888f8b78aSgm89044 		    DSAPARTLEN;
47988f8b78aSgm89044 		PUTCTX16(reqp, CTX_CMD, CMD_DSASIGN);
48088f8b78aSgm89044 	} else {
48188f8b78aSgm89044 		ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 3);
48288f8b78aSgm89044 		PUTCTX16(reqp, CTX_CMD, CMD_DSAVERIFY);
48388f8b78aSgm89044 	}
48488f8b78aSgm89044 
48588f8b78aSgm89044 	PUTCTX16(reqp, CTX_LENGTH, ctxlen);
48688f8b78aSgm89044 	PUTCTX16(reqp, CTX_DSAMSGTYPE, CTX_DSAMSGTYPE_SHA1);
48788f8b78aSgm89044 	PUTCTX16(reqp, CTX_DSARSVD, 0);
48888f8b78aSgm89044 	if (mode == DCA_DSA_SIGN)
48988f8b78aSgm89044 		PUTCTX16(reqp, CTX_DSARNG, CTX_DSARNG_GEN);
49088f8b78aSgm89044 	else
49188f8b78aSgm89044 		PUTCTX16(reqp, CTX_DSARNG, 0);
49288f8b78aSgm89044 	PUTCTX16(reqp, CTX_DSAPLEN, pbits);
49388f8b78aSgm89044 
49488f8b78aSgm89044 	kaddr = reqp->dr_ctx_kaddr + CTX_DSABIGNUMS;
49588f8b78aSgm89044 
49688f8b78aSgm89044 	/* store the bignums */
49788f8b78aSgm89044 	dca_reverse(q, kaddr, qlen, DSAPARTLEN);
49888f8b78aSgm89044 	kaddr += DSAPARTLEN;
49988f8b78aSgm89044 
50088f8b78aSgm89044 	dca_reverse(p, kaddr, plen, padjlen);
50188f8b78aSgm89044 	kaddr += padjlen;
50288f8b78aSgm89044 
50388f8b78aSgm89044 	dca_reverse(g, kaddr, glen, padjlen);
50488f8b78aSgm89044 	kaddr += padjlen;
50588f8b78aSgm89044 
50688f8b78aSgm89044 	if (mode == DCA_DSA_SIGN) {
50788f8b78aSgm89044 		dca_reverse(x, kaddr, xlen, DSAPARTLEN);
50888f8b78aSgm89044 		kaddr += DSAPARTLEN;
50988f8b78aSgm89044 	} else {
51088f8b78aSgm89044 		dca_reverse(x, kaddr, xlen, padjlen);
51188f8b78aSgm89044 		kaddr += padjlen;
51288f8b78aSgm89044 	}
51388f8b78aSgm89044 
51488f8b78aSgm89044 	return (CRYPTO_SUCCESS);
51588f8b78aSgm89044 
51688f8b78aSgm89044 errout:
51788f8b78aSgm89044 
51888f8b78aSgm89044 	dca_dsactxfree(ctx);
51988f8b78aSgm89044 	return (rv);
52088f8b78aSgm89044 }
52188f8b78aSgm89044 
52288f8b78aSgm89044 void
dca_dsactxfree(void * arg)52388f8b78aSgm89044 dca_dsactxfree(void *arg)
52488f8b78aSgm89044 {
52588f8b78aSgm89044 	crypto_ctx_t	*ctx = (crypto_ctx_t *)arg;
52688f8b78aSgm89044 	dca_request_t	*reqp = ctx->cc_provider_private;
52788f8b78aSgm89044 
52888f8b78aSgm89044 	if (reqp == NULL)
52988f8b78aSgm89044 		return;
53088f8b78aSgm89044 
53188f8b78aSgm89044 	reqp->dr_ctx.ctx_cm_type = 0;
53288f8b78aSgm89044 	reqp->dr_ctx.atomic = 0;
53388f8b78aSgm89044 	if (reqp->destroy)
53488f8b78aSgm89044 		dca_destroyreq(reqp);
53588f8b78aSgm89044 	else
53688f8b78aSgm89044 		dca_freereq(reqp);
53788f8b78aSgm89044 
53888f8b78aSgm89044 	ctx->cc_provider_private = NULL;
53988f8b78aSgm89044 }
54088f8b78aSgm89044 
54188f8b78aSgm89044 int
dca_dsaatomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * sig,int kmflag,crypto_req_handle_t req,int mode)54288f8b78aSgm89044 dca_dsaatomic(crypto_provider_handle_t provider,
54388f8b78aSgm89044     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
54488f8b78aSgm89044     crypto_key_t *key, crypto_data_t *data, crypto_data_t *sig,
54588f8b78aSgm89044     int kmflag, crypto_req_handle_t req, int mode)
54688f8b78aSgm89044 {
54788f8b78aSgm89044 	crypto_ctx_t	ctx;	/* on the stack */
54888f8b78aSgm89044 	int		rv;
54988f8b78aSgm89044 
55088f8b78aSgm89044 	ctx.cc_provider = provider;
55188f8b78aSgm89044 	ctx.cc_session = session_id;
55288f8b78aSgm89044 
55388f8b78aSgm89044 	rv = dca_dsainit(&ctx, mechanism, key, kmflag, mode);
55488f8b78aSgm89044 	if (rv != CRYPTO_SUCCESS) {
55588f8b78aSgm89044 		DBG(NULL, DWARN, "dca_dsaatomic: dca_dsainit() failed");
55688f8b78aSgm89044 		return (rv);
55788f8b78aSgm89044 	}
55888f8b78aSgm89044 
55988f8b78aSgm89044 	/*
56088f8b78aSgm89044 	 * Set the atomic flag so that the hardware callback function
56188f8b78aSgm89044 	 * will free the context.
56288f8b78aSgm89044 	 */
56388f8b78aSgm89044 	((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
56488f8b78aSgm89044 
56588f8b78aSgm89044 	if (mode == DCA_DSA_SIGN) {
56688f8b78aSgm89044 		rv = dca_dsa_sign(&ctx, data, sig, req);
56788f8b78aSgm89044 	} else {
56888f8b78aSgm89044 		ASSERT(mode == DCA_DSA_VRFY);
56988f8b78aSgm89044 		rv = dca_dsa_verify(&ctx, data, sig, req);
57088f8b78aSgm89044 	}
57188f8b78aSgm89044 
57288f8b78aSgm89044 	/*
57388f8b78aSgm89044 	 * The context will be freed in the hardware callback function if it
57488f8b78aSgm89044 	 * is queued
57588f8b78aSgm89044 	 */
57688f8b78aSgm89044 	if (rv != CRYPTO_QUEUED)
57788f8b78aSgm89044 		dca_dsactxfree(&ctx);
57888f8b78aSgm89044 
57988f8b78aSgm89044 	return (rv);
58088f8b78aSgm89044 }
581