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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/kmem.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_MAC_OFFSET(f)		offsetof(crypto_mac_ops_t, f)
38 
39 /*
40  * Message authentication codes 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_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
52  *	CRYPTO_INVALID_MECH 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: No provider is
59  *			capable of a function or a mechanism.
60  *	CRYPTO_INVALID_KEY: bogus 'key' argument.
61  *	CRYPTO_INVALID_MAC: bogus 'mac' argument.
62  */
63 
64 /*
65  * crypto_mac_prov()
66  *
67  * Arguments:
68  *	mech:	crypto_mechanism_t pointer.
69  *		mech_type is a valid value previously returned by
70  *		crypto_mech2id();
71  *		When the mech's parameter is not NULL, its definition depends
72  *		on the standard definition of the mechanism.
73  *	key:	pointer to a crypto_key_t structure.
74  *	data:	The message to compute the MAC for.
75  *	mac: Storage for the MAC. The length needed depends on the mechanism.
76  *	tmpl:	a crypto_ctx_template_t, opaque template of a context of a
77  *		MAC with the 'mech' using 'key'. 'tmpl' is created by
78  *		a previous call to crypto_create_ctx_template().
79  *	cr:	crypto_call_req_t calling conditions and call back info.
80  *
81  * Description:
82  *	Asynchronously submits a request for, or synchronously performs a
83  *	single-part message authentication of 'data' with the mechanism
84  *	'mech', using *	the key 'key', on the specified provider with
85  *	the specified session id.
86  *	When complete and successful, 'mac' will contain the message
87  *	authentication code.
88  *
89  * Context:
90  *	Process or interrupt, according to the semantics dictated by the 'crq'.
91  *
92  * Returns:
93  *	See comment in the beginning of the file.
94  */
95 int
96 crypto_mac_prov(crypto_provider_t provider, crypto_session_id_t sid,
97     crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key,
98     crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq)
99 {
100 	kcf_req_params_t params;
101 	kcf_provider_desc_t *pd = provider;
102 	kcf_provider_desc_t *real_provider = pd;
103 	int rv;
104 
105 	ASSERT(KCF_PROV_REFHELD(pd));
106 
107 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
108 		rv = kcf_get_hardware_provider(mech->cm_type, key,
109 		    CRYPTO_MECH_INVALID, NULL, CHECK_RESTRICT(crq), pd,
110 		    &real_provider, CRYPTO_FG_MAC_ATOMIC);
111 
112 		if (rv != CRYPTO_SUCCESS)
113 			return (rv);
114 	}
115 
116 	KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, key,
117 	    data, mac, tmpl);
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_mac_prov(), but relies on the KCF scheduler to choose
127  * a provider. See crypto_mac() comments for more information.
128  */
129 int
130 crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
131     crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
132     crypto_call_req_t *crq)
133 {
134 	int error;
135 	kcf_mech_entry_t *me;
136 	kcf_req_params_t params;
137 	kcf_provider_desc_t *pd;
138 	kcf_ctx_template_t *ctx_tmpl;
139 	crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
140 	kcf_prov_tried_t *list = NULL;
141 
142 retry:
143 	/* The pd is returned held */
144 	if ((pd = kcf_get_mech_provider(mech->cm_type, key, &me, &error,
145 	    list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq),
146 	    data->cd_length)) == NULL) {
147 		if (list != NULL)
148 			kcf_free_triedlist(list);
149 		return (error);
150 	}
151 
152 	/*
153 	 * For SW providers, check the validity of the context template
154 	 * It is very rare that the generation number mis-matches, so
155 	 * is acceptable to fail here, and let the consumer recover by
156 	 * freeing this tmpl and create a new one for the key and new SW
157 	 * provider
158 	 */
159 	if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
160 	    ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
161 		if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
162 			if (list != NULL)
163 				kcf_free_triedlist(list);
164 			KCF_PROV_REFRELE(pd);
165 			return (CRYPTO_OLD_CTX_TEMPLATE);
166 		} else {
167 			spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
168 		}
169 	}
170 
171 	/* The fast path for SW providers. */
172 	if (CHECK_FASTPATH(crq, pd)) {
173 		crypto_mechanism_t lmech;
174 
175 		lmech = *mech;
176 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
177 
178 		error = KCF_PROV_MAC_ATOMIC(pd, pd->pd_sid, &lmech, key, data,
179 		    mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
180 		KCF_PROV_INCRSTATS(pd, error);
181 	} else {
182 		if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
183 		    (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
184 		    (data->cd_length > pd->pd_hash_limit)) {
185 			/*
186 			 * XXX - We need a check to see if this is indeed
187 			 * a HMAC. So far, all kernel clients use
188 			 * this interface only for HMAC. So, this is fine
189 			 * for now.
190 			 */
191 			error = CRYPTO_BUFFER_TOO_BIG;
192 		} else {
193 			KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_ATOMIC,
194 			    pd->pd_sid, mech, key, data, mac, spi_ctx_tmpl);
195 
196 			error = kcf_submit_request(pd, NULL, crq, &params,
197 			    KCF_ISDUALREQ(crq));
198 		}
199 	}
200 
201 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
202 	    IS_RECOVERABLE(error)) {
203 		/* Add pd to the linked list of providers tried. */
204 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
205 			goto retry;
206 	}
207 
208 	if (list != NULL)
209 		kcf_free_triedlist(list);
210 
211 	KCF_PROV_REFRELE(pd);
212 	return (error);
213 }
214 
215 /*
216  * Single part operation to compute the MAC corresponding to the specified
217  * 'data' and to verify that it matches the MAC specified by 'mac'.
218  * The other arguments are the same as the function crypto_mac_prov().
219  */
220 int
221 crypto_mac_verify_prov(crypto_provider_t provider, crypto_session_id_t sid,
222     crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key,
223     crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq)
224 {
225 	kcf_req_params_t params;
226 	kcf_provider_desc_t *pd = provider;
227 	kcf_provider_desc_t *real_provider = pd;
228 	int rv;
229 
230 	ASSERT(KCF_PROV_REFHELD(pd));
231 
232 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
233 		rv = kcf_get_hardware_provider(mech->cm_type, key,
234 		    CRYPTO_MECH_INVALID, NULL, CHECK_RESTRICT(crq), pd,
235 		    &real_provider, CRYPTO_FG_MAC_ATOMIC);
236 
237 		if (rv != CRYPTO_SUCCESS)
238 			return (rv);
239 	}
240 
241 	KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_MAC_VERIFY_ATOMIC, sid, mech,
242 	    key, data, mac, tmpl);
243 	rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
244 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
245 		KCF_PROV_REFRELE(real_provider);
246 
247 	return (rv);
248 }
249 
250 /*
251  * Same as crypto_mac_verify_prov(), but relies on the KCF scheduler to choose
252  * a provider. See crypto_mac_verify_prov() comments for more information.
253  */
254 int
255 crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data,
256     crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
257     crypto_call_req_t *crq)
258 {
259 	int error;
260 	kcf_mech_entry_t *me;
261 	kcf_req_params_t params;
262 	kcf_provider_desc_t *pd;
263 	kcf_ctx_template_t *ctx_tmpl;
264 	crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
265 	kcf_prov_tried_t *list = NULL;
266 
267 retry:
268 	/* The pd is returned held */
269 	if ((pd = kcf_get_mech_provider(mech->cm_type, key, &me, &error,
270 	    list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq),
271 	    data->cd_length)) == NULL) {
272 		if (list != NULL)
273 			kcf_free_triedlist(list);
274 		return (error);
275 	}
276 
277 	/*
278 	 * For SW providers, check the validity of the context template
279 	 * It is very rare that the generation number mis-matches, so
280 	 * is acceptable to fail here, and let the consumer recover by
281 	 * freeing this tmpl and create a new one for the key and new SW
282 	 * provider
283 	 */
284 	if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
285 	    ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
286 		if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
287 			if (list != NULL)
288 				kcf_free_triedlist(list);
289 			KCF_PROV_REFRELE(pd);
290 			return (CRYPTO_OLD_CTX_TEMPLATE);
291 		} else {
292 			spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
293 		}
294 	}
295 
296 	/* The fast path for SW providers. */
297 	if (CHECK_FASTPATH(crq, pd)) {
298 		crypto_mechanism_t lmech;
299 
300 		lmech = *mech;
301 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
302 
303 		error = KCF_PROV_MAC_VERIFY_ATOMIC(pd, pd->pd_sid, &lmech, key,
304 		    data, mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
305 		KCF_PROV_INCRSTATS(pd, error);
306 	} else {
307 		if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
308 		    (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
309 		    (data->cd_length > pd->pd_hash_limit)) {
310 			/* see comments in crypto_mac() */
311 			error = CRYPTO_BUFFER_TOO_BIG;
312 		} else {
313 			KCF_WRAP_MAC_OPS_PARAMS(&params,
314 			    KCF_OP_MAC_VERIFY_ATOMIC, pd->pd_sid, mech,
315 			    key, data, mac, spi_ctx_tmpl);
316 
317 			error = kcf_submit_request(pd, NULL, crq, &params,
318 			    KCF_ISDUALREQ(crq));
319 		}
320 	}
321 
322 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
323 	    IS_RECOVERABLE(error)) {
324 		/* Add pd to the linked list of providers tried. */
325 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
326 			goto retry;
327 	}
328 
329 	if (list != NULL)
330 		kcf_free_triedlist(list);
331 
332 	KCF_PROV_REFRELE(pd);
333 	return (error);
334 }
335 
336 
337 /*
338  * crypto_mac_init_prov()
339  *
340  * Arguments:
341  *	pd:	pointer to the descriptor of the provider to use for this
342  *		operation.
343  *	sid:	provider session id.
344  *	mech:	crypto_mechanism_t pointer.
345  *		mech_type is a valid value previously returned by
346  *		crypto_mech2id();
347  *		When the mech's parameter is not NULL, its definition depends
348  *		on the standard definition of the mechanism.
349  *	key:	pointer to a crypto_key_t structure.
350  *	tmpl:	a crypto_ctx_template_t, opaque template of a context of a
351  *		MAC with the 'mech' using 'key'. 'tmpl' is created by
352  *		a previous call to crypto_create_ctx_template().
353  *	ctxp:	Pointer to a crypto_context_t.
354  *	cr:	crypto_call_req_t calling conditions and call back info.
355  *
356  * Description:
357  *	Asynchronously submits a request for, or synchronously performs the
358  *	initialization of a MAC operation on the specified provider with
359  *	the specified session.
360  *	When possible and applicable, will internally use the pre-computed MAC
361  *	context from the context template, tmpl.
362  *	When complete and successful, 'ctxp' will contain a crypto_context_t
363  *	valid for later calls to mac_update() and mac_final().
364  *	The caller should hold a reference on the specified provider
365  *	descriptor before calling this function.
366  *
367  * Context:
368  *	Process or interrupt, according to the semantics dictated by the 'cr'.
369  *
370  * Returns:
371  *	See comment in the beginning of the file.
372  */
373 int
374 crypto_mac_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
375     crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl,
376     crypto_context_t *ctxp, crypto_call_req_t *crq)
377 {
378 	int rv;
379 	crypto_ctx_t *ctx;
380 	kcf_req_params_t params;
381 	kcf_provider_desc_t *pd = provider;
382 	kcf_provider_desc_t *real_provider = pd;
383 
384 	ASSERT(KCF_PROV_REFHELD(pd));
385 
386 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
387 		rv = kcf_get_hardware_provider(mech->cm_type, key,
388 		    CRYPTO_MECH_INVALID, NULL, CHECK_RESTRICT(crq), pd,
389 		    &real_provider, CRYPTO_FG_MAC);
390 
391 		if (rv != CRYPTO_SUCCESS)
392 			return (rv);
393 	}
394 
395 	/* Allocate and initialize the canonical context */
396 	if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
397 		if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
398 			KCF_PROV_REFRELE(real_provider);
399 		return (CRYPTO_HOST_MEMORY);
400 	}
401 
402 	/* The fast path for SW providers. */
403 	if (CHECK_FASTPATH(crq, pd)) {
404 		crypto_mechanism_t lmech;
405 
406 		lmech = *mech;
407 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
408 		rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl,
409 		    KCF_SWFP_RHNDL(crq));
410 		KCF_PROV_INCRSTATS(pd, rv);
411 	} else {
412 		KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_INIT, sid, mech, key,
413 		    NULL, NULL, tmpl);
414 		rv = kcf_submit_request(real_provider, ctx, crq, &params,
415 		    B_FALSE);
416 	}
417 
418 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
419 		KCF_PROV_REFRELE(real_provider);
420 
421 	if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
422 		*ctxp = (crypto_context_t)ctx;
423 	else {
424 		/* Release the hold done in kcf_new_ctx(). */
425 		KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
426 	}
427 
428 	return (rv);
429 }
430 
431 /*
432  * Same as crypto_mac_init_prov(), but relies on the KCF scheduler to
433  * choose a provider. See crypto_mac_init_prov() comments for more
434  * information.
435  */
436 int
437 crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
438     crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
439     crypto_call_req_t  *crq)
440 {
441 	int error;
442 	kcf_mech_entry_t *me;
443 	kcf_provider_desc_t *pd;
444 	kcf_ctx_template_t *ctx_tmpl;
445 	crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
446 	kcf_prov_tried_t *list = NULL;
447 
448 retry:
449 	/* The pd is returned held */
450 	if ((pd = kcf_get_mech_provider(mech->cm_type, key, &me, &error,
451 	    list, CRYPTO_FG_MAC, CHECK_RESTRICT(crq), 0)) == NULL) {
452 		if (list != NULL)
453 			kcf_free_triedlist(list);
454 		return (error);
455 	}
456 
457 	/*
458 	 * For SW providers, check the validity of the context template
459 	 * It is very rare that the generation number mis-matches, so
460 	 * is acceptable to fail here, and let the consumer recover by
461 	 * freeing this tmpl and create a new one for the key and new SW
462 	 * provider
463 	 */
464 
465 	if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
466 	    ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
467 		if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
468 			if (list != NULL)
469 				kcf_free_triedlist(list);
470 			KCF_PROV_REFRELE(pd);
471 			return (CRYPTO_OLD_CTX_TEMPLATE);
472 		} else {
473 			spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
474 		}
475 	}
476 
477 	if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
478 	    (pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
479 		/*
480 		 * The hardware provider has limited HMAC support.
481 		 * So, we fallback early here to using a software provider.
482 		 *
483 		 * XXX - need to enhance to do the fallback later in
484 		 * crypto_mac_update() if the size of accumulated input data
485 		 * exceeds the maximum size digestable by hardware provider.
486 		 */
487 		error = CRYPTO_BUFFER_TOO_BIG;
488 	} else {
489 		error = crypto_mac_init_prov(pd, pd->pd_sid, mech, key,
490 		    spi_ctx_tmpl, ctxp, crq);
491 	}
492 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
493 	    IS_RECOVERABLE(error)) {
494 		/* Add pd to the linked list of providers tried. */
495 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
496 			goto retry;
497 	}
498 
499 	if (list != NULL)
500 		kcf_free_triedlist(list);
501 
502 	KCF_PROV_REFRELE(pd);
503 	return (error);
504 }
505 
506 /*
507  * crypto_mac_update()
508  *
509  * Arguments:
510  *	context: A crypto_context_t initialized by mac_init().
511  *	data: The message part to be MAC'ed
512  *	cr:	crypto_call_req_t calling conditions and call back info.
513  *
514  * Description:
515  *	Asynchronously submits a request for, or synchronously performs a
516  *	part of a MAC operation.
517  *
518  * Context:
519  *	Process or interrupt, according to the semantics dictated by the 'cr'.
520  *
521  * Returns:
522  *	See comment in the beginning of the file.
523  */
524 int
525 crypto_mac_update(crypto_context_t context, crypto_data_t *data,
526     crypto_call_req_t *cr)
527 {
528 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
529 	kcf_context_t *kcf_ctx;
530 	kcf_provider_desc_t *pd;
531 	kcf_req_params_t params;
532 	int rv;
533 
534 	if ((ctx == NULL) ||
535 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
536 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
537 		return (CRYPTO_INVALID_CONTEXT);
538 	}
539 
540 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
541 
542 	/* The fast path for SW providers. */
543 	if (CHECK_FASTPATH(cr, pd)) {
544 		rv = KCF_PROV_MAC_UPDATE(pd, ctx, data, NULL);
545 		KCF_PROV_INCRSTATS(pd, rv);
546 	} else {
547 		KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_UPDATE,
548 		    ctx->cc_session, NULL, NULL, data, NULL, NULL);
549 		rv = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
550 	}
551 
552 	return (rv);
553 }
554 
555 /*
556  * crypto_mac_final()
557  *
558  * Arguments:
559  *	context: A crypto_context_t initialized by mac_init().
560  *	mac: Storage for the message authentication code.
561  *	cr:	crypto_call_req_t calling conditions and call back info.
562  *
563  * Description:
564  *	Asynchronously submits a request for, or synchronously performs a
565  *	part of a message authentication operation.
566  *
567  * Context:
568  *	Process or interrupt, according to the semantics dictated by the 'cr'.
569  *
570  * Returns:
571  *	See comment in the beginning of the file.
572  */
573 int
574 crypto_mac_final(crypto_context_t context, crypto_data_t *mac,
575     crypto_call_req_t *cr)
576 {
577 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
578 	kcf_context_t *kcf_ctx;
579 	kcf_provider_desc_t *pd;
580 	kcf_req_params_t params;
581 	int rv;
582 
583 	if ((ctx == NULL) ||
584 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
585 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
586 		return (CRYPTO_INVALID_CONTEXT);
587 	}
588 
589 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
590 
591 	/* The fast path for SW providers. */
592 	if (CHECK_FASTPATH(cr, pd)) {
593 		rv = KCF_PROV_MAC_FINAL(pd, ctx, mac, NULL);
594 		KCF_PROV_INCRSTATS(pd, rv);
595 	} else {
596 		KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_FINAL,
597 		    ctx->cc_session, NULL, NULL, NULL, mac, NULL);
598 		rv = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
599 	}
600 
601 	/* Release the hold done in kcf_new_ctx() during init step. */
602 	KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx);
603 	return (rv);
604 }
605 
606 /*
607  * See comments for crypto_mac_update() and crypto_mac_final().
608  */
609 int
610 crypto_mac_single(crypto_context_t context, crypto_data_t *data,
611     crypto_data_t *mac, crypto_call_req_t *cr)
612 {
613 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
614 	kcf_context_t *kcf_ctx;
615 	kcf_provider_desc_t *pd;
616 	int error;
617 	kcf_req_params_t params;
618 
619 
620 	if ((ctx == NULL) ||
621 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
622 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
623 		return (CRYPTO_INVALID_CONTEXT);
624 	}
625 
626 
627 	/* The fast path for SW providers. */
628 	if (CHECK_FASTPATH(cr, pd)) {
629 		error = KCF_PROV_MAC(pd, ctx, data, mac, NULL);
630 		KCF_PROV_INCRSTATS(pd, error);
631 	} else {
632 		KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
633 		    NULL, NULL, data, mac, NULL);
634 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
635 	}
636 
637 	/* Release the hold done in kcf_new_ctx() during init step. */
638 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
639 	return (error);
640 }
641