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