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