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