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