Home | History | Annotate | Download | only in io
      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