xref: /illumos-gate/usr/src/lib/pkcs11/libpkcs11/common/metaUtil.c (revision f48205be61a214698b763ff550ab9e657525104c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <cryptoutil.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <strings.h>
33 #include "metaGlobal.h"
34 
35 /*
36  * meta_operation_init
37  *
38  */
39 CK_RV
40 meta_operation_init(int optype, meta_session_t *session,
41 	CK_MECHANISM *pMechanism, meta_object_t *key)
42 {
43 	CK_RV rv, save_rv;
44 	mechinfo_t **supporting_slots;
45 	CK_ULONG slotnum;
46 	unsigned long i, slotCount = 0;
47 	slot_session_t *init_session = NULL;
48 
49 	/*
50 	 * If an operation is already active, cleanup existing operation
51 	 * and start a new one.
52 	 */
53 	if (session->op1.type != OP_UNUSED) {
54 		meta_operation_cleanup(session, session->op1.type, B_FALSE);
55 	}
56 
57 	/*
58 	 * Get a list of capable slots.
59 	 *
60 	 * If the specified mechanism is used in this session last time,
61 	 * the list of capable slots is already retrieved.  We can save
62 	 * some processing, and just use that list of slots.
63 	 */
64 	if (((session->mech_support_info).mech != pMechanism->mechanism) ||
65 	    ((session->mech_support_info).num_supporting_slots == 0)) {
66 		(session->mech_support_info).mech = pMechanism->mechanism;
67 		rv = meta_mechManager_get_slots(&(session->mech_support_info),
68 		    B_FALSE);
69 		if (rv != CKR_OK) {
70 			goto finish;
71 		}
72 	}
73 
74 	rv = CKR_FUNCTION_FAILED;
75 
76 	/* The following 2 assignment is just to make the code more readable */
77 	slotCount = (session->mech_support_info).num_supporting_slots;
78 	supporting_slots = (session->mech_support_info).supporting_slots;
79 
80 	/* Attempt to initialize operation on slots until one succeeds. */
81 	for (i = 0; i < slotCount; i++) {
82 		slot_object_t *init_key;
83 		CK_SLOT_ID fw_st_id;
84 
85 		init_session = NULL;
86 
87 		slotnum = supporting_slots[i]->slotnum;
88 
89 		/*
90 		 * An actual session with the underlying slot is required
91 		 * for the operation.  When the operation is successfully
92 		 * completed, the underlying session with the slot
93 		 * is not released back to the list of available sessions
94 		 * pool.  This will help if the next operation can
95 		 * also be done on the same slot, because it avoids
96 		 * one extra trip to the session pool to get an idle session.
97 		 * If the operation can't be done on that slot,
98 		 * we release the session back to the session pool then.
99 		 */
100 		if (session->op1.session != NULL) {
101 
102 			if ((session->op1.session)->slotnum == slotnum) {
103 				init_session = session->op1.session;
104 				/*
105 				 * set it to NULL for now, assign it to
106 				 * init_session again if it is successful
107 				 */
108 				session->op1.session = NULL;
109 			} else {
110 				init_session = NULL;
111 			}
112 
113 		}
114 
115 		if (!init_session) {
116 			rv = meta_get_slot_session(slotnum, &init_session,
117 			    session->session_flags);
118 			if (rv != CKR_OK) {
119 				goto loop_cleanup;
120 			}
121 		}
122 
123 		/* if necessary, ensure a clone of the obj exists in slot */
124 		if (optype != OP_DIGEST) {
125 			rv = meta_object_get_clone(key, slotnum, init_session,
126 				&init_key);
127 
128 			if (rv != CKR_OK) {
129 				goto loop_cleanup;
130 			}
131 		}
132 
133 		fw_st_id = init_session->fw_st_id;
134 		switch (optype) {
135 			case OP_ENCRYPT:
136 				rv = FUNCLIST(fw_st_id)->C_EncryptInit(
137 					init_session->hSession, pMechanism,
138 					init_key->hObject);
139 				break;
140 			case OP_DECRYPT:
141 				rv = FUNCLIST(fw_st_id)->C_DecryptInit(
142 					init_session->hSession, pMechanism,
143 					init_key->hObject);
144 				break;
145 			case OP_DIGEST:
146 				rv = FUNCLIST(fw_st_id)->C_DigestInit(
147 					init_session->hSession, pMechanism);
148 				break;
149 			case OP_SIGN:
150 				rv = FUNCLIST(fw_st_id)->C_SignInit(
151 					init_session->hSession, pMechanism,
152 					init_key->hObject);
153 				break;
154 			case OP_VERIFY:
155 				rv = FUNCLIST(fw_st_id)->C_VerifyInit(
156 					init_session->hSession, pMechanism,
157 					init_key->hObject);
158 				break;
159 			case OP_SIGNRECOVER:
160 				rv = FUNCLIST(fw_st_id)->C_SignRecoverInit(
161 					init_session->hSession, pMechanism,
162 					init_key->hObject);
163 				break;
164 			case OP_VERIFYRECOVER:
165 				rv = FUNCLIST(fw_st_id)->C_VerifyRecoverInit(
166 					init_session->hSession, pMechanism,
167 					init_key->hObject);
168 				break;
169 
170 			default:
171 				/*NOTREACHED*/
172 				rv = CKR_FUNCTION_FAILED;
173 				break;
174 		}
175 
176 		if (rv == CKR_OK)
177 			break;
178 
179 loop_cleanup:
180 		if (i == 0) {
181 			save_rv = rv;
182 		}
183 
184 		if (init_session) {
185 			meta_release_slot_session(init_session);
186 			init_session = NULL;
187 		}
188 
189 	}
190 
191 	if (rv == CKR_OK) {
192 
193 		/*
194 		 * If currently stored session is not the one being in use now,
195 		 * release the previous one and store the current one
196 		 */
197 		if ((session->op1.session) &&
198 		    (session->op1.session != init_session)) {
199 			meta_release_slot_session(session->op1.session);
200 		}
201 
202 		/* Save the session */
203 		session->op1.session = init_session;
204 		session->op1.type = optype;
205 	} else {
206 		rv = save_rv;
207 	}
208 
209 finish:
210 	return (rv);
211 }
212 
213 /*
214  * meta_do_operation
215  *
216  * NOTES:
217  *
218  * 1) The spec says you cannot do a C_Encrypt after a C_EncUpdate,
219  *    but we don't explicitly enforce it here (ie, disallow doing MODE_SINGLE
220  *    after a MODE_UPDATE). Instead, we just assume the underlying provider
221  *    will catch the problem and return an appropriate error.
222  *
223  * 2) Note that the Verify operations are a little unusual, due to the
224  *    PKCS#11 API. For C_Verify, the last two arguments are used as inputs,
225  *    unlike the other single pass operations (where they are outputs). For
226  *    C_VerifyFinal, in/inLen are passed instead of out/outLen like the other
227  *    Final operations.
228  *
229  * 3) C_DigestKey is the only crypto operation that uses an object after
230  *    the operation has been initialized. No other callers should provide
231  *    this argument (use NULL).
232  */
233 CK_RV
234 meta_do_operation(int optype, int mode,
235     meta_session_t *session, meta_object_t *object,
236     CK_BYTE *in, CK_ULONG inLen, CK_BYTE *out, CK_ULONG *outLen)
237 {
238 	CK_RV rv;
239 	CK_SESSION_HANDLE hSession;
240 	CK_SLOT_ID fw_st_id;
241 	slot_session_t *slot_session = NULL;
242 	slot_object_t *slot_object = NULL;
243 
244 	boolean_t shutdown, finished_normally;
245 
246 	if (optype != session->op1.type) {
247 		return (CKR_OPERATION_NOT_INITIALIZED);
248 	}
249 
250 	slot_session = session->op1.session;
251 
252 	if (slot_session) {
253 		hSession = slot_session->hSession;
254 		fw_st_id = slot_session->fw_st_id;
255 	} else {
256 		/* should never be here */
257 		return (CKR_FUNCTION_FAILED);
258 	}
259 
260 
261 	/* Do the operation... */
262 	switch (optype | mode) {
263 		case OP_ENCRYPT | MODE_SINGLE:
264 			rv = FUNCLIST(fw_st_id)->C_Encrypt(hSession, in,
265 			    inLen, out, outLen);
266 			break;
267 		case OP_ENCRYPT | MODE_UPDATE:
268 			rv = FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, in,
269 			    inLen, out, outLen);
270 			break;
271 		case OP_ENCRYPT | MODE_FINAL:
272 			rv = FUNCLIST(fw_st_id)->C_EncryptFinal(hSession, out,
273 			    outLen);
274 			break;
275 
276 		case OP_DECRYPT | MODE_SINGLE:
277 			rv = FUNCLIST(fw_st_id)->C_Decrypt(hSession, in,
278 			    inLen, out, outLen);
279 			break;
280 		case OP_DECRYPT | MODE_UPDATE:
281 			rv = FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, in,
282 			    inLen, out, outLen);
283 			break;
284 		case OP_DECRYPT | MODE_FINAL:
285 			rv = FUNCLIST(fw_st_id)->C_DecryptFinal(hSession, out,
286 			    outLen);
287 			break;
288 
289 		case OP_DIGEST | MODE_SINGLE:
290 			rv = FUNCLIST(fw_st_id)->C_Digest(hSession, in, inLen,
291 			    out, outLen);
292 			break;
293 		case OP_DIGEST | MODE_UPDATE:
294 			/* noOutputForOp = TRUE; */
295 			rv = FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, in,
296 			    inLen);
297 			break;
298 		case OP_DIGEST | MODE_UPDATE_WITHKEY:
299 			/* noOutputForOp = TRUE; */
300 			/*
301 			 * For C_DigestKey, a key is provided and
302 			 * we need the clone.
303 			 */
304 			rv = meta_object_get_clone(object,
305 			    slot_session->slotnum, slot_session, &slot_object);
306 			if (rv == CKR_OK)
307 				rv = FUNCLIST(fw_st_id)->C_DigestKey(hSession,
308 				    slot_object->hObject);
309 			break;
310 		case OP_DIGEST | MODE_FINAL:
311 			rv = FUNCLIST(fw_st_id)->C_DigestFinal(hSession, out,
312 			    outLen);
313 			break;
314 
315 
316 		case OP_SIGN | MODE_SINGLE:
317 			rv = FUNCLIST(fw_st_id)->C_Sign(hSession, in, inLen,
318 			    out, outLen);
319 			break;
320 		case OP_SIGN | MODE_UPDATE:
321 			/* noOutputForOp = TRUE; */
322 			rv = FUNCLIST(fw_st_id)->C_SignUpdate(hSession, in,
323 			    inLen);
324 			break;
325 		case OP_SIGN | MODE_FINAL:
326 			rv = FUNCLIST(fw_st_id)->C_SignFinal(hSession, out,
327 			    outLen);
328 			break;
329 
330 		case OP_VERIFY | MODE_SINGLE:
331 			/* noOutputForOp = TRUE; */
332 			/* Yes, use *outLen not outLen (think in2/in2Len) */
333 			rv = FUNCLIST(fw_st_id)->C_Verify(hSession, in,
334 			    inLen, out, *outLen);
335 			break;
336 		case OP_VERIFY | MODE_UPDATE:
337 			/* noOutputForOp = TRUE; */
338 			rv = FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, in,
339 			    inLen);
340 			break;
341 		case OP_VERIFY | MODE_FINAL:
342 			/* noOutputForOp = TRUE; */
343 			/* Yes, use in/inLen instead of out/outLen */
344 			rv = FUNCLIST(fw_st_id)->C_VerifyFinal(hSession, in,
345 			    inLen);
346 			break;
347 
348 		case OP_SIGNRECOVER | MODE_SINGLE:
349 			rv = FUNCLIST(fw_st_id)->C_SignRecover(hSession, in,
350 			    inLen, out, outLen);
351 			break;
352 		case OP_VERIFYRECOVER | MODE_SINGLE:
353 			rv = FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, in,
354 			    inLen, out, outLen);
355 			break;
356 
357 		default:
358 			rv = CKR_FUNCTION_FAILED;
359 	}
360 
361 
362 
363 	/*
364 	 * Mark the operation type as inactive if an abnormal error
365 	 * happens, or if the operation normally results in an inactive
366 	 * operation state.
367 	 *
368 	 * NOTE: The spec isn't very explicit about what happens when you
369 	 * call C_FooFinal (or C_Foo) with a NULL output buffer (to get the
370 	 * output size), but there is no output. Technically this should be
371 	 * no different than the normal case (ie, when there is output), and
372 	 * the operation should remain active until the second call actually
373 	 * terminates it. However, one could make the case that there is no
374 	 * need for a second call, since no data is available. This presents
375 	 * dilemma for metaslot, because we don't know if the operation is
376 	 * going to remain active or not. We will assume a strict reading of
377 	 * the spec, the operation will remain active.
378 	 */
379 	if (rv == CKR_BUFFER_TOO_SMALL ||
380 	    (rv == CKR_OK && out == NULL && optype != OP_VERIFY)) {
381 		/* Leave op active for retry (with larger buffer). */
382 		shutdown = B_FALSE;
383 	} else if (rv != CKR_OK) {
384 		shutdown = B_TRUE;
385 		finished_normally = B_FALSE;
386 	} else { /* CKR_OK */
387 		if (mode == MODE_SINGLE || mode == MODE_FINAL) {
388 			shutdown = B_TRUE;
389 			finished_normally = B_TRUE;
390 		} else { /* mode == MODE_UPDATE */
391 			shutdown = B_FALSE;
392 		}
393 	}
394 
395 	if (shutdown)
396 		meta_operation_cleanup(session, optype, finished_normally);
397 
398 	return (rv);
399 }
400 
401 /*
402  * meta_operation_cleanup
403  *
404  * Cleans up an operation in the specified session.
405  * If the operation did not finish normally, it will force
406  * the operation to terminate.
407  */
408 void
409 meta_operation_cleanup(meta_session_t *session, int optype,
410     boolean_t finished_normally)
411 {
412 	operation_info_t *op;
413 	CK_SESSION_HANDLE hSession;
414 	CK_SLOT_ID fw_st_id;
415 
416 	if (!finished_normally) {
417 		CK_BYTE dummy_buf[8];
418 
419 		if (session->op1.type == optype)
420 			op = &session->op1;
421 		else
422 			return;
423 
424 		hSession = op->session->hSession;
425 		fw_st_id = op->session->fw_st_id;
426 
427 		/*
428 		 * There's no simple, reliable way to abort an
429 		 * operation. So, we'll force the operation to finish.
430 		 *
431 		 * We are here either because we need to abort either after
432 		 * C_xxxxxInit() or C_xxxxxUpdate().
433 		 *
434 		 * We will call C_xxxxxUpdate() with invalid argument to
435 		 * force the operation to abort.  According to the PKCS#11
436 		 * spec, any call to C_xxxxxUpdate() returns in an error
437 		 * will terminate the current operation.
438 		 */
439 
440 		switch (optype) {
441 		    case OP_ENCRYPT:
442 			(void) FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession,
443 			    NULL, 8, dummy_buf, NULL);
444 			break;
445 		    case OP_DECRYPT:
446 			(void) FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession,
447 			    NULL, 8, dummy_buf, NULL);
448 			break;
449 		    case OP_DIGEST:
450 			(void) FUNCLIST(fw_st_id)->C_DigestUpdate(hSession,
451 			    NULL, 8);
452 			break;
453 		    case OP_SIGN:
454 			(void) FUNCLIST(fw_st_id)->C_SignUpdate(hSession,
455 			    NULL, 8);
456 			break;
457 		    case OP_SIGNRECOVER:
458 			(void) FUNCLIST(fw_st_id)->C_SignRecover(hSession,
459 			    NULL, 8, dummy_buf, NULL);
460 			break;
461 		    case OP_VERIFY:
462 			(void) FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession,
463 			    NULL, 8);
464 			break;
465 		    case OP_VERIFYRECOVER:
466 			(void) FUNCLIST(fw_st_id)->C_VerifyRecover(hSession,
467 			    NULL, 8, dummy_buf, NULL);
468 			break;
469 		    default:
470 			/*NOTREACHED*/
471 			break;
472 		}
473 		meta_release_slot_session(session->op1.session);
474 		session->op1.session = NULL;
475 	}
476 
477 	session->op1.type = OP_UNUSED;
478 }
479 
480 /*
481  * Gets the list of slots that supports the specified mechanism.
482  *
483  * If "token_only", check if the keystore slot supports the specified mech,
484  * if so, return that slot only
485  *
486  * Otherwise, get list of all slots that support the mech.
487  *
488  */
489 static CK_RV
490 get_slotlist_for_mech(CK_MECHANISM_TYPE mech_type,
491     mech_support_info_t *mech_support_info,
492     mechinfo_t ***slots, unsigned long *slot_count, boolean_t token_only)
493 {
494 	boolean_t mech_supported = B_FALSE;
495 	CK_RV rv = CKR_OK;
496 
497 	if (token_only) {
498 		rv = meta_mechManager_slot_supports_mech(mech_type,
499 		    get_keystore_slotnum(), &mech_supported,
500 		    &((mech_support_info->supporting_slots)[0]), B_FALSE);
501 
502 		if (rv != CKR_OK) {
503 			return (rv);
504 		}
505 
506 		if (mech_supported) {
507 			mech_support_info->mech = mech_type;
508 			/*
509 			 * Want to leave this at 0, that way, when
510 			 * other operation needs to
511 			 * use this mechanism, but not just for the
512 			 * keystore slot, we will look at other slots
513 			 */
514 			mech_support_info->num_supporting_slots = 0;
515 			*slots = mech_support_info->supporting_slots;
516 			*slot_count = 1;
517 		} else {
518 			rv = CKR_FUNCTION_FAILED;
519 		}
520 	} else {
521 		/*
522 		 * Get a list of slots that support this mech .
523 		 *
524 		 * If the specified mechanism is used last time,
525 		 * the list of capable slots is already retrieved.
526 		 * We can save some processing, and just use that list of slots.
527 		 */
528 		if ((mech_support_info->mech != mech_type) ||
529 		    (mech_support_info->num_supporting_slots == 0)) {
530 			mech_support_info->mech = mech_type;
531 			rv = meta_mechManager_get_slots(mech_support_info,
532 			    B_FALSE);
533 			if (rv != CKR_OK) {
534 				return (CKR_FUNCTION_FAILED);
535 			}
536 		}
537 		*slots = mech_support_info->supporting_slots;
538 		*slot_count = mech_support_info->num_supporting_slots;
539 	}
540 	return (rv);
541 }
542 
543 /*
544  * meta_generate_keys
545  *
546  * Generates symmetric (k1=key, k2=null) or asymmetric (k1=pub, k2=priv) keys.
547  *
548  */
549 CK_RV
550 meta_generate_keys(meta_session_t *session, CK_MECHANISM *pMechanism,
551 	CK_ATTRIBUTE *k1Template, CK_ULONG k1AttrCount, meta_object_t *key1,
552 	CK_ATTRIBUTE *k2Template, CK_ULONG k2AttrCount, meta_object_t *key2)
553 {
554 	CK_RV rv, save_rv;
555 	slot_session_t *gen_session = NULL;
556 	slot_object_t *slot_key1 = NULL, *slot_key2 = NULL;
557 	mechinfo_t **slots = NULL;
558 	unsigned long i, slotCount = 0;
559 	boolean_t doKeyPair = B_FALSE, token_only = B_FALSE;
560 	CK_ULONG slotnum;
561 	/*
562 	 * Since the keygen call is in a loop, it is performance-wise useful
563 	 * to keep track of the token value
564 	 */
565 	CK_BBOOL current_token1_value = FALSE, current_token2_value = FALSE;
566 
567 	(void) get_template_boolean(CKA_TOKEN, k1Template, k1AttrCount,
568 	    &(key1->isToken));
569 	(void) get_template_boolean(CKA_SENSITIVE, k1Template, k1AttrCount,
570 	    &(key1->isSensitive));
571 	(void) get_template_boolean(CKA_PRIVATE, k1Template, k1AttrCount,
572 	    &(key1->isPrivate));
573 
574 	if (!get_template_boolean(CKA_EXTRACTABLE, k1Template, k1AttrCount,
575 		&(key1->isExtractable)))
576 		key1->isExtractable = B_TRUE;
577 
578 	if (key1->isToken)
579 		current_token1_value = TRUE;
580 
581 	if (key2) {
582 		(void) get_template_boolean(CKA_TOKEN, k2Template, k2AttrCount,
583 		    &(key2->isToken));
584 		(void) get_template_boolean(CKA_SENSITIVE, k2Template,
585 		    k2AttrCount, &(key2->isSensitive));
586 		(void) get_template_boolean(CKA_PRIVATE, k2Template,
587 		    k2AttrCount, &(key2->isPrivate));
588 
589 		if (!get_template_boolean(CKA_EXTRACTABLE, k2Template,
590 		    k2AttrCount, &(key2->isExtractable)))
591 			key2->isExtractable = B_TRUE;
592 
593 		if (key2->isToken)
594 			current_token2_value = TRUE;
595 
596 		doKeyPair = B_TRUE;
597 	}
598 
599 
600 	/* Can't create token objects in a read-only session. */
601 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
602 	    ((key1->isToken) || ((key2) && (key2->isToken)))) {
603 		return (CKR_SESSION_READ_ONLY);
604 	}
605 
606 	if (meta_freeobject_check(session, key1, pMechanism, k1Template,
607 		k1AttrCount, NULL)) {
608 
609 		if ((key1->isPrivate || (doKeyPair && key2->isPrivate)) &&
610 		    !metaslot_logged_in())
611 			return (CKR_USER_NOT_LOGGED_IN);
612 
613 		if (!meta_freeobject_set(key1, k1Template, k1AttrCount,
614 			B_FALSE))
615 			return (CKR_FUNCTION_FAILED);
616 
617 		if (doKeyPair) {
618 			key2->isFreeObject = FREE_ALLOWED_KEY;
619 			if (!meta_freeobject_set(key2, k2Template, k2AttrCount,
620 				B_FALSE))
621 				return (CKR_FUNCTION_FAILED);
622 		}
623 
624 	} else if (doKeyPair) {
625 		/*
626 		 * If this is a keypair operation, the second key cannot be
627 		 * a FreeObject if the first is not.  Both keys will have the
628 		 * same fate when it comes to provider choices
629 		 */
630 		key2->isFreeObject = FREE_DISABLED;
631 		key2->isFreeToken = FREE_DISABLED;
632 	}
633 
634 	if ((key1->isToken) || ((doKeyPair) && (key2->isToken))) {
635 		/*
636 		 * Token objects can only be generated in the token object
637 		 * slot.  If token object slot doesn't support generating
638 		 * the key, it will just not be done.
639 		 */
640 		token_only = B_TRUE;
641 	}
642 
643 	rv = get_slotlist_for_mech(pMechanism->mechanism,
644 	    &(session->mech_support_info), &slots, &slotCount, token_only);
645 
646 	if (rv != CKR_OK) {
647 		goto finish;
648 	}
649 
650 	rv = meta_slot_object_alloc(&slot_key1);
651 	if (doKeyPair && rv == CKR_OK)
652 		rv = meta_slot_object_alloc(&slot_key2);
653 	if (rv != CKR_OK)
654 		goto finish;
655 
656 	/* Attempt to generate key on slots until one succeeds. */
657 	for (i = 0; i < slotCount; i++) {
658 		CK_SESSION_HANDLE hSession;
659 		CK_SLOT_ID fw_st_id;
660 
661 		gen_session = NULL;
662 
663 		slotnum = slots[i]->slotnum;
664 
665 		if (session->op1.session != NULL) {
666 			if ((session->op1.session)->slotnum == slotnum) {
667 				gen_session = session->op1.session;
668 				/*
669 				 * set it to NULL for now, assign it to
670 				 * gen_session again if it is successful
671 				 */
672 				session->op1.session = NULL;
673 			} else {
674 				gen_session = NULL;
675 			}
676 		}
677 
678 		if (gen_session == NULL) {
679 			rv = meta_get_slot_session(slotnum, &gen_session,
680 			    session->session_flags);
681 			if (rv != CKR_OK) {
682 				goto loop_cleanup;
683 			}
684 		}
685 
686 		/*
687 		 * If this is a freetoken, make sure the templates are
688 		 * approriate for the slot being used.
689 		 */
690 		if (key1->isFreeToken == FREE_ENABLED) {
691 			rv = meta_freetoken_set(slotnum,
692 			    &current_token1_value, k1Template, k1AttrCount);
693 			if (rv != CKR_OK)
694 				goto loop_cleanup;
695 		}
696 
697 		if (doKeyPair && key2->isFreeToken == FREE_ENABLED) {
698 			rv = meta_freetoken_set(slotnum,
699 			    &current_token2_value, k2Template, k2AttrCount);
700 			if (rv != CKR_OK)
701 				goto loop_cleanup;
702 		}
703 
704 		fw_st_id = gen_session->fw_st_id;
705 		hSession = gen_session->hSession;
706 
707 		if (doKeyPair) {
708 			rv = FUNCLIST(fw_st_id)->C_GenerateKeyPair(hSession,
709 			    pMechanism, k1Template, k1AttrCount,
710 			    k2Template, k2AttrCount,
711 			    &slot_key1->hObject, &slot_key2->hObject);
712 		} else {
713 			rv = FUNCLIST(fw_st_id)->C_GenerateKey(hSession,
714 			    pMechanism, k1Template, k1AttrCount,
715 			    &slot_key1->hObject);
716 		}
717 
718 		if (rv == CKR_OK)
719 			break;
720 
721 loop_cleanup:
722 		if (i == 0) {
723 			save_rv = rv;
724 		}
725 
726 		if (gen_session) {
727 			meta_release_slot_session(gen_session);
728 			gen_session = NULL;
729 		}
730 	}
731 	if (rv != CKR_OK) {
732 		rv = save_rv;
733 		goto finish;
734 	}
735 
736 	rv = meta_object_get_attr(gen_session, slot_key1->hObject, key1);
737 	if (rv != CKR_OK) {
738 		goto finish;
739 	}
740 
741 	if (key2) {
742 		rv = meta_object_get_attr(gen_session, slot_key2->hObject,
743 		    key2);
744 		if (rv != CKR_OK) {
745 			goto finish;
746 		}
747 	}
748 
749 	meta_slot_object_activate(slot_key1, gen_session, key1->isToken);
750 	key1->clones[slotnum] = slot_key1;
751 	key1->master_clone_slotnum = slotnum;
752 	slot_key1 = NULL;
753 	if (key1->isFreeObject == FREE_ENABLED) {
754 		rv = meta_freeobject_clone(session, key1);
755 		if (rv != CKR_OK)
756 			goto finish;
757 	}
758 
759 	if (doKeyPair) {
760 		meta_slot_object_activate(slot_key2, gen_session,
761 		    key2->isToken);
762 		key2->clones[slotnum] = slot_key2;
763 		key2->master_clone_slotnum = slotnum;
764 		slot_key2 = NULL;
765 		if (key2->isFreeObject == FREE_ENABLED) {
766 			rv = meta_freeobject_clone(session, key2);
767 			if (rv != CKR_OK)
768 				goto finish;
769 		}
770 	}
771 
772 finish:
773 	if (slot_key1) {
774 		meta_slot_object_dealloc(slot_key1);
775 	}
776 
777 	if (slot_key2) {
778 		meta_slot_object_dealloc(slot_key2);
779 	}
780 
781 	/* Save the session in case it can be used later */
782 	if (rv == CKR_OK) {
783 		/*
784 		 * If currently stored session is not the one being in use now,
785 		 * release the previous one and store the current one
786 		 */
787 		if ((session->op1.session) &&
788 		    (session->op1.session != gen_session)) {
789 			meta_release_slot_session(session->op1.session);
790 		}
791 
792 		/* Save the session */
793 		session->op1.session = gen_session;
794 	}
795 
796 	return (rv);
797 }
798 
799 
800 /*
801  * meta_wrap_key
802  *
803  */
804 CK_RV
805 meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism,
806     meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key,
807     CK_ULONG *wrapped_key_len)
808 {
809 	CK_RV rv, save_rv;
810 	slot_session_t *wrap_session = NULL;
811 	slot_object_t *slot_wrappingkey, *slot_inputkey;
812 	mechinfo_t **slots = NULL;
813 	unsigned long i, slotCount = 0;
814 	CK_ULONG slotnum;
815 
816 	/*
817 	 * If the key to be wrapped is a token object,
818 	 * the operation can only be done in the token object slot.
819 	 */
820 	rv = get_slotlist_for_mech(pMechanism->mechanism,
821 	    &(session->mech_support_info), &slots, &slotCount,
822 	    inputkey->isToken);
823 
824 	if (rv != CKR_OK) {
825 		return (rv);
826 	}
827 
828 	/* Attempt to wrap key on slots until one succeeds. */
829 	for (i = 0; i < slotCount; i++) {
830 
831 		slotnum = slots[i]->slotnum;
832 		wrap_session = NULL;
833 
834 		if (session->op1.session != NULL) {
835 			if ((session->op1.session)->slotnum == slotnum) {
836 				wrap_session = session->op1.session;
837 				/*
838 				 * set it to NULL for now, assign it to
839 				 * wrap_session again if it is successful
840 				 */
841 				session->op1.session = NULL;
842 			} else {
843 				wrap_session = NULL;
844 			}
845 		}
846 
847 		if (wrap_session == NULL) {
848 			rv = meta_get_slot_session(slotnum, &wrap_session,
849 			    session->session_flags);
850 			if (rv != CKR_OK) {
851 				goto loop_cleanup;
852 			}
853 		}
854 
855 		rv = meta_object_get_clone(wrappingkey, slotnum,
856 		    wrap_session, &slot_wrappingkey);
857 		if (rv != CKR_OK)
858 			goto loop_cleanup;
859 
860 		rv = meta_object_get_clone(inputkey, slotnum,
861 		    wrap_session, &slot_inputkey);
862 		if (rv != CKR_OK)
863 			goto loop_cleanup;
864 
865 		rv = FUNCLIST(wrap_session->fw_st_id)->C_WrapKey(
866 		    wrap_session->hSession, pMechanism,
867 		    slot_wrappingkey->hObject, slot_inputkey->hObject,
868 		    wrapped_key, wrapped_key_len);
869 
870 		if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
871 			break;
872 
873 loop_cleanup:
874 		if (i == 0) {
875 			save_rv = rv;
876 		}
877 
878 		if (wrap_session) {
879 			meta_release_slot_session(wrap_session);
880 			wrap_session = NULL;
881 		}
882 	}
883 	if (rv != CKR_OK) {
884 		if (rv != CKR_BUFFER_TOO_SMALL) {
885 			if (i == slotCount) {
886 				rv = save_rv;
887 			}
888 		}
889 	}
890 
891 finish:
892 	/* Save the session in case it can be used later */
893 	if (rv == CKR_OK) {
894 		/*
895 		 * If currently stored session is not the one being in use now,
896 		 * release the previous one and store the current one
897 		 */
898 		if ((session->op1.session) &&
899 		    (session->op1.session != wrap_session)) {
900 			meta_release_slot_session(session->op1.session);
901 		}
902 
903 		/* Save the session */
904 		session->op1.session = wrap_session;
905 	}
906 	return (rv);
907 }
908 
909 
910 
911 /*
912  * meta_unwrap_key
913  *
914  */
915 CK_RV
916 meta_unwrap_key(meta_session_t *session,
917 	CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key,
918 	CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len,
919 	CK_ATTRIBUTE *template, CK_ULONG template_size,
920 	meta_object_t *unwrapped_key)
921 {
922 	CK_RV rv, save_rv;
923 	CK_OBJECT_HANDLE hUnwrappedKey;
924 	slot_session_t *unwrap_session = NULL;
925 	slot_object_t *slot_unwrappingkey, *slot_unwrapped_key;
926 	mechinfo_t **slots = NULL;
927 	unsigned long i, slotCount = 0;
928 	CK_ULONG slotnum;
929 
930 	/* Can't create token objects in a read-only session. */
931 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
932 	    unwrapped_key->isToken) {
933 		return (CKR_SESSION_READ_ONLY);
934 	}
935 
936 	/*
937 	 * If the the resulting unwrapped key
938 	 * needs to be a token object, the operation can only
939 	 * be performed in the token slot, if it is supported.
940 	 */
941 	rv = get_slotlist_for_mech(pMechanism->mechanism,
942 	    &(session->mech_support_info), &slots, &slotCount,
943 	    unwrapped_key->isToken);
944 
945 	if (rv != CKR_OK) {
946 		return (rv);
947 	}
948 
949 	rv = meta_slot_object_alloc(&slot_unwrapped_key);
950 	if (rv != CKR_OK) {
951 		goto finish;
952 	}
953 
954 	/* Attempt to unwrap key on slots until one succeeds. */
955 	for (i = 0; i < slotCount; i++) {
956 
957 		slotnum = slots[i]->slotnum;
958 		unwrap_session = NULL;
959 
960 		if (session->op1.session != NULL) {
961 			if ((session->op1.session)->slotnum == slotnum) {
962 				unwrap_session = session->op1.session;
963 				/*
964 				 * set it to NULL for now, assign it to
965 				 * unwrap_session again if it is successful
966 				 */
967 				session->op1.session = NULL;
968 			} else {
969 				unwrap_session = NULL;
970 			}
971 		}
972 
973 		if (unwrap_session == NULL) {
974 			rv = meta_get_slot_session(slotnum, &unwrap_session,
975 			    session->session_flags);
976 			if (rv != CKR_OK) {
977 				goto loop_cleanup;
978 			}
979 		}
980 
981 		rv = meta_object_get_clone(unwrapping_key, slotnum,
982 		    unwrap_session, &slot_unwrappingkey);
983 		if (rv != CKR_OK)
984 			goto loop_cleanup;
985 
986 		rv = FUNCLIST(unwrap_session->fw_st_id)->C_UnwrapKey(
987 		    unwrap_session->hSession, pMechanism,
988 		    slot_unwrappingkey->hObject, wrapped_key, wrapped_key_len,
989 		    template, template_size, &hUnwrappedKey);
990 
991 		if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
992 			break;
993 loop_cleanup:
994 		if (i == 0) {
995 			save_rv = rv;
996 		}
997 
998 		if (unwrap_session) {
999 			meta_release_slot_session(unwrap_session);
1000 			unwrap_session = NULL;
1001 		}
1002 	}
1003 
1004 
1005 	if (rv != CKR_OK) {
1006 		if (rv != CKR_BUFFER_TOO_SMALL) {
1007 			rv = save_rv;
1008 		}
1009 		goto finish;
1010 	}
1011 
1012 
1013 	slot_unwrapped_key->hObject = hUnwrappedKey;
1014 	unwrapped_key->clones[slotnum] = slot_unwrapped_key;
1015 	unwrapped_key->master_clone_slotnum = slotnum;
1016 	rv = meta_object_get_attr(unwrap_session,
1017 	    slot_unwrapped_key->hObject, unwrapped_key);
1018 	if (rv != CKR_OK) {
1019 		goto finish;
1020 	}
1021 	meta_slot_object_activate(slot_unwrapped_key, unwrap_session,
1022 	    unwrapped_key->isToken);
1023 	slot_unwrapped_key = NULL;
1024 
1025 finish:
1026 	if (slot_unwrapped_key) {
1027 		meta_slot_object_dealloc(slot_unwrapped_key);
1028 	}
1029 
1030 	/* Save the session in case it can be used later */
1031 	if (rv == CKR_OK) {
1032 		/*
1033 		 * If currently stored session is not the one being in use now,
1034 		 * release the previous one and store the current one
1035 		 */
1036 		if ((session->op1.session) &&
1037 		    (session->op1.session != unwrap_session)) {
1038 			meta_release_slot_session(session->op1.session);
1039 		}
1040 
1041 		/* Save the session */
1042 		session->op1.session = unwrap_session;
1043 	}
1044 
1045 	return (rv);
1046 }
1047 
1048 
1049 /*
1050  * meta_derive_key
1051  *
1052  * Core implementation for C_DeriveKey. This function is a bit gross because
1053  * of PKCS#11 kludges that pass extra object handles in the mechanism
1054  * parameters. Normally C_DeriveKey takes a single existing key as input,
1055  * and creates a single new key as output. But a few mechanisms take 2 keys
1056  * as input, and the two SSL/TLS mechanisms create 4 keys as output.
1057  *
1058  * When an extra input key (basekey2) is set, we set *phBaseKey2 to the clone's
1059  * object handle. phBaseKey2 is provided by the caller so we don't have to
1060  * trudge down into different mechanism parameters to set it when issuing the
1061  * operation.
1062  *
1063  * For the SSL/TLS mechanisms, newKey2/newKey3/newKey4 will be set. We pull
1064  * the new handles from pMech->pParameter in order to fill in the appropriate
1065  * meta_object fields.
1066  */
1067 CK_RV
1068 meta_derive_key(meta_session_t *session, CK_MECHANISM *pMechanism,
1069 	meta_object_t *basekey1, meta_object_t *basekey2,
1070 	CK_OBJECT_HANDLE *phBaseKey2,
1071 	CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount,
1072 	meta_object_t *newKey1, meta_object_t *newKey2,
1073 	meta_object_t *newKey3, meta_object_t *newKey4)
1074 {
1075 	CK_RV rv, save_rv;
1076 	CK_OBJECT_HANDLE hDerivedKey;
1077 
1078 	CK_ULONG slotnum;
1079 	boolean_t isSSL = B_FALSE;
1080 	boolean_t isTLSPRF = B_FALSE;
1081 	mechinfo_t **slots = NULL;
1082 	unsigned long i, slot_count = 0;
1083 	slot_session_t *derive_session = NULL;
1084 	slot_object_t *slot_basekey1 = NULL, *slot_basekey2 = NULL;
1085 	slot_object_t *slotkey1 = NULL, *slotkey2 = NULL,
1086 		*slotkey3 = NULL, *slotkey4 = NULL;
1087 	CK_BBOOL current_token_value = FALSE;
1088 
1089 	/*
1090 	 * if the derived key needs to be a token object, can only
1091 	 * perform the derive operation in the token slot
1092 	 */
1093 	(void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount,
1094 	    &(newKey1->isToken));
1095 	(void) get_template_boolean(CKA_PRIVATE, pTemplate, ulAttributeCount,
1096 	    &(newKey1->isPrivate));
1097 	(void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulAttributeCount,
1098 	    &(newKey1->isSensitive));
1099 
1100 	if (newKey1->isToken)
1101 		current_token_value = TRUE;
1102 
1103 	/* Can't create token objects in a read-only session. */
1104 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
1105 	    newKey1->isToken) {
1106 		rv = CKR_SESSION_READ_ONLY;
1107 		goto finish;
1108 	}
1109 
1110 	if (meta_freeobject_check(session, newKey1, pMechanism, pTemplate,
1111 		ulAttributeCount, NULL)) {
1112 
1113 		if (newKey1->isPrivate && !metaslot_logged_in())
1114 			return (CKR_USER_NOT_LOGGED_IN);
1115 
1116 		if (!meta_freeobject_set(newKey1, pTemplate, ulAttributeCount,
1117 			B_FALSE))
1118 			return (CKR_FUNCTION_FAILED);
1119 	}
1120 
1121 	rv = get_slotlist_for_mech(pMechanism->mechanism,
1122 	    &(session->mech_support_info), &slots, &slot_count,
1123 	    newKey1->isToken);
1124 
1125 	if (rv != CKR_OK) {
1126 		return (rv);
1127 	}
1128 
1129 	if (pMechanism->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE ||
1130 	    pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE)
1131 		isSSL = B_TRUE;
1132 
1133 	else if (pMechanism->mechanism == CKM_TLS_PRF)
1134 		isTLSPRF = B_TRUE;
1135 
1136 	rv = meta_slot_object_alloc(&slotkey1);
1137 	if (isSSL) {
1138 		if (rv == CKR_OK)
1139 			rv = meta_slot_object_alloc(&slotkey2);
1140 		if (rv == CKR_OK)
1141 			rv = meta_slot_object_alloc(&slotkey3);
1142 		if (rv == CKR_OK)
1143 			rv = meta_slot_object_alloc(&slotkey4);
1144 	}
1145 	if (rv != CKR_OK) {
1146 		goto finish;
1147 	}
1148 
1149 	for (i = 0; i < slot_count; i++) {
1150 		slotnum = slots[i]->slotnum;
1151 
1152 		derive_session = NULL;
1153 
1154 		if (session->op1.session != NULL) {
1155 			if ((session->op1.session)->slotnum == slotnum) {
1156 				derive_session = session->op1.session;
1157 				/*
1158 				 * set it to NULL for now, assign it to
1159 				 * derive_session again if it is successful
1160 				 */
1161 				session->op1.session = NULL;
1162 			} else {
1163 				derive_session = NULL;
1164 			}
1165 		}
1166 
1167 		if (derive_session == NULL) {
1168 			rv = meta_get_slot_session(slotnum, &derive_session,
1169 			    session->session_flags);
1170 			if (rv != CKR_OK) {
1171 				goto loop_cleanup;
1172 			}
1173 		}
1174 
1175 		rv = meta_object_get_clone(basekey1, slotnum,
1176 		    derive_session, &slot_basekey1);
1177 		if (rv != CKR_OK)
1178 			goto loop_cleanup;
1179 
1180 		if (basekey2) {
1181 			rv = meta_object_get_clone(basekey2, slotnum,
1182 			    derive_session, &slot_basekey2);
1183 			if (rv != CKR_OK)
1184 				goto loop_cleanup;
1185 
1186 			/* Pass the handle somewhere in the mech params. */
1187 			*phBaseKey2 = slot_basekey2->hObject;
1188 		}
1189 
1190 		if (newKey1->isFreeToken == FREE_ENABLED) {
1191 			rv = meta_freetoken_set(slotnum, &current_token_value,
1192 			    pTemplate, ulAttributeCount);
1193 			if (rv != CKR_OK)
1194 				goto loop_cleanup;
1195 		}
1196 
1197 		rv = FUNCLIST(derive_session->fw_st_id)->C_DeriveKey(
1198 		    derive_session->hSession, pMechanism,
1199 		    slot_basekey1->hObject, pTemplate, ulAttributeCount,
1200 		    (isSSL || isTLSPRF) ? NULL : &hDerivedKey);
1201 
1202 		if (rv == CKR_OK)
1203 			break;
1204 loop_cleanup:
1205 		if (i == 0) {
1206 			save_rv = rv;
1207 		}
1208 
1209 		if (derive_session) {
1210 			meta_release_slot_session(derive_session);
1211 			derive_session = NULL;
1212 		}
1213 		/* No need to cleanup clones, so we can reuse them later. */
1214 	}
1215 
1216 	if (rv != CKR_OK) {
1217 		rv = save_rv;
1218 		goto finish;
1219 	}
1220 
1221 	if (isTLSPRF)
1222 		goto finish;
1223 
1224 	/*
1225 	 * These SSL/TLS are unique in that the parameter in the API for
1226 	 * the new key is unused (NULL). Instead, there are 4 keys which
1227 	 * are derived, and are passed back through the mechanism params.
1228 	 * Both mechs use the same mechanism parameter type.
1229 	 */
1230 	if (isSSL) {
1231 		CK_SSL3_KEY_MAT_PARAMS *keyparams;
1232 		CK_SSL3_KEY_MAT_OUT *keys;
1233 
1234 		/* NULL checks already done by caller */
1235 		keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMechanism->pParameter;
1236 		keys = keyparams->pReturnedKeyMaterial;
1237 
1238 		slotkey1->hObject = keys->hClientMacSecret;
1239 		slotkey2->hObject = keys->hServerMacSecret;
1240 		slotkey3->hObject = keys->hClientKey;
1241 		slotkey4->hObject = keys->hServerKey;
1242 
1243 		rv = meta_object_get_attr(derive_session,
1244 		    slotkey1->hObject, newKey1);
1245 		if (rv != CKR_OK) {
1246 			goto finish;
1247 		}
1248 
1249 		rv = meta_object_get_attr(derive_session,
1250 		    slotkey2->hObject, newKey2);
1251 		if (rv != CKR_OK) {
1252 			goto finish;
1253 		}
1254 
1255 		rv = meta_object_get_attr(derive_session,
1256 		    slotkey3->hObject, newKey3);
1257 		if (rv != CKR_OK) {
1258 			goto finish;
1259 		}
1260 
1261 		rv = meta_object_get_attr(derive_session,
1262 		    slotkey4->hObject, newKey4);
1263 		if (rv != CKR_OK) {
1264 			goto finish;
1265 		}
1266 
1267 		newKey1->clones[slotnum] = slotkey1;
1268 		newKey2->clones[slotnum] = slotkey2;
1269 		newKey3->clones[slotnum] = slotkey3;
1270 		newKey4->clones[slotnum] = slotkey4;
1271 
1272 		newKey1->master_clone_slotnum = slotnum;
1273 		newKey2->master_clone_slotnum = slotnum;
1274 		newKey3->master_clone_slotnum = slotnum;
1275 		newKey4->master_clone_slotnum = slotnum;
1276 
1277 		meta_slot_object_activate(slotkey1, derive_session,
1278 			newKey1->isToken);
1279 		slotkey1 = NULL;
1280 		meta_slot_object_activate(slotkey2, derive_session,
1281 			newKey2->isToken);
1282 		slotkey2 = NULL;
1283 		meta_slot_object_activate(slotkey3, derive_session,
1284 			newKey3->isToken);
1285 		slotkey3 = NULL;
1286 		meta_slot_object_activate(slotkey4, derive_session,
1287 				newKey4->isToken);
1288 		slotkey4 = NULL;
1289 
1290 	} else {
1291 		slotkey1->hObject = hDerivedKey;
1292 		newKey1->clones[slotnum] = slotkey1;
1293 		newKey1->master_clone_slotnum = slotnum;
1294 
1295 		rv = meta_object_get_attr(derive_session,
1296 		    slotkey1->hObject, newKey1);
1297 		if (rv != CKR_OK) {
1298 			goto finish;
1299 		}
1300 
1301 		meta_slot_object_activate(slotkey1, derive_session,
1302 			newKey1->isToken);
1303 		slotkey1 = NULL;
1304 	}
1305 
1306 	if (newKey1->isFreeObject == FREE_ENABLED)
1307 		(void) meta_freeobject_clone(session, newKey1);
1308 
1309 
1310 finish:
1311 	if (slotkey1) {
1312 		meta_slot_object_dealloc(slotkey1);
1313 	}
1314 	if (slotkey2) {
1315 		meta_slot_object_dealloc(slotkey2);
1316 	}
1317 	if (slotkey3) {
1318 		meta_slot_object_dealloc(slotkey3);
1319 	}
1320 	if (slotkey4) {
1321 		meta_slot_object_dealloc(slotkey4);
1322 	}
1323 
1324 	/* Save the session in case it can be used later */
1325 	if (rv == CKR_OK) {
1326 		/*
1327 		 * If currently stored session is not the one being in use now,
1328 		 * release the previous one and store the current one
1329 		 */
1330 		if ((session->op1.session) &&
1331 		    (session->op1.session != derive_session)) {
1332 			meta_release_slot_session(session->op1.session);
1333 		}
1334 
1335 		/* Save the session */
1336 		session->op1.session = derive_session;
1337 	}
1338 
1339 	return (rv);
1340 }
1341 
1342 
1343 /*
1344  * Check the following 4 environment variables for user/application's
1345  * configuration for metaslot.  User's configuration takes precedence
1346  * over the system wide configuration for metaslot
1347  *
1348  * ${METASLOT_ENABLED}
1349  * ${METASLOT_OBJECTSTORE_SLOT}
1350  * ${METASLOT_OBJECTSTORE_TOKEN}
1351  * ${METASLOT_AUTO_KEY_MIGRATE}
1352  *
1353  * values defined in these environment variables will be stored in the
1354  * global variable "metaslot_config"
1355  */
1356 void
1357 get_user_metaslot_config()
1358 {
1359 	char *env_val = NULL;
1360 
1361 	/*
1362 	 * Check to see if any environment variable is defined
1363 	 * by the user for configuring metaslot.
1364 	 */
1365 	bzero(&metaslot_config, sizeof (metaslot_config));
1366 
1367 	/* METASLOT_ENABLED */
1368 	env_val = getenv("METASLOT_ENABLED");
1369 	if (env_val) {
1370 		metaslot_config.enabled_specified = B_TRUE;
1371 		if (strcasecmp(env_val, TRUE_STRING) == 0) {
1372 			metaslot_config.enabled = B_TRUE;
1373 		} else if (strcasecmp(env_val, FALSE_STRING) == 0) {
1374 			metaslot_config.enabled = B_FALSE;
1375 		} else {
1376 			/* value is neither 1 or 0, ignore this value */
1377 			metaslot_config.enabled_specified = B_FALSE;
1378 		}
1379 	}
1380 
1381 	/* METASLOT_AUTO_KEY_MIGRATE */
1382 	env_val = getenv("METASLOT_AUTO_KEY_MIGRATE");
1383 	if (env_val) {
1384 		metaslot_config.auto_key_migrate_specified = B_TRUE;
1385 		if (strcasecmp(env_val, TRUE_STRING) == 0) {
1386 			metaslot_config.auto_key_migrate = B_TRUE;
1387 		} else if (strcasecmp(env_val, FALSE_STRING) == 0) {
1388 			metaslot_config.auto_key_migrate = B_FALSE;
1389 		} else {
1390 			/* value is neither 1 or 0, ignore this value */
1391 			metaslot_config.auto_key_migrate_specified = B_FALSE;
1392 		}
1393 	}
1394 
1395 	/* METASLOT_OBJECTSTORE_SLOT */
1396 	env_val = getenv("METASLOT_OBJECTSTORE_SLOT");
1397 	if (env_val) {
1398 		metaslot_config.keystore_slot_specified = B_TRUE;
1399 		(void) strlcpy((char *)metaslot_config.keystore_slot, env_val,
1400 		    SLOT_DESCRIPTION_SIZE);
1401 	}
1402 
1403 	/* METASLOT_OBJECTSTORE_TOKEN */
1404 	env_val = getenv("METASLOT_OBJECTSTORE_TOKEN");
1405 	if (env_val) {
1406 		metaslot_config.keystore_token_specified = B_TRUE;
1407 		(void) strlcpy((char *)metaslot_config.keystore_token, env_val,
1408 		    TOKEN_LABEL_SIZE);
1409 	}
1410 }
1411