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