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