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