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