xref: /illumos-gate/usr/src/uts/common/crypto/io/dca_dsa.c (revision a07094369b21309434206d9b3601d162693466fc)
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 2005 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/common.h>
38 #include <sys/crypto/spi.h>
39 #include <sys/crypto/ioctl.h>
40 #include <sys/crypto/dca.h>
41 
42 /*
43  * DSA implementation.
44  */
45 
46 static void dca_dsa_sign_done(dca_request_t *, int);
47 static void dca_dsa_verify_done(dca_request_t *, int);
48 
49 
50 int dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
51     crypto_req_handle_t req);
52 int dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
53     crypto_req_handle_t req);
54 int dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
55     crypto_key_t *key, int kmflag, int mode);
56 
57 
58 int
59 dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
60     crypto_req_handle_t req)
61 {
62 	dca_request_t	*reqp = ctx->cc_provider_private;
63 	dca_t		*dca = ctx->cc_provider;
64 	int		err;
65 	int		rv = CRYPTO_QUEUED;
66 	caddr_t		kaddr;
67 	size_t		buflen;
68 
69 	buflen = dca_length(data);
70 	if (buflen != SHA1LEN) {
71 		DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN);
72 		rv = CRYPTO_DATA_LEN_RANGE;
73 		goto errout;
74 	}
75 
76 	/* Return length needed to store the output. */
77 	if (dca_length(sig) < DSASIGLEN) {
78 		DBG(dca, DWARN,
79 		    "dca_dsa_sign: output buffer too short (%d < %d)",
80 		    dca_length(sig), DSASIGLEN);
81 		sig->cd_length = DSASIGLEN;
82 		rv = CRYPTO_BUFFER_TOO_SMALL;
83 		goto errout;
84 	}
85 
86 	/*
87 	 * Don't change the data values of the data crypto_data_t structure
88 	 * yet. Only reset the sig cd_length to zero before writing to it.
89 	 */
90 
91 	reqp->dr_job_stat = DS_DSASIGN;
92 	reqp->dr_byte_stat = -1;
93 	reqp->dr_in = data;
94 	reqp->dr_out = sig;
95 	reqp->dr_callback = dca_dsa_sign_done;
96 
97 	reqp->dr_kcf_req = req;
98 	/* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */
99 	err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
100 	if (err != CRYPTO_SUCCESS) {
101 		DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed");
102 		rv = err;
103 		goto errout;
104 	}
105 
106 
107 	/* sync the input buffer */
108 	(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN,
109 		DDI_DMA_SYNC_FORDEV);
110 	if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
111 	    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
112 		reqp->destroy = TRUE;
113 		rv = CRYPTO_DEVICE_ERROR;
114 		goto errout;
115 	}
116 
117 	reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
118 	reqp->dr_in_next = 0;
119 	reqp->dr_in_len = SHA1LEN;
120 	reqp->dr_pkt_length = buflen;
121 
122 	/*
123 	 * The output requires *two* buffers, r followed by s.
124 	 */
125 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
126 
127 	/* r */
128 	reqp->dr_out_paddr = reqp->dr_obuf_paddr;
129 	reqp->dr_out_len = DSAPARTLEN;
130 	reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset;
131 
132 	/* s */
133 	PUTDESC32(reqp, kaddr, DESC_BUFADDR,
134 	    reqp->dr_obuf_paddr + DSAPARTLEN);
135 	PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
136 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
137 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
138 
139 	/* schedule the work by doing a submit */
140 	rv = dca_start(dca, reqp, MCR2, 1);
141 
142 errout:
143 
144 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL)
145 		(void) dca_free_context(ctx);
146 
147 	return (rv);
148 }
149 
150 static void
151 dca_dsa_sign_done(dca_request_t *reqp, int errno)
152 {
153 	if (errno == CRYPTO_SUCCESS) {
154 		(void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN,
155 		    DDI_DMA_SYNC_FORKERNEL);
156 		if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
157 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
158 			reqp->destroy = TRUE;
159 			errno = CRYPTO_DEVICE_ERROR;
160 			goto errout;
161 		}
162 		/*
163 		 * Set the sig cd_length to zero so it's ready to take the
164 		 * signature. Have already confirmed its size is adequate.
165 		 */
166 		reqp->dr_out->cd_length = 0;
167 		errno = dca_scatter(reqp->dr_obuf_kaddr,
168 		    reqp->dr_out, DSAPARTLEN, 1);
169 		if (errno != CRYPTO_SUCCESS) {
170 			DBG(reqp->dr_dca, DWARN,
171 			    "dca_dsa_sign_done: dca_scatter() failed");
172 			goto errout;
173 		}
174 		errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN,
175 		    reqp->dr_out, DSAPARTLEN, 1);
176 		if (errno != CRYPTO_SUCCESS) {
177 			DBG(reqp->dr_dca, DWARN,
178 			    "dca_dsa_sign_done: dca_scatter() failed");
179 		}
180 	}
181 errout:
182 	ASSERT(reqp->dr_kcf_req != NULL);
183 
184 	/* notify framework that request is completed */
185 	crypto_op_notification(reqp->dr_kcf_req, errno);
186 	DBG(reqp->dr_dca, DINTR,
187 	    "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification",
188 	    errno);
189 
190 	/*
191 	 * For non-atomic operations, reqp will be freed in the kCF
192 	 * callback function since it may be needed again if
193 	 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
194 	 */
195 	if (reqp->dr_ctx.atomic) {
196 		crypto_ctx_t ctx;
197 		ctx.cc_provider_private = reqp;
198 		dca_dsactxfree(&ctx);
199 	}
200 }
201 
202 int
203 dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
204     crypto_req_handle_t req)
205 {
206 	dca_request_t	*reqp = ctx->cc_provider_private;
207 	dca_t		*dca = ctx->cc_provider;
208 	int		err;
209 	int		rv = CRYPTO_QUEUED;
210 	caddr_t		kaddr;
211 
212 	/* Impossible for verify to be an in-place operation. */
213 	if (sig == NULL) {
214 		rv = CRYPTO_ARGUMENTS_BAD;
215 		goto errout;
216 	}
217 
218 	if (dca_length(data) != SHA1LEN) {
219 		DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN);
220 		rv = CRYPTO_DATA_LEN_RANGE;
221 		goto errout;
222 	}
223 
224 	if (dca_length(sig) != DSASIGLEN) {
225 		DBG(dca, DWARN, "dca_dsa_verify: signature length != %d",
226 		    DSASIGLEN);
227 		rv = CRYPTO_SIGNATURE_LEN_RANGE;
228 		goto errout;
229 	}
230 
231 	/* Don't change the data & sig values for verify. */
232 
233 	reqp->dr_job_stat = DS_DSAVERIFY;
234 	reqp->dr_byte_stat = -1;
235 
236 	/*
237 	 * Grab h, r and s.
238 	 */
239 	err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
240 	if (err != CRYPTO_SUCCESS) {
241 		DBG(dca, DWARN,
242 		    "dca_dsa_vrfy: dca_gather() failed for h");
243 		rv = err;
244 		goto errout;
245 	}
246 	err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1);
247 	if (err != CRYPTO_SUCCESS) {
248 		DBG(dca, DWARN,
249 		    "dca_dsa_vrfy: dca_gather() failed for r");
250 		rv = err;
251 		goto errout;
252 	}
253 	err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN,
254 	    DSAPARTLEN, 1);
255 	if (err != CRYPTO_SUCCESS) {
256 		DBG(dca, DWARN,
257 		    "dca_dsa_vrfy: dca_gather() failed for s");
258 		rv = err;
259 		goto errout;
260 	}
261 	/*
262 	 * As dca_gather() increments the cd_offset and decrements
263 	 * the cd_length as it copies the data rewind the values ready for
264 	 * the final compare.
265 	 */
266 	sig->cd_offset -= (DSAPARTLEN * 2);
267 	sig->cd_length += (DSAPARTLEN * 2);
268 	/* sync the input buffer */
269 	(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN,
270 	    DDI_DMA_SYNC_FORDEV);
271 
272 	if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
273 	    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
274 		reqp->destroy = TRUE;
275 		rv = CRYPTO_DEVICE_ERROR;
276 		goto errout;
277 	}
278 
279 	reqp->dr_in = data;
280 	reqp->dr_out = sig;
281 	reqp->dr_kcf_req = req;
282 	reqp->dr_flags |= DR_SCATTER | DR_GATHER;
283 	reqp->dr_callback = dca_dsa_verify_done;
284 
285 	/*
286 	 * Input requires three buffers.  m, followed by r, followed by s.
287 	 * In order to deal with things cleanly, we reverse the signature
288 	 * into the buffer and then fix up the pointers.
289 	 */
290 	reqp->dr_pkt_length = SHA1LEN;
291 
292 	reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
293 	reqp->dr_in_len = SHA1LEN;
294 	reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset;
295 
296 	reqp->dr_out_paddr = reqp->dr_obuf_paddr;
297 	reqp->dr_out_len = DSAPARTLEN;
298 	reqp->dr_out_next = 0;
299 
300 	/* setup 1st chain for r */
301 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
302 	PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN);
303 	PUTDESC32(reqp, kaddr, DESC_NEXT,
304 	    reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE);
305 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
306 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
307 
308 	/* and 2nd chain for s */
309 	kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE;
310 	PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr +
311 	    SHA1LEN + DSAPARTLEN);
312 	PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
313 	PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
314 	PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
315 
316 	/* schedule the work by doing a submit */
317 	rv = dca_start(dca, reqp, MCR2, 1);
318 
319 errout:
320 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
321 		(void) dca_free_context(ctx);
322 	}
323 	return (rv);
324 }
325 
326 static void
327 dca_dsa_verify_done(dca_request_t *reqp, int errno)
328 {
329 	if (errno == CRYPTO_SUCCESS) {
330 		int		count = DSAPARTLEN;
331 		crypto_data_t	*sig = reqp->dr_out;
332 		caddr_t		daddr;
333 
334 		(void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, count,
335 		    DDI_DMA_SYNC_FORKERNEL);
336 		if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
337 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
338 			reqp->destroy = TRUE;
339 			errno = CRYPTO_DEVICE_ERROR;
340 			goto errout;
341 		}
342 
343 		/* Can only handle a contiguous data buffer currently. */
344 		if (dca_sgcheck(reqp->dr_dca, sig, DCA_SG_CONTIG)) {
345 			errno = CRYPTO_SIGNATURE_INVALID;
346 			goto errout;
347 		}
348 
349 		if ((daddr = dca_bufdaddr(sig)) == NULL) {
350 			errno = CRYPTO_ARGUMENTS_BAD;
351 			goto errout;
352 		}
353 
354 		if (dca_bcmp_reverse(daddr, reqp->dr_obuf_kaddr,
355 		    DSAPARTLEN) != 0) {
356 			/* VERIFY FAILED */
357 			errno = CRYPTO_SIGNATURE_INVALID;
358 		}
359 	}
360 errout:
361 	ASSERT(reqp->dr_kcf_req != NULL);
362 
363 	/* notify framework that request is completed */
364 
365 	crypto_op_notification(reqp->dr_kcf_req, errno);
366 	DBG(reqp->dr_dca, DINTR,
367 	    "dca_dsa_verify_done: rtn 0x%x to kef via crypto_op_notification",
368 	    errno);
369 
370 	/*
371 	 * For non-atomic operations, reqp will be freed in the kCF
372 	 * callback function since it may be needed again if
373 	 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
374 	 */
375 	if (reqp->dr_ctx.atomic) {
376 		crypto_ctx_t ctx;
377 		ctx.cc_provider_private = reqp;
378 		dca_dsactxfree(&ctx);
379 	}
380 }
381 
382 /* ARGSUSED */
383 int
384 dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
385     crypto_key_t *key, int kmflag, int mode)
386 {
387 	crypto_object_attribute_t	*attr;
388 	unsigned			plen = 0, qlen = 0, glen = 0, xlen = 0;
389 	uchar_t				*p, *q, *g, *x;
390 	dca_request_t			*reqp = NULL;
391 	dca_t				*dca = (dca_t *)ctx->cc_provider;
392 	int				rv = CRYPTO_SUCCESS;
393 	unsigned			pbits, padjlen;
394 	uint16_t			ctxlen;
395 	caddr_t				kaddr;
396 
397 	if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) {
398 		dca_error(dca,
399 		    "dca_dsainit: unable to allocate request for DSA");
400 		rv = CRYPTO_HOST_MEMORY;
401 		goto errout;
402 	}
403 
404 	ctx->cc_provider_private = reqp;
405 	reqp->dr_ctx.ctx_cm_type = mechanism->cm_type;
406 
407 	if ((attr = dca_get_key_attr(key)) == NULL) {
408 		DBG(NULL, DWARN, "dca_dsainit: key attributes missing");
409 		rv = CRYPTO_KEY_TYPE_INCONSISTENT;
410 		goto errout;
411 	}
412 
413 	/* Prime */
414 	if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_PRIME,
415 	    (void *) &p, &plen)) {
416 		DBG(NULL, DWARN, "dca_dsainit: prime key value not present");
417 		rv = CRYPTO_ARGUMENTS_BAD;
418 		goto errout;
419 	}
420 
421 	/* Subprime */
422 	if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_SUBPRIME,
423 	    (void *) &q, &qlen)) {
424 		DBG(NULL, DWARN, "dca_dsainit: subprime key value not present");
425 		rv = CRYPTO_ARGUMENTS_BAD;
426 		goto errout;
427 	}
428 
429 	/* Base */
430 	if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_BASE,
431 	    (void *) &g, &glen)) {
432 		DBG(NULL, DWARN, "dca_dsainit: base key value not present");
433 		rv = CRYPTO_ARGUMENTS_BAD;
434 		goto errout;
435 	}
436 
437 	/* Value */
438 	if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_VALUE,
439 	    (void *) &x, &xlen)) {
440 		DBG(NULL, DWARN, "dca_dsainit: value key not present");
441 		rv = CRYPTO_ARGUMENTS_BAD;
442 		goto errout;
443 	}
444 
445 	if (plen == 0 || qlen == 0 || glen == 0 || xlen == 0) {
446 		rv = CRYPTO_ARGUMENTS_BAD;
447 		goto errout;
448 	}
449 
450 	if (plen > DSA_MAX_KEY_LEN) {
451 		/* maximum 1Kbit key */
452 		DBG(NULL, DWARN, "dca_dsainit: maximum 1Kbit key (%d)", plen);
453 		rv = CRYPTO_KEY_SIZE_RANGE;
454 		goto errout;
455 	}
456 
457 	if (qlen > DSAPARTLEN) {
458 		DBG(NULL, DWARN, "dca_dsainit: q is too long (%d)", qlen);
459 		rv = CRYPTO_KEY_SIZE_RANGE;
460 		goto errout;
461 	}
462 
463 	if (mode == DCA_DSA_SIGN && xlen > DSAPARTLEN) {
464 		DBG(NULL, DWARN,
465 		    "dca_dsainit: private key is too long (%d)", xlen);
466 		rv = CRYPTO_KEY_SIZE_RANGE;
467 		goto errout;
468 	}
469 
470 	/*
471 	 * Setup the key partion of the request.
472 	 */
473 
474 	pbits = dca_bitlen(p, plen);
475 	padjlen = dca_padfull(pbits);
476 
477 	/* accounts for leading context words */
478 	if (mode == DCA_DSA_SIGN) {
479 		ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 2) +
480 		    DSAPARTLEN;
481 		PUTCTX16(reqp, CTX_CMD, CMD_DSASIGN);
482 	} else {
483 		ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 3);
484 		PUTCTX16(reqp, CTX_CMD, CMD_DSAVERIFY);
485 	}
486 
487 	PUTCTX16(reqp, CTX_LENGTH, ctxlen);
488 	PUTCTX16(reqp, CTX_DSAMSGTYPE, CTX_DSAMSGTYPE_SHA1);
489 	PUTCTX16(reqp, CTX_DSARSVD, 0);
490 	if (mode == DCA_DSA_SIGN)
491 		PUTCTX16(reqp, CTX_DSARNG, CTX_DSARNG_GEN);
492 	else
493 		PUTCTX16(reqp, CTX_DSARNG, 0);
494 	PUTCTX16(reqp, CTX_DSAPLEN, pbits);
495 
496 	kaddr = reqp->dr_ctx_kaddr + CTX_DSABIGNUMS;
497 
498 	/* store the bignums */
499 	dca_reverse(q, kaddr, qlen, DSAPARTLEN);
500 	kaddr += DSAPARTLEN;
501 
502 	dca_reverse(p, kaddr, plen, padjlen);
503 	kaddr += padjlen;
504 
505 	dca_reverse(g, kaddr, glen, padjlen);
506 	kaddr += padjlen;
507 
508 	if (mode == DCA_DSA_SIGN) {
509 		dca_reverse(x, kaddr, xlen, DSAPARTLEN);
510 		kaddr += DSAPARTLEN;
511 	} else {
512 		dca_reverse(x, kaddr, xlen, padjlen);
513 		kaddr += padjlen;
514 	}
515 
516 	return (CRYPTO_SUCCESS);
517 
518 errout:
519 
520 	dca_dsactxfree(ctx);
521 	return (rv);
522 }
523 
524 void
525 dca_dsactxfree(void *arg)
526 {
527 	crypto_ctx_t	*ctx = (crypto_ctx_t *)arg;
528 	dca_request_t	*reqp = ctx->cc_provider_private;
529 
530 	if (reqp == NULL)
531 		return;
532 
533 	reqp->dr_ctx.ctx_cm_type = 0;
534 	reqp->dr_ctx.atomic = 0;
535 	if (reqp->destroy)
536 		dca_destroyreq(reqp);
537 	else
538 		dca_freereq(reqp);
539 
540 	ctx->cc_provider_private = NULL;
541 }
542 
543 int
544 dca_dsaatomic(crypto_provider_handle_t provider,
545     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
546     crypto_key_t *key, crypto_data_t *data, crypto_data_t *sig,
547     int kmflag, crypto_req_handle_t req, int mode)
548 {
549 	crypto_ctx_t	ctx;	/* on the stack */
550 	int		rv;
551 
552 	ctx.cc_provider = provider;
553 	ctx.cc_session = session_id;
554 
555 	rv = dca_dsainit(&ctx, mechanism, key, kmflag, mode);
556 	if (rv != CRYPTO_SUCCESS) {
557 		DBG(NULL, DWARN, "dca_dsaatomic: dca_dsainit() failed");
558 		return (rv);
559 	}
560 
561 	/*
562 	 * Set the atomic flag so that the hardware callback function
563 	 * will free the context.
564 	 */
565 	((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
566 
567 	if (mode == DCA_DSA_SIGN) {
568 		rv = dca_dsa_sign(&ctx, data, sig, req);
569 	} else {
570 		ASSERT(mode == DCA_DSA_VRFY);
571 		rv = dca_dsa_verify(&ctx, data, sig, req);
572 	}
573 
574 	/*
575 	 * The context will be freed in the hardware callback function if it
576 	 * is queued
577 	 */
578 	if (rv != CRYPTO_QUEUED)
579 		dca_dsactxfree(&ctx);
580 
581 	return (rv);
582 }
583