xref: /titanic_50/usr/src/uts/common/crypto/io/md5_mod.c (revision c77a61a72b5ecdc507d6cf104142edd371a16c84)
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 2006 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 %I%"
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 	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 	if (vec_idx == digest->cd_uio->uio_iovcnt) {
405 		/*
406 		 * The caller specified an offset that is
407 		 * larger than the total size of the buffers
408 		 * it provided.
409 		 */
410 		return (CRYPTO_DATA_LEN_RANGE);
411 	}
412 
413 	if (offset + digest_len <=
414 	    digest->cd_uio->uio_iov[vec_idx].iov_len) {
415 		/*
416 		 * The computed MD5 digest will fit in the current
417 		 * iovec.
418 		 */
419 		if (digest_len != MD5_DIGEST_LENGTH) {
420 			/*
421 			 * The caller requested a short digest. Digest
422 			 * into a scratch buffer and return to
423 			 * the user only what was requested.
424 			 */
425 			MD5Final(digest_scratch, md5_ctx);
426 			bcopy(digest_scratch, (uchar_t *)digest->
427 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
428 			    digest_len);
429 		} else {
430 			MD5Final((uchar_t *)digest->
431 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
432 			    md5_ctx);
433 		}
434 	} else {
435 		/*
436 		 * The computed digest will be crossing one or more iovec's.
437 		 * This is bad performance-wise but we need to support it.
438 		 * Allocate a small scratch buffer on the stack and
439 		 * copy it piece meal to the specified digest iovec's.
440 		 */
441 		uchar_t digest_tmp[MD5_DIGEST_LENGTH];
442 		off_t scratch_offset = 0;
443 		size_t length = digest_len;
444 		size_t cur_len;
445 
446 		MD5Final(digest_tmp, md5_ctx);
447 
448 		while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
449 			cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
450 			    offset, length);
451 			bcopy(digest_tmp + scratch_offset,
452 			    digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
453 			    cur_len);
454 
455 			length -= cur_len;
456 			vec_idx++;
457 			scratch_offset += cur_len;
458 			offset = 0;
459 		}
460 
461 		if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
462 			/*
463 			 * The end of the specified iovec's was reached but
464 			 * the length requested could not be processed, i.e.
465 			 * The caller requested to digest more data than it
466 			 * provided.
467 			 */
468 			return (CRYPTO_DATA_LEN_RANGE);
469 		}
470 	}
471 
472 	return (CRYPTO_SUCCESS);
473 }
474 
475 /*
476  * Helper MD5 digest update for mblk's.
477  */
478 static int
479 md5_digest_update_mblk(MD5_CTX *md5_ctx, crypto_data_t *data)
480 {
481 	off_t offset = data->cd_offset;
482 	size_t length = data->cd_length;
483 	mblk_t *mp;
484 	size_t cur_len;
485 
486 	/*
487 	 * Jump to the first mblk_t containing data to be digested.
488 	 */
489 	for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
490 	    offset -= MBLKL(mp), mp = mp->b_cont);
491 	if (mp == NULL) {
492 		/*
493 		 * The caller specified an offset that is larger than the
494 		 * total size of the buffers it provided.
495 		 */
496 		return (CRYPTO_DATA_LEN_RANGE);
497 	}
498 
499 	/*
500 	 * Now do the digesting on the mblk chain.
501 	 */
502 	while (mp != NULL && length > 0) {
503 		cur_len = MIN(MBLKL(mp) - offset, length);
504 		MD5Update(md5_ctx, mp->b_rptr + offset, cur_len);
505 		length -= cur_len;
506 		offset = 0;
507 		mp = mp->b_cont;
508 	}
509 
510 	if (mp == NULL && length > 0) {
511 		/*
512 		 * The end of the mblk was reached but the length requested
513 		 * could not be processed, i.e. The caller requested
514 		 * to digest more data than it provided.
515 		 */
516 		return (CRYPTO_DATA_LEN_RANGE);
517 	}
518 
519 	return (CRYPTO_SUCCESS);
520 }
521 
522 /*
523  * Helper MD5 digest final for mblk's.
524  * digest_len is the length of the desired digest. If digest_len
525  * is smaller than the default MD5 digest length, the caller
526  * must pass a scratch buffer, digest_scratch, which must
527  * be at least MD5_DIGEST_LENGTH bytes.
528  */
529 static int
530 md5_digest_final_mblk(MD5_CTX *md5_ctx, crypto_data_t *digest,
531     ulong_t digest_len, uchar_t *digest_scratch)
532 {
533 	off_t offset = digest->cd_offset;
534 	mblk_t *mp;
535 
536 	/*
537 	 * Jump to the first mblk_t that will be used to store the digest.
538 	 */
539 	for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp);
540 	    offset -= MBLKL(mp), mp = mp->b_cont);
541 	if (mp == NULL) {
542 		/*
543 		 * The caller specified an offset that is larger than the
544 		 * total size of the buffers it provided.
545 		 */
546 		return (CRYPTO_DATA_LEN_RANGE);
547 	}
548 
549 	if (offset + digest_len <= MBLKL(mp)) {
550 		/*
551 		 * The computed MD5 digest will fit in the current mblk.
552 		 * Do the MD5Final() in-place.
553 		 */
554 		if (digest_len != MD5_DIGEST_LENGTH) {
555 			/*
556 			 * The caller requested a short digest. Digest
557 			 * into a scratch buffer and return to
558 			 * the user only what was requested.
559 			 */
560 			MD5Final(digest_scratch, md5_ctx);
561 			bcopy(digest_scratch, mp->b_rptr + offset, digest_len);
562 		} else {
563 			MD5Final(mp->b_rptr + offset, md5_ctx);
564 		}
565 	} else {
566 		/*
567 		 * The computed digest will be crossing one or more mblk's.
568 		 * This is bad performance-wise but we need to support it.
569 		 * Allocate a small scratch buffer on the stack and
570 		 * copy it piece meal to the specified digest iovec's.
571 		 */
572 		uchar_t digest_tmp[MD5_DIGEST_LENGTH];
573 		off_t scratch_offset = 0;
574 		size_t length = digest_len;
575 		size_t cur_len;
576 
577 		MD5Final(digest_tmp, md5_ctx);
578 
579 		while (mp != NULL && length > 0) {
580 			cur_len = MIN(MBLKL(mp) - offset, length);
581 			bcopy(digest_tmp + scratch_offset,
582 			    mp->b_rptr + offset, cur_len);
583 
584 			length -= cur_len;
585 			mp = mp->b_cont;
586 			scratch_offset += cur_len;
587 			offset = 0;
588 		}
589 
590 		if (mp == NULL && length > 0) {
591 			/*
592 			 * The end of the specified mblk was reached but
593 			 * the length requested could not be processed, i.e.
594 			 * The caller requested to digest more data than it
595 			 * provided.
596 			 */
597 			return (CRYPTO_DATA_LEN_RANGE);
598 		}
599 	}
600 
601 	return (CRYPTO_SUCCESS);
602 }
603 
604 /* ARGSUSED */
605 static int
606 md5_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
607     crypto_req_handle_t req)
608 {
609 	int ret = CRYPTO_SUCCESS;
610 
611 	ASSERT(ctx->cc_provider_private != NULL);
612 
613 	/*
614 	 * We need to just return the length needed to store the output.
615 	 * We should not destroy the context for the following cases.
616 	 */
617 	if ((digest->cd_length == 0) ||
618 	    (digest->cd_length < MD5_DIGEST_LENGTH)) {
619 		digest->cd_length = MD5_DIGEST_LENGTH;
620 		return (CRYPTO_BUFFER_TOO_SMALL);
621 	}
622 
623 	/*
624 	 * Do the MD5 update on the specified input data.
625 	 */
626 	switch (data->cd_format) {
627 	case CRYPTO_DATA_RAW:
628 		MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
629 		    data->cd_raw.iov_base + data->cd_offset,
630 		    data->cd_length);
631 		break;
632 	case CRYPTO_DATA_UIO:
633 		ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
634 		    data);
635 		break;
636 	case CRYPTO_DATA_MBLK:
637 		ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
638 		    data);
639 		break;
640 	default:
641 		ret = CRYPTO_ARGUMENTS_BAD;
642 	}
643 
644 	if (ret != CRYPTO_SUCCESS) {
645 		/* the update failed, free context and bail */
646 		kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t));
647 		ctx->cc_provider_private = NULL;
648 		digest->cd_length = 0;
649 		return (ret);
650 	}
651 
652 	/*
653 	 * Do an MD5 final, must be done separately since the digest
654 	 * type can be different than the input data type.
655 	 */
656 	switch (digest->cd_format) {
657 	case CRYPTO_DATA_RAW:
658 		MD5Final((unsigned char *)digest->cd_raw.iov_base +
659 		    digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx);
660 		break;
661 	case CRYPTO_DATA_UIO:
662 		ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
663 		    digest, MD5_DIGEST_LENGTH, NULL);
664 		break;
665 	case CRYPTO_DATA_MBLK:
666 		ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
667 		    digest, MD5_DIGEST_LENGTH, NULL);
668 		break;
669 	default:
670 		ret = CRYPTO_ARGUMENTS_BAD;
671 	}
672 
673 	/* all done, free context and return */
674 
675 	if (ret == CRYPTO_SUCCESS) {
676 		digest->cd_length = MD5_DIGEST_LENGTH;
677 	} else {
678 		digest->cd_length = 0;
679 	}
680 
681 	kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t));
682 	ctx->cc_provider_private = NULL;
683 	return (ret);
684 }
685 
686 /* ARGSUSED */
687 static int
688 md5_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
689     crypto_req_handle_t req)
690 {
691 	int ret = CRYPTO_SUCCESS;
692 
693 	ASSERT(ctx->cc_provider_private != NULL);
694 
695 	/*
696 	 * Do the MD5 update on the specified input data.
697 	 */
698 	switch (data->cd_format) {
699 	case CRYPTO_DATA_RAW:
700 		MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
701 		    data->cd_raw.iov_base + data->cd_offset,
702 		    data->cd_length);
703 		break;
704 	case CRYPTO_DATA_UIO:
705 		ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
706 		    data);
707 		break;
708 	case CRYPTO_DATA_MBLK:
709 		ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
710 		    data);
711 		break;
712 	default:
713 		ret = CRYPTO_ARGUMENTS_BAD;
714 	}
715 
716 	return (ret);
717 }
718 
719 /* ARGSUSED */
720 static int
721 md5_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
722     crypto_req_handle_t req)
723 {
724 	int ret = CRYPTO_SUCCESS;
725 
726 	ASSERT(ctx->cc_provider_private != NULL);
727 
728 	/*
729 	 * We need to just return the length needed to store the output.
730 	 * We should not destroy the context for the following cases.
731 	 */
732 	if ((digest->cd_length == 0) ||
733 	    (digest->cd_length < MD5_DIGEST_LENGTH)) {
734 		digest->cd_length = MD5_DIGEST_LENGTH;
735 		return (CRYPTO_BUFFER_TOO_SMALL);
736 	}
737 
738 	/*
739 	 * Do an MD5 final.
740 	 */
741 	switch (digest->cd_format) {
742 	case CRYPTO_DATA_RAW:
743 		MD5Final((unsigned char *)digest->cd_raw.iov_base +
744 		    digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx);
745 		break;
746 	case CRYPTO_DATA_UIO:
747 		ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
748 		    digest, MD5_DIGEST_LENGTH, NULL);
749 		break;
750 	case CRYPTO_DATA_MBLK:
751 		ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx,
752 		    digest, MD5_DIGEST_LENGTH, NULL);
753 		break;
754 	default:
755 		ret = CRYPTO_ARGUMENTS_BAD;
756 	}
757 
758 	/* all done, free context and return */
759 
760 	if (ret == CRYPTO_SUCCESS) {
761 		digest->cd_length = MD5_DIGEST_LENGTH;
762 	} else {
763 		digest->cd_length = 0;
764 	}
765 
766 	kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t));
767 	ctx->cc_provider_private = NULL;
768 
769 	return (ret);
770 }
771 
772 /* ARGSUSED */
773 static int
774 md5_digest_atomic(crypto_provider_handle_t provider,
775     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
776     crypto_data_t *data, crypto_data_t *digest,
777     crypto_req_handle_t req)
778 {
779 	int ret = CRYPTO_SUCCESS;
780 	MD5_CTX md5_ctx;
781 
782 	if (mechanism->cm_type != MD5_MECH_INFO_TYPE)
783 		return (CRYPTO_MECHANISM_INVALID);
784 
785 	/*
786 	 * Do the MD5 init.
787 	 */
788 	MD5Init(&md5_ctx);
789 
790 	/*
791 	 * Do the MD5 update on the specified input data.
792 	 */
793 	switch (data->cd_format) {
794 	case CRYPTO_DATA_RAW:
795 		MD5Update(&md5_ctx, data->cd_raw.iov_base + data->cd_offset,
796 		    data->cd_length);
797 		break;
798 	case CRYPTO_DATA_UIO:
799 		ret = md5_digest_update_uio(&md5_ctx, data);
800 		break;
801 	case CRYPTO_DATA_MBLK:
802 		ret = md5_digest_update_mblk(&md5_ctx, data);
803 		break;
804 	default:
805 		ret = CRYPTO_ARGUMENTS_BAD;
806 	}
807 
808 	if (ret != CRYPTO_SUCCESS) {
809 		/* the update failed, bail */
810 		digest->cd_length = 0;
811 		return (ret);
812 	}
813 
814 	/*
815 	 * Do an MD5 final, must be done separately since the digest
816 	 * type can be different than the input data type.
817 	 */
818 	switch (digest->cd_format) {
819 	case CRYPTO_DATA_RAW:
820 		MD5Final((unsigned char *)digest->cd_raw.iov_base +
821 		    digest->cd_offset, &md5_ctx);
822 		break;
823 	case CRYPTO_DATA_UIO:
824 		ret = md5_digest_final_uio(&md5_ctx, digest,
825 		    MD5_DIGEST_LENGTH, NULL);
826 		break;
827 	case CRYPTO_DATA_MBLK:
828 		ret = md5_digest_final_mblk(&md5_ctx, digest,
829 		    MD5_DIGEST_LENGTH, NULL);
830 		break;
831 	default:
832 		ret = CRYPTO_ARGUMENTS_BAD;
833 	}
834 
835 	if (ret == CRYPTO_SUCCESS) {
836 		digest->cd_length = MD5_DIGEST_LENGTH;
837 	} else {
838 		digest->cd_length = 0;
839 	}
840 
841 	return (ret);
842 }
843 
844 /*
845  * KCF software provider mac entry points.
846  *
847  * MD5 HMAC is: MD5(key XOR opad, MD5(key XOR ipad, text))
848  *
849  * Init:
850  * The initialization routine initializes what we denote
851  * as the inner and outer contexts by doing
852  * - for inner context: MD5(key XOR ipad)
853  * - for outer context: MD5(key XOR opad)
854  *
855  * Update:
856  * Each subsequent MD5 HMAC update will result in an
857  * update of the inner context with the specified data.
858  *
859  * Final:
860  * The MD5 HMAC final will do a MD5 final operation on the
861  * inner context, and the resulting digest will be used
862  * as the data for an update on the outer context. Last
863  * but not least, an MD5 final on the outer context will
864  * be performed to obtain the MD5 HMAC digest to return
865  * to the user.
866  */
867 
868 /*
869  * Initialize a MD5-HMAC context.
870  */
871 static void
872 md5_mac_init_ctx(md5_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
873 {
874 	uint32_t ipad[MD5_HMAC_INTS_PER_BLOCK];
875 	uint32_t opad[MD5_HMAC_INTS_PER_BLOCK];
876 	uint_t i;
877 
878 	bzero(ipad, MD5_HMAC_BLOCK_SIZE);
879 	bzero(opad, MD5_HMAC_BLOCK_SIZE);
880 
881 	bcopy(keyval, ipad, length_in_bytes);
882 	bcopy(keyval, opad, length_in_bytes);
883 
884 	/* XOR key with ipad (0x36) and opad (0x5c) */
885 	for (i = 0; i < MD5_HMAC_INTS_PER_BLOCK; i++) {
886 		ipad[i] ^= 0x36363636;
887 		opad[i] ^= 0x5c5c5c5c;
888 	}
889 
890 	/* perform MD5 on ipad */
891 	MD5Init(&ctx->hc_icontext);
892 	MD5Update(&ctx->hc_icontext, ipad, MD5_HMAC_BLOCK_SIZE);
893 
894 	/* perform MD5 on opad */
895 	MD5Init(&ctx->hc_ocontext);
896 	MD5Update(&ctx->hc_ocontext, opad, MD5_HMAC_BLOCK_SIZE);
897 }
898 
899 /*
900  * Initializes a multi-part MAC operation.
901  */
902 static int
903 md5_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
904     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
905     crypto_req_handle_t req)
906 {
907 	int ret = CRYPTO_SUCCESS;
908 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
909 
910 	if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE &&
911 	    mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)
912 		return (CRYPTO_MECHANISM_INVALID);
913 
914 	/* Add support for key by attributes (RFE 4706552) */
915 	if (key->ck_format != CRYPTO_KEY_RAW)
916 		return (CRYPTO_ARGUMENTS_BAD);
917 
918 	ctx->cc_provider_private = kmem_alloc(sizeof (md5_hmac_ctx_t),
919 	    crypto_kmflag(req));
920 	if (ctx->cc_provider_private == NULL)
921 		return (CRYPTO_HOST_MEMORY);
922 
923 	if (ctx_template != NULL) {
924 		/* reuse context template */
925 		bcopy(ctx_template, PROV_MD5_HMAC_CTX(ctx),
926 		    sizeof (md5_hmac_ctx_t));
927 	} else {
928 		/* no context template, compute context */
929 		if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) {
930 			uchar_t digested_key[MD5_DIGEST_LENGTH];
931 			md5_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;
932 
933 			/*
934 			 * Hash the passed-in key to get a smaller key.
935 			 * The inner context is used since it hasn't been
936 			 * initialized yet.
937 			 */
938 			PROV_MD5_DIGEST_KEY(&hmac_ctx->hc_icontext,
939 			    key->ck_data, keylen_in_bytes, digested_key);
940 			md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx),
941 			    digested_key, MD5_DIGEST_LENGTH);
942 		} else {
943 			md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx),
944 			    key->ck_data, keylen_in_bytes);
945 		}
946 	}
947 
948 	/*
949 	 * Get the mechanism parameters, if applicable.
950 	 */
951 	PROV_MD5_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;
952 	if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) {
953 		if (mechanism->cm_param == NULL ||
954 		    mechanism->cm_param_len != sizeof (ulong_t))
955 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
956 		PROV_MD5_GET_DIGEST_LEN(mechanism,
957 		    PROV_MD5_HMAC_CTX(ctx)->hc_digest_len);
958 		if (PROV_MD5_HMAC_CTX(ctx)->hc_digest_len >
959 		    MD5_DIGEST_LENGTH)
960 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
961 	}
962 
963 	if (ret != CRYPTO_SUCCESS) {
964 		bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t));
965 		kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t));
966 		ctx->cc_provider_private = NULL;
967 	}
968 
969 	return (ret);
970 }
971 
972 
973 /* ARGSUSED */
974 static int
975 md5_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
976 {
977 	int ret = CRYPTO_SUCCESS;
978 
979 	ASSERT(ctx->cc_provider_private != NULL);
980 
981 	/*
982 	 * Do an MD5 update of the inner context using the specified
983 	 * data.
984 	 */
985 	switch (data->cd_format) {
986 	case CRYPTO_DATA_RAW:
987 		MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_icontext,
988 		    data->cd_raw.iov_base + data->cd_offset,
989 		    data->cd_length);
990 		break;
991 	case CRYPTO_DATA_UIO:
992 		ret = md5_digest_update_uio(
993 		    &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data);
994 		break;
995 	case CRYPTO_DATA_MBLK:
996 		ret = md5_digest_update_mblk(
997 		    &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data);
998 		break;
999 	default:
1000 		ret = CRYPTO_ARGUMENTS_BAD;
1001 	}
1002 
1003 	return (ret);
1004 }
1005 
1006 /* ARGSUSED */
1007 static int
1008 md5_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
1009 {
1010 	int ret = CRYPTO_SUCCESS;
1011 	uchar_t digest[MD5_DIGEST_LENGTH];
1012 	uint32_t digest_len = MD5_DIGEST_LENGTH;
1013 
1014 	ASSERT(ctx->cc_provider_private != NULL);
1015 
1016 	if (PROV_MD5_HMAC_CTX(ctx)->hc_mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE)
1017 	    digest_len = PROV_MD5_HMAC_CTX(ctx)->hc_digest_len;
1018 
1019 	/*
1020 	 * We need to just return the length needed to store the output.
1021 	 * We should not destroy the context for the following cases.
1022 	 */
1023 	if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {
1024 		mac->cd_length = digest_len;
1025 		return (CRYPTO_BUFFER_TOO_SMALL);
1026 	}
1027 
1028 	/*
1029 	 * Do an MD5 final on the inner context.
1030 	 */
1031 	MD5Final(digest, &PROV_MD5_HMAC_CTX(ctx)->hc_icontext);
1032 
1033 	/*
1034 	 * Do an MD5 update on the outer context, feeding the inner
1035 	 * digest as data.
1036 	 */
1037 	MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, digest,
1038 	    MD5_DIGEST_LENGTH);
1039 
1040 	/*
1041 	 * Do an MD5 final on the outer context, storing the computing
1042 	 * digest in the users buffer.
1043 	 */
1044 	switch (mac->cd_format) {
1045 	case CRYPTO_DATA_RAW:
1046 		if (digest_len != MD5_DIGEST_LENGTH) {
1047 			/*
1048 			 * The caller requested a short digest. Digest
1049 			 * into a scratch buffer and return to
1050 			 * the user only what was requested.
1051 			 */
1052 			MD5Final(digest,
1053 			    &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext);
1054 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
1055 			    mac->cd_offset, digest_len);
1056 		} else {
1057 			MD5Final((unsigned char *)mac->cd_raw.iov_base +
1058 			    mac->cd_offset,
1059 			    &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext);
1060 		}
1061 		break;
1062 	case CRYPTO_DATA_UIO:
1063 		ret = md5_digest_final_uio(
1064 		    &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac,
1065 		    digest_len, digest);
1066 		break;
1067 	case CRYPTO_DATA_MBLK:
1068 		ret = md5_digest_final_mblk(
1069 		    &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac,
1070 		    digest_len, digest);
1071 		break;
1072 	default:
1073 		ret = CRYPTO_ARGUMENTS_BAD;
1074 	}
1075 
1076 	if (ret == CRYPTO_SUCCESS) {
1077 		mac->cd_length = digest_len;
1078 	} else {
1079 		mac->cd_length = 0;
1080 	}
1081 
1082 	bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t));
1083 	kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t));
1084 	ctx->cc_provider_private = NULL;
1085 
1086 	return (ret);
1087 }
1088 
1089 #define	MD5_MAC_UPDATE(data, ctx, ret) {				\
1090 	switch (data->cd_format) {					\
1091 	case CRYPTO_DATA_RAW:						\
1092 		MD5Update(&(ctx).hc_icontext,				\
1093 		    data->cd_raw.iov_base + data->cd_offset,		\
1094 		    data->cd_length);					\
1095 		break;							\
1096 	case CRYPTO_DATA_UIO:						\
1097 		ret = md5_digest_update_uio(&(ctx).hc_icontext,	data);	\
1098 		break;							\
1099 	case CRYPTO_DATA_MBLK:						\
1100 		ret = md5_digest_update_mblk(&(ctx).hc_icontext,	\
1101 		    data);						\
1102 		break;							\
1103 	default:							\
1104 		ret = CRYPTO_ARGUMENTS_BAD;				\
1105 	}								\
1106 }
1107 
1108 
1109 /* ARGSUSED */
1110 static int
1111 md5_mac_atomic(crypto_provider_handle_t provider,
1112     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1113     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
1114     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
1115 {
1116 	int ret = CRYPTO_SUCCESS;
1117 	uchar_t digest[MD5_DIGEST_LENGTH];
1118 	md5_hmac_ctx_t md5_hmac_ctx;
1119 	uint32_t digest_len = MD5_DIGEST_LENGTH;
1120 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1121 
1122 	if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE &&
1123 	    mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)
1124 		return (CRYPTO_MECHANISM_INVALID);
1125 
1126 	/* Add support for key by attributes (RFE 4706552) */
1127 	if (key->ck_format != CRYPTO_KEY_RAW)
1128 		return (CRYPTO_ARGUMENTS_BAD);
1129 
1130 	if (ctx_template != NULL) {
1131 		/* reuse context template */
1132 		bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1133 	} else {
1134 		/* no context template, compute context */
1135 		if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) {
1136 			/*
1137 			 * Hash the passed-in key to get a smaller key.
1138 			 * The inner context is used since it hasn't been
1139 			 * initialized yet.
1140 			 */
1141 			PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext,
1142 			    key->ck_data, keylen_in_bytes, digest);
1143 			md5_mac_init_ctx(&md5_hmac_ctx, digest,
1144 			    MD5_DIGEST_LENGTH);
1145 		} else {
1146 			md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data,
1147 			    keylen_in_bytes);
1148 		}
1149 	}
1150 
1151 	/*
1152 	 * Get the mechanism parameters, if applicable.
1153 	 */
1154 	if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) {
1155 		if (mechanism->cm_param == NULL ||
1156 		    mechanism->cm_param_len != sizeof (ulong_t)) {
1157 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1158 			goto bail;
1159 		}
1160 		PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len);
1161 		if (digest_len > MD5_DIGEST_LENGTH) {
1162 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1163 			goto bail;
1164 		}
1165 	}
1166 
1167 	/* do an MD5 update of the inner context using the specified data */
1168 	MD5_MAC_UPDATE(data, md5_hmac_ctx, ret);
1169 	if (ret != CRYPTO_SUCCESS)
1170 		/* the update failed, free context and bail */
1171 		goto bail;
1172 
1173 	/* do an MD5 final on the inner context */
1174 	MD5Final(digest, &md5_hmac_ctx.hc_icontext);
1175 
1176 	/*
1177 	 * Do an MD5 update on the outer context, feeding the inner
1178 	 * digest as data.
1179 	 */
1180 	MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH);
1181 
1182 	/*
1183 	 * Do an MD5 final on the outer context, storing the computed
1184 	 * digest in the users buffer.
1185 	 */
1186 	switch (mac->cd_format) {
1187 	case CRYPTO_DATA_RAW:
1188 		if (digest_len != MD5_DIGEST_LENGTH) {
1189 			/*
1190 			 * The caller requested a short digest. Digest
1191 			 * into a scratch buffer and return to
1192 			 * the user only what was requested.
1193 			 */
1194 			MD5Final(digest, &md5_hmac_ctx.hc_ocontext);
1195 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
1196 			    mac->cd_offset, digest_len);
1197 		} else {
1198 			MD5Final((unsigned char *)mac->cd_raw.iov_base +
1199 			    mac->cd_offset, &md5_hmac_ctx.hc_ocontext);
1200 		}
1201 		break;
1202 	case CRYPTO_DATA_UIO:
1203 		ret = md5_digest_final_uio(&md5_hmac_ctx.hc_ocontext, mac,
1204 		    digest_len, digest);
1205 		break;
1206 	case CRYPTO_DATA_MBLK:
1207 		ret = md5_digest_final_mblk(&md5_hmac_ctx.hc_ocontext, mac,
1208 		    digest_len, digest);
1209 		break;
1210 	default:
1211 		ret = CRYPTO_ARGUMENTS_BAD;
1212 	}
1213 
1214 	if (ret == CRYPTO_SUCCESS) {
1215 		mac->cd_length = digest_len;
1216 	} else {
1217 		mac->cd_length = 0;
1218 	}
1219 	/* Extra paranoia: zeroizing the local context on the stack */
1220 	bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1221 
1222 	return (ret);
1223 bail:
1224 	bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1225 	mac->cd_length = 0;
1226 	return (ret);
1227 }
1228 
1229 /* ARGSUSED */
1230 static int
1231 md5_mac_verify_atomic(crypto_provider_handle_t provider,
1232     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1233     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
1234     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
1235 {
1236 	int ret = CRYPTO_SUCCESS;
1237 	uchar_t digest[MD5_DIGEST_LENGTH];
1238 	md5_hmac_ctx_t md5_hmac_ctx;
1239 	uint32_t digest_len = MD5_DIGEST_LENGTH;
1240 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1241 
1242 	if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE &&
1243 	    mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)
1244 		return (CRYPTO_MECHANISM_INVALID);
1245 
1246 	/* Add support for key by attributes (RFE 4706552) */
1247 	if (key->ck_format != CRYPTO_KEY_RAW)
1248 		return (CRYPTO_ARGUMENTS_BAD);
1249 
1250 	if (ctx_template != NULL) {
1251 		/* reuse context template */
1252 		bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1253 	} else {
1254 		/* no context template, compute context */
1255 		if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) {
1256 			/*
1257 			 * Hash the passed-in key to get a smaller key.
1258 			 * The inner context is used since it hasn't been
1259 			 * initialized yet.
1260 			 */
1261 			PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext,
1262 			    key->ck_data, keylen_in_bytes, digest);
1263 			md5_mac_init_ctx(&md5_hmac_ctx, digest,
1264 			    MD5_DIGEST_LENGTH);
1265 		} else {
1266 			md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data,
1267 			    keylen_in_bytes);
1268 		}
1269 	}
1270 
1271 	/*
1272 	 * Get the mechanism parameters, if applicable.
1273 	 */
1274 	if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) {
1275 		if (mechanism->cm_param == NULL ||
1276 		    mechanism->cm_param_len != sizeof (ulong_t)) {
1277 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1278 			goto bail;
1279 		}
1280 		PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len);
1281 		if (digest_len > MD5_DIGEST_LENGTH) {
1282 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1283 			goto bail;
1284 		}
1285 	}
1286 
1287 	if (mac->cd_length != digest_len) {
1288 		ret = CRYPTO_INVALID_MAC;
1289 		goto bail;
1290 	}
1291 
1292 	/* do an MD5 update of the inner context using the specified data */
1293 	MD5_MAC_UPDATE(data, md5_hmac_ctx, ret);
1294 	if (ret != CRYPTO_SUCCESS)
1295 		/* the update failed, free context and bail */
1296 		goto bail;
1297 
1298 	/* do an MD5 final on the inner context */
1299 	MD5Final(digest, &md5_hmac_ctx.hc_icontext);
1300 
1301 	/*
1302 	 * Do an MD5 update on the outer context, feeding the inner
1303 	 * digest as data.
1304 	 */
1305 	MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH);
1306 
1307 	/*
1308 	 * Do an MD5 final on the outer context, storing the computed
1309 	 * digest in the local digest buffer.
1310 	 */
1311 	MD5Final(digest, &md5_hmac_ctx.hc_ocontext);
1312 
1313 	/*
1314 	 * Compare the computed digest against the expected digest passed
1315 	 * as argument.
1316 	 */
1317 	switch (mac->cd_format) {
1318 
1319 	case CRYPTO_DATA_RAW:
1320 		if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base +
1321 		    mac->cd_offset, digest_len) != 0)
1322 			ret = CRYPTO_INVALID_MAC;
1323 		break;
1324 
1325 	case CRYPTO_DATA_UIO: {
1326 		off_t offset = mac->cd_offset;
1327 		uint_t vec_idx;
1328 		off_t scratch_offset = 0;
1329 		size_t length = digest_len;
1330 		size_t cur_len;
1331 
1332 		/* we support only kernel buffer */
1333 		if (mac->cd_uio->uio_segflg != UIO_SYSSPACE)
1334 			return (CRYPTO_ARGUMENTS_BAD);
1335 
1336 		/* jump to the first iovec containing the expected digest */
1337 		for (vec_idx = 0;
1338 		    offset >= mac->cd_uio->uio_iov[vec_idx].iov_len &&
1339 		    vec_idx < mac->cd_uio->uio_iovcnt;
1340 		    offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len);
1341 		if (vec_idx == mac->cd_uio->uio_iovcnt) {
1342 			/*
1343 			 * The caller specified an offset that is
1344 			 * larger than the total size of the buffers
1345 			 * it provided.
1346 			 */
1347 			ret = CRYPTO_DATA_LEN_RANGE;
1348 			break;
1349 		}
1350 
1351 		/* do the comparison of computed digest vs specified one */
1352 		while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) {
1353 			cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len -
1354 			    offset, length);
1355 
1356 			if (bcmp(digest + scratch_offset,
1357 			    mac->cd_uio->uio_iov[vec_idx].iov_base + offset,
1358 			    cur_len) != 0) {
1359 				ret = CRYPTO_INVALID_MAC;
1360 				break;
1361 			}
1362 
1363 			length -= cur_len;
1364 			vec_idx++;
1365 			scratch_offset += cur_len;
1366 			offset = 0;
1367 		}
1368 		break;
1369 	}
1370 
1371 	case CRYPTO_DATA_MBLK: {
1372 		off_t offset = mac->cd_offset;
1373 		mblk_t *mp;
1374 		off_t scratch_offset = 0;
1375 		size_t length = digest_len;
1376 		size_t cur_len;
1377 
1378 		/* jump to the first mblk_t containing the expected digest */
1379 		for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp);
1380 		    offset -= MBLKL(mp), mp = mp->b_cont);
1381 		if (mp == NULL) {
1382 			/*
1383 			 * The caller specified an offset that is larger than
1384 			 * the total size of the buffers it provided.
1385 			 */
1386 			ret = CRYPTO_DATA_LEN_RANGE;
1387 			break;
1388 		}
1389 
1390 		while (mp != NULL && length > 0) {
1391 			cur_len = MIN(MBLKL(mp) - offset, length);
1392 			if (bcmp(digest + scratch_offset,
1393 			    mp->b_rptr + offset, cur_len) != 0) {
1394 				ret = CRYPTO_INVALID_MAC;
1395 				break;
1396 			}
1397 
1398 			length -= cur_len;
1399 			mp = mp->b_cont;
1400 			scratch_offset += cur_len;
1401 			offset = 0;
1402 		}
1403 		break;
1404 	}
1405 
1406 	default:
1407 		ret = CRYPTO_ARGUMENTS_BAD;
1408 	}
1409 
1410 	bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1411 	return (ret);
1412 bail:
1413 	bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t));
1414 	mac->cd_length = 0;
1415 	return (ret);
1416 }
1417 
1418 /*
1419  * KCF software provider context management entry points.
1420  */
1421 
1422 /* ARGSUSED */
1423 static int
1424 md5_create_ctx_template(crypto_provider_handle_t provider,
1425     crypto_mechanism_t *mechanism, crypto_key_t *key,
1426     crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
1427     crypto_req_handle_t req)
1428 {
1429 	md5_hmac_ctx_t *md5_hmac_ctx_tmpl;
1430 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1431 
1432 	if ((mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE) &&
1433 	    (mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE))
1434 		return (CRYPTO_MECHANISM_INVALID);
1435 
1436 	/* Add support for key by attributes (RFE 4706552) */
1437 	if (key->ck_format != CRYPTO_KEY_RAW)
1438 		return (CRYPTO_ARGUMENTS_BAD);
1439 
1440 	/*
1441 	 * Allocate and initialize MD5 context.
1442 	 */
1443 	md5_hmac_ctx_tmpl = kmem_alloc(sizeof (md5_hmac_ctx_t),
1444 	    crypto_kmflag(req));
1445 	if (md5_hmac_ctx_tmpl == NULL)
1446 		return (CRYPTO_HOST_MEMORY);
1447 
1448 	if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) {
1449 		uchar_t digested_key[MD5_DIGEST_LENGTH];
1450 
1451 		/*
1452 		 * Hash the passed-in key to get a smaller key.
1453 		 * The inner context is used since it hasn't been
1454 		 * initialized yet.
1455 		 */
1456 		PROV_MD5_DIGEST_KEY(&md5_hmac_ctx_tmpl->hc_icontext,
1457 		    key->ck_data, keylen_in_bytes, digested_key);
1458 		md5_mac_init_ctx(md5_hmac_ctx_tmpl, digested_key,
1459 		    MD5_DIGEST_LENGTH);
1460 	} else {
1461 		md5_mac_init_ctx(md5_hmac_ctx_tmpl, key->ck_data,
1462 		    keylen_in_bytes);
1463 	}
1464 
1465 	md5_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;
1466 	*ctx_template = (crypto_spi_ctx_template_t)md5_hmac_ctx_tmpl;
1467 	*ctx_template_size = sizeof (md5_hmac_ctx_t);
1468 
1469 	return (CRYPTO_SUCCESS);
1470 }
1471 
1472 static int
1473 md5_free_context(crypto_ctx_t *ctx)
1474 {
1475 	uint_t ctx_len;
1476 	md5_mech_type_t mech_type;
1477 
1478 	if (ctx->cc_provider_private == NULL)
1479 		return (CRYPTO_SUCCESS);
1480 
1481 	/*
1482 	 * We have to free either MD5 or MD5-HMAC contexts, which
1483 	 * have different lengths.
1484 	 */
1485 
1486 	mech_type = PROV_MD5_CTX(ctx)->mc_mech_type;
1487 	if (mech_type == MD5_MECH_INFO_TYPE)
1488 		ctx_len = sizeof (md5_ctx_t);
1489 	else {
1490 		ASSERT(mech_type == MD5_HMAC_MECH_INFO_TYPE ||
1491 		    mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE);
1492 		ctx_len = sizeof (md5_hmac_ctx_t);
1493 	}
1494 
1495 	bzero(ctx->cc_provider_private, ctx_len);
1496 	kmem_free(ctx->cc_provider_private, ctx_len);
1497 	ctx->cc_provider_private = NULL;
1498 
1499 	return (CRYPTO_SUCCESS);
1500 }
1501