xref: /illumos-gate/usr/src/uts/common/crypto/api/kcf_sign.c (revision a07094369b21309434206d9b3601d162693466fc)
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 2005 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/sysmacros.h>
33 #include <sys/crypto/common.h>
34 #include <sys/crypto/impl.h>
35 #include <sys/crypto/api.h>
36 #include <sys/crypto/spi.h>
37 #include <sys/crypto/sched_impl.h>
38 
39 #define	CRYPTO_OPS_OFFSET(f)		offsetof(crypto_ops_t, co_##f)
40 #define	CRYPTO_SIGN_OFFSET(f)		offsetof(crypto_sign_ops_t, f)
41 
42 /*
43  * Sign entry points.
44  */
45 
46 /*
47  * See comments for crypto_digest_init_prov().
48  */
49 int
50 crypto_sign_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
51     crypto_mechanism_t *mech, crypto_key_t *key, crypto_ctx_template_t tmpl,
52     crypto_context_t *ctxp, crypto_call_req_t *crq)
53 {
54 	int rv;
55 	crypto_ctx_t *ctx;
56 	kcf_req_params_t params;
57 	kcf_provider_desc_t *pd = provider;
58 	kcf_provider_desc_t *real_provider = pd;
59 
60 	ASSERT(KCF_PROV_REFHELD(pd));
61 
62 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
63 		rv = kcf_get_hardware_provider(mech->cm_type,
64 		    CRYPTO_MECH_INVALID, CRYPTO_OPS_OFFSET(sign_ops),
65 		    CRYPTO_SIGN_OFFSET(sign_init),
66 		    CHECK_RESTRICT(crq), pd, &real_provider);
67 
68 		if (rv != CRYPTO_SUCCESS)
69 			return (rv);
70 	}
71 
72 	/* Allocate and initialize the canonical context */
73 	if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
74 		if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
75 			KCF_PROV_REFRELE(real_provider);
76 		return (CRYPTO_HOST_MEMORY);
77 	}
78 
79 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_INIT, sid, mech,
80 	    key, NULL, NULL, tmpl);
81 	rv = kcf_submit_request(real_provider, ctx, crq, &params, B_FALSE);
82 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
83 		KCF_PROV_REFRELE(real_provider);
84 
85 	if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
86 		*ctxp = (crypto_context_t)ctx;
87 	else {
88 		/* Release the hold done in kcf_new_ctx(). */
89 		KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
90 	}
91 
92 	return (rv);
93 }
94 
95 int
96 crypto_sign_init(crypto_mechanism_t *mech, crypto_key_t *key,
97     crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq)
98 {
99 	int error;
100 	kcf_mech_entry_t *me;
101 	kcf_provider_desc_t *pd;
102 	kcf_prov_tried_t *list = NULL;
103 	kcf_ctx_template_t *ctx_tmpl;
104 	crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
105 
106 retry:
107 	/* The pd is returned held */
108 	if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
109 	    list, CRYPTO_FG_SIGN, CHECK_RESTRICT(crq), 0)) == NULL) {
110 		if (list != NULL)
111 			kcf_free_triedlist(list);
112 		return (error);
113 	}
114 
115 	/*
116 	 * For SW providers, check the validity of the context template
117 	 * It is very rare that the generation number mis-matches, so
118 	 * it is acceptable to fail here, and let the consumer recover by
119 	 * freeing this tmpl and create a new one for the key and new SW
120 	 * provider.
121 	 */
122 	if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
123 	    ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
124 		if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
125 			if (list != NULL)
126 				kcf_free_triedlist(list);
127 			KCF_PROV_REFRELE(pd);
128 			return (CRYPTO_OLD_CTX_TEMPLATE);
129 		} else {
130 			spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
131 		}
132 	}
133 
134 	error = crypto_sign_init_prov(pd, pd->pd_sid, mech, key, spi_ctx_tmpl,
135 	    ctxp, crq);
136 
137 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
138 	    IS_RECOVERABLE(error)) {
139 		/* Add pd to the linked list of providers tried. */
140 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
141 			goto retry;
142 	}
143 
144 	if (list != NULL)
145 		kcf_free_triedlist(list);
146 	KCF_PROV_REFRELE(pd);
147 	return (error);
148 }
149 
150 int
151 crypto_sign_single(crypto_context_t context, crypto_data_t *data,
152     crypto_data_t *signature, crypto_call_req_t *cr)
153 {
154 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
155 	kcf_context_t *kcf_ctx;
156 	kcf_provider_desc_t *pd;
157 	int error;
158 	kcf_req_params_t params;
159 
160 	if ((ctx == NULL) ||
161 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
162 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
163 		return (CRYPTO_INVALID_CONTEXT);
164 	}
165 
166 	KCF_PROV_REFHOLD(pd);
167 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_SINGLE, 0, NULL,
168 	    NULL, data, signature, NULL);
169 	error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
170 	KCF_PROV_REFRELE(pd);
171 
172 	/* Release the hold done in kcf_new_ctx() during init step. */
173 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
174 	return (error);
175 }
176 
177 /*
178  * See comments for crypto_digest_update().
179  */
180 int
181 crypto_sign_update(crypto_context_t context, crypto_data_t *data,
182     crypto_call_req_t *cr)
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_SIGN_OPS_PARAMS(&params, KCF_OP_UPDATE, ctx->cc_session, NULL,
199 	    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_sign_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 	int rv;
217 	kcf_req_params_t params;
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_SIGN_OPS_PARAMS(&params, KCF_OP_FINAL, ctx->cc_session, NULL,
228 	    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_sign_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, CRYPTO_OPS_OFFSET(sign_ops),
253 		    CRYPTO_SIGN_OFFSET(sign_atomic), CHECK_RESTRICT(crq),
254 		    pd, &real_provider);
255 
256 		if (rv != CRYPTO_SUCCESS)
257 			return (rv);
258 	}
259 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech,
260 	    key, data, signature, tmpl);
261 	rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
262 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
263 		KCF_PROV_REFRELE(real_provider);
264 
265 	return (rv);
266 }
267 
268 static int
269 sign_sr_atomic_common(crypto_mechanism_t *mech, crypto_key_t *key,
270     crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
271     crypto_call_req_t *crq, crypto_func_group_t fg)
272 {
273 	int error;
274 	kcf_mech_entry_t *me;
275 	kcf_provider_desc_t *pd;
276 	kcf_req_params_t params;
277 	kcf_prov_tried_t *list = NULL;
278 	kcf_ctx_template_t *ctx_tmpl;
279 	crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
280 
281 retry:
282 	/* The pd is returned held */
283 	if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, list, fg,
284 	    CHECK_RESTRICT(crq), data->cd_length)) == NULL) {
285 		if (list != NULL)
286 			kcf_free_triedlist(list);
287 		return (error);
288 	}
289 
290 	/*
291 	 * For SW providers, check the validity of the context template
292 	 * It is very rare that the generation number mis-matches, so
293 	 * it is acceptable to fail here, and let the consumer recover by
294 	 * freeing this tmpl and create a new one for the key and new SW
295 	 * provider.
296 	 */
297 	if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
298 	    ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
299 		if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
300 			if (list != NULL)
301 				kcf_free_triedlist(list);
302 			KCF_PROV_REFRELE(pd);
303 			return (CRYPTO_OLD_CTX_TEMPLATE);
304 		} else {
305 			spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
306 		}
307 	}
308 
309 	/* The fast path for SW providers. */
310 	if (CHECK_FASTPATH(crq, pd)) {
311 		crypto_mechanism_t lmech;
312 
313 		lmech = *mech;
314 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
315 		if (fg == CRYPTO_FG_SIGN_ATOMIC)
316 			error = KCF_PROV_SIGN_ATOMIC(pd, pd->pd_sid, &lmech,
317 			    key, data, spi_ctx_tmpl, signature,
318 			    KCF_SWFP_RHNDL(crq));
319 		else
320 			error = KCF_PROV_SIGN_RECOVER_ATOMIC(pd, pd->pd_sid,
321 			    &lmech, key, data, spi_ctx_tmpl, signature,
322 			    KCF_SWFP_RHNDL(crq));
323 		KCF_PROV_INCRSTATS(pd, error);
324 	} else {
325 		kcf_op_type_t op = ((fg == CRYPTO_FG_SIGN_ATOMIC) ?
326 		    KCF_OP_ATOMIC : KCF_OP_SIGN_RECOVER_ATOMIC);
327 
328 		KCF_WRAP_SIGN_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_sign(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 (sign_sr_atomic_common(mech, key, data, tmpl, signature, crq,
355 	    CRYPTO_FG_SIGN_ATOMIC));
356 }
357 
358 int
359 crypto_sign_recover_prov(crypto_provider_t provider, crypto_session_id_t sid,
360     crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data,
361     crypto_ctx_template_t tmpl, crypto_data_t *signature,
362     crypto_call_req_t *crq)
363 {
364 	kcf_req_params_t params;
365 	kcf_provider_desc_t *pd = provider;
366 	kcf_provider_desc_t *real_provider = pd;
367 	int rv;
368 
369 	ASSERT(KCF_PROV_REFHELD(pd));
370 
371 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
372 		rv = kcf_get_hardware_provider(mech->cm_type,
373 		    CRYPTO_MECH_INVALID, CRYPTO_OPS_OFFSET(sign_ops),
374 		    CRYPTO_SIGN_OFFSET(sign_recover_atomic),
375 		    CHECK_RESTRICT(crq), pd, &real_provider);
376 
377 		if (rv != CRYPTO_SUCCESS)
378 			return (rv);
379 	}
380 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_SIGN_RECOVER_ATOMIC, sid, mech,
381 	    key, data, signature, tmpl);
382 	rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
383 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
384 		KCF_PROV_REFRELE(real_provider);
385 
386 	return (rv);
387 }
388 
389 int
390 crypto_sign_recover(crypto_mechanism_t *mech, crypto_key_t *key,
391     crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
392     crypto_call_req_t *crq)
393 {
394 	return (sign_sr_atomic_common(mech, key, data, tmpl, signature, crq,
395 	    CRYPTO_FG_SIGN_RECOVER_ATOMIC));
396 }
397 
398 int
399 crypto_sign_recover_init_prov(crypto_provider_t provider,
400     crypto_session_id_t sid, crypto_mechanism_t *mech, crypto_key_t *key,
401     crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq)
402 {
403 	int rv;
404 	crypto_ctx_t *ctx;
405 	kcf_req_params_t params;
406 	kcf_provider_desc_t *pd = provider;
407 	kcf_provider_desc_t *real_provider = pd;
408 
409 	ASSERT(KCF_PROV_REFHELD(pd));
410 
411 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
412 		rv = kcf_get_hardware_provider(mech->cm_type,
413 		    CRYPTO_MECH_INVALID, CRYPTO_OPS_OFFSET(sign_ops),
414 		    CRYPTO_SIGN_OFFSET(sign_recover_init),
415 		    CHECK_RESTRICT(crq), pd, &real_provider);
416 
417 		if (rv != CRYPTO_SUCCESS)
418 			return (rv);
419 	}
420 
421 	/* Allocate and initialize the canonical context */
422 	if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
423 		if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
424 			KCF_PROV_REFRELE(real_provider);
425 		return (CRYPTO_HOST_MEMORY);
426 	}
427 
428 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_SIGN_RECOVER_INIT, sid, mech,
429 	    key, NULL, NULL, tmpl);
430 	rv = kcf_submit_request(real_provider, ctx, crq, &params, B_FALSE);
431 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
432 		KCF_PROV_REFRELE(real_provider);
433 
434 	if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
435 		*ctxp = (crypto_context_t)ctx;
436 	else {
437 		/* Release the hold done in kcf_new_ctx(). */
438 		KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
439 	}
440 
441 	return (rv);
442 }
443 
444 int
445 crypto_sign_recover_single(crypto_context_t context, crypto_data_t *data,
446     crypto_data_t *signature, crypto_call_req_t *cr)
447 {
448 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
449 	kcf_context_t *kcf_ctx;
450 	kcf_provider_desc_t *pd;
451 	int error;
452 	kcf_req_params_t params;
453 
454 	if ((ctx == NULL) ||
455 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
456 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
457 		return (CRYPTO_INVALID_CONTEXT);
458 	}
459 
460 	KCF_PROV_REFHOLD(pd);
461 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_SIGN_RECOVER, 0, NULL,
462 	    NULL, data, signature, NULL);
463 	error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
464 	KCF_PROV_REFRELE(pd);
465 
466 	/* Release the hold done in kcf_new_ctx() during init step. */
467 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
468 	return (error);
469 }
470