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