17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
572eff6e2Smcpowers  * Common Development and Distribution License (the "License").
672eff6e2Smcpowers  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*9b009fc1SValerie Bubb Fenwick  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/errno.h>
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
287c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
29894b2776Smcpowers #include <sys/sysmacros.h>
307c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
317c478bd9Sstevel@tonic-gate #include <sys/crypto/impl.h>
327c478bd9Sstevel@tonic-gate #include <sys/crypto/api.h>
337c478bd9Sstevel@tonic-gate #include <sys/crypto/spi.h>
347c478bd9Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
357c478bd9Sstevel@tonic-gate 
36894b2776Smcpowers #define	CRYPTO_OPS_OFFSET(f)		offsetof(crypto_ops_t, co_##f)
37894b2776Smcpowers #define	CRYPTO_DIGEST_OFFSET(f)		offsetof(crypto_digest_ops_t, f)
38894b2776Smcpowers 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Message digest routines
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * The following are the possible returned values common to all the routines
457c478bd9Sstevel@tonic-gate  * below. The applicability of some of these return values depends on the
467c478bd9Sstevel@tonic-gate  * presence of the arguments.
477c478bd9Sstevel@tonic-gate  *
487c478bd9Sstevel@tonic-gate  *	CRYPTO_SUCCESS:	The operation completed successfully.
497c478bd9Sstevel@tonic-gate  *	CRYPTO_QUEUED:	A request was submitted successfully. The callback
507c478bd9Sstevel@tonic-gate  *			routine will be called when the operation is done.
517c478bd9Sstevel@tonic-gate  *	CRYPTO_MECHANISM_INVALID or CRYPTO_INVALID_MECH_PARAM
527c478bd9Sstevel@tonic-gate  *			for problems with the 'mech'.
537c478bd9Sstevel@tonic-gate  *	CRYPTO_INVALID_DATA for bogus 'data'
547c478bd9Sstevel@tonic-gate  *	CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
557c478bd9Sstevel@tonic-gate  *	CRYPTO_INVALID_CONTEXT: Not a valid context.
567c478bd9Sstevel@tonic-gate  *	CRYPTO_BUSY:	Cannot process the request now. Schedule a
577c478bd9Sstevel@tonic-gate  *			crypto_bufcall(), or try later.
587c478bd9Sstevel@tonic-gate  *	CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED:
597c478bd9Sstevel@tonic-gate  *			No provider is capable of a function or a mechanism.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * crypto_digest_prov()
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * Arguments:
677c478bd9Sstevel@tonic-gate  *	pd:	pointer to the descriptor of the provider to use for this
687c478bd9Sstevel@tonic-gate  *		operation.
697c478bd9Sstevel@tonic-gate  *	sid:	provider session id.
707c478bd9Sstevel@tonic-gate  *	mech:	crypto_mechanism_t pointer.
717c478bd9Sstevel@tonic-gate  *		mech_type is a valid value previously returned by
727c478bd9Sstevel@tonic-gate  *		crypto_mech2id();
737c478bd9Sstevel@tonic-gate  *		When the mech's parameter is not NULL, its definition depends
747c478bd9Sstevel@tonic-gate  *		on the standard definition of the mechanism.
757c478bd9Sstevel@tonic-gate  *	data:	The message to be digested.
767c478bd9Sstevel@tonic-gate  *	digest:	Storage for the digest. The length needed depends on the
777c478bd9Sstevel@tonic-gate  *		mechanism.
787c478bd9Sstevel@tonic-gate  *	cr:	crypto_call_req_t calling conditions and call back info.
797c478bd9Sstevel@tonic-gate  *
807c478bd9Sstevel@tonic-gate  * Description:
817c478bd9Sstevel@tonic-gate  *	Asynchronously submits a request for, or synchronously performs the
827c478bd9Sstevel@tonic-gate  *	digesting operation of 'data' on the specified
837c478bd9Sstevel@tonic-gate  *	provider with the specified session.
847c478bd9Sstevel@tonic-gate  *	When complete and successful, 'digest' will contain the digest value.
857c478bd9Sstevel@tonic-gate  *	The caller should hold a reference on the specified provider
867c478bd9Sstevel@tonic-gate  *	descriptor before calling this function.
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * Context:
897c478bd9Sstevel@tonic-gate  *	Process or interrupt, according to the semantics dictated by the 'cr'.
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * Returns:
927c478bd9Sstevel@tonic-gate  *	See comment in the beginning of the file.
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate int
crypto_digest_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * crq)95894b2776Smcpowers crypto_digest_prov(crypto_provider_t provider, crypto_session_id_t sid,
96894b2776Smcpowers     crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest,
97894b2776Smcpowers     crypto_call_req_t *crq)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	kcf_req_params_t params;
100894b2776Smcpowers 	kcf_provider_desc_t *pd = provider;
101894b2776Smcpowers 	kcf_provider_desc_t *real_provider = pd;
102894b2776Smcpowers 	int rv;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	ASSERT(KCF_PROV_REFHELD(pd));
105894b2776Smcpowers 
106894b2776Smcpowers 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
107436935a1SVladimir Kotal 		rv = kcf_get_hardware_provider(mech->cm_type, NULL,
108*9b009fc1SValerie Bubb Fenwick 		    CRYPTO_MECH_INVALID, NULL, pd, &real_provider,
109*9b009fc1SValerie Bubb Fenwick 		    CRYPTO_FG_DIGEST_ATOMIC);
110894b2776Smcpowers 
111894b2776Smcpowers 		if (rv != CRYPTO_SUCCESS)
112894b2776Smcpowers 			return (rv);
113894b2776Smcpowers 	}
1147c478bd9Sstevel@tonic-gate 	KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, NULL,
1157c478bd9Sstevel@tonic-gate 	    data, digest);
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	/* no crypto context to carry between multiple parts. */
118894b2776Smcpowers 	rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
119894b2776Smcpowers 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
120894b2776Smcpowers 		KCF_PROV_REFRELE(real_provider);
121894b2776Smcpowers 
122894b2776Smcpowers 	return (rv);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Same as crypto_digest_prov(), but relies on the KCF scheduler to
1277c478bd9Sstevel@tonic-gate  * choose a provider. See crypto_digest_prov() comments for more information.
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate int
crypto_digest(crypto_mechanism_t * mech,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * crq)1307c478bd9Sstevel@tonic-gate crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
1317c478bd9Sstevel@tonic-gate     crypto_data_t *digest, crypto_call_req_t *crq)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	int error;
1347c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
1357c478bd9Sstevel@tonic-gate 	kcf_req_params_t params;
1367c478bd9Sstevel@tonic-gate 	kcf_prov_tried_t *list = NULL;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate retry:
1397c478bd9Sstevel@tonic-gate 	/* The pd is returned held */
140436935a1SVladimir Kotal 	if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, NULL, &error,
141*9b009fc1SValerie Bubb Fenwick 	    list, CRYPTO_FG_DIGEST_ATOMIC, data->cd_length)) == NULL) {
1427c478bd9Sstevel@tonic-gate 		if (list != NULL)
1437c478bd9Sstevel@tonic-gate 			kcf_free_triedlist(list);
1447c478bd9Sstevel@tonic-gate 		return (error);
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	/* The fast path for SW providers. */
1487c478bd9Sstevel@tonic-gate 	if (CHECK_FASTPATH(crq, pd)) {
1497c478bd9Sstevel@tonic-gate 		crypto_mechanism_t lmech;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 		lmech = *mech;
1527c478bd9Sstevel@tonic-gate 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
1537c478bd9Sstevel@tonic-gate 		error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data,
1547c478bd9Sstevel@tonic-gate 		    digest, KCF_SWFP_RHNDL(crq));
1557c478bd9Sstevel@tonic-gate 		KCF_PROV_INCRSTATS(pd, error);
1567c478bd9Sstevel@tonic-gate 	} else {
157ba5f469cSkrishna 		if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
158ba5f469cSkrishna 		    (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
159ba5f469cSkrishna 		    (data->cd_length > pd->pd_hash_limit)) {
160ba5f469cSkrishna 			error = CRYPTO_BUFFER_TOO_BIG;
161ba5f469cSkrishna 		} else {
162ba5f469cSkrishna 			KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC,
163ba5f469cSkrishna 			    pd->pd_sid, mech, NULL, data, digest);
164ba5f469cSkrishna 
165ba5f469cSkrishna 			/* no crypto context to carry between multiple parts. */
166ba5f469cSkrishna 			error = kcf_submit_request(pd, NULL, crq, &params,
167ba5f469cSkrishna 			    B_FALSE);
168ba5f469cSkrishna 		}
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
1727c478bd9Sstevel@tonic-gate 	    IS_RECOVERABLE(error)) {
1737c478bd9Sstevel@tonic-gate 		/* Add pd to the linked list of providers tried. */
1747c478bd9Sstevel@tonic-gate 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
1757c478bd9Sstevel@tonic-gate 			goto retry;
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (list != NULL)
1797c478bd9Sstevel@tonic-gate 		kcf_free_triedlist(list);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	KCF_PROV_REFRELE(pd);
1827c478bd9Sstevel@tonic-gate 	return (error);
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * crypto_digest_init_prov()
1877c478bd9Sstevel@tonic-gate  *
1887c478bd9Sstevel@tonic-gate  *	pd:	pointer to the descriptor of the provider to use for this
1897c478bd9Sstevel@tonic-gate  *		operation.
1907c478bd9Sstevel@tonic-gate  *	sid:	provider session id.
1917c478bd9Sstevel@tonic-gate  *	mech:	crypto_mechanism_t pointer.
1927c478bd9Sstevel@tonic-gate  *		mech_type is a valid value previously returned by
1937c478bd9Sstevel@tonic-gate  *		crypto_mech2id();
1947c478bd9Sstevel@tonic-gate  *		When the mech's parameter is not NULL, its definition depends
1957c478bd9Sstevel@tonic-gate  *		on the standard definition of the mechanism.
1967c478bd9Sstevel@tonic-gate  *	ctxp:	Pointer to a crypto_context_t.
1977c478bd9Sstevel@tonic-gate  *	cr:	crypto_call_req_t calling conditions and call back info.
1987c478bd9Sstevel@tonic-gate  *
1997c478bd9Sstevel@tonic-gate  * Description:
2007c478bd9Sstevel@tonic-gate  *	Asynchronously submits a request for, or synchronously performs the
2017c478bd9Sstevel@tonic-gate  *	initialization of a message digest operation on the specified
2027c478bd9Sstevel@tonic-gate  *	provider with the specified session.
2037c478bd9Sstevel@tonic-gate  *	When complete and successful, 'ctxp' will contain a crypto_context_t
2047c478bd9Sstevel@tonic-gate  *	valid for later calls to digest_update() and digest_final().
2057c478bd9Sstevel@tonic-gate  *	The caller should hold a reference on the specified provider
2067c478bd9Sstevel@tonic-gate  *	descriptor before calling this function.
2077c478bd9Sstevel@tonic-gate  */
2087c478bd9Sstevel@tonic-gate int
crypto_digest_init_prov(crypto_provider_t provider,crypto_session_id_t sid,crypto_mechanism_t * mech,crypto_context_t * ctxp,crypto_call_req_t * crq)209894b2776Smcpowers crypto_digest_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
210894b2776Smcpowers     crypto_mechanism_t *mech, crypto_context_t *ctxp, crypto_call_req_t  *crq)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate 	int error;
2137c478bd9Sstevel@tonic-gate 	crypto_ctx_t *ctx;
2147c478bd9Sstevel@tonic-gate 	kcf_req_params_t params;
215894b2776Smcpowers 	kcf_provider_desc_t *pd = provider;
216894b2776Smcpowers 	kcf_provider_desc_t *real_provider = pd;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	ASSERT(KCF_PROV_REFHELD(pd));
2197c478bd9Sstevel@tonic-gate 
220894b2776Smcpowers 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
221436935a1SVladimir Kotal 		error = kcf_get_hardware_provider(mech->cm_type, NULL,
222*9b009fc1SValerie Bubb Fenwick 		    CRYPTO_MECH_INVALID, NULL, pd, &real_provider,
223*9b009fc1SValerie Bubb Fenwick 		    CRYPTO_FG_DIGEST);
224894b2776Smcpowers 
225894b2776Smcpowers 		if (error != CRYPTO_SUCCESS)
226894b2776Smcpowers 			return (error);
227894b2776Smcpowers 	}
228894b2776Smcpowers 
229894b2776Smcpowers 	/* Allocate and initialize the canonical context */
230894b2776Smcpowers 	if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
231894b2776Smcpowers 		if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
232894b2776Smcpowers 			KCF_PROV_REFRELE(real_provider);
2337c478bd9Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
234894b2776Smcpowers 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/* The fast path for SW providers. */
2377c478bd9Sstevel@tonic-gate 	if (CHECK_FASTPATH(crq, pd)) {
2387c478bd9Sstevel@tonic-gate 		crypto_mechanism_t lmech;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		lmech = *mech;
241894b2776Smcpowers 		KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
242894b2776Smcpowers 		error = KCF_PROV_DIGEST_INIT(real_provider, ctx, &lmech,
2437c478bd9Sstevel@tonic-gate 		    KCF_SWFP_RHNDL(crq));
2447c478bd9Sstevel@tonic-gate 		KCF_PROV_INCRSTATS(pd, error);
2457c478bd9Sstevel@tonic-gate 	} else {
2467c478bd9Sstevel@tonic-gate 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_INIT, sid,
2477c478bd9Sstevel@tonic-gate 		    mech, NULL, NULL, NULL);
248894b2776Smcpowers 		error = kcf_submit_request(real_provider, ctx, crq, &params,
249894b2776Smcpowers 		    B_FALSE);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
252894b2776Smcpowers 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
253894b2776Smcpowers 		KCF_PROV_REFRELE(real_provider);
254894b2776Smcpowers 
2557c478bd9Sstevel@tonic-gate 	if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
2567c478bd9Sstevel@tonic-gate 		*ctxp = (crypto_context_t)ctx;
2577c478bd9Sstevel@tonic-gate 	else {
2587c478bd9Sstevel@tonic-gate 		/* Release the hold done in kcf_new_ctx(). */
2597c478bd9Sstevel@tonic-gate 		KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	return (error);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate  * Same as crypto_digest_init_prov(), but relies on the KCF scheduler
2687c478bd9Sstevel@tonic-gate  * to choose a provider. See crypto_digest_init_prov() comments for
2697c478bd9Sstevel@tonic-gate  * more information.
2707c478bd9Sstevel@tonic-gate  */
2717c478bd9Sstevel@tonic-gate int
crypto_digest_init(crypto_mechanism_t * mech,crypto_context_t * ctxp,crypto_call_req_t * crq)2727c478bd9Sstevel@tonic-gate crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
2737c478bd9Sstevel@tonic-gate     crypto_call_req_t  *crq)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate 	int error;
2767c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
2777c478bd9Sstevel@tonic-gate 	kcf_prov_tried_t *list = NULL;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate retry:
2807c478bd9Sstevel@tonic-gate 	/* The pd is returned held */
281436935a1SVladimir Kotal 	if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, NULL, &error,
282*9b009fc1SValerie Bubb Fenwick 	    list, CRYPTO_FG_DIGEST, 0)) == NULL) {
2837c478bd9Sstevel@tonic-gate 		if (list != NULL)
2847c478bd9Sstevel@tonic-gate 			kcf_free_triedlist(list);
2857c478bd9Sstevel@tonic-gate 		return (error);
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 
288ba5f469cSkrishna 	if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
289ba5f469cSkrishna 	    (pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
290ba5f469cSkrishna 		/*
291ba5f469cSkrishna 		 * The hardware provider has limited digest support.
292ba5f469cSkrishna 		 * So, we fallback early here to using a software provider.
293ba5f469cSkrishna 		 *
294ba5f469cSkrishna 		 * XXX - need to enhance to do the fallback later in
295ba5f469cSkrishna 		 * crypto_digest_update() if the size of accumulated input data
296ba5f469cSkrishna 		 * exceeds the maximum size digestable by hardware provider.
297ba5f469cSkrishna 		 */
298ba5f469cSkrishna 		error = CRYPTO_BUFFER_TOO_BIG;
299ba5f469cSkrishna 	} else {
300ba5f469cSkrishna 		error = crypto_digest_init_prov(pd, pd->pd_sid,
301ba5f469cSkrishna 		    mech, ctxp, crq);
302ba5f469cSkrishna 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
3057c478bd9Sstevel@tonic-gate 	    IS_RECOVERABLE(error)) {
3067c478bd9Sstevel@tonic-gate 		/* Add pd to the linked list of providers tried. */
3077c478bd9Sstevel@tonic-gate 		if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
3087c478bd9Sstevel@tonic-gate 			goto retry;
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	if (list != NULL)
3127c478bd9Sstevel@tonic-gate 		kcf_free_triedlist(list);
3137c478bd9Sstevel@tonic-gate 	KCF_PROV_REFRELE(pd);
3147c478bd9Sstevel@tonic-gate 	return (error);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate  * crypto_digest_update()
3197c478bd9Sstevel@tonic-gate  *
3207c478bd9Sstevel@tonic-gate  * Arguments:
3217c478bd9Sstevel@tonic-gate  *	context: A crypto_context_t initialized by digest_init().
3227c478bd9Sstevel@tonic-gate  *	data:	The part of message to be digested.
3237c478bd9Sstevel@tonic-gate  *	cr:	crypto_call_req_t calling conditions and call back info.
3247c478bd9Sstevel@tonic-gate  *
3257c478bd9Sstevel@tonic-gate  * Description:
3267c478bd9Sstevel@tonic-gate  *	Asynchronously submits a request for, or synchronously performs a
3277c478bd9Sstevel@tonic-gate  *	part of a message digest operation.
3287c478bd9Sstevel@tonic-gate  *
3297c478bd9Sstevel@tonic-gate  * Context:
3307c478bd9Sstevel@tonic-gate  *	Process or interrupt, according to the semantics dictated by the 'cr'.
3317c478bd9Sstevel@tonic-gate  *
3327c478bd9Sstevel@tonic-gate  * Returns:
3337c478bd9Sstevel@tonic-gate  *	See comment in the beginning of the file.
3347c478bd9Sstevel@tonic-gate  */
3357c478bd9Sstevel@tonic-gate int
crypto_digest_update(crypto_context_t context,crypto_data_t * data,crypto_call_req_t * cr)3367c478bd9Sstevel@tonic-gate crypto_digest_update(crypto_context_t context, crypto_data_t *data,
3377c478bd9Sstevel@tonic-gate     crypto_call_req_t *cr)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
3407c478bd9Sstevel@tonic-gate 	kcf_context_t *kcf_ctx;
3417c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
3427c478bd9Sstevel@tonic-gate 	int error;
3437c478bd9Sstevel@tonic-gate 	kcf_req_params_t params;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	if ((ctx == NULL) ||
3467c478bd9Sstevel@tonic-gate 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
3477c478bd9Sstevel@tonic-gate 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
3487c478bd9Sstevel@tonic-gate 		return (CRYPTO_INVALID_CONTEXT);
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
351894b2776Smcpowers 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/* The fast path for SW providers. */
3547c478bd9Sstevel@tonic-gate 	if (CHECK_FASTPATH(cr, pd)) {
3557c478bd9Sstevel@tonic-gate 		error = KCF_PROV_DIGEST_UPDATE(pd, ctx, data, NULL);
3567c478bd9Sstevel@tonic-gate 		KCF_PROV_INCRSTATS(pd, error);
3577c478bd9Sstevel@tonic-gate 	} else {
358894b2776Smcpowers 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_UPDATE,
359894b2776Smcpowers 		    ctx->cc_session, NULL, NULL, data, NULL);
3607c478bd9Sstevel@tonic-gate 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	return (error);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * crypto_digest_final()
3687c478bd9Sstevel@tonic-gate  *
3697c478bd9Sstevel@tonic-gate  * Arguments:
3707c478bd9Sstevel@tonic-gate  *	context: A crypto_context_t initialized by digest_init().
3717c478bd9Sstevel@tonic-gate  *	digest:	The storage for the digest.
3727c478bd9Sstevel@tonic-gate  *	cr:	crypto_call_req_t calling conditions and call back info.
3737c478bd9Sstevel@tonic-gate  *
3747c478bd9Sstevel@tonic-gate  * Description:
3757c478bd9Sstevel@tonic-gate  *	Asynchronously submits a request for, or synchronously performs the
3767c478bd9Sstevel@tonic-gate  *	final part of a message digest operation.
3777c478bd9Sstevel@tonic-gate  *
3787c478bd9Sstevel@tonic-gate  * Context:
3797c478bd9Sstevel@tonic-gate  *	Process or interrupt, according to the semantics dictated by the 'cr'.
3807c478bd9Sstevel@tonic-gate  *
3817c478bd9Sstevel@tonic-gate  * Returns:
3827c478bd9Sstevel@tonic-gate  *	See comment in the beginning of the file.
3837c478bd9Sstevel@tonic-gate  */
3847c478bd9Sstevel@tonic-gate int
crypto_digest_final(crypto_context_t context,crypto_data_t * digest,crypto_call_req_t * cr)3857c478bd9Sstevel@tonic-gate crypto_digest_final(crypto_context_t context, crypto_data_t *digest,
3867c478bd9Sstevel@tonic-gate     crypto_call_req_t *cr)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
3897c478bd9Sstevel@tonic-gate 	kcf_context_t *kcf_ctx;
3907c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
3917c478bd9Sstevel@tonic-gate 	int error;
3927c478bd9Sstevel@tonic-gate 	kcf_req_params_t params;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if ((ctx == NULL) ||
3957c478bd9Sstevel@tonic-gate 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
3967c478bd9Sstevel@tonic-gate 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
3977c478bd9Sstevel@tonic-gate 		return (CRYPTO_INVALID_CONTEXT);
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
400894b2776Smcpowers 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	/* The fast path for SW providers. */
4037c478bd9Sstevel@tonic-gate 	if (CHECK_FASTPATH(cr, pd)) {
4047c478bd9Sstevel@tonic-gate 		error = KCF_PROV_DIGEST_FINAL(pd, ctx, digest, NULL);
4057c478bd9Sstevel@tonic-gate 		KCF_PROV_INCRSTATS(pd, error);
4067c478bd9Sstevel@tonic-gate 	} else {
407894b2776Smcpowers 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_FINAL,
408894b2776Smcpowers 		    ctx->cc_session, NULL, NULL, NULL, digest);
4097c478bd9Sstevel@tonic-gate 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	/* Release the hold done in kcf_new_ctx() during init step. */
4137c478bd9Sstevel@tonic-gate 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
4147c478bd9Sstevel@tonic-gate 	return (error);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate /*
4187c478bd9Sstevel@tonic-gate  * Performs a digest update on the specified key. Note that there is
4197c478bd9Sstevel@tonic-gate  * no k-API crypto_digest_key() equivalent of this function.
4207c478bd9Sstevel@tonic-gate  */
4217c478bd9Sstevel@tonic-gate int
crypto_digest_key_prov(crypto_context_t context,crypto_key_t * key,crypto_call_req_t * cr)4227c478bd9Sstevel@tonic-gate crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key,
4237c478bd9Sstevel@tonic-gate     crypto_call_req_t *cr)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
4267c478bd9Sstevel@tonic-gate 	kcf_context_t *kcf_ctx;
4277c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
4287c478bd9Sstevel@tonic-gate 	int error;
4297c478bd9Sstevel@tonic-gate 	kcf_req_params_t params;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if ((ctx == NULL) ||
4327c478bd9Sstevel@tonic-gate 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
4337c478bd9Sstevel@tonic-gate 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
4347c478bd9Sstevel@tonic-gate 		return (CRYPTO_INVALID_CONTEXT);
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 
437894b2776Smcpowers 	ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/* The fast path for SW providers. */
4407c478bd9Sstevel@tonic-gate 	if (CHECK_FASTPATH(cr, pd)) {
4417c478bd9Sstevel@tonic-gate 		error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL);
4427c478bd9Sstevel@tonic-gate 		KCF_PROV_INCRSTATS(pd, error);
4437c478bd9Sstevel@tonic-gate 	} else {
4447c478bd9Sstevel@tonic-gate 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_DIGEST_KEY,
445894b2776Smcpowers 		    ctx->cc_session, NULL, key, NULL, NULL);
4467c478bd9Sstevel@tonic-gate 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
4477c478bd9Sstevel@tonic-gate 	}
448894b2776Smcpowers 
4497c478bd9Sstevel@tonic-gate 	return (error);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate  * See comments for crypto_digest_update() and crypto_digest_final().
4547c478bd9Sstevel@tonic-gate  */
4557c478bd9Sstevel@tonic-gate int
crypto_digest_single(crypto_context_t context,crypto_data_t * data,crypto_data_t * digest,crypto_call_req_t * cr)4567c478bd9Sstevel@tonic-gate crypto_digest_single(crypto_context_t context, crypto_data_t *data,
4577c478bd9Sstevel@tonic-gate     crypto_data_t *digest, crypto_call_req_t *cr)
4587c478bd9Sstevel@tonic-gate {
4597c478bd9Sstevel@tonic-gate 	crypto_ctx_t *ctx = (crypto_ctx_t *)context;
4607c478bd9Sstevel@tonic-gate 	kcf_context_t *kcf_ctx;
4617c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
4627c478bd9Sstevel@tonic-gate 	int error;
4637c478bd9Sstevel@tonic-gate 	kcf_req_params_t params;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	if ((ctx == NULL) ||
4667c478bd9Sstevel@tonic-gate 	    ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
4677c478bd9Sstevel@tonic-gate 	    ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
4687c478bd9Sstevel@tonic-gate 		return (CRYPTO_INVALID_CONTEXT);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/* The fast path for SW providers. */
4737c478bd9Sstevel@tonic-gate 	if (CHECK_FASTPATH(cr, pd)) {
4747c478bd9Sstevel@tonic-gate 		error = KCF_PROV_DIGEST(pd, ctx, data, digest, NULL);
4757c478bd9Sstevel@tonic-gate 		KCF_PROV_INCRSTATS(pd, error);
4767c478bd9Sstevel@tonic-gate 	} else {
4777c478bd9Sstevel@tonic-gate 		KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
4787c478bd9Sstevel@tonic-gate 		    NULL, NULL, data, digest);
4797c478bd9Sstevel@tonic-gate 		error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/* Release the hold done in kcf_new_ctx() during init step. */
4837c478bd9Sstevel@tonic-gate 	KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
4847c478bd9Sstevel@tonic-gate 	return (error);
4857c478bd9Sstevel@tonic-gate }
486