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