xref: /titanic_51/usr/src/uts/common/crypto/io/md5_mod.c (revision 98157a7002f4f2cf7978f3084ca5577f0a1d72b2)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * In kernel module, the md5 module is created with two modlinkages:
30  * - a modlmisc that allows consumers to directly call the entry points
31  *   MD5Init, MD5Update, and MD5Final.
32  * - a modlcrypto that allows the module to register with the Kernel
33  *   Cryptographic Framework (KCF) as a software provider for the MD5
34  *   mechanisms.
35  */
36 
37 #include <sys/types.h>
38 #include <sys/systm.h>
39 #include <sys/modctl.h>
40 #include <sys/cmn_err.h>
41 #include <sys/ddi.h>
42 #include <sys/crypto/common.h>
43 #include <sys/crypto/spi.h>
44 #include <sys/sysmacros.h>
45 #include <sys/strsun.h>
46 #include <sys/note.h>
47 #include <sys/md5.h>
48 
49 extern struct mod_ops mod_miscops;
50 extern struct mod_ops mod_cryptoops;
51 
52 /*
53  * Module linkage information for the kernel.
54  */
55 
56 static struct modlmisc modlmisc = {
57 	&mod_miscops,
58 	"MD5 Message-Digest Algorithm"
59 };
60 
61 static struct modlcrypto modlcrypto = {
62 	&mod_cryptoops,
63 	"MD5 Kernel SW Provider"
64 };
65 
66 static struct modlinkage modlinkage = {
67 	MODREV_1,
68 	(void *)&modlmisc,
69 	(void *)&modlcrypto,
70 	NULL
71 };
72 
73 /*
74  * CSPI information (entry points, provider info, etc.)
75  */
76 
77 typedef enum md5_mech_type {
78 	MD5_MECH_INFO_TYPE,		/* SUN_CKM_MD5 */
79 	MD5_HMAC_MECH_INFO_TYPE,	/* SUN_CKM_MD5_HMAC */
80 	MD5_HMAC_GEN_MECH_INFO_TYPE	/* SUN_CKM_MD5_HMAC_GENERAL */
81 } md5_mech_type_t;
82 
83 #define	MD5_DIGEST_LENGTH	16	/* MD5 digest length in bytes */
84 #define	MD5_HMAC_BLOCK_SIZE	64	/* MD5 block size */
85 #define	MD5_HMAC_MIN_KEY_LEN	8	/* MD5-HMAC min key length in bits */
86 #define	MD5_HMAC_MAX_KEY_LEN	INT_MAX	/* MD5-HMAC max key length in bits */
87 #define	MD5_HMAC_INTS_PER_BLOCK	(MD5_HMAC_BLOCK_SIZE/sizeof (uint32_t))
88 
89 /*
90  * Context for MD5 mechanism.
91  */
92 typedef struct md5_ctx {
93 	md5_mech_type_t		mc_mech_type;	/* type of context */
94 	MD5_CTX			mc_md5_ctx;	/* MD5 context */
95 } md5_ctx_t;
96 
97 /*
98  * Context for MD5-HMAC and MD5-HMAC-GENERAL mechanisms.
99  */
100 typedef struct md5_hmac_ctx {
101 	md5_mech_type_t		hc_mech_type;	/* type of context */
102 	uint32_t		hc_digest_len;	/* digest len in bytes */
103 	MD5_CTX			hc_icontext;	/* inner MD5 context */
104 	MD5_CTX			hc_ocontext;	/* outer MD5 context */
105 } md5_hmac_ctx_t;
106 
107 /*
108  * Macros to access the MD5 or MD5-HMAC contexts from a context passed
109  * by KCF to one of the entry points.
110  */
111 
112 #define	PROV_MD5_CTX(ctx)	((md5_ctx_t *)(ctx)->cc_provider_private)
113 #define	PROV_MD5_HMAC_CTX(ctx)	((md5_hmac_ctx_t *)(ctx)->cc_provider_private)
114 /* to extract the digest length passed as mechanism parameter */
115 
116 #define	PROV_MD5_GET_DIGEST_LEN(m, len) {				\
117 	if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t)))		\
118 		(len) = (uint32_t)*((ulong_t *)mechanism->cm_param);	\
119 	else {								\
120 		ulong_t tmp_ulong;					\
121 		bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t));	\
122 		(len) = (uint32_t)tmp_ulong;				\
123 	}								\
124 }
125 
126 #define	PROV_MD5_DIGEST_KEY(ctx, key, len, digest) {	\
127 	MD5Init(ctx);					\
128 	MD5Update(ctx, key, len);			\
129 	MD5Final(digest, ctx);				\
130 }
131 
132 /*
133  * Mechanism info structure passed to KCF during registration.
134  */
135 static crypto_mech_info_t md5_mech_info_tab[] = {
136 	/* MD5 */
137 	{SUN_CKM_MD5, MD5_MECH_INFO_TYPE,
138 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
139 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
140 	/* MD5-HMAC */
141 	{SUN_CKM_MD5_HMAC, MD5_HMAC_MECH_INFO_TYPE,
142 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
143 	    MD5_HMAC_MIN_KEY_LEN, MD5_HMAC_MAX_KEY_LEN,
144 	    CRYPTO_KEYSIZE_UNIT_IN_BITS},
145 	/* MD5-HMAC GENERAL */
146 	{SUN_CKM_MD5_HMAC_GENERAL, MD5_HMAC_GEN_MECH_INFO_TYPE,
147 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
148 	    MD5_HMAC_MIN_KEY_LEN, MD5_HMAC_MAX_KEY_LEN,
149 	    CRYPTO_KEYSIZE_UNIT_IN_BITS}
150 };
151 
152 static void md5_provider_status(crypto_provider_handle_t, uint_t *);
153 
154 static crypto_control_ops_t md5_control_ops = {
155 	md5_provider_status
156 };
157 
158 static int md5_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
159     crypto_req_handle_t);
160 static int md5_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
161     crypto_req_handle_t);
162 static int md5_digest_update(crypto_ctx_t *, crypto_data_t *,
163     crypto_req_handle_t);
164 static int md5_digest_final(crypto_ctx_t *, crypto_data_t *,
165     crypto_req_handle_t);
166 static int md5_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
167     crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
168     crypto_req_handle_t);
169 
170 static crypto_digest_ops_t md5_digest_ops = {
171 	md5_digest_init,
172 	md5_digest,
173 	md5_digest_update,
174 	NULL,
175 	md5_digest_final,
176 	md5_digest_atomic
177 };
178 
179 static int md5_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
180     crypto_spi_ctx_template_t, crypto_req_handle_t);
181 static int md5_mac_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
182 static int md5_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
183 static int md5_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
184     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
185     crypto_spi_ctx_template_t, crypto_req_handle_t);
186 static int md5_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
187     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
188     crypto_spi_ctx_template_t, crypto_req_handle_t);
189 
190 static crypto_mac_ops_t md5_mac_ops = {
191 	md5_mac_init,
192 	NULL,
193 	md5_mac_update,
194 	md5_mac_final,
195 	md5_mac_atomic,
196 	md5_mac_verify_atomic
197 };
198 
199 static int md5_create_ctx_template(crypto_provider_handle_t,
200     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
201     size_t *, crypto_req_handle_t);
202 static int md5_free_context(crypto_ctx_t *);
203 
204 static crypto_ctx_ops_t md5_ctx_ops = {
205 	md5_create_ctx_template,
206 	md5_free_context
207 };
208 
209 static crypto_ops_t md5_crypto_ops = {
210 	&md5_control_ops,
211 	&md5_digest_ops,
212 	NULL,
213 	&md5_mac_ops,
214 	NULL,
215 	NULL,
216 	NULL,
217 	NULL,
218 	NULL,
219 	NULL,
220 	NULL,
221 	NULL,
222 	NULL,
223 	&md5_ctx_ops
224 };
225 
226 static crypto_provider_info_t md5_prov_info = {
227 	CRYPTO_SPI_VERSION_1,
228 	"MD5 Software Provider",
229 	CRYPTO_SW_PROVIDER,
230 	{&modlinkage},
231 	NULL,
232 	&md5_crypto_ops,
233 	sizeof (md5_mech_info_tab)/sizeof (crypto_mech_info_t),
234 	md5_mech_info_tab
235 };
236 
237 static crypto_kcf_provider_handle_t md5_prov_handle = NULL;
238 
239 int
240 _init(void)
241 {
242 	int ret;
243 
244 	if ((ret = mod_install(&modlinkage)) != 0)
245 		return (ret);
246 
247 	/*
248 	 * Register with KCF. If the registration fails, log an
249 	 * error but do not uninstall the module, since the functionality
250 	 * provided by misc/md5 should still be available.
251 	 */
252 	if ((ret = crypto_register_provider(&md5_prov_info,
253 	    &md5_prov_handle)) != CRYPTO_SUCCESS)
254 		cmn_err(CE_WARN, "md5 _init: "
255 		    "crypto_register_provider() failed (0x%x)", ret);
256 
257 	return (0);
258 }
259 
260 int
261 _fini(void)
262 {
263 	int ret;
264 
265 	/*
266 	 * Unregister from KCF if previous registration succeeded.
267 	 */
268 	if (md5_prov_handle != NULL) {
269 		if ((ret = crypto_unregister_provider(md5_prov_handle)) !=
270 		    CRYPTO_SUCCESS) {
271 			cmn_err(CE_WARN, "md5 _fini: "
272 			    "crypto_unregister_provider() failed (0x%x)", ret);
273 			return (EBUSY);
274 		}
275 		md5_prov_handle = NULL;
276 	}
277 
278 	return (mod_remove(&modlinkage));
279 }
280 
281 int
282 _info(struct modinfo *modinfop)
283 {
284 	return (mod_info(&modlinkage, modinfop));
285 }
286 
287 /*
288  * KCF software provider control entry points.
289  */
290 /* ARGSUSED */
291 static void
292 md5_provider_status(crypto_provider_handle_t provider, uint_t *status)
293 {
294 	*status = CRYPTO_PROVIDER_READY;
295 }
296 
297 /*
298  * KCF software provider digest entry points.
299  */
300 
301 static int
302 md5_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
303     crypto_req_handle_t req)
304 {
305 	if (mechanism->cm_type != MD5_MECH_INFO_TYPE)
306 		return (CRYPTO_MECHANISM_INVALID);
307 
308 	/*
309 	 * Allocate and initialize MD5 context.
310 	 */
311 	ctx->cc_provider_private = kmem_alloc(sizeof (md5_ctx_t),
312 	    crypto_kmflag(req));
313 	if (ctx->cc_provider_private == NULL)
314 		return (CRYPTO_HOST_MEMORY);
315 
316 	PROV_MD5_CTX(ctx)->mc_mech_type = MD5_MECH_INFO_TYPE;
317 	MD5Init(&PROV_MD5_CTX(ctx)->mc_md5_ctx);
318 
319 	return (CRYPTO_SUCCESS);
320 }
321 
322 /*
323  * Helper MD5 digest update function for uio data.
324  */
325 static int
326 md5_digest_update_uio(MD5_CTX *md5_ctx, crypto_data_t *data)
327 {
328 	off_t offset = data->cd_offset;
329 	size_t length = data->cd_length;
330 	uint_t vec_idx;
331 	size_t cur_len;
332 
333 	/* we support only kernel buffer */
334 	if (data->cd_uio->uio_segflg != UIO_SYSSPACE)
335 		return (CRYPTO_ARGUMENTS_BAD);
336 
337 	/*
338 	 * Jump to the first iovec containing data to be
339 	 * digested.
340 	 */
341 	for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt &&
342 	    offset >= data->cd_uio->uio_iov[vec_idx].iov_len;
343 	    offset -= data->cd_uio->uio_iov[vec_idx++].iov_len)
344 		;
345 	if (vec_idx == data->cd_uio->uio_iovcnt) {
346 		/*
347 		 * The caller specified an offset that is larger than the
348 		 * total size of the buffers it provided.
349 		 */
350 		return (CRYPTO_DATA_LEN_RANGE);
351 	}
352 
353 	/*
354 	 * Now do the digesting on the iovecs.
355 	 */
356 	while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) {
357 		cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len -
358 		    offset, length);
359 
360 		MD5Update(md5_ctx, data->cd_uio->uio_iov[vec_idx].iov_base +
361 		    offset, cur_len);
362 
363 		length -= cur_len;
364 		vec_idx++;
365 		offset = 0;
366 	}
367 
368 	if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) {
369 		/*
370 		 * The end of the specified iovec's was reached but
371 		 * the length requested could not be processed, i.e.
372 		 * The caller requested to digest more data than it provided.
373 		 */
374 		return (CRYPTO_DATA_LEN_RANGE);
375 	}
376 
377 	return (CRYPTO_SUCCESS);
378 }
379 
380 /*
381  * Helper MD5 digest final function for uio data.
382  * digest_len is the length of the desired digest. If digest_len
383  * is smaller than the default MD5 digest length, the caller
384  * must pass a scratch buffer, digest_scratch, which must
385  * be at least MD5_DIGEST_LENGTH bytes.
386  */
387 static int
388 md5_digest_final_uio(MD5_CTX *md5_ctx, crypto_data_t *digest,
389     ulong_t digest_len, uchar_t *digest_scratch)
390 {
391 	off_t offset = digest->cd_offset;
392 	uint_t vec_idx;
393 
394 	/* we support only kernel buffer */
395 	if (digest->cd_uio->uio_segflg != UIO_SYSSPACE)
396 		return (CRYPTO_ARGUMENTS_BAD);
397 
398 	/*
399 	 * Jump to the first iovec containing ptr to the digest to
400 	 * be returned.
401 	 */
402 	for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len &&
403 	    vec_idx < digest->cd_uio->uio_iovcnt;
404 	    offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len)
405 		;
406 	if (vec_idx == digest->cd_uio->uio_iovcnt) {
407 		/*
408 		 * The caller specified an offset that is
409 		 * larger than the total size of the buffers
410 		 * it provided.
411 		 */
412 		return (CRYPTO_DATA_LEN_RANGE);
413 	}
414 
415 	if (offset + digest_len <=
416 	    digest->cd_uio->uio_iov[vec_idx].iov_len) {
417 		/*
418 		 * The computed MD5 digest will fit in the current
419 		 * iovec.
420 		 */
421 		if (digest_len != MD5_DIGEST_LENGTH) {
422 			/*
423 			 * The caller requested a short digest. Digest
424 			 * into a scratch buffer and return to
425 			 * the user only what was requested.
426 			 */
427 			MD5Final(digest_scratch, md5_ctx);
428 			bcopy(digest_scratch, (uchar_t *)digest->
429 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
430 			    digest_len);
431 		} else {
432 			MD5Final((uchar_t *)digest->
433 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
434 			    md5_ctx);
435 		}
436 	} else {
437 		/*
438 		 * The computed digest will be crossing one or more iovec's.
439 		 * This is bad performance-wise but we need to support it.
440 		 * Allocate a small scratch buffer on the stack and
441 		 * copy it piece meal to the specified digest iovec's.
442 		 */
443 		uchar_t digest_tmp[MD5_DIGEST_LENGTH];
444 		off_t scratch_offset = 0;
445 		size_t length = digest_len;
446 		size_t cur_len;
447 
448 		MD5Final(digest_tmp, md5_ctx);
449 
450 		while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
451 			cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
452 			    offset, length);
453 			bcopy(digest_tmp + scratch_offset,
454 			    digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
455 			    cur_len);
456 
457 			length -= cur_len;
458 			vec_idx++;
459 			scratch_offset += cur_len;
460 			offset = 0;
461 		}
462 
463 		if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
464 			/*
465 			 * The end of the specified iovec's was reached but
466 			 * the length requested could not be processed, i.e.
467 			 * The caller requested to digest more data than it
468 			 * provided.
469 			 */
470 			return (CRYPTO_DATA_LEN_RANGE);
471 		}
472 	}
473 
474 	return (CRYPTO_SUCCESS);
475 }
476 
477 /*
478  * Helper MD5 digest update for mblk's.
479  */
480 static int
481 md5_digest_update_mblk(MD5_CTX *md5_ctx, crypto_data_t *data)
482 {
483 	off_t offset = data->cd_offset;
484 	size_t length = data->cd_length;
485 	mblk_t *mp;
486 	size_t cur_len;
487 
488 	/*
489 	 * Jump to the first mblk_t containing data to be digested.
490 	 */
491 	for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
492 	    offset -= MBLKL(mp), mp = mp->b_cont)
493 		;
494 	if (mp == NULL) {
495 		/*
496 		 * The caller specified an offset that is larger than the
497 		 * total size of the buffers it provided.
498 		 */
499 		return (CRYPTO_DATA_LEN_RANGE);
500 	}
501 
502 	/*
503 	 * Now do the digesting on the mblk chain.
504 	 */
505 	while (mp != NULL && length > 0) {
506 		cur_len = MIN(MBLKL(mp) - offset, length);
507 		MD5Update(md5_ctx, mp->b_rptr + offset, cur_len);
508 		length -= cur_len;
509 		offset = 0;
510 		mp = mp->b_cont;
511 	}
512 
513 	if (mp == NULL && length > 0) {
514 		/*
515 		 * The end of the mblk was reached but the length requested
516 		 * could not be processed, i.e. The caller requested
517 		 * to digest more data than it provided.
518 		 */
519 		return (CRYPTO_DATA_LEN_RANGE);
520 	}
521 
522 	return (CRYPTO_SUCCESS);
523 }
524 
525 /*
526  * Helper MD5 digest final for mblk's.
527  * digest_len is the length of the desired digest. If digest_len
528  * is smaller than the default MD5 digest length, the caller
529  * must pass a scratch buffer, digest_scratch, which must
530  * be at least MD5_DIGEST_LENGTH bytes.
531  */
532 static int
533 md5_digest_final_mblk(MD5_CTX *md5_ctx, crypto_data_t *digest,
534     ulong_t digest_len, uchar_t *digest_scratch)
535 {
536 	off_t offset = digest->cd_offset;
537 	mblk_t *mp;
538 
539 	/*
540 	 * Jump to the first mblk_t that will be used to store the digest.
541 	 */
542 	for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp);
543 	    offset -= MBLKL(mp), mp = mp->b_cont)
544 		;
545 	if (mp == NULL) {
546 		/*
547 		 * The caller specified an offset that is larger than the
548 		 * total size of the buffers it provided.
549 		 */
550 		return (CRYPTO_DATA_LEN_RANGE);
551 	}
552 
553 	if (offset + digest_len <= MBLKL(mp)) {
554 		/*
555 		 * The computed MD5 digest will fit in the current mblk.
556 		 * Do the MD5Final() in-place.
557 		 */
558 		if (digest_len != MD5_DIGEST_LENGTH) {
559 			/*
560 			 * The caller requested a short digest. Digest
561 			 * into a scratch buffer and return to
562 			 * the user only what was requested.
563 			 */
564 			MD5Final(digest_scratch, md5_ctx);
565 			bcopy(digest_scratch, mp->b_rptr + offset, digest_len);
566 		} else {
567 			MD5Final(mp->b_rptr + offset, md5_ctx);
568 		}
569 	} else {
570 		/*
571 		 * The computed digest will be crossing one or more mblk's.
572 		 * This is bad performance-wise but we need to support it.
573 		 * Allocate a small scratch buffer on the stack and
574 		 * copy it piece meal to the specified digest iovec's.
575 		 */
576 		uchar_t digest_tmp[MD5_DIGEST_LENGTH];
577 		off_t scratch_offset = 0;
578 		size_t length = digest_len;
579 		size_t cur_len;
580 
581 		MD5Final(digest_tmp, md5_ctx);
582 
583 		while (mp != NULL && length > 0) {
584 			cur_len = MIN(MBLKL(mp) - offset, length);
585 			bcopy(digest_tmp + scratch_offset,
586 			    mp->b_rptr + offset, cur_len);
587 
588 			length -= cur_len;
589 			mp = mp->b_cont;
590 			scratch_offset += cur_len;
591 			offset = 0;
592 		}
593 
594 		if (mp == NULL && length > 0) {
595 			/*
596 			 * The end of the specified mblk was reached but
597 			 * the length requested could not be processed, i.e.
598 			 * The caller requested to digest more data than it
599 			 * provided.
600 			 */
601 			return (CRYPTO_DATA_LEN_RANGE);
602 		}
603 	}
604 
605 	return (CRYPTO_SUCCESS);
606 }
607 
608 /* ARGSUSED */
609 static int
610 md5_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
611     crypto_req_handle_t req)
612 {
613 	int ret = CRYPTO_SUCCESS;
614 
615 	ASSERT(ctx->cc_provider_private != NULL);
616 
617 	/*
618 	 * We need to just return the length needed to store the output.
619 	 * We should not destroy the context for the following cases.
620 	 */
621 	if ((digest->cd_length == 0) ||
622 	    (digest->cd_length < MD5_DIGEST_LENGTH)) {
623 		digest->cd_length = MD5_DIGEST_LENGTH;
624 		return (CRYPTO_BUFFER_TOO_SMALL);
625 	}
626 
627 	/*
628 	 * Do the MD5 update on the specified input data.
629 	 */
630 	switch (data->cd_format) {
631 	case CRYPTO_DATA_RAW:
632 		MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
633 		    data->cd_raw.iov_base + data->cd_offset,
634 		    data->cd_length);
635 		break;
636 	case CRYPTO_DATA_UIO:
637 		ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
638 		    data);
639 		break;
640 	case CRYPTO_DATA_MBLK:
641 		ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
642 		    data);
643 		break;
644 	default:
645 		ret = CRYPTO_ARGUMENTS_BAD;
646 	}
647 
648 	if (ret != CRYPTO_SUCCESS) {
649 		/* the update failed, free context and bail */
650 		kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t));
651 		ctx->cc_provider_private = NULL;
652 		digest->cd_length = 0;
653 		return (ret);
654 	}
655 
656 	/*
657 	 * Do an MD5 final, must be done separately since the digest
658 	 * type can be different than the input data type.
659 	 */
660 	switch (digest->cd_format) {
661 	case CRYPTO_DATA_RAW:
662 		MD5Final((unsigned char *)digest->cd_raw.iov_base +
663 		    digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx);
664 		break;
665 	case CRYPTO_DATA_UIO:
666 		ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
667 		    digest, MD5_DIGEST_LENGTH, NULL);
668 		break;
669 	case CRYPTO_DATA_MBLK:
670 		ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
671 		    digest, MD5_DIGEST_LENGTH, NULL);
672 		break;
673 	default:
674 		ret = CRYPTO_ARGUMENTS_BAD;
675 	}
676 
677 	/* all done, free context and return */
678 
679 	if (ret == CRYPTO_SUCCESS) {
680 		digest->cd_length = MD5_DIGEST_LENGTH;
681 	} else {
682 		digest->cd_length = 0;
683 	}
684 
685 	kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t));
686 	ctx->cc_provider_private = NULL;
687 	return (ret);
688 }
689 
690 /* ARGSUSED */
691 static int
692 md5_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
693     crypto_req_handle_t req)
694 {
695 	int ret = CRYPTO_SUCCESS;
696 
697 	ASSERT(ctx->cc_provider_private != NULL);
698 
699 	/*
700 	 * Do the MD5 update on the specified input data.
701 	 */
702 	switch (data->cd_format) {
703 	case CRYPTO_DATA_RAW:
704 		MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
705 		    data->cd_raw.iov_base + data->cd_offset,
706 		    data->cd_length);
707 		break;
708 	case CRYPTO_DATA_UIO:
709 		ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
710 		    data);
711 		break;
712 	case CRYPTO_DATA_MBLK:
713 		ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
714 		    data);
715 		break;
716 	default:
717 		ret = CRYPTO_ARGUMENTS_BAD;
718 	}
719 
720 	return (ret);
721 }
722 
723 /* ARGSUSED */
724 static int
725 md5_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
726     crypto_req_handle_t req)
727 {
728 	int ret = CRYPTO_SUCCESS;
729 
730 	ASSERT(ctx->cc_provider_private != NULL);
731 
732 	/*
733 	 * We need to just return the length needed to store the output.
734 	 * We should not destroy the context for the following cases.
735 	 */
736 	if ((digest->cd_length == 0) ||
737 	    (digest->cd_length < MD5_DIGEST_LENGTH)) {
738 		digest->cd_length = MD5_DIGEST_LENGTH;
739 		return (CRYPTO_BUFFER_TOO_SMALL);
740 	}
741 
742 	/*
743 	 * Do an MD5 final.
744 	 */
745 	switch (digest->cd_format) {
746 	case CRYPTO_DATA_RAW:
747 		MD5Final((unsigned char *)digest->cd_raw.iov_base +
748 		    digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx);
749 		break;
750 	case CRYPTO_DATA_UIO:
751 		ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
752 		    digest, MD5_DIGEST_LENGTH, NULL);
753 		break;
754 	case CRYPTO_DATA_MBLK:
755 		ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
756 		    digest, MD5_DIGEST_LENGTH, NULL);
757 		break;
758 	default:
759 		ret = CRYPTO_ARGUMENTS_BAD;
760 	}
761 
762 	/* all done, free context and return */
763 
764 	if (ret == CRYPTO_SUCCESS) {
765 		digest->cd_length = MD5_DIGEST_LENGTH;
766 	} else {
767 		digest->cd_length = 0;
768 	}
769 
770 	kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t));
771 	ctx->cc_provider_private = NULL;
772 
773 	return (ret);
774 }
775 
776 /* ARGSUSED */
777 static int
778 md5_digest_atomic(crypto_provider_handle_t provider,
779     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
780     crypto_data_t *data, crypto_data_t *digest,
781     crypto_req_handle_t req)
782 {
783 	int ret = CRYPTO_SUCCESS;
784 	MD5_CTX md5_ctx;
785 
786 	if (mechanism->cm_type != MD5_MECH_INFO_TYPE)
787 		return (CRYPTO_MECHANISM_INVALID);
788 
789 	/*
790 	 * Do the MD5 init.
791 	 */
792 	MD5Init(&md5_ctx);
793 
794 	/*
795 	 * Do the MD5 update on the specified input data.
796 	 */
797 	switch (data->cd_format) {
798 	case CRYPTO_DATA_RAW:
799 		MD5Update(&md5_ctx, data->cd_raw.iov_base + data->cd_offset,
800 		    data->cd_length);
801 		break;
802 	case CRYPTO_DATA_UIO:
803 		ret = md5_digest_update_uio(&md5_ctx, data);
804 		break;
805 	case CRYPTO_DATA_MBLK:
806 		ret = md5_digest_update_mblk(&md5_ctx, data);
807 		break;
808 	default:
809 		ret = CRYPTO_ARGUMENTS_BAD;
810 	}
811 
812 	if (ret != CRYPTO_SUCCESS) {
813 		/* the update failed, bail */
814 		digest->cd_length = 0;
815 		return (ret);
816 	}
817 
818 	/*
819 	 * Do an MD5 final, must be done separately since the digest
820 	 * type can be different than the input data type.
821 	 */
822 	switch (digest->cd_format) {
823 	case CRYPTO_DATA_RAW:
824 		MD5Final((unsigned char *)digest->cd_raw.iov_base +
825 		    digest->cd_offset, &md5_ctx);
826 		break;
827 	case CRYPTO_DATA_UIO:
828 		ret = md5_digest_final_uio(&md5_ctx, digest,
829 		    MD5_DIGEST_LENGTH, NULL);
830 		break;
831 	case CRYPTO_DATA_MBLK:
832 		ret = md5_digest_final_mblk(&md5_ctx, digest,
833 		    MD5_DIGEST_LENGTH, NULL);
834 		break;
835 	default:
836 		ret = CRYPTO_ARGUMENTS_BAD;
837 	}
838 
839 	if (ret == CRYPTO_SUCCESS) {
840 		digest->cd_length = MD5_DIGEST_LENGTH;
841 	} else {
842 		digest->cd_length = 0;
843 	}
844 
845 	return (ret);
846 }
847 
848 /*
849  * KCF software provider mac entry points.
850  *
851  * MD5 HMAC is: MD5(key XOR opad, MD5(key XOR ipad, text))
852  *
853  * Init:
854  * The initialization routine initializes what we denote
855  * as the inner and outer contexts by doing
856  * - for inner context: MD5(key XOR ipad)
857  * - for outer context: MD5(key XOR opad)
858  *
859  * Update:
860  * Each subsequent MD5 HMAC update will result in an
861  * update of the inner context with the specified data.
862  *
863  * Final:
864  * The MD5 HMAC final will do a MD5 final operation on the
865  * inner context, and the resulting digest will be used
866  * as the data for an update on the outer context. Last
867  * but not least, an MD5 final on the outer context will
868  * be performed to obtain the MD5 HMAC digest to return
869  * to the user.
870  */
871 
872 /*
873  * Initialize a MD5-HMAC context.
874  */
875 static void
876 md5_mac_init_ctx(md5_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
877 {
878 	uint32_t ipad[MD5_HMAC_INTS_PER_BLOCK];
879 	uint32_t opad[MD5_HMAC_INTS_PER_BLOCK];
880 	uint_t i;
881 
882 	bzero(ipad, MD5_HMAC_BLOCK_SIZE);
883 	bzero(opad, MD5_HMAC_BLOCK_SIZE);
884 
885 	bcopy(keyval, ipad, length_in_bytes);
886 	bcopy(keyval, opad, length_in_bytes);
887 
888 	/* XOR key with ipad (0x36) and opad (0x5c) */
889 	for (i = 0; i < MD5_HMAC_INTS_PER_BLOCK; i++) {
890 		ipad[i] ^= 0x36363636;
891 		opad[i] ^= 0x5c5c5c5c;
892 	}
893 
894 	/* perform MD5 on ipad */
895 	MD5Init(&ctx->hc_icontext);
896 	MD5Update(&ctx->hc_icontext, ipad, MD5_HMAC_BLOCK_SIZE);
897 
898 	/* perform MD5 on opad */
899 	MD5Init(&ctx->hc_ocontext);
900 	MD5Update(&ctx->hc_ocontext, opad, MD5_HMAC_BLOCK_SIZE);
901 }
902 
903 /*
904  * Initializes a multi-part MAC operation.
905  */
906 static int
907 md5_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
908     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
909     crypto_req_handle_t req)
910 {
911 	int ret = CRYPTO_SUCCESS;
912 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
913 
914 	if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE &&
915 	    mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)
916 		return (CRYPTO_MECHANISM_INVALID);
917 
918 	/* Add support for key by attributes (RFE 4706552) */
919 	if (key->ck_format != CRYPTO_KEY_RAW)
920 		return (CRYPTO_ARGUMENTS_BAD);
921 
922 	ctx->cc_provider_private = kmem_alloc(sizeof (md5_hmac_ctx_t),
923 	    crypto_kmflag(req));
924 	if (ctx->cc_provider_private == NULL)
925 		return (CRYPTO_HOST_MEMORY);
926 
927 	if (ctx_template != NULL) {
928 		/* reuse context template */
929 		bcopy(ctx_template, PROV_MD5_HMAC_CTX(ctx),
930 		    sizeof (md5_hmac_ctx_t));
931 	} else {
932 		/* no context template, compute context */
933 		if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) {
934 			uchar_t digested_key[MD5_DIGEST_LENGTH];
935 			md5_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;
936 
937 			/*
938 			 * Hash the passed-in key to get a smaller key.
939 			 * The inner context is used since it hasn't been
940 			 * initialized yet.
941 			 */
942 			PROV_MD5_DIGEST_KEY(&hmac_ctx->hc_icontext,
943 			    key->ck_data, keylen_in_bytes, digested_key);
944 			md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx),
945 			    digested_key, MD5_DIGEST_LENGTH);
946 		} else {
947 			md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx),
948 			    key->ck_data, keylen_in_bytes);
949 		}
950 	}
951 
952 	/*
953 	 * Get the mechanism parameters, if applicable.
954 	 */
955 	PROV_MD5_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;
956 	if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) {
957 		if (mechanism->cm_param == NULL ||
958 		    mechanism->cm_param_len != sizeof (ulong_t))
959 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
960 		PROV_MD5_GET_DIGEST_LEN(mechanism,
961 		    PROV_MD5_HMAC_CTX(ctx)->hc_digest_len);
962 		if (PROV_MD5_HMAC_CTX(ctx)->hc_digest_len >
963 		    MD5_DIGEST_LENGTH)
964 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
965 	}
966 
967 	if (ret != CRYPTO_SUCCESS) {
968 		bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t));
969 		kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t));
970 		ctx->cc_provider_private = NULL;
971 	}
972 
973 	return (ret);
974 }
975 
976 
977 /* ARGSUSED */
978 static int
979 md5_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
980 {
981 	int ret = CRYPTO_SUCCESS;
982 
983 	ASSERT(ctx->cc_provider_private != NULL);
984 
985 	/*
986 	 * Do an MD5 update of the inner context using the specified
987 	 * data.
988 	 */
989 	switch (data->cd_format) {
990 	case CRYPTO_DATA_RAW:
991 		MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_icontext,
992 		    data->cd_raw.iov_base + data->cd_offset,
993 		    data->cd_length);
994 		break;
995 	case CRYPTO_DATA_UIO:
996 		ret = md5_digest_update_uio(
997 		    &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data);
998 		break;
999 	case CRYPTO_DATA_MBLK:
1000 		ret = md5_digest_update_mblk(
1001 		    &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data);
1002 		break;
1003 	default:
1004 		ret = CRYPTO_ARGUMENTS_BAD;
1005 	}
1006 
1007 	return (ret);
1008 }
1009 
1010 /* ARGSUSED */
1011 static int
1012 md5_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
1013 {
1014 	int ret = CRYPTO_SUCCESS;
1015 	uchar_t digest[MD5_DIGEST_LENGTH];
1016 	uint32_t digest_len = MD5_DIGEST_LENGTH;
1017 
1018 	ASSERT(ctx->cc_provider_private != NULL);
1019 
1020 	if (PROV_MD5_HMAC_CTX(ctx)->hc_mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE)
1021 		digest_len = PROV_MD5_HMAC_CTX(ctx)->hc_digest_len;
1022 
1023 	/*
1024 	 * We need to just return the length needed to store the output.
1025 	 * We should not destroy the context for the following cases.
1026 	 */
1027 	if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {
1028 		mac->cd_length = digest_len;
1029 		return (CRYPTO_BUFFER_TOO_SMALL);
1030 	}
1031 
1032 	/*
1033 	 * Do an MD5 final on the inner context.
1034 	 */
1035 	MD5Final(digest, &PROV_MD5_HMAC_CTX(ctx)->hc_icontext);
1036 
1037 	/*
1038 	 * Do an MD5 update on the outer context, feeding the inner
1039 	 * digest as data.
1040 	 */
1041 	MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, digest,
1042 	    MD5_DIGEST_LENGTH);
1043 
1044 	/*
1045 	 * Do an MD5 final on the outer context, storing the computing
1046 	 * digest in the users buffer.
1047 	 */
1048 	switch (mac->cd_format) {
1049 	case CRYPTO_DATA_RAW:
1050 		if (digest_len != MD5_DIGEST_LENGTH) {
1051 			/*
1052 			 * The caller requested a short digest. Digest
1053 			 * into a scratch buffer and return to
1054 			 * the user only what was requested.
1055 			 */
1056 			MD5Final(digest,
1057 			    &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext);
1058 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
1059 			    mac->cd_offset, digest_len);
1060 		} else {
1061 			MD5Final((unsigned char *)mac->cd_raw.iov_base +
1062 			    mac->cd_offset,
1063 			    &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext);
1064 		}
1065 		break;
1066 	case CRYPTO_DATA_UIO:
1067 		ret = md5_digest_final_uio(
1068 		    &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac,
1069 		    digest_len, digest);
1070 		break;
1071 	case CRYPTO_DATA_MBLK:
1072 		ret = md5_digest_final_mblk(
1073 		    &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac,
1074 		    digest_len, digest);
1075 		break;
1076 	default:
1077 		ret = CRYPTO_ARGUMENTS_BAD;
1078 	}
1079 
1080 	if (ret == CRYPTO_SUCCESS) {
1081 		mac->cd_length = digest_len;
1082 	} else {
1083 		mac->cd_length = 0;
1084 	}
1085 
1086 	bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t));
1087 	kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t));
1088 	ctx->cc_provider_private = NULL;
1089 
1090 	return (ret);
1091 }
1092 
1093 #define	MD5_MAC_UPDATE(data, ctx, ret) {				\
1094 	switch (data->cd_format) {					\
1095 	case CRYPTO_DATA_RAW:						\
1096 		MD5Update(&(ctx).hc_icontext,				\
1097 		    data->cd_raw.iov_base + data->cd_offset,		\
1098 		    data->cd_length);					\
1099 		break;							\
1100 	case CRYPTO_DATA_UIO:						\
1101 		ret = md5_digest_update_uio(&(ctx).hc_icontext,	data);	\
1102 		break;							\
1103 	case CRYPTO_DATA_MBLK:						\
1104 		ret = md5_digest_update_mblk(&(ctx).hc_icontext,	\
1105 		    data);						\
1106 		break;							\
1107 	default:							\
1108 		ret = CRYPTO_ARGUMENTS_BAD;				\
1109 	}								\
1110 }
1111 
1112 
1113 /* ARGSUSED */
1114 static int
1115 md5_mac_atomic(crypto_provider_handle_t provider,
1116     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1117     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
1118     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
1119 {
1120 	int ret = CRYPTO_SUCCESS;
1121 	uchar_t digest[MD5_DIGEST_LENGTH];
1122 	md5_hmac_ctx_t md5_hmac_ctx;
1123 	uint32_t digest_len = MD5_DIGEST_LENGTH;
1124 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1125 
1126 	if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE &&
1127 	    mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)
1128 		return (CRYPTO_MECHANISM_INVALID);
1129 
1130 	/* Add support for key by attributes (RFE 4706552) */
1131 	if (key->ck_format != CRYPTO_KEY_RAW)
1132 		return (CRYPTO_ARGUMENTS_BAD);
1133 
1134 	if (ctx_template != NULL) {
1135 		/* reuse context template */
1136 		bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1137 	} else {
1138 		/* no context template, compute context */
1139 		if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) {
1140 			/*
1141 			 * Hash the passed-in key to get a smaller key.
1142 			 * The inner context is used since it hasn't been
1143 			 * initialized yet.
1144 			 */
1145 			PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext,
1146 			    key->ck_data, keylen_in_bytes, digest);
1147 			md5_mac_init_ctx(&md5_hmac_ctx, digest,
1148 			    MD5_DIGEST_LENGTH);
1149 		} else {
1150 			md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data,
1151 			    keylen_in_bytes);
1152 		}
1153 	}
1154 
1155 	/*
1156 	 * Get the mechanism parameters, if applicable.
1157 	 */
1158 	if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) {
1159 		if (mechanism->cm_param == NULL ||
1160 		    mechanism->cm_param_len != sizeof (ulong_t)) {
1161 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1162 			goto bail;
1163 		}
1164 		PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len);
1165 		if (digest_len > MD5_DIGEST_LENGTH) {
1166 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1167 			goto bail;
1168 		}
1169 	}
1170 
1171 	/* do an MD5 update of the inner context using the specified data */
1172 	MD5_MAC_UPDATE(data, md5_hmac_ctx, ret);
1173 	if (ret != CRYPTO_SUCCESS)
1174 		/* the update failed, free context and bail */
1175 		goto bail;
1176 
1177 	/* do an MD5 final on the inner context */
1178 	MD5Final(digest, &md5_hmac_ctx.hc_icontext);
1179 
1180 	/*
1181 	 * Do an MD5 update on the outer context, feeding the inner
1182 	 * digest as data.
1183 	 */
1184 	MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH);
1185 
1186 	/*
1187 	 * Do an MD5 final on the outer context, storing the computed
1188 	 * digest in the users buffer.
1189 	 */
1190 	switch (mac->cd_format) {
1191 	case CRYPTO_DATA_RAW:
1192 		if (digest_len != MD5_DIGEST_LENGTH) {
1193 			/*
1194 			 * The caller requested a short digest. Digest
1195 			 * into a scratch buffer and return to
1196 			 * the user only what was requested.
1197 			 */
1198 			MD5Final(digest, &md5_hmac_ctx.hc_ocontext);
1199 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
1200 			    mac->cd_offset, digest_len);
1201 		} else {
1202 			MD5Final((unsigned char *)mac->cd_raw.iov_base +
1203 			    mac->cd_offset, &md5_hmac_ctx.hc_ocontext);
1204 		}
1205 		break;
1206 	case CRYPTO_DATA_UIO:
1207 		ret = md5_digest_final_uio(&md5_hmac_ctx.hc_ocontext, mac,
1208 		    digest_len, digest);
1209 		break;
1210 	case CRYPTO_DATA_MBLK:
1211 		ret = md5_digest_final_mblk(&md5_hmac_ctx.hc_ocontext, mac,
1212 		    digest_len, digest);
1213 		break;
1214 	default:
1215 		ret = CRYPTO_ARGUMENTS_BAD;
1216 	}
1217 
1218 	if (ret == CRYPTO_SUCCESS) {
1219 		mac->cd_length = digest_len;
1220 	} else {
1221 		mac->cd_length = 0;
1222 	}
1223 	/* Extra paranoia: zeroizing the local context on the stack */
1224 	bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1225 
1226 	return (ret);
1227 bail:
1228 	bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1229 	mac->cd_length = 0;
1230 	return (ret);
1231 }
1232 
1233 /* ARGSUSED */
1234 static int
1235 md5_mac_verify_atomic(crypto_provider_handle_t provider,
1236     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1237     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
1238     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
1239 {
1240 	int ret = CRYPTO_SUCCESS;
1241 	uchar_t digest[MD5_DIGEST_LENGTH];
1242 	md5_hmac_ctx_t md5_hmac_ctx;
1243 	uint32_t digest_len = MD5_DIGEST_LENGTH;
1244 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1245 
1246 	if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE &&
1247 	    mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)
1248 		return (CRYPTO_MECHANISM_INVALID);
1249 
1250 	/* Add support for key by attributes (RFE 4706552) */
1251 	if (key->ck_format != CRYPTO_KEY_RAW)
1252 		return (CRYPTO_ARGUMENTS_BAD);
1253 
1254 	if (ctx_template != NULL) {
1255 		/* reuse context template */
1256 		bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1257 	} else {
1258 		/* no context template, compute context */
1259 		if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) {
1260 			/*
1261 			 * Hash the passed-in key to get a smaller key.
1262 			 * The inner context is used since it hasn't been
1263 			 * initialized yet.
1264 			 */
1265 			PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext,
1266 			    key->ck_data, keylen_in_bytes, digest);
1267 			md5_mac_init_ctx(&md5_hmac_ctx, digest,
1268 			    MD5_DIGEST_LENGTH);
1269 		} else {
1270 			md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data,
1271 			    keylen_in_bytes);
1272 		}
1273 	}
1274 
1275 	/*
1276 	 * Get the mechanism parameters, if applicable.
1277 	 */
1278 	if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) {
1279 		if (mechanism->cm_param == NULL ||
1280 		    mechanism->cm_param_len != sizeof (ulong_t)) {
1281 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1282 			goto bail;
1283 		}
1284 		PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len);
1285 		if (digest_len > MD5_DIGEST_LENGTH) {
1286 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1287 			goto bail;
1288 		}
1289 	}
1290 
1291 	if (mac->cd_length != digest_len) {
1292 		ret = CRYPTO_INVALID_MAC;
1293 		goto bail;
1294 	}
1295 
1296 	/* do an MD5 update of the inner context using the specified data */
1297 	MD5_MAC_UPDATE(data, md5_hmac_ctx, ret);
1298 	if (ret != CRYPTO_SUCCESS)
1299 		/* the update failed, free context and bail */
1300 		goto bail;
1301 
1302 	/* do an MD5 final on the inner context */
1303 	MD5Final(digest, &md5_hmac_ctx.hc_icontext);
1304 
1305 	/*
1306 	 * Do an MD5 update on the outer context, feeding the inner
1307 	 * digest as data.
1308 	 */
1309 	MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH);
1310 
1311 	/*
1312 	 * Do an MD5 final on the outer context, storing the computed
1313 	 * digest in the local digest buffer.
1314 	 */
1315 	MD5Final(digest, &md5_hmac_ctx.hc_ocontext);
1316 
1317 	/*
1318 	 * Compare the computed digest against the expected digest passed
1319 	 * as argument.
1320 	 */
1321 	switch (mac->cd_format) {
1322 
1323 	case CRYPTO_DATA_RAW:
1324 		if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base +
1325 		    mac->cd_offset, digest_len) != 0)
1326 			ret = CRYPTO_INVALID_MAC;
1327 		break;
1328 
1329 	case CRYPTO_DATA_UIO: {
1330 		off_t offset = mac->cd_offset;
1331 		uint_t vec_idx;
1332 		off_t scratch_offset = 0;
1333 		size_t length = digest_len;
1334 		size_t cur_len;
1335 
1336 		/* we support only kernel buffer */
1337 		if (mac->cd_uio->uio_segflg != UIO_SYSSPACE)
1338 			return (CRYPTO_ARGUMENTS_BAD);
1339 
1340 		/* jump to the first iovec containing the expected digest */
1341 		for (vec_idx = 0;
1342 		    offset >= mac->cd_uio->uio_iov[vec_idx].iov_len &&
1343 		    vec_idx < mac->cd_uio->uio_iovcnt;
1344 		    offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len)
1345 			;
1346 		if (vec_idx == mac->cd_uio->uio_iovcnt) {
1347 			/*
1348 			 * The caller specified an offset that is
1349 			 * larger than the total size of the buffers
1350 			 * it provided.
1351 			 */
1352 			ret = CRYPTO_DATA_LEN_RANGE;
1353 			break;
1354 		}
1355 
1356 		/* do the comparison of computed digest vs specified one */
1357 		while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) {
1358 			cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len -
1359 			    offset, length);
1360 
1361 			if (bcmp(digest + scratch_offset,
1362 			    mac->cd_uio->uio_iov[vec_idx].iov_base + offset,
1363 			    cur_len) != 0) {
1364 				ret = CRYPTO_INVALID_MAC;
1365 				break;
1366 			}
1367 
1368 			length -= cur_len;
1369 			vec_idx++;
1370 			scratch_offset += cur_len;
1371 			offset = 0;
1372 		}
1373 		break;
1374 	}
1375 
1376 	case CRYPTO_DATA_MBLK: {
1377 		off_t offset = mac->cd_offset;
1378 		mblk_t *mp;
1379 		off_t scratch_offset = 0;
1380 		size_t length = digest_len;
1381 		size_t cur_len;
1382 
1383 		/* jump to the first mblk_t containing the expected digest */
1384 		for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp);
1385 		    offset -= MBLKL(mp), mp = mp->b_cont)
1386 			;
1387 		if (mp == NULL) {
1388 			/*
1389 			 * The caller specified an offset that is larger than
1390 			 * the total size of the buffers it provided.
1391 			 */
1392 			ret = CRYPTO_DATA_LEN_RANGE;
1393 			break;
1394 		}
1395 
1396 		while (mp != NULL && length > 0) {
1397 			cur_len = MIN(MBLKL(mp) - offset, length);
1398 			if (bcmp(digest + scratch_offset,
1399 			    mp->b_rptr + offset, cur_len) != 0) {
1400 				ret = CRYPTO_INVALID_MAC;
1401 				break;
1402 			}
1403 
1404 			length -= cur_len;
1405 			mp = mp->b_cont;
1406 			scratch_offset += cur_len;
1407 			offset = 0;
1408 		}
1409 		break;
1410 	}
1411 
1412 	default:
1413 		ret = CRYPTO_ARGUMENTS_BAD;
1414 	}
1415 
1416 	bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1417 	return (ret);
1418 bail:
1419 	bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1420 	mac->cd_length = 0;
1421 	return (ret);
1422 }
1423 
1424 /*
1425  * KCF software provider context management entry points.
1426  */
1427 
1428 /* ARGSUSED */
1429 static int
1430 md5_create_ctx_template(crypto_provider_handle_t provider,
1431     crypto_mechanism_t *mechanism, crypto_key_t *key,
1432     crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
1433     crypto_req_handle_t req)
1434 {
1435 	md5_hmac_ctx_t *md5_hmac_ctx_tmpl;
1436 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1437 
1438 	if ((mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE) &&
1439 	    (mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE))
1440 		return (CRYPTO_MECHANISM_INVALID);
1441 
1442 	/* Add support for key by attributes (RFE 4706552) */
1443 	if (key->ck_format != CRYPTO_KEY_RAW)
1444 		return (CRYPTO_ARGUMENTS_BAD);
1445 
1446 	/*
1447 	 * Allocate and initialize MD5 context.
1448 	 */
1449 	md5_hmac_ctx_tmpl = kmem_alloc(sizeof (md5_hmac_ctx_t),
1450 	    crypto_kmflag(req));
1451 	if (md5_hmac_ctx_tmpl == NULL)
1452 		return (CRYPTO_HOST_MEMORY);
1453 
1454 	if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) {
1455 		uchar_t digested_key[MD5_DIGEST_LENGTH];
1456 
1457 		/*
1458 		 * Hash the passed-in key to get a smaller key.
1459 		 * The inner context is used since it hasn't been
1460 		 * initialized yet.
1461 		 */
1462 		PROV_MD5_DIGEST_KEY(&md5_hmac_ctx_tmpl->hc_icontext,
1463 		    key->ck_data, keylen_in_bytes, digested_key);
1464 		md5_mac_init_ctx(md5_hmac_ctx_tmpl, digested_key,
1465 		    MD5_DIGEST_LENGTH);
1466 	} else {
1467 		md5_mac_init_ctx(md5_hmac_ctx_tmpl, key->ck_data,
1468 		    keylen_in_bytes);
1469 	}
1470 
1471 	md5_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;
1472 	*ctx_template = (crypto_spi_ctx_template_t)md5_hmac_ctx_tmpl;
1473 	*ctx_template_size = sizeof (md5_hmac_ctx_t);
1474 
1475 	return (CRYPTO_SUCCESS);
1476 }
1477 
1478 static int
1479 md5_free_context(crypto_ctx_t *ctx)
1480 {
1481 	uint_t ctx_len;
1482 	md5_mech_type_t mech_type;
1483 
1484 	if (ctx->cc_provider_private == NULL)
1485 		return (CRYPTO_SUCCESS);
1486 
1487 	/*
1488 	 * We have to free either MD5 or MD5-HMAC contexts, which
1489 	 * have different lengths.
1490 	 */
1491 
1492 	mech_type = PROV_MD5_CTX(ctx)->mc_mech_type;
1493 	if (mech_type == MD5_MECH_INFO_TYPE)
1494 		ctx_len = sizeof (md5_ctx_t);
1495 	else {
1496 		ASSERT(mech_type == MD5_HMAC_MECH_INFO_TYPE ||
1497 		    mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE);
1498 		ctx_len = sizeof (md5_hmac_ctx_t);
1499 	}
1500 
1501 	bzero(ctx->cc_provider_private, ctx_len);
1502 	kmem_free(ctx->cc_provider_private, ctx_len);
1503 	ctx->cc_provider_private = NULL;
1504 
1505 	return (CRYPTO_SUCCESS);
1506 }
1507