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