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