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