xref: /onnv-gate/usr/src/uts/common/crypto/io/dca_dsa.c (revision 906:1b5a12bcb15b)
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