xref: /onnv-gate/usr/src/uts/common/crypto/io/sha1_mod.c (revision 11751:58c0c8f4305f)
11694Sdarrenm /*
21694Sdarrenm  * CDDL HEADER START
31694Sdarrenm  *
41694Sdarrenm  * The contents of this file are subject to the terms of the
51694Sdarrenm  * Common Development and Distribution License (the "License").
61694Sdarrenm  * You may not use this file except in compliance with the License.
71694Sdarrenm  *
81694Sdarrenm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91694Sdarrenm  * or http://www.opensolaris.org/os/licensing.
101694Sdarrenm  * See the License for the specific language governing permissions
111694Sdarrenm  * and limitations under the License.
121694Sdarrenm  *
131694Sdarrenm  * When distributing Covered Code, include this CDDL HEADER in each
141694Sdarrenm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151694Sdarrenm  * If applicable, add the following below this CDDL HEADER, with the
161694Sdarrenm  * fields enclosed by brackets "[]" replaced with your own identifying
171694Sdarrenm  * information: Portions Copyright [yyyy] [name of copyright owner]
181694Sdarrenm  *
191694Sdarrenm  * CDDL HEADER END
201694Sdarrenm  */
211694Sdarrenm 
221694Sdarrenm /*
23*11751SAnthony.Scarpino@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
241694Sdarrenm  * Use is subject to license terms.
251694Sdarrenm  */
261694Sdarrenm 
271694Sdarrenm #include <sys/modctl.h>
281694Sdarrenm #include <sys/cmn_err.h>
291694Sdarrenm #include <sys/note.h>
301694Sdarrenm #include <sys/crypto/common.h>
311694Sdarrenm #include <sys/crypto/spi.h>
321694Sdarrenm #include <sys/strsun.h>
331694Sdarrenm #include <sys/systm.h>
341694Sdarrenm #include <sys/sysmacros.h>
351694Sdarrenm 
361694Sdarrenm #include <sys/sha1.h>
3710500SHai-May.Chao@Sun.COM #include <sha1/sha1_impl.h>
381694Sdarrenm 
391694Sdarrenm /*
401694Sdarrenm  * The sha1 module is created with two modlinkages:
411694Sdarrenm  * - a modlmisc that allows consumers to directly call the entry points
421694Sdarrenm  *   SHA1Init, SHA1Update, and SHA1Final.
431694Sdarrenm  * - a modlcrypto that allows the module to register with the Kernel
441694Sdarrenm  *   Cryptographic Framework (KCF) as a software provider for the SHA1
451694Sdarrenm  *   mechanisms.
461694Sdarrenm  */
471694Sdarrenm 
481694Sdarrenm static struct modlmisc modlmisc = {
491694Sdarrenm 	&mod_miscops,
501694Sdarrenm 	"SHA1 Message-Digest Algorithm"
511694Sdarrenm };
521694Sdarrenm 
531694Sdarrenm static struct modlcrypto modlcrypto = {
541694Sdarrenm 	&mod_cryptoops,
551694Sdarrenm 	"SHA1 Kernel SW Provider 1.1"
561694Sdarrenm };
571694Sdarrenm 
581694Sdarrenm static struct modlinkage modlinkage = {
591694Sdarrenm 	MODREV_1, &modlmisc, &modlcrypto, NULL
601694Sdarrenm };
611694Sdarrenm 
621694Sdarrenm 
631694Sdarrenm /*
641694Sdarrenm  * Macros to access the SHA1 or SHA1-HMAC contexts from a context passed
651694Sdarrenm  * by KCF to one of the entry points.
661694Sdarrenm  */
671694Sdarrenm 
681694Sdarrenm #define	PROV_SHA1_CTX(ctx)	((sha1_ctx_t *)(ctx)->cc_provider_private)
691694Sdarrenm #define	PROV_SHA1_HMAC_CTX(ctx)	((sha1_hmac_ctx_t *)(ctx)->cc_provider_private)
701694Sdarrenm 
711694Sdarrenm /* to extract the digest length passed as mechanism parameter */
721694Sdarrenm #define	PROV_SHA1_GET_DIGEST_LEN(m, len) {				\
731694Sdarrenm 	if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t)))		\
7411141Sopensolaris@drydog.com 		(len) = (uint32_t)*((ulong_t *)(void *)mechanism->cm_param); \
751694Sdarrenm 	else {								\
761694Sdarrenm 		ulong_t tmp_ulong;					\
771694Sdarrenm 		bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t));	\
781694Sdarrenm 		(len) = (uint32_t)tmp_ulong;				\
791694Sdarrenm 	}								\
801694Sdarrenm }
811694Sdarrenm 
821694Sdarrenm #define	PROV_SHA1_DIGEST_KEY(ctx, key, len, digest) {	\
831694Sdarrenm 	SHA1Init(ctx);					\
841694Sdarrenm 	SHA1Update(ctx, key, len);			\
851694Sdarrenm 	SHA1Final(digest, ctx);				\
861694Sdarrenm }
871694Sdarrenm 
881694Sdarrenm /*
891694Sdarrenm  * Mechanism info structure passed to KCF during registration.
901694Sdarrenm  */
911694Sdarrenm static crypto_mech_info_t sha1_mech_info_tab[] = {
921694Sdarrenm 	/* SHA1 */
931694Sdarrenm 	{SUN_CKM_SHA1, SHA1_MECH_INFO_TYPE,
941694Sdarrenm 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
951694Sdarrenm 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
961694Sdarrenm 	/* SHA1-HMAC */
971694Sdarrenm 	{SUN_CKM_SHA1_HMAC, SHA1_HMAC_MECH_INFO_TYPE,
981694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
991694Sdarrenm 	    SHA1_HMAC_MIN_KEY_LEN, SHA1_HMAC_MAX_KEY_LEN,
1009364SVladimir.Kotal@Sun.COM 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1011694Sdarrenm 	/* SHA1-HMAC GENERAL */
1021694Sdarrenm 	{SUN_CKM_SHA1_HMAC_GENERAL, SHA1_HMAC_GEN_MECH_INFO_TYPE,
1031694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
1041694Sdarrenm 	    SHA1_HMAC_MIN_KEY_LEN, SHA1_HMAC_MAX_KEY_LEN,
1059364SVladimir.Kotal@Sun.COM 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES}
1061694Sdarrenm };
1071694Sdarrenm 
1081694Sdarrenm static void sha1_provider_status(crypto_provider_handle_t, uint_t *);
1091694Sdarrenm 
1101694Sdarrenm static crypto_control_ops_t sha1_control_ops = {
1111694Sdarrenm 	sha1_provider_status
1121694Sdarrenm };
1131694Sdarrenm 
1141694Sdarrenm static int sha1_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
1151694Sdarrenm     crypto_req_handle_t);
1161694Sdarrenm static int sha1_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1171694Sdarrenm     crypto_req_handle_t);
1181694Sdarrenm static int sha1_digest_update(crypto_ctx_t *, crypto_data_t *,
1191694Sdarrenm     crypto_req_handle_t);
1201694Sdarrenm static int sha1_digest_final(crypto_ctx_t *, crypto_data_t *,
1211694Sdarrenm     crypto_req_handle_t);
1221694Sdarrenm static int sha1_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
1231694Sdarrenm     crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
1241694Sdarrenm     crypto_req_handle_t);
1251694Sdarrenm 
1261694Sdarrenm static crypto_digest_ops_t sha1_digest_ops = {
1271694Sdarrenm 	sha1_digest_init,
1281694Sdarrenm 	sha1_digest,
1291694Sdarrenm 	sha1_digest_update,
1301694Sdarrenm 	NULL,
1311694Sdarrenm 	sha1_digest_final,
1321694Sdarrenm 	sha1_digest_atomic
1331694Sdarrenm };
1341694Sdarrenm 
1351694Sdarrenm static int sha1_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
1361694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
1371694Sdarrenm static int sha1_mac_update(crypto_ctx_t *, crypto_data_t *,
1381694Sdarrenm     crypto_req_handle_t);
1391694Sdarrenm static int sha1_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
1401694Sdarrenm static int sha1_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
1411694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1421694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
1431694Sdarrenm static int sha1_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
1441694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1451694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
1461694Sdarrenm 
1471694Sdarrenm static crypto_mac_ops_t sha1_mac_ops = {
1481694Sdarrenm 	sha1_mac_init,
1491694Sdarrenm 	NULL,
1501694Sdarrenm 	sha1_mac_update,
1511694Sdarrenm 	sha1_mac_final,
1521694Sdarrenm 	sha1_mac_atomic,
1531694Sdarrenm 	sha1_mac_verify_atomic
1541694Sdarrenm };
1551694Sdarrenm 
1561694Sdarrenm static int sha1_create_ctx_template(crypto_provider_handle_t,
1571694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
1581694Sdarrenm     size_t *, crypto_req_handle_t);
1591694Sdarrenm static int sha1_free_context(crypto_ctx_t *);
1601694Sdarrenm 
1611694Sdarrenm static crypto_ctx_ops_t sha1_ctx_ops = {
1621694Sdarrenm 	sha1_create_ctx_template,
1631694Sdarrenm 	sha1_free_context
1641694Sdarrenm };
1651694Sdarrenm 
16610732SAnthony.Scarpino@Sun.COM static void sha1_POST(int *);
16710732SAnthony.Scarpino@Sun.COM 
16810732SAnthony.Scarpino@Sun.COM static crypto_fips140_ops_t sha1_fips140_ops = {
16910732SAnthony.Scarpino@Sun.COM 	sha1_POST
17010732SAnthony.Scarpino@Sun.COM };
17110732SAnthony.Scarpino@Sun.COM 
1721694Sdarrenm static crypto_ops_t sha1_crypto_ops = {
1731694Sdarrenm 	&sha1_control_ops,
1741694Sdarrenm 	&sha1_digest_ops,
1751694Sdarrenm 	NULL,
1761694Sdarrenm 	&sha1_mac_ops,
1771694Sdarrenm 	NULL,
1781694Sdarrenm 	NULL,
1791694Sdarrenm 	NULL,
1801694Sdarrenm 	NULL,
1811694Sdarrenm 	NULL,
1821694Sdarrenm 	NULL,
1831694Sdarrenm 	NULL,
1841694Sdarrenm 	NULL,
1851694Sdarrenm 	NULL,
18610732SAnthony.Scarpino@Sun.COM 	&sha1_ctx_ops,
18710732SAnthony.Scarpino@Sun.COM 	NULL,
18810732SAnthony.Scarpino@Sun.COM 	NULL,
18910732SAnthony.Scarpino@Sun.COM 	&sha1_fips140_ops
1901694Sdarrenm };
1911694Sdarrenm 
1921694Sdarrenm static crypto_provider_info_t sha1_prov_info = {
19310732SAnthony.Scarpino@Sun.COM 	CRYPTO_SPI_VERSION_4,
1941694Sdarrenm 	"SHA1 Software Provider",
1951694Sdarrenm 	CRYPTO_SW_PROVIDER,
1961694Sdarrenm 	{&modlinkage},
1971694Sdarrenm 	NULL,
1981694Sdarrenm 	&sha1_crypto_ops,
1991694Sdarrenm 	sizeof (sha1_mech_info_tab)/sizeof (crypto_mech_info_t),
2001694Sdarrenm 	sha1_mech_info_tab
2011694Sdarrenm };
2021694Sdarrenm 
2031694Sdarrenm static crypto_kcf_provider_handle_t sha1_prov_handle = NULL;
2041694Sdarrenm 
2051694Sdarrenm int
_init()2061694Sdarrenm _init()
2071694Sdarrenm {
2081694Sdarrenm 	int ret;
2091694Sdarrenm 
2101694Sdarrenm 	if ((ret = mod_install(&modlinkage)) != 0)
2111694Sdarrenm 		return (ret);
2121694Sdarrenm 
2131694Sdarrenm 	/*
214*11751SAnthony.Scarpino@Sun.COM 	 * Register with KCF. If the registration fails, log do not uninstall
215*11751SAnthony.Scarpino@Sun.COM 	 * the module, since the functionality provided by misc/sha1 should
216*11751SAnthony.Scarpino@Sun.COM 	 * still be available.
2171694Sdarrenm 	 */
218*11751SAnthony.Scarpino@Sun.COM 	(void) crypto_register_provider(&sha1_prov_info, &sha1_prov_handle);
2191694Sdarrenm 
2201694Sdarrenm 	return (0);
2211694Sdarrenm }
2221694Sdarrenm 
2231694Sdarrenm int
_info(struct modinfo * modinfop)2241694Sdarrenm _info(struct modinfo *modinfop)
2251694Sdarrenm {
2261694Sdarrenm 	return (mod_info(&modlinkage, modinfop));
2271694Sdarrenm }
2281694Sdarrenm 
2291694Sdarrenm /*
2301694Sdarrenm  * KCF software provider control entry points.
2311694Sdarrenm  */
2321694Sdarrenm /* ARGSUSED */
2331694Sdarrenm static void
sha1_provider_status(crypto_provider_handle_t provider,uint_t * status)2341694Sdarrenm sha1_provider_status(crypto_provider_handle_t provider, uint_t *status)
2351694Sdarrenm {
2361694Sdarrenm 	*status = CRYPTO_PROVIDER_READY;
2371694Sdarrenm }
2381694Sdarrenm 
2391694Sdarrenm /*
2401694Sdarrenm  * KCF software provider digest entry points.
2411694Sdarrenm  */
2421694Sdarrenm 
2431694Sdarrenm static int
sha1_digest_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_req_handle_t req)2441694Sdarrenm sha1_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
2451694Sdarrenm     crypto_req_handle_t req)
2461694Sdarrenm {
2471694Sdarrenm 	if (mechanism->cm_type != SHA1_MECH_INFO_TYPE)
2481694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
2491694Sdarrenm 
2501694Sdarrenm 	/*
2511694Sdarrenm 	 * Allocate and initialize SHA1 context.
2521694Sdarrenm 	 */
2531694Sdarrenm 	ctx->cc_provider_private = kmem_alloc(sizeof (sha1_ctx_t),
2541694Sdarrenm 	    crypto_kmflag(req));
2551694Sdarrenm 	if (ctx->cc_provider_private == NULL)
2561694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
2571694Sdarrenm 
2581694Sdarrenm 	PROV_SHA1_CTX(ctx)->sc_mech_type = SHA1_MECH_INFO_TYPE;
2591694Sdarrenm 	SHA1Init(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
2601694Sdarrenm 
2611694Sdarrenm 	return (CRYPTO_SUCCESS);
2621694Sdarrenm }
2631694Sdarrenm 
2641694Sdarrenm /*
2651694Sdarrenm  * Helper SHA1 digest update function for uio data.
2661694Sdarrenm  */
2671694Sdarrenm static int
sha1_digest_update_uio(SHA1_CTX * sha1_ctx,crypto_data_t * data)2681694Sdarrenm sha1_digest_update_uio(SHA1_CTX *sha1_ctx, crypto_data_t *data)
2691694Sdarrenm {
2701694Sdarrenm 	off_t offset = data->cd_offset;
2711694Sdarrenm 	size_t length = data->cd_length;
2721694Sdarrenm 	uint_t vec_idx;
2731694Sdarrenm 	size_t cur_len;
2741694Sdarrenm 
2751694Sdarrenm 	/* we support only kernel buffer */
2761694Sdarrenm 	if (data->cd_uio->uio_segflg != UIO_SYSSPACE)
2771694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
2781694Sdarrenm 
2791694Sdarrenm 	/*
2801694Sdarrenm 	 * Jump to the first iovec containing data to be
2811694Sdarrenm 	 * digested.
2821694Sdarrenm 	 */
2831694Sdarrenm 	for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt &&
2841694Sdarrenm 	    offset >= data->cd_uio->uio_iov[vec_idx].iov_len;
2859364SVladimir.Kotal@Sun.COM 	    offset -= data->cd_uio->uio_iov[vec_idx++].iov_len)
2869364SVladimir.Kotal@Sun.COM 		;
2871694Sdarrenm 	if (vec_idx == data->cd_uio->uio_iovcnt) {
2881694Sdarrenm 		/*
2891694Sdarrenm 		 * The caller specified an offset that is larger than the
2901694Sdarrenm 		 * total size of the buffers it provided.
2911694Sdarrenm 		 */
2921694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
2931694Sdarrenm 	}
2941694Sdarrenm 
2951694Sdarrenm 	/*
2961694Sdarrenm 	 * Now do the digesting on the iovecs.
2971694Sdarrenm 	 */
2981694Sdarrenm 	while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) {
2991694Sdarrenm 		cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len -
3001694Sdarrenm 		    offset, length);
3011694Sdarrenm 
3021694Sdarrenm 		SHA1Update(sha1_ctx,
3031694Sdarrenm 		    (uint8_t *)data->cd_uio->uio_iov[vec_idx].iov_base + offset,
3041694Sdarrenm 		    cur_len);
3051694Sdarrenm 
3061694Sdarrenm 		length -= cur_len;
3071694Sdarrenm 		vec_idx++;
3081694Sdarrenm 		offset = 0;
3091694Sdarrenm 	}
3101694Sdarrenm 
3111694Sdarrenm 	if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) {
3121694Sdarrenm 		/*
3131694Sdarrenm 		 * The end of the specified iovec's was reached but
3141694Sdarrenm 		 * the length requested could not be processed, i.e.
3151694Sdarrenm 		 * The caller requested to digest more data than it provided.
3161694Sdarrenm 		 */
3171694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
3181694Sdarrenm 	}
3191694Sdarrenm 
3201694Sdarrenm 	return (CRYPTO_SUCCESS);
3211694Sdarrenm }
3221694Sdarrenm 
3231694Sdarrenm /*
3241694Sdarrenm  * Helper SHA1 digest final function for uio data.
3251694Sdarrenm  * digest_len is the length of the desired digest. If digest_len
3261694Sdarrenm  * is smaller than the default SHA1 digest length, the caller
3271694Sdarrenm  * must pass a scratch buffer, digest_scratch, which must
3281694Sdarrenm  * be at least SHA1_DIGEST_LENGTH bytes.
3291694Sdarrenm  */
3301694Sdarrenm static int
sha1_digest_final_uio(SHA1_CTX * sha1_ctx,crypto_data_t * digest,ulong_t digest_len,uchar_t * digest_scratch)3311694Sdarrenm sha1_digest_final_uio(SHA1_CTX *sha1_ctx, crypto_data_t *digest,
3321694Sdarrenm     ulong_t digest_len, uchar_t *digest_scratch)
3331694Sdarrenm {
3341694Sdarrenm 	off_t offset = digest->cd_offset;
3351694Sdarrenm 	uint_t vec_idx;
3361694Sdarrenm 
3371694Sdarrenm 	/* we support only kernel buffer */
3381694Sdarrenm 	if (digest->cd_uio->uio_segflg != UIO_SYSSPACE)
3391694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
3401694Sdarrenm 
3411694Sdarrenm 	/*
3421694Sdarrenm 	 * Jump to the first iovec containing ptr to the digest to
3431694Sdarrenm 	 * be returned.
3441694Sdarrenm 	 */
3451694Sdarrenm 	for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len &&
3461694Sdarrenm 	    vec_idx < digest->cd_uio->uio_iovcnt;
3479364SVladimir.Kotal@Sun.COM 	    offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len)
3489364SVladimir.Kotal@Sun.COM 		;
3491694Sdarrenm 	if (vec_idx == digest->cd_uio->uio_iovcnt) {
3501694Sdarrenm 		/*
3511694Sdarrenm 		 * The caller specified an offset that is
3521694Sdarrenm 		 * larger than the total size of the buffers
3531694Sdarrenm 		 * it provided.
3541694Sdarrenm 		 */
3551694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
3561694Sdarrenm 	}
3571694Sdarrenm 
3581694Sdarrenm 	if (offset + digest_len <=
3591694Sdarrenm 	    digest->cd_uio->uio_iov[vec_idx].iov_len) {
3601694Sdarrenm 		/*
3611694Sdarrenm 		 * The computed SHA1 digest will fit in the current
3621694Sdarrenm 		 * iovec.
3631694Sdarrenm 		 */
3641694Sdarrenm 		if (digest_len != SHA1_DIGEST_LENGTH) {
3651694Sdarrenm 			/*
3661694Sdarrenm 			 * The caller requested a short digest. Digest
3671694Sdarrenm 			 * into a scratch buffer and return to
3681694Sdarrenm 			 * the user only what was requested.
3691694Sdarrenm 			 */
3701694Sdarrenm 			SHA1Final(digest_scratch, sha1_ctx);
3711694Sdarrenm 			bcopy(digest_scratch, (uchar_t *)digest->
3721694Sdarrenm 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
3731694Sdarrenm 			    digest_len);
3741694Sdarrenm 		} else {
3751694Sdarrenm 			SHA1Final((uchar_t *)digest->
3761694Sdarrenm 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
3771694Sdarrenm 			    sha1_ctx);
3781694Sdarrenm 		}
3791694Sdarrenm 	} else {
3801694Sdarrenm 		/*
3811694Sdarrenm 		 * The computed digest will be crossing one or more iovec's.
3821694Sdarrenm 		 * This is bad performance-wise but we need to support it.
3831694Sdarrenm 		 * Allocate a small scratch buffer on the stack and
3841694Sdarrenm 		 * copy it piece meal to the specified digest iovec's.
3851694Sdarrenm 		 */
3861694Sdarrenm 		uchar_t digest_tmp[SHA1_DIGEST_LENGTH];
3871694Sdarrenm 		off_t scratch_offset = 0;
3881694Sdarrenm 		size_t length = digest_len;
3891694Sdarrenm 		size_t cur_len;
3901694Sdarrenm 
3911694Sdarrenm 		SHA1Final(digest_tmp, sha1_ctx);
3921694Sdarrenm 
3931694Sdarrenm 		while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
3941694Sdarrenm 			cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
3951694Sdarrenm 			    offset, length);
3961694Sdarrenm 			bcopy(digest_tmp + scratch_offset,
3971694Sdarrenm 			    digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
3981694Sdarrenm 			    cur_len);
3991694Sdarrenm 
4001694Sdarrenm 			length -= cur_len;
4011694Sdarrenm 			vec_idx++;
4021694Sdarrenm 			scratch_offset += cur_len;
4031694Sdarrenm 			offset = 0;
4041694Sdarrenm 		}
4051694Sdarrenm 
4061694Sdarrenm 		if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
4071694Sdarrenm 			/*
4081694Sdarrenm 			 * The end of the specified iovec's was reached but
4091694Sdarrenm 			 * the length requested could not be processed, i.e.
4101694Sdarrenm 			 * The caller requested to digest more data than it
4111694Sdarrenm 			 * provided.
4121694Sdarrenm 			 */
4131694Sdarrenm 			return (CRYPTO_DATA_LEN_RANGE);
4141694Sdarrenm 		}
4151694Sdarrenm 	}
4161694Sdarrenm 
4171694Sdarrenm 	return (CRYPTO_SUCCESS);
4181694Sdarrenm }
4191694Sdarrenm 
4201694Sdarrenm /*
4211694Sdarrenm  * Helper SHA1 digest update for mblk's.
4221694Sdarrenm  */
4231694Sdarrenm static int
sha1_digest_update_mblk(SHA1_CTX * sha1_ctx,crypto_data_t * data)4241694Sdarrenm sha1_digest_update_mblk(SHA1_CTX *sha1_ctx, crypto_data_t *data)
4251694Sdarrenm {
4261694Sdarrenm 	off_t offset = data->cd_offset;
4271694Sdarrenm 	size_t length = data->cd_length;
4281694Sdarrenm 	mblk_t *mp;
4291694Sdarrenm 	size_t cur_len;
4301694Sdarrenm 
4311694Sdarrenm 	/*
4321694Sdarrenm 	 * Jump to the first mblk_t containing data to be digested.
4331694Sdarrenm 	 */
4341694Sdarrenm 	for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
4359364SVladimir.Kotal@Sun.COM 	    offset -= MBLKL(mp), mp = mp->b_cont)
4369364SVladimir.Kotal@Sun.COM 		;
4371694Sdarrenm 	if (mp == NULL) {
4381694Sdarrenm 		/*
4391694Sdarrenm 		 * The caller specified an offset that is larger than the
4401694Sdarrenm 		 * total size of the buffers it provided.
4411694Sdarrenm 		 */
4421694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
4431694Sdarrenm 	}
4441694Sdarrenm 
4451694Sdarrenm 	/*
4461694Sdarrenm 	 * Now do the digesting on the mblk chain.
4471694Sdarrenm 	 */
4481694Sdarrenm 	while (mp != NULL && length > 0) {
4491694Sdarrenm 		cur_len = MIN(MBLKL(mp) - offset, length);
4501694Sdarrenm 		SHA1Update(sha1_ctx, mp->b_rptr + offset, cur_len);
4511694Sdarrenm 		length -= cur_len;
4521694Sdarrenm 		offset = 0;
4531694Sdarrenm 		mp = mp->b_cont;
4541694Sdarrenm 	}
4551694Sdarrenm 
4561694Sdarrenm 	if (mp == NULL && length > 0) {
4571694Sdarrenm 		/*
4581694Sdarrenm 		 * The end of the mblk was reached but the length requested
4591694Sdarrenm 		 * could not be processed, i.e. The caller requested
4601694Sdarrenm 		 * to digest more data than it provided.
4611694Sdarrenm 		 */
4621694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
4631694Sdarrenm 	}
4641694Sdarrenm 
4651694Sdarrenm 	return (CRYPTO_SUCCESS);
4661694Sdarrenm }
4671694Sdarrenm 
4681694Sdarrenm /*
4691694Sdarrenm  * Helper SHA1 digest final for mblk's.
4701694Sdarrenm  * digest_len is the length of the desired digest. If digest_len
4711694Sdarrenm  * is smaller than the default SHA1 digest length, the caller
4721694Sdarrenm  * must pass a scratch buffer, digest_scratch, which must
4731694Sdarrenm  * be at least SHA1_DIGEST_LENGTH bytes.
4741694Sdarrenm  */
4751694Sdarrenm static int
sha1_digest_final_mblk(SHA1_CTX * sha1_ctx,crypto_data_t * digest,ulong_t digest_len,uchar_t * digest_scratch)4761694Sdarrenm sha1_digest_final_mblk(SHA1_CTX *sha1_ctx, crypto_data_t *digest,
4771694Sdarrenm     ulong_t digest_len, uchar_t *digest_scratch)
4781694Sdarrenm {
4791694Sdarrenm 	off_t offset = digest->cd_offset;
4801694Sdarrenm 	mblk_t *mp;
4811694Sdarrenm 
4821694Sdarrenm 	/*
4831694Sdarrenm 	 * Jump to the first mblk_t that will be used to store the digest.
4841694Sdarrenm 	 */
4851694Sdarrenm 	for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp);
4869364SVladimir.Kotal@Sun.COM 	    offset -= MBLKL(mp), mp = mp->b_cont)
4879364SVladimir.Kotal@Sun.COM 		;
4881694Sdarrenm 	if (mp == NULL) {
4891694Sdarrenm 		/*
4901694Sdarrenm 		 * The caller specified an offset that is larger than the
4911694Sdarrenm 		 * total size of the buffers it provided.
4921694Sdarrenm 		 */
4931694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
4941694Sdarrenm 	}
4951694Sdarrenm 
4961694Sdarrenm 	if (offset + digest_len <= MBLKL(mp)) {
4971694Sdarrenm 		/*
4981694Sdarrenm 		 * The computed SHA1 digest will fit in the current mblk.
4991694Sdarrenm 		 * Do the SHA1Final() in-place.
5001694Sdarrenm 		 */
5011694Sdarrenm 		if (digest_len != SHA1_DIGEST_LENGTH) {
5021694Sdarrenm 			/*
5031694Sdarrenm 			 * The caller requested a short digest. Digest
5041694Sdarrenm 			 * into a scratch buffer and return to
5051694Sdarrenm 			 * the user only what was requested.
5061694Sdarrenm 			 */
5071694Sdarrenm 			SHA1Final(digest_scratch, sha1_ctx);
5081694Sdarrenm 			bcopy(digest_scratch, mp->b_rptr + offset, digest_len);
5091694Sdarrenm 		} else {
5101694Sdarrenm 			SHA1Final(mp->b_rptr + offset, sha1_ctx);
5111694Sdarrenm 		}
5121694Sdarrenm 	} else {
5131694Sdarrenm 		/*
5141694Sdarrenm 		 * The computed digest will be crossing one or more mblk's.
5151694Sdarrenm 		 * This is bad performance-wise but we need to support it.
5161694Sdarrenm 		 * Allocate a small scratch buffer on the stack and
5171694Sdarrenm 		 * copy it piece meal to the specified digest iovec's.
5181694Sdarrenm 		 */
5191694Sdarrenm 		uchar_t digest_tmp[SHA1_DIGEST_LENGTH];
5201694Sdarrenm 		off_t scratch_offset = 0;
5211694Sdarrenm 		size_t length = digest_len;
5221694Sdarrenm 		size_t cur_len;
5231694Sdarrenm 
5241694Sdarrenm 		SHA1Final(digest_tmp, sha1_ctx);
5251694Sdarrenm 
5261694Sdarrenm 		while (mp != NULL && length > 0) {
5271694Sdarrenm 			cur_len = MIN(MBLKL(mp) - offset, length);
5281694Sdarrenm 			bcopy(digest_tmp + scratch_offset,
5291694Sdarrenm 			    mp->b_rptr + offset, cur_len);
5301694Sdarrenm 
5311694Sdarrenm 			length -= cur_len;
5321694Sdarrenm 			mp = mp->b_cont;
5331694Sdarrenm 			scratch_offset += cur_len;
5341694Sdarrenm 			offset = 0;
5351694Sdarrenm 		}
5361694Sdarrenm 
5371694Sdarrenm 		if (mp == NULL && length > 0) {
5381694Sdarrenm 			/*
5391694Sdarrenm 			 * The end of the specified mblk was reached but
5401694Sdarrenm 			 * the length requested could not be processed, i.e.
5411694Sdarrenm 			 * The caller requested to digest more data than it
5421694Sdarrenm 			 * provided.
5431694Sdarrenm 			 */
5441694Sdarrenm 			return (CRYPTO_DATA_LEN_RANGE);
5451694Sdarrenm 		}
5461694Sdarrenm 	}
5471694Sdarrenm 
5481694Sdarrenm 	return (CRYPTO_SUCCESS);
5491694Sdarrenm }
5501694Sdarrenm 
5511694Sdarrenm /* ARGSUSED */
5521694Sdarrenm static int
sha1_digest(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * digest,crypto_req_handle_t req)5531694Sdarrenm sha1_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
5541694Sdarrenm     crypto_req_handle_t req)
5551694Sdarrenm {
5561694Sdarrenm 	int ret = CRYPTO_SUCCESS;
5571694Sdarrenm 
5581694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
5591694Sdarrenm 
5601694Sdarrenm 	/*
5611694Sdarrenm 	 * We need to just return the length needed to store the output.
5621694Sdarrenm 	 * We should not destroy the context for the following cases.
5631694Sdarrenm 	 */
5641694Sdarrenm 	if ((digest->cd_length == 0) ||
5651694Sdarrenm 	    (digest->cd_length < SHA1_DIGEST_LENGTH)) {
5661694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
5671694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
5681694Sdarrenm 	}
5691694Sdarrenm 
5701694Sdarrenm 	/*
5711694Sdarrenm 	 * Do the SHA1 update on the specified input data.
5721694Sdarrenm 	 */
5731694Sdarrenm 	switch (data->cd_format) {
5741694Sdarrenm 	case CRYPTO_DATA_RAW:
5751694Sdarrenm 		SHA1Update(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
5761694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
5771694Sdarrenm 		    data->cd_length);
5781694Sdarrenm 		break;
5791694Sdarrenm 	case CRYPTO_DATA_UIO:
5801694Sdarrenm 		ret = sha1_digest_update_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
5811694Sdarrenm 		    data);
5821694Sdarrenm 		break;
5831694Sdarrenm 	case CRYPTO_DATA_MBLK:
5841694Sdarrenm 		ret = sha1_digest_update_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
5851694Sdarrenm 		    data);
5861694Sdarrenm 		break;
5871694Sdarrenm 	default:
5881694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
5891694Sdarrenm 	}
5901694Sdarrenm 
5911694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
5921694Sdarrenm 		/* the update failed, free context and bail */
5931694Sdarrenm 		kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
5941694Sdarrenm 		ctx->cc_provider_private = NULL;
5951694Sdarrenm 		digest->cd_length = 0;
5961694Sdarrenm 		return (ret);
5971694Sdarrenm 	}
5981694Sdarrenm 
5991694Sdarrenm 	/*
6001694Sdarrenm 	 * Do a SHA1 final, must be done separately since the digest
6011694Sdarrenm 	 * type can be different than the input data type.
6021694Sdarrenm 	 */
6031694Sdarrenm 	switch (digest->cd_format) {
6041694Sdarrenm 	case CRYPTO_DATA_RAW:
6051694Sdarrenm 		SHA1Final((unsigned char *)digest->cd_raw.iov_base +
6061694Sdarrenm 		    digest->cd_offset, &PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
6071694Sdarrenm 		break;
6081694Sdarrenm 	case CRYPTO_DATA_UIO:
6091694Sdarrenm 		ret = sha1_digest_final_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
6101694Sdarrenm 		    digest, SHA1_DIGEST_LENGTH, NULL);
6111694Sdarrenm 		break;
6121694Sdarrenm 	case CRYPTO_DATA_MBLK:
6131694Sdarrenm 		ret = sha1_digest_final_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
6141694Sdarrenm 		    digest, SHA1_DIGEST_LENGTH, NULL);
6151694Sdarrenm 		break;
6161694Sdarrenm 	default:
6171694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
6181694Sdarrenm 	}
6191694Sdarrenm 
6201694Sdarrenm 	/* all done, free context and return */
6211694Sdarrenm 
6221694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
6231694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
6241694Sdarrenm 	} else {
6251694Sdarrenm 		digest->cd_length = 0;
6261694Sdarrenm 	}
6271694Sdarrenm 
6281694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
6291694Sdarrenm 	ctx->cc_provider_private = NULL;
6301694Sdarrenm 	return (ret);
6311694Sdarrenm }
6321694Sdarrenm 
6331694Sdarrenm /* ARGSUSED */
6341694Sdarrenm static int
sha1_digest_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)6351694Sdarrenm sha1_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
6361694Sdarrenm     crypto_req_handle_t req)
6371694Sdarrenm {
6381694Sdarrenm 	int ret = CRYPTO_SUCCESS;
6391694Sdarrenm 
6401694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
6411694Sdarrenm 
6421694Sdarrenm 	/*
6431694Sdarrenm 	 * Do the SHA1 update on the specified input data.
6441694Sdarrenm 	 */
6451694Sdarrenm 	switch (data->cd_format) {
6461694Sdarrenm 	case CRYPTO_DATA_RAW:
6471694Sdarrenm 		SHA1Update(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
6481694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
6491694Sdarrenm 		    data->cd_length);
6501694Sdarrenm 		break;
6511694Sdarrenm 	case CRYPTO_DATA_UIO:
6521694Sdarrenm 		ret = sha1_digest_update_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
6531694Sdarrenm 		    data);
6541694Sdarrenm 		break;
6551694Sdarrenm 	case CRYPTO_DATA_MBLK:
6561694Sdarrenm 		ret = sha1_digest_update_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
6571694Sdarrenm 		    data);
6581694Sdarrenm 		break;
6591694Sdarrenm 	default:
6601694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
6611694Sdarrenm 	}
6621694Sdarrenm 
6631694Sdarrenm 	return (ret);
6641694Sdarrenm }
6651694Sdarrenm 
6661694Sdarrenm /* ARGSUSED */
6671694Sdarrenm static int
sha1_digest_final(crypto_ctx_t * ctx,crypto_data_t * digest,crypto_req_handle_t req)6681694Sdarrenm sha1_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
6691694Sdarrenm     crypto_req_handle_t req)
6701694Sdarrenm {
6711694Sdarrenm 	int ret = CRYPTO_SUCCESS;
6721694Sdarrenm 
6731694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
6741694Sdarrenm 
6751694Sdarrenm 	/*
6761694Sdarrenm 	 * We need to just return the length needed to store the output.
6771694Sdarrenm 	 * We should not destroy the context for the following cases.
6781694Sdarrenm 	 */
6791694Sdarrenm 	if ((digest->cd_length == 0) ||
6801694Sdarrenm 	    (digest->cd_length < SHA1_DIGEST_LENGTH)) {
6811694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
6821694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
6831694Sdarrenm 	}
6841694Sdarrenm 
6851694Sdarrenm 	/*
6861694Sdarrenm 	 * Do a SHA1 final.
6871694Sdarrenm 	 */
6881694Sdarrenm 	switch (digest->cd_format) {
6891694Sdarrenm 	case CRYPTO_DATA_RAW:
6901694Sdarrenm 		SHA1Final((unsigned char *)digest->cd_raw.iov_base +
6911694Sdarrenm 		    digest->cd_offset, &PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
6921694Sdarrenm 		break;
6931694Sdarrenm 	case CRYPTO_DATA_UIO:
6941694Sdarrenm 		ret = sha1_digest_final_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
6951694Sdarrenm 		    digest, SHA1_DIGEST_LENGTH, NULL);
6961694Sdarrenm 		break;
6971694Sdarrenm 	case CRYPTO_DATA_MBLK:
6981694Sdarrenm 		ret = sha1_digest_final_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
6991694Sdarrenm 		    digest, SHA1_DIGEST_LENGTH, NULL);
7001694Sdarrenm 		break;
7011694Sdarrenm 	default:
7021694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
7031694Sdarrenm 	}
7041694Sdarrenm 
7051694Sdarrenm 	/* all done, free context and return */
7061694Sdarrenm 
7071694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
7081694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
7091694Sdarrenm 	} else {
7101694Sdarrenm 		digest->cd_length = 0;
7111694Sdarrenm 	}
7121694Sdarrenm 
7131694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
7141694Sdarrenm 	ctx->cc_provider_private = NULL;
7151694Sdarrenm 
7161694Sdarrenm 	return (ret);
7171694Sdarrenm }
7181694Sdarrenm 
7191694Sdarrenm /* ARGSUSED */
7201694Sdarrenm static int
sha1_digest_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_data_t * data,crypto_data_t * digest,crypto_req_handle_t req)7211694Sdarrenm sha1_digest_atomic(crypto_provider_handle_t provider,
7221694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
7231694Sdarrenm     crypto_data_t *data, crypto_data_t *digest,
7241694Sdarrenm     crypto_req_handle_t req)
7251694Sdarrenm {
7261694Sdarrenm 	int ret = CRYPTO_SUCCESS;
7271694Sdarrenm 	SHA1_CTX sha1_ctx;
7281694Sdarrenm 
7291694Sdarrenm 	if (mechanism->cm_type != SHA1_MECH_INFO_TYPE)
7301694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
7311694Sdarrenm 
7321694Sdarrenm 	/*
7331694Sdarrenm 	 * Do the SHA1 init.
7341694Sdarrenm 	 */
7351694Sdarrenm 	SHA1Init(&sha1_ctx);
7361694Sdarrenm 
7371694Sdarrenm 	/*
7381694Sdarrenm 	 * Do the SHA1 update on the specified input data.
7391694Sdarrenm 	 */
7401694Sdarrenm 	switch (data->cd_format) {
7411694Sdarrenm 	case CRYPTO_DATA_RAW:
7421694Sdarrenm 		SHA1Update(&sha1_ctx,
7431694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
7441694Sdarrenm 		    data->cd_length);
7451694Sdarrenm 		break;
7461694Sdarrenm 	case CRYPTO_DATA_UIO:
7471694Sdarrenm 		ret = sha1_digest_update_uio(&sha1_ctx, data);
7481694Sdarrenm 		break;
7491694Sdarrenm 	case CRYPTO_DATA_MBLK:
7501694Sdarrenm 		ret = sha1_digest_update_mblk(&sha1_ctx, data);
7511694Sdarrenm 		break;
7521694Sdarrenm 	default:
7531694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
7541694Sdarrenm 	}
7551694Sdarrenm 
7561694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
7571694Sdarrenm 		/* the update failed, bail */
7581694Sdarrenm 		digest->cd_length = 0;
7591694Sdarrenm 		return (ret);
7601694Sdarrenm 	}
7611694Sdarrenm 
7621694Sdarrenm 	/*
7631694Sdarrenm 	 * Do a SHA1 final, must be done separately since the digest
7641694Sdarrenm 	 * type can be different than the input data type.
7651694Sdarrenm 	 */
7661694Sdarrenm 	switch (digest->cd_format) {
7671694Sdarrenm 	case CRYPTO_DATA_RAW:
7681694Sdarrenm 		SHA1Final((unsigned char *)digest->cd_raw.iov_base +
7691694Sdarrenm 		    digest->cd_offset, &sha1_ctx);
7701694Sdarrenm 		break;
7711694Sdarrenm 	case CRYPTO_DATA_UIO:
7721694Sdarrenm 		ret = sha1_digest_final_uio(&sha1_ctx, digest,
7731694Sdarrenm 		    SHA1_DIGEST_LENGTH, NULL);
7741694Sdarrenm 		break;
7751694Sdarrenm 	case CRYPTO_DATA_MBLK:
7761694Sdarrenm 		ret = sha1_digest_final_mblk(&sha1_ctx, digest,
7771694Sdarrenm 		    SHA1_DIGEST_LENGTH, NULL);
7781694Sdarrenm 		break;
7791694Sdarrenm 	default:
7801694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
7811694Sdarrenm 	}
7821694Sdarrenm 
7831694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
7841694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
7851694Sdarrenm 	} else {
7861694Sdarrenm 		digest->cd_length = 0;
7871694Sdarrenm 	}
7881694Sdarrenm 
7891694Sdarrenm 	return (ret);
7901694Sdarrenm }
7911694Sdarrenm 
7921694Sdarrenm /*
7931694Sdarrenm  * KCF software provider mac entry points.
7941694Sdarrenm  *
7951694Sdarrenm  * SHA1 HMAC is: SHA1(key XOR opad, SHA1(key XOR ipad, text))
7961694Sdarrenm  *
7971694Sdarrenm  * Init:
7981694Sdarrenm  * The initialization routine initializes what we denote
7991694Sdarrenm  * as the inner and outer contexts by doing
8001694Sdarrenm  * - for inner context: SHA1(key XOR ipad)
8011694Sdarrenm  * - for outer context: SHA1(key XOR opad)
8021694Sdarrenm  *
8031694Sdarrenm  * Update:
8041694Sdarrenm  * Each subsequent SHA1 HMAC update will result in an
8051694Sdarrenm  * update of the inner context with the specified data.
8061694Sdarrenm  *
8071694Sdarrenm  * Final:
8081694Sdarrenm  * The SHA1 HMAC final will do a SHA1 final operation on the
8091694Sdarrenm  * inner context, and the resulting digest will be used
8101694Sdarrenm  * as the data for an update on the outer context. Last
8111694Sdarrenm  * but not least, a SHA1 final on the outer context will
8121694Sdarrenm  * be performed to obtain the SHA1 HMAC digest to return
8131694Sdarrenm  * to the user.
8141694Sdarrenm  */
8151694Sdarrenm 
8161694Sdarrenm /*
8171694Sdarrenm  * Initialize a SHA1-HMAC context.
8181694Sdarrenm  */
8191694Sdarrenm static void
sha1_mac_init_ctx(sha1_hmac_ctx_t * ctx,void * keyval,uint_t length_in_bytes)8201694Sdarrenm sha1_mac_init_ctx(sha1_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
8211694Sdarrenm {
8221694Sdarrenm 	uint32_t ipad[SHA1_HMAC_INTS_PER_BLOCK];
8231694Sdarrenm 	uint32_t opad[SHA1_HMAC_INTS_PER_BLOCK];
8241694Sdarrenm 	uint_t i;
8251694Sdarrenm 
8261694Sdarrenm 	bzero(ipad, SHA1_HMAC_BLOCK_SIZE);
8271694Sdarrenm 	bzero(opad, SHA1_HMAC_BLOCK_SIZE);
8281694Sdarrenm 
8291694Sdarrenm 	bcopy(keyval, ipad, length_in_bytes);
8301694Sdarrenm 	bcopy(keyval, opad, length_in_bytes);
8311694Sdarrenm 
8321694Sdarrenm 	/* XOR key with ipad (0x36) and opad (0x5c) */
8331694Sdarrenm 	for (i = 0; i < SHA1_HMAC_INTS_PER_BLOCK; i++) {
8341694Sdarrenm 		ipad[i] ^= 0x36363636;
8351694Sdarrenm 		opad[i] ^= 0x5c5c5c5c;
8361694Sdarrenm 	}
8371694Sdarrenm 
8381694Sdarrenm 	/* perform SHA1 on ipad */
8391694Sdarrenm 	SHA1Init(&ctx->hc_icontext);
8401694Sdarrenm 	SHA1Update(&ctx->hc_icontext, (uint8_t *)ipad, SHA1_HMAC_BLOCK_SIZE);
8411694Sdarrenm 
8421694Sdarrenm 	/* perform SHA1 on opad */
8431694Sdarrenm 	SHA1Init(&ctx->hc_ocontext);
8441694Sdarrenm 	SHA1Update(&ctx->hc_ocontext, (uint8_t *)opad, SHA1_HMAC_BLOCK_SIZE);
8451694Sdarrenm }
8461694Sdarrenm 
8471694Sdarrenm /*
8481694Sdarrenm  */
8491694Sdarrenm static int
sha1_mac_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)8501694Sdarrenm sha1_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
8511694Sdarrenm     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
8521694Sdarrenm     crypto_req_handle_t req)
8531694Sdarrenm {
8541694Sdarrenm 	int ret = CRYPTO_SUCCESS;
8551694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
8561694Sdarrenm 
8571694Sdarrenm 	if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
8581694Sdarrenm 	    mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
8591694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
8601694Sdarrenm 
8611694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
8621694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
8631694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
8641694Sdarrenm 
8651694Sdarrenm 	ctx->cc_provider_private = kmem_alloc(sizeof (sha1_hmac_ctx_t),
8661694Sdarrenm 	    crypto_kmflag(req));
8671694Sdarrenm 	if (ctx->cc_provider_private == NULL)
8681694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
8691694Sdarrenm 
8701694Sdarrenm 	if (ctx_template != NULL) {
8711694Sdarrenm 		/* reuse context template */
8721694Sdarrenm 		bcopy(ctx_template, PROV_SHA1_HMAC_CTX(ctx),
8731694Sdarrenm 		    sizeof (sha1_hmac_ctx_t));
8741694Sdarrenm 	} else {
8751694Sdarrenm 		/* no context template, compute context */
8761694Sdarrenm 		if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
8771694Sdarrenm 			uchar_t digested_key[SHA1_DIGEST_LENGTH];
8781694Sdarrenm 			sha1_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;
8791694Sdarrenm 
8801694Sdarrenm 			/*
8811694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
8821694Sdarrenm 			 * The inner context is used since it hasn't been
8831694Sdarrenm 			 * initialized yet.
8841694Sdarrenm 			 */
8851694Sdarrenm 			PROV_SHA1_DIGEST_KEY(&hmac_ctx->hc_icontext,
8861694Sdarrenm 			    key->ck_data, keylen_in_bytes, digested_key);
8871694Sdarrenm 			sha1_mac_init_ctx(PROV_SHA1_HMAC_CTX(ctx),
8881694Sdarrenm 			    digested_key, SHA1_DIGEST_LENGTH);
8891694Sdarrenm 		} else {
8901694Sdarrenm 			sha1_mac_init_ctx(PROV_SHA1_HMAC_CTX(ctx),
8911694Sdarrenm 			    key->ck_data, keylen_in_bytes);
8921694Sdarrenm 		}
8931694Sdarrenm 	}
8941694Sdarrenm 
8951694Sdarrenm 	/*
8961694Sdarrenm 	 * Get the mechanism parameters, if applicable.
8971694Sdarrenm 	 */
8981694Sdarrenm 	PROV_SHA1_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;
8991694Sdarrenm 	if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
9001694Sdarrenm 		if (mechanism->cm_param == NULL ||
9011694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t))
9021694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
9031694Sdarrenm 		PROV_SHA1_GET_DIGEST_LEN(mechanism,
9041694Sdarrenm 		    PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len);
9051694Sdarrenm 		if (PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len >
9061694Sdarrenm 		    SHA1_DIGEST_LENGTH)
9071694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
9081694Sdarrenm 	}
9091694Sdarrenm 
9101694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
9111694Sdarrenm 		bzero(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
9121694Sdarrenm 		kmem_free(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
9131694Sdarrenm 		ctx->cc_provider_private = NULL;
9141694Sdarrenm 	}
9151694Sdarrenm 
9161694Sdarrenm 	return (ret);
9171694Sdarrenm }
9181694Sdarrenm 
9191694Sdarrenm /* ARGSUSED */
9201694Sdarrenm static int
sha1_mac_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)9211694Sdarrenm sha1_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
9221694Sdarrenm {
9231694Sdarrenm 	int ret = CRYPTO_SUCCESS;
9241694Sdarrenm 
9251694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
9261694Sdarrenm 
9271694Sdarrenm 	/*
9281694Sdarrenm 	 * Do a SHA1 update of the inner context using the specified
9291694Sdarrenm 	 * data.
9301694Sdarrenm 	 */
9311694Sdarrenm 	switch (data->cd_format) {
9321694Sdarrenm 	case CRYPTO_DATA_RAW:
9331694Sdarrenm 		SHA1Update(&PROV_SHA1_HMAC_CTX(ctx)->hc_icontext,
9341694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
9351694Sdarrenm 		    data->cd_length);
9361694Sdarrenm 		break;
9371694Sdarrenm 	case CRYPTO_DATA_UIO:
9381694Sdarrenm 		ret = sha1_digest_update_uio(
9391694Sdarrenm 		    &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext, data);
9401694Sdarrenm 		break;
9411694Sdarrenm 	case CRYPTO_DATA_MBLK:
9421694Sdarrenm 		ret = sha1_digest_update_mblk(
9431694Sdarrenm 		    &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext, data);
9441694Sdarrenm 		break;
9451694Sdarrenm 	default:
9461694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
9471694Sdarrenm 	}
9481694Sdarrenm 
9491694Sdarrenm 	return (ret);
9501694Sdarrenm }
9511694Sdarrenm 
9521694Sdarrenm /* ARGSUSED */
9531694Sdarrenm static int
sha1_mac_final(crypto_ctx_t * ctx,crypto_data_t * mac,crypto_req_handle_t req)9541694Sdarrenm sha1_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
9551694Sdarrenm {
9561694Sdarrenm 	int ret = CRYPTO_SUCCESS;
9571694Sdarrenm 	uchar_t digest[SHA1_DIGEST_LENGTH];
9581694Sdarrenm 	uint32_t digest_len = SHA1_DIGEST_LENGTH;
9591694Sdarrenm 
9601694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
9611694Sdarrenm 
9621694Sdarrenm 	if (PROV_SHA1_HMAC_CTX(ctx)->hc_mech_type ==
9631694Sdarrenm 	    SHA1_HMAC_GEN_MECH_INFO_TYPE)
9641694Sdarrenm 		digest_len = PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len;
9651694Sdarrenm 
9661694Sdarrenm 	/*
9671694Sdarrenm 	 * We need to just return the length needed to store the output.
9681694Sdarrenm 	 * We should not destroy the context for the following cases.
9691694Sdarrenm 	 */
9701694Sdarrenm 	if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {
9711694Sdarrenm 		mac->cd_length = digest_len;
9721694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
9731694Sdarrenm 	}
9741694Sdarrenm 
9751694Sdarrenm 	/*
9761694Sdarrenm 	 * Do a SHA1 final on the inner context.
9771694Sdarrenm 	 */
9781694Sdarrenm 	SHA1Final(digest, &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext);
9791694Sdarrenm 
9801694Sdarrenm 	/*
9811694Sdarrenm 	 * Do a SHA1 update on the outer context, feeding the inner
9821694Sdarrenm 	 * digest as data.
9831694Sdarrenm 	 */
9841694Sdarrenm 	SHA1Update(&PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, digest,
9851694Sdarrenm 	    SHA1_DIGEST_LENGTH);
9861694Sdarrenm 
9871694Sdarrenm 	/*
9881694Sdarrenm 	 * Do a SHA1 final on the outer context, storing the computing
9891694Sdarrenm 	 * digest in the users buffer.
9901694Sdarrenm 	 */
9911694Sdarrenm 	switch (mac->cd_format) {
9921694Sdarrenm 	case CRYPTO_DATA_RAW:
9931694Sdarrenm 		if (digest_len != SHA1_DIGEST_LENGTH) {
9941694Sdarrenm 			/*
9951694Sdarrenm 			 * The caller requested a short digest. Digest
9961694Sdarrenm 			 * into a scratch buffer and return to
9971694Sdarrenm 			 * the user only what was requested.
9981694Sdarrenm 			 */
9991694Sdarrenm 			SHA1Final(digest,
10001694Sdarrenm 			    &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext);
10011694Sdarrenm 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
10021694Sdarrenm 			    mac->cd_offset, digest_len);
10031694Sdarrenm 		} else {
10041694Sdarrenm 			SHA1Final((unsigned char *)mac->cd_raw.iov_base +
10051694Sdarrenm 			    mac->cd_offset,
10061694Sdarrenm 			    &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext);
10071694Sdarrenm 		}
10081694Sdarrenm 		break;
10091694Sdarrenm 	case CRYPTO_DATA_UIO:
10101694Sdarrenm 		ret = sha1_digest_final_uio(
10111694Sdarrenm 		    &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, mac,
10121694Sdarrenm 		    digest_len, digest);
10131694Sdarrenm 		break;
10141694Sdarrenm 	case CRYPTO_DATA_MBLK:
10151694Sdarrenm 		ret = sha1_digest_final_mblk(
10161694Sdarrenm 		    &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, mac,
10171694Sdarrenm 		    digest_len, digest);
10181694Sdarrenm 		break;
10191694Sdarrenm 	default:
10201694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
10211694Sdarrenm 	}
10221694Sdarrenm 
10231694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
10241694Sdarrenm 		mac->cd_length = digest_len;
10251694Sdarrenm 	} else {
10261694Sdarrenm 		mac->cd_length = 0;
10271694Sdarrenm 	}
10281694Sdarrenm 
10291694Sdarrenm 	bzero(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
10301694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
10311694Sdarrenm 	ctx->cc_provider_private = NULL;
10321694Sdarrenm 
10331694Sdarrenm 	return (ret);
10341694Sdarrenm }
10351694Sdarrenm 
10361694Sdarrenm #define	SHA1_MAC_UPDATE(data, ctx, ret) {				\
10371694Sdarrenm 	switch (data->cd_format) {					\
10381694Sdarrenm 	case CRYPTO_DATA_RAW:						\
10391694Sdarrenm 		SHA1Update(&(ctx).hc_icontext,				\
10401694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base +			\
10411694Sdarrenm 		    data->cd_offset, data->cd_length);			\
10421694Sdarrenm 		break;							\
10431694Sdarrenm 	case CRYPTO_DATA_UIO:						\
10441694Sdarrenm 		ret = sha1_digest_update_uio(&(ctx).hc_icontext, data); \
10451694Sdarrenm 		break;							\
10461694Sdarrenm 	case CRYPTO_DATA_MBLK:						\
10471694Sdarrenm 		ret = sha1_digest_update_mblk(&(ctx).hc_icontext,	\
10481694Sdarrenm 		    data);						\
10491694Sdarrenm 		break;							\
10501694Sdarrenm 	default:							\
10511694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;				\
10521694Sdarrenm 	}								\
10531694Sdarrenm }
10541694Sdarrenm 
10551694Sdarrenm /* ARGSUSED */
10561694Sdarrenm static int
sha1_mac_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * mac,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)10571694Sdarrenm sha1_mac_atomic(crypto_provider_handle_t provider,
10581694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
10591694Sdarrenm     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
10601694Sdarrenm     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
10611694Sdarrenm {
10621694Sdarrenm 	int ret = CRYPTO_SUCCESS;
10631694Sdarrenm 	uchar_t digest[SHA1_DIGEST_LENGTH];
10641694Sdarrenm 	sha1_hmac_ctx_t sha1_hmac_ctx;
10651694Sdarrenm 	uint32_t digest_len = SHA1_DIGEST_LENGTH;
10661694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
10671694Sdarrenm 
10681694Sdarrenm 	if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
10691694Sdarrenm 	    mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
10701694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
10711694Sdarrenm 
10721694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
10731694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
10741694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
10751694Sdarrenm 
10761694Sdarrenm 	if (ctx_template != NULL) {
10771694Sdarrenm 		/* reuse context template */
10781694Sdarrenm 		bcopy(ctx_template, &sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
10791694Sdarrenm 	} else {
10801694Sdarrenm 		/* no context template, initialize context */
10811694Sdarrenm 		if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
10821694Sdarrenm 			/*
10831694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
10841694Sdarrenm 			 * The inner context is used since it hasn't been
10851694Sdarrenm 			 * initialized yet.
10861694Sdarrenm 			 */
10871694Sdarrenm 			PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx.hc_icontext,
10881694Sdarrenm 			    key->ck_data, keylen_in_bytes, digest);
10891694Sdarrenm 			sha1_mac_init_ctx(&sha1_hmac_ctx, digest,
10901694Sdarrenm 			    SHA1_DIGEST_LENGTH);
10911694Sdarrenm 		} else {
10921694Sdarrenm 			sha1_mac_init_ctx(&sha1_hmac_ctx, key->ck_data,
10931694Sdarrenm 			    keylen_in_bytes);
10941694Sdarrenm 		}
10951694Sdarrenm 	}
10961694Sdarrenm 
10971694Sdarrenm 	/* get the mechanism parameters, if applicable */
10981694Sdarrenm 	if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
10991694Sdarrenm 		if (mechanism->cm_param == NULL ||
11001694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t)) {
11011694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
11021694Sdarrenm 			goto bail;
11031694Sdarrenm 		}
11041694Sdarrenm 		PROV_SHA1_GET_DIGEST_LEN(mechanism, digest_len);
11051694Sdarrenm 		if (digest_len > SHA1_DIGEST_LENGTH) {
11061694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
11071694Sdarrenm 			goto bail;
11081694Sdarrenm 		}
11091694Sdarrenm 	}
11101694Sdarrenm 
11111694Sdarrenm 	/* do a SHA1 update of the inner context using the specified data */
11121694Sdarrenm 	SHA1_MAC_UPDATE(data, sha1_hmac_ctx, ret);
11131694Sdarrenm 	if (ret != CRYPTO_SUCCESS)
11141694Sdarrenm 		/* the update failed, free context and bail */
11151694Sdarrenm 		goto bail;
11161694Sdarrenm 
11171694Sdarrenm 	/*
11181694Sdarrenm 	 * Do a SHA1 final on the inner context.
11191694Sdarrenm 	 */
11201694Sdarrenm 	SHA1Final(digest, &sha1_hmac_ctx.hc_icontext);
11211694Sdarrenm 
11221694Sdarrenm 	/*
11231694Sdarrenm 	 * Do an SHA1 update on the outer context, feeding the inner
11241694Sdarrenm 	 * digest as data.
11251694Sdarrenm 	 */
11261694Sdarrenm 	SHA1Update(&sha1_hmac_ctx.hc_ocontext, digest, SHA1_DIGEST_LENGTH);
11271694Sdarrenm 
11281694Sdarrenm 	/*
11291694Sdarrenm 	 * Do a SHA1 final on the outer context, storing the computed
11301694Sdarrenm 	 * digest in the users buffer.
11311694Sdarrenm 	 */
11321694Sdarrenm 	switch (mac->cd_format) {
11331694Sdarrenm 	case CRYPTO_DATA_RAW:
11341694Sdarrenm 		if (digest_len != SHA1_DIGEST_LENGTH) {
11351694Sdarrenm 			/*
11361694Sdarrenm 			 * The caller requested a short digest. Digest
11371694Sdarrenm 			 * into a scratch buffer and return to
11381694Sdarrenm 			 * the user only what was requested.
11391694Sdarrenm 			 */
11401694Sdarrenm 			SHA1Final(digest, &sha1_hmac_ctx.hc_ocontext);
11411694Sdarrenm 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
11421694Sdarrenm 			    mac->cd_offset, digest_len);
11431694Sdarrenm 		} else {
11441694Sdarrenm 			SHA1Final((unsigned char *)mac->cd_raw.iov_base +
11451694Sdarrenm 			    mac->cd_offset, &sha1_hmac_ctx.hc_ocontext);
11461694Sdarrenm 		}
11471694Sdarrenm 		break;
11481694Sdarrenm 	case CRYPTO_DATA_UIO:
11491694Sdarrenm 		ret = sha1_digest_final_uio(&sha1_hmac_ctx.hc_ocontext, mac,
11501694Sdarrenm 		    digest_len, digest);
11511694Sdarrenm 		break;
11521694Sdarrenm 	case CRYPTO_DATA_MBLK:
11531694Sdarrenm 		ret = sha1_digest_final_mblk(&sha1_hmac_ctx.hc_ocontext, mac,
11541694Sdarrenm 		    digest_len, digest);
11551694Sdarrenm 		break;
11561694Sdarrenm 	default:
11571694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
11581694Sdarrenm 	}
11591694Sdarrenm 
11601694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
11611694Sdarrenm 		mac->cd_length = digest_len;
11621694Sdarrenm 	} else {
11631694Sdarrenm 		mac->cd_length = 0;
11641694Sdarrenm 	}
11651694Sdarrenm 	/* Extra paranoia: zeroize the context on the stack */
11661694Sdarrenm 	bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
11671694Sdarrenm 
11681694Sdarrenm 	return (ret);
11691694Sdarrenm bail:
11701694Sdarrenm 	bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
11711694Sdarrenm 	mac->cd_length = 0;
11721694Sdarrenm 	return (ret);
11731694Sdarrenm }
11741694Sdarrenm 
11751694Sdarrenm /* ARGSUSED */
11761694Sdarrenm static int
sha1_mac_verify_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * mac,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)11771694Sdarrenm sha1_mac_verify_atomic(crypto_provider_handle_t provider,
11781694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
11791694Sdarrenm     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
11801694Sdarrenm     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
11811694Sdarrenm {
11821694Sdarrenm 	int ret = CRYPTO_SUCCESS;
11831694Sdarrenm 	uchar_t digest[SHA1_DIGEST_LENGTH];
11841694Sdarrenm 	sha1_hmac_ctx_t sha1_hmac_ctx;
11851694Sdarrenm 	uint32_t digest_len = SHA1_DIGEST_LENGTH;
11861694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
11871694Sdarrenm 
11881694Sdarrenm 	if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
11891694Sdarrenm 	    mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
11901694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
11911694Sdarrenm 
11921694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
11931694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
11941694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
11951694Sdarrenm 
11961694Sdarrenm 	if (ctx_template != NULL) {
11971694Sdarrenm 		/* reuse context template */
11981694Sdarrenm 		bcopy(ctx_template, &sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
11991694Sdarrenm 	} else {
12001694Sdarrenm 		/* no context template, initialize context */
12011694Sdarrenm 		if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
12021694Sdarrenm 			/*
12031694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
12041694Sdarrenm 			 * The inner context is used since it hasn't been
12051694Sdarrenm 			 * initialized yet.
12061694Sdarrenm 			 */
12071694Sdarrenm 			PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx.hc_icontext,
12081694Sdarrenm 			    key->ck_data, keylen_in_bytes, digest);
12091694Sdarrenm 			sha1_mac_init_ctx(&sha1_hmac_ctx, digest,
12101694Sdarrenm 			    SHA1_DIGEST_LENGTH);
12111694Sdarrenm 		} else {
12121694Sdarrenm 			sha1_mac_init_ctx(&sha1_hmac_ctx, key->ck_data,
12131694Sdarrenm 			    keylen_in_bytes);
12141694Sdarrenm 		}
12151694Sdarrenm 	}
12161694Sdarrenm 
12171694Sdarrenm 	/* get the mechanism parameters, if applicable */
12181694Sdarrenm 	if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
12191694Sdarrenm 		if (mechanism->cm_param == NULL ||
12201694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t)) {
12211694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
12221694Sdarrenm 			goto bail;
12231694Sdarrenm 		}
12241694Sdarrenm 		PROV_SHA1_GET_DIGEST_LEN(mechanism, digest_len);
12251694Sdarrenm 		if (digest_len > SHA1_DIGEST_LENGTH) {
12261694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
12271694Sdarrenm 			goto bail;
12281694Sdarrenm 		}
12291694Sdarrenm 	}
12301694Sdarrenm 
12311694Sdarrenm 	if (mac->cd_length != digest_len) {
12321694Sdarrenm 		ret = CRYPTO_INVALID_MAC;
12331694Sdarrenm 		goto bail;
12341694Sdarrenm 	}
12351694Sdarrenm 
12361694Sdarrenm 	/* do a SHA1 update of the inner context using the specified data */
12371694Sdarrenm 	SHA1_MAC_UPDATE(data, sha1_hmac_ctx, ret);
12381694Sdarrenm 	if (ret != CRYPTO_SUCCESS)
12391694Sdarrenm 		/* the update failed, free context and bail */
12401694Sdarrenm 		goto bail;
12411694Sdarrenm 
12421694Sdarrenm 	/* do a SHA1 final on the inner context */
12431694Sdarrenm 	SHA1Final(digest, &sha1_hmac_ctx.hc_icontext);
12441694Sdarrenm 
12451694Sdarrenm 	/*
12461694Sdarrenm 	 * Do an SHA1 update on the outer context, feeding the inner
12471694Sdarrenm 	 * digest as data.
12481694Sdarrenm 	 */
12491694Sdarrenm 	SHA1Update(&sha1_hmac_ctx.hc_ocontext, digest, SHA1_DIGEST_LENGTH);
12501694Sdarrenm 
12511694Sdarrenm 	/*
12521694Sdarrenm 	 * Do a SHA1 final on the outer context, storing the computed
12531694Sdarrenm 	 * digest in the users buffer.
12541694Sdarrenm 	 */
12551694Sdarrenm 	SHA1Final(digest, &sha1_hmac_ctx.hc_ocontext);
12561694Sdarrenm 
12571694Sdarrenm 	/*
12581694Sdarrenm 	 * Compare the computed digest against the expected digest passed
12591694Sdarrenm 	 * as argument.
12601694Sdarrenm 	 */
12611694Sdarrenm 
12621694Sdarrenm 	switch (mac->cd_format) {
12631694Sdarrenm 
12641694Sdarrenm 	case CRYPTO_DATA_RAW:
12651694Sdarrenm 		if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base +
12661694Sdarrenm 		    mac->cd_offset, digest_len) != 0)
12671694Sdarrenm 			ret = CRYPTO_INVALID_MAC;
12681694Sdarrenm 		break;
12691694Sdarrenm 
12701694Sdarrenm 	case CRYPTO_DATA_UIO: {
12711694Sdarrenm 		off_t offset = mac->cd_offset;
12721694Sdarrenm 		uint_t vec_idx;
12731694Sdarrenm 		off_t scratch_offset = 0;
12741694Sdarrenm 		size_t length = digest_len;
12751694Sdarrenm 		size_t cur_len;
12761694Sdarrenm 
12771694Sdarrenm 		/* we support only kernel buffer */
12781694Sdarrenm 		if (mac->cd_uio->uio_segflg != UIO_SYSSPACE)
12791694Sdarrenm 			return (CRYPTO_ARGUMENTS_BAD);
12801694Sdarrenm 
12811694Sdarrenm 		/* jump to the first iovec containing the expected digest */
12821694Sdarrenm 		for (vec_idx = 0;
12831694Sdarrenm 		    offset >= mac->cd_uio->uio_iov[vec_idx].iov_len &&
12841694Sdarrenm 		    vec_idx < mac->cd_uio->uio_iovcnt;
12859364SVladimir.Kotal@Sun.COM 		    offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len)
12869364SVladimir.Kotal@Sun.COM 			;
12871694Sdarrenm 		if (vec_idx == mac->cd_uio->uio_iovcnt) {
12881694Sdarrenm 			/*
12891694Sdarrenm 			 * The caller specified an offset that is
12901694Sdarrenm 			 * larger than the total size of the buffers
12911694Sdarrenm 			 * it provided.
12921694Sdarrenm 			 */
12931694Sdarrenm 			ret = CRYPTO_DATA_LEN_RANGE;
12941694Sdarrenm 			break;
12951694Sdarrenm 		}
12961694Sdarrenm 
12971694Sdarrenm 		/* do the comparison of computed digest vs specified one */
12981694Sdarrenm 		while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) {
12991694Sdarrenm 			cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len -
13001694Sdarrenm 			    offset, length);
13011694Sdarrenm 
13021694Sdarrenm 			if (bcmp(digest + scratch_offset,
13031694Sdarrenm 			    mac->cd_uio->uio_iov[vec_idx].iov_base + offset,
13041694Sdarrenm 			    cur_len) != 0) {
13051694Sdarrenm 				ret = CRYPTO_INVALID_MAC;
13061694Sdarrenm 				break;
13071694Sdarrenm 			}
13081694Sdarrenm 
13091694Sdarrenm 			length -= cur_len;
13101694Sdarrenm 			vec_idx++;
13111694Sdarrenm 			scratch_offset += cur_len;
13121694Sdarrenm 			offset = 0;
13131694Sdarrenm 		}
13141694Sdarrenm 		break;
13151694Sdarrenm 	}
13161694Sdarrenm 
13171694Sdarrenm 	case CRYPTO_DATA_MBLK: {
13181694Sdarrenm 		off_t offset = mac->cd_offset;
13191694Sdarrenm 		mblk_t *mp;
13201694Sdarrenm 		off_t scratch_offset = 0;
13211694Sdarrenm 		size_t length = digest_len;
13221694Sdarrenm 		size_t cur_len;
13231694Sdarrenm 
13241694Sdarrenm 		/* jump to the first mblk_t containing the expected digest */
13251694Sdarrenm 		for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp);
13269364SVladimir.Kotal@Sun.COM 		    offset -= MBLKL(mp), mp = mp->b_cont)
13279364SVladimir.Kotal@Sun.COM 			;
13281694Sdarrenm 		if (mp == NULL) {
13291694Sdarrenm 			/*
13301694Sdarrenm 			 * The caller specified an offset that is larger than
13311694Sdarrenm 			 * the total size of the buffers it provided.
13321694Sdarrenm 			 */
13331694Sdarrenm 			ret = CRYPTO_DATA_LEN_RANGE;
13341694Sdarrenm 			break;
13351694Sdarrenm 		}
13361694Sdarrenm 
13371694Sdarrenm 		while (mp != NULL && length > 0) {
13381694Sdarrenm 			cur_len = MIN(MBLKL(mp) - offset, length);
13391694Sdarrenm 			if (bcmp(digest + scratch_offset,
13401694Sdarrenm 			    mp->b_rptr + offset, cur_len) != 0) {
13411694Sdarrenm 				ret = CRYPTO_INVALID_MAC;
13421694Sdarrenm 				break;
13431694Sdarrenm 			}
13441694Sdarrenm 
13451694Sdarrenm 			length -= cur_len;
13461694Sdarrenm 			mp = mp->b_cont;
13471694Sdarrenm 			scratch_offset += cur_len;
13481694Sdarrenm 			offset = 0;
13491694Sdarrenm 		}
13501694Sdarrenm 		break;
13511694Sdarrenm 	}
13521694Sdarrenm 
13531694Sdarrenm 	default:
13541694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
13551694Sdarrenm 	}
13561694Sdarrenm 
13571694Sdarrenm 	bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
13581694Sdarrenm 	return (ret);
13591694Sdarrenm bail:
13601694Sdarrenm 	bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
13611694Sdarrenm 	mac->cd_length = 0;
13621694Sdarrenm 	return (ret);
13631694Sdarrenm }
13641694Sdarrenm 
13651694Sdarrenm /*
13661694Sdarrenm  * KCF software provider context management entry points.
13671694Sdarrenm  */
13681694Sdarrenm 
13691694Sdarrenm /* ARGSUSED */
13701694Sdarrenm static int
sha1_create_ctx_template(crypto_provider_handle_t provider,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t * ctx_template,size_t * ctx_template_size,crypto_req_handle_t req)13711694Sdarrenm sha1_create_ctx_template(crypto_provider_handle_t provider,
13721694Sdarrenm     crypto_mechanism_t *mechanism, crypto_key_t *key,
13731694Sdarrenm     crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
13741694Sdarrenm     crypto_req_handle_t req)
13751694Sdarrenm {
13761694Sdarrenm 	sha1_hmac_ctx_t *sha1_hmac_ctx_tmpl;
13771694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
13781694Sdarrenm 
13791694Sdarrenm 	if ((mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE) &&
13801694Sdarrenm 	    (mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)) {
13811694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
13821694Sdarrenm 	}
13831694Sdarrenm 
13841694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
13851694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
13861694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
13871694Sdarrenm 
13881694Sdarrenm 	/*
13891694Sdarrenm 	 * Allocate and initialize SHA1 context.
13901694Sdarrenm 	 */
13911694Sdarrenm 	sha1_hmac_ctx_tmpl = kmem_alloc(sizeof (sha1_hmac_ctx_t),
13921694Sdarrenm 	    crypto_kmflag(req));
13931694Sdarrenm 	if (sha1_hmac_ctx_tmpl == NULL)
13941694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
13951694Sdarrenm 
13961694Sdarrenm 	if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
13971694Sdarrenm 		uchar_t digested_key[SHA1_DIGEST_LENGTH];
13981694Sdarrenm 
13991694Sdarrenm 		/*
14001694Sdarrenm 		 * Hash the passed-in key to get a smaller key.
14011694Sdarrenm 		 * The inner context is used since it hasn't been
14021694Sdarrenm 		 * initialized yet.
14031694Sdarrenm 		 */
14041694Sdarrenm 		PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx_tmpl->hc_icontext,
14051694Sdarrenm 		    key->ck_data, keylen_in_bytes, digested_key);
14061694Sdarrenm 		sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, digested_key,
14071694Sdarrenm 		    SHA1_DIGEST_LENGTH);
14081694Sdarrenm 	} else {
14091694Sdarrenm 		sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, key->ck_data,
14101694Sdarrenm 		    keylen_in_bytes);
14111694Sdarrenm 	}
14121694Sdarrenm 
14131694Sdarrenm 	sha1_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;
14141694Sdarrenm 	*ctx_template = (crypto_spi_ctx_template_t)sha1_hmac_ctx_tmpl;
14151694Sdarrenm 	*ctx_template_size = sizeof (sha1_hmac_ctx_t);
14161694Sdarrenm 
14171694Sdarrenm 
14181694Sdarrenm 	return (CRYPTO_SUCCESS);
14191694Sdarrenm }
14201694Sdarrenm 
14211694Sdarrenm static int
sha1_free_context(crypto_ctx_t * ctx)14221694Sdarrenm sha1_free_context(crypto_ctx_t *ctx)
14231694Sdarrenm {
14241694Sdarrenm 	uint_t ctx_len;
14251694Sdarrenm 	sha1_mech_type_t mech_type;
14261694Sdarrenm 
14271694Sdarrenm 	if (ctx->cc_provider_private == NULL)
14281694Sdarrenm 		return (CRYPTO_SUCCESS);
14291694Sdarrenm 
14301694Sdarrenm 	/*
14311694Sdarrenm 	 * We have to free either SHA1 or SHA1-HMAC contexts, which
14321694Sdarrenm 	 * have different lengths.
14331694Sdarrenm 	 */
14341694Sdarrenm 
14351694Sdarrenm 	mech_type = PROV_SHA1_CTX(ctx)->sc_mech_type;
14361694Sdarrenm 	if (mech_type == SHA1_MECH_INFO_TYPE)
14371694Sdarrenm 		ctx_len = sizeof (sha1_ctx_t);
14381694Sdarrenm 	else {
14391694Sdarrenm 		ASSERT(mech_type == SHA1_HMAC_MECH_INFO_TYPE ||
14401694Sdarrenm 		    mech_type == SHA1_HMAC_GEN_MECH_INFO_TYPE);
14411694Sdarrenm 		ctx_len = sizeof (sha1_hmac_ctx_t);
14421694Sdarrenm 	}
14431694Sdarrenm 
14441694Sdarrenm 	bzero(ctx->cc_provider_private, ctx_len);
14451694Sdarrenm 	kmem_free(ctx->cc_provider_private, ctx_len);
14461694Sdarrenm 	ctx->cc_provider_private = NULL;
14471694Sdarrenm 
14481694Sdarrenm 	return (CRYPTO_SUCCESS);
14491694Sdarrenm }
145010500SHai-May.Chao@Sun.COM 
145110500SHai-May.Chao@Sun.COM /*
145210500SHai-May.Chao@Sun.COM  * SHA-1 Power-Up Self-Test
145310500SHai-May.Chao@Sun.COM  */
145410500SHai-May.Chao@Sun.COM void
sha1_POST(int * rc)145510500SHai-May.Chao@Sun.COM sha1_POST(int *rc)
145610500SHai-May.Chao@Sun.COM {
145710500SHai-May.Chao@Sun.COM 
145810500SHai-May.Chao@Sun.COM 	*rc = fips_sha1_post();
145910500SHai-May.Chao@Sun.COM 
146010500SHai-May.Chao@Sun.COM }
1461