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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/errno.h> 30 #include <sys/types.h> 31 #include <sys/kmem.h> 32 #include <sys/crypto/common.h> 33 #include <sys/crypto/impl.h> 34 #include <sys/crypto/api.h> 35 #include <sys/crypto/spi.h> 36 #include <sys/crypto/sched_impl.h> 37 38 /* 39 * Message authentication codes routines. 40 */ 41 42 /* 43 * The following are the possible returned values common to all the routines 44 * below. The applicability of some of these return values depends on the 45 * presence of the arguments. 46 * 47 * CRYPTO_SUCCESS: The operation completed successfully. 48 * CRYPTO_QUEUED: A request was submitted successfully. The callback 49 * routine will be called when the operation is done. 50 * CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or 51 * CRYPTO_INVALID_MECH for problems with the 'mech'. 52 * CRYPTO_INVALID_DATA for bogus 'data' 53 * CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work. 54 * CRYPTO_INVALID_CONTEXT: Not a valid context. 55 * CRYPTO_BUSY: Cannot process the request now. Schedule a 56 * crypto_bufcall(), or try later. 57 * CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is 58 * capable of a function or a mechanism. 59 * CRYPTO_INVALID_KEY: bogus 'key' argument. 60 * CRYPTO_INVALID_MAC: bogus 'mac' argument. 61 */ 62 63 /* 64 * crypto_mac_prov() 65 * 66 * Arguments: 67 * mech: crypto_mechanism_t pointer. 68 * mech_type is a valid value previously returned by 69 * crypto_mech2id(); 70 * When the mech's parameter is not NULL, its definition depends 71 * on the standard definition of the mechanism. 72 * key: pointer to a crypto_key_t structure. 73 * data: The message to compute the MAC for. 74 * mac: Storage for the MAC. The length needed depends on the mechanism. 75 * tmpl: a crypto_ctx_template_t, opaque template of a context of a 76 * MAC with the 'mech' using 'key'. 'tmpl' is created by 77 * a previous call to crypto_create_ctx_template(). 78 * cr: crypto_call_req_t calling conditions and call back info. 79 * 80 * Description: 81 * Asynchronously submits a request for, or synchronously performs a 82 * single-part message authentication of 'data' with the mechanism 83 * 'mech', using * the key 'key', on the specified provider with 84 * the specified session id. 85 * When complete and successful, 'mac' will contain the message 86 * authentication code. 87 * 88 * Context: 89 * Process or interrupt, according to the semantics dictated by the 'crq'. 90 * 91 * Returns: 92 * See comment in the beginning of the file. 93 */ 94 int 95 crypto_mac_prov(crypto_mechanism_t *mech, crypto_data_t *data, 96 crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac, 97 crypto_call_req_t *crq, kcf_provider_desc_t *pd, crypto_session_id_t sid) 98 { 99 kcf_req_params_t params; 100 101 ASSERT(KCF_PROV_REFHELD(pd)); 102 KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, key, 103 data, mac, tmpl); 104 105 return (kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE)); 106 } 107 108 /* 109 * Same as crypto_mac_prov(), but relies on the KCF scheduler to choose 110 * a provider. See crypto_mac() comments for more information. 111 */ 112 int 113 crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data, 114 crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac, 115 crypto_call_req_t *crq) 116 { 117 int error; 118 kcf_mech_entry_t *me; 119 kcf_req_params_t params; 120 kcf_provider_desc_t *pd; 121 kcf_ctx_template_t *ctx_tmpl; 122 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; 123 kcf_prov_tried_t *list = NULL; 124 125 retry: 126 /* The pd is returned held */ 127 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, 128 list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq), 129 data->cd_length)) == NULL) { 130 if (list != NULL) 131 kcf_free_triedlist(list); 132 return (error); 133 } 134 135 /* 136 * For SW providers, check the validity of the context template 137 * It is very rare that the generation number mis-matches, so 138 * is acceptable to fail here, and let the consumer recover by 139 * freeing this tmpl and create a new one for the key and new SW 140 * provider 141 */ 142 if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) && 143 ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) { 144 if (ctx_tmpl->ct_generation != me->me_gen_swprov) { 145 if (list != NULL) 146 kcf_free_triedlist(list); 147 KCF_PROV_REFRELE(pd); 148 return (CRYPTO_OLD_CTX_TEMPLATE); 149 } else { 150 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; 151 } 152 } 153 154 /* The fast path for SW providers. */ 155 if (CHECK_FASTPATH(crq, pd)) { 156 crypto_mechanism_t lmech; 157 158 lmech = *mech; 159 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); 160 161 error = KCF_PROV_MAC_ATOMIC(pd, pd->pd_sid, &lmech, key, data, 162 mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq)); 163 KCF_PROV_INCRSTATS(pd, error); 164 } else { 165 KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, pd->pd_sid, 166 mech, key, data, mac, spi_ctx_tmpl); 167 168 error = kcf_submit_request(pd, NULL, crq, ¶ms, 169 KCF_ISDUALREQ(crq)); 170 } 171 172 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && 173 IS_RECOVERABLE(error)) { 174 /* Add pd to the linked list of providers tried. */ 175 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) 176 goto retry; 177 } 178 179 if (list != NULL) 180 kcf_free_triedlist(list); 181 182 KCF_PROV_REFRELE(pd); 183 return (error); 184 } 185 186 /* 187 * Single part operation to compute the MAC corresponding to the specified 188 * 'data' and to verify that it matches the MAC specified by 'mac'. 189 * The other arguments are the same as the function crypto_mac_prov(). 190 */ 191 int 192 crypto_mac_verify_prov(crypto_mechanism_t *mech, crypto_data_t *data, 193 crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac, 194 crypto_call_req_t *crq, kcf_provider_desc_t *pd, crypto_session_id_t sid) 195 { 196 kcf_req_params_t params; 197 198 ASSERT(KCF_PROV_REFHELD(pd)); 199 KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_MAC_VERIFY_ATOMIC, sid, mech, 200 key, data, mac, tmpl); 201 202 return (kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE)); 203 } 204 205 /* 206 * Same as crypto_mac_verify_prov(), but relies on the KCF scheduler to choose 207 * a provider. See crypto_mac_verify_prov() comments for more information. 208 */ 209 int 210 crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data, 211 crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac, 212 crypto_call_req_t *crq) 213 { 214 int error; 215 kcf_mech_entry_t *me; 216 kcf_req_params_t params; 217 kcf_provider_desc_t *pd; 218 kcf_ctx_template_t *ctx_tmpl; 219 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; 220 kcf_prov_tried_t *list = NULL; 221 222 retry: 223 /* The pd is returned held */ 224 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, 225 list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq), 226 data->cd_length)) == NULL) { 227 if (list != NULL) 228 kcf_free_triedlist(list); 229 return (error); 230 } 231 232 /* 233 * For SW providers, check the validity of the context template 234 * It is very rare that the generation number mis-matches, so 235 * is acceptable to fail here, and let the consumer recover by 236 * freeing this tmpl and create a new one for the key and new SW 237 * provider 238 */ 239 if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) && 240 ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) { 241 if (ctx_tmpl->ct_generation != me->me_gen_swprov) { 242 if (list != NULL) 243 kcf_free_triedlist(list); 244 KCF_PROV_REFRELE(pd); 245 return (CRYPTO_OLD_CTX_TEMPLATE); 246 } else { 247 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; 248 } 249 } 250 251 /* The fast path for SW providers. */ 252 if (CHECK_FASTPATH(crq, pd)) { 253 crypto_mechanism_t lmech; 254 255 lmech = *mech; 256 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); 257 258 error = KCF_PROV_MAC_VERIFY_ATOMIC(pd, pd->pd_sid, &lmech, key, 259 data, mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq)); 260 KCF_PROV_INCRSTATS(pd, error); 261 } else { 262 KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_MAC_VERIFY_ATOMIC, 263 pd->pd_sid, mech, key, data, mac, spi_ctx_tmpl); 264 265 error = kcf_submit_request(pd, NULL, crq, ¶ms, 266 KCF_ISDUALREQ(crq)); 267 } 268 269 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && 270 IS_RECOVERABLE(error)) { 271 /* Add pd to the linked list of providers tried. */ 272 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) 273 goto retry; 274 } 275 276 if (list != NULL) 277 kcf_free_triedlist(list); 278 279 KCF_PROV_REFRELE(pd); 280 return (error); 281 } 282 283 284 /* 285 * crypto_mac_init_prov() 286 * 287 * Arguments: 288 * pd: pointer to the descriptor of the provider to use for this 289 * operation. 290 * sid: provider session id. 291 * mech: crypto_mechanism_t pointer. 292 * mech_type is a valid value previously returned by 293 * crypto_mech2id(); 294 * When the mech's parameter is not NULL, its definition depends 295 * on the standard definition of the mechanism. 296 * key: pointer to a crypto_key_t structure. 297 * tmpl: a crypto_ctx_template_t, opaque template of a context of a 298 * MAC with the 'mech' using 'key'. 'tmpl' is created by 299 * a previous call to crypto_create_ctx_template(). 300 * ctxp: Pointer to a crypto_context_t. 301 * cr: crypto_call_req_t calling conditions and call back info. 302 * 303 * Description: 304 * Asynchronously submits a request for, or synchronously performs the 305 * initialization of a MAC operation on the specified provider with 306 * the specified session. 307 * When possible and applicable, will internally use the pre-computed MAC 308 * context from the context template, tmpl. 309 * When complete and successful, 'ctxp' will contain a crypto_context_t 310 * valid for later calls to mac_update() and mac_final(). 311 * The caller should hold a reference on the specified provider 312 * descriptor before calling this function. 313 * 314 * Context: 315 * Process or interrupt, according to the semantics dictated by the 'cr'. 316 * 317 * Returns: 318 * See comment in the beginning of the file. 319 */ 320 int 321 crypto_mac_init_prov(kcf_provider_desc_t *pd, crypto_session_id_t sid, 322 crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl, 323 crypto_context_t *ctxp, crypto_call_req_t *crq) 324 { 325 int error; 326 crypto_ctx_t *ctx; 327 kcf_req_params_t params; 328 329 ASSERT(KCF_PROV_REFHELD(pd)); 330 331 /* First, allocate and initialize the canonical context */ 332 if ((ctx = kcf_new_ctx(crq, pd, sid)) == NULL) 333 return (CRYPTO_HOST_MEMORY); 334 335 /* The fast path for SW providers. */ 336 if (CHECK_FASTPATH(crq, pd)) { 337 crypto_mechanism_t lmech; 338 339 lmech = *mech; 340 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); 341 error = KCF_PROV_MAC_INIT(pd, ctx, &lmech, key, tmpl, 342 KCF_SWFP_RHNDL(crq)); 343 KCF_PROV_INCRSTATS(pd, error); 344 } else { 345 KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_INIT, sid, mech, key, 346 NULL, NULL, tmpl); 347 error = kcf_submit_request(pd, ctx, crq, ¶ms, B_FALSE); 348 } 349 350 if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED)) 351 *ctxp = (crypto_context_t)ctx; 352 else { 353 /* Release the hold done in kcf_new_ctx(). */ 354 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private); 355 } 356 357 return (error); 358 } 359 360 /* 361 * Same as crypto_mac_init_prov(), but relies on the KCF scheduler to 362 * choose a provider. See crypto_mac_init_prov() comments for more 363 * information. 364 */ 365 int 366 crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key, 367 crypto_ctx_template_t tmpl, crypto_context_t *ctxp, 368 crypto_call_req_t *crq) 369 { 370 int error; 371 kcf_mech_entry_t *me; 372 kcf_provider_desc_t *pd; 373 kcf_ctx_template_t *ctx_tmpl; 374 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; 375 kcf_prov_tried_t *list = NULL; 376 377 retry: 378 /* The pd is returned held */ 379 if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, 380 list, CRYPTO_FG_MAC, CHECK_RESTRICT(crq), 0)) == NULL) { 381 if (list != NULL) 382 kcf_free_triedlist(list); 383 return (error); 384 } 385 386 /* 387 * For SW providers, check the validity of the context template 388 * It is very rare that the generation number mis-matches, so 389 * is acceptable to fail here, and let the consumer recover by 390 * freeing this tmpl and create a new one for the key and new SW 391 * provider 392 */ 393 394 if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) && 395 ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) { 396 if (ctx_tmpl->ct_generation != me->me_gen_swprov) { 397 if (list != NULL) 398 kcf_free_triedlist(list); 399 KCF_PROV_REFRELE(pd); 400 return (CRYPTO_OLD_CTX_TEMPLATE); 401 } else { 402 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; 403 } 404 } 405 406 error = crypto_mac_init_prov(pd, pd->pd_sid, mech, key, spi_ctx_tmpl, 407 ctxp, crq); 408 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && 409 IS_RECOVERABLE(error)) { 410 /* Add pd to the linked list of providers tried. */ 411 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) 412 goto retry; 413 } 414 415 if (list != NULL) 416 kcf_free_triedlist(list); 417 418 KCF_PROV_REFRELE(pd); 419 return (error); 420 } 421 422 /* 423 * crypto_mac_update() 424 * 425 * Arguments: 426 * context: A crypto_context_t initialized by mac_init(). 427 * data: The message part to be MAC'ed 428 * cr: crypto_call_req_t calling conditions and call back info. 429 * 430 * Description: 431 * Asynchronously submits a request for, or synchronously performs a 432 * part of a MAC operation. 433 * 434 * Context: 435 * Process or interrupt, according to the semantics dictated by the 'cr'. 436 * 437 * Returns: 438 * See comment in the beginning of the file. 439 */ 440 int 441 crypto_mac_update(crypto_context_t context, crypto_data_t *data, 442 crypto_call_req_t *cr) 443 { 444 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 445 kcf_context_t *kcf_ctx; 446 kcf_provider_desc_t *pd; 447 int error; 448 kcf_req_params_t params; 449 450 451 if ((ctx == NULL) || 452 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 453 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 454 return (CRYPTO_INVALID_CONTEXT); 455 } 456 457 KCF_PROV_REFHOLD(pd); 458 459 /* The fast path for SW providers. */ 460 if (CHECK_FASTPATH(cr, pd)) { 461 error = KCF_PROV_MAC_UPDATE(pd, ctx, data, NULL); 462 KCF_PROV_INCRSTATS(pd, error); 463 } else { 464 KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_UPDATE, pd->pd_sid, 465 NULL, NULL, data, NULL, NULL); 466 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 467 } 468 469 KCF_PROV_REFRELE(pd); 470 return (error); 471 } 472 473 /* 474 * crypto_mac_final() 475 * 476 * Arguments: 477 * context: A crypto_context_t initialized by mac_init(). 478 * mac: Storage for the message authentication code. 479 * cr: crypto_call_req_t calling conditions and call back info. 480 * 481 * Description: 482 * Asynchronously submits a request for, or synchronously performs a 483 * part of a message authentication operation. 484 * 485 * Context: 486 * Process or interrupt, according to the semantics dictated by the 'cr'. 487 * 488 * Returns: 489 * See comment in the beginning of the file. 490 */ 491 int 492 crypto_mac_final(crypto_context_t context, crypto_data_t *mac, 493 crypto_call_req_t *cr) 494 { 495 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 496 kcf_context_t *kcf_ctx; 497 kcf_provider_desc_t *pd; 498 int error; 499 kcf_req_params_t params; 500 501 if ((ctx == NULL) || 502 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 503 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 504 return (CRYPTO_INVALID_CONTEXT); 505 } 506 507 KCF_PROV_REFHOLD(pd); 508 509 /* The fast path for SW providers. */ 510 if (CHECK_FASTPATH(cr, pd)) { 511 error = KCF_PROV_MAC_FINAL(pd, ctx, mac, NULL); 512 KCF_PROV_INCRSTATS(pd, error); 513 } else { 514 KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_FINAL, pd->pd_sid, NULL, 515 NULL, NULL, mac, NULL); 516 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 517 } 518 519 KCF_PROV_REFRELE(pd); 520 /* Release the hold done in kcf_new_ctx() during init step. */ 521 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx); 522 return (error); 523 } 524 525 /* 526 * See comments for crypto_mac_update() and crypto_mac_final(). 527 */ 528 int 529 crypto_mac_single(crypto_context_t context, crypto_data_t *data, 530 crypto_data_t *mac, crypto_call_req_t *cr) 531 { 532 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 533 kcf_context_t *kcf_ctx; 534 kcf_provider_desc_t *pd; 535 int error; 536 kcf_req_params_t params; 537 538 539 if ((ctx == NULL) || 540 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 541 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 542 return (CRYPTO_INVALID_CONTEXT); 543 } 544 545 KCF_PROV_REFHOLD(pd); 546 547 /* The fast path for SW providers. */ 548 if (CHECK_FASTPATH(cr, pd)) { 549 error = KCF_PROV_MAC(pd, ctx, data, mac, NULL); 550 KCF_PROV_INCRSTATS(pd, error); 551 } else { 552 KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_SINGLE, pd->pd_sid, 553 NULL, NULL, data, mac, NULL); 554 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 555 } 556 557 KCF_PROV_REFRELE(pd); 558 /* Release the hold done in kcf_new_ctx() during init step. */ 559 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx); 560 return (error); 561 } 562