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