1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/zfs_context.h> 28 #include <sys/crypto/common.h> 29 #include <sys/crypto/impl.h> 30 #include <sys/crypto/api.h> 31 #include <sys/crypto/spi.h> 32 #include <sys/crypto/sched_impl.h> 33 34 /* 35 * Message authentication codes routines. 36 */ 37 38 /* 39 * The following are the possible returned values common to all the routines 40 * below. The applicability of some of these return values depends on the 41 * presence of the arguments. 42 * 43 * CRYPTO_SUCCESS: The operation completed successfully. 44 * CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or 45 * CRYPTO_INVALID_MECH for problems with the 'mech'. 46 * CRYPTO_INVALID_DATA for bogus 'data' 47 * CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work. 48 * CRYPTO_INVALID_CONTEXT: Not a valid context. 49 * CRYPTO_BUSY: Cannot process the request now. Try later. 50 * CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is 51 * capable of a function or a mechanism. 52 * CRYPTO_INVALID_KEY: bogus 'key' argument. 53 * CRYPTO_INVALID_MAC: bogus 'mac' argument. 54 */ 55 56 /* 57 * crypto_mac_prov() 58 * 59 * Arguments: 60 * mech: crypto_mechanism_t pointer. 61 * mech_type is a valid value previously returned by 62 * crypto_mech2id(); 63 * When the mech's parameter is not NULL, its definition depends 64 * on the standard definition of the mechanism. 65 * key: pointer to a crypto_key_t structure. 66 * data: The message to compute the MAC for. 67 * mac: Storage for the MAC. The length needed depends on the mechanism. 68 * tmpl: a crypto_ctx_template_t, opaque template of a context of a 69 * MAC with the 'mech' using 'key'. 'tmpl' is created by 70 * a previous call to crypto_create_ctx_template(). 71 * 72 * Description: 73 * Asynchronously submits a request for, or synchronously performs a 74 * single-part message authentication of 'data' with the mechanism 75 * 'mech', using * the key 'key', on the specified provider with 76 * the specified session id. 77 * When complete and successful, 'mac' will contain the message 78 * authentication code. 79 * Relies on the KCF scheduler to choose a provider. 80 * 81 * Returns: 82 * See comment in the beginning of the file. 83 */ 84 int 85 crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data, 86 crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac) 87 { 88 int error; 89 kcf_mech_entry_t *me; 90 kcf_provider_desc_t *pd; 91 kcf_ctx_template_t *ctx_tmpl; 92 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; 93 kcf_prov_tried_t *list = NULL; 94 95 retry: 96 /* The pd is returned held */ 97 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, 98 list, CRYPTO_FG_MAC_ATOMIC)) == NULL) { 99 if (list != NULL) 100 kcf_free_triedlist(list); 101 return (error); 102 } 103 104 if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) 105 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; 106 107 crypto_mechanism_t lmech = *mech; 108 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); 109 error = KCF_PROV_MAC_ATOMIC(pd, &lmech, key, data, 110 mac, spi_ctx_tmpl); 111 112 if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) { 113 /* Add pd to the linked list of providers tried. */ 114 if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL) 115 goto retry; 116 } 117 118 if (list != NULL) 119 kcf_free_triedlist(list); 120 121 KCF_PROV_REFRELE(pd); 122 return (error); 123 } 124 125 /* 126 * crypto_mac_init_prov() 127 * 128 * Arguments: 129 * pd: pointer to the descriptor of the provider to use for this 130 * operation. 131 * mech: crypto_mechanism_t pointer. 132 * mech_type is a valid value previously returned by 133 * crypto_mech2id(); 134 * When the mech's parameter is not NULL, its definition depends 135 * on the standard definition of the mechanism. 136 * key: pointer to a crypto_key_t structure. 137 * tmpl: a crypto_ctx_template_t, opaque template of a context of a 138 * MAC with the 'mech' using 'key'. 'tmpl' is created by 139 * a previous call to crypto_create_ctx_template(). 140 * ctxp: Pointer to a crypto_context_t. 141 * 142 * Description: 143 * Asynchronously submits a request for, or synchronously performs the 144 * initialization of a MAC operation on the specified provider with 145 * the specified session. 146 * When possible and applicable, will internally use the pre-computed MAC 147 * context from the context template, tmpl. 148 * When complete and successful, 'ctxp' will contain a crypto_context_t 149 * valid for later calls to mac_update() and mac_final(). 150 * The caller should hold a reference on the specified provider 151 * descriptor before calling this function. 152 * 153 * Returns: 154 * See comment in the beginning of the file. 155 */ 156 static int 157 crypto_mac_init_prov(kcf_provider_desc_t *pd, 158 crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl, 159 crypto_context_t *ctxp) 160 { 161 int rv; 162 crypto_ctx_t *ctx; 163 kcf_provider_desc_t *real_provider = pd; 164 165 ASSERT(KCF_PROV_REFHELD(pd)); 166 167 /* Allocate and initialize the canonical context */ 168 if ((ctx = kcf_new_ctx(real_provider)) == NULL) 169 return (CRYPTO_HOST_MEMORY); 170 171 crypto_mechanism_t lmech = *mech; 172 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech); 173 rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl); 174 175 if (rv == CRYPTO_SUCCESS) 176 *ctxp = (crypto_context_t)ctx; 177 else { 178 /* Release the hold done in kcf_new_ctx(). */ 179 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private); 180 } 181 182 return (rv); 183 } 184 185 /* 186 * Same as crypto_mac_init_prov(), but relies on the KCF scheduler to 187 * choose a provider. See crypto_mac_init_prov() comments for more 188 * information. 189 */ 190 int 191 crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key, 192 crypto_ctx_template_t tmpl, crypto_context_t *ctxp) 193 { 194 int error; 195 kcf_mech_entry_t *me; 196 kcf_provider_desc_t *pd; 197 kcf_ctx_template_t *ctx_tmpl; 198 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; 199 kcf_prov_tried_t *list = NULL; 200 201 retry: 202 /* The pd is returned held */ 203 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, 204 list, CRYPTO_FG_MAC)) == NULL) { 205 if (list != NULL) 206 kcf_free_triedlist(list); 207 return (error); 208 } 209 210 /* 211 * Check the validity of the context template 212 * It is very rare that the generation number mis-matches, so 213 * is acceptable to fail here, and let the consumer recover by 214 * freeing this tmpl and create a new one for the key and new provider 215 */ 216 217 if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) 218 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; 219 220 error = crypto_mac_init_prov(pd, mech, key, 221 spi_ctx_tmpl, ctxp); 222 if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) { 223 /* Add pd to the linked list of providers tried. */ 224 if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL) 225 goto retry; 226 } 227 228 if (list != NULL) 229 kcf_free_triedlist(list); 230 231 KCF_PROV_REFRELE(pd); 232 return (error); 233 } 234 235 /* 236 * crypto_mac_update() 237 * 238 * Arguments: 239 * context: A crypto_context_t initialized by mac_init(). 240 * data: The message part to be MAC'ed 241 * 242 * Description: 243 * Synchronously performs a part of a MAC operation. 244 * 245 * Returns: 246 * See comment in the beginning of the file. 247 */ 248 int 249 crypto_mac_update(crypto_context_t context, crypto_data_t *data) 250 { 251 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 252 kcf_context_t *kcf_ctx; 253 kcf_provider_desc_t *pd; 254 255 if ((ctx == NULL) || 256 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 257 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 258 return (CRYPTO_INVALID_CONTEXT); 259 } 260 261 return (KCF_PROV_MAC_UPDATE(pd, ctx, data)); 262 } 263 264 /* 265 * crypto_mac_final() 266 * 267 * Arguments: 268 * context: A crypto_context_t initialized by mac_init(). 269 * mac: Storage for the message authentication code. 270 * 271 * Description: 272 * Synchronously performs a part of a message authentication operation. 273 * 274 * Returns: 275 * See comment in the beginning of the file. 276 */ 277 int 278 crypto_mac_final(crypto_context_t context, crypto_data_t *mac) 279 { 280 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 281 kcf_context_t *kcf_ctx; 282 kcf_provider_desc_t *pd; 283 284 if ((ctx == NULL) || 285 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 286 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 287 return (CRYPTO_INVALID_CONTEXT); 288 } 289 290 int rv = KCF_PROV_MAC_FINAL(pd, ctx, mac); 291 292 /* Release the hold done in kcf_new_ctx() during init step. */ 293 KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx); 294 return (rv); 295 } 296 297 #if defined(_KERNEL) 298 EXPORT_SYMBOL(crypto_mac); 299 EXPORT_SYMBOL(crypto_mac_init); 300 EXPORT_SYMBOL(crypto_mac_update); 301 EXPORT_SYMBOL(crypto_mac_final); 302 #endif 303