xref: /illumos-gate/usr/src/uts/common/crypto/api/kcf_verify.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2007 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_WRAP_VERIFY_OPS_PARAMS(&params, KCF_OP_SINGLE, 0, NULL,
166 	    NULL, data, signature, NULL);
167 	error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
168 
169 	/* Release the hold done in kcf_new_ctx() during init step. */
170 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
171 	return (error);
172 }
173 
174 /*
175  * See comments for crypto_digest_update().
176  */
177 int
178 crypto_verify_update(crypto_context_t context, crypto_data_t *data,
179     crypto_call_req_t *cr)
180 
181 {
182 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
183 	kcf_context_t *kcf_ctx;
184 	kcf_provider_desc_t *pd;
185 	kcf_req_params_t params;
186 	int rv;
187 
188 	if ((ctx == NULL) ||
189 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
190 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
191 		return (CRYPTO_INVALID_CONTEXT);
192 	}
193 
194 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
195 	KCF_WRAP_VERIFY_OPS_PARAMS(&params, KCF_OP_UPDATE, ctx->cc_session,
196 	    NULL, NULL, data, NULL, NULL);
197 	rv = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
198 
199 	return (rv);
200 }
201 
202 /*
203  * See comments for crypto_digest_final().
204  */
205 int
206 crypto_verify_final(crypto_context_t context, crypto_data_t *signature,
207     crypto_call_req_t *cr)
208 {
209 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
210 	kcf_context_t *kcf_ctx;
211 	kcf_provider_desc_t *pd;
212 	kcf_req_params_t params;
213 	int rv;
214 
215 	if ((ctx == NULL) ||
216 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
217 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
218 		return (CRYPTO_INVALID_CONTEXT);
219 	}
220 
221 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
222 	KCF_WRAP_VERIFY_OPS_PARAMS(&params, KCF_OP_FINAL, ctx->cc_session,
223 	    NULL, NULL, NULL, signature, NULL);
224 	rv = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
225 
226 	/* Release the hold done in kcf_new_ctx() during init step. */
227 	KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx);
228 	return (rv);
229 }
230 
231 int
232 crypto_verify_prov(crypto_provider_t provider, crypto_session_id_t sid,
233     crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data,
234     crypto_ctx_template_t tmpl, crypto_data_t *signature,
235     crypto_call_req_t *crq)
236 {
237 	kcf_req_params_t params;
238 	kcf_provider_desc_t *pd = provider;
239 	kcf_provider_desc_t *real_provider = pd;
240 	int rv;
241 
242 	ASSERT(KCF_PROV_REFHELD(pd));
243 
244 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
245 		rv = kcf_get_hardware_provider(mech->cm_type,
246 		    CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq),
247 		    pd, &real_provider, CRYPTO_FG_VERIFY_ATOMIC);
248 
249 		if (rv != CRYPTO_SUCCESS)
250 			return (rv);
251 	}
252 	KCF_WRAP_VERIFY_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech,
253 	    key, data, signature, tmpl);
254 	rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
255 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
256 		KCF_PROV_REFRELE(real_provider);
257 
258 	return (rv);
259 }
260 
261 static int
262 verify_vr_atomic_common(crypto_mechanism_t *mech, crypto_key_t *key,
263     crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
264     crypto_call_req_t *crq, crypto_func_group_t fg)
265 {
266 	int error;
267 	kcf_mech_entry_t *me;
268 	kcf_provider_desc_t *pd;
269 	kcf_req_params_t params;
270 	kcf_prov_tried_t *list = NULL;
271 	kcf_ctx_template_t *ctx_tmpl;
272 	crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
273 
274 retry:
275 	/* The pd is returned held */
276 	if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, list, fg,
277 	    CHECK_RESTRICT(crq), data->cd_length)) == NULL) {
278 		if (list != NULL)
279 			kcf_free_triedlist(list);
280 		return (error);
281 	}
282 
283 	/*
284 	 * For SW providers, check the validity of the context template
285 	 * It is very rare that the generation number mis-matches, so
286 	 * it is acceptable to fail here, and let the consumer recover by
287 	 * freeing this tmpl and create a new one for the key and new SW
288 	 * provider.
289 	 */
290 	if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
291 	    ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
292 		if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
293 			if (list != NULL)
294 				kcf_free_triedlist(list);
295 			KCF_PROV_REFRELE(pd);
296 			return (CRYPTO_OLD_CTX_TEMPLATE);
297 		} else {
298 			spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
299 		}
300 	}
301 
302 	/* The fast path for SW providers. */
303 	if (CHECK_FASTPATH(crq, pd)) {
304 		crypto_mechanism_t lmech;
305 
306 		lmech = *mech;
307 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
308 		if (fg == CRYPTO_FG_VERIFY_ATOMIC)
309 			error = KCF_PROV_VERIFY_ATOMIC(pd, pd->pd_sid, &lmech,
310 			    key, data, spi_ctx_tmpl, signature,
311 			    KCF_SWFP_RHNDL(crq));
312 		else
313 			/* Note: The argument order is different from above */
314 			error = KCF_PROV_VERIFY_RECOVER_ATOMIC(pd, pd->pd_sid,
315 			    &lmech, key, signature, spi_ctx_tmpl, data,
316 			    KCF_SWFP_RHNDL(crq));
317 		KCF_PROV_INCRSTATS(pd, error);
318 	} else {
319 		kcf_op_type_t op = ((fg == CRYPTO_FG_VERIFY_ATOMIC) ?
320 		    KCF_OP_ATOMIC : KCF_OP_VERIFY_RECOVER_ATOMIC);
321 
322 		KCF_WRAP_VERIFY_OPS_PARAMS(&params, op, pd->pd_sid,
323 		    mech, key, data, signature, spi_ctx_tmpl);
324 
325 		/* no crypto context to carry between multiple parts. */
326 		error = kcf_submit_request(pd, NULL, crq, &params, B_FALSE);
327 	}
328 
329 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
330 	    IS_RECOVERABLE(error)) {
331 		/* Add pd to the linked list of providers tried. */
332 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
333 			goto retry;
334 	}
335 
336 	if (list != NULL)
337 		kcf_free_triedlist(list);
338 
339 	KCF_PROV_REFRELE(pd);
340 	return (error);
341 }
342 
343 int
344 crypto_verify(crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data,
345     crypto_ctx_template_t tmpl, crypto_data_t *signature,
346     crypto_call_req_t *crq)
347 {
348 	return (verify_vr_atomic_common(mech, key, data, tmpl, signature, crq,
349 	    CRYPTO_FG_VERIFY_ATOMIC));
350 }
351 
352 int
353 crypto_verify_recover_prov(crypto_provider_t provider, crypto_session_id_t sid,
354     crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *signature,
355     crypto_ctx_template_t tmpl, crypto_data_t *data, crypto_call_req_t *crq)
356 {
357 	kcf_req_params_t params;
358 	kcf_provider_desc_t *pd = provider;
359 	kcf_provider_desc_t *real_provider = pd;
360 	int rv;
361 
362 	ASSERT(KCF_PROV_REFHELD(pd));
363 
364 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
365 		rv = kcf_get_hardware_provider(mech->cm_type,
366 		    CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
367 		    &real_provider, CRYPTO_FG_VERIFY_RECOVER_ATOMIC);
368 
369 		if (rv != CRYPTO_SUCCESS)
370 			return (rv);
371 	}
372 	KCF_WRAP_VERIFY_OPS_PARAMS(&params, KCF_OP_VERIFY_RECOVER_ATOMIC,
373 	    sid, mech, key, data, signature, tmpl);
374 	rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
375 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
376 		KCF_PROV_REFRELE(real_provider);
377 
378 	return (rv);
379 }
380 
381 int
382 crypto_verify_recover(crypto_mechanism_t *mech, crypto_key_t *key,
383     crypto_data_t *signature, crypto_ctx_template_t tmpl, crypto_data_t *data,
384     crypto_call_req_t *crq)
385 {
386 	return (verify_vr_atomic_common(mech, key, data, tmpl, signature, crq,
387 	    CRYPTO_FG_VERIFY_RECOVER_ATOMIC));
388 }
389 
390 int
391 crypto_verify_recover_init_prov(crypto_provider_t provider,
392     crypto_session_id_t sid, crypto_mechanism_t *mech, crypto_key_t *key,
393     crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq)
394 {
395 	int rv;
396 	crypto_ctx_t *ctx;
397 	kcf_req_params_t params;
398 	kcf_provider_desc_t *pd = provider;
399 	kcf_provider_desc_t *real_provider = pd;
400 
401 	ASSERT(KCF_PROV_REFHELD(pd));
402 
403 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
404 		rv = kcf_get_hardware_provider(mech->cm_type,
405 		    CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
406 		    &real_provider, CRYPTO_FG_VERIFY_RECOVER);
407 
408 		if (rv != CRYPTO_SUCCESS)
409 			return (rv);
410 	}
411 
412 	/* Allocate and initialize the canonical context */
413 	if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
414 		if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
415 			KCF_PROV_REFRELE(real_provider);
416 		return (CRYPTO_HOST_MEMORY);
417 	}
418 
419 	KCF_WRAP_VERIFY_OPS_PARAMS(&params, KCF_OP_VERIFY_RECOVER_INIT,
420 	    sid, mech, key, NULL, NULL, tmpl);
421 	rv = kcf_submit_request(real_provider, ctx, crq, &params, B_FALSE);
422 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
423 		KCF_PROV_REFRELE(real_provider);
424 
425 	if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
426 		*ctxp = (crypto_context_t)ctx;
427 	else {
428 		/* Release the hold done in kcf_new_ctx(). */
429 		KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
430 	}
431 
432 	return (rv);
433 }
434 
435 int
436 crypto_verify_recover_single(crypto_context_t context, crypto_data_t *signature,
437     crypto_data_t *data, crypto_call_req_t *cr)
438 {
439 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
440 	kcf_context_t *kcf_ctx;
441 	kcf_provider_desc_t *pd;
442 	int error;
443 	kcf_req_params_t params;
444 
445 	if ((ctx == NULL) ||
446 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
447 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
448 		return (CRYPTO_INVALID_CONTEXT);
449 	}
450 
451 	KCF_WRAP_VERIFY_OPS_PARAMS(&params, KCF_OP_VERIFY_RECOVER, 0, NULL,
452 	    NULL, data, signature, NULL);
453 	error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
454 
455 	/* Release the hold done in kcf_new_ctx() during init step. */
456 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
457 	return (error);
458 }
459