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