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