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