Path: blob/main/sys/contrib/openzfs/module/icp/io/sha2_mod.c
48529 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright 2010 Sun Microsystems, Inc. All rights reserved.24* Use is subject to license terms.25*/2627#include <sys/zfs_context.h>28#include <sys/crypto/common.h>29#include <sys/crypto/spi.h>30#include <sys/crypto/icp.h>31#include <sys/sha2.h>32#include <sha2/sha2_impl.h>3334/*35* Macros to access the SHA2 or SHA2-HMAC contexts from a context passed36* by KCF to one of the entry points.37*/3839#define PROV_SHA2_CTX(ctx) ((sha2_ctx_t *)(ctx)->cc_provider_private)40#define PROV_SHA2_HMAC_CTX(ctx) ((sha2_hmac_ctx_t *)(ctx)->cc_provider_private)4142/* to extract the digest length passed as mechanism parameter */43#define PROV_SHA2_GET_DIGEST_LEN(m, len) { \44if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t))) \45(len) = (uint32_t)*((ulong_t *)(m)->cm_param); \46else { \47ulong_t tmp_ulong; \48memcpy(&tmp_ulong, (m)->cm_param, sizeof (ulong_t)); \49(len) = (uint32_t)tmp_ulong; \50} \51}5253#define PROV_SHA2_DIGEST_KEY(mech, ctx, key, len, digest) { \54SHA2Init(mech, ctx); \55SHA2Update(ctx, key, len); \56SHA2Final(digest, ctx); \57}5859/*60* Mechanism info structure passed to KCF during registration.61*/62static const crypto_mech_info_t sha2_mech_info_tab[] = {63/* SHA512-HMAC */64{SUN_CKM_SHA512_HMAC, SHA512_HMAC_MECH_INFO_TYPE,65CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},66};6768static int sha2_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,69crypto_spi_ctx_template_t);70static int sha2_mac_update(crypto_ctx_t *, crypto_data_t *);71static int sha2_mac_final(crypto_ctx_t *, crypto_data_t *);72static int sha2_mac_atomic(crypto_mechanism_t *, crypto_key_t *,73crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);74static int sha2_mac_verify_atomic(crypto_mechanism_t *, crypto_key_t *,75crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);7677static const crypto_mac_ops_t sha2_mac_ops = {78.mac_init = sha2_mac_init,79.mac = NULL,80.mac_update = sha2_mac_update,81.mac_final = sha2_mac_final,82.mac_atomic = sha2_mac_atomic,83.mac_verify_atomic = sha2_mac_verify_atomic84};8586static int sha2_create_ctx_template(crypto_mechanism_t *, crypto_key_t *,87crypto_spi_ctx_template_t *, size_t *);88static int sha2_free_context(crypto_ctx_t *);8990static const crypto_ctx_ops_t sha2_ctx_ops = {91.create_ctx_template = sha2_create_ctx_template,92.free_context = sha2_free_context93};9495static const crypto_ops_t sha2_crypto_ops = {96NULL,97&sha2_mac_ops,98&sha2_ctx_ops,99};100101static const crypto_provider_info_t sha2_prov_info = {102"SHA2 Software Provider",103&sha2_crypto_ops,104sizeof (sha2_mech_info_tab) / sizeof (crypto_mech_info_t),105sha2_mech_info_tab106};107108static crypto_kcf_provider_handle_t sha2_prov_handle = 0;109110int111sha2_mod_init(void)112{113int ret;114115/*116* Register with KCF. If the registration fails, log an117* error but do not uninstall the module, since the functionality118* provided by misc/sha2 should still be available.119*/120if ((ret = crypto_register_provider(&sha2_prov_info,121&sha2_prov_handle)) != CRYPTO_SUCCESS)122cmn_err(CE_WARN, "sha2 _init: "123"crypto_register_provider() failed (0x%x)", ret);124125return (0);126}127128int129sha2_mod_fini(void)130{131int ret = 0;132133if (sha2_prov_handle != 0) {134if ((ret = crypto_unregister_provider(sha2_prov_handle)) !=135CRYPTO_SUCCESS) {136cmn_err(CE_WARN,137"sha2 _fini: crypto_unregister_provider() "138"failed (0x%x)", ret);139return (EBUSY);140}141sha2_prov_handle = 0;142}143144return (ret);145}146147/*148* Helper SHA2 digest update function for uio data.149*/150static int151sha2_digest_update_uio(SHA2_CTX *sha2_ctx, crypto_data_t *data)152{153off_t offset = data->cd_offset;154size_t length = data->cd_length;155uint_t vec_idx = 0;156size_t cur_len;157158/* we support only kernel buffer */159if (zfs_uio_segflg(data->cd_uio) != UIO_SYSSPACE)160return (CRYPTO_ARGUMENTS_BAD);161162/*163* Jump to the first iovec containing data to be164* digested.165*/166offset = zfs_uio_index_at_offset(data->cd_uio, offset, &vec_idx);167if (vec_idx == zfs_uio_iovcnt(data->cd_uio)) {168/*169* The caller specified an offset that is larger than the170* total size of the buffers it provided.171*/172return (CRYPTO_DATA_LEN_RANGE);173}174175/*176* Now do the digesting on the iovecs.177*/178while (vec_idx < zfs_uio_iovcnt(data->cd_uio) && length > 0) {179cur_len = MIN(zfs_uio_iovlen(data->cd_uio, vec_idx) -180offset, length);181182SHA2Update(sha2_ctx, (uint8_t *)zfs_uio_iovbase(data->cd_uio,183vec_idx) + offset, cur_len);184length -= cur_len;185vec_idx++;186offset = 0;187}188189if (vec_idx == zfs_uio_iovcnt(data->cd_uio) && length > 0) {190/*191* The end of the specified iovec's was reached but192* the length requested could not be processed, i.e.193* The caller requested to digest more data than it provided.194*/195return (CRYPTO_DATA_LEN_RANGE);196}197198return (CRYPTO_SUCCESS);199}200201/*202* Helper SHA2 digest final function for uio data.203* digest_len is the length of the desired digest. If digest_len204* is smaller than the default SHA2 digest length, the caller205* must pass a scratch buffer, digest_scratch, which must206* be at least the algorithm's digest length bytes.207*/208static int209sha2_digest_final_uio(SHA2_CTX *sha2_ctx, crypto_data_t *digest,210ulong_t digest_len, uchar_t *digest_scratch)211{212off_t offset = digest->cd_offset;213uint_t vec_idx = 0;214215/* we support only kernel buffer */216if (zfs_uio_segflg(digest->cd_uio) != UIO_SYSSPACE)217return (CRYPTO_ARGUMENTS_BAD);218219/*220* Jump to the first iovec containing ptr to the digest to221* be returned.222*/223offset = zfs_uio_index_at_offset(digest->cd_uio, offset, &vec_idx);224if (vec_idx == zfs_uio_iovcnt(digest->cd_uio)) {225/*226* The caller specified an offset that is227* larger than the total size of the buffers228* it provided.229*/230return (CRYPTO_DATA_LEN_RANGE);231}232233if (offset + digest_len <=234zfs_uio_iovlen(digest->cd_uio, vec_idx)) {235/*236* The computed SHA2 digest will fit in the current237* iovec.238*/239ASSERT3U(sha2_ctx->algotype, ==, SHA512_HMAC_MECH_INFO_TYPE);240if (digest_len != SHA512_DIGEST_LENGTH) {241/*242* The caller requested a short digest. Digest243* into a scratch buffer and return to244* the user only what was requested.245*/246SHA2Final(digest_scratch, sha2_ctx);247248memcpy((uchar_t *)249zfs_uio_iovbase(digest->cd_uio, vec_idx) + offset,250digest_scratch, digest_len);251} else {252SHA2Final((uchar_t *)zfs_uio_iovbase(digest->253cd_uio, vec_idx) + offset,254sha2_ctx);255256}257} else {258/*259* The computed digest will be crossing one or more iovec's.260* This is bad performance-wise but we need to support it.261* Allocate a small scratch buffer on the stack and262* copy it piece meal to the specified digest iovec's.263*/264uchar_t digest_tmp[SHA512_DIGEST_LENGTH];265off_t scratch_offset = 0;266size_t length = digest_len;267size_t cur_len;268269SHA2Final(digest_tmp, sha2_ctx);270271while (vec_idx < zfs_uio_iovcnt(digest->cd_uio) && length > 0) {272cur_len =273MIN(zfs_uio_iovlen(digest->cd_uio, vec_idx) -274offset, length);275memcpy(276zfs_uio_iovbase(digest->cd_uio, vec_idx) + offset,277digest_tmp + scratch_offset,278cur_len);279280length -= cur_len;281vec_idx++;282scratch_offset += cur_len;283offset = 0;284}285286if (vec_idx == zfs_uio_iovcnt(digest->cd_uio) && length > 0) {287/*288* The end of the specified iovec's was reached but289* the length requested could not be processed, i.e.290* The caller requested to digest more data than it291* provided.292*/293return (CRYPTO_DATA_LEN_RANGE);294}295}296297return (CRYPTO_SUCCESS);298}299300/*301* KCF software provider mac entry points.302*303* SHA2 HMAC is: SHA2(key XOR opad, SHA2(key XOR ipad, text))304*305* Init:306* The initialization routine initializes what we denote307* as the inner and outer contexts by doing308* - for inner context: SHA2(key XOR ipad)309* - for outer context: SHA2(key XOR opad)310*311* Update:312* Each subsequent SHA2 HMAC update will result in an313* update of the inner context with the specified data.314*315* Final:316* The SHA2 HMAC final will do a SHA2 final operation on the317* inner context, and the resulting digest will be used318* as the data for an update on the outer context. Last319* but not least, a SHA2 final on the outer context will320* be performed to obtain the SHA2 HMAC digest to return321* to the user.322*/323324/*325* Initialize a SHA2-HMAC context.326*/327static void328sha2_mac_init_ctx(sha2_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)329{330uint64_t ipad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)] = {0};331uint64_t opad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)] = {0};332int i, block_size, blocks_per_int64;333334/* Determine the block size */335ASSERT3U(ctx->hc_mech_type, ==, SHA512_HMAC_MECH_INFO_TYPE);336block_size = SHA512_HMAC_BLOCK_SIZE;337blocks_per_int64 = SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t);338339(void) memset(ipad, 0, block_size);340(void) memset(opad, 0, block_size);341342if (keyval != NULL) {343(void) memcpy(ipad, keyval, length_in_bytes);344(void) memcpy(opad, keyval, length_in_bytes);345} else {346ASSERT0(length_in_bytes);347}348349/* XOR key with ipad (0x36) and opad (0x5c) */350for (i = 0; i < blocks_per_int64; i ++) {351ipad[i] ^= 0x3636363636363636;352opad[i] ^= 0x5c5c5c5c5c5c5c5c;353}354355/* perform SHA2 on ipad */356SHA2Init(ctx->hc_mech_type, &ctx->hc_icontext);357SHA2Update(&ctx->hc_icontext, (uint8_t *)ipad, block_size);358359/* perform SHA2 on opad */360SHA2Init(ctx->hc_mech_type, &ctx->hc_ocontext);361SHA2Update(&ctx->hc_ocontext, (uint8_t *)opad, block_size);362}363364/*365*/366static int367sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,368crypto_key_t *key, crypto_spi_ctx_template_t ctx_template)369{370int ret = CRYPTO_SUCCESS;371uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);372uint_t sha_digest_len, sha_hmac_block_size;373374/*375* Set the digest length and block size to values appropriate to the376* mechanism377*/378switch (mechanism->cm_type) {379case SHA512_HMAC_MECH_INFO_TYPE:380sha_digest_len = SHA512_DIGEST_LENGTH;381sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;382break;383default:384return (CRYPTO_MECHANISM_INVALID);385}386387ctx->cc_provider_private =388kmem_alloc(sizeof (sha2_hmac_ctx_t), KM_SLEEP);389if (ctx->cc_provider_private == NULL)390return (CRYPTO_HOST_MEMORY);391392PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;393if (ctx_template != NULL) {394/* reuse context template */395memcpy(PROV_SHA2_HMAC_CTX(ctx), ctx_template,396sizeof (sha2_hmac_ctx_t));397} else {398/* no context template, compute context */399if (keylen_in_bytes > sha_hmac_block_size) {400uchar_t digested_key[SHA512_DIGEST_LENGTH];401sha2_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;402403/*404* Hash the passed-in key to get a smaller key.405* The inner context is used since it hasn't been406* initialized yet.407*/408PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,409&hmac_ctx->hc_icontext,410key->ck_data, keylen_in_bytes, digested_key);411sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx),412digested_key, sha_digest_len);413} else {414sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx),415key->ck_data, keylen_in_bytes);416}417}418419if (ret != CRYPTO_SUCCESS) {420memset(ctx->cc_provider_private, 0, sizeof (sha2_hmac_ctx_t));421kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));422ctx->cc_provider_private = NULL;423}424425return (ret);426}427428static int429sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data)430{431int ret = CRYPTO_SUCCESS;432433ASSERT(ctx->cc_provider_private != NULL);434435/*436* Do a SHA2 update of the inner context using the specified437* data.438*/439switch (data->cd_format) {440case CRYPTO_DATA_RAW:441SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_icontext,442(uint8_t *)data->cd_raw.iov_base + data->cd_offset,443data->cd_length);444break;445case CRYPTO_DATA_UIO:446ret = sha2_digest_update_uio(447&PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, data);448break;449default:450ret = CRYPTO_ARGUMENTS_BAD;451}452453return (ret);454}455456static int457sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac)458{459int ret = CRYPTO_SUCCESS;460uchar_t digest[SHA512_DIGEST_LENGTH];461uint32_t digest_len, sha_digest_len;462463ASSERT(ctx->cc_provider_private != NULL);464465/* Set the digest lengths to values appropriate to the mechanism */466switch (PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type) {467case SHA512_HMAC_MECH_INFO_TYPE:468sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;469break;470default:471return (CRYPTO_ARGUMENTS_BAD);472}473474/*475* We need to just return the length needed to store the output.476* We should not destroy the context for the following cases.477*/478if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {479mac->cd_length = digest_len;480return (CRYPTO_BUFFER_TOO_SMALL);481}482483/*484* Do a SHA2 final on the inner context.485*/486SHA2Final(digest, &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext);487488/*489* Do a SHA2 update on the outer context, feeding the inner490* digest as data.491*/492SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, digest,493sha_digest_len);494495/*496* Do a SHA2 final on the outer context, storing the computing497* digest in the users buffer.498*/499switch (mac->cd_format) {500case CRYPTO_DATA_RAW:501if (digest_len != sha_digest_len) {502/*503* The caller requested a short digest. Digest504* into a scratch buffer and return to505* the user only what was requested.506*/507SHA2Final(digest,508&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext);509memcpy((unsigned char *)mac->cd_raw.iov_base +510mac->cd_offset, digest, digest_len);511} else {512SHA2Final((unsigned char *)mac->cd_raw.iov_base +513mac->cd_offset,514&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext);515}516break;517case CRYPTO_DATA_UIO:518ret = sha2_digest_final_uio(519&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, mac,520digest_len, digest);521break;522default:523ret = CRYPTO_ARGUMENTS_BAD;524}525526if (ret == CRYPTO_SUCCESS)527mac->cd_length = digest_len;528else529mac->cd_length = 0;530531memset(ctx->cc_provider_private, 0, sizeof (sha2_hmac_ctx_t));532kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));533ctx->cc_provider_private = NULL;534535return (ret);536}537538#define SHA2_MAC_UPDATE(data, ctx, ret) { \539switch (data->cd_format) { \540case CRYPTO_DATA_RAW: \541SHA2Update(&(ctx).hc_icontext, \542(uint8_t *)data->cd_raw.iov_base + \543data->cd_offset, data->cd_length); \544break; \545case CRYPTO_DATA_UIO: \546ret = sha2_digest_update_uio(&(ctx).hc_icontext, data); \547break; \548default: \549ret = CRYPTO_ARGUMENTS_BAD; \550} \551}552553static int554sha2_mac_atomic(crypto_mechanism_t *mechanism,555crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,556crypto_spi_ctx_template_t ctx_template)557{558int ret = CRYPTO_SUCCESS;559uchar_t digest[SHA512_DIGEST_LENGTH];560sha2_hmac_ctx_t sha2_hmac_ctx;561uint32_t sha_digest_len, digest_len, sha_hmac_block_size;562uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);563564/*565* Set the digest length and block size to values appropriate to the566* mechanism567*/568switch (mechanism->cm_type) {569case SHA512_HMAC_MECH_INFO_TYPE:570sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;571sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;572break;573default:574return (CRYPTO_MECHANISM_INVALID);575}576577if (ctx_template != NULL) {578/* reuse context template */579memcpy(&sha2_hmac_ctx, ctx_template, sizeof (sha2_hmac_ctx_t));580} else {581sha2_hmac_ctx.hc_mech_type = mechanism->cm_type;582/* no context template, initialize context */583if (keylen_in_bytes > sha_hmac_block_size) {584/*585* Hash the passed-in key to get a smaller key.586* The inner context is used since it hasn't been587* initialized yet.588*/589PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,590&sha2_hmac_ctx.hc_icontext,591key->ck_data, keylen_in_bytes, digest);592sha2_mac_init_ctx(&sha2_hmac_ctx, digest,593sha_digest_len);594} else {595sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data,596keylen_in_bytes);597}598}599600/* do a SHA2 update of the inner context using the specified data */601SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret);602if (ret != CRYPTO_SUCCESS)603/* the update failed, free context and bail */604goto bail;605606/*607* Do a SHA2 final on the inner context.608*/609SHA2Final(digest, &sha2_hmac_ctx.hc_icontext);610611/*612* Do an SHA2 update on the outer context, feeding the inner613* digest as data.614*/615ASSERT3U(mechanism->cm_type, ==, SHA512_HMAC_MECH_INFO_TYPE);616SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len);617618/*619* Do a SHA2 final on the outer context, storing the computed620* digest in the users buffer.621*/622switch (mac->cd_format) {623case CRYPTO_DATA_RAW:624if (digest_len != sha_digest_len) {625/*626* The caller requested a short digest. Digest627* into a scratch buffer and return to628* the user only what was requested.629*/630SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext);631memcpy((unsigned char *)mac->cd_raw.iov_base +632mac->cd_offset, digest, digest_len);633} else {634SHA2Final((unsigned char *)mac->cd_raw.iov_base +635mac->cd_offset, &sha2_hmac_ctx.hc_ocontext);636}637break;638case CRYPTO_DATA_UIO:639ret = sha2_digest_final_uio(&sha2_hmac_ctx.hc_ocontext, mac,640digest_len, digest);641break;642default:643ret = CRYPTO_ARGUMENTS_BAD;644}645646if (ret == CRYPTO_SUCCESS) {647mac->cd_length = digest_len;648return (CRYPTO_SUCCESS);649}650bail:651memset(&sha2_hmac_ctx, 0, sizeof (sha2_hmac_ctx_t));652mac->cd_length = 0;653return (ret);654}655656static int657sha2_mac_verify_atomic(crypto_mechanism_t *mechanism,658crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,659crypto_spi_ctx_template_t ctx_template)660{661int ret = CRYPTO_SUCCESS;662uchar_t digest[SHA512_DIGEST_LENGTH];663sha2_hmac_ctx_t sha2_hmac_ctx;664uint32_t sha_digest_len, digest_len, sha_hmac_block_size;665uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);666667/*668* Set the digest length and block size to values appropriate to the669* mechanism670*/671switch (mechanism->cm_type) {672case SHA512_HMAC_MECH_INFO_TYPE:673sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;674sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;675break;676default:677return (CRYPTO_MECHANISM_INVALID);678}679680if (ctx_template != NULL) {681/* reuse context template */682memcpy(&sha2_hmac_ctx, ctx_template, sizeof (sha2_hmac_ctx_t));683} else {684sha2_hmac_ctx.hc_mech_type = mechanism->cm_type;685/* no context template, initialize context */686if (keylen_in_bytes > sha_hmac_block_size) {687/*688* Hash the passed-in key to get a smaller key.689* The inner context is used since it hasn't been690* initialized yet.691*/692PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,693&sha2_hmac_ctx.hc_icontext,694key->ck_data, keylen_in_bytes, digest);695sha2_mac_init_ctx(&sha2_hmac_ctx, digest,696sha_digest_len);697} else {698sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data,699keylen_in_bytes);700}701}702703if (mac->cd_length != digest_len) {704ret = CRYPTO_INVALID_MAC;705goto bail;706}707708/* do a SHA2 update of the inner context using the specified data */709SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret);710if (ret != CRYPTO_SUCCESS)711/* the update failed, free context and bail */712goto bail;713714/* do a SHA2 final on the inner context */715SHA2Final(digest, &sha2_hmac_ctx.hc_icontext);716717/*718* Do an SHA2 update on the outer context, feeding the inner719* digest as data.720*/721ASSERT3U(mechanism->cm_type, ==, SHA512_HMAC_MECH_INFO_TYPE);722SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len);723724/*725* Do a SHA2 final on the outer context, storing the computed726* digest in the users buffer.727*/728SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext);729730/*731* Compare the computed digest against the expected digest passed732* as argument.733*/734735switch (mac->cd_format) {736737case CRYPTO_DATA_RAW:738if (memcmp(digest, (unsigned char *)mac->cd_raw.iov_base +739mac->cd_offset, digest_len) != 0)740ret = CRYPTO_INVALID_MAC;741break;742743case CRYPTO_DATA_UIO: {744off_t offset = mac->cd_offset;745uint_t vec_idx = 0;746off_t scratch_offset = 0;747size_t length = digest_len;748size_t cur_len;749750/* we support only kernel buffer */751if (zfs_uio_segflg(mac->cd_uio) != UIO_SYSSPACE)752return (CRYPTO_ARGUMENTS_BAD);753754/* jump to the first iovec containing the expected digest */755offset = zfs_uio_index_at_offset(mac->cd_uio, offset, &vec_idx);756if (vec_idx == zfs_uio_iovcnt(mac->cd_uio)) {757/*758* The caller specified an offset that is759* larger than the total size of the buffers760* it provided.761*/762ret = CRYPTO_DATA_LEN_RANGE;763break;764}765766/* do the comparison of computed digest vs specified one */767while (vec_idx < zfs_uio_iovcnt(mac->cd_uio) && length > 0) {768cur_len = MIN(zfs_uio_iovlen(mac->cd_uio, vec_idx) -769offset, length);770771if (memcmp(digest + scratch_offset,772zfs_uio_iovbase(mac->cd_uio, vec_idx) + offset,773cur_len) != 0) {774ret = CRYPTO_INVALID_MAC;775break;776}777778length -= cur_len;779vec_idx++;780scratch_offset += cur_len;781offset = 0;782}783break;784}785786default:787ret = CRYPTO_ARGUMENTS_BAD;788}789790return (ret);791bail:792memset(&sha2_hmac_ctx, 0, sizeof (sha2_hmac_ctx_t));793mac->cd_length = 0;794return (ret);795}796797/*798* KCF software provider context management entry points.799*/800801static int802sha2_create_ctx_template(crypto_mechanism_t *mechanism, crypto_key_t *key,803crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size)804{805sha2_hmac_ctx_t *sha2_hmac_ctx_tmpl;806uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);807uint32_t sha_digest_len, sha_hmac_block_size;808809/*810* Set the digest length and block size to values appropriate to the811* mechanism812*/813switch (mechanism->cm_type) {814case SHA512_HMAC_MECH_INFO_TYPE:815sha_digest_len = SHA512_DIGEST_LENGTH;816sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;817break;818default:819return (CRYPTO_MECHANISM_INVALID);820}821822/*823* Allocate and initialize SHA2 context.824*/825sha2_hmac_ctx_tmpl = kmem_alloc(sizeof (sha2_hmac_ctx_t), KM_SLEEP);826if (sha2_hmac_ctx_tmpl == NULL)827return (CRYPTO_HOST_MEMORY);828829sha2_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;830831if (keylen_in_bytes > sha_hmac_block_size) {832uchar_t digested_key[SHA512_DIGEST_LENGTH];833834/*835* Hash the passed-in key to get a smaller key.836* The inner context is used since it hasn't been837* initialized yet.838*/839PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,840&sha2_hmac_ctx_tmpl->hc_icontext,841key->ck_data, keylen_in_bytes, digested_key);842sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, digested_key,843sha_digest_len);844} else {845sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, key->ck_data,846keylen_in_bytes);847}848849*ctx_template = (crypto_spi_ctx_template_t)sha2_hmac_ctx_tmpl;850*ctx_template_size = sizeof (sha2_hmac_ctx_t);851852return (CRYPTO_SUCCESS);853}854855static int856sha2_free_context(crypto_ctx_t *ctx)857{858uint_t ctx_len;859860if (ctx->cc_provider_private == NULL)861return (CRYPTO_SUCCESS);862863ASSERT3U(PROV_SHA2_CTX(ctx)->sc_mech_type, ==,864SHA512_HMAC_MECH_INFO_TYPE);865ctx_len = sizeof (sha2_hmac_ctx_t);866867memset(ctx->cc_provider_private, 0, ctx_len);868kmem_free(ctx->cc_provider_private, ctx_len);869ctx->cc_provider_private = NULL;870871return (CRYPTO_SUCCESS);872}873874875