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