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 /* 239364SVladimir.Kotal@Sun.COM * Copyright 2009 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> 37*10500SHai-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))) \ 741694Sdarrenm (len) = (uint32_t)*((ulong_t *)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 1661694Sdarrenm static crypto_ops_t sha1_crypto_ops = { 1671694Sdarrenm &sha1_control_ops, 1681694Sdarrenm &sha1_digest_ops, 1691694Sdarrenm NULL, 1701694Sdarrenm &sha1_mac_ops, 1711694Sdarrenm NULL, 1721694Sdarrenm NULL, 1731694Sdarrenm NULL, 1741694Sdarrenm NULL, 1751694Sdarrenm NULL, 1761694Sdarrenm NULL, 1771694Sdarrenm NULL, 1781694Sdarrenm NULL, 1791694Sdarrenm NULL, 1801694Sdarrenm &sha1_ctx_ops 1811694Sdarrenm }; 1821694Sdarrenm 1831694Sdarrenm static crypto_provider_info_t sha1_prov_info = { 1841694Sdarrenm CRYPTO_SPI_VERSION_1, 1851694Sdarrenm "SHA1 Software Provider", 1861694Sdarrenm CRYPTO_SW_PROVIDER, 1871694Sdarrenm {&modlinkage}, 1881694Sdarrenm NULL, 1891694Sdarrenm &sha1_crypto_ops, 1901694Sdarrenm sizeof (sha1_mech_info_tab)/sizeof (crypto_mech_info_t), 1911694Sdarrenm sha1_mech_info_tab 1921694Sdarrenm }; 1931694Sdarrenm 1941694Sdarrenm static crypto_kcf_provider_handle_t sha1_prov_handle = NULL; 1951694Sdarrenm 1961694Sdarrenm int 1971694Sdarrenm _init() 1981694Sdarrenm { 1991694Sdarrenm int ret; 2001694Sdarrenm 2011694Sdarrenm if ((ret = mod_install(&modlinkage)) != 0) 2021694Sdarrenm return (ret); 2031694Sdarrenm 2041694Sdarrenm /* 2051694Sdarrenm * Register with KCF. If the registration fails, log an 2061694Sdarrenm * error but do not uninstall the module, since the functionality 2071694Sdarrenm * provided by misc/sha1 should still be available. 2081694Sdarrenm */ 2091694Sdarrenm if ((ret = crypto_register_provider(&sha1_prov_info, 2101694Sdarrenm &sha1_prov_handle)) != CRYPTO_SUCCESS) 2111694Sdarrenm cmn_err(CE_WARN, "sha1 _init: " 2121694Sdarrenm "crypto_register_provider() failed (0x%x)", ret); 2131694Sdarrenm 2141694Sdarrenm return (0); 2151694Sdarrenm } 2161694Sdarrenm 2171694Sdarrenm int 2181694Sdarrenm _info(struct modinfo *modinfop) 2191694Sdarrenm { 2201694Sdarrenm return (mod_info(&modlinkage, modinfop)); 2211694Sdarrenm } 2221694Sdarrenm 2231694Sdarrenm /* 2241694Sdarrenm * KCF software provider control entry points. 2251694Sdarrenm */ 2261694Sdarrenm /* ARGSUSED */ 2271694Sdarrenm static void 2281694Sdarrenm sha1_provider_status(crypto_provider_handle_t provider, uint_t *status) 2291694Sdarrenm { 2301694Sdarrenm *status = CRYPTO_PROVIDER_READY; 2311694Sdarrenm } 2321694Sdarrenm 2331694Sdarrenm /* 2341694Sdarrenm * KCF software provider digest entry points. 2351694Sdarrenm */ 2361694Sdarrenm 2371694Sdarrenm static int 2381694Sdarrenm sha1_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 2391694Sdarrenm crypto_req_handle_t req) 2401694Sdarrenm { 2411694Sdarrenm if (mechanism->cm_type != SHA1_MECH_INFO_TYPE) 2421694Sdarrenm return (CRYPTO_MECHANISM_INVALID); 2431694Sdarrenm 2441694Sdarrenm /* 2451694Sdarrenm * Allocate and initialize SHA1 context. 2461694Sdarrenm */ 2471694Sdarrenm ctx->cc_provider_private = kmem_alloc(sizeof (sha1_ctx_t), 2481694Sdarrenm crypto_kmflag(req)); 2491694Sdarrenm if (ctx->cc_provider_private == NULL) 2501694Sdarrenm return (CRYPTO_HOST_MEMORY); 2511694Sdarrenm 2521694Sdarrenm PROV_SHA1_CTX(ctx)->sc_mech_type = SHA1_MECH_INFO_TYPE; 2531694Sdarrenm SHA1Init(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx); 2541694Sdarrenm 2551694Sdarrenm return (CRYPTO_SUCCESS); 2561694Sdarrenm } 2571694Sdarrenm 2581694Sdarrenm /* 2591694Sdarrenm * Helper SHA1 digest update function for uio data. 2601694Sdarrenm */ 2611694Sdarrenm static int 2621694Sdarrenm sha1_digest_update_uio(SHA1_CTX *sha1_ctx, crypto_data_t *data) 2631694Sdarrenm { 2641694Sdarrenm off_t offset = data->cd_offset; 2651694Sdarrenm size_t length = data->cd_length; 2661694Sdarrenm uint_t vec_idx; 2671694Sdarrenm size_t cur_len; 2681694Sdarrenm 2691694Sdarrenm /* we support only kernel buffer */ 2701694Sdarrenm if (data->cd_uio->uio_segflg != UIO_SYSSPACE) 2711694Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 2721694Sdarrenm 2731694Sdarrenm /* 2741694Sdarrenm * Jump to the first iovec containing data to be 2751694Sdarrenm * digested. 2761694Sdarrenm */ 2771694Sdarrenm for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt && 2781694Sdarrenm offset >= data->cd_uio->uio_iov[vec_idx].iov_len; 2799364SVladimir.Kotal@Sun.COM offset -= data->cd_uio->uio_iov[vec_idx++].iov_len) 2809364SVladimir.Kotal@Sun.COM ; 2811694Sdarrenm if (vec_idx == data->cd_uio->uio_iovcnt) { 2821694Sdarrenm /* 2831694Sdarrenm * The caller specified an offset that is larger than the 2841694Sdarrenm * total size of the buffers it provided. 2851694Sdarrenm */ 2861694Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 2871694Sdarrenm } 2881694Sdarrenm 2891694Sdarrenm /* 2901694Sdarrenm * Now do the digesting on the iovecs. 2911694Sdarrenm */ 2921694Sdarrenm while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) { 2931694Sdarrenm cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len - 2941694Sdarrenm offset, length); 2951694Sdarrenm 2961694Sdarrenm SHA1Update(sha1_ctx, 2971694Sdarrenm (uint8_t *)data->cd_uio->uio_iov[vec_idx].iov_base + offset, 2981694Sdarrenm cur_len); 2991694Sdarrenm 3001694Sdarrenm length -= cur_len; 3011694Sdarrenm vec_idx++; 3021694Sdarrenm offset = 0; 3031694Sdarrenm } 3041694Sdarrenm 3051694Sdarrenm if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) { 3061694Sdarrenm /* 3071694Sdarrenm * The end of the specified iovec's was reached but 3081694Sdarrenm * the length requested could not be processed, i.e. 3091694Sdarrenm * The caller requested to digest more data than it provided. 3101694Sdarrenm */ 3111694Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 3121694Sdarrenm } 3131694Sdarrenm 3141694Sdarrenm return (CRYPTO_SUCCESS); 3151694Sdarrenm } 3161694Sdarrenm 3171694Sdarrenm /* 3181694Sdarrenm * Helper SHA1 digest final function for uio data. 3191694Sdarrenm * digest_len is the length of the desired digest. If digest_len 3201694Sdarrenm * is smaller than the default SHA1 digest length, the caller 3211694Sdarrenm * must pass a scratch buffer, digest_scratch, which must 3221694Sdarrenm * be at least SHA1_DIGEST_LENGTH bytes. 3231694Sdarrenm */ 3241694Sdarrenm static int 3251694Sdarrenm sha1_digest_final_uio(SHA1_CTX *sha1_ctx, crypto_data_t *digest, 3261694Sdarrenm ulong_t digest_len, uchar_t *digest_scratch) 3271694Sdarrenm { 3281694Sdarrenm off_t offset = digest->cd_offset; 3291694Sdarrenm uint_t vec_idx; 3301694Sdarrenm 3311694Sdarrenm /* we support only kernel buffer */ 3321694Sdarrenm if (digest->cd_uio->uio_segflg != UIO_SYSSPACE) 3331694Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 3341694Sdarrenm 3351694Sdarrenm /* 3361694Sdarrenm * Jump to the first iovec containing ptr to the digest to 3371694Sdarrenm * be returned. 3381694Sdarrenm */ 3391694Sdarrenm for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len && 3401694Sdarrenm vec_idx < digest->cd_uio->uio_iovcnt; 3419364SVladimir.Kotal@Sun.COM offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len) 3429364SVladimir.Kotal@Sun.COM ; 3431694Sdarrenm if (vec_idx == digest->cd_uio->uio_iovcnt) { 3441694Sdarrenm /* 3451694Sdarrenm * The caller specified an offset that is 3461694Sdarrenm * larger than the total size of the buffers 3471694Sdarrenm * it provided. 3481694Sdarrenm */ 3491694Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 3501694Sdarrenm } 3511694Sdarrenm 3521694Sdarrenm if (offset + digest_len <= 3531694Sdarrenm digest->cd_uio->uio_iov[vec_idx].iov_len) { 3541694Sdarrenm /* 3551694Sdarrenm * The computed SHA1 digest will fit in the current 3561694Sdarrenm * iovec. 3571694Sdarrenm */ 3581694Sdarrenm if (digest_len != SHA1_DIGEST_LENGTH) { 3591694Sdarrenm /* 3601694Sdarrenm * The caller requested a short digest. Digest 3611694Sdarrenm * into a scratch buffer and return to 3621694Sdarrenm * the user only what was requested. 3631694Sdarrenm */ 3641694Sdarrenm SHA1Final(digest_scratch, sha1_ctx); 3651694Sdarrenm bcopy(digest_scratch, (uchar_t *)digest-> 3661694Sdarrenm cd_uio->uio_iov[vec_idx].iov_base + offset, 3671694Sdarrenm digest_len); 3681694Sdarrenm } else { 3691694Sdarrenm SHA1Final((uchar_t *)digest-> 3701694Sdarrenm cd_uio->uio_iov[vec_idx].iov_base + offset, 3711694Sdarrenm sha1_ctx); 3721694Sdarrenm } 3731694Sdarrenm } else { 3741694Sdarrenm /* 3751694Sdarrenm * The computed digest will be crossing one or more iovec's. 3761694Sdarrenm * This is bad performance-wise but we need to support it. 3771694Sdarrenm * Allocate a small scratch buffer on the stack and 3781694Sdarrenm * copy it piece meal to the specified digest iovec's. 3791694Sdarrenm */ 3801694Sdarrenm uchar_t digest_tmp[SHA1_DIGEST_LENGTH]; 3811694Sdarrenm off_t scratch_offset = 0; 3821694Sdarrenm size_t length = digest_len; 3831694Sdarrenm size_t cur_len; 3841694Sdarrenm 3851694Sdarrenm SHA1Final(digest_tmp, sha1_ctx); 3861694Sdarrenm 3871694Sdarrenm while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) { 3881694Sdarrenm cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len - 3891694Sdarrenm offset, length); 3901694Sdarrenm bcopy(digest_tmp + scratch_offset, 3911694Sdarrenm digest->cd_uio->uio_iov[vec_idx].iov_base + offset, 3921694Sdarrenm cur_len); 3931694Sdarrenm 3941694Sdarrenm length -= cur_len; 3951694Sdarrenm vec_idx++; 3961694Sdarrenm scratch_offset += cur_len; 3971694Sdarrenm offset = 0; 3981694Sdarrenm } 3991694Sdarrenm 4001694Sdarrenm if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) { 4011694Sdarrenm /* 4021694Sdarrenm * The end of the specified iovec's was reached but 4031694Sdarrenm * the length requested could not be processed, i.e. 4041694Sdarrenm * The caller requested to digest more data than it 4051694Sdarrenm * provided. 4061694Sdarrenm */ 4071694Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 4081694Sdarrenm } 4091694Sdarrenm } 4101694Sdarrenm 4111694Sdarrenm return (CRYPTO_SUCCESS); 4121694Sdarrenm } 4131694Sdarrenm 4141694Sdarrenm /* 4151694Sdarrenm * Helper SHA1 digest update for mblk's. 4161694Sdarrenm */ 4171694Sdarrenm static int 4181694Sdarrenm sha1_digest_update_mblk(SHA1_CTX *sha1_ctx, crypto_data_t *data) 4191694Sdarrenm { 4201694Sdarrenm off_t offset = data->cd_offset; 4211694Sdarrenm size_t length = data->cd_length; 4221694Sdarrenm mblk_t *mp; 4231694Sdarrenm size_t cur_len; 4241694Sdarrenm 4251694Sdarrenm /* 4261694Sdarrenm * Jump to the first mblk_t containing data to be digested. 4271694Sdarrenm */ 4281694Sdarrenm for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp); 4299364SVladimir.Kotal@Sun.COM offset -= MBLKL(mp), mp = mp->b_cont) 4309364SVladimir.Kotal@Sun.COM ; 4311694Sdarrenm if (mp == NULL) { 4321694Sdarrenm /* 4331694Sdarrenm * The caller specified an offset that is larger than the 4341694Sdarrenm * total size of the buffers it provided. 4351694Sdarrenm */ 4361694Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 4371694Sdarrenm } 4381694Sdarrenm 4391694Sdarrenm /* 4401694Sdarrenm * Now do the digesting on the mblk chain. 4411694Sdarrenm */ 4421694Sdarrenm while (mp != NULL && length > 0) { 4431694Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 4441694Sdarrenm SHA1Update(sha1_ctx, mp->b_rptr + offset, cur_len); 4451694Sdarrenm length -= cur_len; 4461694Sdarrenm offset = 0; 4471694Sdarrenm mp = mp->b_cont; 4481694Sdarrenm } 4491694Sdarrenm 4501694Sdarrenm if (mp == NULL && length > 0) { 4511694Sdarrenm /* 4521694Sdarrenm * The end of the mblk was reached but the length requested 4531694Sdarrenm * could not be processed, i.e. The caller requested 4541694Sdarrenm * to digest more data than it provided. 4551694Sdarrenm */ 4561694Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 4571694Sdarrenm } 4581694Sdarrenm 4591694Sdarrenm return (CRYPTO_SUCCESS); 4601694Sdarrenm } 4611694Sdarrenm 4621694Sdarrenm /* 4631694Sdarrenm * Helper SHA1 digest final for mblk's. 4641694Sdarrenm * digest_len is the length of the desired digest. If digest_len 4651694Sdarrenm * is smaller than the default SHA1 digest length, the caller 4661694Sdarrenm * must pass a scratch buffer, digest_scratch, which must 4671694Sdarrenm * be at least SHA1_DIGEST_LENGTH bytes. 4681694Sdarrenm */ 4691694Sdarrenm static int 4701694Sdarrenm sha1_digest_final_mblk(SHA1_CTX *sha1_ctx, crypto_data_t *digest, 4711694Sdarrenm ulong_t digest_len, uchar_t *digest_scratch) 4721694Sdarrenm { 4731694Sdarrenm off_t offset = digest->cd_offset; 4741694Sdarrenm mblk_t *mp; 4751694Sdarrenm 4761694Sdarrenm /* 4771694Sdarrenm * Jump to the first mblk_t that will be used to store the digest. 4781694Sdarrenm */ 4791694Sdarrenm for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp); 4809364SVladimir.Kotal@Sun.COM offset -= MBLKL(mp), mp = mp->b_cont) 4819364SVladimir.Kotal@Sun.COM ; 4821694Sdarrenm if (mp == NULL) { 4831694Sdarrenm /* 4841694Sdarrenm * The caller specified an offset that is larger than the 4851694Sdarrenm * total size of the buffers it provided. 4861694Sdarrenm */ 4871694Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 4881694Sdarrenm } 4891694Sdarrenm 4901694Sdarrenm if (offset + digest_len <= MBLKL(mp)) { 4911694Sdarrenm /* 4921694Sdarrenm * The computed SHA1 digest will fit in the current mblk. 4931694Sdarrenm * Do the SHA1Final() in-place. 4941694Sdarrenm */ 4951694Sdarrenm if (digest_len != SHA1_DIGEST_LENGTH) { 4961694Sdarrenm /* 4971694Sdarrenm * The caller requested a short digest. Digest 4981694Sdarrenm * into a scratch buffer and return to 4991694Sdarrenm * the user only what was requested. 5001694Sdarrenm */ 5011694Sdarrenm SHA1Final(digest_scratch, sha1_ctx); 5021694Sdarrenm bcopy(digest_scratch, mp->b_rptr + offset, digest_len); 5031694Sdarrenm } else { 5041694Sdarrenm SHA1Final(mp->b_rptr + offset, sha1_ctx); 5051694Sdarrenm } 5061694Sdarrenm } else { 5071694Sdarrenm /* 5081694Sdarrenm * The computed digest will be crossing one or more mblk's. 5091694Sdarrenm * This is bad performance-wise but we need to support it. 5101694Sdarrenm * Allocate a small scratch buffer on the stack and 5111694Sdarrenm * copy it piece meal to the specified digest iovec's. 5121694Sdarrenm */ 5131694Sdarrenm uchar_t digest_tmp[SHA1_DIGEST_LENGTH]; 5141694Sdarrenm off_t scratch_offset = 0; 5151694Sdarrenm size_t length = digest_len; 5161694Sdarrenm size_t cur_len; 5171694Sdarrenm 5181694Sdarrenm SHA1Final(digest_tmp, sha1_ctx); 5191694Sdarrenm 5201694Sdarrenm while (mp != NULL && length > 0) { 5211694Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 5221694Sdarrenm bcopy(digest_tmp + scratch_offset, 5231694Sdarrenm mp->b_rptr + offset, cur_len); 5241694Sdarrenm 5251694Sdarrenm length -= cur_len; 5261694Sdarrenm mp = mp->b_cont; 5271694Sdarrenm scratch_offset += cur_len; 5281694Sdarrenm offset = 0; 5291694Sdarrenm } 5301694Sdarrenm 5311694Sdarrenm if (mp == NULL && length > 0) { 5321694Sdarrenm /* 5331694Sdarrenm * The end of the specified mblk was reached but 5341694Sdarrenm * the length requested could not be processed, i.e. 5351694Sdarrenm * The caller requested to digest more data than it 5361694Sdarrenm * provided. 5371694Sdarrenm */ 5381694Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 5391694Sdarrenm } 5401694Sdarrenm } 5411694Sdarrenm 5421694Sdarrenm return (CRYPTO_SUCCESS); 5431694Sdarrenm } 5441694Sdarrenm 5451694Sdarrenm /* ARGSUSED */ 5461694Sdarrenm static int 5471694Sdarrenm sha1_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest, 5481694Sdarrenm crypto_req_handle_t req) 5491694Sdarrenm { 5501694Sdarrenm int ret = CRYPTO_SUCCESS; 5511694Sdarrenm 5521694Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 5531694Sdarrenm 5541694Sdarrenm /* 5551694Sdarrenm * We need to just return the length needed to store the output. 5561694Sdarrenm * We should not destroy the context for the following cases. 5571694Sdarrenm */ 5581694Sdarrenm if ((digest->cd_length == 0) || 5591694Sdarrenm (digest->cd_length < SHA1_DIGEST_LENGTH)) { 5601694Sdarrenm digest->cd_length = SHA1_DIGEST_LENGTH; 5611694Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 5621694Sdarrenm } 5631694Sdarrenm 5641694Sdarrenm /* 5651694Sdarrenm * Do the SHA1 update on the specified input data. 5661694Sdarrenm */ 5671694Sdarrenm switch (data->cd_format) { 5681694Sdarrenm case CRYPTO_DATA_RAW: 5691694Sdarrenm SHA1Update(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 5701694Sdarrenm (uint8_t *)data->cd_raw.iov_base + data->cd_offset, 5711694Sdarrenm data->cd_length); 5721694Sdarrenm break; 5731694Sdarrenm case CRYPTO_DATA_UIO: 5741694Sdarrenm ret = sha1_digest_update_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 5751694Sdarrenm data); 5761694Sdarrenm break; 5771694Sdarrenm case CRYPTO_DATA_MBLK: 5781694Sdarrenm ret = sha1_digest_update_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 5791694Sdarrenm data); 5801694Sdarrenm break; 5811694Sdarrenm default: 5821694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 5831694Sdarrenm } 5841694Sdarrenm 5851694Sdarrenm if (ret != CRYPTO_SUCCESS) { 5861694Sdarrenm /* the update failed, free context and bail */ 5871694Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t)); 5881694Sdarrenm ctx->cc_provider_private = NULL; 5891694Sdarrenm digest->cd_length = 0; 5901694Sdarrenm return (ret); 5911694Sdarrenm } 5921694Sdarrenm 5931694Sdarrenm /* 5941694Sdarrenm * Do a SHA1 final, must be done separately since the digest 5951694Sdarrenm * type can be different than the input data type. 5961694Sdarrenm */ 5971694Sdarrenm switch (digest->cd_format) { 5981694Sdarrenm case CRYPTO_DATA_RAW: 5991694Sdarrenm SHA1Final((unsigned char *)digest->cd_raw.iov_base + 6001694Sdarrenm digest->cd_offset, &PROV_SHA1_CTX(ctx)->sc_sha1_ctx); 6011694Sdarrenm break; 6021694Sdarrenm case CRYPTO_DATA_UIO: 6031694Sdarrenm ret = sha1_digest_final_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 6041694Sdarrenm digest, SHA1_DIGEST_LENGTH, NULL); 6051694Sdarrenm break; 6061694Sdarrenm case CRYPTO_DATA_MBLK: 6071694Sdarrenm ret = sha1_digest_final_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 6081694Sdarrenm digest, SHA1_DIGEST_LENGTH, NULL); 6091694Sdarrenm break; 6101694Sdarrenm default: 6111694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 6121694Sdarrenm } 6131694Sdarrenm 6141694Sdarrenm /* all done, free context and return */ 6151694Sdarrenm 6161694Sdarrenm if (ret == CRYPTO_SUCCESS) { 6171694Sdarrenm digest->cd_length = SHA1_DIGEST_LENGTH; 6181694Sdarrenm } else { 6191694Sdarrenm digest->cd_length = 0; 6201694Sdarrenm } 6211694Sdarrenm 6221694Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t)); 6231694Sdarrenm ctx->cc_provider_private = NULL; 6241694Sdarrenm return (ret); 6251694Sdarrenm } 6261694Sdarrenm 6271694Sdarrenm /* ARGSUSED */ 6281694Sdarrenm static int 6291694Sdarrenm sha1_digest_update(crypto_ctx_t *ctx, crypto_data_t *data, 6301694Sdarrenm crypto_req_handle_t req) 6311694Sdarrenm { 6321694Sdarrenm int ret = CRYPTO_SUCCESS; 6331694Sdarrenm 6341694Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 6351694Sdarrenm 6361694Sdarrenm /* 6371694Sdarrenm * Do the SHA1 update on the specified input data. 6381694Sdarrenm */ 6391694Sdarrenm switch (data->cd_format) { 6401694Sdarrenm case CRYPTO_DATA_RAW: 6411694Sdarrenm SHA1Update(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 6421694Sdarrenm (uint8_t *)data->cd_raw.iov_base + data->cd_offset, 6431694Sdarrenm data->cd_length); 6441694Sdarrenm break; 6451694Sdarrenm case CRYPTO_DATA_UIO: 6461694Sdarrenm ret = sha1_digest_update_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 6471694Sdarrenm data); 6481694Sdarrenm break; 6491694Sdarrenm case CRYPTO_DATA_MBLK: 6501694Sdarrenm ret = sha1_digest_update_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 6511694Sdarrenm data); 6521694Sdarrenm break; 6531694Sdarrenm default: 6541694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 6551694Sdarrenm } 6561694Sdarrenm 6571694Sdarrenm return (ret); 6581694Sdarrenm } 6591694Sdarrenm 6601694Sdarrenm /* ARGSUSED */ 6611694Sdarrenm static int 6621694Sdarrenm sha1_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest, 6631694Sdarrenm crypto_req_handle_t req) 6641694Sdarrenm { 6651694Sdarrenm int ret = CRYPTO_SUCCESS; 6661694Sdarrenm 6671694Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 6681694Sdarrenm 6691694Sdarrenm /* 6701694Sdarrenm * We need to just return the length needed to store the output. 6711694Sdarrenm * We should not destroy the context for the following cases. 6721694Sdarrenm */ 6731694Sdarrenm if ((digest->cd_length == 0) || 6741694Sdarrenm (digest->cd_length < SHA1_DIGEST_LENGTH)) { 6751694Sdarrenm digest->cd_length = SHA1_DIGEST_LENGTH; 6761694Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 6771694Sdarrenm } 6781694Sdarrenm 6791694Sdarrenm /* 6801694Sdarrenm * Do a SHA1 final. 6811694Sdarrenm */ 6821694Sdarrenm switch (digest->cd_format) { 6831694Sdarrenm case CRYPTO_DATA_RAW: 6841694Sdarrenm SHA1Final((unsigned char *)digest->cd_raw.iov_base + 6851694Sdarrenm digest->cd_offset, &PROV_SHA1_CTX(ctx)->sc_sha1_ctx); 6861694Sdarrenm break; 6871694Sdarrenm case CRYPTO_DATA_UIO: 6881694Sdarrenm ret = sha1_digest_final_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 6891694Sdarrenm digest, SHA1_DIGEST_LENGTH, NULL); 6901694Sdarrenm break; 6911694Sdarrenm case CRYPTO_DATA_MBLK: 6921694Sdarrenm ret = sha1_digest_final_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx, 6931694Sdarrenm digest, SHA1_DIGEST_LENGTH, NULL); 6941694Sdarrenm break; 6951694Sdarrenm default: 6961694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 6971694Sdarrenm } 6981694Sdarrenm 6991694Sdarrenm /* all done, free context and return */ 7001694Sdarrenm 7011694Sdarrenm if (ret == CRYPTO_SUCCESS) { 7021694Sdarrenm digest->cd_length = SHA1_DIGEST_LENGTH; 7031694Sdarrenm } else { 7041694Sdarrenm digest->cd_length = 0; 7051694Sdarrenm } 7061694Sdarrenm 7071694Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t)); 7081694Sdarrenm ctx->cc_provider_private = NULL; 7091694Sdarrenm 7101694Sdarrenm return (ret); 7111694Sdarrenm } 7121694Sdarrenm 7131694Sdarrenm /* ARGSUSED */ 7141694Sdarrenm static int 7151694Sdarrenm sha1_digest_atomic(crypto_provider_handle_t provider, 7161694Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 7171694Sdarrenm crypto_data_t *data, crypto_data_t *digest, 7181694Sdarrenm crypto_req_handle_t req) 7191694Sdarrenm { 7201694Sdarrenm int ret = CRYPTO_SUCCESS; 7211694Sdarrenm SHA1_CTX sha1_ctx; 7221694Sdarrenm 7231694Sdarrenm if (mechanism->cm_type != SHA1_MECH_INFO_TYPE) 7241694Sdarrenm return (CRYPTO_MECHANISM_INVALID); 7251694Sdarrenm 7261694Sdarrenm /* 7271694Sdarrenm * Do the SHA1 init. 7281694Sdarrenm */ 7291694Sdarrenm SHA1Init(&sha1_ctx); 7301694Sdarrenm 7311694Sdarrenm /* 7321694Sdarrenm * Do the SHA1 update on the specified input data. 7331694Sdarrenm */ 7341694Sdarrenm switch (data->cd_format) { 7351694Sdarrenm case CRYPTO_DATA_RAW: 7361694Sdarrenm SHA1Update(&sha1_ctx, 7371694Sdarrenm (uint8_t *)data->cd_raw.iov_base + data->cd_offset, 7381694Sdarrenm data->cd_length); 7391694Sdarrenm break; 7401694Sdarrenm case CRYPTO_DATA_UIO: 7411694Sdarrenm ret = sha1_digest_update_uio(&sha1_ctx, data); 7421694Sdarrenm break; 7431694Sdarrenm case CRYPTO_DATA_MBLK: 7441694Sdarrenm ret = sha1_digest_update_mblk(&sha1_ctx, data); 7451694Sdarrenm break; 7461694Sdarrenm default: 7471694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 7481694Sdarrenm } 7491694Sdarrenm 7501694Sdarrenm if (ret != CRYPTO_SUCCESS) { 7511694Sdarrenm /* the update failed, bail */ 7521694Sdarrenm digest->cd_length = 0; 7531694Sdarrenm return (ret); 7541694Sdarrenm } 7551694Sdarrenm 7561694Sdarrenm /* 7571694Sdarrenm * Do a SHA1 final, must be done separately since the digest 7581694Sdarrenm * type can be different than the input data type. 7591694Sdarrenm */ 7601694Sdarrenm switch (digest->cd_format) { 7611694Sdarrenm case CRYPTO_DATA_RAW: 7621694Sdarrenm SHA1Final((unsigned char *)digest->cd_raw.iov_base + 7631694Sdarrenm digest->cd_offset, &sha1_ctx); 7641694Sdarrenm break; 7651694Sdarrenm case CRYPTO_DATA_UIO: 7661694Sdarrenm ret = sha1_digest_final_uio(&sha1_ctx, digest, 7671694Sdarrenm SHA1_DIGEST_LENGTH, NULL); 7681694Sdarrenm break; 7691694Sdarrenm case CRYPTO_DATA_MBLK: 7701694Sdarrenm ret = sha1_digest_final_mblk(&sha1_ctx, digest, 7711694Sdarrenm SHA1_DIGEST_LENGTH, NULL); 7721694Sdarrenm break; 7731694Sdarrenm default: 7741694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 7751694Sdarrenm } 7761694Sdarrenm 7771694Sdarrenm if (ret == CRYPTO_SUCCESS) { 7781694Sdarrenm digest->cd_length = SHA1_DIGEST_LENGTH; 7791694Sdarrenm } else { 7801694Sdarrenm digest->cd_length = 0; 7811694Sdarrenm } 7821694Sdarrenm 7831694Sdarrenm return (ret); 7841694Sdarrenm } 7851694Sdarrenm 7861694Sdarrenm /* 7871694Sdarrenm * KCF software provider mac entry points. 7881694Sdarrenm * 7891694Sdarrenm * SHA1 HMAC is: SHA1(key XOR opad, SHA1(key XOR ipad, text)) 7901694Sdarrenm * 7911694Sdarrenm * Init: 7921694Sdarrenm * The initialization routine initializes what we denote 7931694Sdarrenm * as the inner and outer contexts by doing 7941694Sdarrenm * - for inner context: SHA1(key XOR ipad) 7951694Sdarrenm * - for outer context: SHA1(key XOR opad) 7961694Sdarrenm * 7971694Sdarrenm * Update: 7981694Sdarrenm * Each subsequent SHA1 HMAC update will result in an 7991694Sdarrenm * update of the inner context with the specified data. 8001694Sdarrenm * 8011694Sdarrenm * Final: 8021694Sdarrenm * The SHA1 HMAC final will do a SHA1 final operation on the 8031694Sdarrenm * inner context, and the resulting digest will be used 8041694Sdarrenm * as the data for an update on the outer context. Last 8051694Sdarrenm * but not least, a SHA1 final on the outer context will 8061694Sdarrenm * be performed to obtain the SHA1 HMAC digest to return 8071694Sdarrenm * to the user. 8081694Sdarrenm */ 8091694Sdarrenm 8101694Sdarrenm /* 8111694Sdarrenm * Initialize a SHA1-HMAC context. 8121694Sdarrenm */ 8131694Sdarrenm static void 8141694Sdarrenm sha1_mac_init_ctx(sha1_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes) 8151694Sdarrenm { 8161694Sdarrenm uint32_t ipad[SHA1_HMAC_INTS_PER_BLOCK]; 8171694Sdarrenm uint32_t opad[SHA1_HMAC_INTS_PER_BLOCK]; 8181694Sdarrenm uint_t i; 8191694Sdarrenm 8201694Sdarrenm bzero(ipad, SHA1_HMAC_BLOCK_SIZE); 8211694Sdarrenm bzero(opad, SHA1_HMAC_BLOCK_SIZE); 8221694Sdarrenm 8231694Sdarrenm bcopy(keyval, ipad, length_in_bytes); 8241694Sdarrenm bcopy(keyval, opad, length_in_bytes); 8251694Sdarrenm 8261694Sdarrenm /* XOR key with ipad (0x36) and opad (0x5c) */ 8271694Sdarrenm for (i = 0; i < SHA1_HMAC_INTS_PER_BLOCK; i++) { 8281694Sdarrenm ipad[i] ^= 0x36363636; 8291694Sdarrenm opad[i] ^= 0x5c5c5c5c; 8301694Sdarrenm } 8311694Sdarrenm 8321694Sdarrenm /* perform SHA1 on ipad */ 8331694Sdarrenm SHA1Init(&ctx->hc_icontext); 8341694Sdarrenm SHA1Update(&ctx->hc_icontext, (uint8_t *)ipad, SHA1_HMAC_BLOCK_SIZE); 8351694Sdarrenm 8361694Sdarrenm /* perform SHA1 on opad */ 8371694Sdarrenm SHA1Init(&ctx->hc_ocontext); 8381694Sdarrenm SHA1Update(&ctx->hc_ocontext, (uint8_t *)opad, SHA1_HMAC_BLOCK_SIZE); 8391694Sdarrenm } 8401694Sdarrenm 8411694Sdarrenm /* 8421694Sdarrenm */ 8431694Sdarrenm static int 8441694Sdarrenm sha1_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 8451694Sdarrenm crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 8461694Sdarrenm crypto_req_handle_t req) 8471694Sdarrenm { 8481694Sdarrenm int ret = CRYPTO_SUCCESS; 8491694Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 8501694Sdarrenm 8511694Sdarrenm if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE && 8521694Sdarrenm mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE) 8531694Sdarrenm return (CRYPTO_MECHANISM_INVALID); 8541694Sdarrenm 8551694Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 8561694Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 8571694Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 8581694Sdarrenm 8591694Sdarrenm ctx->cc_provider_private = kmem_alloc(sizeof (sha1_hmac_ctx_t), 8601694Sdarrenm crypto_kmflag(req)); 8611694Sdarrenm if (ctx->cc_provider_private == NULL) 8621694Sdarrenm return (CRYPTO_HOST_MEMORY); 8631694Sdarrenm 8641694Sdarrenm if (ctx_template != NULL) { 8651694Sdarrenm /* reuse context template */ 8661694Sdarrenm bcopy(ctx_template, PROV_SHA1_HMAC_CTX(ctx), 8671694Sdarrenm sizeof (sha1_hmac_ctx_t)); 8681694Sdarrenm } else { 8691694Sdarrenm /* no context template, compute context */ 8701694Sdarrenm if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) { 8711694Sdarrenm uchar_t digested_key[SHA1_DIGEST_LENGTH]; 8721694Sdarrenm sha1_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private; 8731694Sdarrenm 8741694Sdarrenm /* 8751694Sdarrenm * Hash the passed-in key to get a smaller key. 8761694Sdarrenm * The inner context is used since it hasn't been 8771694Sdarrenm * initialized yet. 8781694Sdarrenm */ 8791694Sdarrenm PROV_SHA1_DIGEST_KEY(&hmac_ctx->hc_icontext, 8801694Sdarrenm key->ck_data, keylen_in_bytes, digested_key); 8811694Sdarrenm sha1_mac_init_ctx(PROV_SHA1_HMAC_CTX(ctx), 8821694Sdarrenm digested_key, SHA1_DIGEST_LENGTH); 8831694Sdarrenm } else { 8841694Sdarrenm sha1_mac_init_ctx(PROV_SHA1_HMAC_CTX(ctx), 8851694Sdarrenm key->ck_data, keylen_in_bytes); 8861694Sdarrenm } 8871694Sdarrenm } 8881694Sdarrenm 8891694Sdarrenm /* 8901694Sdarrenm * Get the mechanism parameters, if applicable. 8911694Sdarrenm */ 8921694Sdarrenm PROV_SHA1_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type; 8931694Sdarrenm if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) { 8941694Sdarrenm if (mechanism->cm_param == NULL || 8951694Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) 8961694Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 8971694Sdarrenm PROV_SHA1_GET_DIGEST_LEN(mechanism, 8981694Sdarrenm PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len); 8991694Sdarrenm if (PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len > 9001694Sdarrenm SHA1_DIGEST_LENGTH) 9011694Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 9021694Sdarrenm } 9031694Sdarrenm 9041694Sdarrenm if (ret != CRYPTO_SUCCESS) { 9051694Sdarrenm bzero(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t)); 9061694Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t)); 9071694Sdarrenm ctx->cc_provider_private = NULL; 9081694Sdarrenm } 9091694Sdarrenm 9101694Sdarrenm return (ret); 9111694Sdarrenm } 9121694Sdarrenm 9131694Sdarrenm /* ARGSUSED */ 9141694Sdarrenm static int 9151694Sdarrenm sha1_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req) 9161694Sdarrenm { 9171694Sdarrenm int ret = CRYPTO_SUCCESS; 9181694Sdarrenm 9191694Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 9201694Sdarrenm 9211694Sdarrenm /* 9221694Sdarrenm * Do a SHA1 update of the inner context using the specified 9231694Sdarrenm * data. 9241694Sdarrenm */ 9251694Sdarrenm switch (data->cd_format) { 9261694Sdarrenm case CRYPTO_DATA_RAW: 9271694Sdarrenm SHA1Update(&PROV_SHA1_HMAC_CTX(ctx)->hc_icontext, 9281694Sdarrenm (uint8_t *)data->cd_raw.iov_base + data->cd_offset, 9291694Sdarrenm data->cd_length); 9301694Sdarrenm break; 9311694Sdarrenm case CRYPTO_DATA_UIO: 9321694Sdarrenm ret = sha1_digest_update_uio( 9331694Sdarrenm &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext, data); 9341694Sdarrenm break; 9351694Sdarrenm case CRYPTO_DATA_MBLK: 9361694Sdarrenm ret = sha1_digest_update_mblk( 9371694Sdarrenm &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext, data); 9381694Sdarrenm break; 9391694Sdarrenm default: 9401694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 9411694Sdarrenm } 9421694Sdarrenm 9431694Sdarrenm return (ret); 9441694Sdarrenm } 9451694Sdarrenm 9461694Sdarrenm /* ARGSUSED */ 9471694Sdarrenm static int 9481694Sdarrenm sha1_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req) 9491694Sdarrenm { 9501694Sdarrenm int ret = CRYPTO_SUCCESS; 9511694Sdarrenm uchar_t digest[SHA1_DIGEST_LENGTH]; 9521694Sdarrenm uint32_t digest_len = SHA1_DIGEST_LENGTH; 9531694Sdarrenm 9541694Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 9551694Sdarrenm 9561694Sdarrenm if (PROV_SHA1_HMAC_CTX(ctx)->hc_mech_type == 9571694Sdarrenm SHA1_HMAC_GEN_MECH_INFO_TYPE) 9581694Sdarrenm digest_len = PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len; 9591694Sdarrenm 9601694Sdarrenm /* 9611694Sdarrenm * We need to just return the length needed to store the output. 9621694Sdarrenm * We should not destroy the context for the following cases. 9631694Sdarrenm */ 9641694Sdarrenm if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) { 9651694Sdarrenm mac->cd_length = digest_len; 9661694Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 9671694Sdarrenm } 9681694Sdarrenm 9691694Sdarrenm /* 9701694Sdarrenm * Do a SHA1 final on the inner context. 9711694Sdarrenm */ 9721694Sdarrenm SHA1Final(digest, &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext); 9731694Sdarrenm 9741694Sdarrenm /* 9751694Sdarrenm * Do a SHA1 update on the outer context, feeding the inner 9761694Sdarrenm * digest as data. 9771694Sdarrenm */ 9781694Sdarrenm SHA1Update(&PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, digest, 9791694Sdarrenm SHA1_DIGEST_LENGTH); 9801694Sdarrenm 9811694Sdarrenm /* 9821694Sdarrenm * Do a SHA1 final on the outer context, storing the computing 9831694Sdarrenm * digest in the users buffer. 9841694Sdarrenm */ 9851694Sdarrenm switch (mac->cd_format) { 9861694Sdarrenm case CRYPTO_DATA_RAW: 9871694Sdarrenm if (digest_len != SHA1_DIGEST_LENGTH) { 9881694Sdarrenm /* 9891694Sdarrenm * The caller requested a short digest. Digest 9901694Sdarrenm * into a scratch buffer and return to 9911694Sdarrenm * the user only what was requested. 9921694Sdarrenm */ 9931694Sdarrenm SHA1Final(digest, 9941694Sdarrenm &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext); 9951694Sdarrenm bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 9961694Sdarrenm mac->cd_offset, digest_len); 9971694Sdarrenm } else { 9981694Sdarrenm SHA1Final((unsigned char *)mac->cd_raw.iov_base + 9991694Sdarrenm mac->cd_offset, 10001694Sdarrenm &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext); 10011694Sdarrenm } 10021694Sdarrenm break; 10031694Sdarrenm case CRYPTO_DATA_UIO: 10041694Sdarrenm ret = sha1_digest_final_uio( 10051694Sdarrenm &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, mac, 10061694Sdarrenm digest_len, digest); 10071694Sdarrenm break; 10081694Sdarrenm case CRYPTO_DATA_MBLK: 10091694Sdarrenm ret = sha1_digest_final_mblk( 10101694Sdarrenm &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, mac, 10111694Sdarrenm digest_len, digest); 10121694Sdarrenm break; 10131694Sdarrenm default: 10141694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 10151694Sdarrenm } 10161694Sdarrenm 10171694Sdarrenm if (ret == CRYPTO_SUCCESS) { 10181694Sdarrenm mac->cd_length = digest_len; 10191694Sdarrenm } else { 10201694Sdarrenm mac->cd_length = 0; 10211694Sdarrenm } 10221694Sdarrenm 10231694Sdarrenm bzero(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t)); 10241694Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t)); 10251694Sdarrenm ctx->cc_provider_private = NULL; 10261694Sdarrenm 10271694Sdarrenm return (ret); 10281694Sdarrenm } 10291694Sdarrenm 10301694Sdarrenm #define SHA1_MAC_UPDATE(data, ctx, ret) { \ 10311694Sdarrenm switch (data->cd_format) { \ 10321694Sdarrenm case CRYPTO_DATA_RAW: \ 10331694Sdarrenm SHA1Update(&(ctx).hc_icontext, \ 10341694Sdarrenm (uint8_t *)data->cd_raw.iov_base + \ 10351694Sdarrenm data->cd_offset, data->cd_length); \ 10361694Sdarrenm break; \ 10371694Sdarrenm case CRYPTO_DATA_UIO: \ 10381694Sdarrenm ret = sha1_digest_update_uio(&(ctx).hc_icontext, data); \ 10391694Sdarrenm break; \ 10401694Sdarrenm case CRYPTO_DATA_MBLK: \ 10411694Sdarrenm ret = sha1_digest_update_mblk(&(ctx).hc_icontext, \ 10421694Sdarrenm data); \ 10431694Sdarrenm break; \ 10441694Sdarrenm default: \ 10451694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; \ 10461694Sdarrenm } \ 10471694Sdarrenm } 10481694Sdarrenm 10491694Sdarrenm /* ARGSUSED */ 10501694Sdarrenm static int 10511694Sdarrenm sha1_mac_atomic(crypto_provider_handle_t provider, 10521694Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 10531694Sdarrenm crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 10541694Sdarrenm crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 10551694Sdarrenm { 10561694Sdarrenm int ret = CRYPTO_SUCCESS; 10571694Sdarrenm uchar_t digest[SHA1_DIGEST_LENGTH]; 10581694Sdarrenm sha1_hmac_ctx_t sha1_hmac_ctx; 10591694Sdarrenm uint32_t digest_len = SHA1_DIGEST_LENGTH; 10601694Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 10611694Sdarrenm 10621694Sdarrenm if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE && 10631694Sdarrenm mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE) 10641694Sdarrenm return (CRYPTO_MECHANISM_INVALID); 10651694Sdarrenm 10661694Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 10671694Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 10681694Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 10691694Sdarrenm 10701694Sdarrenm if (ctx_template != NULL) { 10711694Sdarrenm /* reuse context template */ 10721694Sdarrenm bcopy(ctx_template, &sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t)); 10731694Sdarrenm } else { 10741694Sdarrenm /* no context template, initialize context */ 10751694Sdarrenm if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) { 10761694Sdarrenm /* 10771694Sdarrenm * Hash the passed-in key to get a smaller key. 10781694Sdarrenm * The inner context is used since it hasn't been 10791694Sdarrenm * initialized yet. 10801694Sdarrenm */ 10811694Sdarrenm PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx.hc_icontext, 10821694Sdarrenm key->ck_data, keylen_in_bytes, digest); 10831694Sdarrenm sha1_mac_init_ctx(&sha1_hmac_ctx, digest, 10841694Sdarrenm SHA1_DIGEST_LENGTH); 10851694Sdarrenm } else { 10861694Sdarrenm sha1_mac_init_ctx(&sha1_hmac_ctx, key->ck_data, 10871694Sdarrenm keylen_in_bytes); 10881694Sdarrenm } 10891694Sdarrenm } 10901694Sdarrenm 10911694Sdarrenm /* get the mechanism parameters, if applicable */ 10921694Sdarrenm if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) { 10931694Sdarrenm if (mechanism->cm_param == NULL || 10941694Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) { 10951694Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 10961694Sdarrenm goto bail; 10971694Sdarrenm } 10981694Sdarrenm PROV_SHA1_GET_DIGEST_LEN(mechanism, digest_len); 10991694Sdarrenm if (digest_len > SHA1_DIGEST_LENGTH) { 11001694Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 11011694Sdarrenm goto bail; 11021694Sdarrenm } 11031694Sdarrenm } 11041694Sdarrenm 11051694Sdarrenm /* do a SHA1 update of the inner context using the specified data */ 11061694Sdarrenm SHA1_MAC_UPDATE(data, sha1_hmac_ctx, ret); 11071694Sdarrenm if (ret != CRYPTO_SUCCESS) 11081694Sdarrenm /* the update failed, free context and bail */ 11091694Sdarrenm goto bail; 11101694Sdarrenm 11111694Sdarrenm /* 11121694Sdarrenm * Do a SHA1 final on the inner context. 11131694Sdarrenm */ 11141694Sdarrenm SHA1Final(digest, &sha1_hmac_ctx.hc_icontext); 11151694Sdarrenm 11161694Sdarrenm /* 11171694Sdarrenm * Do an SHA1 update on the outer context, feeding the inner 11181694Sdarrenm * digest as data. 11191694Sdarrenm */ 11201694Sdarrenm SHA1Update(&sha1_hmac_ctx.hc_ocontext, digest, SHA1_DIGEST_LENGTH); 11211694Sdarrenm 11221694Sdarrenm /* 11231694Sdarrenm * Do a SHA1 final on the outer context, storing the computed 11241694Sdarrenm * digest in the users buffer. 11251694Sdarrenm */ 11261694Sdarrenm switch (mac->cd_format) { 11271694Sdarrenm case CRYPTO_DATA_RAW: 11281694Sdarrenm if (digest_len != SHA1_DIGEST_LENGTH) { 11291694Sdarrenm /* 11301694Sdarrenm * The caller requested a short digest. Digest 11311694Sdarrenm * into a scratch buffer and return to 11321694Sdarrenm * the user only what was requested. 11331694Sdarrenm */ 11341694Sdarrenm SHA1Final(digest, &sha1_hmac_ctx.hc_ocontext); 11351694Sdarrenm bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 11361694Sdarrenm mac->cd_offset, digest_len); 11371694Sdarrenm } else { 11381694Sdarrenm SHA1Final((unsigned char *)mac->cd_raw.iov_base + 11391694Sdarrenm mac->cd_offset, &sha1_hmac_ctx.hc_ocontext); 11401694Sdarrenm } 11411694Sdarrenm break; 11421694Sdarrenm case CRYPTO_DATA_UIO: 11431694Sdarrenm ret = sha1_digest_final_uio(&sha1_hmac_ctx.hc_ocontext, mac, 11441694Sdarrenm digest_len, digest); 11451694Sdarrenm break; 11461694Sdarrenm case CRYPTO_DATA_MBLK: 11471694Sdarrenm ret = sha1_digest_final_mblk(&sha1_hmac_ctx.hc_ocontext, mac, 11481694Sdarrenm digest_len, digest); 11491694Sdarrenm break; 11501694Sdarrenm default: 11511694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 11521694Sdarrenm } 11531694Sdarrenm 11541694Sdarrenm if (ret == CRYPTO_SUCCESS) { 11551694Sdarrenm mac->cd_length = digest_len; 11561694Sdarrenm } else { 11571694Sdarrenm mac->cd_length = 0; 11581694Sdarrenm } 11591694Sdarrenm /* Extra paranoia: zeroize the context on the stack */ 11601694Sdarrenm bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t)); 11611694Sdarrenm 11621694Sdarrenm return (ret); 11631694Sdarrenm bail: 11641694Sdarrenm bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t)); 11651694Sdarrenm mac->cd_length = 0; 11661694Sdarrenm return (ret); 11671694Sdarrenm } 11681694Sdarrenm 11691694Sdarrenm /* ARGSUSED */ 11701694Sdarrenm static int 11711694Sdarrenm sha1_mac_verify_atomic(crypto_provider_handle_t provider, 11721694Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 11731694Sdarrenm crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 11741694Sdarrenm crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 11751694Sdarrenm { 11761694Sdarrenm int ret = CRYPTO_SUCCESS; 11771694Sdarrenm uchar_t digest[SHA1_DIGEST_LENGTH]; 11781694Sdarrenm sha1_hmac_ctx_t sha1_hmac_ctx; 11791694Sdarrenm uint32_t digest_len = SHA1_DIGEST_LENGTH; 11801694Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 11811694Sdarrenm 11821694Sdarrenm if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE && 11831694Sdarrenm mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE) 11841694Sdarrenm return (CRYPTO_MECHANISM_INVALID); 11851694Sdarrenm 11861694Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 11871694Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 11881694Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 11891694Sdarrenm 11901694Sdarrenm if (ctx_template != NULL) { 11911694Sdarrenm /* reuse context template */ 11921694Sdarrenm bcopy(ctx_template, &sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t)); 11931694Sdarrenm } else { 11941694Sdarrenm /* no context template, initialize context */ 11951694Sdarrenm if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) { 11961694Sdarrenm /* 11971694Sdarrenm * Hash the passed-in key to get a smaller key. 11981694Sdarrenm * The inner context is used since it hasn't been 11991694Sdarrenm * initialized yet. 12001694Sdarrenm */ 12011694Sdarrenm PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx.hc_icontext, 12021694Sdarrenm key->ck_data, keylen_in_bytes, digest); 12031694Sdarrenm sha1_mac_init_ctx(&sha1_hmac_ctx, digest, 12041694Sdarrenm SHA1_DIGEST_LENGTH); 12051694Sdarrenm } else { 12061694Sdarrenm sha1_mac_init_ctx(&sha1_hmac_ctx, key->ck_data, 12071694Sdarrenm keylen_in_bytes); 12081694Sdarrenm } 12091694Sdarrenm } 12101694Sdarrenm 12111694Sdarrenm /* get the mechanism parameters, if applicable */ 12121694Sdarrenm if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) { 12131694Sdarrenm if (mechanism->cm_param == NULL || 12141694Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) { 12151694Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 12161694Sdarrenm goto bail; 12171694Sdarrenm } 12181694Sdarrenm PROV_SHA1_GET_DIGEST_LEN(mechanism, digest_len); 12191694Sdarrenm if (digest_len > SHA1_DIGEST_LENGTH) { 12201694Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 12211694Sdarrenm goto bail; 12221694Sdarrenm } 12231694Sdarrenm } 12241694Sdarrenm 12251694Sdarrenm if (mac->cd_length != digest_len) { 12261694Sdarrenm ret = CRYPTO_INVALID_MAC; 12271694Sdarrenm goto bail; 12281694Sdarrenm } 12291694Sdarrenm 12301694Sdarrenm /* do a SHA1 update of the inner context using the specified data */ 12311694Sdarrenm SHA1_MAC_UPDATE(data, sha1_hmac_ctx, ret); 12321694Sdarrenm if (ret != CRYPTO_SUCCESS) 12331694Sdarrenm /* the update failed, free context and bail */ 12341694Sdarrenm goto bail; 12351694Sdarrenm 12361694Sdarrenm /* do a SHA1 final on the inner context */ 12371694Sdarrenm SHA1Final(digest, &sha1_hmac_ctx.hc_icontext); 12381694Sdarrenm 12391694Sdarrenm /* 12401694Sdarrenm * Do an SHA1 update on the outer context, feeding the inner 12411694Sdarrenm * digest as data. 12421694Sdarrenm */ 12431694Sdarrenm SHA1Update(&sha1_hmac_ctx.hc_ocontext, digest, SHA1_DIGEST_LENGTH); 12441694Sdarrenm 12451694Sdarrenm /* 12461694Sdarrenm * Do a SHA1 final on the outer context, storing the computed 12471694Sdarrenm * digest in the users buffer. 12481694Sdarrenm */ 12491694Sdarrenm SHA1Final(digest, &sha1_hmac_ctx.hc_ocontext); 12501694Sdarrenm 12511694Sdarrenm /* 12521694Sdarrenm * Compare the computed digest against the expected digest passed 12531694Sdarrenm * as argument. 12541694Sdarrenm */ 12551694Sdarrenm 12561694Sdarrenm switch (mac->cd_format) { 12571694Sdarrenm 12581694Sdarrenm case CRYPTO_DATA_RAW: 12591694Sdarrenm if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base + 12601694Sdarrenm mac->cd_offset, digest_len) != 0) 12611694Sdarrenm ret = CRYPTO_INVALID_MAC; 12621694Sdarrenm break; 12631694Sdarrenm 12641694Sdarrenm case CRYPTO_DATA_UIO: { 12651694Sdarrenm off_t offset = mac->cd_offset; 12661694Sdarrenm uint_t vec_idx; 12671694Sdarrenm off_t scratch_offset = 0; 12681694Sdarrenm size_t length = digest_len; 12691694Sdarrenm size_t cur_len; 12701694Sdarrenm 12711694Sdarrenm /* we support only kernel buffer */ 12721694Sdarrenm if (mac->cd_uio->uio_segflg != UIO_SYSSPACE) 12731694Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 12741694Sdarrenm 12751694Sdarrenm /* jump to the first iovec containing the expected digest */ 12761694Sdarrenm for (vec_idx = 0; 12771694Sdarrenm offset >= mac->cd_uio->uio_iov[vec_idx].iov_len && 12781694Sdarrenm vec_idx < mac->cd_uio->uio_iovcnt; 12799364SVladimir.Kotal@Sun.COM offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len) 12809364SVladimir.Kotal@Sun.COM ; 12811694Sdarrenm if (vec_idx == mac->cd_uio->uio_iovcnt) { 12821694Sdarrenm /* 12831694Sdarrenm * The caller specified an offset that is 12841694Sdarrenm * larger than the total size of the buffers 12851694Sdarrenm * it provided. 12861694Sdarrenm */ 12871694Sdarrenm ret = CRYPTO_DATA_LEN_RANGE; 12881694Sdarrenm break; 12891694Sdarrenm } 12901694Sdarrenm 12911694Sdarrenm /* do the comparison of computed digest vs specified one */ 12921694Sdarrenm while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) { 12931694Sdarrenm cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len - 12941694Sdarrenm offset, length); 12951694Sdarrenm 12961694Sdarrenm if (bcmp(digest + scratch_offset, 12971694Sdarrenm mac->cd_uio->uio_iov[vec_idx].iov_base + offset, 12981694Sdarrenm cur_len) != 0) { 12991694Sdarrenm ret = CRYPTO_INVALID_MAC; 13001694Sdarrenm break; 13011694Sdarrenm } 13021694Sdarrenm 13031694Sdarrenm length -= cur_len; 13041694Sdarrenm vec_idx++; 13051694Sdarrenm scratch_offset += cur_len; 13061694Sdarrenm offset = 0; 13071694Sdarrenm } 13081694Sdarrenm break; 13091694Sdarrenm } 13101694Sdarrenm 13111694Sdarrenm case CRYPTO_DATA_MBLK: { 13121694Sdarrenm off_t offset = mac->cd_offset; 13131694Sdarrenm mblk_t *mp; 13141694Sdarrenm off_t scratch_offset = 0; 13151694Sdarrenm size_t length = digest_len; 13161694Sdarrenm size_t cur_len; 13171694Sdarrenm 13181694Sdarrenm /* jump to the first mblk_t containing the expected digest */ 13191694Sdarrenm for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp); 13209364SVladimir.Kotal@Sun.COM offset -= MBLKL(mp), mp = mp->b_cont) 13219364SVladimir.Kotal@Sun.COM ; 13221694Sdarrenm if (mp == NULL) { 13231694Sdarrenm /* 13241694Sdarrenm * The caller specified an offset that is larger than 13251694Sdarrenm * the total size of the buffers it provided. 13261694Sdarrenm */ 13271694Sdarrenm ret = CRYPTO_DATA_LEN_RANGE; 13281694Sdarrenm break; 13291694Sdarrenm } 13301694Sdarrenm 13311694Sdarrenm while (mp != NULL && length > 0) { 13321694Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 13331694Sdarrenm if (bcmp(digest + scratch_offset, 13341694Sdarrenm mp->b_rptr + offset, cur_len) != 0) { 13351694Sdarrenm ret = CRYPTO_INVALID_MAC; 13361694Sdarrenm break; 13371694Sdarrenm } 13381694Sdarrenm 13391694Sdarrenm length -= cur_len; 13401694Sdarrenm mp = mp->b_cont; 13411694Sdarrenm scratch_offset += cur_len; 13421694Sdarrenm offset = 0; 13431694Sdarrenm } 13441694Sdarrenm break; 13451694Sdarrenm } 13461694Sdarrenm 13471694Sdarrenm default: 13481694Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 13491694Sdarrenm } 13501694Sdarrenm 13511694Sdarrenm bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t)); 13521694Sdarrenm return (ret); 13531694Sdarrenm bail: 13541694Sdarrenm bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t)); 13551694Sdarrenm mac->cd_length = 0; 13561694Sdarrenm return (ret); 13571694Sdarrenm } 13581694Sdarrenm 13591694Sdarrenm /* 13601694Sdarrenm * KCF software provider context management entry points. 13611694Sdarrenm */ 13621694Sdarrenm 13631694Sdarrenm /* ARGSUSED */ 13641694Sdarrenm static int 13651694Sdarrenm sha1_create_ctx_template(crypto_provider_handle_t provider, 13661694Sdarrenm crypto_mechanism_t *mechanism, crypto_key_t *key, 13671694Sdarrenm crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size, 13681694Sdarrenm crypto_req_handle_t req) 13691694Sdarrenm { 13701694Sdarrenm sha1_hmac_ctx_t *sha1_hmac_ctx_tmpl; 13711694Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 13721694Sdarrenm 13731694Sdarrenm if ((mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE) && 13741694Sdarrenm (mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)) { 13751694Sdarrenm return (CRYPTO_MECHANISM_INVALID); 13761694Sdarrenm } 13771694Sdarrenm 13781694Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 13791694Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 13801694Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 13811694Sdarrenm 13821694Sdarrenm /* 13831694Sdarrenm * Allocate and initialize SHA1 context. 13841694Sdarrenm */ 13851694Sdarrenm sha1_hmac_ctx_tmpl = kmem_alloc(sizeof (sha1_hmac_ctx_t), 13861694Sdarrenm crypto_kmflag(req)); 13871694Sdarrenm if (sha1_hmac_ctx_tmpl == NULL) 13881694Sdarrenm return (CRYPTO_HOST_MEMORY); 13891694Sdarrenm 13901694Sdarrenm if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) { 13911694Sdarrenm uchar_t digested_key[SHA1_DIGEST_LENGTH]; 13921694Sdarrenm 13931694Sdarrenm /* 13941694Sdarrenm * Hash the passed-in key to get a smaller key. 13951694Sdarrenm * The inner context is used since it hasn't been 13961694Sdarrenm * initialized yet. 13971694Sdarrenm */ 13981694Sdarrenm PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx_tmpl->hc_icontext, 13991694Sdarrenm key->ck_data, keylen_in_bytes, digested_key); 14001694Sdarrenm sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, digested_key, 14011694Sdarrenm SHA1_DIGEST_LENGTH); 14021694Sdarrenm } else { 14031694Sdarrenm sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, key->ck_data, 14041694Sdarrenm keylen_in_bytes); 14051694Sdarrenm } 14061694Sdarrenm 14071694Sdarrenm sha1_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type; 14081694Sdarrenm *ctx_template = (crypto_spi_ctx_template_t)sha1_hmac_ctx_tmpl; 14091694Sdarrenm *ctx_template_size = sizeof (sha1_hmac_ctx_t); 14101694Sdarrenm 14111694Sdarrenm 14121694Sdarrenm return (CRYPTO_SUCCESS); 14131694Sdarrenm } 14141694Sdarrenm 14151694Sdarrenm static int 14161694Sdarrenm sha1_free_context(crypto_ctx_t *ctx) 14171694Sdarrenm { 14181694Sdarrenm uint_t ctx_len; 14191694Sdarrenm sha1_mech_type_t mech_type; 14201694Sdarrenm 14211694Sdarrenm if (ctx->cc_provider_private == NULL) 14221694Sdarrenm return (CRYPTO_SUCCESS); 14231694Sdarrenm 14241694Sdarrenm /* 14251694Sdarrenm * We have to free either SHA1 or SHA1-HMAC contexts, which 14261694Sdarrenm * have different lengths. 14271694Sdarrenm */ 14281694Sdarrenm 14291694Sdarrenm mech_type = PROV_SHA1_CTX(ctx)->sc_mech_type; 14301694Sdarrenm if (mech_type == SHA1_MECH_INFO_TYPE) 14311694Sdarrenm ctx_len = sizeof (sha1_ctx_t); 14321694Sdarrenm else { 14331694Sdarrenm ASSERT(mech_type == SHA1_HMAC_MECH_INFO_TYPE || 14341694Sdarrenm mech_type == SHA1_HMAC_GEN_MECH_INFO_TYPE); 14351694Sdarrenm ctx_len = sizeof (sha1_hmac_ctx_t); 14361694Sdarrenm } 14371694Sdarrenm 14381694Sdarrenm bzero(ctx->cc_provider_private, ctx_len); 14391694Sdarrenm kmem_free(ctx->cc_provider_private, ctx_len); 14401694Sdarrenm ctx->cc_provider_private = NULL; 14411694Sdarrenm 14421694Sdarrenm return (CRYPTO_SUCCESS); 14431694Sdarrenm } 1444*10500SHai-May.Chao@Sun.COM 1445*10500SHai-May.Chao@Sun.COM /* 1446*10500SHai-May.Chao@Sun.COM * SHA-1 Power-Up Self-Test 1447*10500SHai-May.Chao@Sun.COM */ 1448*10500SHai-May.Chao@Sun.COM void 1449*10500SHai-May.Chao@Sun.COM sha1_POST(int *rc) 1450*10500SHai-May.Chao@Sun.COM { 1451*10500SHai-May.Chao@Sun.COM 1452*10500SHai-May.Chao@Sun.COM *rc = fips_sha1_post(); 1453*10500SHai-May.Chao@Sun.COM 1454*10500SHai-May.Chao@Sun.COM } 1455