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