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(&params, KCF_OP_INIT, sid, mech,
59 	    key, NULL, NULL, tmpl);
60 
61 	error = kcf_submit_request(pd, ctx, crq, &params, 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(&params, KCF_OP_SINGLE, 0, NULL,
146 	    NULL, data, signature, NULL);
147 	error = kcf_submit_request(pd, ctx, cr, &params, 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(&params, KCF_OP_UPDATE, 0, NULL,
177 	    NULL, data, NULL, NULL);
178 	error = kcf_submit_request(pd, ctx, cr, &params, 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(&params, KCF_OP_FINAL, 0, NULL,
205 	    NULL, NULL, signature, NULL);
206 	error = kcf_submit_request(pd, ctx, cr, &params, 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(&params, KCF_OP_ATOMIC, sid, mech,
224 	    key, data, signature, tmpl);
225 
226 	return (kcf_submit_request(pd, NULL, crq, &params, 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(&params, 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, &params, 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(&params, KCF_OP_VERIFY_RECOVER_ATOMIC,
330 	    sid, mech, key, data, signature, tmpl);
331 
332 	return (kcf_submit_request(pd, NULL, crq, &params, 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(&params, KCF_OP_VERIFY_RECOVER_INIT,
358 	    sid, mech, key, NULL, NULL, tmpl);
359 
360 	error = kcf_submit_request(pd, ctx, crq, &params, 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(&params, KCF_OP_VERIFY_RECOVER, 0, NULL,
389 	    NULL, data, signature, NULL);
390 	error = kcf_submit_request(pd, ctx, cr, &params, 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