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