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