xref: /titanic_44/usr/src/uts/common/crypto/api/kcf_digest.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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 2004 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/crypto/common.h>
34 #include <sys/crypto/impl.h>
35 #include <sys/crypto/api.h>
36 #include <sys/crypto/spi.h>
37 #include <sys/crypto/sched_impl.h>
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_mechanism_t *mech, crypto_data_t *data,
96     crypto_data_t *digest, crypto_call_req_t *crq, kcf_provider_desc_t *pd,
97     crypto_session_id_t sid)
98 {
99 	kcf_req_params_t params;
100 
101 	ASSERT(KCF_PROV_REFHELD(pd));
102 	KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, NULL,
103 	    data, digest);
104 
105 	/* no crypto context to carry between multiple parts. */
106 	return (kcf_submit_request(pd, NULL, crq, &params, B_FALSE));
107 }
108 
109 /*
110  * Same as crypto_digest_prov(), but relies on the KCF scheduler to
111  * choose a provider. See crypto_digest_prov() comments for more information.
112  */
113 int
114 crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
115     crypto_data_t *digest, crypto_call_req_t *crq)
116 {
117 	int error;
118 	kcf_provider_desc_t *pd;
119 	kcf_req_params_t params;
120 	kcf_prov_tried_t *list = NULL;
121 
122 retry:
123 	/* The pd is returned held */
124 	if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, list,
125 	    CRYPTO_FG_DIGEST_ATOMIC, CHECK_RESTRICT(crq),
126 	    data->cd_length)) == NULL) {
127 		if (list != NULL)
128 			kcf_free_triedlist(list);
129 		return (error);
130 	}
131 
132 	/* The fast path for SW providers. */
133 	if (CHECK_FASTPATH(crq, pd)) {
134 		crypto_mechanism_t lmech;
135 
136 		lmech = *mech;
137 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
138 		error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data,
139 		    digest, KCF_SWFP_RHNDL(crq));
140 		KCF_PROV_INCRSTATS(pd, error);
141 	} else {
142 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC, pd->pd_sid,
143 		    mech, NULL, data, digest);
144 
145 		/* no crypto context to carry between multiple parts. */
146 		error = kcf_submit_request(pd, NULL, crq, &params, B_FALSE);
147 	}
148 
149 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
150 	    IS_RECOVERABLE(error)) {
151 		/* Add pd to the linked list of providers tried. */
152 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
153 			goto retry;
154 	}
155 
156 	if (list != NULL)
157 		kcf_free_triedlist(list);
158 
159 	KCF_PROV_REFRELE(pd);
160 	return (error);
161 }
162 
163 /*
164  * crypto_digest_init_prov()
165  *
166  *	pd:	pointer to the descriptor of the provider to use for this
167  *		operation.
168  *	sid:	provider session id.
169  *	mech:	crypto_mechanism_t pointer.
170  *		mech_type is a valid value previously returned by
171  *		crypto_mech2id();
172  *		When the mech's parameter is not NULL, its definition depends
173  *		on the standard definition of the mechanism.
174  *	ctxp:	Pointer to a crypto_context_t.
175  *	cr:	crypto_call_req_t calling conditions and call back info.
176  *
177  * Description:
178  *	Asynchronously submits a request for, or synchronously performs the
179  *	initialization of a message digest operation on the specified
180  *	provider with the specified session.
181  *	When complete and successful, 'ctxp' will contain a crypto_context_t
182  *	valid for later calls to digest_update() and digest_final().
183  *	The caller should hold a reference on the specified provider
184  *	descriptor before calling this function.
185  */
186 int
187 crypto_digest_init_prov(kcf_provider_desc_t *pd,
188     crypto_session_id_t sid, crypto_mechanism_t *mech,
189     crypto_context_t *ctxp, crypto_call_req_t  *crq)
190 {
191 	int error;
192 	crypto_ctx_t *ctx;
193 	kcf_req_params_t params;
194 
195 	ASSERT(KCF_PROV_REFHELD(pd));
196 
197 	/* First, allocate and initialize the canonical context */
198 	if ((ctx = kcf_new_ctx(crq, pd, sid)) == NULL)
199 		return (CRYPTO_HOST_MEMORY);
200 
201 	/* The fast path for SW providers. */
202 	if (CHECK_FASTPATH(crq, pd)) {
203 		crypto_mechanism_t lmech;
204 
205 		lmech = *mech;
206 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
207 		error = KCF_PROV_DIGEST_INIT(pd, ctx, &lmech,
208 		    KCF_SWFP_RHNDL(crq));
209 		KCF_PROV_INCRSTATS(pd, error);
210 	} else {
211 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_INIT, sid,
212 		    mech, NULL, NULL, NULL);
213 		error = kcf_submit_request(pd, ctx, crq, &params, B_FALSE);
214 	}
215 
216 	if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
217 		*ctxp = (crypto_context_t)ctx;
218 	else {
219 		/* Release the hold done in kcf_new_ctx(). */
220 		KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
221 	}
222 
223 	return (error);
224 }
225 
226 
227 /*
228  * Same as crypto_digest_init_prov(), but relies on the KCF scheduler
229  * to choose a provider. See crypto_digest_init_prov() comments for
230  * more information.
231  */
232 int
233 crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
234     crypto_call_req_t  *crq)
235 {
236 	int error;
237 	kcf_provider_desc_t *pd;
238 	kcf_prov_tried_t *list = NULL;
239 
240 retry:
241 	/* The pd is returned held */
242 	if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error,
243 	    list, CRYPTO_FG_DIGEST, CHECK_RESTRICT(crq), 0)) == NULL) {
244 		if (list != NULL)
245 			kcf_free_triedlist(list);
246 		return (error);
247 	}
248 
249 	error = crypto_digest_init_prov(pd, pd->pd_sid, mech, ctxp, crq);
250 
251 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
252 	    IS_RECOVERABLE(error)) {
253 		/* Add pd to the linked list of providers tried. */
254 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
255 			goto retry;
256 	}
257 
258 	if (list != NULL)
259 		kcf_free_triedlist(list);
260 	KCF_PROV_REFRELE(pd);
261 	return (error);
262 }
263 
264 /*
265  * crypto_digest_update()
266  *
267  * Arguments:
268  *	context: A crypto_context_t initialized by digest_init().
269  *	data:	The part of message to be digested.
270  *	cr:	crypto_call_req_t calling conditions and call back info.
271  *
272  * Description:
273  *	Asynchronously submits a request for, or synchronously performs a
274  *	part of a message digest operation.
275  *
276  * Context:
277  *	Process or interrupt, according to the semantics dictated by the 'cr'.
278  *
279  * Returns:
280  *	See comment in the beginning of the file.
281  */
282 int
283 crypto_digest_update(crypto_context_t context, crypto_data_t *data,
284     crypto_call_req_t *cr)
285 {
286 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
287 	kcf_context_t *kcf_ctx;
288 	kcf_provider_desc_t *pd;
289 	int error;
290 	kcf_req_params_t params;
291 
292 	if ((ctx == NULL) ||
293 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
294 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
295 		return (CRYPTO_INVALID_CONTEXT);
296 	}
297 
298 	KCF_PROV_REFHOLD(pd);
299 
300 	/* The fast path for SW providers. */
301 	if (CHECK_FASTPATH(cr, pd)) {
302 		error = KCF_PROV_DIGEST_UPDATE(pd, ctx, data, NULL);
303 		KCF_PROV_INCRSTATS(pd, error);
304 	} else {
305 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_UPDATE, pd->pd_sid,
306 		    NULL, NULL, data, NULL);
307 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
308 	}
309 
310 	KCF_PROV_REFRELE(pd);
311 	return (error);
312 }
313 
314 /*
315  * crypto_digest_final()
316  *
317  * Arguments:
318  *	context: A crypto_context_t initialized by digest_init().
319  *	digest:	The storage for the digest.
320  *	cr:	crypto_call_req_t calling conditions and call back info.
321  *
322  * Description:
323  *	Asynchronously submits a request for, or synchronously performs the
324  *	final part of a message digest operation.
325  *
326  * Context:
327  *	Process or interrupt, according to the semantics dictated by the 'cr'.
328  *
329  * Returns:
330  *	See comment in the beginning of the file.
331  */
332 int
333 crypto_digest_final(crypto_context_t context, crypto_data_t *digest,
334     crypto_call_req_t *cr)
335 {
336 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
337 	kcf_context_t *kcf_ctx;
338 	kcf_provider_desc_t *pd;
339 	int error;
340 	kcf_req_params_t params;
341 
342 	if ((ctx == NULL) ||
343 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
344 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
345 		return (CRYPTO_INVALID_CONTEXT);
346 	}
347 
348 	KCF_PROV_REFHOLD(pd);
349 
350 	/* The fast path for SW providers. */
351 	if (CHECK_FASTPATH(cr, pd)) {
352 		error = KCF_PROV_DIGEST_FINAL(pd, ctx, digest, NULL);
353 		KCF_PROV_INCRSTATS(pd, error);
354 	} else {
355 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_FINAL, pd->pd_sid,
356 		    NULL, NULL, NULL, digest);
357 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
358 	}
359 
360 	KCF_PROV_REFRELE(pd);
361 	/* Release the hold done in kcf_new_ctx() during init step. */
362 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
363 	return (error);
364 }
365 
366 /*
367  * Performs a digest update on the specified key. Note that there is
368  * no k-API crypto_digest_key() equivalent of this function.
369  */
370 int
371 crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key,
372     crypto_call_req_t *cr)
373 {
374 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
375 	kcf_context_t *kcf_ctx;
376 	kcf_provider_desc_t *pd;
377 	int error;
378 	kcf_req_params_t params;
379 
380 	if ((ctx == NULL) ||
381 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
382 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
383 		return (CRYPTO_INVALID_CONTEXT);
384 	}
385 
386 	KCF_PROV_REFHOLD(pd);
387 
388 	/* The fast path for SW providers. */
389 	if (CHECK_FASTPATH(cr, pd)) {
390 		error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL);
391 		KCF_PROV_INCRSTATS(pd, error);
392 	} else {
393 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_DIGEST_KEY,
394 		    pd->pd_sid, NULL, key, NULL, NULL);
395 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
396 	}
397 
398 	KCF_PROV_REFRELE(pd);
399 	return (error);
400 }
401 
402 /*
403  * See comments for crypto_digest_update() and crypto_digest_final().
404  */
405 int
406 crypto_digest_single(crypto_context_t context, crypto_data_t *data,
407     crypto_data_t *digest, crypto_call_req_t *cr)
408 {
409 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
410 	kcf_context_t *kcf_ctx;
411 	kcf_provider_desc_t *pd;
412 	int error;
413 	kcf_req_params_t params;
414 
415 	if ((ctx == NULL) ||
416 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
417 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
418 		return (CRYPTO_INVALID_CONTEXT);
419 	}
420 
421 	KCF_PROV_REFHOLD(pd);
422 
423 	/* The fast path for SW providers. */
424 	if (CHECK_FASTPATH(cr, pd)) {
425 		error = KCF_PROV_DIGEST(pd, ctx, data, digest, NULL);
426 		KCF_PROV_INCRSTATS(pd, error);
427 	} else {
428 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
429 		    NULL, NULL, data, digest);
430 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
431 	}
432 
433 	KCF_PROV_REFRELE(pd);
434 	/* Release the hold done in kcf_new_ctx() during init step. */
435 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
436 	return (error);
437 }
438