xref: /titanic_51/usr/src/lib/pkcs11/libpkcs11/common/metaUtil.c (revision 8cae6764ee663bd6a0b140294645a7c2fd8399b8)
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
5034448feSmcpowers  * Common Development and Distribution License (the "License").
6034448feSmcpowers  * 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*8cae6764SAnthony Scarpino  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
277c478bd9Sstevel@tonic-gate #include <errno.h>
287c478bd9Sstevel@tonic-gate #include <fcntl.h>
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <strings.h>
317c478bd9Sstevel@tonic-gate #include "metaGlobal.h"
327c478bd9Sstevel@tonic-gate 
33a039cd31Shaimay extern cipher_mechs_threshold_t	meta_mechs_threshold[];
34cd7d5fafSJan Pechanec static boolean_t threshold_chk_enabled = B_FALSE;
35a039cd31Shaimay 
364a5b2e70Shaimay CK_RV
374a5b2e70Shaimay meta_operation_init_defer(CK_FLAGS optype, meta_session_t *session,
384a5b2e70Shaimay 	CK_MECHANISM *pMechanism, meta_object_t *key)
394a5b2e70Shaimay {
404a5b2e70Shaimay 
414a5b2e70Shaimay 	if (session->init.pMech == NULL) {
424a5b2e70Shaimay 		session->init.pMech = malloc(sizeof (CK_MECHANISM));
434a5b2e70Shaimay 		if (session->init.pMech == NULL)
444a5b2e70Shaimay 			return (CKR_HOST_MEMORY);
454a5b2e70Shaimay 
464a5b2e70Shaimay 		(void) memcpy(session->init.pMech, pMechanism,
474a5b2e70Shaimay 		    sizeof (CK_MECHANISM));
484a5b2e70Shaimay 
494a5b2e70Shaimay 		if ((pMechanism->ulParameterLen > 0) &&
504a5b2e70Shaimay 		    (pMechanism->pParameter != NULL)) {
514a5b2e70Shaimay 			session->init.pMech->pParameter =
524a5b2e70Shaimay 			    malloc(pMechanism->ulParameterLen);
534a5b2e70Shaimay 			if (session->init.pMech->pParameter == NULL) {
544a5b2e70Shaimay 				free(session->init.pMech);
554a5b2e70Shaimay 				session->init.pMech = NULL;
564a5b2e70Shaimay 				return (CKR_HOST_MEMORY);
574a5b2e70Shaimay 			}
584a5b2e70Shaimay 			(void) memcpy(session->init.pMech->pParameter,
594a5b2e70Shaimay 			    pMechanism->pParameter, pMechanism->ulParameterLen);
604a5b2e70Shaimay 		} else {
614a5b2e70Shaimay 			session->init.pMech->pParameter = NULL;
624a5b2e70Shaimay 		}
634a5b2e70Shaimay 	} else { /* reuse it */
644a5b2e70Shaimay 		if ((pMechanism->ulParameterLen > 0) &&
654a5b2e70Shaimay 		    (pMechanism->pParameter != NULL)) {
664a5b2e70Shaimay 			if (pMechanism->ulParameterLen !=
674a5b2e70Shaimay 			    session->init.pMech->ulParameterLen) {
684a5b2e70Shaimay 				if (session->init.pMech->pParameter != NULL)
694a5b2e70Shaimay 					free(session->init.pMech->pParameter);
704a5b2e70Shaimay 				session->init.pMech->pParameter =
714a5b2e70Shaimay 				    malloc(pMechanism->ulParameterLen);
724a5b2e70Shaimay 				if (session->init.pMech->pParameter == NULL) {
734a5b2e70Shaimay 					free(session->init.pMech);
744a5b2e70Shaimay 					session->init.pMech = NULL;
754a5b2e70Shaimay 					return (CKR_HOST_MEMORY);
764a5b2e70Shaimay 				}
774a5b2e70Shaimay 			} /* otherwise reuse it */
784a5b2e70Shaimay 			(void) memcpy(session->init.pMech->pParameter,
794a5b2e70Shaimay 			    pMechanism->pParameter, pMechanism->ulParameterLen);
804a5b2e70Shaimay 		} else {
814a5b2e70Shaimay 			/*
824a5b2e70Shaimay 			 * free the previous pParameter if not yet freed
834a5b2e70Shaimay 			 * because we don't need it now.
844a5b2e70Shaimay 			 */
854a5b2e70Shaimay 			if (session->init.pMech->pParameter != NULL) {
864a5b2e70Shaimay 				free(session->init.pMech->pParameter);
874a5b2e70Shaimay 				session->init.pMech->pParameter = NULL;
884a5b2e70Shaimay 			}
894a5b2e70Shaimay 		}
904a5b2e70Shaimay 		/* copy the rest of data */
914a5b2e70Shaimay 		session->init.pMech->mechanism =
924a5b2e70Shaimay 		    pMechanism->mechanism;
934a5b2e70Shaimay 		session->init.pMech->ulParameterLen =
944a5b2e70Shaimay 		    pMechanism->ulParameterLen;
954a5b2e70Shaimay 	}
964a5b2e70Shaimay 
974a5b2e70Shaimay 	session->init.session = session;
984a5b2e70Shaimay 	session->init.optype = optype;
994a5b2e70Shaimay 	session->init.key = key;
1004a5b2e70Shaimay 	session->init.done = B_FALSE;
1014a5b2e70Shaimay 	session->init.app = B_TRUE;
1024a5b2e70Shaimay 	return (CKR_OK);
1034a5b2e70Shaimay }
1044a5b2e70Shaimay 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * meta_operation_init
1077c478bd9Sstevel@tonic-gate  *
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate CK_RV
110d3a28a55Sdinak meta_operation_init(CK_FLAGS optype, meta_session_t *session,
1117c478bd9Sstevel@tonic-gate 	CK_MECHANISM *pMechanism, meta_object_t *key)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	CK_RV rv, save_rv;
1147c478bd9Sstevel@tonic-gate 	mechinfo_t **supporting_slots;
1157c478bd9Sstevel@tonic-gate 	CK_ULONG slotnum;
1167c478bd9Sstevel@tonic-gate 	unsigned long i, slotCount = 0;
1177c478bd9Sstevel@tonic-gate 	slot_session_t *init_session = NULL;
118d3a28a55Sdinak 	CK_MECHANISM_INFO mech_info;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/*
1217c478bd9Sstevel@tonic-gate 	 * If an operation is already active, cleanup existing operation
1227c478bd9Sstevel@tonic-gate 	 * and start a new one.
1237c478bd9Sstevel@tonic-gate 	 */
124d3a28a55Sdinak 	if (session->op1.type != 0) {
125142e971fShaimay 		CK_MECHANISM mech;
1264a5b2e70Shaimay 		if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
1274a5b2e70Shaimay 		    (optype == CKF_DIGEST)) {
128142e971fShaimay 			mech = *pMechanism;
129142e971fShaimay 
130142e971fShaimay 			if ((pMechanism->ulParameterLen > 0) &&
131142e971fShaimay 			    (pMechanism->pParameter != NULL)) {
132142e971fShaimay 				mech.pParameter =
133142e971fShaimay 				    malloc(pMechanism->ulParameterLen);
134142e971fShaimay 				if (mech.pParameter == NULL) {
135142e971fShaimay 					return (CKR_HOST_MEMORY);
136142e971fShaimay 				}
137142e971fShaimay 				(void) memcpy(mech.pParameter,
138142e971fShaimay 				    pMechanism->pParameter,
139142e971fShaimay 				    pMechanism->ulParameterLen);
140142e971fShaimay 			} else {
141142e971fShaimay 				mech.pParameter = NULL;
142142e971fShaimay 				mech.ulParameterLen = 0;
143142e971fShaimay 			}
144142e971fShaimay 
145142e971fShaimay 			meta_operation_cleanup(session, session->op1.type,
146142e971fShaimay 			    B_FALSE);
1474a5b2e70Shaimay 			rv = meta_operation_init_defer(optype, session,
148142e971fShaimay 			    &mech, key);
149142e971fShaimay 			if (mech.pParameter != NULL) {
150142e971fShaimay 				free(mech.pParameter);
151142e971fShaimay 			}
1524a5b2e70Shaimay 			if (rv != CKR_OK)
1534a5b2e70Shaimay 				return (rv);
154142e971fShaimay 		} else {
155142e971fShaimay 			meta_operation_cleanup(session, session->op1.type,
156142e971fShaimay 			    B_FALSE);
1574a5b2e70Shaimay 		}
158142e971fShaimay 
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 
161d3a28a55Sdinak 	mech_info.flags = optype;
162d3a28a55Sdinak 
1637c478bd9Sstevel@tonic-gate 	/*
1647c478bd9Sstevel@tonic-gate 	 * Get a list of capable slots.
1657c478bd9Sstevel@tonic-gate 	 *
1667c478bd9Sstevel@tonic-gate 	 * If the specified mechanism is used in this session last time,
1677c478bd9Sstevel@tonic-gate 	 * the list of capable slots is already retrieved.  We can save
1687c478bd9Sstevel@tonic-gate 	 * some processing, and just use that list of slots.
1697c478bd9Sstevel@tonic-gate 	 */
1707c478bd9Sstevel@tonic-gate 	if (((session->mech_support_info).mech != pMechanism->mechanism) ||
1717c478bd9Sstevel@tonic-gate 	    ((session->mech_support_info).num_supporting_slots == 0)) {
1727c478bd9Sstevel@tonic-gate 		(session->mech_support_info).mech = pMechanism->mechanism;
1737c478bd9Sstevel@tonic-gate 		rv = meta_mechManager_get_slots(&(session->mech_support_info),
174d3a28a55Sdinak 		    B_FALSE, &mech_info);
1757c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
1767c478bd9Sstevel@tonic-gate 			goto finish;
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	rv = CKR_FUNCTION_FAILED;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* The following 2 assignment is just to make the code more readable */
1837c478bd9Sstevel@tonic-gate 	slotCount = (session->mech_support_info).num_supporting_slots;
1847c478bd9Sstevel@tonic-gate 	supporting_slots = (session->mech_support_info).supporting_slots;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	/* Attempt to initialize operation on slots until one succeeds. */
1877c478bd9Sstevel@tonic-gate 	for (i = 0; i < slotCount; i++) {
1887c478bd9Sstevel@tonic-gate 		slot_object_t *init_key;
1897c478bd9Sstevel@tonic-gate 		CK_SLOT_ID fw_st_id;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 		init_session = NULL;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 		slotnum = supporting_slots[i]->slotnum;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 		/*
1967c478bd9Sstevel@tonic-gate 		 * An actual session with the underlying slot is required
1977c478bd9Sstevel@tonic-gate 		 * for the operation.  When the operation is successfully
1987c478bd9Sstevel@tonic-gate 		 * completed, the underlying session with the slot
1997c478bd9Sstevel@tonic-gate 		 * is not released back to the list of available sessions
2007c478bd9Sstevel@tonic-gate 		 * pool.  This will help if the next operation can
2017c478bd9Sstevel@tonic-gate 		 * also be done on the same slot, because it avoids
2027c478bd9Sstevel@tonic-gate 		 * one extra trip to the session pool to get an idle session.
2037c478bd9Sstevel@tonic-gate 		 * If the operation can't be done on that slot,
2047c478bd9Sstevel@tonic-gate 		 * we release the session back to the session pool then.
2057c478bd9Sstevel@tonic-gate 		 */
2067c478bd9Sstevel@tonic-gate 		if (session->op1.session != NULL) {
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 			if ((session->op1.session)->slotnum == slotnum) {
2097c478bd9Sstevel@tonic-gate 				init_session = session->op1.session;
2107c478bd9Sstevel@tonic-gate 				/*
2117c478bd9Sstevel@tonic-gate 				 * set it to NULL for now, assign it to
2127c478bd9Sstevel@tonic-gate 				 * init_session again if it is successful
2137c478bd9Sstevel@tonic-gate 				 */
2147c478bd9Sstevel@tonic-gate 				session->op1.session = NULL;
2157c478bd9Sstevel@tonic-gate 			} else {
2167c478bd9Sstevel@tonic-gate 				init_session = NULL;
2177c478bd9Sstevel@tonic-gate 			}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 		if (!init_session) {
2227c478bd9Sstevel@tonic-gate 			rv = meta_get_slot_session(slotnum, &init_session,
2237c478bd9Sstevel@tonic-gate 			    session->session_flags);
2247c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
2257c478bd9Sstevel@tonic-gate 				goto loop_cleanup;
2267c478bd9Sstevel@tonic-gate 			}
2277c478bd9Sstevel@tonic-gate 		}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		/* if necessary, ensure a clone of the obj exists in slot */
230d3a28a55Sdinak 		if (optype != CKF_DIGEST) {
2317c478bd9Sstevel@tonic-gate 			rv = meta_object_get_clone(key, slotnum, init_session,
2327c478bd9Sstevel@tonic-gate 			    &init_key);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
2357c478bd9Sstevel@tonic-gate 				goto loop_cleanup;
2367c478bd9Sstevel@tonic-gate 			}
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		fw_st_id = init_session->fw_st_id;
2407c478bd9Sstevel@tonic-gate 		switch (optype) {
241d3a28a55Sdinak 			case CKF_ENCRYPT:
2427c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_EncryptInit(
2437c478bd9Sstevel@tonic-gate 				    init_session->hSession, pMechanism,
2447c478bd9Sstevel@tonic-gate 				    init_key->hObject);
2457c478bd9Sstevel@tonic-gate 				break;
246d3a28a55Sdinak 			case CKF_DECRYPT:
2477c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_DecryptInit(
2487c478bd9Sstevel@tonic-gate 				    init_session->hSession, pMechanism,
2497c478bd9Sstevel@tonic-gate 				    init_key->hObject);
2507c478bd9Sstevel@tonic-gate 				break;
251d3a28a55Sdinak 			case CKF_DIGEST:
2527c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_DigestInit(
2537c478bd9Sstevel@tonic-gate 				    init_session->hSession, pMechanism);
2547c478bd9Sstevel@tonic-gate 				break;
255d3a28a55Sdinak 			case CKF_SIGN:
2567c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_SignInit(
2577c478bd9Sstevel@tonic-gate 				    init_session->hSession, pMechanism,
2587c478bd9Sstevel@tonic-gate 				    init_key->hObject);
2597c478bd9Sstevel@tonic-gate 				break;
260d3a28a55Sdinak 			case CKF_VERIFY:
2617c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_VerifyInit(
2627c478bd9Sstevel@tonic-gate 				    init_session->hSession, pMechanism,
2637c478bd9Sstevel@tonic-gate 				    init_key->hObject);
2647c478bd9Sstevel@tonic-gate 				break;
265d3a28a55Sdinak 			case CKF_SIGN_RECOVER:
2667c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_SignRecoverInit(
2677c478bd9Sstevel@tonic-gate 				    init_session->hSession, pMechanism,
2687c478bd9Sstevel@tonic-gate 				    init_key->hObject);
2697c478bd9Sstevel@tonic-gate 				break;
270d3a28a55Sdinak 			case CKF_VERIFY_RECOVER:
2717c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_VerifyRecoverInit(
2727c478bd9Sstevel@tonic-gate 				    init_session->hSession, pMechanism,
2737c478bd9Sstevel@tonic-gate 				    init_key->hObject);
2747c478bd9Sstevel@tonic-gate 				break;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 			default:
2777c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2787c478bd9Sstevel@tonic-gate 				rv = CKR_FUNCTION_FAILED;
2797c478bd9Sstevel@tonic-gate 				break;
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK)
2837c478bd9Sstevel@tonic-gate 			break;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate loop_cleanup:
2867c478bd9Sstevel@tonic-gate 		if (i == 0) {
2877c478bd9Sstevel@tonic-gate 			save_rv = rv;
2887c478bd9Sstevel@tonic-gate 		}
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 		if (init_session) {
2917c478bd9Sstevel@tonic-gate 			meta_release_slot_session(init_session);
2927c478bd9Sstevel@tonic-gate 			init_session = NULL;
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 		/*
3007c478bd9Sstevel@tonic-gate 		 * If currently stored session is not the one being in use now,
3017c478bd9Sstevel@tonic-gate 		 * release the previous one and store the current one
3027c478bd9Sstevel@tonic-gate 		 */
3037c478bd9Sstevel@tonic-gate 		if ((session->op1.session) &&
3047c478bd9Sstevel@tonic-gate 		    (session->op1.session != init_session)) {
3057c478bd9Sstevel@tonic-gate 			meta_release_slot_session(session->op1.session);
3067c478bd9Sstevel@tonic-gate 		}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 		/* Save the session */
3097c478bd9Sstevel@tonic-gate 		session->op1.session = init_session;
3107c478bd9Sstevel@tonic-gate 		session->op1.type = optype;
3114a5b2e70Shaimay 
3124a5b2e70Shaimay 		session->init.slotnum = slotnum;
3134a5b2e70Shaimay 		session->init.done = B_TRUE;
3147c478bd9Sstevel@tonic-gate 	} else {
3157c478bd9Sstevel@tonic-gate 		rv = save_rv;
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate finish:
3197c478bd9Sstevel@tonic-gate 	return (rv);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3234a5b2e70Shaimay  * meta_operation_init_softtoken()
3244a5b2e70Shaimay  * It will always do the crypto init operation on softtoken slot.
3254a5b2e70Shaimay  */
3264a5b2e70Shaimay CK_RV
3274a5b2e70Shaimay meta_operation_init_softtoken(CK_FLAGS optype, meta_session_t *session,
3284a5b2e70Shaimay 	CK_MECHANISM *pMechanism, meta_object_t *key)
3294a5b2e70Shaimay {
3304a5b2e70Shaimay 	CK_RV rv = CKR_FUNCTION_FAILED;
3314a5b2e70Shaimay 	slot_session_t *init_session = NULL;
3324a5b2e70Shaimay 	slot_object_t *init_key;
3334a5b2e70Shaimay 	CK_SLOT_ID fw_st_id;
3344a5b2e70Shaimay 	CK_ULONG softtoken_slot_num;
3354a5b2e70Shaimay 
3364a5b2e70Shaimay 	softtoken_slot_num = get_softtoken_slotnum();
3374a5b2e70Shaimay 	/*
3384a5b2e70Shaimay 	 * If an operation is already active, cleanup existing operation
3394a5b2e70Shaimay 	 * and start a new one.
3404a5b2e70Shaimay 	 */
3414a5b2e70Shaimay 	if (session->op1.type != 0) {
342142e971fShaimay 		CK_MECHANISM mech;
343142e971fShaimay 		mech = *pMechanism;
344142e971fShaimay 
345142e971fShaimay 		if ((pMechanism->ulParameterLen > 0) &&
346142e971fShaimay 		    (pMechanism->pParameter != NULL)) {
347142e971fShaimay 			mech.pParameter =
348142e971fShaimay 			    malloc(pMechanism->ulParameterLen);
349142e971fShaimay 			if (mech.pParameter == NULL) {
350142e971fShaimay 				return (CKR_HOST_MEMORY);
351142e971fShaimay 			}
352142e971fShaimay 			(void) memcpy(mech.pParameter,
353142e971fShaimay 			    pMechanism->pParameter, pMechanism->ulParameterLen);
354142e971fShaimay 		} else {
355142e971fShaimay 			mech.pParameter = NULL;
356142e971fShaimay 			mech.ulParameterLen = 0;
357142e971fShaimay 		}
358142e971fShaimay 
3594a5b2e70Shaimay 		meta_operation_cleanup(session, session->op1.type, B_FALSE);
360142e971fShaimay 		rv = meta_operation_init_defer(optype, session, &mech,
3614a5b2e70Shaimay 		    key);
362142e971fShaimay 		if (mech.pParameter != NULL) {
363142e971fShaimay 			free(mech.pParameter);
364142e971fShaimay 		}
3654a5b2e70Shaimay 		if (rv != CKR_OK)
3664a5b2e70Shaimay 			return (rv);
3674a5b2e70Shaimay 	}
3684a5b2e70Shaimay 
3694a5b2e70Shaimay 	/*
3704a5b2e70Shaimay 	 * An actual session with the underlying slot is required
3714a5b2e70Shaimay 	 * for the operation.  When the operation is successfully
3724a5b2e70Shaimay 	 * completed, the underlying session with the slot
3734a5b2e70Shaimay 	 * is not released back to the list of available sessions
3744a5b2e70Shaimay 	 * pool.  This will help if the next operation can
3754a5b2e70Shaimay 	 * also be done on the same slot, because it avoids
3764a5b2e70Shaimay 	 * one extra trip to the session pool to get an idle session.
3774a5b2e70Shaimay 	 * If the operation can't be done on that slot,
3784a5b2e70Shaimay 	 * we release the session back to the session pool.
3794a5b2e70Shaimay 	 */
3804a5b2e70Shaimay 	if (session->op1.session != NULL) {
3814a5b2e70Shaimay 		if ((session->op1.session)->slotnum ==
3824a5b2e70Shaimay 		    softtoken_slot_num) {
3834a5b2e70Shaimay 			init_session = session->op1.session;
3844a5b2e70Shaimay 			/*
3854a5b2e70Shaimay 			 * set it to NULL for now, assign it to
3864a5b2e70Shaimay 			 * init_session again if it is successful
3874a5b2e70Shaimay 			 */
3884a5b2e70Shaimay 			session->op1.session = NULL;
3894a5b2e70Shaimay 		} else {
3904a5b2e70Shaimay 			init_session = NULL;
3914a5b2e70Shaimay 		}
3924a5b2e70Shaimay 	}
3934a5b2e70Shaimay 
3944a5b2e70Shaimay 	if (init_session == NULL) {
3954a5b2e70Shaimay 		/* get the active session from softtoken slot */
3964a5b2e70Shaimay 		rv = meta_get_slot_session(softtoken_slot_num,
3974a5b2e70Shaimay 		    &init_session, session->session_flags);
3984a5b2e70Shaimay 		if (rv != CKR_OK) {
3994a5b2e70Shaimay 			goto finish;
4004a5b2e70Shaimay 		}
4014a5b2e70Shaimay 	}
4024a5b2e70Shaimay 
4034a5b2e70Shaimay 	/* if necessary, ensure a clone of the obj exists in softtoken slot */
4044a5b2e70Shaimay 	if (optype != CKF_DIGEST) {
4054a5b2e70Shaimay 		rv = meta_object_get_clone(key, softtoken_slot_num,
4064a5b2e70Shaimay 		    init_session, &init_key);
4074a5b2e70Shaimay 
4084a5b2e70Shaimay 		if (rv != CKR_OK) {
4094a5b2e70Shaimay 			if (init_session != NULL) {
4104a5b2e70Shaimay 				meta_release_slot_session(init_session);
4114a5b2e70Shaimay 				init_session = NULL;
4124a5b2e70Shaimay 			}
4134a5b2e70Shaimay 			goto finish;
4144a5b2e70Shaimay 		}
4154a5b2e70Shaimay 	}
4164a5b2e70Shaimay 
4174a5b2e70Shaimay 	fw_st_id = init_session->fw_st_id;
4184a5b2e70Shaimay 
4194a5b2e70Shaimay 	/*
4204a5b2e70Shaimay 	 * Currently, we only support offloading encrypt, decrypt
4214a5b2e70Shaimay 	 * and digest operations to softtoken based on kernel
4224a5b2e70Shaimay 	 * threshold for the supported mechanisms.
4234a5b2e70Shaimay 	 */
4244a5b2e70Shaimay 	switch (optype) {
4254a5b2e70Shaimay 		case CKF_ENCRYPT:
4264a5b2e70Shaimay 			rv = FUNCLIST(fw_st_id)->C_EncryptInit(
4274a5b2e70Shaimay 			    init_session->hSession, pMechanism,
4284a5b2e70Shaimay 			    init_key->hObject);
4294a5b2e70Shaimay 			break;
4304a5b2e70Shaimay 		case CKF_DECRYPT:
4314a5b2e70Shaimay 			rv = FUNCLIST(fw_st_id)->C_DecryptInit(
4324a5b2e70Shaimay 			    init_session->hSession, pMechanism,
4334a5b2e70Shaimay 			    init_key->hObject);
4344a5b2e70Shaimay 			break;
4354a5b2e70Shaimay 		case CKF_DIGEST:
4364a5b2e70Shaimay 			rv = FUNCLIST(fw_st_id)->C_DigestInit(
4374a5b2e70Shaimay 			    init_session->hSession, pMechanism);
4384a5b2e70Shaimay 			break;
4394a5b2e70Shaimay 
4404a5b2e70Shaimay 		default:
4414a5b2e70Shaimay 			/*NOTREACHED*/
4424a5b2e70Shaimay 			rv = CKR_FUNCTION_FAILED;
4434a5b2e70Shaimay 			break;
4444a5b2e70Shaimay 	}
4454a5b2e70Shaimay 
4464a5b2e70Shaimay 	if (rv == CKR_OK) {
4474a5b2e70Shaimay 
4484a5b2e70Shaimay 		/*
4494a5b2e70Shaimay 		 * If currently stored session is not the one being in use now,
4504a5b2e70Shaimay 		 * release the previous one and store the current one
4514a5b2e70Shaimay 		 */
4524a5b2e70Shaimay 		if ((session->op1.session) &&
4534a5b2e70Shaimay 		    (session->op1.session != init_session)) {
4544a5b2e70Shaimay 			meta_release_slot_session(session->op1.session);
4554a5b2e70Shaimay 		}
4564a5b2e70Shaimay 
4574a5b2e70Shaimay 		/* Save the session */
4584a5b2e70Shaimay 		session->op1.session = init_session;
4594a5b2e70Shaimay 		session->op1.type = optype;
4604a5b2e70Shaimay 		/*
4614a5b2e70Shaimay 		 * The init.done flag will be checked by the meta_do_operation()
4624a5b2e70Shaimay 		 * to indicate whether the C_xxxInit has been done against
4634a5b2e70Shaimay 		 * softtoken.
4644a5b2e70Shaimay 		 */
4654a5b2e70Shaimay 		session->init.done = B_TRUE;
4664a5b2e70Shaimay 		session->init.slotnum = softtoken_slot_num;
4674a5b2e70Shaimay 	}
4684a5b2e70Shaimay 
4694a5b2e70Shaimay finish:
4704a5b2e70Shaimay 	return (rv);
4714a5b2e70Shaimay }
4724a5b2e70Shaimay 
473a039cd31Shaimay int
474a039cd31Shaimay meta_GetThreshold(CK_MECHANISM_TYPE mechanism)
475a039cd31Shaimay {
476a039cd31Shaimay 
477a039cd31Shaimay 	int i;
478a039cd31Shaimay 
479a039cd31Shaimay 	for (i = 0; i < MAX_NUM_THRESHOLD; i++) {
480a039cd31Shaimay 		if (mechanism == meta_mechs_threshold[i].mech_type)
481a039cd31Shaimay 			return (meta_mechs_threshold[i].mech_threshold);
482a039cd31Shaimay 	}
483a039cd31Shaimay 
484a039cd31Shaimay 	/* no matching mechanism */
485a039cd31Shaimay 	return (0);
486a039cd31Shaimay }
487a039cd31Shaimay 
4884a5b2e70Shaimay /*
4897c478bd9Sstevel@tonic-gate  * meta_do_operation
4907c478bd9Sstevel@tonic-gate  *
4917c478bd9Sstevel@tonic-gate  * NOTES:
4927c478bd9Sstevel@tonic-gate  *
4937c478bd9Sstevel@tonic-gate  * 1) The spec says you cannot do a C_Encrypt after a C_EncUpdate,
4947c478bd9Sstevel@tonic-gate  *    but we don't explicitly enforce it here (ie, disallow doing MODE_SINGLE
4957c478bd9Sstevel@tonic-gate  *    after a MODE_UPDATE). Instead, we just assume the underlying provider
4967c478bd9Sstevel@tonic-gate  *    will catch the problem and return an appropriate error.
4977c478bd9Sstevel@tonic-gate  *
4987c478bd9Sstevel@tonic-gate  * 2) Note that the Verify operations are a little unusual, due to the
4997c478bd9Sstevel@tonic-gate  *    PKCS#11 API. For C_Verify, the last two arguments are used as inputs,
5007c478bd9Sstevel@tonic-gate  *    unlike the other single pass operations (where they are outputs). For
5017c478bd9Sstevel@tonic-gate  *    C_VerifyFinal, in/inLen are passed instead of out/outLen like the other
5027c478bd9Sstevel@tonic-gate  *    Final operations.
5037c478bd9Sstevel@tonic-gate  *
5047c478bd9Sstevel@tonic-gate  * 3) C_DigestKey is the only crypto operation that uses an object after
5057c478bd9Sstevel@tonic-gate  *    the operation has been initialized. No other callers should provide
5067c478bd9Sstevel@tonic-gate  *    this argument (use NULL).
5077c478bd9Sstevel@tonic-gate  */
5087c478bd9Sstevel@tonic-gate CK_RV
509d3a28a55Sdinak meta_do_operation(CK_FLAGS optype, int mode,
5107c478bd9Sstevel@tonic-gate     meta_session_t *session, meta_object_t *object,
5117c478bd9Sstevel@tonic-gate     CK_BYTE *in, CK_ULONG inLen, CK_BYTE *out, CK_ULONG *outLen)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	CK_RV rv;
5147c478bd9Sstevel@tonic-gate 	CK_SESSION_HANDLE hSession;
5157c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id;
5167c478bd9Sstevel@tonic-gate 	slot_session_t *slot_session = NULL;
5177c478bd9Sstevel@tonic-gate 	slot_object_t *slot_object = NULL;
5184a5b2e70Shaimay 	int threshold = 0;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	boolean_t shutdown, finished_normally;
5217c478bd9Sstevel@tonic-gate 
5224a5b2e70Shaimay 	/*
5234a5b2e70Shaimay 	 * We've deferred the init for encrypt, decrypt and digest
5244a5b2e70Shaimay 	 * operations. As we know the size of the input data now, we
5254a5b2e70Shaimay 	 * can decide where to perform the real init operation based
5264a5b2e70Shaimay 	 * on the kernel cipher-specific thresholds for certain
5274a5b2e70Shaimay 	 * supported mechanisms.
5284a5b2e70Shaimay 	 */
5294a5b2e70Shaimay 	if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
5304a5b2e70Shaimay 	    (optype == CKF_DIGEST)) {
5314a5b2e70Shaimay 		if (Tmp_GetThreshold != NULL) {
5324a5b2e70Shaimay 			if (!session->init.app) {
5334a5b2e70Shaimay 				return (CKR_OPERATION_NOT_INITIALIZED);
5344a5b2e70Shaimay 			}
535a039cd31Shaimay 			threshold = meta_GetThreshold(
5364a5b2e70Shaimay 			    session->init.pMech->mechanism);
5374a5b2e70Shaimay 		}
5384a5b2e70Shaimay 
539cd7d5fafSJan Pechanec 		if ((threshold_chk_enabled == B_FALSE) || (inLen > threshold)) {
5404a5b2e70Shaimay 			if ((session->init.app) && (!session->init.done)) {
5414a5b2e70Shaimay 				/*
5424a5b2e70Shaimay 				 * Call real init operation only if the
5434a5b2e70Shaimay 				 * application has called C_xxxInit
5444a5b2e70Shaimay 				 * but the real init operation has not
5454a5b2e70Shaimay 				 * been done.
5464a5b2e70Shaimay 				 */
5474a5b2e70Shaimay 				rv = meta_operation_init(optype,
5484a5b2e70Shaimay 				    session->init.session,
5494a5b2e70Shaimay 				    session->init.pMech,
5504a5b2e70Shaimay 				    session->init.key);
5514a5b2e70Shaimay 				if (rv != CKR_OK)
5524a5b2e70Shaimay 					goto exit;
5534a5b2e70Shaimay 			} else if (!session->init.app) {
5544a5b2e70Shaimay 				/*
5554a5b2e70Shaimay 				 * This checking detects the case that
5564a5b2e70Shaimay 				 * application calls C_En(De)Crypt/Digest
5574a5b2e70Shaimay 				 * directly without calling C_xxxInit.
5584a5b2e70Shaimay 				 */
5594a5b2e70Shaimay 				return (CKR_OPERATION_NOT_INITIALIZED);
5604a5b2e70Shaimay 			}
5614a5b2e70Shaimay 		} else {
5624a5b2e70Shaimay 			/*
5634a5b2e70Shaimay 			 * The size of the input data is smaller than the
5644a5b2e70Shaimay 			 * threshold so we'll use softoken to perform the
5654a5b2e70Shaimay 			 * crypto operation for better performance reason.
5664a5b2e70Shaimay 			 */
5674a5b2e70Shaimay 			if ((session->init.app) && (!session->init.done))  {
5684a5b2e70Shaimay 				/*
5694a5b2e70Shaimay 				 * Call real init operation only if the
5704a5b2e70Shaimay 				 * application has called C_xxxInit
5714a5b2e70Shaimay 				 * but the real init operation has not
5724a5b2e70Shaimay 				 * been done.
5734a5b2e70Shaimay 				 */
5744a5b2e70Shaimay 				rv = meta_operation_init_softtoken(optype,
5754a5b2e70Shaimay 				    session->init.session,
5764a5b2e70Shaimay 				    session->init.pMech,
5774a5b2e70Shaimay 				    session->init.key);
5784a5b2e70Shaimay 				if (rv != CKR_OK) {
5794a5b2e70Shaimay 					/*
5804a5b2e70Shaimay 					 * In case the operation fails in
5814a5b2e70Shaimay 					 * softtoken, go back to use the
5824a5b2e70Shaimay 					 * original slot again.
5834a5b2e70Shaimay 					 */
5844a5b2e70Shaimay 					rv = meta_operation_init(optype,
5854a5b2e70Shaimay 					    session->init.session,
5864a5b2e70Shaimay 					    session->init.pMech,
5874a5b2e70Shaimay 					    session->init.key);
5884a5b2e70Shaimay 					if (rv != CKR_OK)
5894a5b2e70Shaimay 						goto exit;
5904a5b2e70Shaimay 				}
5914a5b2e70Shaimay 			} else if (!session->init.app) {
5924a5b2e70Shaimay 				/*
5934a5b2e70Shaimay 				 * This checking detects the case that
5944a5b2e70Shaimay 				 * application calls C_En(De)Crypt/Digest
5954a5b2e70Shaimay 				 * directly without calling C_xxxInit.
5964a5b2e70Shaimay 				 */
5974a5b2e70Shaimay 				return (CKR_OPERATION_NOT_INITIALIZED);
5984a5b2e70Shaimay 			}
5994a5b2e70Shaimay 		}
6004a5b2e70Shaimay 	} else if (optype != session->op1.type) {
6017c478bd9Sstevel@tonic-gate 			return (CKR_OPERATION_NOT_INITIALIZED);
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	slot_session = session->op1.session;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	if (slot_session) {
6077c478bd9Sstevel@tonic-gate 		hSession = slot_session->hSession;
6087c478bd9Sstevel@tonic-gate 		fw_st_id = slot_session->fw_st_id;
6097c478bd9Sstevel@tonic-gate 	} else {
6107c478bd9Sstevel@tonic-gate 		/* should never be here */
6114a5b2e70Shaimay 		rv = CKR_FUNCTION_FAILED;
6124a5b2e70Shaimay 		goto exit;
6137c478bd9Sstevel@tonic-gate 	}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	/* Do the operation... */
616d3a28a55Sdinak 	if (optype == CKF_ENCRYPT && mode == MODE_SINGLE) {
6177c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_Encrypt(hSession, in,
6187c478bd9Sstevel@tonic-gate 			    inLen, out, outLen);
619d3a28a55Sdinak 	} else if (optype == CKF_ENCRYPT && mode == MODE_UPDATE) {
6207c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, in,
6217c478bd9Sstevel@tonic-gate 			    inLen, out, outLen);
622d3a28a55Sdinak 	} else if (optype == CKF_ENCRYPT && mode == MODE_FINAL) {
6237c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_EncryptFinal(hSession, out,
6247c478bd9Sstevel@tonic-gate 			    outLen);
6257c478bd9Sstevel@tonic-gate 
626d3a28a55Sdinak 	} else if (optype == CKF_DECRYPT && mode == MODE_SINGLE) {
6277c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_Decrypt(hSession, in,
6287c478bd9Sstevel@tonic-gate 			    inLen, out, outLen);
629d3a28a55Sdinak 	} else if (optype == CKF_DECRYPT && mode == MODE_UPDATE) {
6307c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, in,
6317c478bd9Sstevel@tonic-gate 			    inLen, out, outLen);
632d3a28a55Sdinak 	} else if (optype == CKF_DECRYPT && mode == MODE_FINAL) {
6337c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_DecryptFinal(hSession, out,
6347c478bd9Sstevel@tonic-gate 			    outLen);
6357c478bd9Sstevel@tonic-gate 
636d3a28a55Sdinak 	} else if (optype == CKF_DIGEST && mode == MODE_SINGLE) {
6377c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_Digest(hSession, in, inLen,
6387c478bd9Sstevel@tonic-gate 			    out, outLen);
639d3a28a55Sdinak 	} else if (optype == CKF_DIGEST && mode == MODE_UPDATE) {
6407c478bd9Sstevel@tonic-gate 			/* noOutputForOp = TRUE; */
6417c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, in,
6427c478bd9Sstevel@tonic-gate 			    inLen);
643d3a28a55Sdinak 	} else if (optype == CKF_DIGEST && mode == MODE_UPDATE_WITHKEY) {
6447c478bd9Sstevel@tonic-gate 			/* noOutputForOp = TRUE; */
6457c478bd9Sstevel@tonic-gate 			/*
6467c478bd9Sstevel@tonic-gate 			 * For C_DigestKey, a key is provided and
6477c478bd9Sstevel@tonic-gate 			 * we need the clone.
6487c478bd9Sstevel@tonic-gate 			 */
6497c478bd9Sstevel@tonic-gate 			rv = meta_object_get_clone(object,
6507c478bd9Sstevel@tonic-gate 			    slot_session->slotnum, slot_session, &slot_object);
6517c478bd9Sstevel@tonic-gate 			if (rv == CKR_OK)
6527c478bd9Sstevel@tonic-gate 				rv = FUNCLIST(fw_st_id)->C_DigestKey(hSession,
6537c478bd9Sstevel@tonic-gate 				    slot_object->hObject);
654d3a28a55Sdinak 	} else if (optype == CKF_DIGEST && mode == MODE_FINAL) {
6557c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_DigestFinal(hSession, out,
6567c478bd9Sstevel@tonic-gate 			    outLen);
6577c478bd9Sstevel@tonic-gate 
658d3a28a55Sdinak 	} else if (optype == CKF_SIGN && mode == MODE_SINGLE) {
6597c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_Sign(hSession, in, inLen,
6607c478bd9Sstevel@tonic-gate 			    out, outLen);
661d3a28a55Sdinak 	} else if (optype == CKF_SIGN && mode == MODE_UPDATE) {
6627c478bd9Sstevel@tonic-gate 			/* noOutputForOp = TRUE; */
6637c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_SignUpdate(hSession, in,
6647c478bd9Sstevel@tonic-gate 			    inLen);
665d3a28a55Sdinak 	} else if (optype == CKF_SIGN && mode == MODE_FINAL) {
6667c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_SignFinal(hSession, out,
6677c478bd9Sstevel@tonic-gate 			    outLen);
6687c478bd9Sstevel@tonic-gate 
669d3a28a55Sdinak 	} else if (optype == CKF_VERIFY && mode == MODE_SINGLE) {
6707c478bd9Sstevel@tonic-gate 			/* noOutputForOp = TRUE; */
6717c478bd9Sstevel@tonic-gate 			/* Yes, use *outLen not outLen (think in2/in2Len) */
6727c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_Verify(hSession, in,
6737c478bd9Sstevel@tonic-gate 			    inLen, out, *outLen);
674d3a28a55Sdinak 	} else if (optype == CKF_VERIFY && mode == MODE_UPDATE) {
6757c478bd9Sstevel@tonic-gate 			/* noOutputForOp = TRUE; */
6767c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, in,
6777c478bd9Sstevel@tonic-gate 			    inLen);
678d3a28a55Sdinak 	} else if (optype == CKF_VERIFY && mode == MODE_FINAL) {
6797c478bd9Sstevel@tonic-gate 			/* noOutputForOp = TRUE; */
6807c478bd9Sstevel@tonic-gate 			/* Yes, use in/inLen instead of out/outLen */
6817c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_VerifyFinal(hSession, in,
6827c478bd9Sstevel@tonic-gate 			    inLen);
6837c478bd9Sstevel@tonic-gate 
684d3a28a55Sdinak 	} else if (optype == CKF_SIGN_RECOVER && mode == MODE_SINGLE) {
6857c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_SignRecover(hSession, in,
6867c478bd9Sstevel@tonic-gate 			    inLen, out, outLen);
687d3a28a55Sdinak 	} else if (optype == CKF_VERIFY_RECOVER && mode == MODE_SINGLE) {
6887c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, in,
6897c478bd9Sstevel@tonic-gate 			    inLen, out, outLen);
6907c478bd9Sstevel@tonic-gate 
691d3a28a55Sdinak 	} else {
6927c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/*
6977c478bd9Sstevel@tonic-gate 	 * Mark the operation type as inactive if an abnormal error
6987c478bd9Sstevel@tonic-gate 	 * happens, or if the operation normally results in an inactive
6997c478bd9Sstevel@tonic-gate 	 * operation state.
7007c478bd9Sstevel@tonic-gate 	 *
7017c478bd9Sstevel@tonic-gate 	 * NOTE: The spec isn't very explicit about what happens when you
7027c478bd9Sstevel@tonic-gate 	 * call C_FooFinal (or C_Foo) with a NULL output buffer (to get the
7037c478bd9Sstevel@tonic-gate 	 * output size), but there is no output. Technically this should be
7047c478bd9Sstevel@tonic-gate 	 * no different than the normal case (ie, when there is output), and
7057c478bd9Sstevel@tonic-gate 	 * the operation should remain active until the second call actually
7067c478bd9Sstevel@tonic-gate 	 * terminates it. However, one could make the case that there is no
7077c478bd9Sstevel@tonic-gate 	 * need for a second call, since no data is available. This presents
7087c478bd9Sstevel@tonic-gate 	 * dilemma for metaslot, because we don't know if the operation is
7097c478bd9Sstevel@tonic-gate 	 * going to remain active or not. We will assume a strict reading of
7107c478bd9Sstevel@tonic-gate 	 * the spec, the operation will remain active.
7117c478bd9Sstevel@tonic-gate 	 */
7124a5b2e70Shaimay exit:
7137c478bd9Sstevel@tonic-gate 	if (rv == CKR_BUFFER_TOO_SMALL ||
714d3a28a55Sdinak 	    (rv == CKR_OK && out == NULL && optype != CKF_VERIFY)) {
7157c478bd9Sstevel@tonic-gate 		/* Leave op active for retry (with larger buffer). */
7167c478bd9Sstevel@tonic-gate 		shutdown = B_FALSE;
7177c478bd9Sstevel@tonic-gate 	} else if (rv != CKR_OK) {
7187c478bd9Sstevel@tonic-gate 		shutdown = B_TRUE;
7197c478bd9Sstevel@tonic-gate 		finished_normally = B_FALSE;
7207c478bd9Sstevel@tonic-gate 	} else { /* CKR_OK */
7217c478bd9Sstevel@tonic-gate 		if (mode == MODE_SINGLE || mode == MODE_FINAL) {
7227c478bd9Sstevel@tonic-gate 			shutdown = B_TRUE;
7237c478bd9Sstevel@tonic-gate 			finished_normally = B_TRUE;
7247c478bd9Sstevel@tonic-gate 		} else { /* mode == MODE_UPDATE */
7257c478bd9Sstevel@tonic-gate 			shutdown = B_FALSE;
7267c478bd9Sstevel@tonic-gate 		}
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 
7294a5b2e70Shaimay 	if (shutdown) {
7304a5b2e70Shaimay 		if (mode == MODE_SINGLE || mode == MODE_FINAL) {
7314a5b2e70Shaimay 			session->init.app = B_FALSE;
7324a5b2e70Shaimay 		}
7334a5b2e70Shaimay 
7347c478bd9Sstevel@tonic-gate 		meta_operation_cleanup(session, optype, finished_normally);
7354a5b2e70Shaimay 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	return (rv);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate 
7404a5b2e70Shaimay void
7414a5b2e70Shaimay free_session_mechanism(meta_session_t *session)
7424a5b2e70Shaimay {
7434a5b2e70Shaimay 	if (session->init.pMech != NULL) {
7444a5b2e70Shaimay 		if (session->init.pMech->pParameter != NULL) {
7454a5b2e70Shaimay 			free(session->init.pMech->pParameter);
7464a5b2e70Shaimay 			session->init.pMech->pParameter = NULL;
747f2b9e082Shaimay 			session->init.pMech->ulParameterLen = 0;
7484a5b2e70Shaimay 		}
7494a5b2e70Shaimay 		free(session->init.pMech);
7504a5b2e70Shaimay 		session->init.pMech = NULL;
7514a5b2e70Shaimay 	}
7524a5b2e70Shaimay }
7534a5b2e70Shaimay 
7547c478bd9Sstevel@tonic-gate /*
7557c478bd9Sstevel@tonic-gate  * meta_operation_cleanup
7567c478bd9Sstevel@tonic-gate  *
7577c478bd9Sstevel@tonic-gate  * Cleans up an operation in the specified session.
7587c478bd9Sstevel@tonic-gate  * If the operation did not finish normally, it will force
7597c478bd9Sstevel@tonic-gate  * the operation to terminate.
7607c478bd9Sstevel@tonic-gate  */
7617c478bd9Sstevel@tonic-gate void
762d3a28a55Sdinak meta_operation_cleanup(meta_session_t *session, CK_FLAGS optype,
7637c478bd9Sstevel@tonic-gate     boolean_t finished_normally)
7647c478bd9Sstevel@tonic-gate {
7657c478bd9Sstevel@tonic-gate 	operation_info_t *op;
7667c478bd9Sstevel@tonic-gate 	CK_SESSION_HANDLE hSession;
7677c478bd9Sstevel@tonic-gate 	CK_SLOT_ID fw_st_id;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	if (!finished_normally) {
7707c478bd9Sstevel@tonic-gate 		CK_BYTE dummy_buf[8];
7717c478bd9Sstevel@tonic-gate 
7724a5b2e70Shaimay 		if (session->op1.type == optype) {
7737c478bd9Sstevel@tonic-gate 			op = &session->op1;
7744a5b2e70Shaimay 		} else {
7754a5b2e70Shaimay 			if ((optype == CKF_ENCRYPT) ||
7764a5b2e70Shaimay 			    (optype == CKF_DECRYPT) ||
7774a5b2e70Shaimay 			    (optype == CKF_DIGEST)) {
7784a5b2e70Shaimay 				session->op1.type = 0;
7794a5b2e70Shaimay 				session->init.app = B_FALSE;
7804a5b2e70Shaimay 				session->init.done = B_FALSE;
7814a5b2e70Shaimay 				free_session_mechanism(session);
7824a5b2e70Shaimay 			}
7837c478bd9Sstevel@tonic-gate 			return;
7844a5b2e70Shaimay 		}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 		hSession = op->session->hSession;
7877c478bd9Sstevel@tonic-gate 		fw_st_id = op->session->fw_st_id;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		/*
7907c478bd9Sstevel@tonic-gate 		 * There's no simple, reliable way to abort an
7917c478bd9Sstevel@tonic-gate 		 * operation. So, we'll force the operation to finish.
7927c478bd9Sstevel@tonic-gate 		 *
7937c478bd9Sstevel@tonic-gate 		 * We are here either because we need to abort either after
7947c478bd9Sstevel@tonic-gate 		 * C_xxxxxInit() or C_xxxxxUpdate().
7957c478bd9Sstevel@tonic-gate 		 *
7967c478bd9Sstevel@tonic-gate 		 * We will call C_xxxxxUpdate() with invalid argument to
7977c478bd9Sstevel@tonic-gate 		 * force the operation to abort.  According to the PKCS#11
7987c478bd9Sstevel@tonic-gate 		 * spec, any call to C_xxxxxUpdate() returns in an error
7997c478bd9Sstevel@tonic-gate 		 * will terminate the current operation.
8007c478bd9Sstevel@tonic-gate 		 */
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 		switch (optype) {
803d3a28a55Sdinak 		case CKF_ENCRYPT:
8047c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession,
8057c478bd9Sstevel@tonic-gate 			    NULL, 8, dummy_buf, NULL);
8067c478bd9Sstevel@tonic-gate 			break;
807d3a28a55Sdinak 		case CKF_DECRYPT:
8087c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession,
8097c478bd9Sstevel@tonic-gate 			    NULL, 8, dummy_buf, NULL);
8107c478bd9Sstevel@tonic-gate 			break;
811d3a28a55Sdinak 		case CKF_DIGEST:
8127c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(fw_st_id)->C_DigestUpdate(hSession,
8137c478bd9Sstevel@tonic-gate 			    NULL, 8);
8147c478bd9Sstevel@tonic-gate 			break;
815d3a28a55Sdinak 		case CKF_SIGN:
8167c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(fw_st_id)->C_SignUpdate(hSession,
8177c478bd9Sstevel@tonic-gate 			    NULL, 8);
8187c478bd9Sstevel@tonic-gate 			break;
819d3a28a55Sdinak 		case CKF_SIGN_RECOVER:
8207c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(fw_st_id)->C_SignRecover(hSession,
8217c478bd9Sstevel@tonic-gate 			    NULL, 8, dummy_buf, NULL);
8227c478bd9Sstevel@tonic-gate 			break;
823d3a28a55Sdinak 		case CKF_VERIFY:
8247c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession,
8257c478bd9Sstevel@tonic-gate 			    NULL, 8);
8267c478bd9Sstevel@tonic-gate 			break;
827d3a28a55Sdinak 		case CKF_VERIFY_RECOVER:
8287c478bd9Sstevel@tonic-gate 			(void) FUNCLIST(fw_st_id)->C_VerifyRecover(hSession,
8297c478bd9Sstevel@tonic-gate 			    NULL, 8, dummy_buf, NULL);
8307c478bd9Sstevel@tonic-gate 			break;
8317c478bd9Sstevel@tonic-gate 		default:
8327c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
8337c478bd9Sstevel@tonic-gate 			break;
8347c478bd9Sstevel@tonic-gate 		}
8357c478bd9Sstevel@tonic-gate 		meta_release_slot_session(session->op1.session);
8367c478bd9Sstevel@tonic-gate 		session->op1.session = NULL;
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 
8394a5b2e70Shaimay 	if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
8404a5b2e70Shaimay 	    (optype == CKF_DIGEST)) {
8414a5b2e70Shaimay 		session->init.done = B_FALSE;
8424a5b2e70Shaimay 		free_session_mechanism(session);
8434a5b2e70Shaimay 	}
844d3a28a55Sdinak 	session->op1.type = 0;
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate /*
8487c478bd9Sstevel@tonic-gate  * Gets the list of slots that supports the specified mechanism.
8497c478bd9Sstevel@tonic-gate  *
8507c478bd9Sstevel@tonic-gate  * If "token_only", check if the keystore slot supports the specified mech,
8517c478bd9Sstevel@tonic-gate  * if so, return that slot only
8527c478bd9Sstevel@tonic-gate  *
8537c478bd9Sstevel@tonic-gate  * Otherwise, get list of all slots that support the mech.
8547c478bd9Sstevel@tonic-gate  *
8557c478bd9Sstevel@tonic-gate  */
8567c478bd9Sstevel@tonic-gate static CK_RV
8577c478bd9Sstevel@tonic-gate get_slotlist_for_mech(CK_MECHANISM_TYPE mech_type,
8587c478bd9Sstevel@tonic-gate     mech_support_info_t *mech_support_info,
859d3a28a55Sdinak     mechinfo_t ***slots, unsigned long *slot_count, boolean_t token_only,
860d3a28a55Sdinak     CK_MECHANISM_INFO *mech_info)
8617c478bd9Sstevel@tonic-gate {
8627c478bd9Sstevel@tonic-gate 	boolean_t mech_supported = B_FALSE;
8637c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	if (token_only) {
8667c478bd9Sstevel@tonic-gate 		rv = meta_mechManager_slot_supports_mech(mech_type,
8677c478bd9Sstevel@tonic-gate 		    get_keystore_slotnum(), &mech_supported,
868d3a28a55Sdinak 		    &((mech_support_info->supporting_slots)[0]), B_FALSE,
869d3a28a55Sdinak 		    mech_info);
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
8727c478bd9Sstevel@tonic-gate 			return (rv);
8737c478bd9Sstevel@tonic-gate 		}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 		if (mech_supported) {
8767c478bd9Sstevel@tonic-gate 			mech_support_info->mech = mech_type;
8777c478bd9Sstevel@tonic-gate 			/*
8787c478bd9Sstevel@tonic-gate 			 * Want to leave this at 0, that way, when
8797c478bd9Sstevel@tonic-gate 			 * other operation needs to
8807c478bd9Sstevel@tonic-gate 			 * use this mechanism, but not just for the
8817c478bd9Sstevel@tonic-gate 			 * keystore slot, we will look at other slots
8827c478bd9Sstevel@tonic-gate 			 */
8837c478bd9Sstevel@tonic-gate 			mech_support_info->num_supporting_slots = 0;
8847c478bd9Sstevel@tonic-gate 			*slots = mech_support_info->supporting_slots;
8857c478bd9Sstevel@tonic-gate 			*slot_count = 1;
8867c478bd9Sstevel@tonic-gate 		} else {
8877c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
8887c478bd9Sstevel@tonic-gate 		}
8897c478bd9Sstevel@tonic-gate 	} else {
8907c478bd9Sstevel@tonic-gate 		/*
8917c478bd9Sstevel@tonic-gate 		 * Get a list of slots that support this mech .
8927c478bd9Sstevel@tonic-gate 		 *
8937c478bd9Sstevel@tonic-gate 		 * If the specified mechanism is used last time,
8947c478bd9Sstevel@tonic-gate 		 * the list of capable slots is already retrieved.
8957c478bd9Sstevel@tonic-gate 		 * We can save some processing, and just use that list of slots.
8967c478bd9Sstevel@tonic-gate 		 */
8977c478bd9Sstevel@tonic-gate 		if ((mech_support_info->mech != mech_type) ||
8987c478bd9Sstevel@tonic-gate 		    (mech_support_info->num_supporting_slots == 0)) {
8997c478bd9Sstevel@tonic-gate 			mech_support_info->mech = mech_type;
9007c478bd9Sstevel@tonic-gate 			rv = meta_mechManager_get_slots(mech_support_info,
901d3a28a55Sdinak 			    B_FALSE, mech_info);
9027c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
9037c478bd9Sstevel@tonic-gate 				return (CKR_FUNCTION_FAILED);
9047c478bd9Sstevel@tonic-gate 			}
9057c478bd9Sstevel@tonic-gate 		}
9067c478bd9Sstevel@tonic-gate 		*slots = mech_support_info->supporting_slots;
9077c478bd9Sstevel@tonic-gate 		*slot_count = mech_support_info->num_supporting_slots;
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 	return (rv);
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate /*
9137c478bd9Sstevel@tonic-gate  * meta_generate_keys
9147c478bd9Sstevel@tonic-gate  *
9157c478bd9Sstevel@tonic-gate  * Generates symmetric (k1=key, k2=null) or asymmetric (k1=pub, k2=priv) keys.
9167c478bd9Sstevel@tonic-gate  *
9177c478bd9Sstevel@tonic-gate  */
9187c478bd9Sstevel@tonic-gate CK_RV
9197c478bd9Sstevel@tonic-gate meta_generate_keys(meta_session_t *session, CK_MECHANISM *pMechanism,
9207c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE *k1Template, CK_ULONG k1AttrCount, meta_object_t *key1,
9217c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE *k2Template, CK_ULONG k2AttrCount, meta_object_t *key2)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	CK_RV rv, save_rv;
9247c478bd9Sstevel@tonic-gate 	slot_session_t *gen_session = NULL;
9257c478bd9Sstevel@tonic-gate 	slot_object_t *slot_key1 = NULL, *slot_key2 = NULL;
9267c478bd9Sstevel@tonic-gate 	mechinfo_t **slots = NULL;
9277c478bd9Sstevel@tonic-gate 	unsigned long i, slotCount = 0;
9287c478bd9Sstevel@tonic-gate 	boolean_t doKeyPair = B_FALSE, token_only = B_FALSE;
9297c478bd9Sstevel@tonic-gate 	CK_ULONG slotnum;
930d3a28a55Sdinak 	CK_MECHANISM_INFO mech_info;
931034448feSmcpowers 	/*
932034448feSmcpowers 	 * Since the keygen call is in a loop, it is performance-wise useful
933034448feSmcpowers 	 * to keep track of the token value
934034448feSmcpowers 	 */
935034448feSmcpowers 	CK_BBOOL current_token1_value = FALSE, current_token2_value = FALSE;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	(void) get_template_boolean(CKA_TOKEN, k1Template, k1AttrCount,
9387c478bd9Sstevel@tonic-gate 	    &(key1->isToken));
939034448feSmcpowers 	(void) get_template_boolean(CKA_SENSITIVE, k1Template, k1AttrCount,
940034448feSmcpowers 	    &(key1->isSensitive));
941034448feSmcpowers 	(void) get_template_boolean(CKA_PRIVATE, k1Template, k1AttrCount,
942034448feSmcpowers 	    &(key1->isPrivate));
943034448feSmcpowers 
944034448feSmcpowers 	if (!get_template_boolean(CKA_EXTRACTABLE, k1Template, k1AttrCount,
945034448feSmcpowers 	    &(key1->isExtractable)))
946034448feSmcpowers 		key1->isExtractable = B_TRUE;
947034448feSmcpowers 
948034448feSmcpowers 	if (key1->isToken)
949034448feSmcpowers 		current_token1_value = TRUE;
950034448feSmcpowers 
951d3a28a55Sdinak 	mech_info.flags = CKF_GENERATE;
952d3a28a55Sdinak 
9537c478bd9Sstevel@tonic-gate 	if (key2) {
9547c478bd9Sstevel@tonic-gate 		(void) get_template_boolean(CKA_TOKEN, k2Template, k2AttrCount,
9557c478bd9Sstevel@tonic-gate 		    &(key2->isToken));
956034448feSmcpowers 		(void) get_template_boolean(CKA_SENSITIVE, k2Template,
957034448feSmcpowers 		    k2AttrCount, &(key2->isSensitive));
958034448feSmcpowers 		(void) get_template_boolean(CKA_PRIVATE, k2Template,
959034448feSmcpowers 		    k2AttrCount, &(key2->isPrivate));
960034448feSmcpowers 
961034448feSmcpowers 		if (!get_template_boolean(CKA_EXTRACTABLE, k2Template,
962034448feSmcpowers 		    k2AttrCount, &(key2->isExtractable)))
963034448feSmcpowers 			key2->isExtractable = B_TRUE;
964034448feSmcpowers 
965034448feSmcpowers 		if (key2->isToken)
966034448feSmcpowers 			current_token2_value = TRUE;
967034448feSmcpowers 
9687c478bd9Sstevel@tonic-gate 		doKeyPair = B_TRUE;
969d3a28a55Sdinak 		mech_info.flags = CKF_GENERATE_KEY_PAIR;
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 
972034448feSmcpowers 
9737c478bd9Sstevel@tonic-gate 	/* Can't create token objects in a read-only session. */
9747c478bd9Sstevel@tonic-gate 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
9757c478bd9Sstevel@tonic-gate 	    ((key1->isToken) || ((key2) && (key2->isToken)))) {
9767c478bd9Sstevel@tonic-gate 		return (CKR_SESSION_READ_ONLY);
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 
979034448feSmcpowers 	if (meta_freeobject_check(session, key1, pMechanism, k1Template,
980034448feSmcpowers 	    k1AttrCount, NULL)) {
981034448feSmcpowers 
982034448feSmcpowers 		if ((key1->isPrivate || (doKeyPair && key2->isPrivate)) &&
983034448feSmcpowers 		    !metaslot_logged_in())
984034448feSmcpowers 			return (CKR_USER_NOT_LOGGED_IN);
985034448feSmcpowers 
986034448feSmcpowers 		if (!meta_freeobject_set(key1, k1Template, k1AttrCount,
987034448feSmcpowers 		    B_FALSE))
988034448feSmcpowers 			return (CKR_FUNCTION_FAILED);
989034448feSmcpowers 
990034448feSmcpowers 		if (doKeyPair) {
991034448feSmcpowers 			key2->isFreeObject = FREE_ALLOWED_KEY;
992034448feSmcpowers 			if (!meta_freeobject_set(key2, k2Template, k2AttrCount,
993034448feSmcpowers 			    B_FALSE))
994034448feSmcpowers 				return (CKR_FUNCTION_FAILED);
995034448feSmcpowers 		}
996034448feSmcpowers 
997034448feSmcpowers 	} else if (doKeyPair) {
998034448feSmcpowers 		/*
999034448feSmcpowers 		 * If this is a keypair operation, the second key cannot be
1000034448feSmcpowers 		 * a FreeObject if the first is not.  Both keys will have the
1001034448feSmcpowers 		 * same fate when it comes to provider choices
1002034448feSmcpowers 		 */
1003034448feSmcpowers 		key2->isFreeObject = FREE_DISABLED;
1004034448feSmcpowers 		key2->isFreeToken = FREE_DISABLED;
1005034448feSmcpowers 	}
1006034448feSmcpowers 
10077c478bd9Sstevel@tonic-gate 	if ((key1->isToken) || ((doKeyPair) && (key2->isToken))) {
10087c478bd9Sstevel@tonic-gate 		/*
10097c478bd9Sstevel@tonic-gate 		 * Token objects can only be generated in the token object
10107c478bd9Sstevel@tonic-gate 		 * slot.  If token object slot doesn't support generating
1011034448feSmcpowers 		 * the key, it will just not be done.
10127c478bd9Sstevel@tonic-gate 		 */
10137c478bd9Sstevel@tonic-gate 		token_only = B_TRUE;
10147c478bd9Sstevel@tonic-gate 	}
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	rv = get_slotlist_for_mech(pMechanism->mechanism,
1017d3a28a55Sdinak 	    &(session->mech_support_info), &slots, &slotCount, token_only,
1018d3a28a55Sdinak 	    &mech_info);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
10217c478bd9Sstevel@tonic-gate 		goto finish;
10227c478bd9Sstevel@tonic-gate 	}
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	rv = meta_slot_object_alloc(&slot_key1);
10257c478bd9Sstevel@tonic-gate 	if (doKeyPair && rv == CKR_OK)
10267c478bd9Sstevel@tonic-gate 		rv = meta_slot_object_alloc(&slot_key2);
10277c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
10287c478bd9Sstevel@tonic-gate 		goto finish;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	/* Attempt to generate key on slots until one succeeds. */
10317c478bd9Sstevel@tonic-gate 	for (i = 0; i < slotCount; i++) {
10327c478bd9Sstevel@tonic-gate 		CK_SESSION_HANDLE hSession;
10337c478bd9Sstevel@tonic-gate 		CK_SLOT_ID fw_st_id;
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 		gen_session = NULL;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 		slotnum = slots[i]->slotnum;
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 		if (session->op1.session != NULL) {
10407c478bd9Sstevel@tonic-gate 			if ((session->op1.session)->slotnum == slotnum) {
10417c478bd9Sstevel@tonic-gate 				gen_session = session->op1.session;
10427c478bd9Sstevel@tonic-gate 				/*
10437c478bd9Sstevel@tonic-gate 				 * set it to NULL for now, assign it to
10447c478bd9Sstevel@tonic-gate 				 * gen_session again if it is successful
10457c478bd9Sstevel@tonic-gate 				 */
10467c478bd9Sstevel@tonic-gate 				session->op1.session = NULL;
10477c478bd9Sstevel@tonic-gate 			} else {
10487c478bd9Sstevel@tonic-gate 				gen_session = NULL;
10497c478bd9Sstevel@tonic-gate 			}
10507c478bd9Sstevel@tonic-gate 		}
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 		if (gen_session == NULL) {
10537c478bd9Sstevel@tonic-gate 			rv = meta_get_slot_session(slotnum, &gen_session,
10547c478bd9Sstevel@tonic-gate 			    session->session_flags);
10557c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
10567c478bd9Sstevel@tonic-gate 				goto loop_cleanup;
10577c478bd9Sstevel@tonic-gate 			}
10587c478bd9Sstevel@tonic-gate 		}
10597c478bd9Sstevel@tonic-gate 
1060034448feSmcpowers 		/*
1061034448feSmcpowers 		 * If this is a freetoken, make sure the templates are
1062034448feSmcpowers 		 * approriate for the slot being used.
1063034448feSmcpowers 		 */
1064034448feSmcpowers 		if (key1->isFreeToken == FREE_ENABLED) {
1065034448feSmcpowers 			rv = meta_freetoken_set(slotnum,
1066034448feSmcpowers 			    &current_token1_value, k1Template, k1AttrCount);
1067034448feSmcpowers 			if (rv != CKR_OK)
1068034448feSmcpowers 				goto loop_cleanup;
1069034448feSmcpowers 		}
1070034448feSmcpowers 
1071034448feSmcpowers 		if (doKeyPair && key2->isFreeToken == FREE_ENABLED) {
1072034448feSmcpowers 			rv = meta_freetoken_set(slotnum,
1073034448feSmcpowers 			    &current_token2_value, k2Template, k2AttrCount);
1074034448feSmcpowers 			if (rv != CKR_OK)
1075034448feSmcpowers 				goto loop_cleanup;
1076034448feSmcpowers 		}
1077034448feSmcpowers 
10787c478bd9Sstevel@tonic-gate 		fw_st_id = gen_session->fw_st_id;
10797c478bd9Sstevel@tonic-gate 		hSession = gen_session->hSession;
1080034448feSmcpowers 
10817c478bd9Sstevel@tonic-gate 		if (doKeyPair) {
10827c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_GenerateKeyPair(hSession,
10837c478bd9Sstevel@tonic-gate 			    pMechanism, k1Template, k1AttrCount,
10847c478bd9Sstevel@tonic-gate 			    k2Template, k2AttrCount,
10857c478bd9Sstevel@tonic-gate 			    &slot_key1->hObject, &slot_key2->hObject);
10867c478bd9Sstevel@tonic-gate 		} else {
10877c478bd9Sstevel@tonic-gate 			rv = FUNCLIST(fw_st_id)->C_GenerateKey(hSession,
10887c478bd9Sstevel@tonic-gate 			    pMechanism, k1Template, k1AttrCount,
10897c478bd9Sstevel@tonic-gate 			    &slot_key1->hObject);
10907c478bd9Sstevel@tonic-gate 		}
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK)
10937c478bd9Sstevel@tonic-gate 			break;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate loop_cleanup:
10967c478bd9Sstevel@tonic-gate 		if (i == 0) {
10977c478bd9Sstevel@tonic-gate 			save_rv = rv;
10987c478bd9Sstevel@tonic-gate 		}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 		if (gen_session) {
11017c478bd9Sstevel@tonic-gate 			meta_release_slot_session(gen_session);
11027c478bd9Sstevel@tonic-gate 			gen_session = NULL;
11037c478bd9Sstevel@tonic-gate 		}
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
11067c478bd9Sstevel@tonic-gate 		rv = save_rv;
11077c478bd9Sstevel@tonic-gate 		goto finish;
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	rv = meta_object_get_attr(gen_session, slot_key1->hObject, key1);
11117c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
11127c478bd9Sstevel@tonic-gate 		goto finish;
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	if (key2) {
11167c478bd9Sstevel@tonic-gate 		rv = meta_object_get_attr(gen_session, slot_key2->hObject,
11177c478bd9Sstevel@tonic-gate 		    key2);
11187c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
11197c478bd9Sstevel@tonic-gate 			goto finish;
11207c478bd9Sstevel@tonic-gate 		}
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 
1123*8cae6764SAnthony Scarpino 	/* Allow FreeToken to activate onto token obj list */
1124*8cae6764SAnthony Scarpino 	if (key1->isFreeToken == FREE_ENABLED)
1125*8cae6764SAnthony Scarpino 		key1->isToken = B_TRUE;
1126*8cae6764SAnthony Scarpino 
11277c478bd9Sstevel@tonic-gate 	meta_slot_object_activate(slot_key1, gen_session, key1->isToken);
11287c478bd9Sstevel@tonic-gate 	key1->clones[slotnum] = slot_key1;
11297c478bd9Sstevel@tonic-gate 	key1->master_clone_slotnum = slotnum;
11307c478bd9Sstevel@tonic-gate 	slot_key1 = NULL;
1131034448feSmcpowers 	if (key1->isFreeObject == FREE_ENABLED) {
1132034448feSmcpowers 		rv = meta_freeobject_clone(session, key1);
1133034448feSmcpowers 		if (rv != CKR_OK)
1134034448feSmcpowers 			goto finish;
1135034448feSmcpowers 	}
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	if (doKeyPair) {
1138*8cae6764SAnthony Scarpino 		/* Allow FreeToken to activate onto token obj list */
1139*8cae6764SAnthony Scarpino 		if (key2->isFreeToken == FREE_ENABLED)
1140*8cae6764SAnthony Scarpino 			key2->isToken = B_TRUE;
1141*8cae6764SAnthony Scarpino 
11427c478bd9Sstevel@tonic-gate 		meta_slot_object_activate(slot_key2, gen_session,
11437c478bd9Sstevel@tonic-gate 		    key2->isToken);
11447c478bd9Sstevel@tonic-gate 		key2->clones[slotnum] = slot_key2;
11457c478bd9Sstevel@tonic-gate 		key2->master_clone_slotnum = slotnum;
11467c478bd9Sstevel@tonic-gate 		slot_key2 = NULL;
1147034448feSmcpowers 		if (key2->isFreeObject == FREE_ENABLED) {
1148034448feSmcpowers 			rv = meta_freeobject_clone(session, key2);
1149034448feSmcpowers 			if (rv != CKR_OK)
1150034448feSmcpowers 				goto finish;
1151034448feSmcpowers 		}
11527c478bd9Sstevel@tonic-gate 	}
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate finish:
11557c478bd9Sstevel@tonic-gate 	if (slot_key1) {
11567c478bd9Sstevel@tonic-gate 		meta_slot_object_dealloc(slot_key1);
11577c478bd9Sstevel@tonic-gate 	}
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	if (slot_key2) {
11607c478bd9Sstevel@tonic-gate 		meta_slot_object_dealloc(slot_key2);
11617c478bd9Sstevel@tonic-gate 	}
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	/* Save the session in case it can be used later */
11647c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
11657c478bd9Sstevel@tonic-gate 		/*
11667c478bd9Sstevel@tonic-gate 		 * If currently stored session is not the one being in use now,
11677c478bd9Sstevel@tonic-gate 		 * release the previous one and store the current one
11687c478bd9Sstevel@tonic-gate 		 */
11697c478bd9Sstevel@tonic-gate 		if ((session->op1.session) &&
11707c478bd9Sstevel@tonic-gate 		    (session->op1.session != gen_session)) {
11717c478bd9Sstevel@tonic-gate 			meta_release_slot_session(session->op1.session);
11727c478bd9Sstevel@tonic-gate 		}
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 		/* Save the session */
11757c478bd9Sstevel@tonic-gate 		session->op1.session = gen_session;
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	return (rv);
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate /*
11837c478bd9Sstevel@tonic-gate  * meta_wrap_key
11847c478bd9Sstevel@tonic-gate  *
11857c478bd9Sstevel@tonic-gate  */
11867c478bd9Sstevel@tonic-gate CK_RV
11877c478bd9Sstevel@tonic-gate meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism,
11887c478bd9Sstevel@tonic-gate     meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key,
11897c478bd9Sstevel@tonic-gate     CK_ULONG *wrapped_key_len)
11907c478bd9Sstevel@tonic-gate {
11917c478bd9Sstevel@tonic-gate 	CK_RV rv, save_rv;
11927c478bd9Sstevel@tonic-gate 	slot_session_t *wrap_session = NULL;
11937c478bd9Sstevel@tonic-gate 	slot_object_t *slot_wrappingkey, *slot_inputkey;
11947c478bd9Sstevel@tonic-gate 	mechinfo_t **slots = NULL;
11957c478bd9Sstevel@tonic-gate 	unsigned long i, slotCount = 0;
11967c478bd9Sstevel@tonic-gate 	CK_ULONG slotnum;
1197d3a28a55Sdinak 	CK_MECHANISM_INFO mech_info;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	/*
12007c478bd9Sstevel@tonic-gate 	 * If the key to be wrapped is a token object,
12017c478bd9Sstevel@tonic-gate 	 * the operation can only be done in the token object slot.
12027c478bd9Sstevel@tonic-gate 	 */
1203d3a28a55Sdinak 	mech_info.flags = CKF_WRAP;
12047c478bd9Sstevel@tonic-gate 	rv = get_slotlist_for_mech(pMechanism->mechanism,
12057c478bd9Sstevel@tonic-gate 	    &(session->mech_support_info), &slots, &slotCount,
1206d3a28a55Sdinak 	    inputkey->isToken, &mech_info);
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
12097c478bd9Sstevel@tonic-gate 		return (rv);
12107c478bd9Sstevel@tonic-gate 	}
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	/* Attempt to wrap key on slots until one succeeds. */
12137c478bd9Sstevel@tonic-gate 	for (i = 0; i < slotCount; i++) {
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 		slotnum = slots[i]->slotnum;
12167c478bd9Sstevel@tonic-gate 		wrap_session = NULL;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 		if (session->op1.session != NULL) {
12197c478bd9Sstevel@tonic-gate 			if ((session->op1.session)->slotnum == slotnum) {
12207c478bd9Sstevel@tonic-gate 				wrap_session = session->op1.session;
12217c478bd9Sstevel@tonic-gate 				/*
12227c478bd9Sstevel@tonic-gate 				 * set it to NULL for now, assign it to
12237c478bd9Sstevel@tonic-gate 				 * wrap_session again if it is successful
12247c478bd9Sstevel@tonic-gate 				 */
12257c478bd9Sstevel@tonic-gate 				session->op1.session = NULL;
12267c478bd9Sstevel@tonic-gate 			} else {
12277c478bd9Sstevel@tonic-gate 				wrap_session = NULL;
12287c478bd9Sstevel@tonic-gate 			}
12297c478bd9Sstevel@tonic-gate 		}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 		if (wrap_session == NULL) {
12327c478bd9Sstevel@tonic-gate 			rv = meta_get_slot_session(slotnum, &wrap_session,
12337c478bd9Sstevel@tonic-gate 			    session->session_flags);
12347c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
12357c478bd9Sstevel@tonic-gate 				goto loop_cleanup;
12367c478bd9Sstevel@tonic-gate 			}
12377c478bd9Sstevel@tonic-gate 		}
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 		rv = meta_object_get_clone(wrappingkey, slotnum,
12407c478bd9Sstevel@tonic-gate 		    wrap_session, &slot_wrappingkey);
12417c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
12427c478bd9Sstevel@tonic-gate 			goto loop_cleanup;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 		rv = meta_object_get_clone(inputkey, slotnum,
12457c478bd9Sstevel@tonic-gate 		    wrap_session, &slot_inputkey);
12467c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
12477c478bd9Sstevel@tonic-gate 			goto loop_cleanup;
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 		rv = FUNCLIST(wrap_session->fw_st_id)->C_WrapKey(
12507c478bd9Sstevel@tonic-gate 		    wrap_session->hSession, pMechanism,
12517c478bd9Sstevel@tonic-gate 		    slot_wrappingkey->hObject, slot_inputkey->hObject,
12527c478bd9Sstevel@tonic-gate 		    wrapped_key, wrapped_key_len);
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
12557c478bd9Sstevel@tonic-gate 			break;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate loop_cleanup:
12587c478bd9Sstevel@tonic-gate 		if (i == 0) {
12597c478bd9Sstevel@tonic-gate 			save_rv = rv;
12607c478bd9Sstevel@tonic-gate 		}
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		if (wrap_session) {
12637c478bd9Sstevel@tonic-gate 			meta_release_slot_session(wrap_session);
12647c478bd9Sstevel@tonic-gate 			wrap_session = NULL;
12657c478bd9Sstevel@tonic-gate 		}
12667c478bd9Sstevel@tonic-gate 	}
12677c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
12687c478bd9Sstevel@tonic-gate 		if (rv != CKR_BUFFER_TOO_SMALL) {
12697c478bd9Sstevel@tonic-gate 			if (i == slotCount) {
12707c478bd9Sstevel@tonic-gate 				rv = save_rv;
12717c478bd9Sstevel@tonic-gate 			}
12727c478bd9Sstevel@tonic-gate 		}
12737c478bd9Sstevel@tonic-gate 	}
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate finish:
12767c478bd9Sstevel@tonic-gate 	/* Save the session in case it can be used later */
12777c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
12787c478bd9Sstevel@tonic-gate 		/*
12797c478bd9Sstevel@tonic-gate 		 * If currently stored session is not the one being in use now,
12807c478bd9Sstevel@tonic-gate 		 * release the previous one and store the current one
12817c478bd9Sstevel@tonic-gate 		 */
12827c478bd9Sstevel@tonic-gate 		if ((session->op1.session) &&
12837c478bd9Sstevel@tonic-gate 		    (session->op1.session != wrap_session)) {
12847c478bd9Sstevel@tonic-gate 			meta_release_slot_session(session->op1.session);
12857c478bd9Sstevel@tonic-gate 		}
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 		/* Save the session */
12887c478bd9Sstevel@tonic-gate 		session->op1.session = wrap_session;
12897c478bd9Sstevel@tonic-gate 	}
12907c478bd9Sstevel@tonic-gate 	return (rv);
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate /*
12967c478bd9Sstevel@tonic-gate  * meta_unwrap_key
12977c478bd9Sstevel@tonic-gate  *
12987c478bd9Sstevel@tonic-gate  */
12997c478bd9Sstevel@tonic-gate CK_RV
13007c478bd9Sstevel@tonic-gate meta_unwrap_key(meta_session_t *session,
13017c478bd9Sstevel@tonic-gate 	CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key,
13027c478bd9Sstevel@tonic-gate 	CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len,
13037c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE *template, CK_ULONG template_size,
13047c478bd9Sstevel@tonic-gate 	meta_object_t *unwrapped_key)
13057c478bd9Sstevel@tonic-gate {
13067c478bd9Sstevel@tonic-gate 	CK_RV rv, save_rv;
13077c478bd9Sstevel@tonic-gate 	CK_OBJECT_HANDLE hUnwrappedKey;
13087c478bd9Sstevel@tonic-gate 	slot_session_t *unwrap_session = NULL;
13097c478bd9Sstevel@tonic-gate 	slot_object_t *slot_unwrappingkey, *slot_unwrapped_key;
13107c478bd9Sstevel@tonic-gate 	mechinfo_t **slots = NULL;
13117c478bd9Sstevel@tonic-gate 	unsigned long i, slotCount = 0;
13127c478bd9Sstevel@tonic-gate 	CK_ULONG slotnum;
1313d3a28a55Sdinak 	CK_MECHANISM_INFO mech_info;
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	/* Can't create token objects in a read-only session. */
13167c478bd9Sstevel@tonic-gate 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
13177c478bd9Sstevel@tonic-gate 	    unwrapped_key->isToken) {
13187c478bd9Sstevel@tonic-gate 		return (CKR_SESSION_READ_ONLY);
13197c478bd9Sstevel@tonic-gate 	}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	/*
13227c478bd9Sstevel@tonic-gate 	 * If the the resulting unwrapped key
13237c478bd9Sstevel@tonic-gate 	 * needs to be a token object, the operation can only
13247c478bd9Sstevel@tonic-gate 	 * be performed in the token slot, if it is supported.
13257c478bd9Sstevel@tonic-gate 	 */
1326d3a28a55Sdinak 	mech_info.flags = CKF_UNWRAP;
13277c478bd9Sstevel@tonic-gate 	rv = get_slotlist_for_mech(pMechanism->mechanism,
13287c478bd9Sstevel@tonic-gate 	    &(session->mech_support_info), &slots, &slotCount,
1329d3a28a55Sdinak 	    unwrapped_key->isToken, &mech_info);
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
13327c478bd9Sstevel@tonic-gate 		return (rv);
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	rv = meta_slot_object_alloc(&slot_unwrapped_key);
13367c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
13377c478bd9Sstevel@tonic-gate 		goto finish;
13387c478bd9Sstevel@tonic-gate 	}
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	/* Attempt to unwrap key on slots until one succeeds. */
13417c478bd9Sstevel@tonic-gate 	for (i = 0; i < slotCount; i++) {
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 		slotnum = slots[i]->slotnum;
13447c478bd9Sstevel@tonic-gate 		unwrap_session = NULL;
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 		if (session->op1.session != NULL) {
13477c478bd9Sstevel@tonic-gate 			if ((session->op1.session)->slotnum == slotnum) {
13487c478bd9Sstevel@tonic-gate 				unwrap_session = session->op1.session;
13497c478bd9Sstevel@tonic-gate 				/*
13507c478bd9Sstevel@tonic-gate 				 * set it to NULL for now, assign it to
13517c478bd9Sstevel@tonic-gate 				 * unwrap_session again if it is successful
13527c478bd9Sstevel@tonic-gate 				 */
13537c478bd9Sstevel@tonic-gate 				session->op1.session = NULL;
13547c478bd9Sstevel@tonic-gate 			} else {
13557c478bd9Sstevel@tonic-gate 				unwrap_session = NULL;
13567c478bd9Sstevel@tonic-gate 			}
13577c478bd9Sstevel@tonic-gate 		}
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 		if (unwrap_session == NULL) {
13607c478bd9Sstevel@tonic-gate 			rv = meta_get_slot_session(slotnum, &unwrap_session,
13617c478bd9Sstevel@tonic-gate 			    session->session_flags);
13627c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
13637c478bd9Sstevel@tonic-gate 				goto loop_cleanup;
13647c478bd9Sstevel@tonic-gate 			}
13657c478bd9Sstevel@tonic-gate 		}
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 		rv = meta_object_get_clone(unwrapping_key, slotnum,
13687c478bd9Sstevel@tonic-gate 		    unwrap_session, &slot_unwrappingkey);
13697c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
13707c478bd9Sstevel@tonic-gate 			goto loop_cleanup;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 		rv = FUNCLIST(unwrap_session->fw_st_id)->C_UnwrapKey(
13737c478bd9Sstevel@tonic-gate 		    unwrap_session->hSession, pMechanism,
13747c478bd9Sstevel@tonic-gate 		    slot_unwrappingkey->hObject, wrapped_key, wrapped_key_len,
13757c478bd9Sstevel@tonic-gate 		    template, template_size, &hUnwrappedKey);
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
13787c478bd9Sstevel@tonic-gate 			break;
13797c478bd9Sstevel@tonic-gate loop_cleanup:
13807c478bd9Sstevel@tonic-gate 		if (i == 0) {
13817c478bd9Sstevel@tonic-gate 			save_rv = rv;
13827c478bd9Sstevel@tonic-gate 		}
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 		if (unwrap_session) {
13857c478bd9Sstevel@tonic-gate 			meta_release_slot_session(unwrap_session);
13867c478bd9Sstevel@tonic-gate 			unwrap_session = NULL;
13877c478bd9Sstevel@tonic-gate 		}
13887c478bd9Sstevel@tonic-gate 	}
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
13927c478bd9Sstevel@tonic-gate 		if (rv != CKR_BUFFER_TOO_SMALL) {
13937c478bd9Sstevel@tonic-gate 			rv = save_rv;
13947c478bd9Sstevel@tonic-gate 		}
13957c478bd9Sstevel@tonic-gate 		goto finish;
13967c478bd9Sstevel@tonic-gate 	}
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	slot_unwrapped_key->hObject = hUnwrappedKey;
14007c478bd9Sstevel@tonic-gate 	unwrapped_key->clones[slotnum] = slot_unwrapped_key;
14017c478bd9Sstevel@tonic-gate 	unwrapped_key->master_clone_slotnum = slotnum;
14027c478bd9Sstevel@tonic-gate 	rv = meta_object_get_attr(unwrap_session,
14037c478bd9Sstevel@tonic-gate 	    slot_unwrapped_key->hObject, unwrapped_key);
14047c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14057c478bd9Sstevel@tonic-gate 		goto finish;
14067c478bd9Sstevel@tonic-gate 	}
14077c478bd9Sstevel@tonic-gate 	meta_slot_object_activate(slot_unwrapped_key, unwrap_session,
14087c478bd9Sstevel@tonic-gate 	    unwrapped_key->isToken);
14097c478bd9Sstevel@tonic-gate 	slot_unwrapped_key = NULL;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate finish:
14127c478bd9Sstevel@tonic-gate 	if (slot_unwrapped_key) {
14137c478bd9Sstevel@tonic-gate 		meta_slot_object_dealloc(slot_unwrapped_key);
14147c478bd9Sstevel@tonic-gate 	}
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	/* Save the session in case it can be used later */
14177c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
14187c478bd9Sstevel@tonic-gate 		/*
14197c478bd9Sstevel@tonic-gate 		 * If currently stored session is not the one being in use now,
14207c478bd9Sstevel@tonic-gate 		 * release the previous one and store the current one
14217c478bd9Sstevel@tonic-gate 		 */
14227c478bd9Sstevel@tonic-gate 		if ((session->op1.session) &&
14237c478bd9Sstevel@tonic-gate 		    (session->op1.session != unwrap_session)) {
14247c478bd9Sstevel@tonic-gate 			meta_release_slot_session(session->op1.session);
14257c478bd9Sstevel@tonic-gate 		}
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 		/* Save the session */
14287c478bd9Sstevel@tonic-gate 		session->op1.session = unwrap_session;
14297c478bd9Sstevel@tonic-gate 	}
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	return (rv);
14327c478bd9Sstevel@tonic-gate }
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate /*
14367c478bd9Sstevel@tonic-gate  * meta_derive_key
14377c478bd9Sstevel@tonic-gate  *
14387c478bd9Sstevel@tonic-gate  * Core implementation for C_DeriveKey. This function is a bit gross because
14397c478bd9Sstevel@tonic-gate  * of PKCS#11 kludges that pass extra object handles in the mechanism
14407c478bd9Sstevel@tonic-gate  * parameters. Normally C_DeriveKey takes a single existing key as input,
14417c478bd9Sstevel@tonic-gate  * and creates a single new key as output. But a few mechanisms take 2 keys
14427c478bd9Sstevel@tonic-gate  * as input, and the two SSL/TLS mechanisms create 4 keys as output.
14437c478bd9Sstevel@tonic-gate  *
14447c478bd9Sstevel@tonic-gate  * When an extra input key (basekey2) is set, we set *phBaseKey2 to the clone's
14457c478bd9Sstevel@tonic-gate  * object handle. phBaseKey2 is provided by the caller so we don't have to
14467c478bd9Sstevel@tonic-gate  * trudge down into different mechanism parameters to set it when issuing the
14477c478bd9Sstevel@tonic-gate  * operation.
14487c478bd9Sstevel@tonic-gate  *
14497c478bd9Sstevel@tonic-gate  * For the SSL/TLS mechanisms, newKey2/newKey3/newKey4 will be set. We pull
14507c478bd9Sstevel@tonic-gate  * the new handles from pMech->pParameter in order to fill in the appropriate
14517c478bd9Sstevel@tonic-gate  * meta_object fields.
14527c478bd9Sstevel@tonic-gate  */
14537c478bd9Sstevel@tonic-gate CK_RV
14547c478bd9Sstevel@tonic-gate meta_derive_key(meta_session_t *session, CK_MECHANISM *pMechanism,
14557c478bd9Sstevel@tonic-gate 	meta_object_t *basekey1, meta_object_t *basekey2,
14567c478bd9Sstevel@tonic-gate 	CK_OBJECT_HANDLE *phBaseKey2,
14577c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount,
14587c478bd9Sstevel@tonic-gate 	meta_object_t *newKey1, meta_object_t *newKey2,
14597c478bd9Sstevel@tonic-gate 	meta_object_t *newKey3, meta_object_t *newKey4)
14607c478bd9Sstevel@tonic-gate {
14617c478bd9Sstevel@tonic-gate 	CK_RV rv, save_rv;
14627c478bd9Sstevel@tonic-gate 	CK_OBJECT_HANDLE hDerivedKey;
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	CK_ULONG slotnum;
14657c478bd9Sstevel@tonic-gate 	boolean_t isSSL = B_FALSE;
146660722cc8Sizick 	boolean_t isTLSPRF = B_FALSE;
14677c478bd9Sstevel@tonic-gate 	mechinfo_t **slots = NULL;
14687c478bd9Sstevel@tonic-gate 	unsigned long i, slot_count = 0;
14697c478bd9Sstevel@tonic-gate 	slot_session_t *derive_session = NULL;
14707c478bd9Sstevel@tonic-gate 	slot_object_t *slot_basekey1 = NULL, *slot_basekey2 = NULL;
1471d3a28a55Sdinak 	slot_object_t *slotkey1 = NULL, *slotkey2 = NULL, *slotkey3 = NULL,
1472d3a28a55Sdinak 	    *slotkey4 = NULL;
1473d3a28a55Sdinak 	CK_MECHANISM_INFO mech_info;
1474034448feSmcpowers 	CK_BBOOL current_token_value = FALSE;
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	/*
14777c478bd9Sstevel@tonic-gate 	 * if the derived key needs to be a token object, can only
14787c478bd9Sstevel@tonic-gate 	 * perform the derive operation in the token slot
14797c478bd9Sstevel@tonic-gate 	 */
14807c478bd9Sstevel@tonic-gate 	(void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount,
14817c478bd9Sstevel@tonic-gate 	    &(newKey1->isToken));
1482034448feSmcpowers 	(void) get_template_boolean(CKA_PRIVATE, pTemplate, ulAttributeCount,
1483034448feSmcpowers 	    &(newKey1->isPrivate));
1484034448feSmcpowers 	(void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulAttributeCount,
1485034448feSmcpowers 	    &(newKey1->isSensitive));
1486034448feSmcpowers 
1487034448feSmcpowers 	if (newKey1->isToken)
1488034448feSmcpowers 		current_token_value = TRUE;
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	/* Can't create token objects in a read-only session. */
14917c478bd9Sstevel@tonic-gate 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
14927c478bd9Sstevel@tonic-gate 	    newKey1->isToken) {
14937c478bd9Sstevel@tonic-gate 		rv = CKR_SESSION_READ_ONLY;
14947c478bd9Sstevel@tonic-gate 		goto finish;
14957c478bd9Sstevel@tonic-gate 	}
14967c478bd9Sstevel@tonic-gate 
1497034448feSmcpowers 	if (meta_freeobject_check(session, newKey1, pMechanism, pTemplate,
1498034448feSmcpowers 	    ulAttributeCount, NULL)) {
1499034448feSmcpowers 
1500034448feSmcpowers 		if (newKey1->isPrivate && !metaslot_logged_in())
1501034448feSmcpowers 			return (CKR_USER_NOT_LOGGED_IN);
1502034448feSmcpowers 
1503034448feSmcpowers 		if (!meta_freeobject_set(newKey1, pTemplate, ulAttributeCount,
1504034448feSmcpowers 		    B_FALSE))
1505034448feSmcpowers 			return (CKR_FUNCTION_FAILED);
1506034448feSmcpowers 	}
1507034448feSmcpowers 
1508d3a28a55Sdinak 	mech_info.flags = CKF_DERIVE;
15097c478bd9Sstevel@tonic-gate 	rv = get_slotlist_for_mech(pMechanism->mechanism,
15107c478bd9Sstevel@tonic-gate 	    &(session->mech_support_info), &slots, &slot_count,
1511d3a28a55Sdinak 	    newKey1->isToken, &mech_info);
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
15147c478bd9Sstevel@tonic-gate 		return (rv);
15157c478bd9Sstevel@tonic-gate 	}
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	if (pMechanism->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE ||
151860722cc8Sizick 	    pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE)
15197c478bd9Sstevel@tonic-gate 		isSSL = B_TRUE;
152060722cc8Sizick 
152160722cc8Sizick 	else if (pMechanism->mechanism == CKM_TLS_PRF)
152260722cc8Sizick 		isTLSPRF = B_TRUE;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	rv = meta_slot_object_alloc(&slotkey1);
15257c478bd9Sstevel@tonic-gate 	if (isSSL) {
15267c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK)
15277c478bd9Sstevel@tonic-gate 			rv = meta_slot_object_alloc(&slotkey2);
15287c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK)
15297c478bd9Sstevel@tonic-gate 			rv = meta_slot_object_alloc(&slotkey3);
15307c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK)
15317c478bd9Sstevel@tonic-gate 			rv = meta_slot_object_alloc(&slotkey4);
15327c478bd9Sstevel@tonic-gate 	}
15337c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
15347c478bd9Sstevel@tonic-gate 		goto finish;
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	for (i = 0; i < slot_count; i++) {
15387c478bd9Sstevel@tonic-gate 		slotnum = slots[i]->slotnum;
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 		derive_session = NULL;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 		if (session->op1.session != NULL) {
15437c478bd9Sstevel@tonic-gate 			if ((session->op1.session)->slotnum == slotnum) {
15447c478bd9Sstevel@tonic-gate 				derive_session = session->op1.session;
15457c478bd9Sstevel@tonic-gate 				/*
15467c478bd9Sstevel@tonic-gate 				 * set it to NULL for now, assign it to
15477c478bd9Sstevel@tonic-gate 				 * derive_session again if it is successful
15487c478bd9Sstevel@tonic-gate 				 */
15497c478bd9Sstevel@tonic-gate 				session->op1.session = NULL;
15507c478bd9Sstevel@tonic-gate 			} else {
15517c478bd9Sstevel@tonic-gate 				derive_session = NULL;
15527c478bd9Sstevel@tonic-gate 			}
15537c478bd9Sstevel@tonic-gate 		}
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 		if (derive_session == NULL) {
15567c478bd9Sstevel@tonic-gate 			rv = meta_get_slot_session(slotnum, &derive_session,
15577c478bd9Sstevel@tonic-gate 			    session->session_flags);
15587c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
15597c478bd9Sstevel@tonic-gate 				goto loop_cleanup;
15607c478bd9Sstevel@tonic-gate 			}
15617c478bd9Sstevel@tonic-gate 		}
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 		rv = meta_object_get_clone(basekey1, slotnum,
15647c478bd9Sstevel@tonic-gate 		    derive_session, &slot_basekey1);
15657c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
15667c478bd9Sstevel@tonic-gate 			goto loop_cleanup;
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 		if (basekey2) {
15697c478bd9Sstevel@tonic-gate 			rv = meta_object_get_clone(basekey2, slotnum,
15707c478bd9Sstevel@tonic-gate 			    derive_session, &slot_basekey2);
15717c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK)
15727c478bd9Sstevel@tonic-gate 				goto loop_cleanup;
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 			/* Pass the handle somewhere in the mech params. */
15757c478bd9Sstevel@tonic-gate 			*phBaseKey2 = slot_basekey2->hObject;
15767c478bd9Sstevel@tonic-gate 		}
15777c478bd9Sstevel@tonic-gate 
1578034448feSmcpowers 		if (newKey1->isFreeToken == FREE_ENABLED) {
1579034448feSmcpowers 			rv = meta_freetoken_set(slotnum, &current_token_value,
1580034448feSmcpowers 			    pTemplate, ulAttributeCount);
1581034448feSmcpowers 			if (rv != CKR_OK)
1582034448feSmcpowers 				goto loop_cleanup;
1583034448feSmcpowers 		}
1584034448feSmcpowers 
15857c478bd9Sstevel@tonic-gate 		rv = FUNCLIST(derive_session->fw_st_id)->C_DeriveKey(
15867c478bd9Sstevel@tonic-gate 		    derive_session->hSession, pMechanism,
15877c478bd9Sstevel@tonic-gate 		    slot_basekey1->hObject, pTemplate, ulAttributeCount,
158860722cc8Sizick 		    (isSSL || isTLSPRF) ? NULL : &hDerivedKey);
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK)
15917c478bd9Sstevel@tonic-gate 			break;
15927c478bd9Sstevel@tonic-gate loop_cleanup:
15937c478bd9Sstevel@tonic-gate 		if (i == 0) {
15947c478bd9Sstevel@tonic-gate 			save_rv = rv;
15957c478bd9Sstevel@tonic-gate 		}
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 		if (derive_session) {
15987c478bd9Sstevel@tonic-gate 			meta_release_slot_session(derive_session);
15997c478bd9Sstevel@tonic-gate 			derive_session = NULL;
16007c478bd9Sstevel@tonic-gate 		}
16017c478bd9Sstevel@tonic-gate 		/* No need to cleanup clones, so we can reuse them later. */
16027c478bd9Sstevel@tonic-gate 	}
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
16057c478bd9Sstevel@tonic-gate 		rv = save_rv;
16067c478bd9Sstevel@tonic-gate 		goto finish;
16077c478bd9Sstevel@tonic-gate 	}
16087c478bd9Sstevel@tonic-gate 
160960722cc8Sizick 	if (isTLSPRF)
161060722cc8Sizick 		goto finish;
161160722cc8Sizick 
16127c478bd9Sstevel@tonic-gate 	/*
16137c478bd9Sstevel@tonic-gate 	 * These SSL/TLS are unique in that the parameter in the API for
16147c478bd9Sstevel@tonic-gate 	 * the new key is unused (NULL). Instead, there are 4 keys which
16157c478bd9Sstevel@tonic-gate 	 * are derived, and are passed back through the mechanism params.
16167c478bd9Sstevel@tonic-gate 	 * Both mechs use the same mechanism parameter type.
16177c478bd9Sstevel@tonic-gate 	 */
16187c478bd9Sstevel@tonic-gate 	if (isSSL) {
16197c478bd9Sstevel@tonic-gate 		CK_SSL3_KEY_MAT_PARAMS *keyparams;
16207c478bd9Sstevel@tonic-gate 		CK_SSL3_KEY_MAT_OUT *keys;
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 		/* NULL checks already done by caller */
16237c478bd9Sstevel@tonic-gate 		keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMechanism->pParameter;
16247c478bd9Sstevel@tonic-gate 		keys = keyparams->pReturnedKeyMaterial;
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 		slotkey1->hObject = keys->hClientMacSecret;
16277c478bd9Sstevel@tonic-gate 		slotkey2->hObject = keys->hServerMacSecret;
16287c478bd9Sstevel@tonic-gate 		slotkey3->hObject = keys->hClientKey;
16297c478bd9Sstevel@tonic-gate 		slotkey4->hObject = keys->hServerKey;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 		rv = meta_object_get_attr(derive_session,
16327c478bd9Sstevel@tonic-gate 		    slotkey1->hObject, newKey1);
16337c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
16347c478bd9Sstevel@tonic-gate 			goto finish;
16357c478bd9Sstevel@tonic-gate 		}
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 		rv = meta_object_get_attr(derive_session,
16387c478bd9Sstevel@tonic-gate 		    slotkey2->hObject, newKey2);
16397c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
16407c478bd9Sstevel@tonic-gate 			goto finish;
16417c478bd9Sstevel@tonic-gate 		}
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 		rv = meta_object_get_attr(derive_session,
16447c478bd9Sstevel@tonic-gate 		    slotkey3->hObject, newKey3);
16457c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
16467c478bd9Sstevel@tonic-gate 			goto finish;
16477c478bd9Sstevel@tonic-gate 		}
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 		rv = meta_object_get_attr(derive_session,
16507c478bd9Sstevel@tonic-gate 		    slotkey4->hObject, newKey4);
16517c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
16527c478bd9Sstevel@tonic-gate 			goto finish;
16537c478bd9Sstevel@tonic-gate 		}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 		newKey1->clones[slotnum] = slotkey1;
16567c478bd9Sstevel@tonic-gate 		newKey2->clones[slotnum] = slotkey2;
16577c478bd9Sstevel@tonic-gate 		newKey3->clones[slotnum] = slotkey3;
16587c478bd9Sstevel@tonic-gate 		newKey4->clones[slotnum] = slotkey4;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 		newKey1->master_clone_slotnum = slotnum;
16617c478bd9Sstevel@tonic-gate 		newKey2->master_clone_slotnum = slotnum;
16627c478bd9Sstevel@tonic-gate 		newKey3->master_clone_slotnum = slotnum;
16637c478bd9Sstevel@tonic-gate 		newKey4->master_clone_slotnum = slotnum;
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 		meta_slot_object_activate(slotkey1, derive_session,
16667c478bd9Sstevel@tonic-gate 		    newKey1->isToken);
16677c478bd9Sstevel@tonic-gate 		slotkey1 = NULL;
16687c478bd9Sstevel@tonic-gate 		meta_slot_object_activate(slotkey2, derive_session,
16697c478bd9Sstevel@tonic-gate 		    newKey2->isToken);
16707c478bd9Sstevel@tonic-gate 		slotkey2 = NULL;
16717c478bd9Sstevel@tonic-gate 		meta_slot_object_activate(slotkey3, derive_session,
16727c478bd9Sstevel@tonic-gate 		    newKey3->isToken);
16737c478bd9Sstevel@tonic-gate 		slotkey3 = NULL;
16747c478bd9Sstevel@tonic-gate 		meta_slot_object_activate(slotkey4, derive_session,
16757c478bd9Sstevel@tonic-gate 		    newKey4->isToken);
16767c478bd9Sstevel@tonic-gate 		slotkey4 = NULL;
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	} else {
16797c478bd9Sstevel@tonic-gate 		slotkey1->hObject = hDerivedKey;
16807c478bd9Sstevel@tonic-gate 		newKey1->clones[slotnum] = slotkey1;
16817c478bd9Sstevel@tonic-gate 		newKey1->master_clone_slotnum = slotnum;
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 		rv = meta_object_get_attr(derive_session,
16847c478bd9Sstevel@tonic-gate 		    slotkey1->hObject, newKey1);
16857c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
16867c478bd9Sstevel@tonic-gate 			goto finish;
16877c478bd9Sstevel@tonic-gate 		}
1688034448feSmcpowers 
1689*8cae6764SAnthony Scarpino 		/* Allow FreeToken to activate onto token obj list */
1690*8cae6764SAnthony Scarpino 		if (newKey1->isFreeToken == FREE_ENABLED)
1691*8cae6764SAnthony Scarpino 			newKey1->isToken = B_TRUE;
1692*8cae6764SAnthony Scarpino 
16937c478bd9Sstevel@tonic-gate 		meta_slot_object_activate(slotkey1, derive_session,
16947c478bd9Sstevel@tonic-gate 		    newKey1->isToken);
16957c478bd9Sstevel@tonic-gate 		slotkey1 = NULL;
16967c478bd9Sstevel@tonic-gate 	}
16977c478bd9Sstevel@tonic-gate 
1698034448feSmcpowers 	if (newKey1->isFreeObject == FREE_ENABLED)
1699034448feSmcpowers 		(void) meta_freeobject_clone(session, newKey1);
1700034448feSmcpowers 
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate finish:
17037c478bd9Sstevel@tonic-gate 	if (slotkey1) {
17047c478bd9Sstevel@tonic-gate 		meta_slot_object_dealloc(slotkey1);
17057c478bd9Sstevel@tonic-gate 	}
17067c478bd9Sstevel@tonic-gate 	if (slotkey2) {
17077c478bd9Sstevel@tonic-gate 		meta_slot_object_dealloc(slotkey2);
17087c478bd9Sstevel@tonic-gate 	}
17097c478bd9Sstevel@tonic-gate 	if (slotkey3) {
17107c478bd9Sstevel@tonic-gate 		meta_slot_object_dealloc(slotkey3);
17117c478bd9Sstevel@tonic-gate 	}
17127c478bd9Sstevel@tonic-gate 	if (slotkey4) {
17137c478bd9Sstevel@tonic-gate 		meta_slot_object_dealloc(slotkey4);
17147c478bd9Sstevel@tonic-gate 	}
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	/* Save the session in case it can be used later */
17177c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
17187c478bd9Sstevel@tonic-gate 		/*
17197c478bd9Sstevel@tonic-gate 		 * If currently stored session is not the one being in use now,
17207c478bd9Sstevel@tonic-gate 		 * release the previous one and store the current one
17217c478bd9Sstevel@tonic-gate 		 */
17227c478bd9Sstevel@tonic-gate 		if ((session->op1.session) &&
17237c478bd9Sstevel@tonic-gate 		    (session->op1.session != derive_session)) {
17247c478bd9Sstevel@tonic-gate 			meta_release_slot_session(session->op1.session);
17257c478bd9Sstevel@tonic-gate 		}
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 		/* Save the session */
17287c478bd9Sstevel@tonic-gate 		session->op1.session = derive_session;
17297c478bd9Sstevel@tonic-gate 	}
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	return (rv);
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate /*
17367c478bd9Sstevel@tonic-gate  * Check the following 4 environment variables for user/application's
17377c478bd9Sstevel@tonic-gate  * configuration for metaslot.  User's configuration takes precedence
17387c478bd9Sstevel@tonic-gate  * over the system wide configuration for metaslot
17397c478bd9Sstevel@tonic-gate  *
17407c478bd9Sstevel@tonic-gate  * ${METASLOT_ENABLED}
17417c478bd9Sstevel@tonic-gate  * ${METASLOT_OBJECTSTORE_SLOT}
17427c478bd9Sstevel@tonic-gate  * ${METASLOT_OBJECTSTORE_TOKEN}
17437c478bd9Sstevel@tonic-gate  * ${METASLOT_AUTO_KEY_MIGRATE}
17447c478bd9Sstevel@tonic-gate  *
1745cd7d5fafSJan Pechanec  * ${_METASLOT_ENABLE_THRESHOLD} - private environmental variable to
1746cd7d5fafSJan Pechanec  * enable the treshold checking which is disabled by default.
1747cd7d5fafSJan Pechanec  *
17487c478bd9Sstevel@tonic-gate  * values defined in these environment variables will be stored in the
1749cd7d5fafSJan Pechanec  * global variable "metaslot_config". Variable threshold_chk_disabled is an
1750cd7d5fafSJan Pechanec  * exception.
17517c478bd9Sstevel@tonic-gate  */
17527c478bd9Sstevel@tonic-gate void
17537c478bd9Sstevel@tonic-gate get_user_metaslot_config()
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate 	char *env_val = NULL;
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	/*
17587c478bd9Sstevel@tonic-gate 	 * Check to see if any environment variable is defined
17597c478bd9Sstevel@tonic-gate 	 * by the user for configuring metaslot.
17607c478bd9Sstevel@tonic-gate 	 */
17617c478bd9Sstevel@tonic-gate 	bzero(&metaslot_config, sizeof (metaslot_config));
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 	/* METASLOT_ENABLED */
17647c478bd9Sstevel@tonic-gate 	env_val = getenv("METASLOT_ENABLED");
17657c478bd9Sstevel@tonic-gate 	if (env_val) {
17667c478bd9Sstevel@tonic-gate 		metaslot_config.enabled_specified = B_TRUE;
17677c478bd9Sstevel@tonic-gate 		if (strcasecmp(env_val, TRUE_STRING) == 0) {
17687c478bd9Sstevel@tonic-gate 			metaslot_config.enabled = B_TRUE;
17697c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(env_val, FALSE_STRING) == 0) {
17707c478bd9Sstevel@tonic-gate 			metaslot_config.enabled = B_FALSE;
17717c478bd9Sstevel@tonic-gate 		} else {
17727c478bd9Sstevel@tonic-gate 			/* value is neither 1 or 0, ignore this value */
17737c478bd9Sstevel@tonic-gate 			metaslot_config.enabled_specified = B_FALSE;
17747c478bd9Sstevel@tonic-gate 		}
17757c478bd9Sstevel@tonic-gate 	}
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	/* METASLOT_AUTO_KEY_MIGRATE */
17787c478bd9Sstevel@tonic-gate 	env_val = getenv("METASLOT_AUTO_KEY_MIGRATE");
17797c478bd9Sstevel@tonic-gate 	if (env_val) {
17807c478bd9Sstevel@tonic-gate 		metaslot_config.auto_key_migrate_specified = B_TRUE;
17817c478bd9Sstevel@tonic-gate 		if (strcasecmp(env_val, TRUE_STRING) == 0) {
17827c478bd9Sstevel@tonic-gate 			metaslot_config.auto_key_migrate = B_TRUE;
17837c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(env_val, FALSE_STRING) == 0) {
17847c478bd9Sstevel@tonic-gate 			metaslot_config.auto_key_migrate = B_FALSE;
17857c478bd9Sstevel@tonic-gate 		} else {
17867c478bd9Sstevel@tonic-gate 			/* value is neither 1 or 0, ignore this value */
17877c478bd9Sstevel@tonic-gate 			metaslot_config.auto_key_migrate_specified = B_FALSE;
17887c478bd9Sstevel@tonic-gate 		}
17897c478bd9Sstevel@tonic-gate 	}
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	/* METASLOT_OBJECTSTORE_SLOT */
17927c478bd9Sstevel@tonic-gate 	env_val = getenv("METASLOT_OBJECTSTORE_SLOT");
17937c478bd9Sstevel@tonic-gate 	if (env_val) {
17947c478bd9Sstevel@tonic-gate 		metaslot_config.keystore_slot_specified = B_TRUE;
17957c478bd9Sstevel@tonic-gate 		(void) strlcpy((char *)metaslot_config.keystore_slot, env_val,
17967c478bd9Sstevel@tonic-gate 		    SLOT_DESCRIPTION_SIZE);
17977c478bd9Sstevel@tonic-gate 	}
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	/* METASLOT_OBJECTSTORE_TOKEN */
18007c478bd9Sstevel@tonic-gate 	env_val = getenv("METASLOT_OBJECTSTORE_TOKEN");
18017c478bd9Sstevel@tonic-gate 	if (env_val) {
18027c478bd9Sstevel@tonic-gate 		metaslot_config.keystore_token_specified = B_TRUE;
18037c478bd9Sstevel@tonic-gate 		(void) strlcpy((char *)metaslot_config.keystore_token, env_val,
18047c478bd9Sstevel@tonic-gate 		    TOKEN_LABEL_SIZE);
18057c478bd9Sstevel@tonic-gate 	}
1806cd7d5fafSJan Pechanec 
1807cd7d5fafSJan Pechanec 	/* _METASLOT_ENABLE_THRESHOLD */
1808cd7d5fafSJan Pechanec 	env_val = getenv("_METASLOT_ENABLE_THRESHOLD");
1809cd7d5fafSJan Pechanec 	if (env_val) {
1810cd7d5fafSJan Pechanec 		threshold_chk_enabled = B_TRUE;
1811cd7d5fafSJan Pechanec 	}
18127c478bd9Sstevel@tonic-gate }
1813