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