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