xref: /illumos-gate/usr/src/uts/common/crypto/io/dca_3des.c (revision e79c98e6c943cb3032f272714ff4ce6137d40394)
1 
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 /*
31  * Deimos - cryptographic acceleration based upon Broadcom 582x.
32  */
33 
34 #include <sys/types.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/kmem.h>
38 #include <sys/note.h>
39 #include <sys/crypto/common.h>
40 #include <sys/crypto/spi.h>
41 #include <sys/crypto/dca.h>
42 
43 /*
44  * 3DES implementation.
45  */
46 
47 static int dca_3desstart(dca_t *, uint32_t, dca_request_t *);
48 static void dca_3desdone(dca_request_t *, int);
49 
50 
51 int
52 dca_3des(crypto_ctx_t *ctx, crypto_data_t *in,
53     crypto_data_t *out, crypto_req_handle_t req, int flags)
54 {
55 	int			len;
56 	int			rv;
57 	dca_request_t		*reqp = ctx->cc_provider_private;
58 	dca_request_t		*des_ctx = ctx->cc_provider_private;
59 	dca_t			*dca = ctx->cc_provider;
60 	crypto_data_t		*nin = &reqp->dr_ctx.in_dup;
61 
62 	len = dca_length(in);
63 	if (len % DESBLOCK) {
64 		DBG(dca, DWARN, "input not an integral number of DES blocks");
65 		(void) dca_free_context(ctx);
66 		if (flags & DR_DECRYPT) {
67 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
68 		} else {
69 			return (CRYPTO_DATA_LEN_RANGE);
70 		}
71 	}
72 
73 	/*
74 	 * If cd_miscdata non-null then this contains the IV.
75 	 */
76 	if (in->cd_miscdata != NULL) {
77 		uchar_t	*p = (uchar_t *)in->cd_miscdata;
78 		des_ctx->dr_ctx.iv[0] = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];
79 		des_ctx->dr_ctx.iv[1] = p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7];
80 	}
81 
82 	if (len > dca_length(out)) {
83 		DBG(dca, DWARN, "inadequate output space (need %d, got %d)",
84 		    len, dca_length(out));
85 		out->cd_length = len;
86 		/* Do not free the context since the app will call again */
87 		return (CRYPTO_BUFFER_TOO_SMALL);
88 	}
89 
90 	if ((rv = dca_verifyio(in, out)) != CRYPTO_SUCCESS) {
91 		(void) dca_free_context(ctx);
92 		return (rv);
93 	}
94 
95 	/* special handling for null-sized input buffers */
96 	if (len == 0) {
97 		out->cd_length = 0;
98 		(void) dca_free_context(ctx);
99 		return (CRYPTO_SUCCESS);
100 	}
101 
102 	/*
103 	 * Make a local copy of the input crypto_data_t structure. This
104 	 * allows it to be manipulated locally and for dealing with in-place
105 	 * data (ie in == out). Note that "nin" has been pre-allocated,
106 	 * and only fields are copied, not actual data.
107 	 */
108 	if ((rv = dca_dupcrypto(in, nin)) != CRYPTO_SUCCESS) {
109 		(void) dca_free_context(ctx);
110 		return (rv);
111 	}
112 
113 	/* Set output to zero ready to take the processed data */
114 	out->cd_length = 0;
115 
116 	reqp->dr_kcf_req = req;
117 	reqp->dr_in = nin;
118 	reqp->dr_out = out;
119 	reqp->dr_job_stat = DS_3DESJOBS;
120 	reqp->dr_byte_stat = DS_3DESBYTES;
121 
122 	rv = dca_3desstart(dca, flags, reqp);
123 
124 	/* Context will be freed in the kCF callback function otherwise */
125 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
126 		(void) dca_free_context(ctx);
127 	}
128 	return (rv);
129 }
130 
131 
132 void
133 dca_3desctxfree(void *arg)
134 {
135 	crypto_ctx_t	*ctx = (crypto_ctx_t *)arg;
136 	dca_request_t	*des_ctx = ctx->cc_provider_private;
137 
138 	if (des_ctx == NULL)
139 		return;
140 
141 	des_ctx->dr_ctx.atomic = 0;
142 	des_ctx->dr_ctx.ctx_cm_type = 0;
143 	ctx->cc_provider_private = NULL;
144 
145 	if (des_ctx->destroy)
146 		dca_destroyreq(des_ctx);
147 	else
148 		/* Return it to the pool */
149 		dca_freereq(des_ctx);
150 }
151 
152 int
153 dca_3desupdate(crypto_ctx_t *ctx, crypto_data_t *in,
154     crypto_data_t *out, crypto_req_handle_t req, int flags)
155 {
156 	int			len;
157 	int			rawlen;
158 	int			rv;
159 	dca_request_t		*reqp = ctx->cc_provider_private;
160 	dca_request_t		*des_ctx = ctx->cc_provider_private;
161 	dca_t			*dca = ctx->cc_provider;
162 	crypto_data_t		*nin = &reqp->dr_ctx.in_dup;
163 
164 	rawlen = dca_length(in) + des_ctx->dr_ctx.residlen;
165 
166 	len = ROUNDDOWN(rawlen, DESBLOCK);
167 	/*
168 	 * If cd_miscdata non-null then this contains the IV.
169 	 */
170 	if (in->cd_miscdata != NULL) {
171 		uchar_t	*p = (uchar_t *)in->cd_miscdata;
172 		des_ctx->dr_ctx.iv[0] = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];
173 		des_ctx->dr_ctx.iv[1] = p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7];
174 	}
175 
176 	if (len > dca_length(out)) {
177 		DBG(dca, DWARN, "not enough output space (need %d, got %d)",
178 		    len, dca_length(out));
179 		out->cd_length = len;
180 		/* Do not free the context since the app will call again */
181 		return (CRYPTO_BUFFER_TOO_SMALL);
182 	}
183 
184 	if ((rv = dca_verifyio(in, out)) != CRYPTO_SUCCESS) {
185 		(void) dca_free_context(ctx);
186 		return (rv);
187 	}
188 
189 	reqp->dr_kcf_req = req;
190 
191 	/*
192 	 * From here on out, we are committed.
193 	 */
194 
195 	if (len == 0) {
196 		/*
197 		 * No blocks being encrypted, so we just accumulate the
198 		 * input for the next pass and return.
199 		 */
200 		if ((rv = dca_getbufbytes(in, 0,
201 		    (rawlen % DESBLOCK) - des_ctx->dr_ctx.residlen,
202 		    des_ctx->dr_ctx.resid + des_ctx->dr_ctx.residlen)) !=
203 		    CRYPTO_SUCCESS) {
204 			DBG(dca, DWARN,
205 	    "dca_3desupdate: dca_getbufbytes() failed for residual only pass");
206 			dca_freereq(reqp);
207 			return (rv);
208 		}
209 		des_ctx->dr_ctx.residlen = rawlen % DESBLOCK;
210 
211 		out->cd_length = 0;
212 		/*
213 		 * Do not free the context here since it will be done
214 		 * in the final function
215 		 */
216 		return (CRYPTO_SUCCESS);
217 	}
218 
219 	/*
220 	 * Set up rbuf for previous residual data.
221 	 */
222 	if (des_ctx->dr_ctx.residlen) {
223 		bcopy(des_ctx->dr_ctx.resid, des_ctx->dr_ctx.activeresid,
224 		    des_ctx->dr_ctx.residlen);
225 		des_ctx->dr_ctx.activeresidlen = des_ctx->dr_ctx.residlen;
226 	}
227 
228 	/*
229 	 * Locate and save residual data for next encrypt_update.
230 	 */
231 	if ((rv = dca_getbufbytes(in, len - des_ctx->dr_ctx.residlen,
232 	    rawlen % DESBLOCK, des_ctx->dr_ctx.resid)) != CRYPTO_SUCCESS) {
233 		DBG(dca, DWARN, "dca_3desupdate: dca_getbufbytes() failed");
234 		(void) dca_free_context(ctx);
235 		return (rv);
236 	}
237 
238 	/* Calculate new residual length. */
239 	des_ctx->dr_ctx.residlen = rawlen % DESBLOCK;
240 
241 	/*
242 	 * Make a local copy of the input crypto_data_t structure. This
243 	 * allows it to be manipulated locally and for dealing with in-place
244 	 * data (ie in == out).
245 	 */
246 	if ((rv = dca_dupcrypto(in, nin)) != CRYPTO_SUCCESS) {
247 		(void) dca_free_context(ctx);
248 		return (rv);
249 	}
250 
251 	/* Set output to zero ready to take the processed data */
252 	out->cd_length = 0;
253 
254 	reqp->dr_in = nin;
255 	reqp->dr_out = out;
256 	reqp->dr_job_stat = DS_3DESJOBS;
257 	reqp->dr_byte_stat = DS_3DESBYTES;
258 
259 	rv = dca_3desstart(dca, flags, reqp);
260 
261 	/*
262 	 * As this is multi-part the context is cleared on success
263 	 * (CRYPTO_QUEUED) in dca_3desfinal().
264 	 */
265 
266 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
267 		(void) dca_free_context(ctx);
268 	}
269 	return (rv);
270 }
271 
272 int
273 dca_3desfinal(crypto_ctx_t *ctx, crypto_data_t *out, int mode)
274 {
275 	dca_request_t	*des_ctx = ctx->cc_provider_private;
276 	dca_t		*dca = ctx->cc_provider;
277 	int		rv = CRYPTO_SUCCESS;
278 
279 	ASSERT(ctx->cc_provider_private != NULL);
280 	/*
281 	 * There must be no unprocessed ciphertext/plaintext.
282 	 * This happens if the length of the last data is
283 	 * not a multiple of the DES block length.
284 	 */
285 	if (des_ctx->dr_ctx.residlen != 0) {
286 		DBG(dca, DWARN, "dca_3desfinal: invalid nonzero residual");
287 		if (mode & DR_DECRYPT) {
288 			rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
289 		} else {
290 			rv = CRYPTO_DATA_LEN_RANGE;
291 		}
292 	}
293 	(void) dca_free_context(ctx);
294 	out->cd_length = 0;
295 	return (rv);
296 }
297 
298 int
299 dca_3desatomic(crypto_provider_handle_t provider,
300     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
301     crypto_key_t *key, crypto_data_t *input, crypto_data_t *output,
302     int kmflag, crypto_req_handle_t req, int mode)
303 {
304 	crypto_ctx_t	ctx;	/* on the stack */
305 	int		rv;
306 
307 	ctx.cc_provider = provider;
308 	ctx.cc_session = session_id;
309 
310 	/*
311 	 * Input must be a multiple of the block size. This test only
312 	 * works for non-padded mechanisms when the blocksize is 2^N.
313 	 */
314 	if ((dca_length(input) & (DESBLOCK - 1)) != 0) {
315 		DBG(NULL, DWARN, "dca_3desatomic: input not multiple of BS");
316 		if (mode & DR_DECRYPT) {
317 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
318 		} else {
319 			return (CRYPTO_DATA_LEN_RANGE);
320 		}
321 	}
322 
323 	rv = dca_3desctxinit(&ctx, mechanism, key, kmflag, mode);
324 	if (rv != CRYPTO_SUCCESS) {
325 		DBG(NULL, DWARN, "dca_3desatomic: dca_3desctxinit() failed");
326 		return (rv);
327 	}
328 
329 	/*
330 	 * Set the atomic flag so that the hardware callback function
331 	 * will free the context.
332 	 */
333 	((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
334 
335 	/* check for inplace ops */
336 	if (input == output) {
337 		((dca_request_t *)ctx.cc_provider_private)->dr_flags
338 		    |= DR_INPLACE;
339 	}
340 
341 	rv = dca_3des(&ctx, input, output, req, mode);
342 	if ((rv != CRYPTO_QUEUED) && (rv != CRYPTO_SUCCESS)) {
343 		DBG(NULL, DWARN, "dca_3desatomic: dca_3des() failed");
344 		output->cd_length = 0;
345 	}
346 
347 	/*
348 	 * The features of dca_3desfinal() are implemented within
349 	 * dca_3desdone() due to the asynchronous nature of dca_3des().
350 	 */
351 
352 	/*
353 	 * The context will be freed in the hardware callback function if it
354 	 * is queued
355 	 */
356 	if (rv != CRYPTO_QUEUED)
357 		dca_3desctxfree(&ctx);
358 
359 	return (rv);
360 }
361 
362 int
363 dca_3desstart(dca_t *dca, uint32_t flags, dca_request_t *reqp)
364 {
365 	size_t		len;
366 	crypto_data_t	*in = reqp->dr_in;
367 	int		rv;
368 	dca_request_t	*ctx = reqp;
369 	uint32_t	iv[2];
370 
371 	/*
372 	 * Preconditions:
373 	 * 1) in and out point to the "right" buffers.
374 	 * 2) in->b_bcount - in->b_resid == initial offset
375 	 * 3) likewise for out
376 	 * 4) there is enough space in the output
377 	 * 5) we perform a block for block encrypt
378 	 */
379 	len = ctx->dr_ctx.activeresidlen + dca_length(in);
380 	len = ROUNDDOWN(min(len, MAXPACKET), DESBLOCK);
381 	reqp->dr_pkt_length = (uint16_t)len;
382 
383 	/* collect IVs for this pass */
384 	iv[0] = ctx->dr_ctx.iv[0];
385 	iv[1] = ctx->dr_ctx.iv[1];
386 
387 	/*
388 	 * And also, for decrypt, collect the IV for the next pass.  For
389 	 * decrypt, the IV must be collected BEFORE decryption, or else
390 	 * we will lose it.  (For encrypt, we grab the IV AFTER encryption,
391 	 * in dca_3desdone.
392 	 */
393 	if (flags & DR_DECRYPT) {
394 		uchar_t		ivstore[DESBLOCK];
395 		uchar_t		*ivp = ivstore;
396 
397 		/* get last 8 bytes of ciphertext for IV of next op */
398 		/*
399 		 * If we're processing only a DESBLOCKS worth of data
400 		 * and there is active residual present then it will be
401 		 * needed for the IV also.
402 		 */
403 		if ((len == DESBLOCK) && ctx->dr_ctx.activeresidlen) {
404 			/* Bring the active residual into play */
405 			bcopy(ctx->dr_ctx.activeresid, ivstore,
406 			    ctx->dr_ctx.activeresidlen);
407 			rv = dca_getbufbytes(in, 0,
408 			    DESBLOCK - ctx->dr_ctx.activeresidlen,
409 			    ivstore + ctx->dr_ctx.activeresidlen);
410 		} else {
411 			rv = dca_getbufbytes(in,
412 			    len - DESBLOCK - ctx->dr_ctx.activeresidlen,
413 			    DESBLOCK, ivstore);
414 		}
415 
416 		if (rv != CRYPTO_SUCCESS) {
417 			DBG(dca, DWARN,
418 			    "dca_3desstart: dca_getbufbytes() failed");
419 			return (rv);
420 		}
421 
422 		/* store as a pair of native 32-bit values */
423 		ctx->dr_ctx.iv[0] =
424 		    ivp[0]<<24 | ivp[1]<<16 | ivp[2]<<8 | ivp[3];
425 		ctx->dr_ctx.iv[1] =
426 		    ivp[4]<<24 | ivp[5]<<16 | ivp[6]<<8 | ivp[7];
427 	}
428 
429 	/* For now we force a pullup.  Add direct DMA later. */
430 	reqp->dr_flags &= ~(DR_SCATTER | DR_GATHER);
431 	if ((len < dca_mindma) || (ctx->dr_ctx.activeresidlen > 0) ||
432 	    dca_sgcheck(dca, reqp->dr_in, DCA_SG_CONTIG) ||
433 	    dca_sgcheck(dca, reqp->dr_out, DCA_SG_WALIGN)) {
434 		reqp->dr_flags |= DR_SCATTER | DR_GATHER;
435 	}
436 
437 	/* Try to do direct DMA. */
438 	if (!(reqp->dr_flags & (DR_SCATTER | DR_GATHER))) {
439 		if (dca_bindchains(reqp, len, len) == DDI_SUCCESS) {
440 			reqp->dr_in->cd_offset += len;
441 			reqp->dr_in->cd_length -= len;
442 		} else {
443 			DBG(dca, DWARN,
444 			    "dca_3desstart: dca_bindchains() failed");
445 			return (CRYPTO_DEVICE_ERROR);
446 		}
447 	}
448 
449 	/* gather the data into the device */
450 	if (reqp->dr_flags & DR_GATHER) {
451 		rv = dca_resid_gather(in, (char *)ctx->dr_ctx.activeresid,
452 		    &ctx->dr_ctx.activeresidlen, reqp->dr_ibuf_kaddr, len);
453 		if (rv != CRYPTO_SUCCESS) {
454 			DBG(dca, DWARN,
455 			    "dca_3desstart: dca_resid_gather() failed");
456 			return (rv);
457 		}
458 		/*
459 		 * Setup for scattering the result back out
460 		 * The output buffer is a multi-entry chain for x86 and
461 		 * a single entry chain for Sparc.
462 		 * Use the actual length if the first entry is sufficient.
463 		 */
464 		(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, len,
465 		    DDI_DMA_SYNC_FORDEV);
466 		if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
467 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
468 			reqp->destroy = TRUE;
469 			return (CRYPTO_DEVICE_ERROR);
470 		}
471 
472 		reqp->dr_in_paddr = reqp->dr_ibuf_head.dc_buffer_paddr;
473 		reqp->dr_in_next = reqp->dr_ibuf_head.dc_next_paddr;
474 		if (len > reqp->dr_ibuf_head.dc_buffer_length)
475 			reqp->dr_in_len = reqp->dr_ibuf_head.dc_buffer_length;
476 		else
477 			reqp->dr_in_len = len;
478 	}
479 	/*
480 	 * Setup for scattering the result back out
481 	 * The output buffer is a multi-entry chain for x86 and
482 	 * a single entry chain for Sparc.
483 	 * Use the actual length if the first entry is sufficient.
484 	 */
485 	if (reqp->dr_flags & DR_SCATTER) {
486 		reqp->dr_out_paddr = reqp->dr_obuf_head.dc_buffer_paddr;
487 		reqp->dr_out_next = reqp->dr_obuf_head.dc_next_paddr;
488 		if (len > reqp->dr_obuf_head.dc_buffer_length)
489 			reqp->dr_out_len = reqp->dr_obuf_head.dc_buffer_length;
490 		else
491 			reqp->dr_out_len = len;
492 	}
493 
494 	reqp->dr_flags |= flags;
495 	reqp->dr_callback = dca_3desdone;
496 
497 	/* write out the context structure */
498 	PUTCTX32(reqp, CTX_3DESIVHI, iv[0]);
499 	PUTCTX32(reqp, CTX_3DESIVLO, iv[1]);
500 
501 	/* schedule the work by doing a submit */
502 	return (dca_start(dca, reqp, MCR1, 1));
503 }
504 
505 void
506 dca_3desdone(dca_request_t *reqp, int errno)
507 {
508 	crypto_data_t	*out = reqp->dr_out;
509 	dca_request_t	*ctx = reqp;
510 	ASSERT(ctx != NULL);
511 
512 	if (errno == CRYPTO_SUCCESS) {
513 		size_t		off;
514 		/*
515 		 * Save the offset: this has to be done *before* dca_scatter
516 		 * modifies the buffer.  We take the initial offset into the
517 		 * first buf, and add that to the total packet size to find
518 		 * the end of the packet.
519 		 */
520 		off = dca_length(out) + reqp->dr_pkt_length - DESBLOCK;
521 
522 		if (reqp->dr_flags & DR_SCATTER) {
523 			(void) ddi_dma_sync(reqp->dr_obuf_dmah, 0,
524 			    reqp->dr_out_len, DDI_DMA_SYNC_FORKERNEL);
525 			if (dca_check_dma_handle(reqp->dr_dca,
526 			    reqp->dr_obuf_dmah, DCA_FM_ECLASS_NONE) !=
527 			    DDI_SUCCESS) {
528 				reqp->destroy = TRUE;
529 				errno = CRYPTO_DEVICE_ERROR;
530 				goto errout;
531 			}
532 
533 			errno = dca_scatter(reqp->dr_obuf_kaddr,
534 			    reqp->dr_out, reqp->dr_out_len, 0);
535 			if (errno != CRYPTO_SUCCESS) {
536 				DBG(NULL, DWARN,
537 				    "dca_3desdone: dca_scatter() failed");
538 				goto errout;
539 			}
540 
541 		} else {
542 			/* we've processed some more data */
543 			out->cd_length += reqp->dr_pkt_length;
544 		}
545 
546 
547 		/*
548 		 * For encryption only, we have to grab the IV for the
549 		 * next pass AFTER encryption.
550 		 */
551 		if (reqp->dr_flags & DR_ENCRYPT) {
552 			uchar_t		ivstore[DESBLOCK];
553 			uchar_t		*iv = ivstore;
554 
555 			/* get last 8 bytes for IV of next op */
556 			errno = dca_getbufbytes(out, off, DESBLOCK, iv);
557 			if (errno != CRYPTO_SUCCESS) {
558 				DBG(NULL, DWARN,
559 				    "dca_3desdone: dca_getbufbytes() failed");
560 				goto errout;
561 			}
562 			/* store as a pair of native 32-bit values */
563 			ctx->dr_ctx.iv[0] =
564 			    iv[0]<<24 | iv[1]<<16 | iv[2]<<8 | iv[3];
565 			ctx->dr_ctx.iv[1] =
566 			    iv[4]<<24 | iv[5]<<16 | iv[6]<<8 | iv[7];
567 		}
568 
569 		/*
570 		 * If there is more to do, then reschedule another
571 		 * pass.
572 		 */
573 		if (dca_length(reqp->dr_in) >= 8) {
574 			errno = dca_3desstart(reqp->dr_dca, reqp->dr_flags,
575 			    reqp);
576 			if (errno == CRYPTO_QUEUED) {
577 				return;
578 			}
579 		}
580 	}
581 
582 errout:
583 
584 	/*
585 	 * If this is an atomic operation perform the final function
586 	 * tasks (equivalent to to dca_3desfinal()).
587 	 */
588 	if (reqp->dr_ctx.atomic) {
589 		if ((errno == CRYPTO_SUCCESS) && (ctx->dr_ctx.residlen != 0)) {
590 			DBG(NULL, DWARN,
591 			    "dca_3desdone: invalid nonzero residual");
592 			if (reqp->dr_flags & DR_DECRYPT) {
593 				errno = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
594 			} else {
595 				errno = CRYPTO_DATA_LEN_RANGE;
596 			}
597 		}
598 	}
599 
600 	ASSERT(reqp->dr_kcf_req != NULL);
601 	/* notify framework that request is completed */
602 	crypto_op_notification(reqp->dr_kcf_req, errno);
603 	DBG(NULL, DINTR,
604 	    "dca_3desdone: returning %d to the kef via crypto_op_notification",
605 	    errno);
606 
607 	/* This has to be done after notifing the framework */
608 	if (reqp->dr_ctx.atomic) {
609 		reqp->dr_context = NULL;
610 		reqp->dr_ctx.atomic = 0;
611 		reqp->dr_ctx.ctx_cm_type = 0;
612 		if (reqp->destroy)
613 			dca_destroyreq(reqp);
614 		else
615 			dca_freereq(reqp);
616 	}
617 }
618 
619 /* ARGSUSED */
620 int
621 dca_3desctxinit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
622     crypto_key_t *key, int kmflag, int flags)
623 {
624 	dca_request_t	*des_ctx;
625 	dca_t		*dca = ctx->cc_provider;
626 	uchar_t		*param;
627 	uchar_t		*value;
628 	size_t		paramsz;
629 	unsigned	len;
630 	int		i, j;
631 
632 	paramsz = mechanism->cm_param_len;
633 	param = (uchar_t *)mechanism->cm_param;
634 	if ((paramsz != 0) && (paramsz != DES_IV_LEN)) {
635 		DBG(NULL, DWARN,
636 		    "dca_3desctxinit: parameter(IV) length not %d (%d)",
637 		    DES_IV_LEN, paramsz);
638 		return (CRYPTO_MECHANISM_PARAM_INVALID);
639 	}
640 
641 	if ((des_ctx = dca_getreq(dca, MCR1, 1)) == NULL) {
642 		dca_error(dca, "unable to allocate request for 3DES");
643 		return (CRYPTO_HOST_MEMORY);
644 	}
645 	/*
646 	 * Identify and store the IV as a pair of native 32-bit words.
647 	 *
648 	 * If cm_param == NULL then the IV comes from the cd_miscdata field
649 	 * in the crypto_data structure.
650 	 */
651 	if (param != NULL) {
652 		ASSERT(paramsz == DES_IV_LEN);
653 		des_ctx->dr_ctx.iv[0] = param[0]<<24 | param[1]<<16 |
654 		    param[2]<<8 | param[3];
655 		des_ctx->dr_ctx.iv[1] = param[4]<<24 | param[5]<<16 |
656 		    param[6]<<8 | param[7];
657 	}
658 	des_ctx->dr_ctx.residlen = 0;
659 	des_ctx->dr_ctx.activeresidlen = 0;
660 	des_ctx->dr_ctx.ctx_cm_type = mechanism->cm_type;
661 	ctx->cc_provider_private = des_ctx;
662 
663 	if (key->ck_format != CRYPTO_KEY_RAW) {
664 		DBG(NULL, DWARN,
665 	"dca_3desctxinit: only raw crypto key type support with DES/3DES");
666 		dca_3desctxfree(ctx);
667 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
668 	}
669 
670 	len = key->ck_length;
671 	value = (uchar_t *)key->ck_data;
672 
673 	if (flags & DR_TRIPLE) {
674 		/* 3DES */
675 		switch (len) {
676 		case 192:
677 			for (i = 0; i < 6; i++) {
678 				des_ctx->dr_ctx.key[i] = 0;
679 				for (j = 0; j < 4; j++) {
680 					des_ctx->dr_ctx.key[i] <<= 8;
681 					des_ctx->dr_ctx.key[i] |= *value;
682 					value++;
683 				}
684 			}
685 			break;
686 
687 		case 128:
688 			for (i = 0; i < 4; i++) {
689 				des_ctx->dr_ctx.key[i] = 0;
690 				for (j = 0; j < 4; j++) {
691 					des_ctx->dr_ctx.key[i] <<= 8;
692 					des_ctx->dr_ctx.key[i] |= *value;
693 					value++;
694 				}
695 			}
696 			des_ctx->dr_ctx.key[4] = des_ctx->dr_ctx.key[0];
697 			des_ctx->dr_ctx.key[5] = des_ctx->dr_ctx.key[1];
698 			break;
699 
700 		default:
701 			DBG(NULL, DWARN, "Incorrect 3DES keysize (%d)", len);
702 			dca_3desctxfree(ctx);
703 			return (CRYPTO_KEY_SIZE_RANGE);
704 		}
705 	} else {
706 		/* single DES */
707 		if (len != 64) {
708 			DBG(NULL, DWARN, "Incorrect DES keysize (%d)", len);
709 			dca_3desctxfree(ctx);
710 			return (CRYPTO_KEY_SIZE_RANGE);
711 		}
712 		des_ctx->dr_ctx.key[0] =
713 		    value[0]<<24 | value[1]<<16 | value[2]<<8 | value[3];
714 		des_ctx->dr_ctx.key[1] =
715 		    value[4]<<24 | value[5]<<16 | value[6]<<8 | value[7];
716 		/* for single des just repeat des key */
717 		des_ctx->dr_ctx.key[4] =
718 		    des_ctx->dr_ctx.key[2] = des_ctx->dr_ctx.key[0];
719 		des_ctx->dr_ctx.key[5] =
720 		    des_ctx->dr_ctx.key[3] = des_ctx->dr_ctx.key[1];
721 	}
722 
723 	/*
724 	 * Setup the context here so that we do not need to setup it up
725 	 * for every update
726 	 */
727 	PUTCTX16(des_ctx, CTX_LENGTH, CTX_3DES_LENGTH);
728 	PUTCTX16(des_ctx, CTX_CMD, CMD_3DES);
729 	PUTCTX32(des_ctx, CTX_3DESDIRECTION,
730 	    flags & DR_ENCRYPT ? CTX_3DES_ENCRYPT : CTX_3DES_DECRYPT);
731 	PUTCTX32(des_ctx, CTX_3DESKEY1HI, des_ctx->dr_ctx.key[0]);
732 	PUTCTX32(des_ctx, CTX_3DESKEY1LO, des_ctx->dr_ctx.key[1]);
733 	PUTCTX32(des_ctx, CTX_3DESKEY2HI, des_ctx->dr_ctx.key[2]);
734 	PUTCTX32(des_ctx, CTX_3DESKEY2LO, des_ctx->dr_ctx.key[3]);
735 	PUTCTX32(des_ctx, CTX_3DESKEY3HI, des_ctx->dr_ctx.key[4]);
736 	PUTCTX32(des_ctx, CTX_3DESKEY3LO, des_ctx->dr_ctx.key[5]);
737 
738 	return (CRYPTO_SUCCESS);
739 }
740