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