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