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