xref: /titanic_50/usr/src/uts/common/crypto/io/dca_dsa.c (revision f317a3a3712d9b82387b437ac621db3733d8c804)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Deimos - cryptographic acceleration based upon Broadcom 582x.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/kmem.h>
37 #include <sys/crypto/spi.h>
38 #include <sys/crypto/dca.h>
39 
40 /*
41  * DSA implementation.
42  */
43 
44 static void dca_dsa_sign_done(dca_request_t *, int);
45 static void dca_dsa_verify_done(dca_request_t *, int);
46 
47 
48 int dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
49     crypto_req_handle_t req);
50 int dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
51     crypto_req_handle_t req);
52 int dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
53     crypto_key_t *key, int kmflag, int mode);
54 
55 
56 int
dca_dsa_sign(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * sig,crypto_req_handle_t req)57 dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
58     crypto_req_handle_t req)
59 {
60 	dca_request_t	*reqp = ctx->cc_provider_private;
61 	dca_t		*dca = ctx->cc_provider;
62 	int		err;
63 	int		rv = CRYPTO_QUEUED;
64 	caddr_t		kaddr;
65 	size_t		buflen;
66 
67 	buflen = dca_length(data);
68 	if (buflen != SHA1LEN) {
69 		DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN);
70 		rv = CRYPTO_DATA_LEN_RANGE;
71 		goto errout;
72 	}
73 
74 	/* Return length needed to store the output. */
75 	if (dca_length(sig) < DSASIGLEN) {
76 		DBG(dca, DWARN,
77 		    "dca_dsa_sign: output buffer too short (%d < %d)",
78 		    dca_length(sig), DSASIGLEN);
79 		sig->cd_length = DSASIGLEN;
80 		rv = CRYPTO_BUFFER_TOO_SMALL;
81 		goto errout;
82 	}
83 
84 	/*
85 	 * Don't change the data values of the data crypto_data_t structure
86 	 * yet. Only reset the sig cd_length to zero before writing to it.
87 	 */
88 
89 	reqp->dr_job_stat = DS_DSASIGN;
90 	reqp->dr_byte_stat = -1;
91 	reqp->dr_in = data;
92 	reqp->dr_out = sig;
93 	reqp->dr_callback = dca_dsa_sign_done;
94 
95 	reqp->dr_kcf_req = req;
96 	/* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */
97 	err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
98 	if (err != CRYPTO_SUCCESS) {
99 		DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed");
100 		rv = err;
101 		goto errout;
102 	}
103 
104 
105 	/* sync the input buffer */
106 	(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN,
107 		DDI_DMA_SYNC_FORDEV);
108 	if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
109 	    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
110 		reqp->destroy = TRUE;
111 		rv = CRYPTO_DEVICE_ERROR;
112 		goto errout;
113 	}
114 
115 	reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
116 	reqp->dr_in_next = 0;
117 	reqp->dr_in_len = SHA1LEN;
118 	reqp->dr_pkt_length = buflen;
119 
120 	/*
121 	 * The output requires *two* buffers, r followed by s.
122 	 */
123 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
124 
125 	/* r */
126 	reqp->dr_out_paddr = reqp->dr_obuf_paddr;
127 	reqp->dr_out_len = DSAPARTLEN;
128 	reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset;
129 
130 	/* s */
131 	PUTDESC32(reqp, kaddr, DESC_BUFADDR,
132 	    reqp->dr_obuf_paddr + DSAPARTLEN);
133 	PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
134 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
135 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
136 
137 	/* schedule the work by doing a submit */
138 	rv = dca_start(dca, reqp, MCR2, 1);
139 
140 errout:
141 
142 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL)
143 		(void) dca_free_context(ctx);
144 
145 	return (rv);
146 }
147 
148 static void
dca_dsa_sign_done(dca_request_t * reqp,int errno)149 dca_dsa_sign_done(dca_request_t *reqp, int errno)
150 {
151 	if (errno == CRYPTO_SUCCESS) {
152 		(void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN,
153 		    DDI_DMA_SYNC_FORKERNEL);
154 		if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
155 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
156 			reqp->destroy = TRUE;
157 			errno = CRYPTO_DEVICE_ERROR;
158 			goto errout;
159 		}
160 		/*
161 		 * Set the sig cd_length to zero so it's ready to take the
162 		 * signature. Have already confirmed its size is adequate.
163 		 */
164 		reqp->dr_out->cd_length = 0;
165 		errno = dca_scatter(reqp->dr_obuf_kaddr,
166 		    reqp->dr_out, DSAPARTLEN, 1);
167 		if (errno != CRYPTO_SUCCESS) {
168 			DBG(reqp->dr_dca, DWARN,
169 			    "dca_dsa_sign_done: dca_scatter() failed");
170 			goto errout;
171 		}
172 		errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN,
173 		    reqp->dr_out, DSAPARTLEN, 1);
174 		if (errno != CRYPTO_SUCCESS) {
175 			DBG(reqp->dr_dca, DWARN,
176 			    "dca_dsa_sign_done: dca_scatter() failed");
177 		}
178 	}
179 errout:
180 	ASSERT(reqp->dr_kcf_req != NULL);
181 
182 	/* notify framework that request is completed */
183 	crypto_op_notification(reqp->dr_kcf_req, errno);
184 	DBG(reqp->dr_dca, DINTR,
185 	    "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification",
186 	    errno);
187 
188 	/*
189 	 * For non-atomic operations, reqp will be freed in the kCF
190 	 * callback function since it may be needed again if
191 	 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
192 	 */
193 	if (reqp->dr_ctx.atomic) {
194 		crypto_ctx_t ctx;
195 		ctx.cc_provider_private = reqp;
196 		dca_dsactxfree(&ctx);
197 	}
198 }
199 
200 int
dca_dsa_verify(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * sig,crypto_req_handle_t req)201 dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
202     crypto_req_handle_t req)
203 {
204 	dca_request_t	*reqp = ctx->cc_provider_private;
205 	dca_t		*dca = ctx->cc_provider;
206 	int		err;
207 	int		rv = CRYPTO_QUEUED;
208 	caddr_t		kaddr;
209 
210 	/* Impossible for verify to be an in-place operation. */
211 	if (sig == NULL) {
212 		rv = CRYPTO_ARGUMENTS_BAD;
213 		goto errout;
214 	}
215 
216 	if (dca_length(data) != SHA1LEN) {
217 		DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN);
218 		rv = CRYPTO_DATA_LEN_RANGE;
219 		goto errout;
220 	}
221 
222 	if (dca_length(sig) != DSASIGLEN) {
223 		DBG(dca, DWARN, "dca_dsa_verify: signature length != %d",
224 		    DSASIGLEN);
225 		rv = CRYPTO_SIGNATURE_LEN_RANGE;
226 		goto errout;
227 	}
228 
229 	/* Don't change the data & sig values for verify. */
230 
231 	reqp->dr_job_stat = DS_DSAVERIFY;
232 	reqp->dr_byte_stat = -1;
233 
234 	/*
235 	 * Grab h, r and s.
236 	 */
237 	err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
238 	if (err != CRYPTO_SUCCESS) {
239 		DBG(dca, DWARN,
240 		    "dca_dsa_vrfy: dca_gather() failed for h");
241 		rv = err;
242 		goto errout;
243 	}
244 	err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1);
245 	if (err != CRYPTO_SUCCESS) {
246 		DBG(dca, DWARN,
247 		    "dca_dsa_vrfy: dca_gather() failed for r");
248 		rv = err;
249 		goto errout;
250 	}
251 	err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN,
252 	    DSAPARTLEN, 1);
253 	if (err != CRYPTO_SUCCESS) {
254 		DBG(dca, DWARN,
255 		    "dca_dsa_vrfy: dca_gather() failed for s");
256 		rv = err;
257 		goto errout;
258 	}
259 	/*
260 	 * As dca_gather() increments the cd_offset and decrements
261 	 * the cd_length as it copies the data rewind the values ready for
262 	 * the final compare.
263 	 */
264 	sig->cd_offset -= (DSAPARTLEN * 2);
265 	sig->cd_length += (DSAPARTLEN * 2);
266 	/* sync the input buffer */
267 	(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN,
268 	    DDI_DMA_SYNC_FORDEV);
269 
270 	if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
271 	    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
272 		reqp->destroy = TRUE;
273 		rv = CRYPTO_DEVICE_ERROR;
274 		goto errout;
275 	}
276 
277 	reqp->dr_in = data;
278 	reqp->dr_out = sig;
279 	reqp->dr_kcf_req = req;
280 	reqp->dr_flags |= DR_SCATTER | DR_GATHER;
281 	reqp->dr_callback = dca_dsa_verify_done;
282 
283 	/*
284 	 * Input requires three buffers.  m, followed by r, followed by s.
285 	 * In order to deal with things cleanly, we reverse the signature
286 	 * into the buffer and then fix up the pointers.
287 	 */
288 	reqp->dr_pkt_length = SHA1LEN;
289 
290 	reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
291 	reqp->dr_in_len = SHA1LEN;
292 	reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset;
293 
294 	reqp->dr_out_paddr = reqp->dr_obuf_paddr;
295 	reqp->dr_out_len = DSAPARTLEN;
296 	reqp->dr_out_next = 0;
297 
298 	/* setup 1st chain for r */
299 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
300 	PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN);
301 	PUTDESC32(reqp, kaddr, DESC_NEXT,
302 	    reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE);
303 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
304 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
305 
306 	/* and 2nd chain for s */
307 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE;
308 	PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr +
309 	    SHA1LEN + DSAPARTLEN);
310 	PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
311 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
312 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
313 
314 	/* schedule the work by doing a submit */
315 	rv = dca_start(dca, reqp, MCR2, 1);
316 
317 errout:
318 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
319 		(void) dca_free_context(ctx);
320 	}
321 	return (rv);
322 }
323 
324 static void
dca_dsa_verify_done(dca_request_t * reqp,int errno)325 dca_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 	}
358 errout:
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 */
381 int
dca_dsainit(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag,int mode)382 dca_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 
516 errout:
517 
518 	dca_dsactxfree(ctx);
519 	return (rv);
520 }
521 
522 void
dca_dsactxfree(void * arg)523 dca_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 
541 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)542 dca_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