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