xref: /onnv-gate/usr/src/uts/common/crypto/io/sha2_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/crypto/common.h>
301694Sdarrenm #include <sys/crypto/spi.h>
311694Sdarrenm #include <sys/strsun.h>
321694Sdarrenm #include <sys/systm.h>
331694Sdarrenm #include <sys/sysmacros.h>
341694Sdarrenm #define	_SHA2_IMPL
351694Sdarrenm #include <sys/sha2.h>
3610500SHai-May.Chao@Sun.COM #include <sha2/sha2_impl.h>
371694Sdarrenm 
381694Sdarrenm /*
391694Sdarrenm  * The sha2 module is created with two modlinkages:
401694Sdarrenm  * - a modlmisc that allows consumers to directly call the entry points
411694Sdarrenm  *   SHA2Init, SHA2Update, and SHA2Final.
421694Sdarrenm  * - a modlcrypto that allows the module to register with the Kernel
431694Sdarrenm  *   Cryptographic Framework (KCF) as a software provider for the SHA2
441694Sdarrenm  *   mechanisms.
451694Sdarrenm  */
461694Sdarrenm 
471694Sdarrenm static struct modlmisc modlmisc = {
481694Sdarrenm 	&mod_miscops,
491694Sdarrenm 	"SHA2 Message-Digest Algorithm"
501694Sdarrenm };
511694Sdarrenm 
521694Sdarrenm static struct modlcrypto modlcrypto = {
531694Sdarrenm 	&mod_cryptoops,
545072Smcpowers 	"SHA2 Kernel SW Provider"
551694Sdarrenm };
561694Sdarrenm 
571694Sdarrenm static struct modlinkage modlinkage = {
581694Sdarrenm 	MODREV_1, &modlmisc, &modlcrypto, NULL
591694Sdarrenm };
601694Sdarrenm 
611694Sdarrenm /*
621694Sdarrenm  * Macros to access the SHA2 or SHA2-HMAC contexts from a context passed
631694Sdarrenm  * by KCF to one of the entry points.
641694Sdarrenm  */
651694Sdarrenm 
661694Sdarrenm #define	PROV_SHA2_CTX(ctx)	((sha2_ctx_t *)(ctx)->cc_provider_private)
671694Sdarrenm #define	PROV_SHA2_HMAC_CTX(ctx)	((sha2_hmac_ctx_t *)(ctx)->cc_provider_private)
681694Sdarrenm 
691694Sdarrenm /* to extract the digest length passed as mechanism parameter */
701694Sdarrenm #define	PROV_SHA2_GET_DIGEST_LEN(m, len) {				\
711694Sdarrenm 	if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t)))		\
7211141Sopensolaris@drydog.com 		(len) = (uint32_t)*((ulong_t *)(void *)(m)->cm_param);	\
731694Sdarrenm 	else {								\
741694Sdarrenm 		ulong_t tmp_ulong;					\
751694Sdarrenm 		bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t));	\
761694Sdarrenm 		(len) = (uint32_t)tmp_ulong;				\
771694Sdarrenm 	}								\
781694Sdarrenm }
791694Sdarrenm 
801694Sdarrenm #define	PROV_SHA2_DIGEST_KEY(mech, ctx, key, len, digest) {	\
811694Sdarrenm 	SHA2Init(mech, ctx);				\
821694Sdarrenm 	SHA2Update(ctx, key, len);			\
831694Sdarrenm 	SHA2Final(digest, ctx);				\
841694Sdarrenm }
851694Sdarrenm 
861694Sdarrenm /*
871694Sdarrenm  * Mechanism info structure passed to KCF during registration.
881694Sdarrenm  */
891694Sdarrenm static crypto_mech_info_t sha2_mech_info_tab[] = {
901694Sdarrenm 	/* SHA256 */
911694Sdarrenm 	{SUN_CKM_SHA256, SHA256_MECH_INFO_TYPE,
921694Sdarrenm 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
931694Sdarrenm 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
941694Sdarrenm 	/* SHA256-HMAC */
951694Sdarrenm 	{SUN_CKM_SHA256_HMAC, SHA256_HMAC_MECH_INFO_TYPE,
961694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
971694Sdarrenm 	    SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
989364SVladimir.Kotal@Sun.COM 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
991694Sdarrenm 	/* SHA256-HMAC GENERAL */
1001694Sdarrenm 	{SUN_CKM_SHA256_HMAC_GENERAL, SHA256_HMAC_GEN_MECH_INFO_TYPE,
1011694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
1021694Sdarrenm 	    SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
1039364SVladimir.Kotal@Sun.COM 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1041694Sdarrenm 	/* SHA384 */
1051694Sdarrenm 	{SUN_CKM_SHA384, SHA384_MECH_INFO_TYPE,
1061694Sdarrenm 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
1071694Sdarrenm 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
1081694Sdarrenm 	/* SHA384-HMAC */
1091694Sdarrenm 	{SUN_CKM_SHA384_HMAC, SHA384_HMAC_MECH_INFO_TYPE,
1101694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
1111694Sdarrenm 	    SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
1129364SVladimir.Kotal@Sun.COM 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1131694Sdarrenm 	/* SHA384-HMAC GENERAL */
1141694Sdarrenm 	{SUN_CKM_SHA384_HMAC_GENERAL, SHA384_HMAC_GEN_MECH_INFO_TYPE,
1151694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
1161694Sdarrenm 	    SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
1179364SVladimir.Kotal@Sun.COM 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1181694Sdarrenm 	/* SHA512 */
1191694Sdarrenm 	{SUN_CKM_SHA512, SHA512_MECH_INFO_TYPE,
1201694Sdarrenm 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
1211694Sdarrenm 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
1221694Sdarrenm 	/* SHA512-HMAC */
1231694Sdarrenm 	{SUN_CKM_SHA512_HMAC, SHA512_HMAC_MECH_INFO_TYPE,
1241694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
1251694Sdarrenm 	    SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
1269364SVladimir.Kotal@Sun.COM 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
1271694Sdarrenm 	/* SHA512-HMAC GENERAL */
1281694Sdarrenm 	{SUN_CKM_SHA512_HMAC_GENERAL, SHA512_HMAC_GEN_MECH_INFO_TYPE,
1291694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
1301694Sdarrenm 	    SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
1319364SVladimir.Kotal@Sun.COM 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES}
1321694Sdarrenm };
1331694Sdarrenm 
1341694Sdarrenm static void sha2_provider_status(crypto_provider_handle_t, uint_t *);
1351694Sdarrenm 
1361694Sdarrenm static crypto_control_ops_t sha2_control_ops = {
1371694Sdarrenm 	sha2_provider_status
1381694Sdarrenm };
1391694Sdarrenm 
1401694Sdarrenm static int sha2_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
1411694Sdarrenm     crypto_req_handle_t);
1421694Sdarrenm static int sha2_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1431694Sdarrenm     crypto_req_handle_t);
1441694Sdarrenm static int sha2_digest_update(crypto_ctx_t *, crypto_data_t *,
1451694Sdarrenm     crypto_req_handle_t);
1461694Sdarrenm static int sha2_digest_final(crypto_ctx_t *, crypto_data_t *,
1471694Sdarrenm     crypto_req_handle_t);
1481694Sdarrenm static int sha2_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
1491694Sdarrenm     crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
1501694Sdarrenm     crypto_req_handle_t);
1511694Sdarrenm 
1521694Sdarrenm static crypto_digest_ops_t sha2_digest_ops = {
1531694Sdarrenm 	sha2_digest_init,
1541694Sdarrenm 	sha2_digest,
1551694Sdarrenm 	sha2_digest_update,
1561694Sdarrenm 	NULL,
1571694Sdarrenm 	sha2_digest_final,
1581694Sdarrenm 	sha2_digest_atomic
1591694Sdarrenm };
1601694Sdarrenm 
1611694Sdarrenm static int sha2_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
1621694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
1631694Sdarrenm static int sha2_mac_update(crypto_ctx_t *, crypto_data_t *,
1641694Sdarrenm     crypto_req_handle_t);
1651694Sdarrenm static int sha2_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
1661694Sdarrenm static int sha2_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
1671694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1681694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
1691694Sdarrenm static int sha2_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
1701694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1711694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
1721694Sdarrenm 
1731694Sdarrenm static crypto_mac_ops_t sha2_mac_ops = {
1741694Sdarrenm 	sha2_mac_init,
1751694Sdarrenm 	NULL,
1761694Sdarrenm 	sha2_mac_update,
1771694Sdarrenm 	sha2_mac_final,
1781694Sdarrenm 	sha2_mac_atomic,
1791694Sdarrenm 	sha2_mac_verify_atomic
1801694Sdarrenm };
1811694Sdarrenm 
1821694Sdarrenm static int sha2_create_ctx_template(crypto_provider_handle_t,
1831694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
1841694Sdarrenm     size_t *, crypto_req_handle_t);
1851694Sdarrenm static int sha2_free_context(crypto_ctx_t *);
1861694Sdarrenm 
1871694Sdarrenm static crypto_ctx_ops_t sha2_ctx_ops = {
1881694Sdarrenm 	sha2_create_ctx_template,
1891694Sdarrenm 	sha2_free_context
1901694Sdarrenm };
1911694Sdarrenm 
19210732SAnthony.Scarpino@Sun.COM static void sha2_POST(int *);
19310732SAnthony.Scarpino@Sun.COM 
19410732SAnthony.Scarpino@Sun.COM static crypto_fips140_ops_t sha2_fips140_ops = {
19510732SAnthony.Scarpino@Sun.COM 	sha2_POST
19610732SAnthony.Scarpino@Sun.COM };
19710732SAnthony.Scarpino@Sun.COM 
1981694Sdarrenm static crypto_ops_t sha2_crypto_ops = {
1991694Sdarrenm 	&sha2_control_ops,
2001694Sdarrenm 	&sha2_digest_ops,
2011694Sdarrenm 	NULL,
2021694Sdarrenm 	&sha2_mac_ops,
2031694Sdarrenm 	NULL,
2041694Sdarrenm 	NULL,
2051694Sdarrenm 	NULL,
2061694Sdarrenm 	NULL,
2071694Sdarrenm 	NULL,
2081694Sdarrenm 	NULL,
2091694Sdarrenm 	NULL,
2101694Sdarrenm 	NULL,
2111694Sdarrenm 	NULL,
21210732SAnthony.Scarpino@Sun.COM 	&sha2_ctx_ops,
21310732SAnthony.Scarpino@Sun.COM 	NULL,
21410732SAnthony.Scarpino@Sun.COM 	NULL,
21510732SAnthony.Scarpino@Sun.COM 	&sha2_fips140_ops
2161694Sdarrenm };
2171694Sdarrenm 
2181694Sdarrenm static crypto_provider_info_t sha2_prov_info = {
21910732SAnthony.Scarpino@Sun.COM 	CRYPTO_SPI_VERSION_4,
2201694Sdarrenm 	"SHA2 Software Provider",
2211694Sdarrenm 	CRYPTO_SW_PROVIDER,
2221694Sdarrenm 	{&modlinkage},
2231694Sdarrenm 	NULL,
2241694Sdarrenm 	&sha2_crypto_ops,
2251694Sdarrenm 	sizeof (sha2_mech_info_tab)/sizeof (crypto_mech_info_t),
2261694Sdarrenm 	sha2_mech_info_tab
2271694Sdarrenm };
2281694Sdarrenm 
2291694Sdarrenm static crypto_kcf_provider_handle_t sha2_prov_handle = NULL;
2301694Sdarrenm 
2311694Sdarrenm int
_init()2321694Sdarrenm _init()
2331694Sdarrenm {
2341694Sdarrenm 	int ret;
2351694Sdarrenm 
2361694Sdarrenm 	if ((ret = mod_install(&modlinkage)) != 0)
2371694Sdarrenm 		return (ret);
2381694Sdarrenm 
2391694Sdarrenm 	/*
240*11751SAnthony.Scarpino@Sun.COM 	 * Register with KCF. If the registration fails, do not uninstall the
241*11751SAnthony.Scarpino@Sun.COM 	 * module, since the functionality provided by misc/sha2 should still
242*11751SAnthony.Scarpino@Sun.COM 	 * be available.
2431694Sdarrenm 	 */
244*11751SAnthony.Scarpino@Sun.COM 	(void) crypto_register_provider(&sha2_prov_info, &sha2_prov_handle);
2451694Sdarrenm 
2461694Sdarrenm 	return (0);
2471694Sdarrenm }
2481694Sdarrenm 
2491694Sdarrenm int
_info(struct modinfo * modinfop)2501694Sdarrenm _info(struct modinfo *modinfop)
2511694Sdarrenm {
2521694Sdarrenm 	return (mod_info(&modlinkage, modinfop));
2531694Sdarrenm }
2541694Sdarrenm 
2551694Sdarrenm /*
2561694Sdarrenm  * KCF software provider control entry points.
2571694Sdarrenm  */
2581694Sdarrenm /* ARGSUSED */
2591694Sdarrenm static void
sha2_provider_status(crypto_provider_handle_t provider,uint_t * status)2601694Sdarrenm sha2_provider_status(crypto_provider_handle_t provider, uint_t *status)
2611694Sdarrenm {
2621694Sdarrenm 	*status = CRYPTO_PROVIDER_READY;
2631694Sdarrenm }
2641694Sdarrenm 
2651694Sdarrenm /*
2661694Sdarrenm  * KCF software provider digest entry points.
2671694Sdarrenm  */
2681694Sdarrenm 
2691694Sdarrenm static int
sha2_digest_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_req_handle_t req)2701694Sdarrenm sha2_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
2711694Sdarrenm     crypto_req_handle_t req)
2721694Sdarrenm {
2731694Sdarrenm 
2741694Sdarrenm 	/*
2751694Sdarrenm 	 * Allocate and initialize SHA2 context.
2761694Sdarrenm 	 */
2771694Sdarrenm 	ctx->cc_provider_private = kmem_alloc(sizeof (sha2_ctx_t),
2781694Sdarrenm 	    crypto_kmflag(req));
2791694Sdarrenm 	if (ctx->cc_provider_private == NULL)
2801694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
2811694Sdarrenm 
2821694Sdarrenm 	PROV_SHA2_CTX(ctx)->sc_mech_type = mechanism->cm_type;
2831694Sdarrenm 	SHA2Init(mechanism->cm_type, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx);
2841694Sdarrenm 
2851694Sdarrenm 	return (CRYPTO_SUCCESS);
2861694Sdarrenm }
2871694Sdarrenm 
2881694Sdarrenm /*
2891694Sdarrenm  * Helper SHA2 digest update function for uio data.
2901694Sdarrenm  */
2911694Sdarrenm static int
sha2_digest_update_uio(SHA2_CTX * sha2_ctx,crypto_data_t * data)2921694Sdarrenm sha2_digest_update_uio(SHA2_CTX *sha2_ctx, crypto_data_t *data)
2931694Sdarrenm {
2941694Sdarrenm 	off_t offset = data->cd_offset;
2951694Sdarrenm 	size_t length = data->cd_length;
2961694Sdarrenm 	uint_t vec_idx;
2971694Sdarrenm 	size_t cur_len;
2981694Sdarrenm 
2991694Sdarrenm 	/* we support only kernel buffer */
3001694Sdarrenm 	if (data->cd_uio->uio_segflg != UIO_SYSSPACE)
3011694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
3021694Sdarrenm 
3031694Sdarrenm 	/*
3041694Sdarrenm 	 * Jump to the first iovec containing data to be
3051694Sdarrenm 	 * digested.
3061694Sdarrenm 	 */
3071694Sdarrenm 	for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt &&
3081694Sdarrenm 	    offset >= data->cd_uio->uio_iov[vec_idx].iov_len;
3095072Smcpowers 	    offset -= data->cd_uio->uio_iov[vec_idx++].iov_len)
3105072Smcpowers 		;
3111694Sdarrenm 	if (vec_idx == data->cd_uio->uio_iovcnt) {
3121694Sdarrenm 		/*
3131694Sdarrenm 		 * The caller specified an offset that is larger than the
3141694Sdarrenm 		 * total size of the buffers it provided.
3151694Sdarrenm 		 */
3161694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
3171694Sdarrenm 	}
3181694Sdarrenm 
3191694Sdarrenm 	/*
3201694Sdarrenm 	 * Now do the digesting on the iovecs.
3211694Sdarrenm 	 */
3221694Sdarrenm 	while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) {
3231694Sdarrenm 		cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len -
3241694Sdarrenm 		    offset, length);
3251694Sdarrenm 
3261694Sdarrenm 		SHA2Update(sha2_ctx, (uint8_t *)data->cd_uio->
3271694Sdarrenm 		    uio_iov[vec_idx].iov_base + offset, cur_len);
3281694Sdarrenm 		length -= cur_len;
3291694Sdarrenm 		vec_idx++;
3301694Sdarrenm 		offset = 0;
3311694Sdarrenm 	}
3321694Sdarrenm 
3331694Sdarrenm 	if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) {
3341694Sdarrenm 		/*
3351694Sdarrenm 		 * The end of the specified iovec's was reached but
3361694Sdarrenm 		 * the length requested could not be processed, i.e.
3371694Sdarrenm 		 * The caller requested to digest more data than it provided.
3381694Sdarrenm 		 */
3391694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
3401694Sdarrenm 	}
3411694Sdarrenm 
3421694Sdarrenm 	return (CRYPTO_SUCCESS);
3431694Sdarrenm }
3441694Sdarrenm 
3451694Sdarrenm /*
3461694Sdarrenm  * Helper SHA2 digest final function for uio data.
3471694Sdarrenm  * digest_len is the length of the desired digest. If digest_len
3481694Sdarrenm  * is smaller than the default SHA2 digest length, the caller
3491694Sdarrenm  * must pass a scratch buffer, digest_scratch, which must
3501694Sdarrenm  * be at least the algorithm's digest length bytes.
3511694Sdarrenm  */
3521694Sdarrenm static int
sha2_digest_final_uio(SHA2_CTX * sha2_ctx,crypto_data_t * digest,ulong_t digest_len,uchar_t * digest_scratch)3531694Sdarrenm sha2_digest_final_uio(SHA2_CTX *sha2_ctx, crypto_data_t *digest,
3541694Sdarrenm     ulong_t digest_len, uchar_t *digest_scratch)
3551694Sdarrenm {
3561694Sdarrenm 	off_t offset = digest->cd_offset;
3571694Sdarrenm 	uint_t vec_idx;
3581694Sdarrenm 
3591694Sdarrenm 	/* we support only kernel buffer */
3601694Sdarrenm 	if (digest->cd_uio->uio_segflg != UIO_SYSSPACE)
3611694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
3621694Sdarrenm 
3631694Sdarrenm 	/*
3641694Sdarrenm 	 * Jump to the first iovec containing ptr to the digest to
3651694Sdarrenm 	 * be returned.
3661694Sdarrenm 	 */
3671694Sdarrenm 	for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len &&
3681694Sdarrenm 	    vec_idx < digest->cd_uio->uio_iovcnt;
3695072Smcpowers 	    offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len)
3705072Smcpowers 		;
3711694Sdarrenm 	if (vec_idx == digest->cd_uio->uio_iovcnt) {
3721694Sdarrenm 		/*
3731694Sdarrenm 		 * The caller specified an offset that is
3741694Sdarrenm 		 * larger than the total size of the buffers
3751694Sdarrenm 		 * it provided.
3761694Sdarrenm 		 */
3771694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
3781694Sdarrenm 	}
3791694Sdarrenm 
3801694Sdarrenm 	if (offset + digest_len <=
3811694Sdarrenm 	    digest->cd_uio->uio_iov[vec_idx].iov_len) {
3821694Sdarrenm 		/*
3831694Sdarrenm 		 * The computed SHA2 digest will fit in the current
3841694Sdarrenm 		 * iovec.
3851694Sdarrenm 		 */
3861694Sdarrenm 		if (((sha2_ctx->algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) &&
3871694Sdarrenm 		    (digest_len != SHA256_DIGEST_LENGTH)) ||
3881694Sdarrenm 		    ((sha2_ctx->algotype > SHA256_HMAC_GEN_MECH_INFO_TYPE) &&
3895072Smcpowers 		    (digest_len != SHA512_DIGEST_LENGTH))) {
3901694Sdarrenm 			/*
3911694Sdarrenm 			 * The caller requested a short digest. Digest
3921694Sdarrenm 			 * into a scratch buffer and return to
3931694Sdarrenm 			 * the user only what was requested.
3941694Sdarrenm 			 */
3951694Sdarrenm 			SHA2Final(digest_scratch, sha2_ctx);
3961694Sdarrenm 
3971694Sdarrenm 			bcopy(digest_scratch, (uchar_t *)digest->
3981694Sdarrenm 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
3991694Sdarrenm 			    digest_len);
4001694Sdarrenm 		} else {
4011694Sdarrenm 			SHA2Final((uchar_t *)digest->
4021694Sdarrenm 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
4031694Sdarrenm 			    sha2_ctx);
4041694Sdarrenm 
4051694Sdarrenm 		}
4061694Sdarrenm 	} else {
4071694Sdarrenm 		/*
4081694Sdarrenm 		 * The computed digest will be crossing one or more iovec's.
4091694Sdarrenm 		 * This is bad performance-wise but we need to support it.
4101694Sdarrenm 		 * Allocate a small scratch buffer on the stack and
4111694Sdarrenm 		 * copy it piece meal to the specified digest iovec's.
4121694Sdarrenm 		 */
4131694Sdarrenm 		uchar_t digest_tmp[SHA512_DIGEST_LENGTH];
4141694Sdarrenm 		off_t scratch_offset = 0;
4151694Sdarrenm 		size_t length = digest_len;
4161694Sdarrenm 		size_t cur_len;
4171694Sdarrenm 
4181694Sdarrenm 		SHA2Final(digest_tmp, sha2_ctx);
4191694Sdarrenm 
4201694Sdarrenm 		while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
4211694Sdarrenm 			cur_len =
4221694Sdarrenm 			    MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
4235072Smcpowers 			    offset, length);
4241694Sdarrenm 			bcopy(digest_tmp + scratch_offset,
4251694Sdarrenm 			    digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
4261694Sdarrenm 			    cur_len);
4271694Sdarrenm 
4281694Sdarrenm 			length -= cur_len;
4291694Sdarrenm 			vec_idx++;
4301694Sdarrenm 			scratch_offset += cur_len;
4311694Sdarrenm 			offset = 0;
4321694Sdarrenm 		}
4331694Sdarrenm 
4341694Sdarrenm 		if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
4351694Sdarrenm 			/*
4361694Sdarrenm 			 * The end of the specified iovec's was reached but
4371694Sdarrenm 			 * the length requested could not be processed, i.e.
4381694Sdarrenm 			 * The caller requested to digest more data than it
4391694Sdarrenm 			 * provided.
4401694Sdarrenm 			 */
4411694Sdarrenm 			return (CRYPTO_DATA_LEN_RANGE);
4421694Sdarrenm 		}
4431694Sdarrenm 	}
4441694Sdarrenm 
4451694Sdarrenm 	return (CRYPTO_SUCCESS);
4461694Sdarrenm }
4471694Sdarrenm 
4481694Sdarrenm /*
4491694Sdarrenm  * Helper SHA2 digest update for mblk's.
4501694Sdarrenm  */
4511694Sdarrenm static int
sha2_digest_update_mblk(SHA2_CTX * sha2_ctx,crypto_data_t * data)4521694Sdarrenm sha2_digest_update_mblk(SHA2_CTX *sha2_ctx, crypto_data_t *data)
4531694Sdarrenm {
4541694Sdarrenm 	off_t offset = data->cd_offset;
4551694Sdarrenm 	size_t length = data->cd_length;
4561694Sdarrenm 	mblk_t *mp;
4571694Sdarrenm 	size_t cur_len;
4581694Sdarrenm 
4591694Sdarrenm 	/*
4601694Sdarrenm 	 * Jump to the first mblk_t containing data to be digested.
4611694Sdarrenm 	 */
4621694Sdarrenm 	for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
4635072Smcpowers 	    offset -= MBLKL(mp), mp = mp->b_cont)
4645072Smcpowers 		;
4651694Sdarrenm 	if (mp == NULL) {
4661694Sdarrenm 		/*
4671694Sdarrenm 		 * The caller specified an offset that is larger than the
4681694Sdarrenm 		 * total size of the buffers it provided.
4691694Sdarrenm 		 */
4701694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
4711694Sdarrenm 	}
4721694Sdarrenm 
4731694Sdarrenm 	/*
4741694Sdarrenm 	 * Now do the digesting on the mblk chain.
4751694Sdarrenm 	 */
4761694Sdarrenm 	while (mp != NULL && length > 0) {
4771694Sdarrenm 		cur_len = MIN(MBLKL(mp) - offset, length);
4781694Sdarrenm 		SHA2Update(sha2_ctx, mp->b_rptr + offset, cur_len);
4791694Sdarrenm 		length -= cur_len;
4801694Sdarrenm 		offset = 0;
4811694Sdarrenm 		mp = mp->b_cont;
4821694Sdarrenm 	}
4831694Sdarrenm 
4841694Sdarrenm 	if (mp == NULL && length > 0) {
4851694Sdarrenm 		/*
4861694Sdarrenm 		 * The end of the mblk was reached but the length requested
4871694Sdarrenm 		 * could not be processed, i.e. The caller requested
4881694Sdarrenm 		 * to digest more data than it provided.
4891694Sdarrenm 		 */
4901694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
4911694Sdarrenm 	}
4921694Sdarrenm 
4931694Sdarrenm 	return (CRYPTO_SUCCESS);
4941694Sdarrenm }
4951694Sdarrenm 
4961694Sdarrenm /*
4971694Sdarrenm  * Helper SHA2 digest final for mblk's.
4981694Sdarrenm  * digest_len is the length of the desired digest. If digest_len
4991694Sdarrenm  * is smaller than the default SHA2 digest length, the caller
5001694Sdarrenm  * must pass a scratch buffer, digest_scratch, which must
5011694Sdarrenm  * be at least the algorithm's digest length bytes.
5021694Sdarrenm  */
5031694Sdarrenm static int
sha2_digest_final_mblk(SHA2_CTX * sha2_ctx,crypto_data_t * digest,ulong_t digest_len,uchar_t * digest_scratch)5041694Sdarrenm sha2_digest_final_mblk(SHA2_CTX *sha2_ctx, crypto_data_t *digest,
5051694Sdarrenm     ulong_t digest_len, uchar_t *digest_scratch)
5061694Sdarrenm {
5071694Sdarrenm 	off_t offset = digest->cd_offset;
5081694Sdarrenm 	mblk_t *mp;
5091694Sdarrenm 
5101694Sdarrenm 	/*
5111694Sdarrenm 	 * Jump to the first mblk_t that will be used to store the digest.
5121694Sdarrenm 	 */
5131694Sdarrenm 	for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp);
5145072Smcpowers 	    offset -= MBLKL(mp), mp = mp->b_cont)
5155072Smcpowers 		;
5161694Sdarrenm 	if (mp == NULL) {
5171694Sdarrenm 		/*
5181694Sdarrenm 		 * The caller specified an offset that is larger than the
5191694Sdarrenm 		 * total size of the buffers it provided.
5201694Sdarrenm 		 */
5211694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
5221694Sdarrenm 	}
5231694Sdarrenm 
5241694Sdarrenm 	if (offset + digest_len <= MBLKL(mp)) {
5251694Sdarrenm 		/*
5261694Sdarrenm 		 * The computed SHA2 digest will fit in the current mblk.
5271694Sdarrenm 		 * Do the SHA2Final() in-place.
5281694Sdarrenm 		 */
5291694Sdarrenm 		if (((sha2_ctx->algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) &&
5301694Sdarrenm 		    (digest_len != SHA256_DIGEST_LENGTH)) ||
5311694Sdarrenm 		    ((sha2_ctx->algotype > SHA256_HMAC_GEN_MECH_INFO_TYPE) &&
5325072Smcpowers 		    (digest_len != SHA512_DIGEST_LENGTH))) {
5331694Sdarrenm 			/*
5341694Sdarrenm 			 * The caller requested a short digest. Digest
5351694Sdarrenm 			 * into a scratch buffer and return to
5361694Sdarrenm 			 * the user only what was requested.
5371694Sdarrenm 			 */
5381694Sdarrenm 			SHA2Final(digest_scratch, sha2_ctx);
5391694Sdarrenm 			bcopy(digest_scratch, mp->b_rptr + offset, digest_len);
5401694Sdarrenm 		} else {
5411694Sdarrenm 			SHA2Final(mp->b_rptr + offset, sha2_ctx);
5421694Sdarrenm 		}
5431694Sdarrenm 	} else {
5441694Sdarrenm 		/*
5451694Sdarrenm 		 * The computed digest will be crossing one or more mblk's.
5461694Sdarrenm 		 * This is bad performance-wise but we need to support it.
5471694Sdarrenm 		 * Allocate a small scratch buffer on the stack and
5481694Sdarrenm 		 * copy it piece meal to the specified digest iovec's.
5491694Sdarrenm 		 */
5501694Sdarrenm 		uchar_t digest_tmp[SHA512_DIGEST_LENGTH];
5511694Sdarrenm 		off_t scratch_offset = 0;
5521694Sdarrenm 		size_t length = digest_len;
5531694Sdarrenm 		size_t cur_len;
5541694Sdarrenm 
5551694Sdarrenm 		SHA2Final(digest_tmp, sha2_ctx);
5561694Sdarrenm 
5571694Sdarrenm 		while (mp != NULL && length > 0) {
5581694Sdarrenm 			cur_len = MIN(MBLKL(mp) - offset, length);
5591694Sdarrenm 			bcopy(digest_tmp + scratch_offset,
5601694Sdarrenm 			    mp->b_rptr + offset, cur_len);
5611694Sdarrenm 
5621694Sdarrenm 			length -= cur_len;
5631694Sdarrenm 			mp = mp->b_cont;
5641694Sdarrenm 			scratch_offset += cur_len;
5651694Sdarrenm 			offset = 0;
5661694Sdarrenm 		}
5671694Sdarrenm 
5681694Sdarrenm 		if (mp == NULL && length > 0) {
5691694Sdarrenm 			/*
5701694Sdarrenm 			 * The end of the specified mblk was reached but
5711694Sdarrenm 			 * the length requested could not be processed, i.e.
5721694Sdarrenm 			 * The caller requested to digest more data than it
5731694Sdarrenm 			 * provided.
5741694Sdarrenm 			 */
5751694Sdarrenm 			return (CRYPTO_DATA_LEN_RANGE);
5761694Sdarrenm 		}
5771694Sdarrenm 	}
5781694Sdarrenm 
5791694Sdarrenm 	return (CRYPTO_SUCCESS);
5801694Sdarrenm }
5811694Sdarrenm 
5821694Sdarrenm /* ARGSUSED */
5831694Sdarrenm static int
sha2_digest(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * digest,crypto_req_handle_t req)5841694Sdarrenm sha2_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
5851694Sdarrenm     crypto_req_handle_t req)
5861694Sdarrenm {
5871694Sdarrenm 	int ret = CRYPTO_SUCCESS;
5881694Sdarrenm 	uint_t sha_digest_len;
5891694Sdarrenm 
5901694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
5911694Sdarrenm 
5921694Sdarrenm 	switch (PROV_SHA2_CTX(ctx)->sc_mech_type) {
5931694Sdarrenm 	case SHA256_MECH_INFO_TYPE:
5941694Sdarrenm 		sha_digest_len = SHA256_DIGEST_LENGTH;
5951694Sdarrenm 		break;
5961694Sdarrenm 	case SHA384_MECH_INFO_TYPE:
5971694Sdarrenm 		sha_digest_len = SHA384_DIGEST_LENGTH;
5981694Sdarrenm 		break;
5991694Sdarrenm 	case SHA512_MECH_INFO_TYPE:
6001694Sdarrenm 		sha_digest_len = SHA512_DIGEST_LENGTH;
6011694Sdarrenm 		break;
6021694Sdarrenm 	default:
6031694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
6041694Sdarrenm 	}
6051694Sdarrenm 
6061694Sdarrenm 	/*
6071694Sdarrenm 	 * We need to just return the length needed to store the output.
6081694Sdarrenm 	 * We should not destroy the context for the following cases.
6091694Sdarrenm 	 */
6101694Sdarrenm 	if ((digest->cd_length == 0) ||
6111694Sdarrenm 	    (digest->cd_length < sha_digest_len)) {
6121694Sdarrenm 		digest->cd_length = sha_digest_len;
6131694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
6141694Sdarrenm 	}
6151694Sdarrenm 
6161694Sdarrenm 	/*
6171694Sdarrenm 	 * Do the SHA2 update on the specified input data.
6181694Sdarrenm 	 */
6191694Sdarrenm 	switch (data->cd_format) {
6201694Sdarrenm 	case CRYPTO_DATA_RAW:
6211694Sdarrenm 		SHA2Update(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
6221694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
6231694Sdarrenm 		    data->cd_length);
6241694Sdarrenm 		break;
6251694Sdarrenm 	case CRYPTO_DATA_UIO:
6261694Sdarrenm 		ret = sha2_digest_update_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
6271694Sdarrenm 		    data);
6281694Sdarrenm 		break;
6291694Sdarrenm 	case CRYPTO_DATA_MBLK:
6301694Sdarrenm 		ret = sha2_digest_update_mblk(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
6311694Sdarrenm 		    data);
6321694Sdarrenm 		break;
6331694Sdarrenm 	default:
6341694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
6351694Sdarrenm 	}
6361694Sdarrenm 
6371694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
6381694Sdarrenm 		/* the update failed, free context and bail */
6391694Sdarrenm 		kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t));
6401694Sdarrenm 		ctx->cc_provider_private = NULL;
6411694Sdarrenm 		digest->cd_length = 0;
6421694Sdarrenm 		return (ret);
6431694Sdarrenm 	}
6441694Sdarrenm 
6451694Sdarrenm 	/*
6461694Sdarrenm 	 * Do a SHA2 final, must be done separately since the digest
6471694Sdarrenm 	 * type can be different than the input data type.
6481694Sdarrenm 	 */
6491694Sdarrenm 	switch (digest->cd_format) {
6501694Sdarrenm 	case CRYPTO_DATA_RAW:
6511694Sdarrenm 		SHA2Final((unsigned char *)digest->cd_raw.iov_base +
6521694Sdarrenm 		    digest->cd_offset, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx);
6531694Sdarrenm 		break;
6541694Sdarrenm 	case CRYPTO_DATA_UIO:
6551694Sdarrenm 		ret = sha2_digest_final_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
6561694Sdarrenm 		    digest, sha_digest_len, NULL);
6571694Sdarrenm 		break;
6581694Sdarrenm 	case CRYPTO_DATA_MBLK:
6591694Sdarrenm 		ret = sha2_digest_final_mblk(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
6601694Sdarrenm 		    digest, sha_digest_len, NULL);
6611694Sdarrenm 		break;
6621694Sdarrenm 	default:
6631694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
6641694Sdarrenm 	}
6651694Sdarrenm 
6661694Sdarrenm 	/* all done, free context and return */
6671694Sdarrenm 
6681694Sdarrenm 	if (ret == CRYPTO_SUCCESS)
6691694Sdarrenm 		digest->cd_length = sha_digest_len;
6701694Sdarrenm 	else
6711694Sdarrenm 		digest->cd_length = 0;
6721694Sdarrenm 
6731694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t));
6741694Sdarrenm 	ctx->cc_provider_private = NULL;
6751694Sdarrenm 	return (ret);
6761694Sdarrenm }
6771694Sdarrenm 
6781694Sdarrenm /* ARGSUSED */
6791694Sdarrenm static int
sha2_digest_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)6801694Sdarrenm sha2_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
6811694Sdarrenm     crypto_req_handle_t req)
6821694Sdarrenm {
6831694Sdarrenm 	int ret = CRYPTO_SUCCESS;
6841694Sdarrenm 
6851694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
6861694Sdarrenm 
6871694Sdarrenm 	/*
6881694Sdarrenm 	 * Do the SHA2 update on the specified input data.
6891694Sdarrenm 	 */
6901694Sdarrenm 	switch (data->cd_format) {
6911694Sdarrenm 	case CRYPTO_DATA_RAW:
6921694Sdarrenm 		SHA2Update(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
6931694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
6941694Sdarrenm 		    data->cd_length);
6951694Sdarrenm 		break;
6961694Sdarrenm 	case CRYPTO_DATA_UIO:
6971694Sdarrenm 		ret = sha2_digest_update_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
6981694Sdarrenm 		    data);
6991694Sdarrenm 		break;
7001694Sdarrenm 	case CRYPTO_DATA_MBLK:
7011694Sdarrenm 		ret = sha2_digest_update_mblk(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
7021694Sdarrenm 		    data);
7031694Sdarrenm 		break;
7041694Sdarrenm 	default:
7051694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
7061694Sdarrenm 	}
7071694Sdarrenm 
7081694Sdarrenm 	return (ret);
7091694Sdarrenm }
7101694Sdarrenm 
7111694Sdarrenm /* ARGSUSED */
7121694Sdarrenm static int
sha2_digest_final(crypto_ctx_t * ctx,crypto_data_t * digest,crypto_req_handle_t req)7131694Sdarrenm sha2_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
7141694Sdarrenm     crypto_req_handle_t req)
7151694Sdarrenm {
7161694Sdarrenm 	int ret = CRYPTO_SUCCESS;
7171694Sdarrenm 	uint_t sha_digest_len;
7181694Sdarrenm 
7191694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
7201694Sdarrenm 
7211694Sdarrenm 	switch (PROV_SHA2_CTX(ctx)->sc_mech_type) {
7221694Sdarrenm 	case SHA256_MECH_INFO_TYPE:
7231694Sdarrenm 		sha_digest_len = SHA256_DIGEST_LENGTH;
7241694Sdarrenm 		break;
7251694Sdarrenm 	case SHA384_MECH_INFO_TYPE:
7261694Sdarrenm 		sha_digest_len = SHA384_DIGEST_LENGTH;
7271694Sdarrenm 		break;
7281694Sdarrenm 	case SHA512_MECH_INFO_TYPE:
7291694Sdarrenm 		sha_digest_len = SHA512_DIGEST_LENGTH;
7301694Sdarrenm 		break;
7311694Sdarrenm 	default:
7321694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
7331694Sdarrenm 	}
7341694Sdarrenm 
7351694Sdarrenm 	/*
7361694Sdarrenm 	 * We need to just return the length needed to store the output.
7371694Sdarrenm 	 * We should not destroy the context for the following cases.
7381694Sdarrenm 	 */
7391694Sdarrenm 	if ((digest->cd_length == 0) ||
7401694Sdarrenm 	    (digest->cd_length < sha_digest_len)) {
7411694Sdarrenm 		digest->cd_length = sha_digest_len;
7421694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
7431694Sdarrenm 	}
7441694Sdarrenm 
7451694Sdarrenm 	/*
7461694Sdarrenm 	 * Do a SHA2 final.
7471694Sdarrenm 	 */
7481694Sdarrenm 	switch (digest->cd_format) {
7491694Sdarrenm 	case CRYPTO_DATA_RAW:
7501694Sdarrenm 		SHA2Final((unsigned char *)digest->cd_raw.iov_base +
7511694Sdarrenm 		    digest->cd_offset, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx);
7521694Sdarrenm 		break;
7531694Sdarrenm 	case CRYPTO_DATA_UIO:
7541694Sdarrenm 		ret = sha2_digest_final_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
7551694Sdarrenm 		    digest, sha_digest_len, NULL);
7561694Sdarrenm 		break;
7571694Sdarrenm 	case CRYPTO_DATA_MBLK:
7581694Sdarrenm 		ret = sha2_digest_final_mblk(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
7591694Sdarrenm 		    digest, sha_digest_len, NULL);
7601694Sdarrenm 		break;
7611694Sdarrenm 	default:
7621694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
7631694Sdarrenm 	}
7641694Sdarrenm 
7651694Sdarrenm 	/* all done, free context and return */
7661694Sdarrenm 
7671694Sdarrenm 	if (ret == CRYPTO_SUCCESS)
7681694Sdarrenm 		digest->cd_length = sha_digest_len;
7691694Sdarrenm 	else
7701694Sdarrenm 		digest->cd_length = 0;
7711694Sdarrenm 
7721694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t));
7731694Sdarrenm 	ctx->cc_provider_private = NULL;
7741694Sdarrenm 
7751694Sdarrenm 	return (ret);
7761694Sdarrenm }
7771694Sdarrenm 
7781694Sdarrenm /* ARGSUSED */
7791694Sdarrenm static int
sha2_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)7801694Sdarrenm sha2_digest_atomic(crypto_provider_handle_t provider,
7811694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
7821694Sdarrenm     crypto_data_t *data, crypto_data_t *digest,
7831694Sdarrenm     crypto_req_handle_t req)
7841694Sdarrenm {
7851694Sdarrenm 	int ret = CRYPTO_SUCCESS;
7861694Sdarrenm 	SHA2_CTX sha2_ctx;
7871694Sdarrenm 	uint32_t sha_digest_len;
7881694Sdarrenm 
7891694Sdarrenm 	/*
7901694Sdarrenm 	 * Do the SHA inits.
7911694Sdarrenm 	 */
7921694Sdarrenm 
7931694Sdarrenm 	SHA2Init(mechanism->cm_type, &sha2_ctx);
7941694Sdarrenm 
7951694Sdarrenm 	switch (data->cd_format) {
7961694Sdarrenm 	case CRYPTO_DATA_RAW:
7971694Sdarrenm 		SHA2Update(&sha2_ctx, (uint8_t *)data->
7981694Sdarrenm 		    cd_raw.iov_base + data->cd_offset, data->cd_length);
7991694Sdarrenm 		break;
8001694Sdarrenm 	case CRYPTO_DATA_UIO:
8011694Sdarrenm 		ret = sha2_digest_update_uio(&sha2_ctx, data);
8021694Sdarrenm 		break;
8031694Sdarrenm 	case CRYPTO_DATA_MBLK:
8041694Sdarrenm 		ret = sha2_digest_update_mblk(&sha2_ctx, data);
8051694Sdarrenm 		break;
8061694Sdarrenm 	default:
8071694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
8081694Sdarrenm 	}
8091694Sdarrenm 
8101694Sdarrenm 	/*
8111694Sdarrenm 	 * Do the SHA updates on the specified input data.
8121694Sdarrenm 	 */
8131694Sdarrenm 
8141694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
8151694Sdarrenm 		/* the update failed, bail */
8161694Sdarrenm 		digest->cd_length = 0;
8171694Sdarrenm 		return (ret);
8181694Sdarrenm 	}
8191694Sdarrenm 
8201694Sdarrenm 	if (mechanism->cm_type <= SHA256_HMAC_GEN_MECH_INFO_TYPE)
8211694Sdarrenm 		sha_digest_len = SHA256_DIGEST_LENGTH;
8221694Sdarrenm 	else
8231694Sdarrenm 		sha_digest_len = SHA512_DIGEST_LENGTH;
8241694Sdarrenm 
8251694Sdarrenm 	/*
8261694Sdarrenm 	 * Do a SHA2 final, must be done separately since the digest
8271694Sdarrenm 	 * type can be different than the input data type.
8281694Sdarrenm 	 */
8291694Sdarrenm 	switch (digest->cd_format) {
8301694Sdarrenm 	case CRYPTO_DATA_RAW:
8311694Sdarrenm 		SHA2Final((unsigned char *)digest->cd_raw.iov_base +
8321694Sdarrenm 		    digest->cd_offset, &sha2_ctx);
8331694Sdarrenm 		break;
8341694Sdarrenm 	case CRYPTO_DATA_UIO:
8351694Sdarrenm 		ret = sha2_digest_final_uio(&sha2_ctx, digest,
8361694Sdarrenm 		    sha_digest_len, NULL);
8371694Sdarrenm 		break;
8381694Sdarrenm 	case CRYPTO_DATA_MBLK:
8391694Sdarrenm 		ret = sha2_digest_final_mblk(&sha2_ctx, digest,
8401694Sdarrenm 		    sha_digest_len, NULL);
8411694Sdarrenm 		break;
8421694Sdarrenm 	default:
8431694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
8441694Sdarrenm 	}
8451694Sdarrenm 
8461694Sdarrenm 	if (ret == CRYPTO_SUCCESS)
8471694Sdarrenm 		digest->cd_length = sha_digest_len;
8481694Sdarrenm 	else
8491694Sdarrenm 		digest->cd_length = 0;
8501694Sdarrenm 
8511694Sdarrenm 	return (ret);
8521694Sdarrenm }
8531694Sdarrenm 
8541694Sdarrenm /*
8551694Sdarrenm  * KCF software provider mac entry points.
8561694Sdarrenm  *
8571694Sdarrenm  * SHA2 HMAC is: SHA2(key XOR opad, SHA2(key XOR ipad, text))
8581694Sdarrenm  *
8591694Sdarrenm  * Init:
8601694Sdarrenm  * The initialization routine initializes what we denote
8611694Sdarrenm  * as the inner and outer contexts by doing
8621694Sdarrenm  * - for inner context: SHA2(key XOR ipad)
8631694Sdarrenm  * - for outer context: SHA2(key XOR opad)
8641694Sdarrenm  *
8651694Sdarrenm  * Update:
8661694Sdarrenm  * Each subsequent SHA2 HMAC update will result in an
8671694Sdarrenm  * update of the inner context with the specified data.
8681694Sdarrenm  *
8691694Sdarrenm  * Final:
8701694Sdarrenm  * The SHA2 HMAC final will do a SHA2 final operation on the
8711694Sdarrenm  * inner context, and the resulting digest will be used
8721694Sdarrenm  * as the data for an update on the outer context. Last
8731694Sdarrenm  * but not least, a SHA2 final on the outer context will
8741694Sdarrenm  * be performed to obtain the SHA2 HMAC digest to return
8751694Sdarrenm  * to the user.
8761694Sdarrenm  */
8771694Sdarrenm 
8781694Sdarrenm /*
8791694Sdarrenm  * Initialize a SHA2-HMAC context.
8801694Sdarrenm  */
8811694Sdarrenm static void
sha2_mac_init_ctx(sha2_hmac_ctx_t * ctx,void * keyval,uint_t length_in_bytes)8821694Sdarrenm sha2_mac_init_ctx(sha2_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
8831694Sdarrenm {
8841694Sdarrenm 	uint64_t ipad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)];
8851694Sdarrenm 	uint64_t opad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)];
8861694Sdarrenm 	int i, block_size, blocks_per_int64;
8871694Sdarrenm 
8881694Sdarrenm 	/* Determine the block size */
8891694Sdarrenm 	if (ctx->hc_mech_type <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
8901694Sdarrenm 		block_size = SHA256_HMAC_BLOCK_SIZE;
8911694Sdarrenm 		blocks_per_int64 = SHA256_HMAC_BLOCK_SIZE / sizeof (uint64_t);
8921694Sdarrenm 	} else {
8931694Sdarrenm 		block_size = SHA512_HMAC_BLOCK_SIZE;
8941694Sdarrenm 		blocks_per_int64 = SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t);
8951694Sdarrenm 	}
8961694Sdarrenm 
8971694Sdarrenm 	(void) bzero(ipad, block_size);
8981694Sdarrenm 	(void) bzero(opad, block_size);
8991694Sdarrenm 	(void) bcopy(keyval, ipad, length_in_bytes);
9001694Sdarrenm 	(void) bcopy(keyval, opad, length_in_bytes);
9011694Sdarrenm 
9021694Sdarrenm 	/* XOR key with ipad (0x36) and opad (0x5c) */
9031694Sdarrenm 	for (i = 0; i < blocks_per_int64; i ++) {
9041694Sdarrenm 		ipad[i] ^= 0x3636363636363636;
9051694Sdarrenm 		opad[i] ^= 0x5c5c5c5c5c5c5c5c;
9061694Sdarrenm 	}
9071694Sdarrenm 
9081694Sdarrenm 	/* perform SHA2 on ipad */
9091694Sdarrenm 	SHA2Init(ctx->hc_mech_type, &ctx->hc_icontext);
9101694Sdarrenm 	SHA2Update(&ctx->hc_icontext, (uint8_t *)ipad, block_size);
9111694Sdarrenm 
9121694Sdarrenm 	/* perform SHA2 on opad */
9131694Sdarrenm 	SHA2Init(ctx->hc_mech_type, &ctx->hc_ocontext);
9141694Sdarrenm 	SHA2Update(&ctx->hc_ocontext, (uint8_t *)opad, block_size);
9151694Sdarrenm 
9161694Sdarrenm }
9171694Sdarrenm 
9181694Sdarrenm /*
9191694Sdarrenm  */
9201694Sdarrenm static int
sha2_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)9211694Sdarrenm sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
9221694Sdarrenm     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
9231694Sdarrenm     crypto_req_handle_t req)
9241694Sdarrenm {
9251694Sdarrenm 	int ret = CRYPTO_SUCCESS;
9261694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
9271694Sdarrenm 	uint_t sha_digest_len, sha_hmac_block_size;
9281694Sdarrenm 
9291694Sdarrenm 	/*
93011141Sopensolaris@drydog.com 	 * Set the digest length and block size to values appropriate to the
9311694Sdarrenm 	 * mechanism
9321694Sdarrenm 	 */
9331694Sdarrenm 	switch (mechanism->cm_type) {
9341694Sdarrenm 	case SHA256_HMAC_MECH_INFO_TYPE:
9351694Sdarrenm 	case SHA256_HMAC_GEN_MECH_INFO_TYPE:
9361694Sdarrenm 		sha_digest_len = SHA256_DIGEST_LENGTH;
9371694Sdarrenm 		sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE;
9381694Sdarrenm 		break;
9391694Sdarrenm 	case SHA384_HMAC_MECH_INFO_TYPE:
9401694Sdarrenm 	case SHA384_HMAC_GEN_MECH_INFO_TYPE:
9411694Sdarrenm 	case SHA512_HMAC_MECH_INFO_TYPE:
9421694Sdarrenm 	case SHA512_HMAC_GEN_MECH_INFO_TYPE:
9431694Sdarrenm 		sha_digest_len = SHA512_DIGEST_LENGTH;
9441694Sdarrenm 		sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
9451694Sdarrenm 		break;
9461694Sdarrenm 	default:
9471694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
9481694Sdarrenm 	}
9491694Sdarrenm 
9501694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
9511694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
9521694Sdarrenm 
9531694Sdarrenm 	ctx->cc_provider_private = kmem_alloc(sizeof (sha2_hmac_ctx_t),
9541694Sdarrenm 	    crypto_kmflag(req));
9551694Sdarrenm 	if (ctx->cc_provider_private == NULL)
9561694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
9571694Sdarrenm 
9584072Skrishna 	PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;
9591694Sdarrenm 	if (ctx_template != NULL) {
9601694Sdarrenm 		/* reuse context template */
9611694Sdarrenm 		bcopy(ctx_template, PROV_SHA2_HMAC_CTX(ctx),
9621694Sdarrenm 		    sizeof (sha2_hmac_ctx_t));
9631694Sdarrenm 	} else {
9641694Sdarrenm 		/* no context template, compute context */
9651694Sdarrenm 		if (keylen_in_bytes > sha_hmac_block_size) {
9661694Sdarrenm 			uchar_t digested_key[SHA512_DIGEST_LENGTH];
9671694Sdarrenm 			sha2_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;
9681694Sdarrenm 
9691694Sdarrenm 			/*
9701694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
9711694Sdarrenm 			 * The inner context is used since it hasn't been
9721694Sdarrenm 			 * initialized yet.
9731694Sdarrenm 			 */
9741694Sdarrenm 			PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
9751694Sdarrenm 			    &hmac_ctx->hc_icontext,
9761694Sdarrenm 			    key->ck_data, keylen_in_bytes, digested_key);
9771694Sdarrenm 			sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx),
9781694Sdarrenm 			    digested_key, sha_digest_len);
9791694Sdarrenm 		} else {
9801694Sdarrenm 			sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx),
9811694Sdarrenm 			    key->ck_data, keylen_in_bytes);
9821694Sdarrenm 		}
9831694Sdarrenm 	}
9841694Sdarrenm 
9851694Sdarrenm 	/*
9861694Sdarrenm 	 * Get the mechanism parameters, if applicable.
9871694Sdarrenm 	 */
9881694Sdarrenm 	if (mechanism->cm_type % 3 == 2) {
9891694Sdarrenm 		if (mechanism->cm_param == NULL ||
9901694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t))
9911694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
9921694Sdarrenm 		PROV_SHA2_GET_DIGEST_LEN(mechanism,
9931694Sdarrenm 		    PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len);
9941694Sdarrenm 		if (PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len > sha_digest_len)
9951694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
9961694Sdarrenm 	}
9971694Sdarrenm 
9981694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
9991694Sdarrenm 		bzero(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
10001694Sdarrenm 		kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
10011694Sdarrenm 		ctx->cc_provider_private = NULL;
10021694Sdarrenm 	}
10031694Sdarrenm 
10041694Sdarrenm 	return (ret);
10051694Sdarrenm }
10061694Sdarrenm 
10071694Sdarrenm /* ARGSUSED */
10081694Sdarrenm static int
sha2_mac_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)10091694Sdarrenm sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data,
10101694Sdarrenm     crypto_req_handle_t req)
10111694Sdarrenm {
10121694Sdarrenm 	int ret = CRYPTO_SUCCESS;
10131694Sdarrenm 
10141694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
10151694Sdarrenm 
10161694Sdarrenm 	/*
10171694Sdarrenm 	 * Do a SHA2 update of the inner context using the specified
10181694Sdarrenm 	 * data.
10191694Sdarrenm 	 */
10201694Sdarrenm 	switch (data->cd_format) {
10211694Sdarrenm 	case CRYPTO_DATA_RAW:
10221694Sdarrenm 		SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_icontext,
10231694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
10241694Sdarrenm 		    data->cd_length);
10251694Sdarrenm 		break;
10261694Sdarrenm 	case CRYPTO_DATA_UIO:
10271694Sdarrenm 		ret = sha2_digest_update_uio(
10281694Sdarrenm 		    &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, data);
10291694Sdarrenm 		break;
10301694Sdarrenm 	case CRYPTO_DATA_MBLK:
10311694Sdarrenm 		ret = sha2_digest_update_mblk(
10321694Sdarrenm 		    &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, data);
10331694Sdarrenm 		break;
10341694Sdarrenm 	default:
10351694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
10361694Sdarrenm 	}
10371694Sdarrenm 
10381694Sdarrenm 	return (ret);
10391694Sdarrenm }
10401694Sdarrenm 
10411694Sdarrenm /* ARGSUSED */
10421694Sdarrenm static int
sha2_mac_final(crypto_ctx_t * ctx,crypto_data_t * mac,crypto_req_handle_t req)10431694Sdarrenm sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
10441694Sdarrenm {
10451694Sdarrenm 	int ret = CRYPTO_SUCCESS;
10461694Sdarrenm 	uchar_t digest[SHA512_DIGEST_LENGTH];
10471694Sdarrenm 	uint32_t digest_len, sha_digest_len;
10481694Sdarrenm 
10491694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
10501694Sdarrenm 
105111141Sopensolaris@drydog.com 	/* Set the digest lengths to values appropriate to the mechanism */
10521694Sdarrenm 	switch (PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type) {
10531694Sdarrenm 	case SHA256_HMAC_MECH_INFO_TYPE:
10541694Sdarrenm 		sha_digest_len = digest_len = SHA256_DIGEST_LENGTH;
10551694Sdarrenm 		break;
10561694Sdarrenm 	case SHA384_HMAC_MECH_INFO_TYPE:
10574072Skrishna 		sha_digest_len = digest_len = SHA384_DIGEST_LENGTH;
10584072Skrishna 		break;
10591694Sdarrenm 	case SHA512_HMAC_MECH_INFO_TYPE:
10601694Sdarrenm 		sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
10611694Sdarrenm 		break;
10621694Sdarrenm 	case SHA256_HMAC_GEN_MECH_INFO_TYPE:
10631694Sdarrenm 		sha_digest_len = SHA256_DIGEST_LENGTH;
10641694Sdarrenm 		digest_len = PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len;
10651694Sdarrenm 		break;
10661694Sdarrenm 	case SHA384_HMAC_GEN_MECH_INFO_TYPE:
10671694Sdarrenm 	case SHA512_HMAC_GEN_MECH_INFO_TYPE:
10681694Sdarrenm 		sha_digest_len = SHA512_DIGEST_LENGTH;
10691694Sdarrenm 		digest_len = PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len;
10701694Sdarrenm 		break;
10711694Sdarrenm 	}
10721694Sdarrenm 
10731694Sdarrenm 	/*
10741694Sdarrenm 	 * We need to just return the length needed to store the output.
10751694Sdarrenm 	 * We should not destroy the context for the following cases.
10761694Sdarrenm 	 */
10771694Sdarrenm 	if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {
10781694Sdarrenm 		mac->cd_length = digest_len;
10791694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
10801694Sdarrenm 	}
10811694Sdarrenm 
10821694Sdarrenm 	/*
10831694Sdarrenm 	 * Do a SHA2 final on the inner context.
10841694Sdarrenm 	 */
10851694Sdarrenm 	SHA2Final(digest, &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext);
10861694Sdarrenm 
10871694Sdarrenm 	/*
10881694Sdarrenm 	 * Do a SHA2 update on the outer context, feeding the inner
10891694Sdarrenm 	 * digest as data.
10901694Sdarrenm 	 */
10911694Sdarrenm 	SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, digest,
10921694Sdarrenm 	    sha_digest_len);
10931694Sdarrenm 
10941694Sdarrenm 	/*
10951694Sdarrenm 	 * Do a SHA2 final on the outer context, storing the computing
10961694Sdarrenm 	 * digest in the users buffer.
10971694Sdarrenm 	 */
10981694Sdarrenm 	switch (mac->cd_format) {
10991694Sdarrenm 	case CRYPTO_DATA_RAW:
11001694Sdarrenm 		if (digest_len != sha_digest_len) {
11011694Sdarrenm 			/*
11021694Sdarrenm 			 * The caller requested a short digest. Digest
11031694Sdarrenm 			 * into a scratch buffer and return to
11041694Sdarrenm 			 * the user only what was requested.
11051694Sdarrenm 			 */
11061694Sdarrenm 			SHA2Final(digest,
11071694Sdarrenm 			    &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext);
11081694Sdarrenm 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
11091694Sdarrenm 			    mac->cd_offset, digest_len);
11101694Sdarrenm 		} else {
11111694Sdarrenm 			SHA2Final((unsigned char *)mac->cd_raw.iov_base +
11121694Sdarrenm 			    mac->cd_offset,
11131694Sdarrenm 			    &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext);
11141694Sdarrenm 		}
11151694Sdarrenm 		break;
11161694Sdarrenm 	case CRYPTO_DATA_UIO:
11171694Sdarrenm 		ret = sha2_digest_final_uio(
11181694Sdarrenm 		    &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, mac,
11191694Sdarrenm 		    digest_len, digest);
11201694Sdarrenm 		break;
11211694Sdarrenm 	case CRYPTO_DATA_MBLK:
11221694Sdarrenm 		ret = sha2_digest_final_mblk(
11231694Sdarrenm 		    &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, mac,
11241694Sdarrenm 		    digest_len, digest);
11251694Sdarrenm 		break;
11261694Sdarrenm 	default:
11271694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
11281694Sdarrenm 	}
11291694Sdarrenm 
11301694Sdarrenm 	if (ret == CRYPTO_SUCCESS)
11311694Sdarrenm 		mac->cd_length = digest_len;
11321694Sdarrenm 	else
11331694Sdarrenm 		mac->cd_length = 0;
11341694Sdarrenm 
11354072Skrishna 	bzero(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
11361694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
11371694Sdarrenm 	ctx->cc_provider_private = NULL;
11381694Sdarrenm 
11391694Sdarrenm 	return (ret);
11401694Sdarrenm }
11411694Sdarrenm 
11421694Sdarrenm #define	SHA2_MAC_UPDATE(data, ctx, ret) {				\
11431694Sdarrenm 	switch (data->cd_format) {					\
11441694Sdarrenm 	case CRYPTO_DATA_RAW:						\
11451694Sdarrenm 		SHA2Update(&(ctx).hc_icontext,				\
11461694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base +			\
11471694Sdarrenm 		    data->cd_offset, data->cd_length);			\
11481694Sdarrenm 		break;							\
11491694Sdarrenm 	case CRYPTO_DATA_UIO:						\
11501694Sdarrenm 		ret = sha2_digest_update_uio(&(ctx).hc_icontext, data);	\
11511694Sdarrenm 		break;							\
11521694Sdarrenm 	case CRYPTO_DATA_MBLK:						\
11531694Sdarrenm 		ret = sha2_digest_update_mblk(&(ctx).hc_icontext,	\
11541694Sdarrenm 		    data);						\
11551694Sdarrenm 		break;							\
11561694Sdarrenm 	default:							\
11571694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;				\
11581694Sdarrenm 	}								\
11591694Sdarrenm }
11601694Sdarrenm 
11611694Sdarrenm /* ARGSUSED */
11621694Sdarrenm static int
sha2_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)11631694Sdarrenm sha2_mac_atomic(crypto_provider_handle_t provider,
11641694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
11651694Sdarrenm     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
11661694Sdarrenm     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
11671694Sdarrenm {
11681694Sdarrenm 	int ret = CRYPTO_SUCCESS;
11691694Sdarrenm 	uchar_t digest[SHA512_DIGEST_LENGTH];
11701694Sdarrenm 	sha2_hmac_ctx_t sha2_hmac_ctx;
11711694Sdarrenm 	uint32_t sha_digest_len, digest_len, sha_hmac_block_size;
11721694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
11731694Sdarrenm 
11741694Sdarrenm 	/*
117511141Sopensolaris@drydog.com 	 * Set the digest length and block size to values appropriate to the
11761694Sdarrenm 	 * mechanism
11771694Sdarrenm 	 */
11781694Sdarrenm 	switch (mechanism->cm_type) {
11791694Sdarrenm 	case SHA256_HMAC_MECH_INFO_TYPE:
11801694Sdarrenm 	case SHA256_HMAC_GEN_MECH_INFO_TYPE:
11811694Sdarrenm 		sha_digest_len = digest_len = SHA256_DIGEST_LENGTH;
11821694Sdarrenm 		sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE;
11831694Sdarrenm 		break;
11841694Sdarrenm 	case SHA384_HMAC_MECH_INFO_TYPE:
11851694Sdarrenm 	case SHA384_HMAC_GEN_MECH_INFO_TYPE:
11861694Sdarrenm 	case SHA512_HMAC_MECH_INFO_TYPE:
11871694Sdarrenm 	case SHA512_HMAC_GEN_MECH_INFO_TYPE:
11881694Sdarrenm 		sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
11891694Sdarrenm 		sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
11901694Sdarrenm 		break;
11911694Sdarrenm 	default:
11921694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
11931694Sdarrenm 	}
11941694Sdarrenm 
11951694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
11961694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
11971694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
11981694Sdarrenm 
11991694Sdarrenm 	if (ctx_template != NULL) {
12001694Sdarrenm 		/* reuse context template */
12011694Sdarrenm 		bcopy(ctx_template, &sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
12021694Sdarrenm 	} else {
12031694Sdarrenm 		sha2_hmac_ctx.hc_mech_type = mechanism->cm_type;
12041694Sdarrenm 		/* no context template, initialize context */
12051694Sdarrenm 		if (keylen_in_bytes > sha_hmac_block_size) {
12061694Sdarrenm 			/*
12071694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
12081694Sdarrenm 			 * The inner context is used since it hasn't been
12091694Sdarrenm 			 * initialized yet.
12101694Sdarrenm 			 */
12111694Sdarrenm 			PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
12121694Sdarrenm 			    &sha2_hmac_ctx.hc_icontext,
12131694Sdarrenm 			    key->ck_data, keylen_in_bytes, digest);
12141694Sdarrenm 			sha2_mac_init_ctx(&sha2_hmac_ctx, digest,
12151694Sdarrenm 			    sha_digest_len);
12161694Sdarrenm 		} else {
12171694Sdarrenm 			sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data,
12181694Sdarrenm 			    keylen_in_bytes);
12191694Sdarrenm 		}
12201694Sdarrenm 	}
12211694Sdarrenm 
12221694Sdarrenm 	/* get the mechanism parameters, if applicable */
12231694Sdarrenm 	if ((mechanism->cm_type % 3) == 2) {
12241694Sdarrenm 		if (mechanism->cm_param == NULL ||
12251694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t)) {
12261694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
12271694Sdarrenm 			goto bail;
12281694Sdarrenm 		}
12291694Sdarrenm 		PROV_SHA2_GET_DIGEST_LEN(mechanism, digest_len);
12301694Sdarrenm 		if (digest_len > sha_digest_len) {
12311694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
12321694Sdarrenm 			goto bail;
12331694Sdarrenm 		}
12341694Sdarrenm 	}
12351694Sdarrenm 
12361694Sdarrenm 	/* do a SHA2 update of the inner context using the specified data */
12371694Sdarrenm 	SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret);
12381694Sdarrenm 	if (ret != CRYPTO_SUCCESS)
12391694Sdarrenm 		/* the update failed, free context and bail */
12401694Sdarrenm 		goto bail;
12411694Sdarrenm 
12421694Sdarrenm 	/*
12431694Sdarrenm 	 * Do a SHA2 final on the inner context.
12441694Sdarrenm 	 */
12451694Sdarrenm 	SHA2Final(digest, &sha2_hmac_ctx.hc_icontext);
12461694Sdarrenm 
12471694Sdarrenm 	/*
12481694Sdarrenm 	 * Do an SHA2 update on the outer context, feeding the inner
12491694Sdarrenm 	 * digest as data.
12501694Sdarrenm 	 *
12516126Sdanmcd 	 * HMAC-SHA384 needs special handling as the outer hash needs only 48
12526126Sdanmcd 	 * bytes of the inner hash value.
12531694Sdarrenm 	 */
12541694Sdarrenm 	if (mechanism->cm_type == SHA384_HMAC_MECH_INFO_TYPE ||
12551694Sdarrenm 	    mechanism->cm_type == SHA384_HMAC_GEN_MECH_INFO_TYPE)
12561694Sdarrenm 		SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest,
12571694Sdarrenm 		    SHA384_DIGEST_LENGTH);
12581694Sdarrenm 	else
12591694Sdarrenm 		SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len);
12601694Sdarrenm 
12611694Sdarrenm 	/*
12621694Sdarrenm 	 * Do a SHA2 final on the outer context, storing the computed
12631694Sdarrenm 	 * digest in the users buffer.
12641694Sdarrenm 	 */
12651694Sdarrenm 	switch (mac->cd_format) {
12661694Sdarrenm 	case CRYPTO_DATA_RAW:
12671694Sdarrenm 		if (digest_len != sha_digest_len) {
12681694Sdarrenm 			/*
12691694Sdarrenm 			 * The caller requested a short digest. Digest
12701694Sdarrenm 			 * into a scratch buffer and return to
12711694Sdarrenm 			 * the user only what was requested.
12721694Sdarrenm 			 */
12731694Sdarrenm 			SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext);
12741694Sdarrenm 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
12751694Sdarrenm 			    mac->cd_offset, digest_len);
12761694Sdarrenm 		} else {
12771694Sdarrenm 			SHA2Final((unsigned char *)mac->cd_raw.iov_base +
12781694Sdarrenm 			    mac->cd_offset, &sha2_hmac_ctx.hc_ocontext);
12791694Sdarrenm 		}
12801694Sdarrenm 		break;
12811694Sdarrenm 	case CRYPTO_DATA_UIO:
12821694Sdarrenm 		ret = sha2_digest_final_uio(&sha2_hmac_ctx.hc_ocontext, mac,
12831694Sdarrenm 		    digest_len, digest);
12841694Sdarrenm 		break;
12851694Sdarrenm 	case CRYPTO_DATA_MBLK:
12861694Sdarrenm 		ret = sha2_digest_final_mblk(&sha2_hmac_ctx.hc_ocontext, mac,
12871694Sdarrenm 		    digest_len, digest);
12881694Sdarrenm 		break;
12891694Sdarrenm 	default:
12901694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
12911694Sdarrenm 	}
12921694Sdarrenm 
12931694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
12941694Sdarrenm 		mac->cd_length = digest_len;
12951694Sdarrenm 		return (CRYPTO_SUCCESS);
12961694Sdarrenm 	}
12971694Sdarrenm bail:
12981694Sdarrenm 	bzero(&sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
12991694Sdarrenm 	mac->cd_length = 0;
13001694Sdarrenm 	return (ret);
13011694Sdarrenm }
13021694Sdarrenm 
13031694Sdarrenm /* ARGSUSED */
13041694Sdarrenm static int
sha2_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)13051694Sdarrenm sha2_mac_verify_atomic(crypto_provider_handle_t provider,
13061694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
13071694Sdarrenm     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
13081694Sdarrenm     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
13091694Sdarrenm {
13101694Sdarrenm 	int ret = CRYPTO_SUCCESS;
13111694Sdarrenm 	uchar_t digest[SHA512_DIGEST_LENGTH];
13121694Sdarrenm 	sha2_hmac_ctx_t sha2_hmac_ctx;
13131694Sdarrenm 	uint32_t sha_digest_len, digest_len, sha_hmac_block_size;
13141694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
13151694Sdarrenm 
13161694Sdarrenm 	/*
131711141Sopensolaris@drydog.com 	 * Set the digest length and block size to values appropriate to the
13181694Sdarrenm 	 * mechanism
13191694Sdarrenm 	 */
13201694Sdarrenm 	switch (mechanism->cm_type) {
13211694Sdarrenm 	case SHA256_HMAC_MECH_INFO_TYPE:
13221694Sdarrenm 	case SHA256_HMAC_GEN_MECH_INFO_TYPE:
13231694Sdarrenm 		sha_digest_len = digest_len = SHA256_DIGEST_LENGTH;
13241694Sdarrenm 		sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE;
13251694Sdarrenm 		break;
13261694Sdarrenm 	case SHA384_HMAC_MECH_INFO_TYPE:
13271694Sdarrenm 	case SHA384_HMAC_GEN_MECH_INFO_TYPE:
13281694Sdarrenm 	case SHA512_HMAC_MECH_INFO_TYPE:
13291694Sdarrenm 	case SHA512_HMAC_GEN_MECH_INFO_TYPE:
13301694Sdarrenm 		sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
13311694Sdarrenm 		sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
13321694Sdarrenm 		break;
13331694Sdarrenm 	default:
13341694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
13351694Sdarrenm 	}
13361694Sdarrenm 
13371694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
13381694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
13391694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
13401694Sdarrenm 
13411694Sdarrenm 	if (ctx_template != NULL) {
13421694Sdarrenm 		/* reuse context template */
13431694Sdarrenm 		bcopy(ctx_template, &sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
13441694Sdarrenm 	} else {
13459456SMark.Powers@Sun.COM 		sha2_hmac_ctx.hc_mech_type = mechanism->cm_type;
13461694Sdarrenm 		/* no context template, initialize context */
13471694Sdarrenm 		if (keylen_in_bytes > sha_hmac_block_size) {
13481694Sdarrenm 			/*
13491694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
13501694Sdarrenm 			 * The inner context is used since it hasn't been
13511694Sdarrenm 			 * initialized yet.
13521694Sdarrenm 			 */
13531694Sdarrenm 			PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
13541694Sdarrenm 			    &sha2_hmac_ctx.hc_icontext,
13551694Sdarrenm 			    key->ck_data, keylen_in_bytes, digest);
13561694Sdarrenm 			sha2_mac_init_ctx(&sha2_hmac_ctx, digest,
13571694Sdarrenm 			    sha_digest_len);
13581694Sdarrenm 		} else {
13591694Sdarrenm 			sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data,
13601694Sdarrenm 			    keylen_in_bytes);
13611694Sdarrenm 		}
13621694Sdarrenm 	}
13631694Sdarrenm 
13641694Sdarrenm 	/* get the mechanism parameters, if applicable */
13651694Sdarrenm 	if (mechanism->cm_type % 3 == 2) {
13661694Sdarrenm 		if (mechanism->cm_param == NULL ||
13671694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t)) {
13681694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
13691694Sdarrenm 			goto bail;
13701694Sdarrenm 		}
13711694Sdarrenm 		PROV_SHA2_GET_DIGEST_LEN(mechanism, digest_len);
13721694Sdarrenm 		if (digest_len > sha_digest_len) {
13731694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
13741694Sdarrenm 			goto bail;
13751694Sdarrenm 		}
13761694Sdarrenm 	}
13771694Sdarrenm 
13781694Sdarrenm 	if (mac->cd_length != digest_len) {
13791694Sdarrenm 		ret = CRYPTO_INVALID_MAC;
13801694Sdarrenm 		goto bail;
13811694Sdarrenm 	}
13821694Sdarrenm 
13831694Sdarrenm 	/* do a SHA2 update of the inner context using the specified data */
13841694Sdarrenm 	SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret);
13851694Sdarrenm 	if (ret != CRYPTO_SUCCESS)
13861694Sdarrenm 		/* the update failed, free context and bail */
13871694Sdarrenm 		goto bail;
13881694Sdarrenm 
13891694Sdarrenm 	/* do a SHA2 final on the inner context */
13901694Sdarrenm 	SHA2Final(digest, &sha2_hmac_ctx.hc_icontext);
13911694Sdarrenm 
13921694Sdarrenm 	/*
13931694Sdarrenm 	 * Do an SHA2 update on the outer context, feeding the inner
13941694Sdarrenm 	 * digest as data.
13956126Sdanmcd 	 *
13966126Sdanmcd 	 * HMAC-SHA384 needs special handling as the outer hash needs only 48
13976126Sdanmcd 	 * bytes of the inner hash value.
13981694Sdarrenm 	 */
13996126Sdanmcd 	if (mechanism->cm_type == SHA384_HMAC_MECH_INFO_TYPE ||
14006126Sdanmcd 	    mechanism->cm_type == SHA384_HMAC_GEN_MECH_INFO_TYPE)
14016126Sdanmcd 		SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest,
14026126Sdanmcd 		    SHA384_DIGEST_LENGTH);
14036126Sdanmcd 	else
14046126Sdanmcd 		SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len);
14051694Sdarrenm 
14061694Sdarrenm 	/*
14071694Sdarrenm 	 * Do a SHA2 final on the outer context, storing the computed
14081694Sdarrenm 	 * digest in the users buffer.
14091694Sdarrenm 	 */
14101694Sdarrenm 	SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext);
14111694Sdarrenm 
14121694Sdarrenm 	/*
14131694Sdarrenm 	 * Compare the computed digest against the expected digest passed
14141694Sdarrenm 	 * as argument.
14151694Sdarrenm 	 */
14161694Sdarrenm 
14171694Sdarrenm 	switch (mac->cd_format) {
14181694Sdarrenm 
14191694Sdarrenm 	case CRYPTO_DATA_RAW:
14201694Sdarrenm 		if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base +
14211694Sdarrenm 		    mac->cd_offset, digest_len) != 0)
14221694Sdarrenm 			ret = CRYPTO_INVALID_MAC;
14231694Sdarrenm 		break;
14241694Sdarrenm 
14251694Sdarrenm 	case CRYPTO_DATA_UIO: {
14261694Sdarrenm 		off_t offset = mac->cd_offset;
14271694Sdarrenm 		uint_t vec_idx;
14281694Sdarrenm 		off_t scratch_offset = 0;
14291694Sdarrenm 		size_t length = digest_len;
14301694Sdarrenm 		size_t cur_len;
14311694Sdarrenm 
14321694Sdarrenm 		/* we support only kernel buffer */
14331694Sdarrenm 		if (mac->cd_uio->uio_segflg != UIO_SYSSPACE)
14341694Sdarrenm 			return (CRYPTO_ARGUMENTS_BAD);
14351694Sdarrenm 
14361694Sdarrenm 		/* jump to the first iovec containing the expected digest */
14371694Sdarrenm 		for (vec_idx = 0;
14381694Sdarrenm 		    offset >= mac->cd_uio->uio_iov[vec_idx].iov_len &&
14391694Sdarrenm 		    vec_idx < mac->cd_uio->uio_iovcnt;
14405072Smcpowers 		    offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len)
14415072Smcpowers 			;
14421694Sdarrenm 		if (vec_idx == mac->cd_uio->uio_iovcnt) {
14431694Sdarrenm 			/*
14441694Sdarrenm 			 * The caller specified an offset that is
14451694Sdarrenm 			 * larger than the total size of the buffers
14461694Sdarrenm 			 * it provided.
14471694Sdarrenm 			 */
14481694Sdarrenm 			ret = CRYPTO_DATA_LEN_RANGE;
14491694Sdarrenm 			break;
14501694Sdarrenm 		}
14511694Sdarrenm 
14521694Sdarrenm 		/* do the comparison of computed digest vs specified one */
14531694Sdarrenm 		while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) {
14541694Sdarrenm 			cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len -
14551694Sdarrenm 			    offset, length);
14561694Sdarrenm 
14571694Sdarrenm 			if (bcmp(digest + scratch_offset,
14581694Sdarrenm 			    mac->cd_uio->uio_iov[vec_idx].iov_base + offset,
14591694Sdarrenm 			    cur_len) != 0) {
14601694Sdarrenm 				ret = CRYPTO_INVALID_MAC;
14611694Sdarrenm 				break;
14621694Sdarrenm 			}
14631694Sdarrenm 
14641694Sdarrenm 			length -= cur_len;
14651694Sdarrenm 			vec_idx++;
14661694Sdarrenm 			scratch_offset += cur_len;
14671694Sdarrenm 			offset = 0;
14681694Sdarrenm 		}
14691694Sdarrenm 		break;
14701694Sdarrenm 	}
14711694Sdarrenm 
14721694Sdarrenm 	case CRYPTO_DATA_MBLK: {
14731694Sdarrenm 		off_t offset = mac->cd_offset;
14741694Sdarrenm 		mblk_t *mp;
14751694Sdarrenm 		off_t scratch_offset = 0;
14761694Sdarrenm 		size_t length = digest_len;
14771694Sdarrenm 		size_t cur_len;
14781694Sdarrenm 
14791694Sdarrenm 		/* jump to the first mblk_t containing the expected digest */
14801694Sdarrenm 		for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp);
14815072Smcpowers 		    offset -= MBLKL(mp), mp = mp->b_cont)
14825072Smcpowers 			;
14831694Sdarrenm 		if (mp == NULL) {
14841694Sdarrenm 			/*
14851694Sdarrenm 			 * The caller specified an offset that is larger than
14861694Sdarrenm 			 * the total size of the buffers it provided.
14871694Sdarrenm 			 */
14881694Sdarrenm 			ret = CRYPTO_DATA_LEN_RANGE;
14891694Sdarrenm 			break;
14901694Sdarrenm 		}
14911694Sdarrenm 
14921694Sdarrenm 		while (mp != NULL && length > 0) {
14931694Sdarrenm 			cur_len = MIN(MBLKL(mp) - offset, length);
14941694Sdarrenm 			if (bcmp(digest + scratch_offset,
14951694Sdarrenm 			    mp->b_rptr + offset, cur_len) != 0) {
14961694Sdarrenm 				ret = CRYPTO_INVALID_MAC;
14971694Sdarrenm 				break;
14981694Sdarrenm 			}
14991694Sdarrenm 
15001694Sdarrenm 			length -= cur_len;
15011694Sdarrenm 			mp = mp->b_cont;
15021694Sdarrenm 			scratch_offset += cur_len;
15031694Sdarrenm 			offset = 0;
15041694Sdarrenm 		}
15051694Sdarrenm 		break;
15061694Sdarrenm 	}
15071694Sdarrenm 
15081694Sdarrenm 	default:
15091694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
15101694Sdarrenm 	}
15111694Sdarrenm 
15121694Sdarrenm 	return (ret);
15131694Sdarrenm bail:
15141694Sdarrenm 	bzero(&sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
15151694Sdarrenm 	mac->cd_length = 0;
15161694Sdarrenm 	return (ret);
15171694Sdarrenm }
15181694Sdarrenm 
15191694Sdarrenm /*
15201694Sdarrenm  * KCF software provider context management entry points.
15211694Sdarrenm  */
15221694Sdarrenm 
15231694Sdarrenm /* ARGSUSED */
15241694Sdarrenm static int
sha2_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)15251694Sdarrenm sha2_create_ctx_template(crypto_provider_handle_t provider,
15261694Sdarrenm     crypto_mechanism_t *mechanism, crypto_key_t *key,
15271694Sdarrenm     crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
15281694Sdarrenm     crypto_req_handle_t req)
15291694Sdarrenm {
15301694Sdarrenm 	sha2_hmac_ctx_t *sha2_hmac_ctx_tmpl;
15311694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
15321694Sdarrenm 	uint32_t sha_digest_len, sha_hmac_block_size;
15331694Sdarrenm 
15341694Sdarrenm 	/*
153511141Sopensolaris@drydog.com 	 * Set the digest length and block size to values appropriate to the
15361694Sdarrenm 	 * mechanism
15371694Sdarrenm 	 */
15381694Sdarrenm 	switch (mechanism->cm_type) {
15391694Sdarrenm 	case SHA256_HMAC_MECH_INFO_TYPE:
15401694Sdarrenm 	case SHA256_HMAC_GEN_MECH_INFO_TYPE:
15411694Sdarrenm 		sha_digest_len = SHA256_DIGEST_LENGTH;
15421694Sdarrenm 		sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE;
15431694Sdarrenm 		break;
15441694Sdarrenm 	case SHA384_HMAC_MECH_INFO_TYPE:
15451694Sdarrenm 	case SHA384_HMAC_GEN_MECH_INFO_TYPE:
15461694Sdarrenm 	case SHA512_HMAC_MECH_INFO_TYPE:
15471694Sdarrenm 	case SHA512_HMAC_GEN_MECH_INFO_TYPE:
15481694Sdarrenm 		sha_digest_len = SHA512_DIGEST_LENGTH;
15491694Sdarrenm 		sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
15501694Sdarrenm 		break;
15511694Sdarrenm 	default:
15521694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
15531694Sdarrenm 	}
15541694Sdarrenm 
15551694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
15561694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
15571694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
15581694Sdarrenm 
15591694Sdarrenm 	/*
15601694Sdarrenm 	 * Allocate and initialize SHA2 context.
15611694Sdarrenm 	 */
15621694Sdarrenm 	sha2_hmac_ctx_tmpl = kmem_alloc(sizeof (sha2_hmac_ctx_t),
15631694Sdarrenm 	    crypto_kmflag(req));
15641694Sdarrenm 	if (sha2_hmac_ctx_tmpl == NULL)
15651694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
15661694Sdarrenm 
15671694Sdarrenm 	sha2_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;
15681694Sdarrenm 
15691694Sdarrenm 	if (keylen_in_bytes > sha_hmac_block_size) {
15701694Sdarrenm 		uchar_t digested_key[SHA512_DIGEST_LENGTH];
15711694Sdarrenm 
15721694Sdarrenm 		/*
15731694Sdarrenm 		 * Hash the passed-in key to get a smaller key.
15741694Sdarrenm 		 * The inner context is used since it hasn't been
15751694Sdarrenm 		 * initialized yet.
15761694Sdarrenm 		 */
15771694Sdarrenm 		PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
15781694Sdarrenm 		    &sha2_hmac_ctx_tmpl->hc_icontext,
15791694Sdarrenm 		    key->ck_data, keylen_in_bytes, digested_key);
15801694Sdarrenm 		sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, digested_key,
15811694Sdarrenm 		    sha_digest_len);
15821694Sdarrenm 	} else {
15831694Sdarrenm 		sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, key->ck_data,
15841694Sdarrenm 		    keylen_in_bytes);
15851694Sdarrenm 	}
15861694Sdarrenm 
15871694Sdarrenm 	*ctx_template = (crypto_spi_ctx_template_t)sha2_hmac_ctx_tmpl;
15881694Sdarrenm 	*ctx_template_size = sizeof (sha2_hmac_ctx_t);
15891694Sdarrenm 
15901694Sdarrenm 	return (CRYPTO_SUCCESS);
15911694Sdarrenm }
15921694Sdarrenm 
15931694Sdarrenm static int
sha2_free_context(crypto_ctx_t * ctx)15941694Sdarrenm sha2_free_context(crypto_ctx_t *ctx)
15951694Sdarrenm {
15961694Sdarrenm 	uint_t ctx_len;
15971694Sdarrenm 
15981694Sdarrenm 	if (ctx->cc_provider_private == NULL)
15991694Sdarrenm 		return (CRYPTO_SUCCESS);
16001694Sdarrenm 
16011694Sdarrenm 	/*
16021694Sdarrenm 	 * We have to free either SHA2 or SHA2-HMAC contexts, which
16031694Sdarrenm 	 * have different lengths.
16041694Sdarrenm 	 *
16051694Sdarrenm 	 * Note: Below is dependent on the mechanism ordering.
16061694Sdarrenm 	 */
16071694Sdarrenm 
16081694Sdarrenm 	if (PROV_SHA2_CTX(ctx)->sc_mech_type % 3 == 0)
16091694Sdarrenm 		ctx_len = sizeof (sha2_ctx_t);
16101694Sdarrenm 	else
16111694Sdarrenm 		ctx_len = sizeof (sha2_hmac_ctx_t);
16121694Sdarrenm 
16131694Sdarrenm 	bzero(ctx->cc_provider_private, ctx_len);
16141694Sdarrenm 	kmem_free(ctx->cc_provider_private, ctx_len);
16151694Sdarrenm 	ctx->cc_provider_private = NULL;
16161694Sdarrenm 
16171694Sdarrenm 	return (CRYPTO_SUCCESS);
16181694Sdarrenm }
161910500SHai-May.Chao@Sun.COM 
162010500SHai-May.Chao@Sun.COM /*
162110500SHai-May.Chao@Sun.COM  * SHA-2 Power-Up Self-Test
162210500SHai-May.Chao@Sun.COM  */
162310500SHai-May.Chao@Sun.COM void
sha2_POST(int * rc)162410500SHai-May.Chao@Sun.COM sha2_POST(int *rc)
162510500SHai-May.Chao@Sun.COM {
162610500SHai-May.Chao@Sun.COM 
162710500SHai-May.Chao@Sun.COM 	*rc = fips_sha2_post();
162810500SHai-May.Chao@Sun.COM 
162910500SHai-May.Chao@Sun.COM }
1630