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