xref: /titanic_44/usr/src/uts/common/crypto/api/kcf_sign.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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/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  * Sign entry points.
40  */
41 
42 /*
43  * See comments for crypto_digest_init_prov().
44  */
45 int
46 crypto_sign_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_SIGN_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 int
73 crypto_sign_init(crypto_mechanism_t *mech, crypto_key_t *key,
74     crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *crq)
75 {
76 	int error;
77 	kcf_mech_entry_t *me;
78 	kcf_provider_desc_t *pd;
79 	kcf_prov_tried_t *list = NULL;
80 	kcf_ctx_template_t *ctx_tmpl;
81 	crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
82 
83 retry:
84 	/* The pd is returned held */
85 	if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
86 	    list, CRYPTO_FG_SIGN, CHECK_RESTRICT(crq), 0)) == NULL) {
87 		if (list != NULL)
88 			kcf_free_triedlist(list);
89 		return (error);
90 	}
91 
92 	/*
93 	 * For SW providers, check the validity of the context template
94 	 * It is very rare that the generation number mis-matches, so
95 	 * it is acceptable to fail here, and let the consumer recover by
96 	 * freeing this tmpl and create a new one for the key and new SW
97 	 * provider.
98 	 */
99 	if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
100 	    ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
101 		if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
102 			if (list != NULL)
103 				kcf_free_triedlist(list);
104 			KCF_PROV_REFRELE(pd);
105 			return (CRYPTO_OLD_CTX_TEMPLATE);
106 		} else {
107 			spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
108 		}
109 	}
110 
111 	error = crypto_sign_init_prov(pd, pd->pd_sid, mech, key, spi_ctx_tmpl,
112 	    ctxp, crq);
113 
114 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
115 	    IS_RECOVERABLE(error)) {
116 		/* Add pd to the linked list of providers tried. */
117 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
118 			goto retry;
119 	}
120 
121 	if (list != NULL)
122 		kcf_free_triedlist(list);
123 	KCF_PROV_REFRELE(pd);
124 	return (error);
125 }
126 
127 int
128 crypto_sign_single(crypto_context_t context, crypto_data_t *data,
129     crypto_data_t *signature, crypto_call_req_t *cr)
130 {
131 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
132 	kcf_context_t *kcf_ctx;
133 	kcf_provider_desc_t *pd;
134 	int error;
135 	kcf_req_params_t params;
136 
137 	if ((ctx == NULL) ||
138 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
139 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
140 		return (CRYPTO_INVALID_CONTEXT);
141 	}
142 
143 	KCF_PROV_REFHOLD(pd);
144 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_SINGLE, 0, NULL,
145 	    NULL, data, signature, NULL);
146 	error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
147 	KCF_PROV_REFRELE(pd);
148 
149 	/* Release the hold done in kcf_new_ctx() during init step. */
150 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
151 	return (error);
152 }
153 
154 /*
155  * See comments for crypto_digest_update().
156  */
157 int
158 crypto_sign_update(crypto_context_t context, crypto_data_t *data,
159     crypto_call_req_t *cr)
160 {
161 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
162 	kcf_context_t *kcf_ctx;
163 	kcf_provider_desc_t *pd;
164 	int error;
165 	kcf_req_params_t params;
166 
167 	if ((ctx == NULL) ||
168 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
169 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
170 		return (CRYPTO_INVALID_CONTEXT);
171 	}
172 
173 	KCF_PROV_REFHOLD(pd);
174 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_UPDATE, 0, NULL,
175 	    NULL, data, NULL, NULL);
176 	error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
177 	KCF_PROV_REFRELE(pd);
178 
179 	return (error);
180 }
181 
182 /*
183  * See comments for crypto_digest_final().
184  */
185 int
186 crypto_sign_final(crypto_context_t context, crypto_data_t *signature,
187     crypto_call_req_t *cr)
188 {
189 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
190 	kcf_context_t *kcf_ctx;
191 	kcf_provider_desc_t *pd;
192 	int error;
193 	kcf_req_params_t params;
194 
195 	if ((ctx == NULL) ||
196 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
197 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
198 		return (CRYPTO_INVALID_CONTEXT);
199 	}
200 
201 	KCF_PROV_REFHOLD(pd);
202 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_FINAL, 0, NULL,
203 	    NULL, NULL, signature, NULL);
204 	error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
205 	KCF_PROV_REFRELE(pd);
206 
207 	/* Release the hold done in kcf_new_ctx() during init step. */
208 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
209 	return (error);
210 }
211 
212 int
213 crypto_sign_prov(kcf_provider_desc_t *pd, crypto_session_id_t sid,
214     crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data,
215     crypto_ctx_template_t tmpl, crypto_data_t *signature,
216     crypto_call_req_t *crq)
217 {
218 	kcf_req_params_t params;
219 
220 	ASSERT(KCF_PROV_REFHELD(pd));
221 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech,
222 	    key, data, signature, tmpl);
223 
224 	return (kcf_submit_request(pd, NULL, crq, &params, B_FALSE));
225 }
226 
227 static int
228 sign_sr_atomic_common(crypto_mechanism_t *mech, crypto_key_t *key,
229     crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
230     crypto_call_req_t *crq, crypto_func_group_t fg)
231 {
232 	int error;
233 	kcf_mech_entry_t *me;
234 	kcf_provider_desc_t *pd;
235 	kcf_req_params_t params;
236 	kcf_prov_tried_t *list = NULL;
237 	kcf_ctx_template_t *ctx_tmpl;
238 	crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
239 
240 retry:
241 	/* The pd is returned held */
242 	if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error, list, fg,
243 	    CHECK_RESTRICT(crq), data->cd_length)) == NULL) {
244 		if (list != NULL)
245 			kcf_free_triedlist(list);
246 		return (error);
247 	}
248 
249 	/*
250 	 * For SW providers, check the validity of the context template
251 	 * It is very rare that the generation number mis-matches, so
252 	 * it is acceptable to fail here, and let the consumer recover by
253 	 * freeing this tmpl and create a new one for the key and new SW
254 	 * provider.
255 	 */
256 	if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
257 	    ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
258 		if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
259 			if (list != NULL)
260 				kcf_free_triedlist(list);
261 			KCF_PROV_REFRELE(pd);
262 			return (CRYPTO_OLD_CTX_TEMPLATE);
263 		} else {
264 			spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
265 		}
266 	}
267 
268 	/* The fast path for SW providers. */
269 	if (CHECK_FASTPATH(crq, pd)) {
270 		crypto_mechanism_t lmech;
271 
272 		lmech = *mech;
273 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
274 		if (fg == CRYPTO_FG_SIGN_ATOMIC)
275 			error = KCF_PROV_SIGN_ATOMIC(pd, pd->pd_sid, &lmech,
276 			    key, data, spi_ctx_tmpl, signature,
277 			    KCF_SWFP_RHNDL(crq));
278 		else
279 			error = KCF_PROV_SIGN_RECOVER_ATOMIC(pd, pd->pd_sid,
280 			    &lmech, key, data, spi_ctx_tmpl, signature,
281 			    KCF_SWFP_RHNDL(crq));
282 		KCF_PROV_INCRSTATS(pd, error);
283 	} else {
284 		kcf_op_type_t op = ((fg == CRYPTO_FG_SIGN_ATOMIC) ?
285 		    KCF_OP_ATOMIC : KCF_OP_SIGN_RECOVER_ATOMIC);
286 
287 		KCF_WRAP_SIGN_OPS_PARAMS(&params, op, pd->pd_sid,
288 		    mech, key, data, signature, spi_ctx_tmpl);
289 
290 		/* no crypto context to carry between multiple parts. */
291 		error = kcf_submit_request(pd, NULL, crq, &params, B_FALSE);
292 	}
293 
294 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
295 	    IS_RECOVERABLE(error)) {
296 		/* Add pd to the linked list of providers tried. */
297 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
298 			goto retry;
299 	}
300 
301 	if (list != NULL)
302 		kcf_free_triedlist(list);
303 
304 	KCF_PROV_REFRELE(pd);
305 	return (error);
306 }
307 
308 int
309 crypto_sign(crypto_mechanism_t *mech, crypto_key_t *key, crypto_data_t *data,
310     crypto_ctx_template_t tmpl, crypto_data_t *signature,
311     crypto_call_req_t *crq)
312 {
313 	return (sign_sr_atomic_common(mech, key, data, tmpl, signature, crq,
314 	    CRYPTO_FG_SIGN_ATOMIC));
315 }
316 
317 int
318 crypto_sign_recover_prov(kcf_provider_desc_t *pd,
319     crypto_session_id_t sid, crypto_mechanism_t *mech, crypto_key_t *key,
320     crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
321     crypto_call_req_t *crq)
322 {
323 	kcf_req_params_t params;
324 
325 	ASSERT(KCF_PROV_REFHELD(pd));
326 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_SIGN_RECOVER_ATOMIC, sid, mech,
327 	    key, data, signature, tmpl);
328 
329 	return (kcf_submit_request(pd, NULL, crq, &params, B_FALSE));
330 }
331 
332 int
333 crypto_sign_recover(crypto_mechanism_t *mech, crypto_key_t *key,
334     crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
335     crypto_call_req_t *crq)
336 {
337 	return (sign_sr_atomic_common(mech, key, data, tmpl, signature, crq,
338 	    CRYPTO_FG_SIGN_RECOVER_ATOMIC));
339 }
340 
341 int
342 crypto_sign_recover_init_prov(kcf_provider_desc_t *pd, crypto_session_id_t sid,
343     crypto_mechanism_t *mech, crypto_key_t *key, crypto_ctx_template_t tmpl,
344     crypto_context_t *ctxp, crypto_call_req_t *crq)
345 {
346 	int error;
347 	crypto_ctx_t *ctx;
348 	kcf_req_params_t params;
349 
350 	/* First, allocate and initialize the canonical context */
351 	if ((ctx = kcf_new_ctx(crq, pd, sid)) == NULL)
352 		return (CRYPTO_HOST_MEMORY);
353 
354 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_SIGN_RECOVER_INIT, sid, mech,
355 	    key, NULL, NULL, tmpl);
356 
357 	error = kcf_submit_request(pd, ctx, crq, &params, B_FALSE);
358 	if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
359 		*ctxp = (crypto_context_t)ctx;
360 	else {
361 		/* Release the hold done in kcf_new_ctx(). */
362 		KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
363 	}
364 
365 	return (error);
366 }
367 
368 int
369 crypto_sign_recover_single(crypto_context_t context, crypto_data_t *data,
370     crypto_data_t *signature, crypto_call_req_t *cr)
371 {
372 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
373 	kcf_context_t *kcf_ctx;
374 	kcf_provider_desc_t *pd;
375 	int error;
376 	kcf_req_params_t params;
377 
378 	if ((ctx == NULL) ||
379 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
380 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
381 		return (CRYPTO_INVALID_CONTEXT);
382 	}
383 
384 	KCF_PROV_REFHOLD(pd);
385 	KCF_WRAP_SIGN_OPS_PARAMS(&params, KCF_OP_SIGN_RECOVER, 0, NULL,
386 	    NULL, data, signature, NULL);
387 	error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
388 	KCF_PROV_REFRELE(pd);
389 
390 	/* Release the hold done in kcf_new_ctx() during init step. */
391 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
392 	return (error);
393 }
394