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 2005 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/cmn_err.h> 33 #include <sys/sysmacros.h> 34 #include <sys/crypto/common.h> 35 #include <sys/crypto/impl.h> 36 #include <sys/crypto/api.h> 37 #include <sys/crypto/spi.h> 38 #include <sys/crypto/sched_impl.h> 39 40 #define CRYPTO_OPS_OFFSET(f) offsetof(crypto_ops_t, co_##f) 41 #define CRYPTO_DIGEST_OFFSET(f) offsetof(crypto_digest_ops_t, f) 42 43 /* 44 * Message digest routines 45 */ 46 47 /* 48 * The following are the possible returned values common to all the routines 49 * below. The applicability of some of these return values depends on the 50 * presence of the arguments. 51 * 52 * CRYPTO_SUCCESS: The operation completed successfully. 53 * CRYPTO_QUEUED: A request was submitted successfully. The callback 54 * routine will be called when the operation is done. 55 * CRYPTO_MECHANISM_INVALID or CRYPTO_INVALID_MECH_PARAM 56 * for problems with the 'mech'. 57 * CRYPTO_INVALID_DATA for bogus 'data' 58 * CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work. 59 * CRYPTO_INVALID_CONTEXT: Not a valid context. 60 * CRYPTO_BUSY: Cannot process the request now. Schedule a 61 * crypto_bufcall(), or try later. 62 * CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: 63 * No provider is capable of a function or a mechanism. 64 */ 65 66 67 /* 68 * crypto_digest_prov() 69 * 70 * Arguments: 71 * pd: pointer to the descriptor of the provider to use for this 72 * operation. 73 * sid: provider session id. 74 * mech: crypto_mechanism_t pointer. 75 * mech_type is a valid value previously returned by 76 * crypto_mech2id(); 77 * When the mech's parameter is not NULL, its definition depends 78 * on the standard definition of the mechanism. 79 * data: The message to be digested. 80 * digest: Storage for the digest. The length needed depends on the 81 * mechanism. 82 * cr: crypto_call_req_t calling conditions and call back info. 83 * 84 * Description: 85 * Asynchronously submits a request for, or synchronously performs the 86 * digesting operation of 'data' on the specified 87 * provider with the specified session. 88 * When complete and successful, 'digest' will contain the digest value. 89 * The caller should hold a reference on the specified provider 90 * descriptor before calling this function. 91 * 92 * Context: 93 * Process or interrupt, according to the semantics dictated by the 'cr'. 94 * 95 * Returns: 96 * See comment in the beginning of the file. 97 */ 98 int 99 crypto_digest_prov(crypto_provider_t provider, crypto_session_id_t sid, 100 crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest, 101 crypto_call_req_t *crq) 102 { 103 kcf_req_params_t params; 104 kcf_provider_desc_t *pd = provider; 105 kcf_provider_desc_t *real_provider = pd; 106 int rv; 107 108 ASSERT(KCF_PROV_REFHELD(pd)); 109 110 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { 111 rv = kcf_get_hardware_provider(mech->cm_type, 112 CRYPTO_MECH_INVALID, CRYPTO_OPS_OFFSET(digest_ops), 113 CRYPTO_DIGEST_OFFSET(digest_atomic), CHECK_RESTRICT(crq), 114 pd, &real_provider); 115 116 if (rv != CRYPTO_SUCCESS) 117 return (rv); 118 } 119 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, NULL, 120 data, digest); 121 122 /* no crypto context to carry between multiple parts. */ 123 rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); 124 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 125 KCF_PROV_REFRELE(real_provider); 126 127 return (rv); 128 } 129 130 /* 131 * Same as crypto_digest_prov(), but relies on the KCF scheduler to 132 * choose a provider. See crypto_digest_prov() comments for more information. 133 */ 134 int 135 crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data, 136 crypto_data_t *digest, crypto_call_req_t *crq) 137 { 138 int error; 139 kcf_provider_desc_t *pd; 140 kcf_req_params_t params; 141 kcf_prov_tried_t *list = NULL; 142 143 retry: 144 /* The pd is returned held */ 145 if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, list, 146 CRYPTO_FG_DIGEST_ATOMIC, CHECK_RESTRICT(crq), 147 data->cd_length)) == NULL) { 148 if (list != NULL) 149 kcf_free_triedlist(list); 150 return (error); 151 } 152 153 /* The fast path for SW providers. */ 154 if (CHECK_FASTPATH(crq, pd)) { 155 crypto_mechanism_t lmech; 156 157 lmech = *mech; 158 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); 159 error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data, 160 digest, KCF_SWFP_RHNDL(crq)); 161 KCF_PROV_INCRSTATS(pd, error); 162 } else { 163 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, pd->pd_sid, 164 mech, NULL, data, digest); 165 166 /* no crypto context to carry between multiple parts. */ 167 error = kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE); 168 } 169 170 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && 171 IS_RECOVERABLE(error)) { 172 /* Add pd to the linked list of providers tried. */ 173 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) 174 goto retry; 175 } 176 177 if (list != NULL) 178 kcf_free_triedlist(list); 179 180 KCF_PROV_REFRELE(pd); 181 return (error); 182 } 183 184 /* 185 * crypto_digest_init_prov() 186 * 187 * pd: pointer to the descriptor of the provider to use for this 188 * operation. 189 * sid: provider session id. 190 * mech: crypto_mechanism_t pointer. 191 * mech_type is a valid value previously returned by 192 * crypto_mech2id(); 193 * When the mech's parameter is not NULL, its definition depends 194 * on the standard definition of the mechanism. 195 * ctxp: Pointer to a crypto_context_t. 196 * cr: crypto_call_req_t calling conditions and call back info. 197 * 198 * Description: 199 * Asynchronously submits a request for, or synchronously performs the 200 * initialization of a message digest operation on the specified 201 * provider with the specified session. 202 * When complete and successful, 'ctxp' will contain a crypto_context_t 203 * valid for later calls to digest_update() and digest_final(). 204 * The caller should hold a reference on the specified provider 205 * descriptor before calling this function. 206 */ 207 int 208 crypto_digest_init_prov(crypto_provider_t provider, crypto_session_id_t sid, 209 crypto_mechanism_t *mech, crypto_context_t *ctxp, crypto_call_req_t *crq) 210 { 211 int error; 212 crypto_ctx_t *ctx; 213 kcf_req_params_t params; 214 kcf_provider_desc_t *pd = provider; 215 kcf_provider_desc_t *real_provider = pd; 216 217 ASSERT(KCF_PROV_REFHELD(pd)); 218 219 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { 220 error = kcf_get_hardware_provider(mech->cm_type, 221 CRYPTO_MECH_INVALID, CRYPTO_OPS_OFFSET(digest_ops), 222 CRYPTO_DIGEST_OFFSET(digest_init), 223 CHECK_RESTRICT(crq), pd, &real_provider); 224 225 if (error != CRYPTO_SUCCESS) 226 return (error); 227 } 228 229 /* Allocate and initialize the canonical context */ 230 if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) { 231 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 232 KCF_PROV_REFRELE(real_provider); 233 return (CRYPTO_HOST_MEMORY); 234 } 235 236 /* The fast path for SW providers. */ 237 if (CHECK_FASTPATH(crq, pd)) { 238 crypto_mechanism_t lmech; 239 240 lmech = *mech; 241 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech); 242 error = KCF_PROV_DIGEST_INIT(real_provider, ctx, &lmech, 243 KCF_SWFP_RHNDL(crq)); 244 KCF_PROV_INCRSTATS(pd, error); 245 } else { 246 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_INIT, sid, 247 mech, NULL, NULL, NULL); 248 error = kcf_submit_request(real_provider, ctx, crq, ¶ms, 249 B_FALSE); 250 } 251 252 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 253 KCF_PROV_REFRELE(real_provider); 254 255 if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED)) 256 *ctxp = (crypto_context_t)ctx; 257 else { 258 /* Release the hold done in kcf_new_ctx(). */ 259 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private); 260 } 261 262 return (error); 263 } 264 265 266 /* 267 * Same as crypto_digest_init_prov(), but relies on the KCF scheduler 268 * to choose a provider. See crypto_digest_init_prov() comments for 269 * more information. 270 */ 271 int 272 crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp, 273 crypto_call_req_t *crq) 274 { 275 int error; 276 kcf_provider_desc_t *pd; 277 kcf_prov_tried_t *list = NULL; 278 279 retry: 280 /* The pd is returned held */ 281 if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, 282 list, CRYPTO_FG_DIGEST, CHECK_RESTRICT(crq), 0)) == NULL) { 283 if (list != NULL) 284 kcf_free_triedlist(list); 285 return (error); 286 } 287 288 error = crypto_digest_init_prov(pd, pd->pd_sid, mech, ctxp, crq); 289 290 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && 291 IS_RECOVERABLE(error)) { 292 /* Add pd to the linked list of providers tried. */ 293 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) 294 goto retry; 295 } 296 297 if (list != NULL) 298 kcf_free_triedlist(list); 299 KCF_PROV_REFRELE(pd); 300 return (error); 301 } 302 303 /* 304 * crypto_digest_update() 305 * 306 * Arguments: 307 * context: A crypto_context_t initialized by digest_init(). 308 * data: The part of message to be digested. 309 * cr: crypto_call_req_t calling conditions and call back info. 310 * 311 * Description: 312 * Asynchronously submits a request for, or synchronously performs a 313 * part of a message digest operation. 314 * 315 * Context: 316 * Process or interrupt, according to the semantics dictated by the 'cr'. 317 * 318 * Returns: 319 * See comment in the beginning of the file. 320 */ 321 int 322 crypto_digest_update(crypto_context_t context, crypto_data_t *data, 323 crypto_call_req_t *cr) 324 { 325 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 326 kcf_context_t *kcf_ctx; 327 kcf_provider_desc_t *pd; 328 int error; 329 kcf_req_params_t params; 330 331 if ((ctx == NULL) || 332 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 333 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 334 return (CRYPTO_INVALID_CONTEXT); 335 } 336 337 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); 338 KCF_PROV_REFHOLD(pd); 339 340 /* The fast path for SW providers. */ 341 if (CHECK_FASTPATH(cr, pd)) { 342 error = KCF_PROV_DIGEST_UPDATE(pd, ctx, data, NULL); 343 KCF_PROV_INCRSTATS(pd, error); 344 } else { 345 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_UPDATE, 346 ctx->cc_session, NULL, NULL, data, NULL); 347 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 348 } 349 350 KCF_PROV_REFRELE(pd); 351 return (error); 352 } 353 354 /* 355 * crypto_digest_final() 356 * 357 * Arguments: 358 * context: A crypto_context_t initialized by digest_init(). 359 * digest: The storage for the digest. 360 * cr: crypto_call_req_t calling conditions and call back info. 361 * 362 * Description: 363 * Asynchronously submits a request for, or synchronously performs the 364 * final part of a message digest operation. 365 * 366 * Context: 367 * Process or interrupt, according to the semantics dictated by the 'cr'. 368 * 369 * Returns: 370 * See comment in the beginning of the file. 371 */ 372 int 373 crypto_digest_final(crypto_context_t context, crypto_data_t *digest, 374 crypto_call_req_t *cr) 375 { 376 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 377 kcf_context_t *kcf_ctx; 378 kcf_provider_desc_t *pd; 379 int error; 380 kcf_req_params_t params; 381 382 if ((ctx == NULL) || 383 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 384 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 385 return (CRYPTO_INVALID_CONTEXT); 386 } 387 388 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); 389 KCF_PROV_REFHOLD(pd); 390 391 /* The fast path for SW providers. */ 392 if (CHECK_FASTPATH(cr, pd)) { 393 error = KCF_PROV_DIGEST_FINAL(pd, ctx, digest, NULL); 394 KCF_PROV_INCRSTATS(pd, error); 395 } else { 396 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_FINAL, 397 ctx->cc_session, NULL, NULL, NULL, digest); 398 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 399 } 400 401 KCF_PROV_REFRELE(pd); 402 /* Release the hold done in kcf_new_ctx() during init step. */ 403 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx); 404 return (error); 405 } 406 407 /* 408 * Performs a digest update on the specified key. Note that there is 409 * no k-API crypto_digest_key() equivalent of this function. 410 */ 411 int 412 crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key, 413 crypto_call_req_t *cr) 414 { 415 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 416 kcf_context_t *kcf_ctx; 417 kcf_provider_desc_t *pd; 418 int error; 419 kcf_req_params_t params; 420 421 if ((ctx == NULL) || 422 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 423 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 424 return (CRYPTO_INVALID_CONTEXT); 425 } 426 427 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); 428 KCF_PROV_REFHOLD(pd); 429 430 /* The fast path for SW providers. */ 431 if (CHECK_FASTPATH(cr, pd)) { 432 error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL); 433 KCF_PROV_INCRSTATS(pd, error); 434 } else { 435 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_DIGEST_KEY, 436 ctx->cc_session, NULL, key, NULL, NULL); 437 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 438 } 439 KCF_PROV_REFRELE(pd); 440 441 return (error); 442 } 443 444 /* 445 * See comments for crypto_digest_update() and crypto_digest_final(). 446 */ 447 int 448 crypto_digest_single(crypto_context_t context, crypto_data_t *data, 449 crypto_data_t *digest, crypto_call_req_t *cr) 450 { 451 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 452 kcf_context_t *kcf_ctx; 453 kcf_provider_desc_t *pd; 454 int error; 455 kcf_req_params_t params; 456 457 if ((ctx == NULL) || 458 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 459 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 460 return (CRYPTO_INVALID_CONTEXT); 461 } 462 463 KCF_PROV_REFHOLD(pd); 464 465 /* The fast path for SW providers. */ 466 if (CHECK_FASTPATH(cr, pd)) { 467 error = KCF_PROV_DIGEST(pd, ctx, data, digest, NULL); 468 KCF_PROV_INCRSTATS(pd, error); 469 } else { 470 KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_SINGLE, pd->pd_sid, 471 NULL, NULL, data, digest); 472 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 473 } 474 475 KCF_PROV_REFRELE(pd); 476 /* Release the hold done in kcf_new_ctx() during init step. */ 477 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx); 478 return (error); 479 } 480