Path: blob/main/sys/contrib/openzfs/module/icp/api/kcf_mac.c
48531 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*/21/*22* Copyright 2007 Sun Microsystems, Inc. All rights reserved.23* Use is subject to license terms.24*/2526#include <sys/zfs_context.h>27#include <sys/crypto/common.h>28#include <sys/crypto/impl.h>29#include <sys/crypto/api.h>30#include <sys/crypto/spi.h>31#include <sys/crypto/sched_impl.h>3233/*34* Message authentication codes routines.35*/3637/*38* The following are the possible returned values common to all the routines39* below. The applicability of some of these return values depends on the40* presence of the arguments.41*42* CRYPTO_SUCCESS: The operation completed successfully.43* CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or44* CRYPTO_INVALID_MECH for problems with the 'mech'.45* CRYPTO_INVALID_DATA for bogus 'data'46* CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.47* CRYPTO_INVALID_CONTEXT: Not a valid context.48* CRYPTO_BUSY: Cannot process the request now. Try later.49* CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is50* capable of a function or a mechanism.51* CRYPTO_INVALID_KEY: bogus 'key' argument.52* CRYPTO_INVALID_MAC: bogus 'mac' argument.53*/5455/*56* crypto_mac_prov()57*58* Arguments:59* mech: crypto_mechanism_t pointer.60* mech_type is a valid value previously returned by61* crypto_mech2id();62* When the mech's parameter is not NULL, its definition depends63* on the standard definition of the mechanism.64* key: pointer to a crypto_key_t structure.65* data: The message to compute the MAC for.66* mac: Storage for the MAC. The length needed depends on the mechanism.67* tmpl: a crypto_ctx_template_t, opaque template of a context of a68* MAC with the 'mech' using 'key'. 'tmpl' is created by69* a previous call to crypto_create_ctx_template().70*71* Description:72* Asynchronously submits a request for, or synchronously performs a73* single-part message authentication of 'data' with the mechanism74* 'mech', using * the key 'key', on the specified provider with75* the specified session id.76* When complete and successful, 'mac' will contain the message77* authentication code.78* Relies on the KCF scheduler to choose a provider.79*80* Returns:81* See comment in the beginning of the file.82*/83int84crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,85crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac)86{87int error;88kcf_mech_entry_t *me;89kcf_provider_desc_t *pd;90kcf_ctx_template_t *ctx_tmpl;91crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;92kcf_prov_tried_t *list = NULL;9394retry:95/* The pd is returned held */96if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,97list, CRYPTO_FG_MAC_ATOMIC)) == NULL) {98if (list != NULL)99kcf_free_triedlist(list);100return (error);101}102103if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))104spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;105106crypto_mechanism_t lmech = *mech;107KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);108error = KCF_PROV_MAC_ATOMIC(pd, &lmech, key, data,109mac, spi_ctx_tmpl);110111if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {112/* Add pd to the linked list of providers tried. */113if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)114goto retry;115}116117if (list != NULL)118kcf_free_triedlist(list);119120KCF_PROV_REFRELE(pd);121return (error);122}123124/*125* crypto_mac_init_prov()126*127* Arguments:128* pd: pointer to the descriptor of the provider to use for this129* operation.130* mech: crypto_mechanism_t pointer.131* mech_type is a valid value previously returned by132* crypto_mech2id();133* When the mech's parameter is not NULL, its definition depends134* on the standard definition of the mechanism.135* key: pointer to a crypto_key_t structure.136* tmpl: a crypto_ctx_template_t, opaque template of a context of a137* MAC with the 'mech' using 'key'. 'tmpl' is created by138* a previous call to crypto_create_ctx_template().139* ctxp: Pointer to a crypto_context_t.140*141* Description:142* Asynchronously submits a request for, or synchronously performs the143* initialization of a MAC operation on the specified provider with144* the specified session.145* When possible and applicable, will internally use the pre-computed MAC146* context from the context template, tmpl.147* When complete and successful, 'ctxp' will contain a crypto_context_t148* valid for later calls to mac_update() and mac_final().149* The caller should hold a reference on the specified provider150* descriptor before calling this function.151*152* Returns:153* See comment in the beginning of the file.154*/155static int156crypto_mac_init_prov(kcf_provider_desc_t *pd,157crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl,158crypto_context_t *ctxp)159{160int rv;161crypto_ctx_t *ctx;162kcf_provider_desc_t *real_provider = pd;163164ASSERT(KCF_PROV_REFHELD(pd));165166/* Allocate and initialize the canonical context */167if ((ctx = kcf_new_ctx(real_provider)) == NULL)168return (CRYPTO_HOST_MEMORY);169170crypto_mechanism_t lmech = *mech;171KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);172rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl);173174if (rv == CRYPTO_SUCCESS)175*ctxp = (crypto_context_t)ctx;176else {177/* Release the hold done in kcf_new_ctx(). */178KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);179}180181return (rv);182}183184/*185* Same as crypto_mac_init_prov(), but relies on the KCF scheduler to186* choose a provider. See crypto_mac_init_prov() comments for more187* information.188*/189int190crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,191crypto_ctx_template_t tmpl, crypto_context_t *ctxp)192{193int error;194kcf_mech_entry_t *me;195kcf_provider_desc_t *pd;196kcf_ctx_template_t *ctx_tmpl;197crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;198kcf_prov_tried_t *list = NULL;199200retry:201/* The pd is returned held */202if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,203list, CRYPTO_FG_MAC)) == NULL) {204if (list != NULL)205kcf_free_triedlist(list);206return (error);207}208209/*210* Check the validity of the context template211* It is very rare that the generation number mis-matches, so212* is acceptable to fail here, and let the consumer recover by213* freeing this tmpl and create a new one for the key and new provider214*/215216if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))217spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;218219error = crypto_mac_init_prov(pd, mech, key,220spi_ctx_tmpl, ctxp);221if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {222/* Add pd to the linked list of providers tried. */223if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)224goto retry;225}226227if (list != NULL)228kcf_free_triedlist(list);229230KCF_PROV_REFRELE(pd);231return (error);232}233234/*235* crypto_mac_update()236*237* Arguments:238* context: A crypto_context_t initialized by mac_init().239* data: The message part to be MAC'ed240*241* Description:242* Synchronously performs a part of a MAC operation.243*244* Returns:245* See comment in the beginning of the file.246*/247int248crypto_mac_update(crypto_context_t context, crypto_data_t *data)249{250crypto_ctx_t *ctx = (crypto_ctx_t *)context;251kcf_context_t *kcf_ctx;252kcf_provider_desc_t *pd;253254if ((ctx == NULL) ||255((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||256((pd = kcf_ctx->kc_prov_desc) == NULL)) {257return (CRYPTO_INVALID_CONTEXT);258}259260return (KCF_PROV_MAC_UPDATE(pd, ctx, data));261}262263/*264* crypto_mac_final()265*266* Arguments:267* context: A crypto_context_t initialized by mac_init().268* mac: Storage for the message authentication code.269*270* Description:271* Synchronously performs a part of a message authentication operation.272*273* Returns:274* See comment in the beginning of the file.275*/276int277crypto_mac_final(crypto_context_t context, crypto_data_t *mac)278{279crypto_ctx_t *ctx = (crypto_ctx_t *)context;280kcf_context_t *kcf_ctx;281kcf_provider_desc_t *pd;282283if ((ctx == NULL) ||284((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||285((pd = kcf_ctx->kc_prov_desc) == NULL)) {286return (CRYPTO_INVALID_CONTEXT);287}288289int rv = KCF_PROV_MAC_FINAL(pd, ctx, mac);290291/* Release the hold done in kcf_new_ctx() during init step. */292KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx);293return (rv);294}295296#if defined(_KERNEL)297EXPORT_SYMBOL(crypto_mac);298EXPORT_SYMBOL(crypto_mac_init);299EXPORT_SYMBOL(crypto_mac_update);300EXPORT_SYMBOL(crypto_mac_final);301#endif302303304