1734b6a94Sdarrenm /* 2734b6a94Sdarrenm * CDDL HEADER START 3734b6a94Sdarrenm * 4734b6a94Sdarrenm * The contents of this file are subject to the terms of the 5734b6a94Sdarrenm * Common Development and Distribution License (the "License"). 6734b6a94Sdarrenm * You may not use this file except in compliance with the License. 7734b6a94Sdarrenm * 8734b6a94Sdarrenm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9734b6a94Sdarrenm * or http://www.opensolaris.org/os/licensing. 10734b6a94Sdarrenm * See the License for the specific language governing permissions 11734b6a94Sdarrenm * and limitations under the License. 12734b6a94Sdarrenm * 13734b6a94Sdarrenm * When distributing Covered Code, include this CDDL HEADER in each 14734b6a94Sdarrenm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15734b6a94Sdarrenm * If applicable, add the following below this CDDL HEADER, with the 16734b6a94Sdarrenm * fields enclosed by brackets "[]" replaced with your own identifying 17734b6a94Sdarrenm * information: Portions Copyright [yyyy] [name of copyright owner] 18734b6a94Sdarrenm * 19734b6a94Sdarrenm * CDDL HEADER END 20734b6a94Sdarrenm */ 21734b6a94Sdarrenm 22734b6a94Sdarrenm /* 23*d3b2efc7SAnthony Scarpino * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24734b6a94Sdarrenm * Use is subject to license terms. 25734b6a94Sdarrenm */ 26734b6a94Sdarrenm 27734b6a94Sdarrenm /* 28734b6a94Sdarrenm * In kernel module, the md5 module is created with two modlinkages: 29734b6a94Sdarrenm * - a modlmisc that allows consumers to directly call the entry points 30734b6a94Sdarrenm * MD5Init, MD5Update, and MD5Final. 31734b6a94Sdarrenm * - a modlcrypto that allows the module to register with the Kernel 32734b6a94Sdarrenm * Cryptographic Framework (KCF) as a software provider for the MD5 33734b6a94Sdarrenm * mechanisms. 34734b6a94Sdarrenm */ 35734b6a94Sdarrenm 36734b6a94Sdarrenm #include <sys/types.h> 37734b6a94Sdarrenm #include <sys/systm.h> 38734b6a94Sdarrenm #include <sys/modctl.h> 39734b6a94Sdarrenm #include <sys/cmn_err.h> 40734b6a94Sdarrenm #include <sys/ddi.h> 41734b6a94Sdarrenm #include <sys/crypto/common.h> 42734b6a94Sdarrenm #include <sys/crypto/spi.h> 43734b6a94Sdarrenm #include <sys/sysmacros.h> 44734b6a94Sdarrenm #include <sys/strsun.h> 45734b6a94Sdarrenm #include <sys/note.h> 46734b6a94Sdarrenm #include <sys/md5.h> 47734b6a94Sdarrenm 48734b6a94Sdarrenm extern struct mod_ops mod_miscops; 49734b6a94Sdarrenm extern struct mod_ops mod_cryptoops; 50734b6a94Sdarrenm 51734b6a94Sdarrenm /* 52734b6a94Sdarrenm * Module linkage information for the kernel. 53734b6a94Sdarrenm */ 54734b6a94Sdarrenm 55734b6a94Sdarrenm static struct modlmisc modlmisc = { 56734b6a94Sdarrenm &mod_miscops, 57734b6a94Sdarrenm "MD5 Message-Digest Algorithm" 58734b6a94Sdarrenm }; 59734b6a94Sdarrenm 60734b6a94Sdarrenm static struct modlcrypto modlcrypto = { 61734b6a94Sdarrenm &mod_cryptoops, 62d2b32306Smcpowers "MD5 Kernel SW Provider" 63734b6a94Sdarrenm }; 64734b6a94Sdarrenm 65734b6a94Sdarrenm static struct modlinkage modlinkage = { 66734b6a94Sdarrenm MODREV_1, 67734b6a94Sdarrenm (void *)&modlmisc, 68734b6a94Sdarrenm (void *)&modlcrypto, 69734b6a94Sdarrenm NULL 70734b6a94Sdarrenm }; 71734b6a94Sdarrenm 72734b6a94Sdarrenm /* 73734b6a94Sdarrenm * CSPI information (entry points, provider info, etc.) 74734b6a94Sdarrenm */ 75734b6a94Sdarrenm 76734b6a94Sdarrenm typedef enum md5_mech_type { 77734b6a94Sdarrenm MD5_MECH_INFO_TYPE, /* SUN_CKM_MD5 */ 78734b6a94Sdarrenm MD5_HMAC_MECH_INFO_TYPE, /* SUN_CKM_MD5_HMAC */ 79734b6a94Sdarrenm MD5_HMAC_GEN_MECH_INFO_TYPE /* SUN_CKM_MD5_HMAC_GENERAL */ 80734b6a94Sdarrenm } md5_mech_type_t; 81734b6a94Sdarrenm 82734b6a94Sdarrenm #define MD5_DIGEST_LENGTH 16 /* MD5 digest length in bytes */ 83734b6a94Sdarrenm #define MD5_HMAC_BLOCK_SIZE 64 /* MD5 block size */ 845b675b31SVladimir Kotal #define MD5_HMAC_MIN_KEY_LEN 1 /* MD5-HMAC min key length in bytes */ 855b675b31SVladimir Kotal #define MD5_HMAC_MAX_KEY_LEN INT_MAX /* MD5-HMAC max key length in bytes */ 86734b6a94Sdarrenm #define MD5_HMAC_INTS_PER_BLOCK (MD5_HMAC_BLOCK_SIZE/sizeof (uint32_t)) 87734b6a94Sdarrenm 88734b6a94Sdarrenm /* 89734b6a94Sdarrenm * Context for MD5 mechanism. 90734b6a94Sdarrenm */ 91734b6a94Sdarrenm typedef struct md5_ctx { 92734b6a94Sdarrenm md5_mech_type_t mc_mech_type; /* type of context */ 93734b6a94Sdarrenm MD5_CTX mc_md5_ctx; /* MD5 context */ 94734b6a94Sdarrenm } md5_ctx_t; 95734b6a94Sdarrenm 96734b6a94Sdarrenm /* 97734b6a94Sdarrenm * Context for MD5-HMAC and MD5-HMAC-GENERAL mechanisms. 98734b6a94Sdarrenm */ 99734b6a94Sdarrenm typedef struct md5_hmac_ctx { 100734b6a94Sdarrenm md5_mech_type_t hc_mech_type; /* type of context */ 101734b6a94Sdarrenm uint32_t hc_digest_len; /* digest len in bytes */ 102734b6a94Sdarrenm MD5_CTX hc_icontext; /* inner MD5 context */ 103734b6a94Sdarrenm MD5_CTX hc_ocontext; /* outer MD5 context */ 104734b6a94Sdarrenm } md5_hmac_ctx_t; 105734b6a94Sdarrenm 106734b6a94Sdarrenm /* 107734b6a94Sdarrenm * Macros to access the MD5 or MD5-HMAC contexts from a context passed 108734b6a94Sdarrenm * by KCF to one of the entry points. 109734b6a94Sdarrenm */ 110734b6a94Sdarrenm 111734b6a94Sdarrenm #define PROV_MD5_CTX(ctx) ((md5_ctx_t *)(ctx)->cc_provider_private) 112734b6a94Sdarrenm #define PROV_MD5_HMAC_CTX(ctx) ((md5_hmac_ctx_t *)(ctx)->cc_provider_private) 113734b6a94Sdarrenm /* to extract the digest length passed as mechanism parameter */ 114734b6a94Sdarrenm 115734b6a94Sdarrenm #define PROV_MD5_GET_DIGEST_LEN(m, len) { \ 116734b6a94Sdarrenm if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t))) \ 1178de5c4f4SDan OpenSolaris Anderson (len) = (uint32_t)*((ulong_t *)(void *)mechanism->cm_param); \ 118734b6a94Sdarrenm else { \ 119734b6a94Sdarrenm ulong_t tmp_ulong; \ 120734b6a94Sdarrenm bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t)); \ 121734b6a94Sdarrenm (len) = (uint32_t)tmp_ulong; \ 122734b6a94Sdarrenm } \ 123734b6a94Sdarrenm } 124734b6a94Sdarrenm 125734b6a94Sdarrenm #define PROV_MD5_DIGEST_KEY(ctx, key, len, digest) { \ 126734b6a94Sdarrenm MD5Init(ctx); \ 127734b6a94Sdarrenm MD5Update(ctx, key, len); \ 128734b6a94Sdarrenm MD5Final(digest, ctx); \ 129734b6a94Sdarrenm } 130734b6a94Sdarrenm 131734b6a94Sdarrenm /* 132734b6a94Sdarrenm * Mechanism info structure passed to KCF during registration. 133734b6a94Sdarrenm */ 134734b6a94Sdarrenm static crypto_mech_info_t md5_mech_info_tab[] = { 135734b6a94Sdarrenm /* MD5 */ 136734b6a94Sdarrenm {SUN_CKM_MD5, MD5_MECH_INFO_TYPE, 137734b6a94Sdarrenm CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, 138734b6a94Sdarrenm 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, 139734b6a94Sdarrenm /* MD5-HMAC */ 140734b6a94Sdarrenm {SUN_CKM_MD5_HMAC, MD5_HMAC_MECH_INFO_TYPE, 141734b6a94Sdarrenm CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 142734b6a94Sdarrenm MD5_HMAC_MIN_KEY_LEN, MD5_HMAC_MAX_KEY_LEN, 1435b675b31SVladimir Kotal CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 144734b6a94Sdarrenm /* MD5-HMAC GENERAL */ 145734b6a94Sdarrenm {SUN_CKM_MD5_HMAC_GENERAL, MD5_HMAC_GEN_MECH_INFO_TYPE, 146734b6a94Sdarrenm CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 147734b6a94Sdarrenm MD5_HMAC_MIN_KEY_LEN, MD5_HMAC_MAX_KEY_LEN, 1485b675b31SVladimir Kotal CRYPTO_KEYSIZE_UNIT_IN_BYTES} 149734b6a94Sdarrenm }; 150734b6a94Sdarrenm 151734b6a94Sdarrenm static void md5_provider_status(crypto_provider_handle_t, uint_t *); 152734b6a94Sdarrenm 153734b6a94Sdarrenm static crypto_control_ops_t md5_control_ops = { 154734b6a94Sdarrenm md5_provider_status 155734b6a94Sdarrenm }; 156734b6a94Sdarrenm 157734b6a94Sdarrenm static int md5_digest_init(crypto_ctx_t *, crypto_mechanism_t *, 158734b6a94Sdarrenm crypto_req_handle_t); 159734b6a94Sdarrenm static int md5_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 160734b6a94Sdarrenm crypto_req_handle_t); 161734b6a94Sdarrenm static int md5_digest_update(crypto_ctx_t *, crypto_data_t *, 162734b6a94Sdarrenm crypto_req_handle_t); 163734b6a94Sdarrenm static int md5_digest_final(crypto_ctx_t *, crypto_data_t *, 164734b6a94Sdarrenm crypto_req_handle_t); 165734b6a94Sdarrenm static int md5_digest_atomic(crypto_provider_handle_t, crypto_session_id_t, 166734b6a94Sdarrenm crypto_mechanism_t *, crypto_data_t *, crypto_data_t *, 167734b6a94Sdarrenm crypto_req_handle_t); 168734b6a94Sdarrenm 169734b6a94Sdarrenm static crypto_digest_ops_t md5_digest_ops = { 170734b6a94Sdarrenm md5_digest_init, 171734b6a94Sdarrenm md5_digest, 172734b6a94Sdarrenm md5_digest_update, 173734b6a94Sdarrenm NULL, 174734b6a94Sdarrenm md5_digest_final, 175734b6a94Sdarrenm md5_digest_atomic 176734b6a94Sdarrenm }; 177734b6a94Sdarrenm 178734b6a94Sdarrenm static int md5_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, 179734b6a94Sdarrenm crypto_spi_ctx_template_t, crypto_req_handle_t); 180734b6a94Sdarrenm static int md5_mac_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); 181734b6a94Sdarrenm static int md5_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); 182734b6a94Sdarrenm static int md5_mac_atomic(crypto_provider_handle_t, crypto_session_id_t, 183734b6a94Sdarrenm crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 184734b6a94Sdarrenm crypto_spi_ctx_template_t, crypto_req_handle_t); 185734b6a94Sdarrenm static int md5_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t, 186734b6a94Sdarrenm crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 187734b6a94Sdarrenm crypto_spi_ctx_template_t, crypto_req_handle_t); 188734b6a94Sdarrenm 189734b6a94Sdarrenm static crypto_mac_ops_t md5_mac_ops = { 190734b6a94Sdarrenm md5_mac_init, 191734b6a94Sdarrenm NULL, 192734b6a94Sdarrenm md5_mac_update, 193734b6a94Sdarrenm md5_mac_final, 194734b6a94Sdarrenm md5_mac_atomic, 195734b6a94Sdarrenm md5_mac_verify_atomic 196734b6a94Sdarrenm }; 197734b6a94Sdarrenm 198734b6a94Sdarrenm static int md5_create_ctx_template(crypto_provider_handle_t, 199734b6a94Sdarrenm crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *, 200734b6a94Sdarrenm size_t *, crypto_req_handle_t); 201734b6a94Sdarrenm static int md5_free_context(crypto_ctx_t *); 202734b6a94Sdarrenm 203734b6a94Sdarrenm static crypto_ctx_ops_t md5_ctx_ops = { 204734b6a94Sdarrenm md5_create_ctx_template, 205734b6a94Sdarrenm md5_free_context 206734b6a94Sdarrenm }; 207734b6a94Sdarrenm 208734b6a94Sdarrenm static crypto_ops_t md5_crypto_ops = { 209734b6a94Sdarrenm &md5_control_ops, 210734b6a94Sdarrenm &md5_digest_ops, 211734b6a94Sdarrenm NULL, 212734b6a94Sdarrenm &md5_mac_ops, 213734b6a94Sdarrenm NULL, 214734b6a94Sdarrenm NULL, 215734b6a94Sdarrenm NULL, 216734b6a94Sdarrenm NULL, 217734b6a94Sdarrenm NULL, 218734b6a94Sdarrenm NULL, 219734b6a94Sdarrenm NULL, 220734b6a94Sdarrenm NULL, 221734b6a94Sdarrenm NULL, 222734b6a94Sdarrenm &md5_ctx_ops 223734b6a94Sdarrenm }; 224734b6a94Sdarrenm 225734b6a94Sdarrenm static crypto_provider_info_t md5_prov_info = { 226734b6a94Sdarrenm CRYPTO_SPI_VERSION_1, 227734b6a94Sdarrenm "MD5 Software Provider", 228734b6a94Sdarrenm CRYPTO_SW_PROVIDER, 229734b6a94Sdarrenm {&modlinkage}, 230734b6a94Sdarrenm NULL, 231734b6a94Sdarrenm &md5_crypto_ops, 232734b6a94Sdarrenm sizeof (md5_mech_info_tab)/sizeof (crypto_mech_info_t), 233734b6a94Sdarrenm md5_mech_info_tab 234734b6a94Sdarrenm }; 235734b6a94Sdarrenm 236734b6a94Sdarrenm static crypto_kcf_provider_handle_t md5_prov_handle = NULL; 237734b6a94Sdarrenm 238734b6a94Sdarrenm int 239734b6a94Sdarrenm _init(void) 240734b6a94Sdarrenm { 241734b6a94Sdarrenm int ret; 242734b6a94Sdarrenm 243734b6a94Sdarrenm if ((ret = mod_install(&modlinkage)) != 0) 244734b6a94Sdarrenm return (ret); 245734b6a94Sdarrenm 246734b6a94Sdarrenm /* 247*d3b2efc7SAnthony Scarpino * Register with KCF. If the registration fails, do not uninstall the 248*d3b2efc7SAnthony Scarpino * module, since the functionality provided by misc/md5 should still be 249*d3b2efc7SAnthony Scarpino * available. 250734b6a94Sdarrenm */ 251*d3b2efc7SAnthony Scarpino (void) crypto_register_provider(&md5_prov_info, &md5_prov_handle); 252734b6a94Sdarrenm 253734b6a94Sdarrenm return (0); 254734b6a94Sdarrenm } 255734b6a94Sdarrenm 256734b6a94Sdarrenm int 257734b6a94Sdarrenm _fini(void) 258734b6a94Sdarrenm { 259734b6a94Sdarrenm int ret; 260734b6a94Sdarrenm 261734b6a94Sdarrenm /* 262734b6a94Sdarrenm * Unregister from KCF if previous registration succeeded. 263734b6a94Sdarrenm */ 264734b6a94Sdarrenm if (md5_prov_handle != NULL) { 265734b6a94Sdarrenm if ((ret = crypto_unregister_provider(md5_prov_handle)) != 266*d3b2efc7SAnthony Scarpino CRYPTO_SUCCESS) 267*d3b2efc7SAnthony Scarpino return (ret); 268*d3b2efc7SAnthony Scarpino 269734b6a94Sdarrenm md5_prov_handle = NULL; 270734b6a94Sdarrenm } 271734b6a94Sdarrenm 272734b6a94Sdarrenm return (mod_remove(&modlinkage)); 273734b6a94Sdarrenm } 274734b6a94Sdarrenm 275734b6a94Sdarrenm int 276734b6a94Sdarrenm _info(struct modinfo *modinfop) 277734b6a94Sdarrenm { 278734b6a94Sdarrenm return (mod_info(&modlinkage, modinfop)); 279734b6a94Sdarrenm } 280734b6a94Sdarrenm 281734b6a94Sdarrenm /* 282734b6a94Sdarrenm * KCF software provider control entry points. 283734b6a94Sdarrenm */ 284734b6a94Sdarrenm /* ARGSUSED */ 285734b6a94Sdarrenm static void 286734b6a94Sdarrenm md5_provider_status(crypto_provider_handle_t provider, uint_t *status) 287734b6a94Sdarrenm { 288734b6a94Sdarrenm *status = CRYPTO_PROVIDER_READY; 289734b6a94Sdarrenm } 290734b6a94Sdarrenm 291734b6a94Sdarrenm /* 292734b6a94Sdarrenm * KCF software provider digest entry points. 293734b6a94Sdarrenm */ 294734b6a94Sdarrenm 295734b6a94Sdarrenm static int 296734b6a94Sdarrenm md5_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 297734b6a94Sdarrenm crypto_req_handle_t req) 298734b6a94Sdarrenm { 299734b6a94Sdarrenm if (mechanism->cm_type != MD5_MECH_INFO_TYPE) 300734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 301734b6a94Sdarrenm 302734b6a94Sdarrenm /* 303734b6a94Sdarrenm * Allocate and initialize MD5 context. 304734b6a94Sdarrenm */ 305734b6a94Sdarrenm ctx->cc_provider_private = kmem_alloc(sizeof (md5_ctx_t), 306734b6a94Sdarrenm crypto_kmflag(req)); 307734b6a94Sdarrenm if (ctx->cc_provider_private == NULL) 308734b6a94Sdarrenm return (CRYPTO_HOST_MEMORY); 309734b6a94Sdarrenm 310734b6a94Sdarrenm PROV_MD5_CTX(ctx)->mc_mech_type = MD5_MECH_INFO_TYPE; 311734b6a94Sdarrenm MD5Init(&PROV_MD5_CTX(ctx)->mc_md5_ctx); 312734b6a94Sdarrenm 313734b6a94Sdarrenm return (CRYPTO_SUCCESS); 314734b6a94Sdarrenm } 315734b6a94Sdarrenm 316734b6a94Sdarrenm /* 317734b6a94Sdarrenm * Helper MD5 digest update function for uio data. 318734b6a94Sdarrenm */ 319734b6a94Sdarrenm static int 320734b6a94Sdarrenm md5_digest_update_uio(MD5_CTX *md5_ctx, crypto_data_t *data) 321734b6a94Sdarrenm { 322734b6a94Sdarrenm off_t offset = data->cd_offset; 323734b6a94Sdarrenm size_t length = data->cd_length; 324734b6a94Sdarrenm uint_t vec_idx; 325734b6a94Sdarrenm size_t cur_len; 326734b6a94Sdarrenm 327734b6a94Sdarrenm /* we support only kernel buffer */ 328734b6a94Sdarrenm if (data->cd_uio->uio_segflg != UIO_SYSSPACE) 329734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 330734b6a94Sdarrenm 331734b6a94Sdarrenm /* 332734b6a94Sdarrenm * Jump to the first iovec containing data to be 333734b6a94Sdarrenm * digested. 334734b6a94Sdarrenm */ 335734b6a94Sdarrenm for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt && 336734b6a94Sdarrenm offset >= data->cd_uio->uio_iov[vec_idx].iov_len; 337d2b32306Smcpowers offset -= data->cd_uio->uio_iov[vec_idx++].iov_len) 338d2b32306Smcpowers ; 339734b6a94Sdarrenm if (vec_idx == data->cd_uio->uio_iovcnt) { 340734b6a94Sdarrenm /* 341734b6a94Sdarrenm * The caller specified an offset that is larger than the 342734b6a94Sdarrenm * total size of the buffers it provided. 343734b6a94Sdarrenm */ 344734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 345734b6a94Sdarrenm } 346734b6a94Sdarrenm 347734b6a94Sdarrenm /* 348734b6a94Sdarrenm * Now do the digesting on the iovecs. 349734b6a94Sdarrenm */ 350734b6a94Sdarrenm while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) { 351734b6a94Sdarrenm cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len - 352734b6a94Sdarrenm offset, length); 353734b6a94Sdarrenm 354734b6a94Sdarrenm MD5Update(md5_ctx, data->cd_uio->uio_iov[vec_idx].iov_base + 355734b6a94Sdarrenm offset, cur_len); 356734b6a94Sdarrenm 357734b6a94Sdarrenm length -= cur_len; 358734b6a94Sdarrenm vec_idx++; 359734b6a94Sdarrenm offset = 0; 360734b6a94Sdarrenm } 361734b6a94Sdarrenm 362734b6a94Sdarrenm if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) { 363734b6a94Sdarrenm /* 364734b6a94Sdarrenm * The end of the specified iovec's was reached but 365734b6a94Sdarrenm * the length requested could not be processed, i.e. 366734b6a94Sdarrenm * The caller requested to digest more data than it provided. 367734b6a94Sdarrenm */ 368734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 369734b6a94Sdarrenm } 370734b6a94Sdarrenm 371734b6a94Sdarrenm return (CRYPTO_SUCCESS); 372734b6a94Sdarrenm } 373734b6a94Sdarrenm 374734b6a94Sdarrenm /* 375734b6a94Sdarrenm * Helper MD5 digest final function for uio data. 376734b6a94Sdarrenm * digest_len is the length of the desired digest. If digest_len 377734b6a94Sdarrenm * is smaller than the default MD5 digest length, the caller 378734b6a94Sdarrenm * must pass a scratch buffer, digest_scratch, which must 379734b6a94Sdarrenm * be at least MD5_DIGEST_LENGTH bytes. 380734b6a94Sdarrenm */ 381734b6a94Sdarrenm static int 382734b6a94Sdarrenm md5_digest_final_uio(MD5_CTX *md5_ctx, crypto_data_t *digest, 383734b6a94Sdarrenm ulong_t digest_len, uchar_t *digest_scratch) 384734b6a94Sdarrenm { 385734b6a94Sdarrenm off_t offset = digest->cd_offset; 386734b6a94Sdarrenm uint_t vec_idx; 387734b6a94Sdarrenm 388734b6a94Sdarrenm /* we support only kernel buffer */ 389734b6a94Sdarrenm if (digest->cd_uio->uio_segflg != UIO_SYSSPACE) 390734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 391734b6a94Sdarrenm 392734b6a94Sdarrenm /* 393734b6a94Sdarrenm * Jump to the first iovec containing ptr to the digest to 394734b6a94Sdarrenm * be returned. 395734b6a94Sdarrenm */ 396734b6a94Sdarrenm for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len && 397734b6a94Sdarrenm vec_idx < digest->cd_uio->uio_iovcnt; 398d2b32306Smcpowers offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len) 399d2b32306Smcpowers ; 400734b6a94Sdarrenm if (vec_idx == digest->cd_uio->uio_iovcnt) { 401734b6a94Sdarrenm /* 402734b6a94Sdarrenm * The caller specified an offset that is 403734b6a94Sdarrenm * larger than the total size of the buffers 404734b6a94Sdarrenm * it provided. 405734b6a94Sdarrenm */ 406734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 407734b6a94Sdarrenm } 408734b6a94Sdarrenm 409734b6a94Sdarrenm if (offset + digest_len <= 410734b6a94Sdarrenm digest->cd_uio->uio_iov[vec_idx].iov_len) { 411734b6a94Sdarrenm /* 412734b6a94Sdarrenm * The computed MD5 digest will fit in the current 413734b6a94Sdarrenm * iovec. 414734b6a94Sdarrenm */ 415734b6a94Sdarrenm if (digest_len != MD5_DIGEST_LENGTH) { 416734b6a94Sdarrenm /* 417734b6a94Sdarrenm * The caller requested a short digest. Digest 418734b6a94Sdarrenm * into a scratch buffer and return to 419734b6a94Sdarrenm * the user only what was requested. 420734b6a94Sdarrenm */ 421734b6a94Sdarrenm MD5Final(digest_scratch, md5_ctx); 422734b6a94Sdarrenm bcopy(digest_scratch, (uchar_t *)digest-> 423734b6a94Sdarrenm cd_uio->uio_iov[vec_idx].iov_base + offset, 424734b6a94Sdarrenm digest_len); 425734b6a94Sdarrenm } else { 426734b6a94Sdarrenm MD5Final((uchar_t *)digest-> 427734b6a94Sdarrenm cd_uio->uio_iov[vec_idx].iov_base + offset, 428734b6a94Sdarrenm md5_ctx); 429734b6a94Sdarrenm } 430734b6a94Sdarrenm } else { 431734b6a94Sdarrenm /* 432734b6a94Sdarrenm * The computed digest will be crossing one or more iovec's. 433734b6a94Sdarrenm * This is bad performance-wise but we need to support it. 434734b6a94Sdarrenm * Allocate a small scratch buffer on the stack and 435734b6a94Sdarrenm * copy it piece meal to the specified digest iovec's. 436734b6a94Sdarrenm */ 437734b6a94Sdarrenm uchar_t digest_tmp[MD5_DIGEST_LENGTH]; 438734b6a94Sdarrenm off_t scratch_offset = 0; 439734b6a94Sdarrenm size_t length = digest_len; 440734b6a94Sdarrenm size_t cur_len; 441734b6a94Sdarrenm 442734b6a94Sdarrenm MD5Final(digest_tmp, md5_ctx); 443734b6a94Sdarrenm 444734b6a94Sdarrenm while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) { 445734b6a94Sdarrenm cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len - 446734b6a94Sdarrenm offset, length); 447734b6a94Sdarrenm bcopy(digest_tmp + scratch_offset, 448734b6a94Sdarrenm digest->cd_uio->uio_iov[vec_idx].iov_base + offset, 449734b6a94Sdarrenm cur_len); 450734b6a94Sdarrenm 451734b6a94Sdarrenm length -= cur_len; 452734b6a94Sdarrenm vec_idx++; 453734b6a94Sdarrenm scratch_offset += cur_len; 454734b6a94Sdarrenm offset = 0; 455734b6a94Sdarrenm } 456734b6a94Sdarrenm 457734b6a94Sdarrenm if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) { 458734b6a94Sdarrenm /* 459734b6a94Sdarrenm * The end of the specified iovec's was reached but 460734b6a94Sdarrenm * the length requested could not be processed, i.e. 461734b6a94Sdarrenm * The caller requested to digest more data than it 462734b6a94Sdarrenm * provided. 463734b6a94Sdarrenm */ 464734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 465734b6a94Sdarrenm } 466734b6a94Sdarrenm } 467734b6a94Sdarrenm 468734b6a94Sdarrenm return (CRYPTO_SUCCESS); 469734b6a94Sdarrenm } 470734b6a94Sdarrenm 471734b6a94Sdarrenm /* 472734b6a94Sdarrenm * Helper MD5 digest update for mblk's. 473734b6a94Sdarrenm */ 474734b6a94Sdarrenm static int 475734b6a94Sdarrenm md5_digest_update_mblk(MD5_CTX *md5_ctx, crypto_data_t *data) 476734b6a94Sdarrenm { 477734b6a94Sdarrenm off_t offset = data->cd_offset; 478734b6a94Sdarrenm size_t length = data->cd_length; 479734b6a94Sdarrenm mblk_t *mp; 480734b6a94Sdarrenm size_t cur_len; 481734b6a94Sdarrenm 482734b6a94Sdarrenm /* 483734b6a94Sdarrenm * Jump to the first mblk_t containing data to be digested. 484734b6a94Sdarrenm */ 485734b6a94Sdarrenm for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp); 486d2b32306Smcpowers offset -= MBLKL(mp), mp = mp->b_cont) 487d2b32306Smcpowers ; 488734b6a94Sdarrenm if (mp == NULL) { 489734b6a94Sdarrenm /* 490734b6a94Sdarrenm * The caller specified an offset that is larger than the 491734b6a94Sdarrenm * total size of the buffers it provided. 492734b6a94Sdarrenm */ 493734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 494734b6a94Sdarrenm } 495734b6a94Sdarrenm 496734b6a94Sdarrenm /* 497734b6a94Sdarrenm * Now do the digesting on the mblk chain. 498734b6a94Sdarrenm */ 499734b6a94Sdarrenm while (mp != NULL && length > 0) { 500734b6a94Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 501734b6a94Sdarrenm MD5Update(md5_ctx, mp->b_rptr + offset, cur_len); 502734b6a94Sdarrenm length -= cur_len; 503734b6a94Sdarrenm offset = 0; 504734b6a94Sdarrenm mp = mp->b_cont; 505734b6a94Sdarrenm } 506734b6a94Sdarrenm 507734b6a94Sdarrenm if (mp == NULL && length > 0) { 508734b6a94Sdarrenm /* 509734b6a94Sdarrenm * The end of the mblk was reached but the length requested 510734b6a94Sdarrenm * could not be processed, i.e. The caller requested 511734b6a94Sdarrenm * to digest more data than it provided. 512734b6a94Sdarrenm */ 513734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 514734b6a94Sdarrenm } 515734b6a94Sdarrenm 516734b6a94Sdarrenm return (CRYPTO_SUCCESS); 517734b6a94Sdarrenm } 518734b6a94Sdarrenm 519734b6a94Sdarrenm /* 520734b6a94Sdarrenm * Helper MD5 digest final for mblk's. 521734b6a94Sdarrenm * digest_len is the length of the desired digest. If digest_len 522734b6a94Sdarrenm * is smaller than the default MD5 digest length, the caller 523734b6a94Sdarrenm * must pass a scratch buffer, digest_scratch, which must 524734b6a94Sdarrenm * be at least MD5_DIGEST_LENGTH bytes. 525734b6a94Sdarrenm */ 526734b6a94Sdarrenm static int 527734b6a94Sdarrenm md5_digest_final_mblk(MD5_CTX *md5_ctx, crypto_data_t *digest, 528734b6a94Sdarrenm ulong_t digest_len, uchar_t *digest_scratch) 529734b6a94Sdarrenm { 530734b6a94Sdarrenm off_t offset = digest->cd_offset; 531734b6a94Sdarrenm mblk_t *mp; 532734b6a94Sdarrenm 533734b6a94Sdarrenm /* 534734b6a94Sdarrenm * Jump to the first mblk_t that will be used to store the digest. 535734b6a94Sdarrenm */ 536734b6a94Sdarrenm for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp); 537d2b32306Smcpowers offset -= MBLKL(mp), mp = mp->b_cont) 538d2b32306Smcpowers ; 539734b6a94Sdarrenm if (mp == NULL) { 540734b6a94Sdarrenm /* 541734b6a94Sdarrenm * The caller specified an offset that is larger than the 542734b6a94Sdarrenm * total size of the buffers it provided. 543734b6a94Sdarrenm */ 544734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 545734b6a94Sdarrenm } 546734b6a94Sdarrenm 547734b6a94Sdarrenm if (offset + digest_len <= MBLKL(mp)) { 548734b6a94Sdarrenm /* 549734b6a94Sdarrenm * The computed MD5 digest will fit in the current mblk. 550734b6a94Sdarrenm * Do the MD5Final() in-place. 551734b6a94Sdarrenm */ 552734b6a94Sdarrenm if (digest_len != MD5_DIGEST_LENGTH) { 553734b6a94Sdarrenm /* 554734b6a94Sdarrenm * The caller requested a short digest. Digest 555734b6a94Sdarrenm * into a scratch buffer and return to 556734b6a94Sdarrenm * the user only what was requested. 557734b6a94Sdarrenm */ 558734b6a94Sdarrenm MD5Final(digest_scratch, md5_ctx); 559734b6a94Sdarrenm bcopy(digest_scratch, mp->b_rptr + offset, digest_len); 560734b6a94Sdarrenm } else { 561734b6a94Sdarrenm MD5Final(mp->b_rptr + offset, md5_ctx); 562734b6a94Sdarrenm } 563734b6a94Sdarrenm } else { 564734b6a94Sdarrenm /* 565734b6a94Sdarrenm * The computed digest will be crossing one or more mblk's. 566734b6a94Sdarrenm * This is bad performance-wise but we need to support it. 567734b6a94Sdarrenm * Allocate a small scratch buffer on the stack and 568734b6a94Sdarrenm * copy it piece meal to the specified digest iovec's. 569734b6a94Sdarrenm */ 570734b6a94Sdarrenm uchar_t digest_tmp[MD5_DIGEST_LENGTH]; 571734b6a94Sdarrenm off_t scratch_offset = 0; 572734b6a94Sdarrenm size_t length = digest_len; 573734b6a94Sdarrenm size_t cur_len; 574734b6a94Sdarrenm 575734b6a94Sdarrenm MD5Final(digest_tmp, md5_ctx); 576734b6a94Sdarrenm 577734b6a94Sdarrenm while (mp != NULL && length > 0) { 578734b6a94Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 579734b6a94Sdarrenm bcopy(digest_tmp + scratch_offset, 580734b6a94Sdarrenm mp->b_rptr + offset, cur_len); 581734b6a94Sdarrenm 582734b6a94Sdarrenm length -= cur_len; 583734b6a94Sdarrenm mp = mp->b_cont; 584734b6a94Sdarrenm scratch_offset += cur_len; 585734b6a94Sdarrenm offset = 0; 586734b6a94Sdarrenm } 587734b6a94Sdarrenm 588734b6a94Sdarrenm if (mp == NULL && length > 0) { 589734b6a94Sdarrenm /* 590734b6a94Sdarrenm * The end of the specified mblk was reached but 591734b6a94Sdarrenm * the length requested could not be processed, i.e. 592734b6a94Sdarrenm * The caller requested to digest more data than it 593734b6a94Sdarrenm * provided. 594734b6a94Sdarrenm */ 595734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 596734b6a94Sdarrenm } 597734b6a94Sdarrenm } 598734b6a94Sdarrenm 599734b6a94Sdarrenm return (CRYPTO_SUCCESS); 600734b6a94Sdarrenm } 601734b6a94Sdarrenm 602734b6a94Sdarrenm /* ARGSUSED */ 603734b6a94Sdarrenm static int 604734b6a94Sdarrenm md5_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest, 605734b6a94Sdarrenm crypto_req_handle_t req) 606734b6a94Sdarrenm { 607734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 608734b6a94Sdarrenm 609734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 610734b6a94Sdarrenm 611734b6a94Sdarrenm /* 612734b6a94Sdarrenm * We need to just return the length needed to store the output. 613734b6a94Sdarrenm * We should not destroy the context for the following cases. 614734b6a94Sdarrenm */ 615734b6a94Sdarrenm if ((digest->cd_length == 0) || 616734b6a94Sdarrenm (digest->cd_length < MD5_DIGEST_LENGTH)) { 617734b6a94Sdarrenm digest->cd_length = MD5_DIGEST_LENGTH; 618734b6a94Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 619734b6a94Sdarrenm } 620734b6a94Sdarrenm 621734b6a94Sdarrenm /* 622734b6a94Sdarrenm * Do the MD5 update on the specified input data. 623734b6a94Sdarrenm */ 624734b6a94Sdarrenm switch (data->cd_format) { 625734b6a94Sdarrenm case CRYPTO_DATA_RAW: 626734b6a94Sdarrenm MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 627734b6a94Sdarrenm data->cd_raw.iov_base + data->cd_offset, 628734b6a94Sdarrenm data->cd_length); 629734b6a94Sdarrenm break; 630734b6a94Sdarrenm case CRYPTO_DATA_UIO: 631734b6a94Sdarrenm ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 632734b6a94Sdarrenm data); 633734b6a94Sdarrenm break; 634734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 635734b6a94Sdarrenm ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 636734b6a94Sdarrenm data); 637734b6a94Sdarrenm break; 638734b6a94Sdarrenm default: 639734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 640734b6a94Sdarrenm } 641734b6a94Sdarrenm 642734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) { 643734b6a94Sdarrenm /* the update failed, free context and bail */ 644734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 645734b6a94Sdarrenm ctx->cc_provider_private = NULL; 646734b6a94Sdarrenm digest->cd_length = 0; 647734b6a94Sdarrenm return (ret); 648734b6a94Sdarrenm } 649734b6a94Sdarrenm 650734b6a94Sdarrenm /* 651734b6a94Sdarrenm * Do an MD5 final, must be done separately since the digest 652734b6a94Sdarrenm * type can be different than the input data type. 653734b6a94Sdarrenm */ 654734b6a94Sdarrenm switch (digest->cd_format) { 655734b6a94Sdarrenm case CRYPTO_DATA_RAW: 656734b6a94Sdarrenm MD5Final((unsigned char *)digest->cd_raw.iov_base + 657734b6a94Sdarrenm digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx); 658734b6a94Sdarrenm break; 659734b6a94Sdarrenm case CRYPTO_DATA_UIO: 660734b6a94Sdarrenm ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 661734b6a94Sdarrenm digest, MD5_DIGEST_LENGTH, NULL); 662734b6a94Sdarrenm break; 663734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 664734b6a94Sdarrenm ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 665734b6a94Sdarrenm digest, MD5_DIGEST_LENGTH, NULL); 666734b6a94Sdarrenm break; 667734b6a94Sdarrenm default: 668734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 669734b6a94Sdarrenm } 670734b6a94Sdarrenm 671734b6a94Sdarrenm /* all done, free context and return */ 672734b6a94Sdarrenm 673734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) { 674734b6a94Sdarrenm digest->cd_length = MD5_DIGEST_LENGTH; 675734b6a94Sdarrenm } else { 676734b6a94Sdarrenm digest->cd_length = 0; 677734b6a94Sdarrenm } 678734b6a94Sdarrenm 679734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 680734b6a94Sdarrenm ctx->cc_provider_private = NULL; 681734b6a94Sdarrenm return (ret); 682734b6a94Sdarrenm } 683734b6a94Sdarrenm 684734b6a94Sdarrenm /* ARGSUSED */ 685734b6a94Sdarrenm static int 686734b6a94Sdarrenm md5_digest_update(crypto_ctx_t *ctx, crypto_data_t *data, 687734b6a94Sdarrenm crypto_req_handle_t req) 688734b6a94Sdarrenm { 689734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 690734b6a94Sdarrenm 691734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 692734b6a94Sdarrenm 693734b6a94Sdarrenm /* 694734b6a94Sdarrenm * Do the MD5 update on the specified input data. 695734b6a94Sdarrenm */ 696734b6a94Sdarrenm switch (data->cd_format) { 697734b6a94Sdarrenm case CRYPTO_DATA_RAW: 698734b6a94Sdarrenm MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 699734b6a94Sdarrenm data->cd_raw.iov_base + data->cd_offset, 700734b6a94Sdarrenm data->cd_length); 701734b6a94Sdarrenm break; 702734b6a94Sdarrenm case CRYPTO_DATA_UIO: 703734b6a94Sdarrenm ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 704734b6a94Sdarrenm data); 705734b6a94Sdarrenm break; 706734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 707734b6a94Sdarrenm ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 708734b6a94Sdarrenm data); 709734b6a94Sdarrenm break; 710734b6a94Sdarrenm default: 711734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 712734b6a94Sdarrenm } 713734b6a94Sdarrenm 714734b6a94Sdarrenm return (ret); 715734b6a94Sdarrenm } 716734b6a94Sdarrenm 717734b6a94Sdarrenm /* ARGSUSED */ 718734b6a94Sdarrenm static int 719734b6a94Sdarrenm md5_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest, 720734b6a94Sdarrenm crypto_req_handle_t req) 721734b6a94Sdarrenm { 722734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 723734b6a94Sdarrenm 724734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 725734b6a94Sdarrenm 726734b6a94Sdarrenm /* 727734b6a94Sdarrenm * We need to just return the length needed to store the output. 728734b6a94Sdarrenm * We should not destroy the context for the following cases. 729734b6a94Sdarrenm */ 730734b6a94Sdarrenm if ((digest->cd_length == 0) || 731734b6a94Sdarrenm (digest->cd_length < MD5_DIGEST_LENGTH)) { 732734b6a94Sdarrenm digest->cd_length = MD5_DIGEST_LENGTH; 733734b6a94Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 734734b6a94Sdarrenm } 735734b6a94Sdarrenm 736734b6a94Sdarrenm /* 737734b6a94Sdarrenm * Do an MD5 final. 738734b6a94Sdarrenm */ 739734b6a94Sdarrenm switch (digest->cd_format) { 740734b6a94Sdarrenm case CRYPTO_DATA_RAW: 741734b6a94Sdarrenm MD5Final((unsigned char *)digest->cd_raw.iov_base + 742734b6a94Sdarrenm digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx); 743734b6a94Sdarrenm break; 744734b6a94Sdarrenm case CRYPTO_DATA_UIO: 745734b6a94Sdarrenm ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 746734b6a94Sdarrenm digest, MD5_DIGEST_LENGTH, NULL); 747734b6a94Sdarrenm break; 748734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 749734b6a94Sdarrenm ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 750734b6a94Sdarrenm digest, MD5_DIGEST_LENGTH, NULL); 751734b6a94Sdarrenm break; 752734b6a94Sdarrenm default: 753734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 754734b6a94Sdarrenm } 755734b6a94Sdarrenm 756734b6a94Sdarrenm /* all done, free context and return */ 757734b6a94Sdarrenm 758734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) { 759734b6a94Sdarrenm digest->cd_length = MD5_DIGEST_LENGTH; 760734b6a94Sdarrenm } else { 761734b6a94Sdarrenm digest->cd_length = 0; 762734b6a94Sdarrenm } 763734b6a94Sdarrenm 764734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 765734b6a94Sdarrenm ctx->cc_provider_private = NULL; 766734b6a94Sdarrenm 767734b6a94Sdarrenm return (ret); 768734b6a94Sdarrenm } 769734b6a94Sdarrenm 770734b6a94Sdarrenm /* ARGSUSED */ 771734b6a94Sdarrenm static int 772734b6a94Sdarrenm md5_digest_atomic(crypto_provider_handle_t provider, 773734b6a94Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 774734b6a94Sdarrenm crypto_data_t *data, crypto_data_t *digest, 775734b6a94Sdarrenm crypto_req_handle_t req) 776734b6a94Sdarrenm { 777734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 778734b6a94Sdarrenm MD5_CTX md5_ctx; 779734b6a94Sdarrenm 780734b6a94Sdarrenm if (mechanism->cm_type != MD5_MECH_INFO_TYPE) 781734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 782734b6a94Sdarrenm 783734b6a94Sdarrenm /* 784734b6a94Sdarrenm * Do the MD5 init. 785734b6a94Sdarrenm */ 786734b6a94Sdarrenm MD5Init(&md5_ctx); 787734b6a94Sdarrenm 788734b6a94Sdarrenm /* 789734b6a94Sdarrenm * Do the MD5 update on the specified input data. 790734b6a94Sdarrenm */ 791734b6a94Sdarrenm switch (data->cd_format) { 792734b6a94Sdarrenm case CRYPTO_DATA_RAW: 793734b6a94Sdarrenm MD5Update(&md5_ctx, data->cd_raw.iov_base + data->cd_offset, 794734b6a94Sdarrenm data->cd_length); 795734b6a94Sdarrenm break; 796734b6a94Sdarrenm case CRYPTO_DATA_UIO: 797734b6a94Sdarrenm ret = md5_digest_update_uio(&md5_ctx, data); 798734b6a94Sdarrenm break; 799734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 800734b6a94Sdarrenm ret = md5_digest_update_mblk(&md5_ctx, data); 801734b6a94Sdarrenm break; 802734b6a94Sdarrenm default: 803734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 804734b6a94Sdarrenm } 805734b6a94Sdarrenm 806734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) { 807734b6a94Sdarrenm /* the update failed, bail */ 808734b6a94Sdarrenm digest->cd_length = 0; 809734b6a94Sdarrenm return (ret); 810734b6a94Sdarrenm } 811734b6a94Sdarrenm 812734b6a94Sdarrenm /* 813734b6a94Sdarrenm * Do an MD5 final, must be done separately since the digest 814734b6a94Sdarrenm * type can be different than the input data type. 815734b6a94Sdarrenm */ 816734b6a94Sdarrenm switch (digest->cd_format) { 817734b6a94Sdarrenm case CRYPTO_DATA_RAW: 818734b6a94Sdarrenm MD5Final((unsigned char *)digest->cd_raw.iov_base + 819734b6a94Sdarrenm digest->cd_offset, &md5_ctx); 820734b6a94Sdarrenm break; 821734b6a94Sdarrenm case CRYPTO_DATA_UIO: 822734b6a94Sdarrenm ret = md5_digest_final_uio(&md5_ctx, digest, 823734b6a94Sdarrenm MD5_DIGEST_LENGTH, NULL); 824734b6a94Sdarrenm break; 825734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 826734b6a94Sdarrenm ret = md5_digest_final_mblk(&md5_ctx, digest, 827734b6a94Sdarrenm MD5_DIGEST_LENGTH, NULL); 828734b6a94Sdarrenm break; 829734b6a94Sdarrenm default: 830734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 831734b6a94Sdarrenm } 832734b6a94Sdarrenm 833734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) { 834734b6a94Sdarrenm digest->cd_length = MD5_DIGEST_LENGTH; 835734b6a94Sdarrenm } else { 836734b6a94Sdarrenm digest->cd_length = 0; 837734b6a94Sdarrenm } 838734b6a94Sdarrenm 839734b6a94Sdarrenm return (ret); 840734b6a94Sdarrenm } 841734b6a94Sdarrenm 842734b6a94Sdarrenm /* 843734b6a94Sdarrenm * KCF software provider mac entry points. 844734b6a94Sdarrenm * 845734b6a94Sdarrenm * MD5 HMAC is: MD5(key XOR opad, MD5(key XOR ipad, text)) 846734b6a94Sdarrenm * 847734b6a94Sdarrenm * Init: 848734b6a94Sdarrenm * The initialization routine initializes what we denote 849734b6a94Sdarrenm * as the inner and outer contexts by doing 850734b6a94Sdarrenm * - for inner context: MD5(key XOR ipad) 851734b6a94Sdarrenm * - for outer context: MD5(key XOR opad) 852734b6a94Sdarrenm * 853734b6a94Sdarrenm * Update: 854734b6a94Sdarrenm * Each subsequent MD5 HMAC update will result in an 855734b6a94Sdarrenm * update of the inner context with the specified data. 856734b6a94Sdarrenm * 857734b6a94Sdarrenm * Final: 858734b6a94Sdarrenm * The MD5 HMAC final will do a MD5 final operation on the 859734b6a94Sdarrenm * inner context, and the resulting digest will be used 860734b6a94Sdarrenm * as the data for an update on the outer context. Last 861734b6a94Sdarrenm * but not least, an MD5 final on the outer context will 862734b6a94Sdarrenm * be performed to obtain the MD5 HMAC digest to return 863734b6a94Sdarrenm * to the user. 864734b6a94Sdarrenm */ 865734b6a94Sdarrenm 866734b6a94Sdarrenm /* 867734b6a94Sdarrenm * Initialize a MD5-HMAC context. 868734b6a94Sdarrenm */ 869734b6a94Sdarrenm static void 870734b6a94Sdarrenm md5_mac_init_ctx(md5_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes) 871734b6a94Sdarrenm { 872734b6a94Sdarrenm uint32_t ipad[MD5_HMAC_INTS_PER_BLOCK]; 873734b6a94Sdarrenm uint32_t opad[MD5_HMAC_INTS_PER_BLOCK]; 874734b6a94Sdarrenm uint_t i; 875734b6a94Sdarrenm 876734b6a94Sdarrenm bzero(ipad, MD5_HMAC_BLOCK_SIZE); 877734b6a94Sdarrenm bzero(opad, MD5_HMAC_BLOCK_SIZE); 878734b6a94Sdarrenm 879734b6a94Sdarrenm bcopy(keyval, ipad, length_in_bytes); 880734b6a94Sdarrenm bcopy(keyval, opad, length_in_bytes); 881734b6a94Sdarrenm 882734b6a94Sdarrenm /* XOR key with ipad (0x36) and opad (0x5c) */ 883734b6a94Sdarrenm for (i = 0; i < MD5_HMAC_INTS_PER_BLOCK; i++) { 884734b6a94Sdarrenm ipad[i] ^= 0x36363636; 885734b6a94Sdarrenm opad[i] ^= 0x5c5c5c5c; 886734b6a94Sdarrenm } 887734b6a94Sdarrenm 888734b6a94Sdarrenm /* perform MD5 on ipad */ 889734b6a94Sdarrenm MD5Init(&ctx->hc_icontext); 890734b6a94Sdarrenm MD5Update(&ctx->hc_icontext, ipad, MD5_HMAC_BLOCK_SIZE); 891734b6a94Sdarrenm 892734b6a94Sdarrenm /* perform MD5 on opad */ 893734b6a94Sdarrenm MD5Init(&ctx->hc_ocontext); 894734b6a94Sdarrenm MD5Update(&ctx->hc_ocontext, opad, MD5_HMAC_BLOCK_SIZE); 895734b6a94Sdarrenm } 896734b6a94Sdarrenm 897734b6a94Sdarrenm /* 898734b6a94Sdarrenm * Initializes a multi-part MAC operation. 899734b6a94Sdarrenm */ 900734b6a94Sdarrenm static int 901734b6a94Sdarrenm md5_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 902734b6a94Sdarrenm crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 903734b6a94Sdarrenm crypto_req_handle_t req) 904734b6a94Sdarrenm { 905734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 906734b6a94Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 907734b6a94Sdarrenm 908734b6a94Sdarrenm if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 909734b6a94Sdarrenm mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 910734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 911734b6a94Sdarrenm 912734b6a94Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 913734b6a94Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 914734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 915734b6a94Sdarrenm 916734b6a94Sdarrenm ctx->cc_provider_private = kmem_alloc(sizeof (md5_hmac_ctx_t), 917734b6a94Sdarrenm crypto_kmflag(req)); 918734b6a94Sdarrenm if (ctx->cc_provider_private == NULL) 919734b6a94Sdarrenm return (CRYPTO_HOST_MEMORY); 920734b6a94Sdarrenm 921734b6a94Sdarrenm if (ctx_template != NULL) { 922734b6a94Sdarrenm /* reuse context template */ 923734b6a94Sdarrenm bcopy(ctx_template, PROV_MD5_HMAC_CTX(ctx), 924734b6a94Sdarrenm sizeof (md5_hmac_ctx_t)); 925734b6a94Sdarrenm } else { 926734b6a94Sdarrenm /* no context template, compute context */ 927734b6a94Sdarrenm if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 928734b6a94Sdarrenm uchar_t digested_key[MD5_DIGEST_LENGTH]; 929734b6a94Sdarrenm md5_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private; 930734b6a94Sdarrenm 931734b6a94Sdarrenm /* 932734b6a94Sdarrenm * Hash the passed-in key to get a smaller key. 933734b6a94Sdarrenm * The inner context is used since it hasn't been 934734b6a94Sdarrenm * initialized yet. 935734b6a94Sdarrenm */ 936734b6a94Sdarrenm PROV_MD5_DIGEST_KEY(&hmac_ctx->hc_icontext, 937734b6a94Sdarrenm key->ck_data, keylen_in_bytes, digested_key); 938734b6a94Sdarrenm md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx), 939734b6a94Sdarrenm digested_key, MD5_DIGEST_LENGTH); 940734b6a94Sdarrenm } else { 941734b6a94Sdarrenm md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx), 942734b6a94Sdarrenm key->ck_data, keylen_in_bytes); 943734b6a94Sdarrenm } 944734b6a94Sdarrenm } 945734b6a94Sdarrenm 946734b6a94Sdarrenm /* 947734b6a94Sdarrenm * Get the mechanism parameters, if applicable. 948734b6a94Sdarrenm */ 949734b6a94Sdarrenm PROV_MD5_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type; 950734b6a94Sdarrenm if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 951734b6a94Sdarrenm if (mechanism->cm_param == NULL || 952734b6a94Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) 953734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 954734b6a94Sdarrenm PROV_MD5_GET_DIGEST_LEN(mechanism, 955734b6a94Sdarrenm PROV_MD5_HMAC_CTX(ctx)->hc_digest_len); 956734b6a94Sdarrenm if (PROV_MD5_HMAC_CTX(ctx)->hc_digest_len > 957734b6a94Sdarrenm MD5_DIGEST_LENGTH) 958734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 959734b6a94Sdarrenm } 960734b6a94Sdarrenm 961734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) { 962734b6a94Sdarrenm bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 963734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 964734b6a94Sdarrenm ctx->cc_provider_private = NULL; 965734b6a94Sdarrenm } 966734b6a94Sdarrenm 967734b6a94Sdarrenm return (ret); 968734b6a94Sdarrenm } 969734b6a94Sdarrenm 970734b6a94Sdarrenm 971734b6a94Sdarrenm /* ARGSUSED */ 972734b6a94Sdarrenm static int 973734b6a94Sdarrenm md5_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req) 974734b6a94Sdarrenm { 975734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 976734b6a94Sdarrenm 977734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 978734b6a94Sdarrenm 979734b6a94Sdarrenm /* 980734b6a94Sdarrenm * Do an MD5 update of the inner context using the specified 981734b6a94Sdarrenm * data. 982734b6a94Sdarrenm */ 983734b6a94Sdarrenm switch (data->cd_format) { 984734b6a94Sdarrenm case CRYPTO_DATA_RAW: 985734b6a94Sdarrenm MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_icontext, 986734b6a94Sdarrenm data->cd_raw.iov_base + data->cd_offset, 987734b6a94Sdarrenm data->cd_length); 988734b6a94Sdarrenm break; 989734b6a94Sdarrenm case CRYPTO_DATA_UIO: 990734b6a94Sdarrenm ret = md5_digest_update_uio( 991734b6a94Sdarrenm &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data); 992734b6a94Sdarrenm break; 993734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 994734b6a94Sdarrenm ret = md5_digest_update_mblk( 995734b6a94Sdarrenm &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data); 996734b6a94Sdarrenm break; 997734b6a94Sdarrenm default: 998734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 999734b6a94Sdarrenm } 1000734b6a94Sdarrenm 1001734b6a94Sdarrenm return (ret); 1002734b6a94Sdarrenm } 1003734b6a94Sdarrenm 1004734b6a94Sdarrenm /* ARGSUSED */ 1005734b6a94Sdarrenm static int 1006734b6a94Sdarrenm md5_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req) 1007734b6a94Sdarrenm { 1008734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 1009734b6a94Sdarrenm uchar_t digest[MD5_DIGEST_LENGTH]; 1010734b6a94Sdarrenm uint32_t digest_len = MD5_DIGEST_LENGTH; 1011734b6a94Sdarrenm 1012734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 1013734b6a94Sdarrenm 1014734b6a94Sdarrenm if (PROV_MD5_HMAC_CTX(ctx)->hc_mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE) 1015734b6a94Sdarrenm digest_len = PROV_MD5_HMAC_CTX(ctx)->hc_digest_len; 1016734b6a94Sdarrenm 1017734b6a94Sdarrenm /* 1018734b6a94Sdarrenm * We need to just return the length needed to store the output. 1019734b6a94Sdarrenm * We should not destroy the context for the following cases. 1020734b6a94Sdarrenm */ 1021734b6a94Sdarrenm if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) { 1022734b6a94Sdarrenm mac->cd_length = digest_len; 1023734b6a94Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 1024734b6a94Sdarrenm } 1025734b6a94Sdarrenm 1026734b6a94Sdarrenm /* 1027734b6a94Sdarrenm * Do an MD5 final on the inner context. 1028734b6a94Sdarrenm */ 1029734b6a94Sdarrenm MD5Final(digest, &PROV_MD5_HMAC_CTX(ctx)->hc_icontext); 1030734b6a94Sdarrenm 1031734b6a94Sdarrenm /* 1032734b6a94Sdarrenm * Do an MD5 update on the outer context, feeding the inner 1033734b6a94Sdarrenm * digest as data. 1034734b6a94Sdarrenm */ 1035734b6a94Sdarrenm MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, digest, 1036734b6a94Sdarrenm MD5_DIGEST_LENGTH); 1037734b6a94Sdarrenm 1038734b6a94Sdarrenm /* 1039734b6a94Sdarrenm * Do an MD5 final on the outer context, storing the computing 1040734b6a94Sdarrenm * digest in the users buffer. 1041734b6a94Sdarrenm */ 1042734b6a94Sdarrenm switch (mac->cd_format) { 1043734b6a94Sdarrenm case CRYPTO_DATA_RAW: 1044734b6a94Sdarrenm if (digest_len != MD5_DIGEST_LENGTH) { 1045734b6a94Sdarrenm /* 1046734b6a94Sdarrenm * The caller requested a short digest. Digest 1047734b6a94Sdarrenm * into a scratch buffer and return to 1048734b6a94Sdarrenm * the user only what was requested. 1049734b6a94Sdarrenm */ 1050734b6a94Sdarrenm MD5Final(digest, 1051734b6a94Sdarrenm &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext); 1052734b6a94Sdarrenm bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1053734b6a94Sdarrenm mac->cd_offset, digest_len); 1054734b6a94Sdarrenm } else { 1055734b6a94Sdarrenm MD5Final((unsigned char *)mac->cd_raw.iov_base + 1056734b6a94Sdarrenm mac->cd_offset, 1057734b6a94Sdarrenm &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext); 1058734b6a94Sdarrenm } 1059734b6a94Sdarrenm break; 1060734b6a94Sdarrenm case CRYPTO_DATA_UIO: 1061734b6a94Sdarrenm ret = md5_digest_final_uio( 1062734b6a94Sdarrenm &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac, 1063734b6a94Sdarrenm digest_len, digest); 1064734b6a94Sdarrenm break; 1065734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 1066734b6a94Sdarrenm ret = md5_digest_final_mblk( 1067734b6a94Sdarrenm &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac, 1068734b6a94Sdarrenm digest_len, digest); 1069734b6a94Sdarrenm break; 1070734b6a94Sdarrenm default: 1071734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 1072734b6a94Sdarrenm } 1073734b6a94Sdarrenm 1074734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) { 1075734b6a94Sdarrenm mac->cd_length = digest_len; 1076734b6a94Sdarrenm } else { 1077734b6a94Sdarrenm mac->cd_length = 0; 1078734b6a94Sdarrenm } 1079734b6a94Sdarrenm 1080734b6a94Sdarrenm bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1081734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1082734b6a94Sdarrenm ctx->cc_provider_private = NULL; 1083734b6a94Sdarrenm 1084734b6a94Sdarrenm return (ret); 1085734b6a94Sdarrenm } 1086734b6a94Sdarrenm 1087734b6a94Sdarrenm #define MD5_MAC_UPDATE(data, ctx, ret) { \ 1088734b6a94Sdarrenm switch (data->cd_format) { \ 1089734b6a94Sdarrenm case CRYPTO_DATA_RAW: \ 1090734b6a94Sdarrenm MD5Update(&(ctx).hc_icontext, \ 1091734b6a94Sdarrenm data->cd_raw.iov_base + data->cd_offset, \ 1092734b6a94Sdarrenm data->cd_length); \ 1093734b6a94Sdarrenm break; \ 1094734b6a94Sdarrenm case CRYPTO_DATA_UIO: \ 1095734b6a94Sdarrenm ret = md5_digest_update_uio(&(ctx).hc_icontext, data); \ 1096734b6a94Sdarrenm break; \ 1097734b6a94Sdarrenm case CRYPTO_DATA_MBLK: \ 1098734b6a94Sdarrenm ret = md5_digest_update_mblk(&(ctx).hc_icontext, \ 1099734b6a94Sdarrenm data); \ 1100734b6a94Sdarrenm break; \ 1101734b6a94Sdarrenm default: \ 1102734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; \ 1103734b6a94Sdarrenm } \ 1104734b6a94Sdarrenm } 1105734b6a94Sdarrenm 1106734b6a94Sdarrenm 1107734b6a94Sdarrenm /* ARGSUSED */ 1108734b6a94Sdarrenm static int 1109734b6a94Sdarrenm md5_mac_atomic(crypto_provider_handle_t provider, 1110734b6a94Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1111734b6a94Sdarrenm crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1112734b6a94Sdarrenm crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1113734b6a94Sdarrenm { 1114734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 1115734b6a94Sdarrenm uchar_t digest[MD5_DIGEST_LENGTH]; 1116734b6a94Sdarrenm md5_hmac_ctx_t md5_hmac_ctx; 1117734b6a94Sdarrenm uint32_t digest_len = MD5_DIGEST_LENGTH; 1118734b6a94Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1119734b6a94Sdarrenm 1120734b6a94Sdarrenm if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1121734b6a94Sdarrenm mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1122734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 1123734b6a94Sdarrenm 1124734b6a94Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 1125734b6a94Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 1126734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 1127734b6a94Sdarrenm 1128734b6a94Sdarrenm if (ctx_template != NULL) { 1129734b6a94Sdarrenm /* reuse context template */ 1130734b6a94Sdarrenm bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1131734b6a94Sdarrenm } else { 1132734b6a94Sdarrenm /* no context template, compute context */ 1133734b6a94Sdarrenm if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1134734b6a94Sdarrenm /* 1135734b6a94Sdarrenm * Hash the passed-in key to get a smaller key. 1136734b6a94Sdarrenm * The inner context is used since it hasn't been 1137734b6a94Sdarrenm * initialized yet. 1138734b6a94Sdarrenm */ 1139734b6a94Sdarrenm PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext, 1140734b6a94Sdarrenm key->ck_data, keylen_in_bytes, digest); 1141734b6a94Sdarrenm md5_mac_init_ctx(&md5_hmac_ctx, digest, 1142734b6a94Sdarrenm MD5_DIGEST_LENGTH); 1143734b6a94Sdarrenm } else { 1144734b6a94Sdarrenm md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data, 1145734b6a94Sdarrenm keylen_in_bytes); 1146734b6a94Sdarrenm } 1147734b6a94Sdarrenm } 1148734b6a94Sdarrenm 1149734b6a94Sdarrenm /* 1150734b6a94Sdarrenm * Get the mechanism parameters, if applicable. 1151734b6a94Sdarrenm */ 1152734b6a94Sdarrenm if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1153734b6a94Sdarrenm if (mechanism->cm_param == NULL || 1154734b6a94Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) { 1155734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1156734b6a94Sdarrenm goto bail; 1157734b6a94Sdarrenm } 1158734b6a94Sdarrenm PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len); 1159734b6a94Sdarrenm if (digest_len > MD5_DIGEST_LENGTH) { 1160734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1161734b6a94Sdarrenm goto bail; 1162734b6a94Sdarrenm } 1163734b6a94Sdarrenm } 1164734b6a94Sdarrenm 1165734b6a94Sdarrenm /* do an MD5 update of the inner context using the specified data */ 1166734b6a94Sdarrenm MD5_MAC_UPDATE(data, md5_hmac_ctx, ret); 1167734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) 1168734b6a94Sdarrenm /* the update failed, free context and bail */ 1169734b6a94Sdarrenm goto bail; 1170734b6a94Sdarrenm 1171734b6a94Sdarrenm /* do an MD5 final on the inner context */ 1172734b6a94Sdarrenm MD5Final(digest, &md5_hmac_ctx.hc_icontext); 1173734b6a94Sdarrenm 1174734b6a94Sdarrenm /* 1175734b6a94Sdarrenm * Do an MD5 update on the outer context, feeding the inner 1176734b6a94Sdarrenm * digest as data. 1177734b6a94Sdarrenm */ 1178734b6a94Sdarrenm MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH); 1179734b6a94Sdarrenm 1180734b6a94Sdarrenm /* 1181734b6a94Sdarrenm * Do an MD5 final on the outer context, storing the computed 1182734b6a94Sdarrenm * digest in the users buffer. 1183734b6a94Sdarrenm */ 1184734b6a94Sdarrenm switch (mac->cd_format) { 1185734b6a94Sdarrenm case CRYPTO_DATA_RAW: 1186734b6a94Sdarrenm if (digest_len != MD5_DIGEST_LENGTH) { 1187734b6a94Sdarrenm /* 1188734b6a94Sdarrenm * The caller requested a short digest. Digest 1189734b6a94Sdarrenm * into a scratch buffer and return to 1190734b6a94Sdarrenm * the user only what was requested. 1191734b6a94Sdarrenm */ 1192734b6a94Sdarrenm MD5Final(digest, &md5_hmac_ctx.hc_ocontext); 1193734b6a94Sdarrenm bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1194734b6a94Sdarrenm mac->cd_offset, digest_len); 1195734b6a94Sdarrenm } else { 1196734b6a94Sdarrenm MD5Final((unsigned char *)mac->cd_raw.iov_base + 1197734b6a94Sdarrenm mac->cd_offset, &md5_hmac_ctx.hc_ocontext); 1198734b6a94Sdarrenm } 1199734b6a94Sdarrenm break; 1200734b6a94Sdarrenm case CRYPTO_DATA_UIO: 1201734b6a94Sdarrenm ret = md5_digest_final_uio(&md5_hmac_ctx.hc_ocontext, mac, 1202734b6a94Sdarrenm digest_len, digest); 1203734b6a94Sdarrenm break; 1204734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 1205734b6a94Sdarrenm ret = md5_digest_final_mblk(&md5_hmac_ctx.hc_ocontext, mac, 1206734b6a94Sdarrenm digest_len, digest); 1207734b6a94Sdarrenm break; 1208734b6a94Sdarrenm default: 1209734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 1210734b6a94Sdarrenm } 1211734b6a94Sdarrenm 1212734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) { 1213734b6a94Sdarrenm mac->cd_length = digest_len; 1214734b6a94Sdarrenm } else { 1215734b6a94Sdarrenm mac->cd_length = 0; 1216734b6a94Sdarrenm } 1217734b6a94Sdarrenm /* Extra paranoia: zeroizing the local context on the stack */ 1218734b6a94Sdarrenm bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1219734b6a94Sdarrenm 1220734b6a94Sdarrenm return (ret); 1221734b6a94Sdarrenm bail: 1222734b6a94Sdarrenm bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1223734b6a94Sdarrenm mac->cd_length = 0; 1224734b6a94Sdarrenm return (ret); 1225734b6a94Sdarrenm } 1226734b6a94Sdarrenm 1227734b6a94Sdarrenm /* ARGSUSED */ 1228734b6a94Sdarrenm static int 1229734b6a94Sdarrenm md5_mac_verify_atomic(crypto_provider_handle_t provider, 1230734b6a94Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1231734b6a94Sdarrenm crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1232734b6a94Sdarrenm crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1233734b6a94Sdarrenm { 1234734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 1235734b6a94Sdarrenm uchar_t digest[MD5_DIGEST_LENGTH]; 1236734b6a94Sdarrenm md5_hmac_ctx_t md5_hmac_ctx; 1237734b6a94Sdarrenm uint32_t digest_len = MD5_DIGEST_LENGTH; 1238734b6a94Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1239734b6a94Sdarrenm 1240734b6a94Sdarrenm if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1241734b6a94Sdarrenm mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1242734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 1243734b6a94Sdarrenm 1244734b6a94Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 1245734b6a94Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 1246734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 1247734b6a94Sdarrenm 1248734b6a94Sdarrenm if (ctx_template != NULL) { 1249734b6a94Sdarrenm /* reuse context template */ 1250734b6a94Sdarrenm bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1251734b6a94Sdarrenm } else { 1252734b6a94Sdarrenm /* no context template, compute context */ 1253734b6a94Sdarrenm if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1254734b6a94Sdarrenm /* 1255734b6a94Sdarrenm * Hash the passed-in key to get a smaller key. 1256734b6a94Sdarrenm * The inner context is used since it hasn't been 1257734b6a94Sdarrenm * initialized yet. 1258734b6a94Sdarrenm */ 1259734b6a94Sdarrenm PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext, 1260734b6a94Sdarrenm key->ck_data, keylen_in_bytes, digest); 1261734b6a94Sdarrenm md5_mac_init_ctx(&md5_hmac_ctx, digest, 1262734b6a94Sdarrenm MD5_DIGEST_LENGTH); 1263734b6a94Sdarrenm } else { 1264734b6a94Sdarrenm md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data, 1265734b6a94Sdarrenm keylen_in_bytes); 1266734b6a94Sdarrenm } 1267734b6a94Sdarrenm } 1268734b6a94Sdarrenm 1269734b6a94Sdarrenm /* 1270734b6a94Sdarrenm * Get the mechanism parameters, if applicable. 1271734b6a94Sdarrenm */ 1272734b6a94Sdarrenm if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1273734b6a94Sdarrenm if (mechanism->cm_param == NULL || 1274734b6a94Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) { 1275734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1276734b6a94Sdarrenm goto bail; 1277734b6a94Sdarrenm } 1278734b6a94Sdarrenm PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len); 1279734b6a94Sdarrenm if (digest_len > MD5_DIGEST_LENGTH) { 1280734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1281734b6a94Sdarrenm goto bail; 1282734b6a94Sdarrenm } 1283734b6a94Sdarrenm } 1284734b6a94Sdarrenm 1285734b6a94Sdarrenm if (mac->cd_length != digest_len) { 1286734b6a94Sdarrenm ret = CRYPTO_INVALID_MAC; 1287734b6a94Sdarrenm goto bail; 1288734b6a94Sdarrenm } 1289734b6a94Sdarrenm 1290734b6a94Sdarrenm /* do an MD5 update of the inner context using the specified data */ 1291734b6a94Sdarrenm MD5_MAC_UPDATE(data, md5_hmac_ctx, ret); 1292734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) 1293734b6a94Sdarrenm /* the update failed, free context and bail */ 1294734b6a94Sdarrenm goto bail; 1295734b6a94Sdarrenm 1296734b6a94Sdarrenm /* do an MD5 final on the inner context */ 1297734b6a94Sdarrenm MD5Final(digest, &md5_hmac_ctx.hc_icontext); 1298734b6a94Sdarrenm 1299734b6a94Sdarrenm /* 1300734b6a94Sdarrenm * Do an MD5 update on the outer context, feeding the inner 1301734b6a94Sdarrenm * digest as data. 1302734b6a94Sdarrenm */ 1303734b6a94Sdarrenm MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH); 1304734b6a94Sdarrenm 1305734b6a94Sdarrenm /* 1306734b6a94Sdarrenm * Do an MD5 final on the outer context, storing the computed 1307734b6a94Sdarrenm * digest in the local digest buffer. 1308734b6a94Sdarrenm */ 1309734b6a94Sdarrenm MD5Final(digest, &md5_hmac_ctx.hc_ocontext); 1310734b6a94Sdarrenm 1311734b6a94Sdarrenm /* 1312734b6a94Sdarrenm * Compare the computed digest against the expected digest passed 1313734b6a94Sdarrenm * as argument. 1314734b6a94Sdarrenm */ 1315734b6a94Sdarrenm switch (mac->cd_format) { 1316734b6a94Sdarrenm 1317734b6a94Sdarrenm case CRYPTO_DATA_RAW: 1318734b6a94Sdarrenm if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base + 1319734b6a94Sdarrenm mac->cd_offset, digest_len) != 0) 1320734b6a94Sdarrenm ret = CRYPTO_INVALID_MAC; 1321734b6a94Sdarrenm break; 1322734b6a94Sdarrenm 1323734b6a94Sdarrenm case CRYPTO_DATA_UIO: { 1324734b6a94Sdarrenm off_t offset = mac->cd_offset; 1325734b6a94Sdarrenm uint_t vec_idx; 1326734b6a94Sdarrenm off_t scratch_offset = 0; 1327734b6a94Sdarrenm size_t length = digest_len; 1328734b6a94Sdarrenm size_t cur_len; 1329734b6a94Sdarrenm 1330734b6a94Sdarrenm /* we support only kernel buffer */ 1331734b6a94Sdarrenm if (mac->cd_uio->uio_segflg != UIO_SYSSPACE) 1332734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 1333734b6a94Sdarrenm 1334734b6a94Sdarrenm /* jump to the first iovec containing the expected digest */ 1335734b6a94Sdarrenm for (vec_idx = 0; 1336734b6a94Sdarrenm offset >= mac->cd_uio->uio_iov[vec_idx].iov_len && 1337734b6a94Sdarrenm vec_idx < mac->cd_uio->uio_iovcnt; 1338d2b32306Smcpowers offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len) 1339d2b32306Smcpowers ; 1340734b6a94Sdarrenm if (vec_idx == mac->cd_uio->uio_iovcnt) { 1341734b6a94Sdarrenm /* 1342734b6a94Sdarrenm * The caller specified an offset that is 1343734b6a94Sdarrenm * larger than the total size of the buffers 1344734b6a94Sdarrenm * it provided. 1345734b6a94Sdarrenm */ 1346734b6a94Sdarrenm ret = CRYPTO_DATA_LEN_RANGE; 1347734b6a94Sdarrenm break; 1348734b6a94Sdarrenm } 1349734b6a94Sdarrenm 1350734b6a94Sdarrenm /* do the comparison of computed digest vs specified one */ 1351734b6a94Sdarrenm while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) { 1352734b6a94Sdarrenm cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len - 1353734b6a94Sdarrenm offset, length); 1354734b6a94Sdarrenm 1355734b6a94Sdarrenm if (bcmp(digest + scratch_offset, 1356734b6a94Sdarrenm mac->cd_uio->uio_iov[vec_idx].iov_base + offset, 1357734b6a94Sdarrenm cur_len) != 0) { 1358734b6a94Sdarrenm ret = CRYPTO_INVALID_MAC; 1359734b6a94Sdarrenm break; 1360734b6a94Sdarrenm } 1361734b6a94Sdarrenm 1362734b6a94Sdarrenm length -= cur_len; 1363734b6a94Sdarrenm vec_idx++; 1364734b6a94Sdarrenm scratch_offset += cur_len; 1365734b6a94Sdarrenm offset = 0; 1366734b6a94Sdarrenm } 1367734b6a94Sdarrenm break; 1368734b6a94Sdarrenm } 1369734b6a94Sdarrenm 1370734b6a94Sdarrenm case CRYPTO_DATA_MBLK: { 1371734b6a94Sdarrenm off_t offset = mac->cd_offset; 1372734b6a94Sdarrenm mblk_t *mp; 1373734b6a94Sdarrenm off_t scratch_offset = 0; 1374734b6a94Sdarrenm size_t length = digest_len; 1375734b6a94Sdarrenm size_t cur_len; 1376734b6a94Sdarrenm 1377734b6a94Sdarrenm /* jump to the first mblk_t containing the expected digest */ 1378734b6a94Sdarrenm for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp); 1379d2b32306Smcpowers offset -= MBLKL(mp), mp = mp->b_cont) 1380d2b32306Smcpowers ; 1381734b6a94Sdarrenm if (mp == NULL) { 1382734b6a94Sdarrenm /* 1383734b6a94Sdarrenm * The caller specified an offset that is larger than 1384734b6a94Sdarrenm * the total size of the buffers it provided. 1385734b6a94Sdarrenm */ 1386734b6a94Sdarrenm ret = CRYPTO_DATA_LEN_RANGE; 1387734b6a94Sdarrenm break; 1388734b6a94Sdarrenm } 1389734b6a94Sdarrenm 1390734b6a94Sdarrenm while (mp != NULL && length > 0) { 1391734b6a94Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 1392734b6a94Sdarrenm if (bcmp(digest + scratch_offset, 1393734b6a94Sdarrenm mp->b_rptr + offset, cur_len) != 0) { 1394734b6a94Sdarrenm ret = CRYPTO_INVALID_MAC; 1395734b6a94Sdarrenm break; 1396734b6a94Sdarrenm } 1397734b6a94Sdarrenm 1398734b6a94Sdarrenm length -= cur_len; 1399734b6a94Sdarrenm mp = mp->b_cont; 1400734b6a94Sdarrenm scratch_offset += cur_len; 1401734b6a94Sdarrenm offset = 0; 1402734b6a94Sdarrenm } 1403734b6a94Sdarrenm break; 1404734b6a94Sdarrenm } 1405734b6a94Sdarrenm 1406734b6a94Sdarrenm default: 1407734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 1408734b6a94Sdarrenm } 1409734b6a94Sdarrenm 1410734b6a94Sdarrenm bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1411734b6a94Sdarrenm return (ret); 1412734b6a94Sdarrenm bail: 1413734b6a94Sdarrenm bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1414734b6a94Sdarrenm mac->cd_length = 0; 1415734b6a94Sdarrenm return (ret); 1416734b6a94Sdarrenm } 1417734b6a94Sdarrenm 1418734b6a94Sdarrenm /* 1419734b6a94Sdarrenm * KCF software provider context management entry points. 1420734b6a94Sdarrenm */ 1421734b6a94Sdarrenm 1422734b6a94Sdarrenm /* ARGSUSED */ 1423734b6a94Sdarrenm static int 1424734b6a94Sdarrenm md5_create_ctx_template(crypto_provider_handle_t provider, 1425734b6a94Sdarrenm crypto_mechanism_t *mechanism, crypto_key_t *key, 1426734b6a94Sdarrenm crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size, 1427734b6a94Sdarrenm crypto_req_handle_t req) 1428734b6a94Sdarrenm { 1429734b6a94Sdarrenm md5_hmac_ctx_t *md5_hmac_ctx_tmpl; 1430734b6a94Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1431734b6a94Sdarrenm 1432734b6a94Sdarrenm if ((mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE) && 1433734b6a94Sdarrenm (mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)) 1434734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 1435734b6a94Sdarrenm 1436734b6a94Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 1437734b6a94Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 1438734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 1439734b6a94Sdarrenm 1440734b6a94Sdarrenm /* 1441734b6a94Sdarrenm * Allocate and initialize MD5 context. 1442734b6a94Sdarrenm */ 1443734b6a94Sdarrenm md5_hmac_ctx_tmpl = kmem_alloc(sizeof (md5_hmac_ctx_t), 1444734b6a94Sdarrenm crypto_kmflag(req)); 1445734b6a94Sdarrenm if (md5_hmac_ctx_tmpl == NULL) 1446734b6a94Sdarrenm return (CRYPTO_HOST_MEMORY); 1447734b6a94Sdarrenm 1448734b6a94Sdarrenm if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1449734b6a94Sdarrenm uchar_t digested_key[MD5_DIGEST_LENGTH]; 1450734b6a94Sdarrenm 1451734b6a94Sdarrenm /* 1452734b6a94Sdarrenm * Hash the passed-in key to get a smaller key. 1453734b6a94Sdarrenm * The inner context is used since it hasn't been 1454734b6a94Sdarrenm * initialized yet. 1455734b6a94Sdarrenm */ 1456734b6a94Sdarrenm PROV_MD5_DIGEST_KEY(&md5_hmac_ctx_tmpl->hc_icontext, 1457734b6a94Sdarrenm key->ck_data, keylen_in_bytes, digested_key); 1458734b6a94Sdarrenm md5_mac_init_ctx(md5_hmac_ctx_tmpl, digested_key, 1459734b6a94Sdarrenm MD5_DIGEST_LENGTH); 1460734b6a94Sdarrenm } else { 1461734b6a94Sdarrenm md5_mac_init_ctx(md5_hmac_ctx_tmpl, key->ck_data, 1462734b6a94Sdarrenm keylen_in_bytes); 1463734b6a94Sdarrenm } 1464734b6a94Sdarrenm 1465734b6a94Sdarrenm md5_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type; 1466734b6a94Sdarrenm *ctx_template = (crypto_spi_ctx_template_t)md5_hmac_ctx_tmpl; 1467734b6a94Sdarrenm *ctx_template_size = sizeof (md5_hmac_ctx_t); 1468734b6a94Sdarrenm 1469734b6a94Sdarrenm return (CRYPTO_SUCCESS); 1470734b6a94Sdarrenm } 1471734b6a94Sdarrenm 1472734b6a94Sdarrenm static int 1473734b6a94Sdarrenm md5_free_context(crypto_ctx_t *ctx) 1474734b6a94Sdarrenm { 1475734b6a94Sdarrenm uint_t ctx_len; 1476734b6a94Sdarrenm md5_mech_type_t mech_type; 1477734b6a94Sdarrenm 1478734b6a94Sdarrenm if (ctx->cc_provider_private == NULL) 1479734b6a94Sdarrenm return (CRYPTO_SUCCESS); 1480734b6a94Sdarrenm 1481734b6a94Sdarrenm /* 1482734b6a94Sdarrenm * We have to free either MD5 or MD5-HMAC contexts, which 1483734b6a94Sdarrenm * have different lengths. 1484734b6a94Sdarrenm */ 1485734b6a94Sdarrenm 1486734b6a94Sdarrenm mech_type = PROV_MD5_CTX(ctx)->mc_mech_type; 1487734b6a94Sdarrenm if (mech_type == MD5_MECH_INFO_TYPE) 1488734b6a94Sdarrenm ctx_len = sizeof (md5_ctx_t); 1489734b6a94Sdarrenm else { 1490734b6a94Sdarrenm ASSERT(mech_type == MD5_HMAC_MECH_INFO_TYPE || 1491734b6a94Sdarrenm mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE); 1492734b6a94Sdarrenm ctx_len = sizeof (md5_hmac_ctx_t); 1493734b6a94Sdarrenm } 1494734b6a94Sdarrenm 1495734b6a94Sdarrenm bzero(ctx->cc_provider_private, ctx_len); 1496734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, ctx_len); 1497734b6a94Sdarrenm ctx->cc_provider_private = NULL; 1498734b6a94Sdarrenm 1499734b6a94Sdarrenm return (CRYPTO_SUCCESS); 1500734b6a94Sdarrenm } 1501