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*5b675b31SVladimir Kotal * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24734b6a94Sdarrenm * Use is subject to license terms. 25734b6a94Sdarrenm */ 26734b6a94Sdarrenm 27734b6a94Sdarrenm #include <sys/modctl.h> 28734b6a94Sdarrenm #include <sys/cmn_err.h> 29734b6a94Sdarrenm #include <sys/crypto/common.h> 30734b6a94Sdarrenm #include <sys/crypto/spi.h> 31734b6a94Sdarrenm #include <sys/strsun.h> 32734b6a94Sdarrenm #include <sys/systm.h> 33734b6a94Sdarrenm #include <sys/sysmacros.h> 34734b6a94Sdarrenm #define _SHA2_IMPL 35734b6a94Sdarrenm #include <sys/sha2.h> 36734b6a94Sdarrenm 37734b6a94Sdarrenm /* 38734b6a94Sdarrenm * The sha2 module is created with two modlinkages: 39734b6a94Sdarrenm * - a modlmisc that allows consumers to directly call the entry points 40734b6a94Sdarrenm * SHA2Init, SHA2Update, and SHA2Final. 41734b6a94Sdarrenm * - a modlcrypto that allows the module to register with the Kernel 42734b6a94Sdarrenm * Cryptographic Framework (KCF) as a software provider for the SHA2 43734b6a94Sdarrenm * mechanisms. 44734b6a94Sdarrenm */ 45734b6a94Sdarrenm 46734b6a94Sdarrenm static struct modlmisc modlmisc = { 47734b6a94Sdarrenm &mod_miscops, 48734b6a94Sdarrenm "SHA2 Message-Digest Algorithm" 49734b6a94Sdarrenm }; 50734b6a94Sdarrenm 51734b6a94Sdarrenm static struct modlcrypto modlcrypto = { 52734b6a94Sdarrenm &mod_cryptoops, 53d2b32306Smcpowers "SHA2 Kernel SW Provider" 54734b6a94Sdarrenm }; 55734b6a94Sdarrenm 56734b6a94Sdarrenm static struct modlinkage modlinkage = { 57734b6a94Sdarrenm MODREV_1, &modlmisc, &modlcrypto, NULL 58734b6a94Sdarrenm }; 59734b6a94Sdarrenm 60734b6a94Sdarrenm /* 61734b6a94Sdarrenm * CSPI information (entry points, provider info, etc.) 62734b6a94Sdarrenm */ 63734b6a94Sdarrenm 64734b6a94Sdarrenm /* 65734b6a94Sdarrenm * Context for SHA2 mechanism. 66734b6a94Sdarrenm */ 67734b6a94Sdarrenm typedef struct sha2_ctx { 68734b6a94Sdarrenm sha2_mech_type_t sc_mech_type; /* type of context */ 69734b6a94Sdarrenm SHA2_CTX sc_sha2_ctx; /* SHA2 context */ 70734b6a94Sdarrenm } sha2_ctx_t; 71734b6a94Sdarrenm 72734b6a94Sdarrenm /* 73734b6a94Sdarrenm * Context for SHA2 HMAC and HMAC GENERAL mechanisms. 74734b6a94Sdarrenm */ 75734b6a94Sdarrenm typedef struct sha2_hmac_ctx { 76734b6a94Sdarrenm sha2_mech_type_t hc_mech_type; /* type of context */ 77734b6a94Sdarrenm uint32_t hc_digest_len; /* digest len in bytes */ 78734b6a94Sdarrenm SHA2_CTX hc_icontext; /* inner SHA2 context */ 79734b6a94Sdarrenm SHA2_CTX hc_ocontext; /* outer SHA2 context */ 80734b6a94Sdarrenm } sha2_hmac_ctx_t; 81734b6a94Sdarrenm 82734b6a94Sdarrenm /* 83734b6a94Sdarrenm * Macros to access the SHA2 or SHA2-HMAC contexts from a context passed 84734b6a94Sdarrenm * by KCF to one of the entry points. 85734b6a94Sdarrenm */ 86734b6a94Sdarrenm 87734b6a94Sdarrenm #define PROV_SHA2_CTX(ctx) ((sha2_ctx_t *)(ctx)->cc_provider_private) 88734b6a94Sdarrenm #define PROV_SHA2_HMAC_CTX(ctx) ((sha2_hmac_ctx_t *)(ctx)->cc_provider_private) 89734b6a94Sdarrenm 90734b6a94Sdarrenm /* to extract the digest length passed as mechanism parameter */ 91734b6a94Sdarrenm #define PROV_SHA2_GET_DIGEST_LEN(m, len) { \ 92734b6a94Sdarrenm if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t))) \ 93734b6a94Sdarrenm (len) = (uint32_t)*((ulong_t *)(m)->cm_param); \ 94734b6a94Sdarrenm else { \ 95734b6a94Sdarrenm ulong_t tmp_ulong; \ 96734b6a94Sdarrenm bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t)); \ 97734b6a94Sdarrenm (len) = (uint32_t)tmp_ulong; \ 98734b6a94Sdarrenm } \ 99734b6a94Sdarrenm } 100734b6a94Sdarrenm 101734b6a94Sdarrenm #define PROV_SHA2_DIGEST_KEY(mech, ctx, key, len, digest) { \ 102734b6a94Sdarrenm SHA2Init(mech, ctx); \ 103734b6a94Sdarrenm SHA2Update(ctx, key, len); \ 104734b6a94Sdarrenm SHA2Final(digest, ctx); \ 105734b6a94Sdarrenm } 106734b6a94Sdarrenm 107734b6a94Sdarrenm /* 108734b6a94Sdarrenm * Mechanism info structure passed to KCF during registration. 109734b6a94Sdarrenm */ 110734b6a94Sdarrenm static crypto_mech_info_t sha2_mech_info_tab[] = { 111734b6a94Sdarrenm /* SHA256 */ 112734b6a94Sdarrenm {SUN_CKM_SHA256, SHA256_MECH_INFO_TYPE, 113734b6a94Sdarrenm CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, 114734b6a94Sdarrenm 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, 115734b6a94Sdarrenm /* SHA256-HMAC */ 116734b6a94Sdarrenm {SUN_CKM_SHA256_HMAC, SHA256_HMAC_MECH_INFO_TYPE, 117734b6a94Sdarrenm CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 118734b6a94Sdarrenm SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN, 119*5b675b31SVladimir Kotal CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 120734b6a94Sdarrenm /* SHA256-HMAC GENERAL */ 121734b6a94Sdarrenm {SUN_CKM_SHA256_HMAC_GENERAL, SHA256_HMAC_GEN_MECH_INFO_TYPE, 122734b6a94Sdarrenm CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 123734b6a94Sdarrenm SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN, 124*5b675b31SVladimir Kotal CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 125734b6a94Sdarrenm /* SHA384 */ 126734b6a94Sdarrenm {SUN_CKM_SHA384, SHA384_MECH_INFO_TYPE, 127734b6a94Sdarrenm CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, 128734b6a94Sdarrenm 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, 129734b6a94Sdarrenm /* SHA384-HMAC */ 130734b6a94Sdarrenm {SUN_CKM_SHA384_HMAC, SHA384_HMAC_MECH_INFO_TYPE, 131734b6a94Sdarrenm CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 132734b6a94Sdarrenm SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN, 133*5b675b31SVladimir Kotal CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 134734b6a94Sdarrenm /* SHA384-HMAC GENERAL */ 135734b6a94Sdarrenm {SUN_CKM_SHA384_HMAC_GENERAL, SHA384_HMAC_GEN_MECH_INFO_TYPE, 136734b6a94Sdarrenm CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 137734b6a94Sdarrenm SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN, 138*5b675b31SVladimir Kotal CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 139734b6a94Sdarrenm /* SHA512 */ 140734b6a94Sdarrenm {SUN_CKM_SHA512, SHA512_MECH_INFO_TYPE, 141734b6a94Sdarrenm CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, 142734b6a94Sdarrenm 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, 143734b6a94Sdarrenm /* SHA512-HMAC */ 144734b6a94Sdarrenm {SUN_CKM_SHA512_HMAC, SHA512_HMAC_MECH_INFO_TYPE, 145734b6a94Sdarrenm CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 146734b6a94Sdarrenm SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN, 147*5b675b31SVladimir Kotal CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 148734b6a94Sdarrenm /* SHA512-HMAC GENERAL */ 149734b6a94Sdarrenm {SUN_CKM_SHA512_HMAC_GENERAL, SHA512_HMAC_GEN_MECH_INFO_TYPE, 150734b6a94Sdarrenm CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 151734b6a94Sdarrenm SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN, 152*5b675b31SVladimir Kotal CRYPTO_KEYSIZE_UNIT_IN_BYTES} 153734b6a94Sdarrenm }; 154734b6a94Sdarrenm 155734b6a94Sdarrenm static void sha2_provider_status(crypto_provider_handle_t, uint_t *); 156734b6a94Sdarrenm 157734b6a94Sdarrenm static crypto_control_ops_t sha2_control_ops = { 158734b6a94Sdarrenm sha2_provider_status 159734b6a94Sdarrenm }; 160734b6a94Sdarrenm 161734b6a94Sdarrenm static int sha2_digest_init(crypto_ctx_t *, crypto_mechanism_t *, 162734b6a94Sdarrenm crypto_req_handle_t); 163734b6a94Sdarrenm static int sha2_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 164734b6a94Sdarrenm crypto_req_handle_t); 165734b6a94Sdarrenm static int sha2_digest_update(crypto_ctx_t *, crypto_data_t *, 166734b6a94Sdarrenm crypto_req_handle_t); 167734b6a94Sdarrenm static int sha2_digest_final(crypto_ctx_t *, crypto_data_t *, 168734b6a94Sdarrenm crypto_req_handle_t); 169734b6a94Sdarrenm static int sha2_digest_atomic(crypto_provider_handle_t, crypto_session_id_t, 170734b6a94Sdarrenm crypto_mechanism_t *, crypto_data_t *, crypto_data_t *, 171734b6a94Sdarrenm crypto_req_handle_t); 172734b6a94Sdarrenm 173734b6a94Sdarrenm static crypto_digest_ops_t sha2_digest_ops = { 174734b6a94Sdarrenm sha2_digest_init, 175734b6a94Sdarrenm sha2_digest, 176734b6a94Sdarrenm sha2_digest_update, 177734b6a94Sdarrenm NULL, 178734b6a94Sdarrenm sha2_digest_final, 179734b6a94Sdarrenm sha2_digest_atomic 180734b6a94Sdarrenm }; 181734b6a94Sdarrenm 182734b6a94Sdarrenm static int sha2_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, 183734b6a94Sdarrenm crypto_spi_ctx_template_t, crypto_req_handle_t); 184734b6a94Sdarrenm static int sha2_mac_update(crypto_ctx_t *, crypto_data_t *, 185734b6a94Sdarrenm crypto_req_handle_t); 186734b6a94Sdarrenm static int sha2_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); 187734b6a94Sdarrenm static int sha2_mac_atomic(crypto_provider_handle_t, crypto_session_id_t, 188734b6a94Sdarrenm crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 189734b6a94Sdarrenm crypto_spi_ctx_template_t, crypto_req_handle_t); 190734b6a94Sdarrenm static int sha2_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t, 191734b6a94Sdarrenm crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 192734b6a94Sdarrenm crypto_spi_ctx_template_t, crypto_req_handle_t); 193734b6a94Sdarrenm 194734b6a94Sdarrenm static crypto_mac_ops_t sha2_mac_ops = { 195734b6a94Sdarrenm sha2_mac_init, 196734b6a94Sdarrenm NULL, 197734b6a94Sdarrenm sha2_mac_update, 198734b6a94Sdarrenm sha2_mac_final, 199734b6a94Sdarrenm sha2_mac_atomic, 200734b6a94Sdarrenm sha2_mac_verify_atomic 201734b6a94Sdarrenm }; 202734b6a94Sdarrenm 203734b6a94Sdarrenm static int sha2_create_ctx_template(crypto_provider_handle_t, 204734b6a94Sdarrenm crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *, 205734b6a94Sdarrenm size_t *, crypto_req_handle_t); 206734b6a94Sdarrenm static int sha2_free_context(crypto_ctx_t *); 207734b6a94Sdarrenm 208734b6a94Sdarrenm static crypto_ctx_ops_t sha2_ctx_ops = { 209734b6a94Sdarrenm sha2_create_ctx_template, 210734b6a94Sdarrenm sha2_free_context 211734b6a94Sdarrenm }; 212734b6a94Sdarrenm 213734b6a94Sdarrenm static crypto_ops_t sha2_crypto_ops = { 214734b6a94Sdarrenm &sha2_control_ops, 215734b6a94Sdarrenm &sha2_digest_ops, 216734b6a94Sdarrenm NULL, 217734b6a94Sdarrenm &sha2_mac_ops, 218734b6a94Sdarrenm NULL, 219734b6a94Sdarrenm NULL, 220734b6a94Sdarrenm NULL, 221734b6a94Sdarrenm NULL, 222734b6a94Sdarrenm NULL, 223734b6a94Sdarrenm NULL, 224734b6a94Sdarrenm NULL, 225734b6a94Sdarrenm NULL, 226734b6a94Sdarrenm NULL, 227734b6a94Sdarrenm &sha2_ctx_ops 228734b6a94Sdarrenm }; 229734b6a94Sdarrenm 230734b6a94Sdarrenm static crypto_provider_info_t sha2_prov_info = { 231734b6a94Sdarrenm CRYPTO_SPI_VERSION_1, 232734b6a94Sdarrenm "SHA2 Software Provider", 233734b6a94Sdarrenm CRYPTO_SW_PROVIDER, 234734b6a94Sdarrenm {&modlinkage}, 235734b6a94Sdarrenm NULL, 236734b6a94Sdarrenm &sha2_crypto_ops, 237734b6a94Sdarrenm sizeof (sha2_mech_info_tab)/sizeof (crypto_mech_info_t), 238734b6a94Sdarrenm sha2_mech_info_tab 239734b6a94Sdarrenm }; 240734b6a94Sdarrenm 241734b6a94Sdarrenm static crypto_kcf_provider_handle_t sha2_prov_handle = NULL; 242734b6a94Sdarrenm 243734b6a94Sdarrenm int 244734b6a94Sdarrenm _init() 245734b6a94Sdarrenm { 246734b6a94Sdarrenm int ret; 247734b6a94Sdarrenm 248734b6a94Sdarrenm if ((ret = mod_install(&modlinkage)) != 0) 249734b6a94Sdarrenm return (ret); 250734b6a94Sdarrenm 251734b6a94Sdarrenm /* 252734b6a94Sdarrenm * Register with KCF. If the registration fails, log an 253734b6a94Sdarrenm * error but do not uninstall the module, since the functionality 254734b6a94Sdarrenm * provided by misc/sha2 should still be available. 255734b6a94Sdarrenm */ 256734b6a94Sdarrenm if ((ret = crypto_register_provider(&sha2_prov_info, 257734b6a94Sdarrenm &sha2_prov_handle)) != CRYPTO_SUCCESS) 258734b6a94Sdarrenm cmn_err(CE_WARN, "sha2 _init: " 259734b6a94Sdarrenm "crypto_register_provider() failed (0x%x)", ret); 260734b6a94Sdarrenm 261734b6a94Sdarrenm return (0); 262734b6a94Sdarrenm } 263734b6a94Sdarrenm 264734b6a94Sdarrenm int 265734b6a94Sdarrenm _info(struct modinfo *modinfop) 266734b6a94Sdarrenm { 267734b6a94Sdarrenm return (mod_info(&modlinkage, modinfop)); 268734b6a94Sdarrenm } 269734b6a94Sdarrenm 270734b6a94Sdarrenm /* 271734b6a94Sdarrenm * KCF software provider control entry points. 272734b6a94Sdarrenm */ 273734b6a94Sdarrenm /* ARGSUSED */ 274734b6a94Sdarrenm static void 275734b6a94Sdarrenm sha2_provider_status(crypto_provider_handle_t provider, uint_t *status) 276734b6a94Sdarrenm { 277734b6a94Sdarrenm *status = CRYPTO_PROVIDER_READY; 278734b6a94Sdarrenm } 279734b6a94Sdarrenm 280734b6a94Sdarrenm /* 281734b6a94Sdarrenm * KCF software provider digest entry points. 282734b6a94Sdarrenm */ 283734b6a94Sdarrenm 284734b6a94Sdarrenm static int 285734b6a94Sdarrenm sha2_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 286734b6a94Sdarrenm crypto_req_handle_t req) 287734b6a94Sdarrenm { 288734b6a94Sdarrenm 289734b6a94Sdarrenm /* 290734b6a94Sdarrenm * Allocate and initialize SHA2 context. 291734b6a94Sdarrenm */ 292734b6a94Sdarrenm ctx->cc_provider_private = kmem_alloc(sizeof (sha2_ctx_t), 293734b6a94Sdarrenm crypto_kmflag(req)); 294734b6a94Sdarrenm if (ctx->cc_provider_private == NULL) 295734b6a94Sdarrenm return (CRYPTO_HOST_MEMORY); 296734b6a94Sdarrenm 297734b6a94Sdarrenm PROV_SHA2_CTX(ctx)->sc_mech_type = mechanism->cm_type; 298734b6a94Sdarrenm SHA2Init(mechanism->cm_type, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx); 299734b6a94Sdarrenm 300734b6a94Sdarrenm return (CRYPTO_SUCCESS); 301734b6a94Sdarrenm } 302734b6a94Sdarrenm 303734b6a94Sdarrenm /* 304734b6a94Sdarrenm * Helper SHA2 digest update function for uio data. 305734b6a94Sdarrenm */ 306734b6a94Sdarrenm static int 307734b6a94Sdarrenm sha2_digest_update_uio(SHA2_CTX *sha2_ctx, crypto_data_t *data) 308734b6a94Sdarrenm { 309734b6a94Sdarrenm off_t offset = data->cd_offset; 310734b6a94Sdarrenm size_t length = data->cd_length; 311734b6a94Sdarrenm uint_t vec_idx; 312734b6a94Sdarrenm size_t cur_len; 313734b6a94Sdarrenm 314734b6a94Sdarrenm /* we support only kernel buffer */ 315734b6a94Sdarrenm if (data->cd_uio->uio_segflg != UIO_SYSSPACE) 316734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 317734b6a94Sdarrenm 318734b6a94Sdarrenm /* 319734b6a94Sdarrenm * Jump to the first iovec containing data to be 320734b6a94Sdarrenm * digested. 321734b6a94Sdarrenm */ 322734b6a94Sdarrenm for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt && 323734b6a94Sdarrenm offset >= data->cd_uio->uio_iov[vec_idx].iov_len; 324d2b32306Smcpowers offset -= data->cd_uio->uio_iov[vec_idx++].iov_len) 325d2b32306Smcpowers ; 326734b6a94Sdarrenm if (vec_idx == data->cd_uio->uio_iovcnt) { 327734b6a94Sdarrenm /* 328734b6a94Sdarrenm * The caller specified an offset that is larger than the 329734b6a94Sdarrenm * total size of the buffers it provided. 330734b6a94Sdarrenm */ 331734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 332734b6a94Sdarrenm } 333734b6a94Sdarrenm 334734b6a94Sdarrenm /* 335734b6a94Sdarrenm * Now do the digesting on the iovecs. 336734b6a94Sdarrenm */ 337734b6a94Sdarrenm while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) { 338734b6a94Sdarrenm cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len - 339734b6a94Sdarrenm offset, length); 340734b6a94Sdarrenm 341734b6a94Sdarrenm SHA2Update(sha2_ctx, (uint8_t *)data->cd_uio-> 342734b6a94Sdarrenm uio_iov[vec_idx].iov_base + offset, cur_len); 343734b6a94Sdarrenm length -= cur_len; 344734b6a94Sdarrenm vec_idx++; 345734b6a94Sdarrenm offset = 0; 346734b6a94Sdarrenm } 347734b6a94Sdarrenm 348734b6a94Sdarrenm if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) { 349734b6a94Sdarrenm /* 350734b6a94Sdarrenm * The end of the specified iovec's was reached but 351734b6a94Sdarrenm * the length requested could not be processed, i.e. 352734b6a94Sdarrenm * The caller requested to digest more data than it provided. 353734b6a94Sdarrenm */ 354734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 355734b6a94Sdarrenm } 356734b6a94Sdarrenm 357734b6a94Sdarrenm return (CRYPTO_SUCCESS); 358734b6a94Sdarrenm } 359734b6a94Sdarrenm 360734b6a94Sdarrenm /* 361734b6a94Sdarrenm * Helper SHA2 digest final function for uio data. 362734b6a94Sdarrenm * digest_len is the length of the desired digest. If digest_len 363734b6a94Sdarrenm * is smaller than the default SHA2 digest length, the caller 364734b6a94Sdarrenm * must pass a scratch buffer, digest_scratch, which must 365734b6a94Sdarrenm * be at least the algorithm's digest length bytes. 366734b6a94Sdarrenm */ 367734b6a94Sdarrenm static int 368734b6a94Sdarrenm sha2_digest_final_uio(SHA2_CTX *sha2_ctx, crypto_data_t *digest, 369734b6a94Sdarrenm ulong_t digest_len, uchar_t *digest_scratch) 370734b6a94Sdarrenm { 371734b6a94Sdarrenm off_t offset = digest->cd_offset; 372734b6a94Sdarrenm uint_t vec_idx; 373734b6a94Sdarrenm 374734b6a94Sdarrenm /* we support only kernel buffer */ 375734b6a94Sdarrenm if (digest->cd_uio->uio_segflg != UIO_SYSSPACE) 376734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 377734b6a94Sdarrenm 378734b6a94Sdarrenm /* 379734b6a94Sdarrenm * Jump to the first iovec containing ptr to the digest to 380734b6a94Sdarrenm * be returned. 381734b6a94Sdarrenm */ 382734b6a94Sdarrenm for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len && 383734b6a94Sdarrenm vec_idx < digest->cd_uio->uio_iovcnt; 384d2b32306Smcpowers offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len) 385d2b32306Smcpowers ; 386734b6a94Sdarrenm if (vec_idx == digest->cd_uio->uio_iovcnt) { 387734b6a94Sdarrenm /* 388734b6a94Sdarrenm * The caller specified an offset that is 389734b6a94Sdarrenm * larger than the total size of the buffers 390734b6a94Sdarrenm * it provided. 391734b6a94Sdarrenm */ 392734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 393734b6a94Sdarrenm } 394734b6a94Sdarrenm 395734b6a94Sdarrenm if (offset + digest_len <= 396734b6a94Sdarrenm digest->cd_uio->uio_iov[vec_idx].iov_len) { 397734b6a94Sdarrenm /* 398734b6a94Sdarrenm * The computed SHA2 digest will fit in the current 399734b6a94Sdarrenm * iovec. 400734b6a94Sdarrenm */ 401734b6a94Sdarrenm if (((sha2_ctx->algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) && 402734b6a94Sdarrenm (digest_len != SHA256_DIGEST_LENGTH)) || 403734b6a94Sdarrenm ((sha2_ctx->algotype > SHA256_HMAC_GEN_MECH_INFO_TYPE) && 404734b6a94Sdarrenm (digest_len != SHA512_DIGEST_LENGTH))) { 405734b6a94Sdarrenm /* 406734b6a94Sdarrenm * The caller requested a short digest. Digest 407734b6a94Sdarrenm * into a scratch buffer and return to 408734b6a94Sdarrenm * the user only what was requested. 409734b6a94Sdarrenm */ 410734b6a94Sdarrenm SHA2Final(digest_scratch, sha2_ctx); 411734b6a94Sdarrenm 412734b6a94Sdarrenm bcopy(digest_scratch, (uchar_t *)digest-> 413734b6a94Sdarrenm cd_uio->uio_iov[vec_idx].iov_base + offset, 414734b6a94Sdarrenm digest_len); 415734b6a94Sdarrenm } else { 416734b6a94Sdarrenm SHA2Final((uchar_t *)digest-> 417734b6a94Sdarrenm cd_uio->uio_iov[vec_idx].iov_base + offset, 418734b6a94Sdarrenm sha2_ctx); 419734b6a94Sdarrenm 420734b6a94Sdarrenm } 421734b6a94Sdarrenm } else { 422734b6a94Sdarrenm /* 423734b6a94Sdarrenm * The computed digest will be crossing one or more iovec's. 424734b6a94Sdarrenm * This is bad performance-wise but we need to support it. 425734b6a94Sdarrenm * Allocate a small scratch buffer on the stack and 426734b6a94Sdarrenm * copy it piece meal to the specified digest iovec's. 427734b6a94Sdarrenm */ 428734b6a94Sdarrenm uchar_t digest_tmp[SHA512_DIGEST_LENGTH]; 429734b6a94Sdarrenm off_t scratch_offset = 0; 430734b6a94Sdarrenm size_t length = digest_len; 431734b6a94Sdarrenm size_t cur_len; 432734b6a94Sdarrenm 433734b6a94Sdarrenm SHA2Final(digest_tmp, sha2_ctx); 434734b6a94Sdarrenm 435734b6a94Sdarrenm while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) { 436734b6a94Sdarrenm cur_len = 437734b6a94Sdarrenm MIN(digest->cd_uio->uio_iov[vec_idx].iov_len - 438734b6a94Sdarrenm offset, length); 439734b6a94Sdarrenm bcopy(digest_tmp + scratch_offset, 440734b6a94Sdarrenm digest->cd_uio->uio_iov[vec_idx].iov_base + offset, 441734b6a94Sdarrenm cur_len); 442734b6a94Sdarrenm 443734b6a94Sdarrenm length -= cur_len; 444734b6a94Sdarrenm vec_idx++; 445734b6a94Sdarrenm scratch_offset += cur_len; 446734b6a94Sdarrenm offset = 0; 447734b6a94Sdarrenm } 448734b6a94Sdarrenm 449734b6a94Sdarrenm if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) { 450734b6a94Sdarrenm /* 451734b6a94Sdarrenm * The end of the specified iovec's was reached but 452734b6a94Sdarrenm * the length requested could not be processed, i.e. 453734b6a94Sdarrenm * The caller requested to digest more data than it 454734b6a94Sdarrenm * provided. 455734b6a94Sdarrenm */ 456734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 457734b6a94Sdarrenm } 458734b6a94Sdarrenm } 459734b6a94Sdarrenm 460734b6a94Sdarrenm return (CRYPTO_SUCCESS); 461734b6a94Sdarrenm } 462734b6a94Sdarrenm 463734b6a94Sdarrenm /* 464734b6a94Sdarrenm * Helper SHA2 digest update for mblk's. 465734b6a94Sdarrenm */ 466734b6a94Sdarrenm static int 467734b6a94Sdarrenm sha2_digest_update_mblk(SHA2_CTX *sha2_ctx, crypto_data_t *data) 468734b6a94Sdarrenm { 469734b6a94Sdarrenm off_t offset = data->cd_offset; 470734b6a94Sdarrenm size_t length = data->cd_length; 471734b6a94Sdarrenm mblk_t *mp; 472734b6a94Sdarrenm size_t cur_len; 473734b6a94Sdarrenm 474734b6a94Sdarrenm /* 475734b6a94Sdarrenm * Jump to the first mblk_t containing data to be digested. 476734b6a94Sdarrenm */ 477734b6a94Sdarrenm for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp); 478d2b32306Smcpowers offset -= MBLKL(mp), mp = mp->b_cont) 479d2b32306Smcpowers ; 480734b6a94Sdarrenm if (mp == NULL) { 481734b6a94Sdarrenm /* 482734b6a94Sdarrenm * The caller specified an offset that is larger than the 483734b6a94Sdarrenm * total size of the buffers it provided. 484734b6a94Sdarrenm */ 485734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 486734b6a94Sdarrenm } 487734b6a94Sdarrenm 488734b6a94Sdarrenm /* 489734b6a94Sdarrenm * Now do the digesting on the mblk chain. 490734b6a94Sdarrenm */ 491734b6a94Sdarrenm while (mp != NULL && length > 0) { 492734b6a94Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 493734b6a94Sdarrenm SHA2Update(sha2_ctx, mp->b_rptr + offset, cur_len); 494734b6a94Sdarrenm length -= cur_len; 495734b6a94Sdarrenm offset = 0; 496734b6a94Sdarrenm mp = mp->b_cont; 497734b6a94Sdarrenm } 498734b6a94Sdarrenm 499734b6a94Sdarrenm if (mp == NULL && length > 0) { 500734b6a94Sdarrenm /* 501734b6a94Sdarrenm * The end of the mblk was reached but the length requested 502734b6a94Sdarrenm * could not be processed, i.e. The caller requested 503734b6a94Sdarrenm * to digest more data than it provided. 504734b6a94Sdarrenm */ 505734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 506734b6a94Sdarrenm } 507734b6a94Sdarrenm 508734b6a94Sdarrenm return (CRYPTO_SUCCESS); 509734b6a94Sdarrenm } 510734b6a94Sdarrenm 511734b6a94Sdarrenm /* 512734b6a94Sdarrenm * Helper SHA2 digest final for mblk's. 513734b6a94Sdarrenm * digest_len is the length of the desired digest. If digest_len 514734b6a94Sdarrenm * is smaller than the default SHA2 digest length, the caller 515734b6a94Sdarrenm * must pass a scratch buffer, digest_scratch, which must 516734b6a94Sdarrenm * be at least the algorithm's digest length bytes. 517734b6a94Sdarrenm */ 518734b6a94Sdarrenm static int 519734b6a94Sdarrenm sha2_digest_final_mblk(SHA2_CTX *sha2_ctx, crypto_data_t *digest, 520734b6a94Sdarrenm ulong_t digest_len, uchar_t *digest_scratch) 521734b6a94Sdarrenm { 522734b6a94Sdarrenm off_t offset = digest->cd_offset; 523734b6a94Sdarrenm mblk_t *mp; 524734b6a94Sdarrenm 525734b6a94Sdarrenm /* 526734b6a94Sdarrenm * Jump to the first mblk_t that will be used to store the digest. 527734b6a94Sdarrenm */ 528734b6a94Sdarrenm for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp); 529d2b32306Smcpowers offset -= MBLKL(mp), mp = mp->b_cont) 530d2b32306Smcpowers ; 531734b6a94Sdarrenm if (mp == NULL) { 532734b6a94Sdarrenm /* 533734b6a94Sdarrenm * The caller specified an offset that is larger than the 534734b6a94Sdarrenm * total size of the buffers it provided. 535734b6a94Sdarrenm */ 536734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 537734b6a94Sdarrenm } 538734b6a94Sdarrenm 539734b6a94Sdarrenm if (offset + digest_len <= MBLKL(mp)) { 540734b6a94Sdarrenm /* 541734b6a94Sdarrenm * The computed SHA2 digest will fit in the current mblk. 542734b6a94Sdarrenm * Do the SHA2Final() in-place. 543734b6a94Sdarrenm */ 544734b6a94Sdarrenm if (((sha2_ctx->algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) && 545734b6a94Sdarrenm (digest_len != SHA256_DIGEST_LENGTH)) || 546734b6a94Sdarrenm ((sha2_ctx->algotype > SHA256_HMAC_GEN_MECH_INFO_TYPE) && 547734b6a94Sdarrenm (digest_len != SHA512_DIGEST_LENGTH))) { 548734b6a94Sdarrenm /* 549734b6a94Sdarrenm * The caller requested a short digest. Digest 550734b6a94Sdarrenm * into a scratch buffer and return to 551734b6a94Sdarrenm * the user only what was requested. 552734b6a94Sdarrenm */ 553734b6a94Sdarrenm SHA2Final(digest_scratch, sha2_ctx); 554734b6a94Sdarrenm bcopy(digest_scratch, mp->b_rptr + offset, digest_len); 555734b6a94Sdarrenm } else { 556734b6a94Sdarrenm SHA2Final(mp->b_rptr + offset, sha2_ctx); 557734b6a94Sdarrenm } 558734b6a94Sdarrenm } else { 559734b6a94Sdarrenm /* 560734b6a94Sdarrenm * The computed digest will be crossing one or more mblk's. 561734b6a94Sdarrenm * This is bad performance-wise but we need to support it. 562734b6a94Sdarrenm * Allocate a small scratch buffer on the stack and 563734b6a94Sdarrenm * copy it piece meal to the specified digest iovec's. 564734b6a94Sdarrenm */ 565734b6a94Sdarrenm uchar_t digest_tmp[SHA512_DIGEST_LENGTH]; 566734b6a94Sdarrenm off_t scratch_offset = 0; 567734b6a94Sdarrenm size_t length = digest_len; 568734b6a94Sdarrenm size_t cur_len; 569734b6a94Sdarrenm 570734b6a94Sdarrenm SHA2Final(digest_tmp, sha2_ctx); 571734b6a94Sdarrenm 572734b6a94Sdarrenm while (mp != NULL && length > 0) { 573734b6a94Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 574734b6a94Sdarrenm bcopy(digest_tmp + scratch_offset, 575734b6a94Sdarrenm mp->b_rptr + offset, cur_len); 576734b6a94Sdarrenm 577734b6a94Sdarrenm length -= cur_len; 578734b6a94Sdarrenm mp = mp->b_cont; 579734b6a94Sdarrenm scratch_offset += cur_len; 580734b6a94Sdarrenm offset = 0; 581734b6a94Sdarrenm } 582734b6a94Sdarrenm 583734b6a94Sdarrenm if (mp == NULL && length > 0) { 584734b6a94Sdarrenm /* 585734b6a94Sdarrenm * The end of the specified mblk was reached but 586734b6a94Sdarrenm * the length requested could not be processed, i.e. 587734b6a94Sdarrenm * The caller requested to digest more data than it 588734b6a94Sdarrenm * provided. 589734b6a94Sdarrenm */ 590734b6a94Sdarrenm return (CRYPTO_DATA_LEN_RANGE); 591734b6a94Sdarrenm } 592734b6a94Sdarrenm } 593734b6a94Sdarrenm 594734b6a94Sdarrenm return (CRYPTO_SUCCESS); 595734b6a94Sdarrenm } 596734b6a94Sdarrenm 597734b6a94Sdarrenm /* ARGSUSED */ 598734b6a94Sdarrenm static int 599734b6a94Sdarrenm sha2_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest, 600734b6a94Sdarrenm crypto_req_handle_t req) 601734b6a94Sdarrenm { 602734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 603734b6a94Sdarrenm uint_t sha_digest_len; 604734b6a94Sdarrenm 605734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 606734b6a94Sdarrenm 607734b6a94Sdarrenm switch (PROV_SHA2_CTX(ctx)->sc_mech_type) { 608734b6a94Sdarrenm case SHA256_MECH_INFO_TYPE: 609734b6a94Sdarrenm sha_digest_len = SHA256_DIGEST_LENGTH; 610734b6a94Sdarrenm break; 611734b6a94Sdarrenm case SHA384_MECH_INFO_TYPE: 612734b6a94Sdarrenm sha_digest_len = SHA384_DIGEST_LENGTH; 613734b6a94Sdarrenm break; 614734b6a94Sdarrenm case SHA512_MECH_INFO_TYPE: 615734b6a94Sdarrenm sha_digest_len = SHA512_DIGEST_LENGTH; 616734b6a94Sdarrenm break; 617734b6a94Sdarrenm default: 618734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 619734b6a94Sdarrenm } 620734b6a94Sdarrenm 621734b6a94Sdarrenm /* 622734b6a94Sdarrenm * We need to just return the length needed to store the output. 623734b6a94Sdarrenm * We should not destroy the context for the following cases. 624734b6a94Sdarrenm */ 625734b6a94Sdarrenm if ((digest->cd_length == 0) || 626734b6a94Sdarrenm (digest->cd_length < sha_digest_len)) { 627734b6a94Sdarrenm digest->cd_length = sha_digest_len; 628734b6a94Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 629734b6a94Sdarrenm } 630734b6a94Sdarrenm 631734b6a94Sdarrenm /* 632734b6a94Sdarrenm * Do the SHA2 update on the specified input data. 633734b6a94Sdarrenm */ 634734b6a94Sdarrenm switch (data->cd_format) { 635734b6a94Sdarrenm case CRYPTO_DATA_RAW: 636734b6a94Sdarrenm SHA2Update(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 637734b6a94Sdarrenm (uint8_t *)data->cd_raw.iov_base + data->cd_offset, 638734b6a94Sdarrenm data->cd_length); 639734b6a94Sdarrenm break; 640734b6a94Sdarrenm case CRYPTO_DATA_UIO: 641734b6a94Sdarrenm ret = sha2_digest_update_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 642734b6a94Sdarrenm data); 643734b6a94Sdarrenm break; 644734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 645734b6a94Sdarrenm ret = sha2_digest_update_mblk(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 646734b6a94Sdarrenm data); 647734b6a94Sdarrenm break; 648734b6a94Sdarrenm default: 649734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 650734b6a94Sdarrenm } 651734b6a94Sdarrenm 652734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) { 653734b6a94Sdarrenm /* the update failed, free context and bail */ 654734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t)); 655734b6a94Sdarrenm ctx->cc_provider_private = NULL; 656734b6a94Sdarrenm digest->cd_length = 0; 657734b6a94Sdarrenm return (ret); 658734b6a94Sdarrenm } 659734b6a94Sdarrenm 660734b6a94Sdarrenm /* 661734b6a94Sdarrenm * Do a SHA2 final, must be done separately since the digest 662734b6a94Sdarrenm * type can be different than the input data type. 663734b6a94Sdarrenm */ 664734b6a94Sdarrenm switch (digest->cd_format) { 665734b6a94Sdarrenm case CRYPTO_DATA_RAW: 666734b6a94Sdarrenm SHA2Final((unsigned char *)digest->cd_raw.iov_base + 667734b6a94Sdarrenm digest->cd_offset, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx); 668734b6a94Sdarrenm break; 669734b6a94Sdarrenm case CRYPTO_DATA_UIO: 670734b6a94Sdarrenm ret = sha2_digest_final_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 671734b6a94Sdarrenm digest, sha_digest_len, NULL); 672734b6a94Sdarrenm break; 673734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 674734b6a94Sdarrenm ret = sha2_digest_final_mblk(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 675734b6a94Sdarrenm digest, sha_digest_len, NULL); 676734b6a94Sdarrenm break; 677734b6a94Sdarrenm default: 678734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 679734b6a94Sdarrenm } 680734b6a94Sdarrenm 681734b6a94Sdarrenm /* all done, free context and return */ 682734b6a94Sdarrenm 683734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) 684734b6a94Sdarrenm digest->cd_length = sha_digest_len; 685734b6a94Sdarrenm else 686734b6a94Sdarrenm digest->cd_length = 0; 687734b6a94Sdarrenm 688734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t)); 689734b6a94Sdarrenm ctx->cc_provider_private = NULL; 690734b6a94Sdarrenm return (ret); 691734b6a94Sdarrenm } 692734b6a94Sdarrenm 693734b6a94Sdarrenm /* ARGSUSED */ 694734b6a94Sdarrenm static int 695734b6a94Sdarrenm sha2_digest_update(crypto_ctx_t *ctx, crypto_data_t *data, 696734b6a94Sdarrenm crypto_req_handle_t req) 697734b6a94Sdarrenm { 698734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 699734b6a94Sdarrenm 700734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 701734b6a94Sdarrenm 702734b6a94Sdarrenm /* 703734b6a94Sdarrenm * Do the SHA2 update on the specified input data. 704734b6a94Sdarrenm */ 705734b6a94Sdarrenm switch (data->cd_format) { 706734b6a94Sdarrenm case CRYPTO_DATA_RAW: 707734b6a94Sdarrenm SHA2Update(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 708734b6a94Sdarrenm (uint8_t *)data->cd_raw.iov_base + data->cd_offset, 709734b6a94Sdarrenm data->cd_length); 710734b6a94Sdarrenm break; 711734b6a94Sdarrenm case CRYPTO_DATA_UIO: 712734b6a94Sdarrenm ret = sha2_digest_update_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 713734b6a94Sdarrenm data); 714734b6a94Sdarrenm break; 715734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 716734b6a94Sdarrenm ret = sha2_digest_update_mblk(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 717734b6a94Sdarrenm data); 718734b6a94Sdarrenm break; 719734b6a94Sdarrenm default: 720734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 721734b6a94Sdarrenm } 722734b6a94Sdarrenm 723734b6a94Sdarrenm return (ret); 724734b6a94Sdarrenm } 725734b6a94Sdarrenm 726734b6a94Sdarrenm /* ARGSUSED */ 727734b6a94Sdarrenm static int 728734b6a94Sdarrenm sha2_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest, 729734b6a94Sdarrenm crypto_req_handle_t req) 730734b6a94Sdarrenm { 731734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 732734b6a94Sdarrenm uint_t sha_digest_len; 733734b6a94Sdarrenm 734734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 735734b6a94Sdarrenm 736734b6a94Sdarrenm switch (PROV_SHA2_CTX(ctx)->sc_mech_type) { 737734b6a94Sdarrenm case SHA256_MECH_INFO_TYPE: 738734b6a94Sdarrenm sha_digest_len = SHA256_DIGEST_LENGTH; 739734b6a94Sdarrenm break; 740734b6a94Sdarrenm case SHA384_MECH_INFO_TYPE: 741734b6a94Sdarrenm sha_digest_len = SHA384_DIGEST_LENGTH; 742734b6a94Sdarrenm break; 743734b6a94Sdarrenm case SHA512_MECH_INFO_TYPE: 744734b6a94Sdarrenm sha_digest_len = SHA512_DIGEST_LENGTH; 745734b6a94Sdarrenm break; 746734b6a94Sdarrenm default: 747734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 748734b6a94Sdarrenm } 749734b6a94Sdarrenm 750734b6a94Sdarrenm /* 751734b6a94Sdarrenm * We need to just return the length needed to store the output. 752734b6a94Sdarrenm * We should not destroy the context for the following cases. 753734b6a94Sdarrenm */ 754734b6a94Sdarrenm if ((digest->cd_length == 0) || 755734b6a94Sdarrenm (digest->cd_length < sha_digest_len)) { 756734b6a94Sdarrenm digest->cd_length = sha_digest_len; 757734b6a94Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 758734b6a94Sdarrenm } 759734b6a94Sdarrenm 760734b6a94Sdarrenm /* 761734b6a94Sdarrenm * Do a SHA2 final. 762734b6a94Sdarrenm */ 763734b6a94Sdarrenm switch (digest->cd_format) { 764734b6a94Sdarrenm case CRYPTO_DATA_RAW: 765734b6a94Sdarrenm SHA2Final((unsigned char *)digest->cd_raw.iov_base + 766734b6a94Sdarrenm digest->cd_offset, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx); 767734b6a94Sdarrenm break; 768734b6a94Sdarrenm case CRYPTO_DATA_UIO: 769734b6a94Sdarrenm ret = sha2_digest_final_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 770734b6a94Sdarrenm digest, sha_digest_len, NULL); 771734b6a94Sdarrenm break; 772734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 773734b6a94Sdarrenm ret = sha2_digest_final_mblk(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx, 774734b6a94Sdarrenm digest, sha_digest_len, NULL); 775734b6a94Sdarrenm break; 776734b6a94Sdarrenm default: 777734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 778734b6a94Sdarrenm } 779734b6a94Sdarrenm 780734b6a94Sdarrenm /* all done, free context and return */ 781734b6a94Sdarrenm 782734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) 783734b6a94Sdarrenm digest->cd_length = sha_digest_len; 784734b6a94Sdarrenm else 785734b6a94Sdarrenm digest->cd_length = 0; 786734b6a94Sdarrenm 787734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t)); 788734b6a94Sdarrenm ctx->cc_provider_private = NULL; 789734b6a94Sdarrenm 790734b6a94Sdarrenm return (ret); 791734b6a94Sdarrenm } 792734b6a94Sdarrenm 793734b6a94Sdarrenm /* ARGSUSED */ 794734b6a94Sdarrenm static int 795734b6a94Sdarrenm sha2_digest_atomic(crypto_provider_handle_t provider, 796734b6a94Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 797734b6a94Sdarrenm crypto_data_t *data, crypto_data_t *digest, 798734b6a94Sdarrenm crypto_req_handle_t req) 799734b6a94Sdarrenm { 800734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 801734b6a94Sdarrenm SHA2_CTX sha2_ctx; 802734b6a94Sdarrenm uint32_t sha_digest_len; 803734b6a94Sdarrenm 804734b6a94Sdarrenm /* 805734b6a94Sdarrenm * Do the SHA inits. 806734b6a94Sdarrenm */ 807734b6a94Sdarrenm 808734b6a94Sdarrenm SHA2Init(mechanism->cm_type, &sha2_ctx); 809734b6a94Sdarrenm 810734b6a94Sdarrenm switch (data->cd_format) { 811734b6a94Sdarrenm case CRYPTO_DATA_RAW: 812734b6a94Sdarrenm SHA2Update(&sha2_ctx, (uint8_t *)data-> 813734b6a94Sdarrenm cd_raw.iov_base + data->cd_offset, data->cd_length); 814734b6a94Sdarrenm break; 815734b6a94Sdarrenm case CRYPTO_DATA_UIO: 816734b6a94Sdarrenm ret = sha2_digest_update_uio(&sha2_ctx, data); 817734b6a94Sdarrenm break; 818734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 819734b6a94Sdarrenm ret = sha2_digest_update_mblk(&sha2_ctx, data); 820734b6a94Sdarrenm break; 821734b6a94Sdarrenm default: 822734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 823734b6a94Sdarrenm } 824734b6a94Sdarrenm 825734b6a94Sdarrenm /* 826734b6a94Sdarrenm * Do the SHA updates on the specified input data. 827734b6a94Sdarrenm */ 828734b6a94Sdarrenm 829734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) { 830734b6a94Sdarrenm /* the update failed, bail */ 831734b6a94Sdarrenm digest->cd_length = 0; 832734b6a94Sdarrenm return (ret); 833734b6a94Sdarrenm } 834734b6a94Sdarrenm 835734b6a94Sdarrenm if (mechanism->cm_type <= SHA256_HMAC_GEN_MECH_INFO_TYPE) 836734b6a94Sdarrenm sha_digest_len = SHA256_DIGEST_LENGTH; 837734b6a94Sdarrenm else 838734b6a94Sdarrenm sha_digest_len = SHA512_DIGEST_LENGTH; 839734b6a94Sdarrenm 840734b6a94Sdarrenm /* 841734b6a94Sdarrenm * Do a SHA2 final, must be done separately since the digest 842734b6a94Sdarrenm * type can be different than the input data type. 843734b6a94Sdarrenm */ 844734b6a94Sdarrenm switch (digest->cd_format) { 845734b6a94Sdarrenm case CRYPTO_DATA_RAW: 846734b6a94Sdarrenm SHA2Final((unsigned char *)digest->cd_raw.iov_base + 847734b6a94Sdarrenm digest->cd_offset, &sha2_ctx); 848734b6a94Sdarrenm break; 849734b6a94Sdarrenm case CRYPTO_DATA_UIO: 850734b6a94Sdarrenm ret = sha2_digest_final_uio(&sha2_ctx, digest, 851734b6a94Sdarrenm sha_digest_len, NULL); 852734b6a94Sdarrenm break; 853734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 854734b6a94Sdarrenm ret = sha2_digest_final_mblk(&sha2_ctx, digest, 855734b6a94Sdarrenm sha_digest_len, NULL); 856734b6a94Sdarrenm break; 857734b6a94Sdarrenm default: 858734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 859734b6a94Sdarrenm } 860734b6a94Sdarrenm 861734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) 862734b6a94Sdarrenm digest->cd_length = sha_digest_len; 863734b6a94Sdarrenm else 864734b6a94Sdarrenm digest->cd_length = 0; 865734b6a94Sdarrenm 866734b6a94Sdarrenm return (ret); 867734b6a94Sdarrenm } 868734b6a94Sdarrenm 869734b6a94Sdarrenm /* 870734b6a94Sdarrenm * KCF software provider mac entry points. 871734b6a94Sdarrenm * 872734b6a94Sdarrenm * SHA2 HMAC is: SHA2(key XOR opad, SHA2(key XOR ipad, text)) 873734b6a94Sdarrenm * 874734b6a94Sdarrenm * Init: 875734b6a94Sdarrenm * The initialization routine initializes what we denote 876734b6a94Sdarrenm * as the inner and outer contexts by doing 877734b6a94Sdarrenm * - for inner context: SHA2(key XOR ipad) 878734b6a94Sdarrenm * - for outer context: SHA2(key XOR opad) 879734b6a94Sdarrenm * 880734b6a94Sdarrenm * Update: 881734b6a94Sdarrenm * Each subsequent SHA2 HMAC update will result in an 882734b6a94Sdarrenm * update of the inner context with the specified data. 883734b6a94Sdarrenm * 884734b6a94Sdarrenm * Final: 885734b6a94Sdarrenm * The SHA2 HMAC final will do a SHA2 final operation on the 886734b6a94Sdarrenm * inner context, and the resulting digest will be used 887734b6a94Sdarrenm * as the data for an update on the outer context. Last 888734b6a94Sdarrenm * but not least, a SHA2 final on the outer context will 889734b6a94Sdarrenm * be performed to obtain the SHA2 HMAC digest to return 890734b6a94Sdarrenm * to the user. 891734b6a94Sdarrenm */ 892734b6a94Sdarrenm 893734b6a94Sdarrenm /* 894734b6a94Sdarrenm * Initialize a SHA2-HMAC context. 895734b6a94Sdarrenm */ 896734b6a94Sdarrenm static void 897734b6a94Sdarrenm sha2_mac_init_ctx(sha2_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes) 898734b6a94Sdarrenm { 899734b6a94Sdarrenm uint64_t ipad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)]; 900734b6a94Sdarrenm uint64_t opad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)]; 901734b6a94Sdarrenm int i, block_size, blocks_per_int64; 902734b6a94Sdarrenm 903734b6a94Sdarrenm /* Determine the block size */ 904734b6a94Sdarrenm if (ctx->hc_mech_type <= SHA256_HMAC_GEN_MECH_INFO_TYPE) { 905734b6a94Sdarrenm block_size = SHA256_HMAC_BLOCK_SIZE; 906734b6a94Sdarrenm blocks_per_int64 = SHA256_HMAC_BLOCK_SIZE / sizeof (uint64_t); 907734b6a94Sdarrenm } else { 908734b6a94Sdarrenm block_size = SHA512_HMAC_BLOCK_SIZE; 909734b6a94Sdarrenm blocks_per_int64 = SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t); 910734b6a94Sdarrenm } 911734b6a94Sdarrenm 912734b6a94Sdarrenm (void) bzero(ipad, block_size); 913734b6a94Sdarrenm (void) bzero(opad, block_size); 914734b6a94Sdarrenm (void) bcopy(keyval, ipad, length_in_bytes); 915734b6a94Sdarrenm (void) bcopy(keyval, opad, length_in_bytes); 916734b6a94Sdarrenm 917734b6a94Sdarrenm /* XOR key with ipad (0x36) and opad (0x5c) */ 918734b6a94Sdarrenm for (i = 0; i < blocks_per_int64; i ++) { 919734b6a94Sdarrenm ipad[i] ^= 0x3636363636363636; 920734b6a94Sdarrenm opad[i] ^= 0x5c5c5c5c5c5c5c5c; 921734b6a94Sdarrenm } 922734b6a94Sdarrenm 923734b6a94Sdarrenm /* perform SHA2 on ipad */ 924734b6a94Sdarrenm SHA2Init(ctx->hc_mech_type, &ctx->hc_icontext); 925734b6a94Sdarrenm SHA2Update(&ctx->hc_icontext, (uint8_t *)ipad, block_size); 926734b6a94Sdarrenm 927734b6a94Sdarrenm /* perform SHA2 on opad */ 928734b6a94Sdarrenm SHA2Init(ctx->hc_mech_type, &ctx->hc_ocontext); 929734b6a94Sdarrenm SHA2Update(&ctx->hc_ocontext, (uint8_t *)opad, block_size); 930734b6a94Sdarrenm 931734b6a94Sdarrenm } 932734b6a94Sdarrenm 933734b6a94Sdarrenm /* 934734b6a94Sdarrenm */ 935734b6a94Sdarrenm static int 936734b6a94Sdarrenm sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 937734b6a94Sdarrenm crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 938734b6a94Sdarrenm crypto_req_handle_t req) 939734b6a94Sdarrenm { 940734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 941734b6a94Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 942734b6a94Sdarrenm uint_t sha_digest_len, sha_hmac_block_size; 943734b6a94Sdarrenm 944734b6a94Sdarrenm /* 945734b6a94Sdarrenm * Set the digest length and block size to values approriate to the 946734b6a94Sdarrenm * mechanism 947734b6a94Sdarrenm */ 948734b6a94Sdarrenm switch (mechanism->cm_type) { 949734b6a94Sdarrenm case SHA256_HMAC_MECH_INFO_TYPE: 950734b6a94Sdarrenm case SHA256_HMAC_GEN_MECH_INFO_TYPE: 951734b6a94Sdarrenm sha_digest_len = SHA256_DIGEST_LENGTH; 952734b6a94Sdarrenm sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE; 953734b6a94Sdarrenm break; 954734b6a94Sdarrenm case SHA384_HMAC_MECH_INFO_TYPE: 955734b6a94Sdarrenm case SHA384_HMAC_GEN_MECH_INFO_TYPE: 956734b6a94Sdarrenm case SHA512_HMAC_MECH_INFO_TYPE: 957734b6a94Sdarrenm case SHA512_HMAC_GEN_MECH_INFO_TYPE: 958734b6a94Sdarrenm sha_digest_len = SHA512_DIGEST_LENGTH; 959734b6a94Sdarrenm sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE; 960734b6a94Sdarrenm break; 961734b6a94Sdarrenm default: 962734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 963734b6a94Sdarrenm } 964734b6a94Sdarrenm 965734b6a94Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 966734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 967734b6a94Sdarrenm 968734b6a94Sdarrenm ctx->cc_provider_private = kmem_alloc(sizeof (sha2_hmac_ctx_t), 969734b6a94Sdarrenm crypto_kmflag(req)); 970734b6a94Sdarrenm if (ctx->cc_provider_private == NULL) 971734b6a94Sdarrenm return (CRYPTO_HOST_MEMORY); 972734b6a94Sdarrenm 973ba5f469cSkrishna PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type; 974734b6a94Sdarrenm if (ctx_template != NULL) { 975734b6a94Sdarrenm /* reuse context template */ 976734b6a94Sdarrenm bcopy(ctx_template, PROV_SHA2_HMAC_CTX(ctx), 977734b6a94Sdarrenm sizeof (sha2_hmac_ctx_t)); 978734b6a94Sdarrenm } else { 979734b6a94Sdarrenm /* no context template, compute context */ 980734b6a94Sdarrenm if (keylen_in_bytes > sha_hmac_block_size) { 981734b6a94Sdarrenm uchar_t digested_key[SHA512_DIGEST_LENGTH]; 982734b6a94Sdarrenm sha2_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private; 983734b6a94Sdarrenm 984734b6a94Sdarrenm /* 985734b6a94Sdarrenm * Hash the passed-in key to get a smaller key. 986734b6a94Sdarrenm * The inner context is used since it hasn't been 987734b6a94Sdarrenm * initialized yet. 988734b6a94Sdarrenm */ 989734b6a94Sdarrenm PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3, 990734b6a94Sdarrenm &hmac_ctx->hc_icontext, 991734b6a94Sdarrenm key->ck_data, keylen_in_bytes, digested_key); 992734b6a94Sdarrenm sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx), 993734b6a94Sdarrenm digested_key, sha_digest_len); 994734b6a94Sdarrenm } else { 995734b6a94Sdarrenm sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx), 996734b6a94Sdarrenm key->ck_data, keylen_in_bytes); 997734b6a94Sdarrenm } 998734b6a94Sdarrenm } 999734b6a94Sdarrenm 1000734b6a94Sdarrenm /* 1001734b6a94Sdarrenm * Get the mechanism parameters, if applicable. 1002734b6a94Sdarrenm */ 1003734b6a94Sdarrenm if (mechanism->cm_type % 3 == 2) { 1004734b6a94Sdarrenm if (mechanism->cm_param == NULL || 1005734b6a94Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) 1006734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1007734b6a94Sdarrenm PROV_SHA2_GET_DIGEST_LEN(mechanism, 1008734b6a94Sdarrenm PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len); 1009734b6a94Sdarrenm if (PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len > sha_digest_len) 1010734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1011734b6a94Sdarrenm } 1012734b6a94Sdarrenm 1013734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) { 1014734b6a94Sdarrenm bzero(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t)); 1015734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t)); 1016734b6a94Sdarrenm ctx->cc_provider_private = NULL; 1017734b6a94Sdarrenm } 1018734b6a94Sdarrenm 1019734b6a94Sdarrenm return (ret); 1020734b6a94Sdarrenm } 1021734b6a94Sdarrenm 1022734b6a94Sdarrenm /* ARGSUSED */ 1023734b6a94Sdarrenm static int 1024734b6a94Sdarrenm sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, 1025734b6a94Sdarrenm crypto_req_handle_t req) 1026734b6a94Sdarrenm { 1027734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 1028734b6a94Sdarrenm 1029734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 1030734b6a94Sdarrenm 1031734b6a94Sdarrenm /* 1032734b6a94Sdarrenm * Do a SHA2 update of the inner context using the specified 1033734b6a94Sdarrenm * data. 1034734b6a94Sdarrenm */ 1035734b6a94Sdarrenm switch (data->cd_format) { 1036734b6a94Sdarrenm case CRYPTO_DATA_RAW: 1037734b6a94Sdarrenm SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, 1038734b6a94Sdarrenm (uint8_t *)data->cd_raw.iov_base + data->cd_offset, 1039734b6a94Sdarrenm data->cd_length); 1040734b6a94Sdarrenm break; 1041734b6a94Sdarrenm case CRYPTO_DATA_UIO: 1042734b6a94Sdarrenm ret = sha2_digest_update_uio( 1043734b6a94Sdarrenm &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, data); 1044734b6a94Sdarrenm break; 1045734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 1046734b6a94Sdarrenm ret = sha2_digest_update_mblk( 1047734b6a94Sdarrenm &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, data); 1048734b6a94Sdarrenm break; 1049734b6a94Sdarrenm default: 1050734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 1051734b6a94Sdarrenm } 1052734b6a94Sdarrenm 1053734b6a94Sdarrenm return (ret); 1054734b6a94Sdarrenm } 1055734b6a94Sdarrenm 1056734b6a94Sdarrenm /* ARGSUSED */ 1057734b6a94Sdarrenm static int 1058734b6a94Sdarrenm sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req) 1059734b6a94Sdarrenm { 1060734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 1061734b6a94Sdarrenm uchar_t digest[SHA512_DIGEST_LENGTH]; 1062734b6a94Sdarrenm uint32_t digest_len, sha_digest_len; 1063734b6a94Sdarrenm 1064734b6a94Sdarrenm ASSERT(ctx->cc_provider_private != NULL); 1065734b6a94Sdarrenm 1066734b6a94Sdarrenm /* Set the digest lengths to values approriate to the mechanism */ 1067734b6a94Sdarrenm switch (PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type) { 1068734b6a94Sdarrenm case SHA256_HMAC_MECH_INFO_TYPE: 1069734b6a94Sdarrenm sha_digest_len = digest_len = SHA256_DIGEST_LENGTH; 1070734b6a94Sdarrenm break; 1071734b6a94Sdarrenm case SHA384_HMAC_MECH_INFO_TYPE: 1072ba5f469cSkrishna sha_digest_len = digest_len = SHA384_DIGEST_LENGTH; 1073ba5f469cSkrishna break; 1074734b6a94Sdarrenm case SHA512_HMAC_MECH_INFO_TYPE: 1075734b6a94Sdarrenm sha_digest_len = digest_len = SHA512_DIGEST_LENGTH; 1076734b6a94Sdarrenm break; 1077734b6a94Sdarrenm case SHA256_HMAC_GEN_MECH_INFO_TYPE: 1078734b6a94Sdarrenm sha_digest_len = SHA256_DIGEST_LENGTH; 1079734b6a94Sdarrenm digest_len = PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len; 1080734b6a94Sdarrenm break; 1081734b6a94Sdarrenm case SHA384_HMAC_GEN_MECH_INFO_TYPE: 1082734b6a94Sdarrenm case SHA512_HMAC_GEN_MECH_INFO_TYPE: 1083734b6a94Sdarrenm sha_digest_len = SHA512_DIGEST_LENGTH; 1084734b6a94Sdarrenm digest_len = PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len; 1085734b6a94Sdarrenm break; 1086734b6a94Sdarrenm } 1087734b6a94Sdarrenm 1088734b6a94Sdarrenm /* 1089734b6a94Sdarrenm * We need to just return the length needed to store the output. 1090734b6a94Sdarrenm * We should not destroy the context for the following cases. 1091734b6a94Sdarrenm */ 1092734b6a94Sdarrenm if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) { 1093734b6a94Sdarrenm mac->cd_length = digest_len; 1094734b6a94Sdarrenm return (CRYPTO_BUFFER_TOO_SMALL); 1095734b6a94Sdarrenm } 1096734b6a94Sdarrenm 1097734b6a94Sdarrenm /* 1098734b6a94Sdarrenm * Do a SHA2 final on the inner context. 1099734b6a94Sdarrenm */ 1100734b6a94Sdarrenm SHA2Final(digest, &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext); 1101734b6a94Sdarrenm 1102734b6a94Sdarrenm /* 1103734b6a94Sdarrenm * Do a SHA2 update on the outer context, feeding the inner 1104734b6a94Sdarrenm * digest as data. 1105734b6a94Sdarrenm */ 1106734b6a94Sdarrenm SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, digest, 1107734b6a94Sdarrenm sha_digest_len); 1108734b6a94Sdarrenm 1109734b6a94Sdarrenm /* 1110734b6a94Sdarrenm * Do a SHA2 final on the outer context, storing the computing 1111734b6a94Sdarrenm * digest in the users buffer. 1112734b6a94Sdarrenm */ 1113734b6a94Sdarrenm switch (mac->cd_format) { 1114734b6a94Sdarrenm case CRYPTO_DATA_RAW: 1115734b6a94Sdarrenm if (digest_len != sha_digest_len) { 1116734b6a94Sdarrenm /* 1117734b6a94Sdarrenm * The caller requested a short digest. Digest 1118734b6a94Sdarrenm * into a scratch buffer and return to 1119734b6a94Sdarrenm * the user only what was requested. 1120734b6a94Sdarrenm */ 1121734b6a94Sdarrenm SHA2Final(digest, 1122734b6a94Sdarrenm &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext); 1123734b6a94Sdarrenm bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1124734b6a94Sdarrenm mac->cd_offset, digest_len); 1125734b6a94Sdarrenm } else { 1126734b6a94Sdarrenm SHA2Final((unsigned char *)mac->cd_raw.iov_base + 1127734b6a94Sdarrenm mac->cd_offset, 1128734b6a94Sdarrenm &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext); 1129734b6a94Sdarrenm } 1130734b6a94Sdarrenm break; 1131734b6a94Sdarrenm case CRYPTO_DATA_UIO: 1132734b6a94Sdarrenm ret = sha2_digest_final_uio( 1133734b6a94Sdarrenm &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, mac, 1134734b6a94Sdarrenm digest_len, digest); 1135734b6a94Sdarrenm break; 1136734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 1137734b6a94Sdarrenm ret = sha2_digest_final_mblk( 1138734b6a94Sdarrenm &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, mac, 1139734b6a94Sdarrenm digest_len, digest); 1140734b6a94Sdarrenm break; 1141734b6a94Sdarrenm default: 1142734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 1143734b6a94Sdarrenm } 1144734b6a94Sdarrenm 1145734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) 1146734b6a94Sdarrenm mac->cd_length = digest_len; 1147734b6a94Sdarrenm else 1148734b6a94Sdarrenm mac->cd_length = 0; 1149734b6a94Sdarrenm 1150ba5f469cSkrishna bzero(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t)); 1151734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t)); 1152734b6a94Sdarrenm ctx->cc_provider_private = NULL; 1153734b6a94Sdarrenm 1154734b6a94Sdarrenm return (ret); 1155734b6a94Sdarrenm } 1156734b6a94Sdarrenm 1157734b6a94Sdarrenm #define SHA2_MAC_UPDATE(data, ctx, ret) { \ 1158734b6a94Sdarrenm switch (data->cd_format) { \ 1159734b6a94Sdarrenm case CRYPTO_DATA_RAW: \ 1160734b6a94Sdarrenm SHA2Update(&(ctx).hc_icontext, \ 1161734b6a94Sdarrenm (uint8_t *)data->cd_raw.iov_base + \ 1162734b6a94Sdarrenm data->cd_offset, data->cd_length); \ 1163734b6a94Sdarrenm break; \ 1164734b6a94Sdarrenm case CRYPTO_DATA_UIO: \ 1165734b6a94Sdarrenm ret = sha2_digest_update_uio(&(ctx).hc_icontext, data); \ 1166734b6a94Sdarrenm break; \ 1167734b6a94Sdarrenm case CRYPTO_DATA_MBLK: \ 1168734b6a94Sdarrenm ret = sha2_digest_update_mblk(&(ctx).hc_icontext, \ 1169734b6a94Sdarrenm data); \ 1170734b6a94Sdarrenm break; \ 1171734b6a94Sdarrenm default: \ 1172734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; \ 1173734b6a94Sdarrenm } \ 1174734b6a94Sdarrenm } 1175734b6a94Sdarrenm 1176734b6a94Sdarrenm /* ARGSUSED */ 1177734b6a94Sdarrenm static int 1178734b6a94Sdarrenm sha2_mac_atomic(crypto_provider_handle_t provider, 1179734b6a94Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1180734b6a94Sdarrenm crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1181734b6a94Sdarrenm crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1182734b6a94Sdarrenm { 1183734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 1184734b6a94Sdarrenm uchar_t digest[SHA512_DIGEST_LENGTH]; 1185734b6a94Sdarrenm sha2_hmac_ctx_t sha2_hmac_ctx; 1186734b6a94Sdarrenm uint32_t sha_digest_len, digest_len, sha_hmac_block_size; 1187734b6a94Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1188734b6a94Sdarrenm 1189734b6a94Sdarrenm /* 1190734b6a94Sdarrenm * Set the digest length and block size to values approriate to the 1191734b6a94Sdarrenm * mechanism 1192734b6a94Sdarrenm */ 1193734b6a94Sdarrenm switch (mechanism->cm_type) { 1194734b6a94Sdarrenm case SHA256_HMAC_MECH_INFO_TYPE: 1195734b6a94Sdarrenm case SHA256_HMAC_GEN_MECH_INFO_TYPE: 1196734b6a94Sdarrenm sha_digest_len = digest_len = SHA256_DIGEST_LENGTH; 1197734b6a94Sdarrenm sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE; 1198734b6a94Sdarrenm break; 1199734b6a94Sdarrenm case SHA384_HMAC_MECH_INFO_TYPE: 1200734b6a94Sdarrenm case SHA384_HMAC_GEN_MECH_INFO_TYPE: 1201734b6a94Sdarrenm case SHA512_HMAC_MECH_INFO_TYPE: 1202734b6a94Sdarrenm case SHA512_HMAC_GEN_MECH_INFO_TYPE: 1203734b6a94Sdarrenm sha_digest_len = digest_len = SHA512_DIGEST_LENGTH; 1204734b6a94Sdarrenm sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE; 1205734b6a94Sdarrenm break; 1206734b6a94Sdarrenm default: 1207734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 1208734b6a94Sdarrenm } 1209734b6a94Sdarrenm 1210734b6a94Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 1211734b6a94Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 1212734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 1213734b6a94Sdarrenm 1214734b6a94Sdarrenm if (ctx_template != NULL) { 1215734b6a94Sdarrenm /* reuse context template */ 1216734b6a94Sdarrenm bcopy(ctx_template, &sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t)); 1217734b6a94Sdarrenm } else { 1218734b6a94Sdarrenm sha2_hmac_ctx.hc_mech_type = mechanism->cm_type; 1219734b6a94Sdarrenm /* no context template, initialize context */ 1220734b6a94Sdarrenm if (keylen_in_bytes > sha_hmac_block_size) { 1221734b6a94Sdarrenm /* 1222734b6a94Sdarrenm * Hash the passed-in key to get a smaller key. 1223734b6a94Sdarrenm * The inner context is used since it hasn't been 1224734b6a94Sdarrenm * initialized yet. 1225734b6a94Sdarrenm */ 1226734b6a94Sdarrenm PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3, 1227734b6a94Sdarrenm &sha2_hmac_ctx.hc_icontext, 1228734b6a94Sdarrenm key->ck_data, keylen_in_bytes, digest); 1229734b6a94Sdarrenm sha2_mac_init_ctx(&sha2_hmac_ctx, digest, 1230734b6a94Sdarrenm sha_digest_len); 1231734b6a94Sdarrenm } else { 1232734b6a94Sdarrenm sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data, 1233734b6a94Sdarrenm keylen_in_bytes); 1234734b6a94Sdarrenm } 1235734b6a94Sdarrenm } 1236734b6a94Sdarrenm 1237734b6a94Sdarrenm /* get the mechanism parameters, if applicable */ 1238734b6a94Sdarrenm if ((mechanism->cm_type % 3) == 2) { 1239734b6a94Sdarrenm if (mechanism->cm_param == NULL || 1240734b6a94Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) { 1241734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1242734b6a94Sdarrenm goto bail; 1243734b6a94Sdarrenm } 1244734b6a94Sdarrenm PROV_SHA2_GET_DIGEST_LEN(mechanism, digest_len); 1245734b6a94Sdarrenm if (digest_len > sha_digest_len) { 1246734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1247734b6a94Sdarrenm goto bail; 1248734b6a94Sdarrenm } 1249734b6a94Sdarrenm } 1250734b6a94Sdarrenm 1251734b6a94Sdarrenm /* do a SHA2 update of the inner context using the specified data */ 1252734b6a94Sdarrenm SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret); 1253734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) 1254734b6a94Sdarrenm /* the update failed, free context and bail */ 1255734b6a94Sdarrenm goto bail; 1256734b6a94Sdarrenm 1257734b6a94Sdarrenm /* 1258734b6a94Sdarrenm * Do a SHA2 final on the inner context. 1259734b6a94Sdarrenm */ 1260734b6a94Sdarrenm SHA2Final(digest, &sha2_hmac_ctx.hc_icontext); 1261734b6a94Sdarrenm 1262734b6a94Sdarrenm /* 1263734b6a94Sdarrenm * Do an SHA2 update on the outer context, feeding the inner 1264734b6a94Sdarrenm * digest as data. 1265734b6a94Sdarrenm * 12660358d3a6Sdanmcd * HMAC-SHA384 needs special handling as the outer hash needs only 48 12670358d3a6Sdanmcd * bytes of the inner hash value. 1268734b6a94Sdarrenm */ 1269734b6a94Sdarrenm if (mechanism->cm_type == SHA384_HMAC_MECH_INFO_TYPE || 1270734b6a94Sdarrenm mechanism->cm_type == SHA384_HMAC_GEN_MECH_INFO_TYPE) 1271734b6a94Sdarrenm SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, 1272734b6a94Sdarrenm SHA384_DIGEST_LENGTH); 1273734b6a94Sdarrenm else 1274734b6a94Sdarrenm SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len); 1275734b6a94Sdarrenm 1276734b6a94Sdarrenm /* 1277734b6a94Sdarrenm * Do a SHA2 final on the outer context, storing the computed 1278734b6a94Sdarrenm * digest in the users buffer. 1279734b6a94Sdarrenm */ 1280734b6a94Sdarrenm switch (mac->cd_format) { 1281734b6a94Sdarrenm case CRYPTO_DATA_RAW: 1282734b6a94Sdarrenm if (digest_len != sha_digest_len) { 1283734b6a94Sdarrenm /* 1284734b6a94Sdarrenm * The caller requested a short digest. Digest 1285734b6a94Sdarrenm * into a scratch buffer and return to 1286734b6a94Sdarrenm * the user only what was requested. 1287734b6a94Sdarrenm */ 1288734b6a94Sdarrenm SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext); 1289734b6a94Sdarrenm bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1290734b6a94Sdarrenm mac->cd_offset, digest_len); 1291734b6a94Sdarrenm } else { 1292734b6a94Sdarrenm SHA2Final((unsigned char *)mac->cd_raw.iov_base + 1293734b6a94Sdarrenm mac->cd_offset, &sha2_hmac_ctx.hc_ocontext); 1294734b6a94Sdarrenm } 1295734b6a94Sdarrenm break; 1296734b6a94Sdarrenm case CRYPTO_DATA_UIO: 1297734b6a94Sdarrenm ret = sha2_digest_final_uio(&sha2_hmac_ctx.hc_ocontext, mac, 1298734b6a94Sdarrenm digest_len, digest); 1299734b6a94Sdarrenm break; 1300734b6a94Sdarrenm case CRYPTO_DATA_MBLK: 1301734b6a94Sdarrenm ret = sha2_digest_final_mblk(&sha2_hmac_ctx.hc_ocontext, mac, 1302734b6a94Sdarrenm digest_len, digest); 1303734b6a94Sdarrenm break; 1304734b6a94Sdarrenm default: 1305734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 1306734b6a94Sdarrenm } 1307734b6a94Sdarrenm 1308734b6a94Sdarrenm if (ret == CRYPTO_SUCCESS) { 1309734b6a94Sdarrenm mac->cd_length = digest_len; 1310734b6a94Sdarrenm return (CRYPTO_SUCCESS); 1311734b6a94Sdarrenm } 1312734b6a94Sdarrenm bail: 1313734b6a94Sdarrenm bzero(&sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t)); 1314734b6a94Sdarrenm mac->cd_length = 0; 1315734b6a94Sdarrenm return (ret); 1316734b6a94Sdarrenm } 1317734b6a94Sdarrenm 1318734b6a94Sdarrenm /* ARGSUSED */ 1319734b6a94Sdarrenm static int 1320734b6a94Sdarrenm sha2_mac_verify_atomic(crypto_provider_handle_t provider, 1321734b6a94Sdarrenm crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1322734b6a94Sdarrenm crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1323734b6a94Sdarrenm crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1324734b6a94Sdarrenm { 1325734b6a94Sdarrenm int ret = CRYPTO_SUCCESS; 1326734b6a94Sdarrenm uchar_t digest[SHA512_DIGEST_LENGTH]; 1327734b6a94Sdarrenm sha2_hmac_ctx_t sha2_hmac_ctx; 1328734b6a94Sdarrenm uint32_t sha_digest_len, digest_len, sha_hmac_block_size; 1329734b6a94Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1330734b6a94Sdarrenm 1331734b6a94Sdarrenm /* 1332734b6a94Sdarrenm * Set the digest length and block size to values approriate to the 1333734b6a94Sdarrenm * mechanism 1334734b6a94Sdarrenm */ 1335734b6a94Sdarrenm switch (mechanism->cm_type) { 1336734b6a94Sdarrenm case SHA256_HMAC_MECH_INFO_TYPE: 1337734b6a94Sdarrenm case SHA256_HMAC_GEN_MECH_INFO_TYPE: 1338734b6a94Sdarrenm sha_digest_len = digest_len = SHA256_DIGEST_LENGTH; 1339734b6a94Sdarrenm sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE; 1340734b6a94Sdarrenm break; 1341734b6a94Sdarrenm case SHA384_HMAC_MECH_INFO_TYPE: 1342734b6a94Sdarrenm case SHA384_HMAC_GEN_MECH_INFO_TYPE: 1343734b6a94Sdarrenm case SHA512_HMAC_MECH_INFO_TYPE: 1344734b6a94Sdarrenm case SHA512_HMAC_GEN_MECH_INFO_TYPE: 1345734b6a94Sdarrenm sha_digest_len = digest_len = SHA512_DIGEST_LENGTH; 1346734b6a94Sdarrenm sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE; 1347734b6a94Sdarrenm break; 1348734b6a94Sdarrenm default: 1349734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 1350734b6a94Sdarrenm } 1351734b6a94Sdarrenm 1352734b6a94Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 1353734b6a94Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 1354734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 1355734b6a94Sdarrenm 1356734b6a94Sdarrenm if (ctx_template != NULL) { 1357734b6a94Sdarrenm /* reuse context template */ 1358734b6a94Sdarrenm bcopy(ctx_template, &sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t)); 1359734b6a94Sdarrenm } else { 1360734b6a94Sdarrenm /* no context template, initialize context */ 1361734b6a94Sdarrenm if (keylen_in_bytes > sha_hmac_block_size) { 1362734b6a94Sdarrenm /* 1363734b6a94Sdarrenm * Hash the passed-in key to get a smaller key. 1364734b6a94Sdarrenm * The inner context is used since it hasn't been 1365734b6a94Sdarrenm * initialized yet. 1366734b6a94Sdarrenm */ 1367734b6a94Sdarrenm PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3, 1368734b6a94Sdarrenm &sha2_hmac_ctx.hc_icontext, 1369734b6a94Sdarrenm key->ck_data, keylen_in_bytes, digest); 1370734b6a94Sdarrenm sha2_mac_init_ctx(&sha2_hmac_ctx, digest, 1371734b6a94Sdarrenm sha_digest_len); 1372734b6a94Sdarrenm } else { 1373734b6a94Sdarrenm sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data, 1374734b6a94Sdarrenm keylen_in_bytes); 1375734b6a94Sdarrenm } 1376734b6a94Sdarrenm } 1377734b6a94Sdarrenm 1378734b6a94Sdarrenm /* get the mechanism parameters, if applicable */ 1379734b6a94Sdarrenm if (mechanism->cm_type % 3 == 2) { 1380734b6a94Sdarrenm if (mechanism->cm_param == NULL || 1381734b6a94Sdarrenm mechanism->cm_param_len != sizeof (ulong_t)) { 1382734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1383734b6a94Sdarrenm goto bail; 1384734b6a94Sdarrenm } 1385734b6a94Sdarrenm PROV_SHA2_GET_DIGEST_LEN(mechanism, digest_len); 1386734b6a94Sdarrenm if (digest_len > sha_digest_len) { 1387734b6a94Sdarrenm ret = CRYPTO_MECHANISM_PARAM_INVALID; 1388734b6a94Sdarrenm goto bail; 1389734b6a94Sdarrenm } 1390734b6a94Sdarrenm } 1391734b6a94Sdarrenm 1392734b6a94Sdarrenm if (mac->cd_length != digest_len) { 1393734b6a94Sdarrenm ret = CRYPTO_INVALID_MAC; 1394734b6a94Sdarrenm goto bail; 1395734b6a94Sdarrenm } 1396734b6a94Sdarrenm 1397734b6a94Sdarrenm /* do a SHA2 update of the inner context using the specified data */ 1398734b6a94Sdarrenm SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret); 1399734b6a94Sdarrenm if (ret != CRYPTO_SUCCESS) 1400734b6a94Sdarrenm /* the update failed, free context and bail */ 1401734b6a94Sdarrenm goto bail; 1402734b6a94Sdarrenm 1403734b6a94Sdarrenm /* do a SHA2 final on the inner context */ 1404734b6a94Sdarrenm SHA2Final(digest, &sha2_hmac_ctx.hc_icontext); 1405734b6a94Sdarrenm 1406734b6a94Sdarrenm /* 1407734b6a94Sdarrenm * Do an SHA2 update on the outer context, feeding the inner 1408734b6a94Sdarrenm * digest as data. 14090358d3a6Sdanmcd * 14100358d3a6Sdanmcd * HMAC-SHA384 needs special handling as the outer hash needs only 48 14110358d3a6Sdanmcd * bytes of the inner hash value. 1412734b6a94Sdarrenm */ 14130358d3a6Sdanmcd if (mechanism->cm_type == SHA384_HMAC_MECH_INFO_TYPE || 14140358d3a6Sdanmcd mechanism->cm_type == SHA384_HMAC_GEN_MECH_INFO_TYPE) 14150358d3a6Sdanmcd SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, 14160358d3a6Sdanmcd SHA384_DIGEST_LENGTH); 14170358d3a6Sdanmcd else 1418734b6a94Sdarrenm SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len); 1419734b6a94Sdarrenm 1420734b6a94Sdarrenm /* 1421734b6a94Sdarrenm * Do a SHA2 final on the outer context, storing the computed 1422734b6a94Sdarrenm * digest in the users buffer. 1423734b6a94Sdarrenm */ 1424734b6a94Sdarrenm SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext); 1425734b6a94Sdarrenm 1426734b6a94Sdarrenm /* 1427734b6a94Sdarrenm * Compare the computed digest against the expected digest passed 1428734b6a94Sdarrenm * as argument. 1429734b6a94Sdarrenm */ 1430734b6a94Sdarrenm 1431734b6a94Sdarrenm switch (mac->cd_format) { 1432734b6a94Sdarrenm 1433734b6a94Sdarrenm case CRYPTO_DATA_RAW: 1434734b6a94Sdarrenm if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base + 1435734b6a94Sdarrenm mac->cd_offset, digest_len) != 0) 1436734b6a94Sdarrenm ret = CRYPTO_INVALID_MAC; 1437734b6a94Sdarrenm break; 1438734b6a94Sdarrenm 1439734b6a94Sdarrenm case CRYPTO_DATA_UIO: { 1440734b6a94Sdarrenm off_t offset = mac->cd_offset; 1441734b6a94Sdarrenm uint_t vec_idx; 1442734b6a94Sdarrenm off_t scratch_offset = 0; 1443734b6a94Sdarrenm size_t length = digest_len; 1444734b6a94Sdarrenm size_t cur_len; 1445734b6a94Sdarrenm 1446734b6a94Sdarrenm /* we support only kernel buffer */ 1447734b6a94Sdarrenm if (mac->cd_uio->uio_segflg != UIO_SYSSPACE) 1448734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 1449734b6a94Sdarrenm 1450734b6a94Sdarrenm /* jump to the first iovec containing the expected digest */ 1451734b6a94Sdarrenm for (vec_idx = 0; 1452734b6a94Sdarrenm offset >= mac->cd_uio->uio_iov[vec_idx].iov_len && 1453734b6a94Sdarrenm vec_idx < mac->cd_uio->uio_iovcnt; 1454d2b32306Smcpowers offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len) 1455d2b32306Smcpowers ; 1456734b6a94Sdarrenm if (vec_idx == mac->cd_uio->uio_iovcnt) { 1457734b6a94Sdarrenm /* 1458734b6a94Sdarrenm * The caller specified an offset that is 1459734b6a94Sdarrenm * larger than the total size of the buffers 1460734b6a94Sdarrenm * it provided. 1461734b6a94Sdarrenm */ 1462734b6a94Sdarrenm ret = CRYPTO_DATA_LEN_RANGE; 1463734b6a94Sdarrenm break; 1464734b6a94Sdarrenm } 1465734b6a94Sdarrenm 1466734b6a94Sdarrenm /* do the comparison of computed digest vs specified one */ 1467734b6a94Sdarrenm while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) { 1468734b6a94Sdarrenm cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len - 1469734b6a94Sdarrenm offset, length); 1470734b6a94Sdarrenm 1471734b6a94Sdarrenm if (bcmp(digest + scratch_offset, 1472734b6a94Sdarrenm mac->cd_uio->uio_iov[vec_idx].iov_base + offset, 1473734b6a94Sdarrenm cur_len) != 0) { 1474734b6a94Sdarrenm ret = CRYPTO_INVALID_MAC; 1475734b6a94Sdarrenm break; 1476734b6a94Sdarrenm } 1477734b6a94Sdarrenm 1478734b6a94Sdarrenm length -= cur_len; 1479734b6a94Sdarrenm vec_idx++; 1480734b6a94Sdarrenm scratch_offset += cur_len; 1481734b6a94Sdarrenm offset = 0; 1482734b6a94Sdarrenm } 1483734b6a94Sdarrenm break; 1484734b6a94Sdarrenm } 1485734b6a94Sdarrenm 1486734b6a94Sdarrenm case CRYPTO_DATA_MBLK: { 1487734b6a94Sdarrenm off_t offset = mac->cd_offset; 1488734b6a94Sdarrenm mblk_t *mp; 1489734b6a94Sdarrenm off_t scratch_offset = 0; 1490734b6a94Sdarrenm size_t length = digest_len; 1491734b6a94Sdarrenm size_t cur_len; 1492734b6a94Sdarrenm 1493734b6a94Sdarrenm /* jump to the first mblk_t containing the expected digest */ 1494734b6a94Sdarrenm for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp); 1495d2b32306Smcpowers offset -= MBLKL(mp), mp = mp->b_cont) 1496d2b32306Smcpowers ; 1497734b6a94Sdarrenm if (mp == NULL) { 1498734b6a94Sdarrenm /* 1499734b6a94Sdarrenm * The caller specified an offset that is larger than 1500734b6a94Sdarrenm * the total size of the buffers it provided. 1501734b6a94Sdarrenm */ 1502734b6a94Sdarrenm ret = CRYPTO_DATA_LEN_RANGE; 1503734b6a94Sdarrenm break; 1504734b6a94Sdarrenm } 1505734b6a94Sdarrenm 1506734b6a94Sdarrenm while (mp != NULL && length > 0) { 1507734b6a94Sdarrenm cur_len = MIN(MBLKL(mp) - offset, length); 1508734b6a94Sdarrenm if (bcmp(digest + scratch_offset, 1509734b6a94Sdarrenm mp->b_rptr + offset, cur_len) != 0) { 1510734b6a94Sdarrenm ret = CRYPTO_INVALID_MAC; 1511734b6a94Sdarrenm break; 1512734b6a94Sdarrenm } 1513734b6a94Sdarrenm 1514734b6a94Sdarrenm length -= cur_len; 1515734b6a94Sdarrenm mp = mp->b_cont; 1516734b6a94Sdarrenm scratch_offset += cur_len; 1517734b6a94Sdarrenm offset = 0; 1518734b6a94Sdarrenm } 1519734b6a94Sdarrenm break; 1520734b6a94Sdarrenm } 1521734b6a94Sdarrenm 1522734b6a94Sdarrenm default: 1523734b6a94Sdarrenm ret = CRYPTO_ARGUMENTS_BAD; 1524734b6a94Sdarrenm } 1525734b6a94Sdarrenm 1526734b6a94Sdarrenm return (ret); 1527734b6a94Sdarrenm bail: 1528734b6a94Sdarrenm bzero(&sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t)); 1529734b6a94Sdarrenm mac->cd_length = 0; 1530734b6a94Sdarrenm return (ret); 1531734b6a94Sdarrenm } 1532734b6a94Sdarrenm 1533734b6a94Sdarrenm /* 1534734b6a94Sdarrenm * KCF software provider context management entry points. 1535734b6a94Sdarrenm */ 1536734b6a94Sdarrenm 1537734b6a94Sdarrenm /* ARGSUSED */ 1538734b6a94Sdarrenm static int 1539734b6a94Sdarrenm sha2_create_ctx_template(crypto_provider_handle_t provider, 1540734b6a94Sdarrenm crypto_mechanism_t *mechanism, crypto_key_t *key, 1541734b6a94Sdarrenm crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size, 1542734b6a94Sdarrenm crypto_req_handle_t req) 1543734b6a94Sdarrenm { 1544734b6a94Sdarrenm sha2_hmac_ctx_t *sha2_hmac_ctx_tmpl; 1545734b6a94Sdarrenm uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1546734b6a94Sdarrenm uint32_t sha_digest_len, sha_hmac_block_size; 1547734b6a94Sdarrenm 1548734b6a94Sdarrenm /* 1549734b6a94Sdarrenm * Set the digest length and block size to values approriate to the 1550734b6a94Sdarrenm * mechanism 1551734b6a94Sdarrenm */ 1552734b6a94Sdarrenm switch (mechanism->cm_type) { 1553734b6a94Sdarrenm case SHA256_HMAC_MECH_INFO_TYPE: 1554734b6a94Sdarrenm case SHA256_HMAC_GEN_MECH_INFO_TYPE: 1555734b6a94Sdarrenm sha_digest_len = SHA256_DIGEST_LENGTH; 1556734b6a94Sdarrenm sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE; 1557734b6a94Sdarrenm break; 1558734b6a94Sdarrenm case SHA384_HMAC_MECH_INFO_TYPE: 1559734b6a94Sdarrenm case SHA384_HMAC_GEN_MECH_INFO_TYPE: 1560734b6a94Sdarrenm case SHA512_HMAC_MECH_INFO_TYPE: 1561734b6a94Sdarrenm case SHA512_HMAC_GEN_MECH_INFO_TYPE: 1562734b6a94Sdarrenm sha_digest_len = SHA512_DIGEST_LENGTH; 1563734b6a94Sdarrenm sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE; 1564734b6a94Sdarrenm break; 1565734b6a94Sdarrenm default: 1566734b6a94Sdarrenm return (CRYPTO_MECHANISM_INVALID); 1567734b6a94Sdarrenm } 1568734b6a94Sdarrenm 1569734b6a94Sdarrenm /* Add support for key by attributes (RFE 4706552) */ 1570734b6a94Sdarrenm if (key->ck_format != CRYPTO_KEY_RAW) 1571734b6a94Sdarrenm return (CRYPTO_ARGUMENTS_BAD); 1572734b6a94Sdarrenm 1573734b6a94Sdarrenm /* 1574734b6a94Sdarrenm * Allocate and initialize SHA2 context. 1575734b6a94Sdarrenm */ 1576734b6a94Sdarrenm sha2_hmac_ctx_tmpl = kmem_alloc(sizeof (sha2_hmac_ctx_t), 1577734b6a94Sdarrenm crypto_kmflag(req)); 1578734b6a94Sdarrenm if (sha2_hmac_ctx_tmpl == NULL) 1579734b6a94Sdarrenm return (CRYPTO_HOST_MEMORY); 1580734b6a94Sdarrenm 1581734b6a94Sdarrenm sha2_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type; 1582734b6a94Sdarrenm 1583734b6a94Sdarrenm if (keylen_in_bytes > sha_hmac_block_size) { 1584734b6a94Sdarrenm uchar_t digested_key[SHA512_DIGEST_LENGTH]; 1585734b6a94Sdarrenm 1586734b6a94Sdarrenm /* 1587734b6a94Sdarrenm * Hash the passed-in key to get a smaller key. 1588734b6a94Sdarrenm * The inner context is used since it hasn't been 1589734b6a94Sdarrenm * initialized yet. 1590734b6a94Sdarrenm */ 1591734b6a94Sdarrenm PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3, 1592734b6a94Sdarrenm &sha2_hmac_ctx_tmpl->hc_icontext, 1593734b6a94Sdarrenm key->ck_data, keylen_in_bytes, digested_key); 1594734b6a94Sdarrenm sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, digested_key, 1595734b6a94Sdarrenm sha_digest_len); 1596734b6a94Sdarrenm } else { 1597734b6a94Sdarrenm sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, key->ck_data, 1598734b6a94Sdarrenm keylen_in_bytes); 1599734b6a94Sdarrenm } 1600734b6a94Sdarrenm 1601734b6a94Sdarrenm *ctx_template = (crypto_spi_ctx_template_t)sha2_hmac_ctx_tmpl; 1602734b6a94Sdarrenm *ctx_template_size = sizeof (sha2_hmac_ctx_t); 1603734b6a94Sdarrenm 1604734b6a94Sdarrenm return (CRYPTO_SUCCESS); 1605734b6a94Sdarrenm } 1606734b6a94Sdarrenm 1607734b6a94Sdarrenm static int 1608734b6a94Sdarrenm sha2_free_context(crypto_ctx_t *ctx) 1609734b6a94Sdarrenm { 1610734b6a94Sdarrenm uint_t ctx_len; 1611734b6a94Sdarrenm 1612734b6a94Sdarrenm if (ctx->cc_provider_private == NULL) 1613734b6a94Sdarrenm return (CRYPTO_SUCCESS); 1614734b6a94Sdarrenm 1615734b6a94Sdarrenm /* 1616734b6a94Sdarrenm * We have to free either SHA2 or SHA2-HMAC contexts, which 1617734b6a94Sdarrenm * have different lengths. 1618734b6a94Sdarrenm * 1619734b6a94Sdarrenm * Note: Below is dependent on the mechanism ordering. 1620734b6a94Sdarrenm */ 1621734b6a94Sdarrenm 1622734b6a94Sdarrenm if (PROV_SHA2_CTX(ctx)->sc_mech_type % 3 == 0) 1623734b6a94Sdarrenm ctx_len = sizeof (sha2_ctx_t); 1624734b6a94Sdarrenm else 1625734b6a94Sdarrenm ctx_len = sizeof (sha2_hmac_ctx_t); 1626734b6a94Sdarrenm 1627734b6a94Sdarrenm bzero(ctx->cc_provider_private, ctx_len); 1628734b6a94Sdarrenm kmem_free(ctx->cc_provider_private, ctx_len); 1629734b6a94Sdarrenm ctx->cc_provider_private = NULL; 1630734b6a94Sdarrenm 1631734b6a94Sdarrenm return (CRYPTO_SUCCESS); 1632734b6a94Sdarrenm } 1633