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