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/sysmacros.h> 30 #include <sys/crypto/common.h> 31 #include <sys/crypto/impl.h> 32 #include <sys/crypto/api.h> 33 #include <sys/crypto/spi.h> 34 #include <sys/crypto/sched_impl.h> 35 36 #define CRYPTO_OPS_OFFSET(f) offsetof(crypto_ops_t, co_##f) 37 #define CRYPTO_SIGN_OFFSET(f) offsetof(crypto_sign_ops_t, f) 38 39 /* 40 * Sign entry points. 41 */ 42 43 /* 44 * See comments for crypto_digest_init_prov(). 45 */ 46 int 47 crypto_sign_init_prov(crypto_provider_t provider, crypto_session_id_t sid, 48 crypto_mechanism_t *mech, crypto_key_t *key, crypto_ctx_template_t tmpl, 49 crypto_context_t *ctxp, crypto_call_req_t *crq) 50 { 51 int rv; 52 crypto_ctx_t *ctx; 53 kcf_req_params_t params; 54 kcf_provider_desc_t *pd = provider; 55 kcf_provider_desc_t *real_provider = pd; 56 57 ASSERT(KCF_PROV_REFHELD(pd)); 58 59 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { 60 rv = kcf_get_hardware_provider(mech->cm_type, key, 61 CRYPTO_MECH_INVALID, NULL, CHECK_RESTRICT(crq), pd, 62 &real_provider, CRYPTO_FG_SIGN); 63 64 if (rv != CRYPTO_SUCCESS) 65 return (rv); 66 } 67 68 /* Allocate and initialize the canonical context */ 69 if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) { 70 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 71 KCF_PROV_REFRELE(real_provider); 72 return (CRYPTO_HOST_MEMORY); 73 } 74 75 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_INIT, sid, mech, 76 key, NULL, NULL, tmpl); 77 rv = kcf_submit_request(real_provider, ctx, crq, ¶ms, B_FALSE); 78 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 79 KCF_PROV_REFRELE(real_provider); 80 81 if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED)) 82 *ctxp = (crypto_context_t)ctx; 83 else { 84 /* Release the hold done in kcf_new_ctx(). */ 85 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private); 86 } 87 88 return (rv); 89 } 90 91 int 92 crypto_sign_init(crypto_mechanism_t *mech, crypto_key_t *key, 93 crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq) 94 { 95 int error; 96 kcf_mech_entry_t *me; 97 kcf_provider_desc_t *pd; 98 kcf_prov_tried_t *list = NULL; 99 kcf_ctx_template_t *ctx_tmpl; 100 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; 101 102 retry: 103 /* The pd is returned held */ 104 if ((pd = kcf_get_mech_provider(mech->cm_type, key, &me, &error, 105 list, CRYPTO_FG_SIGN, CHECK_RESTRICT(crq), 0)) == NULL) { 106 if (list != NULL) 107 kcf_free_triedlist(list); 108 return (error); 109 } 110 111 /* 112 * For SW providers, check the validity of the context template 113 * It is very rare that the generation number mis-matches, so 114 * it is acceptable to fail here, and let the consumer recover by 115 * freeing this tmpl and create a new one for the key and new SW 116 * provider. 117 */ 118 if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) && 119 ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) { 120 if (ctx_tmpl->ct_generation != me->me_gen_swprov) { 121 if (list != NULL) 122 kcf_free_triedlist(list); 123 KCF_PROV_REFRELE(pd); 124 return (CRYPTO_OLD_CTX_TEMPLATE); 125 } else { 126 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; 127 } 128 } 129 130 error = crypto_sign_init_prov(pd, pd->pd_sid, mech, key, spi_ctx_tmpl, 131 ctxp, crq); 132 133 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && 134 IS_RECOVERABLE(error)) { 135 /* Add pd to the linked list of providers tried. */ 136 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) 137 goto retry; 138 } 139 140 if (list != NULL) 141 kcf_free_triedlist(list); 142 KCF_PROV_REFRELE(pd); 143 return (error); 144 } 145 146 int 147 crypto_sign_single(crypto_context_t context, crypto_data_t *data, 148 crypto_data_t *signature, crypto_call_req_t *cr) 149 { 150 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 151 kcf_context_t *kcf_ctx; 152 kcf_provider_desc_t *pd; 153 int error; 154 kcf_req_params_t params; 155 156 if ((ctx == NULL) || 157 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 158 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 159 return (CRYPTO_INVALID_CONTEXT); 160 } 161 162 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SINGLE, 0, NULL, 163 NULL, data, signature, NULL); 164 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 165 166 /* Release the hold done in kcf_new_ctx() during init step. */ 167 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx); 168 return (error); 169 } 170 171 /* 172 * See comments for crypto_digest_update(). 173 */ 174 int 175 crypto_sign_update(crypto_context_t context, crypto_data_t *data, 176 crypto_call_req_t *cr) 177 { 178 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 179 kcf_context_t *kcf_ctx; 180 kcf_provider_desc_t *pd; 181 kcf_req_params_t params; 182 int rv; 183 184 if ((ctx == NULL) || 185 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 186 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 187 return (CRYPTO_INVALID_CONTEXT); 188 } 189 190 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); 191 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_UPDATE, ctx->cc_session, NULL, 192 NULL, data, NULL, NULL); 193 rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 194 195 return (rv); 196 } 197 198 /* 199 * See comments for crypto_digest_final(). 200 */ 201 int 202 crypto_sign_final(crypto_context_t context, crypto_data_t *signature, 203 crypto_call_req_t *cr) 204 { 205 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 206 kcf_context_t *kcf_ctx; 207 kcf_provider_desc_t *pd; 208 int rv; 209 kcf_req_params_t params; 210 211 if ((ctx == NULL) || 212 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 213 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 214 return (CRYPTO_INVALID_CONTEXT); 215 } 216 217 ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER); 218 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_FINAL, ctx->cc_session, NULL, 219 NULL, NULL, signature, NULL); 220 rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 221 222 /* Release the hold done in kcf_new_ctx() during init step. */ 223 KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx); 224 return (rv); 225 } 226 227 int 228 crypto_sign_prov(crypto_provider_t provider, crypto_session_id_t sid, 229 crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data, 230 crypto_ctx_template_t tmpl, crypto_data_t *signature, 231 crypto_call_req_t *crq) 232 { 233 kcf_req_params_t params; 234 kcf_provider_desc_t *pd = provider; 235 kcf_provider_desc_t *real_provider = pd; 236 int rv; 237 238 ASSERT(KCF_PROV_REFHELD(pd)); 239 240 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { 241 rv = kcf_get_hardware_provider(mech->cm_type, key, 242 CRYPTO_MECH_INVALID, NULL, CHECK_RESTRICT(crq), 243 pd, &real_provider, CRYPTO_FG_SIGN_ATOMIC); 244 245 if (rv != CRYPTO_SUCCESS) 246 return (rv); 247 } 248 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, 249 key, data, signature, tmpl); 250 rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); 251 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 252 KCF_PROV_REFRELE(real_provider); 253 254 return (rv); 255 } 256 257 static int 258 sign_sr_atomic_common(crypto_mechanism_t *mech, crypto_key_t *key, 259 crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature, 260 crypto_call_req_t *crq, crypto_func_group_t fg) 261 { 262 int error; 263 kcf_mech_entry_t *me; 264 kcf_provider_desc_t *pd; 265 kcf_req_params_t params; 266 kcf_prov_tried_t *list = NULL; 267 kcf_ctx_template_t *ctx_tmpl; 268 crypto_spi_ctx_template_t spi_ctx_tmpl = NULL; 269 270 retry: 271 /* The pd is returned held */ 272 if ((pd = kcf_get_mech_provider(mech->cm_type, key, &me, &error, 273 list, fg, CHECK_RESTRICT(crq), data->cd_length)) == NULL) { 274 if (list != NULL) 275 kcf_free_triedlist(list); 276 return (error); 277 } 278 279 /* 280 * For SW providers, check the validity of the context template 281 * It is very rare that the generation number mis-matches, so 282 * it is acceptable to fail here, and let the consumer recover by 283 * freeing this tmpl and create a new one for the key and new SW 284 * provider. 285 */ 286 if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) && 287 ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) { 288 if (ctx_tmpl->ct_generation != me->me_gen_swprov) { 289 if (list != NULL) 290 kcf_free_triedlist(list); 291 KCF_PROV_REFRELE(pd); 292 return (CRYPTO_OLD_CTX_TEMPLATE); 293 } else { 294 spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl; 295 } 296 } 297 298 /* The fast path for SW providers. */ 299 if (CHECK_FASTPATH(crq, pd)) { 300 crypto_mechanism_t lmech; 301 302 lmech = *mech; 303 KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech); 304 if (fg == CRYPTO_FG_SIGN_ATOMIC) 305 error = KCF_PROV_SIGN_ATOMIC(pd, pd->pd_sid, &lmech, 306 key, data, spi_ctx_tmpl, signature, 307 KCF_SWFP_RHNDL(crq)); 308 else 309 error = KCF_PROV_SIGN_RECOVER_ATOMIC(pd, pd->pd_sid, 310 &lmech, key, data, spi_ctx_tmpl, signature, 311 KCF_SWFP_RHNDL(crq)); 312 KCF_PROV_INCRSTATS(pd, error); 313 } else { 314 kcf_op_type_t op = ((fg == CRYPTO_FG_SIGN_ATOMIC) ? 315 KCF_OP_ATOMIC : KCF_OP_SIGN_RECOVER_ATOMIC); 316 317 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, op, pd->pd_sid, 318 mech, key, data, signature, spi_ctx_tmpl); 319 320 /* no crypto context to carry between multiple parts. */ 321 error = kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE); 322 } 323 324 if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED && 325 IS_RECOVERABLE(error)) { 326 /* Add pd to the linked list of providers tried. */ 327 if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL) 328 goto retry; 329 } 330 331 if (list != NULL) 332 kcf_free_triedlist(list); 333 334 KCF_PROV_REFRELE(pd); 335 return (error); 336 } 337 338 int 339 crypto_sign(crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data, 340 crypto_ctx_template_t tmpl, crypto_data_t *signature, 341 crypto_call_req_t *crq) 342 { 343 return (sign_sr_atomic_common(mech, key, data, tmpl, signature, crq, 344 CRYPTO_FG_SIGN_ATOMIC)); 345 } 346 347 int 348 crypto_sign_recover_prov(crypto_provider_t provider, crypto_session_id_t sid, 349 crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data, 350 crypto_ctx_template_t tmpl, crypto_data_t *signature, 351 crypto_call_req_t *crq) 352 { 353 kcf_req_params_t params; 354 kcf_provider_desc_t *pd = provider; 355 kcf_provider_desc_t *real_provider = pd; 356 int rv; 357 358 ASSERT(KCF_PROV_REFHELD(pd)); 359 360 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { 361 rv = kcf_get_hardware_provider(mech->cm_type, key, 362 CRYPTO_MECH_INVALID, NULL, CHECK_RESTRICT(crq), pd, 363 &real_provider, CRYPTO_FG_SIGN_RECOVER_ATOMIC); 364 365 if (rv != CRYPTO_SUCCESS) 366 return (rv); 367 } 368 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SIGN_RECOVER_ATOMIC, sid, mech, 369 key, data, signature, tmpl); 370 rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE); 371 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 372 KCF_PROV_REFRELE(real_provider); 373 374 return (rv); 375 } 376 377 int 378 crypto_sign_recover(crypto_mechanism_t *mech, crypto_key_t *key, 379 crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature, 380 crypto_call_req_t *crq) 381 { 382 return (sign_sr_atomic_common(mech, key, data, tmpl, signature, crq, 383 CRYPTO_FG_SIGN_RECOVER_ATOMIC)); 384 } 385 386 int 387 crypto_sign_recover_init_prov(crypto_provider_t provider, 388 crypto_session_id_t sid, crypto_mechanism_t *mech, crypto_key_t *key, 389 crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq) 390 { 391 int rv; 392 crypto_ctx_t *ctx; 393 kcf_req_params_t params; 394 kcf_provider_desc_t *pd = provider; 395 kcf_provider_desc_t *real_provider = pd; 396 397 ASSERT(KCF_PROV_REFHELD(pd)); 398 399 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) { 400 rv = kcf_get_hardware_provider(mech->cm_type, key, 401 CRYPTO_MECH_INVALID, NULL, CHECK_RESTRICT(crq), pd, 402 &real_provider, CRYPTO_FG_SIGN_RECOVER); 403 404 if (rv != CRYPTO_SUCCESS) 405 return (rv); 406 } 407 408 /* Allocate and initialize the canonical context */ 409 if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) { 410 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 411 KCF_PROV_REFRELE(real_provider); 412 return (CRYPTO_HOST_MEMORY); 413 } 414 415 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SIGN_RECOVER_INIT, sid, mech, 416 key, NULL, NULL, tmpl); 417 rv = kcf_submit_request(real_provider, ctx, crq, ¶ms, B_FALSE); 418 if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) 419 KCF_PROV_REFRELE(real_provider); 420 421 if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED)) 422 *ctxp = (crypto_context_t)ctx; 423 else { 424 /* Release the hold done in kcf_new_ctx(). */ 425 KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private); 426 } 427 428 return (rv); 429 } 430 431 int 432 crypto_sign_recover_single(crypto_context_t context, crypto_data_t *data, 433 crypto_data_t *signature, crypto_call_req_t *cr) 434 { 435 crypto_ctx_t *ctx = (crypto_ctx_t *)context; 436 kcf_context_t *kcf_ctx; 437 kcf_provider_desc_t *pd; 438 int error; 439 kcf_req_params_t params; 440 441 if ((ctx == NULL) || 442 ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) || 443 ((pd = kcf_ctx->kc_prov_desc) == NULL)) { 444 return (CRYPTO_INVALID_CONTEXT); 445 } 446 447 KCF_WRAP_SIGN_OPS_PARAMS(¶ms, KCF_OP_SIGN_RECOVER, 0, NULL, 448 NULL, data, signature, NULL); 449 error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE); 450 451 /* Release the hold done in kcf_new_ctx() during init step. */ 452 KCF_CONTEXT_COND_RELEASE(error, kcf_ctx); 453 return (error); 454 } 455