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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/zfs_context.h>
27 #include <sys/crypto/common.h>
28 #include <sys/crypto/impl.h>
29 #include <sys/crypto/api.h>
30 #include <sys/crypto/spi.h>
31 #include <sys/crypto/sched_impl.h>
32 
33 /*
34  * Message digest routines
35  */
36 
37 /*
38  * The following are the possible returned values common to all the routines
39  * below. The applicability of some of these return values depends on the
40  * presence of the arguments.
41  *
42  *	CRYPTO_SUCCESS:	The operation completed successfully.
43  *	CRYPTO_QUEUED:	A request was submitted successfully. The callback
44  *			routine will be called when the operation is done.
45  *	CRYPTO_MECHANISM_INVALID or CRYPTO_INVALID_MECH_PARAM
46  *			for problems with the 'mech'.
47  *	CRYPTO_INVALID_DATA for bogus 'data'
48  *	CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
49  *	CRYPTO_INVALID_CONTEXT: Not a valid context.
50  *	CRYPTO_BUSY:	Cannot process the request now. Schedule a
51  *			crypto_bufcall(), or try later.
52  *	CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED:
53  *			No provider is capable of a function or a mechanism.
54  */
55 
56 
57 /*
58  * crypto_digest_prov()
59  *
60  * Arguments:
61  *	pd:	pointer to the descriptor of the provider to use for this
62  *		operation.
63  *	sid:	provider session id.
64  *	mech:	crypto_mechanism_t pointer.
65  *		mech_type is a valid value previously returned by
66  *		crypto_mech2id();
67  *		When the mech's parameter is not NULL, its definition depends
68  *		on the standard definition of the mechanism.
69  *	data:	The message to be digested.
70  *	digest:	Storage for the digest. The length needed depends on the
71  *		mechanism.
72  *	cr:	crypto_call_req_t calling conditions and call back info.
73  *
74  * Description:
75  *	Asynchronously submits a request for, or synchronously performs the
76  *	digesting operation of 'data' on the specified
77  *	provider with the specified session.
78  *	When complete and successful, 'digest' will contain the digest value.
79  *	The caller should hold a reference on the specified provider
80  *	descriptor before calling this function.
81  *
82  * Context:
83  *	Process or interrupt, according to the semantics dictated by the 'cr'.
84  *
85  * Returns:
86  *	See comment in the beginning of the file.
87  */
88 int
crypto_digest_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * crq)89 crypto_digest_prov(crypto_provider_t provider, crypto_session_id_t sid,
90     crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest,
91     crypto_call_req_t *crq)
92 {
93 	kcf_req_params_t params;
94 	kcf_provider_desc_t *pd = provider;
95 	kcf_provider_desc_t *real_provider = pd;
96 	int rv;
97 
98 	ASSERT(KCF_PROV_REFHELD(pd));
99 
100 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
101 		rv = kcf_get_hardware_provider(mech->cm_type,
102 		    CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq),
103 		    pd, &real_provider, CRYPTO_FG_DIGEST_ATOMIC);
104 
105 		if (rv != CRYPTO_SUCCESS)
106 			return (rv);
107 	}
108 	KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, NULL,
109 	    data, digest);
110 
111 	/* no crypto context to carry between multiple parts. */
112 	rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
113 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
114 		KCF_PROV_REFRELE(real_provider);
115 
116 	return (rv);
117 }
118 
119 
120 /*
121  * Same as crypto_digest_prov(), but relies on the KCF scheduler to
122  * choose a provider. See crypto_digest_prov() comments for more information.
123  */
124 int
crypto_digest(crypto_mechanism_t * mech,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * crq)125 crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
126     crypto_data_t *digest, crypto_call_req_t *crq)
127 {
128 	int error;
129 	kcf_provider_desc_t *pd;
130 	kcf_req_params_t params;
131 	kcf_prov_tried_t *list = NULL;
132 
133 retry:
134 	/* The pd is returned held */
135 	if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, list,
136 	    CRYPTO_FG_DIGEST_ATOMIC, CHECK_RESTRICT(crq),
137 	    data->cd_length)) == NULL) {
138 		if (list != NULL)
139 			kcf_free_triedlist(list);
140 		return (error);
141 	}
142 
143 	/* The fast path for SW providers. */
144 	if (CHECK_FASTPATH(crq, pd)) {
145 		crypto_mechanism_t lmech;
146 
147 		lmech = *mech;
148 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
149 		error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data,
150 		    digest, KCF_SWFP_RHNDL(crq));
151 		KCF_PROV_INCRSTATS(pd, error);
152 	} else {
153 		if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
154 		    (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
155 		    (data->cd_length > pd->pd_hash_limit)) {
156 			error = CRYPTO_BUFFER_TOO_BIG;
157 		} else {
158 			KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC,
159 			    pd->pd_sid, mech, NULL, data, digest);
160 
161 			/* no crypto context to carry between multiple parts. */
162 			error = kcf_submit_request(pd, NULL, crq, &params,
163 			    B_FALSE);
164 		}
165 	}
166 
167 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
168 	    IS_RECOVERABLE(error)) {
169 		/* Add pd to the linked list of providers tried. */
170 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
171 			goto retry;
172 	}
173 
174 	if (list != NULL)
175 		kcf_free_triedlist(list);
176 
177 	KCF_PROV_REFRELE(pd);
178 	return (error);
179 }
180 
181 /*
182  * crypto_digest_init_prov()
183  *
184  *	pd:	pointer to the descriptor of the provider to use for this
185  *		operation.
186  *	sid:	provider session id.
187  *	mech:	crypto_mechanism_t pointer.
188  *		mech_type is a valid value previously returned by
189  *		crypto_mech2id();
190  *		When the mech's parameter is not NULL, its definition depends
191  *		on the standard definition of the mechanism.
192  *	ctxp:	Pointer to a crypto_context_t.
193  *	cr:	crypto_call_req_t calling conditions and call back info.
194  *
195  * Description:
196  *	Asynchronously submits a request for, or synchronously performs the
197  *	initialization of a message digest operation on the specified
198  *	provider with the specified session.
199  *	When complete and successful, 'ctxp' will contain a crypto_context_t
200  *	valid for later calls to digest_update() and digest_final().
201  *	The caller should hold a reference on the specified provider
202  *	descriptor before calling this function.
203  */
204 int
crypto_digest_init_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_context_t * ctxp,crypto_call_req_t * crq)205 crypto_digest_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
206     crypto_mechanism_t *mech, crypto_context_t *ctxp, crypto_call_req_t  *crq)
207 {
208 	int error;
209 	crypto_ctx_t *ctx;
210 	kcf_req_params_t params;
211 	kcf_provider_desc_t *pd = provider;
212 	kcf_provider_desc_t *real_provider = pd;
213 
214 	ASSERT(KCF_PROV_REFHELD(pd));
215 
216 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
217 		error = kcf_get_hardware_provider(mech->cm_type,
218 		    CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
219 		    &real_provider, CRYPTO_FG_DIGEST);
220 
221 		if (error != CRYPTO_SUCCESS)
222 			return (error);
223 	}
224 
225 	/* Allocate and initialize the canonical context */
226 	if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
227 		if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
228 			KCF_PROV_REFRELE(real_provider);
229 		return (CRYPTO_HOST_MEMORY);
230 	}
231 
232 	/* The fast path for SW providers. */
233 	if (CHECK_FASTPATH(crq, pd)) {
234 		crypto_mechanism_t lmech;
235 
236 		lmech = *mech;
237 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
238 		error = KCF_PROV_DIGEST_INIT(real_provider, ctx, &lmech,
239 		    KCF_SWFP_RHNDL(crq));
240 		KCF_PROV_INCRSTATS(pd, error);
241 	} else {
242 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_INIT, sid,
243 		    mech, NULL, NULL, NULL);
244 		error = kcf_submit_request(real_provider, ctx, crq, &params,
245 		    B_FALSE);
246 	}
247 
248 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
249 		KCF_PROV_REFRELE(real_provider);
250 
251 	if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
252 		*ctxp = (crypto_context_t)ctx;
253 	else {
254 		/* Release the hold done in kcf_new_ctx(). */
255 		KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
256 	}
257 
258 	return (error);
259 }
260 
261 /*
262  * Same as crypto_digest_init_prov(), but relies on the KCF scheduler
263  * to choose a provider. See crypto_digest_init_prov() comments for
264  * more information.
265  */
266 int
crypto_digest_init(crypto_mechanism_t * mech,crypto_context_t * ctxp,crypto_call_req_t * crq)267 crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
268     crypto_call_req_t  *crq)
269 {
270 	int error;
271 	kcf_provider_desc_t *pd;
272 	kcf_prov_tried_t *list = NULL;
273 
274 retry:
275 	/* The pd is returned held */
276 	if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error,
277 	    list, CRYPTO_FG_DIGEST, CHECK_RESTRICT(crq), 0)) == NULL) {
278 		if (list != NULL)
279 			kcf_free_triedlist(list);
280 		return (error);
281 	}
282 
283 	if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
284 	    (pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
285 		/*
286 		 * The hardware provider has limited digest support.
287 		 * So, we fallback early here to using a software provider.
288 		 *
289 		 * XXX - need to enhance to do the fallback later in
290 		 * crypto_digest_update() if the size of accumulated input data
291 		 * exceeds the maximum size digestable by hardware provider.
292 		 */
293 		error = CRYPTO_BUFFER_TOO_BIG;
294 	} else {
295 		error = crypto_digest_init_prov(pd, pd->pd_sid,
296 		    mech, ctxp, crq);
297 	}
298 
299 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
300 	    IS_RECOVERABLE(error)) {
301 		/* Add pd to the linked list of providers tried. */
302 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
303 			goto retry;
304 	}
305 
306 	if (list != NULL)
307 		kcf_free_triedlist(list);
308 	KCF_PROV_REFRELE(pd);
309 	return (error);
310 }
311 
312 /*
313  * crypto_digest_update()
314  *
315  * Arguments:
316  *	context: A crypto_context_t initialized by digest_init().
317  *	data:	The part of message to be digested.
318  *	cr:	crypto_call_req_t calling conditions and call back info.
319  *
320  * Description:
321  *	Asynchronously submits a request for, or synchronously performs a
322  *	part of a message digest operation.
323  *
324  * Context:
325  *	Process or interrupt, according to the semantics dictated by the 'cr'.
326  *
327  * Returns:
328  *	See comment in the beginning of the file.
329  */
330 int
crypto_digest_update(crypto_context_t context,crypto_data_t * data,crypto_call_req_t * cr)331 crypto_digest_update(crypto_context_t context, crypto_data_t *data,
332     crypto_call_req_t *cr)
333 {
334 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
335 	kcf_context_t *kcf_ctx;
336 	kcf_provider_desc_t *pd;
337 	int error;
338 	kcf_req_params_t params;
339 
340 	if ((ctx == NULL) ||
341 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
342 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
343 		return (CRYPTO_INVALID_CONTEXT);
344 	}
345 
346 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
347 
348 	/* The fast path for SW providers. */
349 	if (CHECK_FASTPATH(cr, pd)) {
350 		error = KCF_PROV_DIGEST_UPDATE(pd, ctx, data, NULL);
351 		KCF_PROV_INCRSTATS(pd, error);
352 	} else {
353 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_UPDATE,
354 		    ctx->cc_session, NULL, NULL, data, NULL);
355 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
356 	}
357 
358 	return (error);
359 }
360 
361 /*
362  * crypto_digest_final()
363  *
364  * Arguments:
365  *	context: A crypto_context_t initialized by digest_init().
366  *	digest:	The storage for the digest.
367  *	cr:	crypto_call_req_t calling conditions and call back info.
368  *
369  * Description:
370  *	Asynchronously submits a request for, or synchronously performs the
371  *	final part of a message digest operation.
372  *
373  * Context:
374  *	Process or interrupt, according to the semantics dictated by the 'cr'.
375  *
376  * Returns:
377  *	See comment in the beginning of the file.
378  */
379 int
crypto_digest_final(crypto_context_t context,crypto_data_t * digest,crypto_call_req_t * cr)380 crypto_digest_final(crypto_context_t context, crypto_data_t *digest,
381     crypto_call_req_t *cr)
382 {
383 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
384 	kcf_context_t *kcf_ctx;
385 	kcf_provider_desc_t *pd;
386 	int error;
387 	kcf_req_params_t params;
388 
389 	if ((ctx == NULL) ||
390 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
391 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
392 		return (CRYPTO_INVALID_CONTEXT);
393 	}
394 
395 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
396 
397 	/* The fast path for SW providers. */
398 	if (CHECK_FASTPATH(cr, pd)) {
399 		error = KCF_PROV_DIGEST_FINAL(pd, ctx, digest, NULL);
400 		KCF_PROV_INCRSTATS(pd, error);
401 	} else {
402 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_FINAL,
403 		    ctx->cc_session, NULL, NULL, NULL, digest);
404 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
405 	}
406 
407 	/* Release the hold done in kcf_new_ctx() during init step. */
408 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
409 	return (error);
410 }
411 
412 /*
413  * Performs a digest update on the specified key. Note that there is
414  * no k-API crypto_digest_key() equivalent of this function.
415  */
416 int
crypto_digest_key_prov(crypto_context_t context,crypto_key_t * key,crypto_call_req_t * cr)417 crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key,
418     crypto_call_req_t *cr)
419 {
420 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
421 	kcf_context_t *kcf_ctx;
422 	kcf_provider_desc_t *pd;
423 	int error;
424 	kcf_req_params_t params;
425 
426 	if ((ctx == NULL) ||
427 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
428 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
429 		return (CRYPTO_INVALID_CONTEXT);
430 	}
431 
432 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
433 
434 	/* The fast path for SW providers. */
435 	if (CHECK_FASTPATH(cr, pd)) {
436 		error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL);
437 		KCF_PROV_INCRSTATS(pd, error);
438 	} else {
439 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_DIGEST_KEY,
440 		    ctx->cc_session, NULL, key, NULL, NULL);
441 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
442 	}
443 
444 	return (error);
445 }
446 
447 /*
448  * See comments for crypto_digest_update() and crypto_digest_final().
449  */
450 int
crypto_digest_single(crypto_context_t context,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * cr)451 crypto_digest_single(crypto_context_t context, crypto_data_t *data,
452     crypto_data_t *digest, crypto_call_req_t *cr)
453 {
454 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
455 	kcf_context_t *kcf_ctx;
456 	kcf_provider_desc_t *pd;
457 	int error;
458 	kcf_req_params_t params;
459 
460 	if ((ctx == NULL) ||
461 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
462 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
463 		return (CRYPTO_INVALID_CONTEXT);
464 	}
465 
466 
467 	/* The fast path for SW providers. */
468 	if (CHECK_FASTPATH(cr, pd)) {
469 		error = KCF_PROV_DIGEST(pd, ctx, data, digest, NULL);
470 		KCF_PROV_INCRSTATS(pd, error);
471 	} else {
472 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
473 		    NULL, NULL, data, digest);
474 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
475 	}
476 
477 	/* Release the hold done in kcf_new_ctx() during init step. */
478 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
479 	return (error);
480 }
481 
482 #if defined(_KERNEL)
483 EXPORT_SYMBOL(crypto_digest_prov);
484 EXPORT_SYMBOL(crypto_digest);
485 EXPORT_SYMBOL(crypto_digest_init_prov);
486 EXPORT_SYMBOL(crypto_digest_init);
487 EXPORT_SYMBOL(crypto_digest_update);
488 EXPORT_SYMBOL(crypto_digest_final);
489 EXPORT_SYMBOL(crypto_digest_key_prov);
490 EXPORT_SYMBOL(crypto_digest_single);
491 #endif
492