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