dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / pkcs11 / libpkcs11 / common / metaUtil.c
blobb8d1b2f334ed491b085280f5f44cb6c5595a9b78
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <cryptoutil.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <strings.h>
31 #include "metaGlobal.h"
33 extern cipher_mechs_threshold_t meta_mechs_threshold[];
34 static boolean_t threshold_chk_enabled = B_FALSE;
36 CK_RV
37 meta_operation_init_defer(CK_FLAGS optype, meta_session_t *session,
38 CK_MECHANISM *pMechanism, meta_object_t *key)
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);
46 (void) memcpy(session->init.pMech, pMechanism,
47 sizeof (CK_MECHANISM));
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);
58 (void) memcpy(session->init.pMech->pParameter,
59 pMechanism->pParameter, pMechanism->ulParameterLen);
60 } else {
61 session->init.pMech->pParameter = NULL;
63 } else { /* reuse it */
64 if ((pMechanism->ulParameterLen > 0) &&
65 (pMechanism->pParameter != NULL)) {
66 if (pMechanism->ulParameterLen !=
67 session->init.pMech->ulParameterLen) {
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);
76 } /* otherwise reuse it */
77 (void) memcpy(session->init.pMech->pParameter,
78 pMechanism->pParameter, pMechanism->ulParameterLen);
79 } else {
81 * free the previous pParameter if not yet freed
82 * because we don't need it now.
84 if (session->init.pMech->pParameter != NULL) {
85 free(session->init.pMech->pParameter);
86 session->init.pMech->pParameter = NULL;
89 /* copy the rest of data */
90 session->init.pMech->mechanism =
91 pMechanism->mechanism;
92 session->init.pMech->ulParameterLen =
93 pMechanism->ulParameterLen;
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);
105 * meta_operation_init
108 CK_RV
109 meta_operation_init(CK_FLAGS optype, meta_session_t *session,
110 CK_MECHANISM *pMechanism, meta_object_t *key)
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;
120 * If an operation is already active, cleanup existing operation
121 * and start a new one.
123 if (session->op1.type != 0) {
124 CK_MECHANISM mech;
125 if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
126 (optype == CKF_DIGEST)) {
127 mech = *pMechanism;
129 if ((pMechanism->ulParameterLen > 0) &&
130 (pMechanism->pParameter != NULL)) {
131 mech.pParameter =
132 malloc(pMechanism->ulParameterLen);
133 if (mech.pParameter == NULL) {
134 return (CKR_HOST_MEMORY);
136 (void) memcpy(mech.pParameter,
137 pMechanism->pParameter,
138 pMechanism->ulParameterLen);
139 } else {
140 mech.pParameter = NULL;
141 mech.ulParameterLen = 0;
144 meta_operation_cleanup(session, session->op1.type,
145 B_FALSE);
146 rv = meta_operation_init_defer(optype, session,
147 &mech, key);
148 if (mech.pParameter != NULL) {
149 free(mech.pParameter);
151 if (rv != CKR_OK)
152 return (rv);
153 } else {
154 meta_operation_cleanup(session, session->op1.type,
155 B_FALSE);
160 mech_info.flags = optype;
163 * Get a list of capable slots.
165 * If the specified mechanism is used in this session last time,
166 * the list of capable slots is already retrieved. We can save
167 * some processing, and just use that list of slots.
169 if (((session->mech_support_info).mech != pMechanism->mechanism) ||
170 ((session->mech_support_info).num_supporting_slots == 0)) {
171 (session->mech_support_info).mech = pMechanism->mechanism;
172 rv = meta_mechManager_get_slots(&(session->mech_support_info),
173 B_FALSE, &mech_info);
174 if (rv != CKR_OK) {
175 goto finish;
179 rv = CKR_FUNCTION_FAILED;
181 /* The following 2 assignment is just to make the code more readable */
182 slotCount = (session->mech_support_info).num_supporting_slots;
183 supporting_slots = (session->mech_support_info).supporting_slots;
185 /* Attempt to initialize operation on slots until one succeeds. */
186 for (i = 0; i < slotCount; i++) {
187 slot_object_t *init_key;
188 CK_SLOT_ID fw_st_id;
190 init_session = NULL;
192 slotnum = supporting_slots[i]->slotnum;
195 * An actual session with the underlying slot is required
196 * for the operation. When the operation is successfully
197 * completed, the underlying session with the slot
198 * is not released back to the list of available sessions
199 * pool. This will help if the next operation can
200 * also be done on the same slot, because it avoids
201 * one extra trip to the session pool to get an idle session.
202 * If the operation can't be done on that slot,
203 * we release the session back to the session pool then.
205 if (session->op1.session != NULL) {
207 if ((session->op1.session)->slotnum == slotnum) {
208 init_session = session->op1.session;
210 * set it to NULL for now, assign it to
211 * init_session again if it is successful
213 session->op1.session = NULL;
214 } else {
215 init_session = NULL;
220 if (!init_session) {
221 rv = meta_get_slot_session(slotnum, &init_session,
222 session->session_flags);
223 if (rv != CKR_OK) {
224 goto loop_cleanup;
228 /* if necessary, ensure a clone of the obj exists in slot */
229 if (optype != CKF_DIGEST) {
230 rv = meta_object_get_clone(key, slotnum, init_session,
231 &init_key);
233 if (rv != CKR_OK) {
234 goto loop_cleanup;
238 fw_st_id = init_session->fw_st_id;
239 switch (optype) {
240 case CKF_ENCRYPT:
241 rv = FUNCLIST(fw_st_id)->C_EncryptInit(
242 init_session->hSession, pMechanism,
243 init_key->hObject);
244 break;
245 case CKF_DECRYPT:
246 rv = FUNCLIST(fw_st_id)->C_DecryptInit(
247 init_session->hSession, pMechanism,
248 init_key->hObject);
249 break;
250 case CKF_DIGEST:
251 rv = FUNCLIST(fw_st_id)->C_DigestInit(
252 init_session->hSession, pMechanism);
253 break;
254 case CKF_SIGN:
255 rv = FUNCLIST(fw_st_id)->C_SignInit(
256 init_session->hSession, pMechanism,
257 init_key->hObject);
258 break;
259 case CKF_VERIFY:
260 rv = FUNCLIST(fw_st_id)->C_VerifyInit(
261 init_session->hSession, pMechanism,
262 init_key->hObject);
263 break;
264 case CKF_SIGN_RECOVER:
265 rv = FUNCLIST(fw_st_id)->C_SignRecoverInit(
266 init_session->hSession, pMechanism,
267 init_key->hObject);
268 break;
269 case CKF_VERIFY_RECOVER:
270 rv = FUNCLIST(fw_st_id)->C_VerifyRecoverInit(
271 init_session->hSession, pMechanism,
272 init_key->hObject);
273 break;
275 default:
276 /*NOTREACHED*/
277 rv = CKR_FUNCTION_FAILED;
278 break;
281 if (rv == CKR_OK)
282 break;
284 loop_cleanup:
285 if (i == 0) {
286 save_rv = rv;
289 if (init_session) {
290 meta_release_slot_session(init_session);
291 init_session = NULL;
296 if (rv == CKR_OK) {
299 * If currently stored session is not the one being in use now,
300 * release the previous one and store the current one
302 if ((session->op1.session) &&
303 (session->op1.session != init_session)) {
304 meta_release_slot_session(session->op1.session);
307 /* Save the session */
308 session->op1.session = init_session;
309 session->op1.type = optype;
311 session->init.slotnum = slotnum;
312 session->init.done = B_TRUE;
313 } else {
314 rv = save_rv;
317 finish:
318 return (rv);
322 * meta_operation_init_softtoken()
323 * It will always do the crypto init operation on softtoken slot.
325 CK_RV
326 meta_operation_init_softtoken(CK_FLAGS optype, meta_session_t *session,
327 CK_MECHANISM *pMechanism, meta_object_t *key)
329 CK_RV rv = CKR_FUNCTION_FAILED;
330 slot_session_t *init_session = NULL;
331 slot_object_t *init_key;
332 CK_SLOT_ID fw_st_id;
333 CK_ULONG softtoken_slot_num;
335 softtoken_slot_num = get_softtoken_slotnum();
337 * If an operation is already active, cleanup existing operation
338 * and start a new one.
340 if (session->op1.type != 0) {
341 CK_MECHANISM mech;
342 mech = *pMechanism;
344 if ((pMechanism->ulParameterLen > 0) &&
345 (pMechanism->pParameter != NULL)) {
346 mech.pParameter =
347 malloc(pMechanism->ulParameterLen);
348 if (mech.pParameter == NULL) {
349 return (CKR_HOST_MEMORY);
351 (void) memcpy(mech.pParameter,
352 pMechanism->pParameter, pMechanism->ulParameterLen);
353 } else {
354 mech.pParameter = NULL;
355 mech.ulParameterLen = 0;
358 meta_operation_cleanup(session, session->op1.type, B_FALSE);
359 rv = meta_operation_init_defer(optype, session, &mech,
360 key);
361 if (mech.pParameter != NULL) {
362 free(mech.pParameter);
364 if (rv != CKR_OK)
365 return (rv);
369 * An actual session with the underlying slot is required
370 * for the operation. When the operation is successfully
371 * completed, the underlying session with the slot
372 * is not released back to the list of available sessions
373 * pool. This will help if the next operation can
374 * also be done on the same slot, because it avoids
375 * one extra trip to the session pool to get an idle session.
376 * If the operation can't be done on that slot,
377 * we release the session back to the session pool.
379 if (session->op1.session != NULL) {
380 if ((session->op1.session)->slotnum ==
381 softtoken_slot_num) {
382 init_session = session->op1.session;
384 * set it to NULL for now, assign it to
385 * init_session again if it is successful
387 session->op1.session = NULL;
388 } else {
389 init_session = NULL;
393 if (init_session == NULL) {
394 /* get the active session from softtoken slot */
395 rv = meta_get_slot_session(softtoken_slot_num,
396 &init_session, session->session_flags);
397 if (rv != CKR_OK) {
398 goto finish;
402 /* if necessary, ensure a clone of the obj exists in softtoken slot */
403 if (optype != CKF_DIGEST) {
404 rv = meta_object_get_clone(key, softtoken_slot_num,
405 init_session, &init_key);
407 if (rv != CKR_OK) {
408 if (init_session != NULL) {
409 meta_release_slot_session(init_session);
410 init_session = NULL;
412 goto finish;
416 fw_st_id = init_session->fw_st_id;
419 * Currently, we only support offloading encrypt, decrypt
420 * and digest operations to softtoken based on kernel
421 * threshold for the supported mechanisms.
423 switch (optype) {
424 case CKF_ENCRYPT:
425 rv = FUNCLIST(fw_st_id)->C_EncryptInit(
426 init_session->hSession, pMechanism,
427 init_key->hObject);
428 break;
429 case CKF_DECRYPT:
430 rv = FUNCLIST(fw_st_id)->C_DecryptInit(
431 init_session->hSession, pMechanism,
432 init_key->hObject);
433 break;
434 case CKF_DIGEST:
435 rv = FUNCLIST(fw_st_id)->C_DigestInit(
436 init_session->hSession, pMechanism);
437 break;
439 default:
440 /*NOTREACHED*/
441 rv = CKR_FUNCTION_FAILED;
442 break;
445 if (rv == CKR_OK) {
448 * If currently stored session is not the one being in use now,
449 * release the previous one and store the current one
451 if ((session->op1.session) &&
452 (session->op1.session != init_session)) {
453 meta_release_slot_session(session->op1.session);
456 /* Save the session */
457 session->op1.session = init_session;
458 session->op1.type = optype;
460 * The init.done flag will be checked by the meta_do_operation()
461 * to indicate whether the C_xxxInit has been done against
462 * softtoken.
464 session->init.done = B_TRUE;
465 session->init.slotnum = softtoken_slot_num;
468 finish:
469 return (rv);
473 meta_GetThreshold(CK_MECHANISM_TYPE mechanism)
476 int i;
478 for (i = 0; i < MAX_NUM_THRESHOLD; i++) {
479 if (mechanism == meta_mechs_threshold[i].mech_type)
480 return (meta_mechs_threshold[i].mech_threshold);
483 /* no matching mechanism */
484 return (0);
488 * meta_do_operation
490 * NOTES:
492 * 1) The spec says you cannot do a C_Encrypt after a C_EncUpdate,
493 * but we don't explicitly enforce it here (ie, disallow doing MODE_SINGLE
494 * after a MODE_UPDATE). Instead, we just assume the underlying provider
495 * will catch the problem and return an appropriate error.
497 * 2) Note that the Verify operations are a little unusual, due to the
498 * PKCS#11 API. For C_Verify, the last two arguments are used as inputs,
499 * unlike the other single pass operations (where they are outputs). For
500 * C_VerifyFinal, in/inLen are passed instead of out/outLen like the other
501 * Final operations.
503 * 3) C_DigestKey is the only crypto operation that uses an object after
504 * the operation has been initialized. No other callers should provide
505 * this argument (use NULL).
507 CK_RV
508 meta_do_operation(CK_FLAGS optype, int mode,
509 meta_session_t *session, meta_object_t *object,
510 CK_BYTE *in, CK_ULONG inLen, CK_BYTE *out, CK_ULONG *outLen)
512 CK_RV rv;
513 CK_SESSION_HANDLE hSession;
514 CK_SLOT_ID fw_st_id;
515 slot_session_t *slot_session = NULL;
516 slot_object_t *slot_object = NULL;
517 int threshold = 0;
519 boolean_t shutdown, finished_normally;
522 * We've deferred the init for encrypt, decrypt and digest
523 * operations. As we know the size of the input data now, we
524 * can decide where to perform the real init operation based
525 * on the kernel cipher-specific thresholds for certain
526 * supported mechanisms.
528 if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
529 (optype == CKF_DIGEST)) {
530 if (Tmp_GetThreshold != NULL) {
531 if (!session->init.app) {
532 return (CKR_OPERATION_NOT_INITIALIZED);
534 threshold = meta_GetThreshold(
535 session->init.pMech->mechanism);
538 if ((threshold_chk_enabled == B_FALSE) || (inLen > threshold)) {
539 if ((session->init.app) && (!session->init.done)) {
541 * Call real init operation only if the
542 * application has called C_xxxInit
543 * but the real init operation has not
544 * been done.
546 rv = meta_operation_init(optype,
547 session->init.session,
548 session->init.pMech,
549 session->init.key);
550 if (rv != CKR_OK)
551 goto exit;
552 } else if (!session->init.app) {
554 * This checking detects the case that
555 * application calls C_En(De)Crypt/Digest
556 * directly without calling C_xxxInit.
558 return (CKR_OPERATION_NOT_INITIALIZED);
560 } else {
562 * The size of the input data is smaller than the
563 * threshold so we'll use softoken to perform the
564 * crypto operation for better performance reason.
566 if ((session->init.app) && (!session->init.done)) {
568 * Call real init operation only if the
569 * application has called C_xxxInit
570 * but the real init operation has not
571 * been done.
573 rv = meta_operation_init_softtoken(optype,
574 session->init.session,
575 session->init.pMech,
576 session->init.key);
577 if (rv != CKR_OK) {
579 * In case the operation fails in
580 * softtoken, go back to use the
581 * original slot again.
583 rv = meta_operation_init(optype,
584 session->init.session,
585 session->init.pMech,
586 session->init.key);
587 if (rv != CKR_OK)
588 goto exit;
590 } else if (!session->init.app) {
592 * This checking detects the case that
593 * application calls C_En(De)Crypt/Digest
594 * directly without calling C_xxxInit.
596 return (CKR_OPERATION_NOT_INITIALIZED);
599 } else if (optype != session->op1.type) {
600 return (CKR_OPERATION_NOT_INITIALIZED);
603 slot_session = session->op1.session;
605 if (slot_session) {
606 hSession = slot_session->hSession;
607 fw_st_id = slot_session->fw_st_id;
608 } else {
609 /* should never be here */
610 rv = CKR_FUNCTION_FAILED;
611 goto exit;
614 /* Do the operation... */
615 if (optype == CKF_ENCRYPT && mode == MODE_SINGLE) {
616 rv = FUNCLIST(fw_st_id)->C_Encrypt(hSession, in,
617 inLen, out, outLen);
618 } else if (optype == CKF_ENCRYPT && mode == MODE_UPDATE) {
619 rv = FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, in,
620 inLen, out, outLen);
621 } else if (optype == CKF_ENCRYPT && mode == MODE_FINAL) {
622 rv = FUNCLIST(fw_st_id)->C_EncryptFinal(hSession, out,
623 outLen);
625 } else if (optype == CKF_DECRYPT && mode == MODE_SINGLE) {
626 rv = FUNCLIST(fw_st_id)->C_Decrypt(hSession, in,
627 inLen, out, outLen);
628 } else if (optype == CKF_DECRYPT && mode == MODE_UPDATE) {
629 rv = FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, in,
630 inLen, out, outLen);
631 } else if (optype == CKF_DECRYPT && mode == MODE_FINAL) {
632 rv = FUNCLIST(fw_st_id)->C_DecryptFinal(hSession, out,
633 outLen);
635 } else if (optype == CKF_DIGEST && mode == MODE_SINGLE) {
636 rv = FUNCLIST(fw_st_id)->C_Digest(hSession, in, inLen,
637 out, outLen);
638 } else if (optype == CKF_DIGEST && mode == MODE_UPDATE) {
639 /* noOutputForOp = TRUE; */
640 rv = FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, in,
641 inLen);
642 } else if (optype == CKF_DIGEST && mode == MODE_UPDATE_WITHKEY) {
643 /* noOutputForOp = TRUE; */
645 * For C_DigestKey, a key is provided and
646 * we need the clone.
648 rv = meta_object_get_clone(object,
649 slot_session->slotnum, slot_session, &slot_object);
650 if (rv == CKR_OK)
651 rv = FUNCLIST(fw_st_id)->C_DigestKey(hSession,
652 slot_object->hObject);
653 } else if (optype == CKF_DIGEST && mode == MODE_FINAL) {
654 rv = FUNCLIST(fw_st_id)->C_DigestFinal(hSession, out,
655 outLen);
657 } else if (optype == CKF_SIGN && mode == MODE_SINGLE) {
658 rv = FUNCLIST(fw_st_id)->C_Sign(hSession, in, inLen,
659 out, outLen);
660 } else if (optype == CKF_SIGN && mode == MODE_UPDATE) {
661 /* noOutputForOp = TRUE; */
662 rv = FUNCLIST(fw_st_id)->C_SignUpdate(hSession, in,
663 inLen);
664 } else if (optype == CKF_SIGN && mode == MODE_FINAL) {
665 rv = FUNCLIST(fw_st_id)->C_SignFinal(hSession, out,
666 outLen);
668 } else if (optype == CKF_VERIFY && mode == MODE_SINGLE) {
669 /* noOutputForOp = TRUE; */
670 /* Yes, use *outLen not outLen (think in2/in2Len) */
671 rv = FUNCLIST(fw_st_id)->C_Verify(hSession, in,
672 inLen, out, *outLen);
673 } else if (optype == CKF_VERIFY && mode == MODE_UPDATE) {
674 /* noOutputForOp = TRUE; */
675 rv = FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, in,
676 inLen);
677 } else if (optype == CKF_VERIFY && mode == MODE_FINAL) {
678 /* noOutputForOp = TRUE; */
679 /* Yes, use in/inLen instead of out/outLen */
680 rv = FUNCLIST(fw_st_id)->C_VerifyFinal(hSession, in,
681 inLen);
683 } else if (optype == CKF_SIGN_RECOVER && mode == MODE_SINGLE) {
684 rv = FUNCLIST(fw_st_id)->C_SignRecover(hSession, in,
685 inLen, out, outLen);
686 } else if (optype == CKF_VERIFY_RECOVER && mode == MODE_SINGLE) {
687 rv = FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, in,
688 inLen, out, outLen);
690 } else {
691 rv = CKR_FUNCTION_FAILED;
696 * Mark the operation type as inactive if an abnormal error
697 * happens, or if the operation normally results in an inactive
698 * operation state.
700 * NOTE: The spec isn't very explicit about what happens when you
701 * call C_FooFinal (or C_Foo) with a NULL output buffer (to get the
702 * output size), but there is no output. Technically this should be
703 * no different than the normal case (ie, when there is output), and
704 * the operation should remain active until the second call actually
705 * terminates it. However, one could make the case that there is no
706 * need for a second call, since no data is available. This presents
707 * dilemma for metaslot, because we don't know if the operation is
708 * going to remain active or not. We will assume a strict reading of
709 * the spec, the operation will remain active.
711 exit:
712 if (rv == CKR_BUFFER_TOO_SMALL ||
713 (rv == CKR_OK && out == NULL && optype != CKF_VERIFY)) {
714 /* Leave op active for retry (with larger buffer). */
715 shutdown = B_FALSE;
716 } else if (rv != CKR_OK) {
717 shutdown = B_TRUE;
718 finished_normally = B_FALSE;
719 } else { /* CKR_OK */
720 if (mode == MODE_SINGLE || mode == MODE_FINAL) {
721 shutdown = B_TRUE;
722 finished_normally = B_TRUE;
723 } else { /* mode == MODE_UPDATE */
724 shutdown = B_FALSE;
728 if (shutdown) {
729 if (mode == MODE_SINGLE || mode == MODE_FINAL) {
730 session->init.app = B_FALSE;
733 meta_operation_cleanup(session, optype, finished_normally);
736 return (rv);
739 void
740 free_session_mechanism(meta_session_t *session)
742 if (session->init.pMech != NULL) {
743 if (session->init.pMech->pParameter != NULL) {
744 free(session->init.pMech->pParameter);
745 session->init.pMech->pParameter = NULL;
746 session->init.pMech->ulParameterLen = 0;
748 free(session->init.pMech);
749 session->init.pMech = NULL;
754 * meta_operation_cleanup
756 * Cleans up an operation in the specified session.
757 * If the operation did not finish normally, it will force
758 * the operation to terminate.
760 void
761 meta_operation_cleanup(meta_session_t *session, CK_FLAGS optype,
762 boolean_t finished_normally)
764 operation_info_t *op;
765 CK_SESSION_HANDLE hSession;
766 CK_SLOT_ID fw_st_id;
768 if (!finished_normally) {
769 CK_BYTE dummy_buf[8];
771 if (session->op1.type == optype) {
772 op = &session->op1;
773 } else {
774 if ((optype == CKF_ENCRYPT) ||
775 (optype == CKF_DECRYPT) ||
776 (optype == CKF_DIGEST)) {
777 session->op1.type = 0;
778 session->init.app = B_FALSE;
779 session->init.done = B_FALSE;
780 free_session_mechanism(session);
782 return;
785 hSession = op->session->hSession;
786 fw_st_id = op->session->fw_st_id;
789 * There's no simple, reliable way to abort an
790 * operation. So, we'll force the operation to finish.
792 * We are here either because we need to abort either after
793 * C_xxxxxInit() or C_xxxxxUpdate().
795 * We will call C_xxxxxUpdate() with invalid argument to
796 * force the operation to abort. According to the PKCS#11
797 * spec, any call to C_xxxxxUpdate() returns in an error
798 * will terminate the current operation.
801 switch (optype) {
802 case CKF_ENCRYPT:
803 (void) FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession,
804 NULL, 8, dummy_buf, NULL);
805 break;
806 case CKF_DECRYPT:
807 (void) FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession,
808 NULL, 8, dummy_buf, NULL);
809 break;
810 case CKF_DIGEST:
811 (void) FUNCLIST(fw_st_id)->C_DigestUpdate(hSession,
812 NULL, 8);
813 break;
814 case CKF_SIGN:
815 (void) FUNCLIST(fw_st_id)->C_SignUpdate(hSession,
816 NULL, 8);
817 break;
818 case CKF_SIGN_RECOVER:
819 (void) FUNCLIST(fw_st_id)->C_SignRecover(hSession,
820 NULL, 8, dummy_buf, NULL);
821 break;
822 case CKF_VERIFY:
823 (void) FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession,
824 NULL, 8);
825 break;
826 case CKF_VERIFY_RECOVER:
827 (void) FUNCLIST(fw_st_id)->C_VerifyRecover(hSession,
828 NULL, 8, dummy_buf, NULL);
829 break;
830 default:
831 /*NOTREACHED*/
832 break;
834 meta_release_slot_session(session->op1.session);
835 session->op1.session = NULL;
838 if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
839 (optype == CKF_DIGEST)) {
840 session->init.done = B_FALSE;
841 free_session_mechanism(session);
843 session->op1.type = 0;
847 * Gets the list of slots that supports the specified mechanism.
849 * If "token_only", check if the keystore slot supports the specified mech,
850 * if so, return that slot only
852 * Otherwise, get list of all slots that support the mech.
855 static CK_RV
856 get_slotlist_for_mech(CK_MECHANISM_TYPE mech_type,
857 mech_support_info_t *mech_support_info,
858 mechinfo_t ***slots, unsigned long *slot_count, boolean_t token_only,
859 CK_MECHANISM_INFO *mech_info)
861 boolean_t mech_supported = B_FALSE;
862 CK_RV rv = CKR_OK;
864 if (token_only) {
865 rv = meta_mechManager_slot_supports_mech(mech_type,
866 get_keystore_slotnum(), &mech_supported,
867 &((mech_support_info->supporting_slots)[0]), B_FALSE,
868 mech_info);
870 if (rv != CKR_OK) {
871 return (rv);
874 if (mech_supported) {
875 mech_support_info->mech = mech_type;
877 * Want to leave this at 0, that way, when
878 * other operation needs to
879 * use this mechanism, but not just for the
880 * keystore slot, we will look at other slots
882 mech_support_info->num_supporting_slots = 0;
883 *slots = mech_support_info->supporting_slots;
884 *slot_count = 1;
885 } else {
886 rv = CKR_FUNCTION_FAILED;
888 } else {
890 * Get a list of slots that support this mech .
892 * If the specified mechanism is used last time,
893 * the list of capable slots is already retrieved.
894 * We can save some processing, and just use that list of slots.
896 if ((mech_support_info->mech != mech_type) ||
897 (mech_support_info->num_supporting_slots == 0)) {
898 mech_support_info->mech = mech_type;
899 rv = meta_mechManager_get_slots(mech_support_info,
900 B_FALSE, mech_info);
901 if (rv != CKR_OK) {
902 return (CKR_FUNCTION_FAILED);
905 *slots = mech_support_info->supporting_slots;
906 *slot_count = mech_support_info->num_supporting_slots;
908 return (rv);
912 * meta_generate_keys
914 * Generates symmetric (k1=key, k2=null) or asymmetric (k1=pub, k2=priv) keys.
917 CK_RV
918 meta_generate_keys(meta_session_t *session, CK_MECHANISM *pMechanism,
919 CK_ATTRIBUTE *k1Template, CK_ULONG k1AttrCount, meta_object_t *key1,
920 CK_ATTRIBUTE *k2Template, CK_ULONG k2AttrCount, meta_object_t *key2)
922 CK_RV rv, save_rv;
923 slot_session_t *gen_session = NULL;
924 slot_object_t *slot_key1 = NULL, *slot_key2 = NULL;
925 mechinfo_t **slots = NULL;
926 unsigned long i, slotCount = 0;
927 boolean_t doKeyPair = B_FALSE, token_only = B_FALSE;
928 CK_ULONG slotnum;
929 CK_MECHANISM_INFO mech_info;
931 * Since the keygen call is in a loop, it is performance-wise useful
932 * to keep track of the token value
934 CK_BBOOL current_token1_value = FALSE, current_token2_value = FALSE;
936 (void) get_template_boolean(CKA_TOKEN, k1Template, k1AttrCount,
937 &(key1->isToken));
938 (void) get_template_boolean(CKA_SENSITIVE, k1Template, k1AttrCount,
939 &(key1->isSensitive));
940 (void) get_template_boolean(CKA_PRIVATE, k1Template, k1AttrCount,
941 &(key1->isPrivate));
943 if (!get_template_boolean(CKA_EXTRACTABLE, k1Template, k1AttrCount,
944 &(key1->isExtractable)))
945 key1->isExtractable = B_TRUE;
947 if (key1->isToken)
948 current_token1_value = TRUE;
950 mech_info.flags = CKF_GENERATE;
952 if (key2) {
953 (void) get_template_boolean(CKA_TOKEN, k2Template, k2AttrCount,
954 &(key2->isToken));
955 (void) get_template_boolean(CKA_SENSITIVE, k2Template,
956 k2AttrCount, &(key2->isSensitive));
957 (void) get_template_boolean(CKA_PRIVATE, k2Template,
958 k2AttrCount, &(key2->isPrivate));
960 if (!get_template_boolean(CKA_EXTRACTABLE, k2Template,
961 k2AttrCount, &(key2->isExtractable)))
962 key2->isExtractable = B_TRUE;
964 if (key2->isToken)
965 current_token2_value = TRUE;
967 doKeyPair = B_TRUE;
968 mech_info.flags = CKF_GENERATE_KEY_PAIR;
972 /* Can't create token objects in a read-only session. */
973 if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
974 ((key1->isToken) || ((key2) && (key2->isToken)))) {
975 return (CKR_SESSION_READ_ONLY);
978 if (meta_freeobject_check(session, key1, pMechanism, k1Template,
979 k1AttrCount, 0)) {
981 if ((key1->isPrivate || (doKeyPair && key2->isPrivate)) &&
982 !metaslot_logged_in())
983 return (CKR_USER_NOT_LOGGED_IN);
985 if (!meta_freeobject_set(key1, k1Template, k1AttrCount,
986 B_FALSE))
987 return (CKR_FUNCTION_FAILED);
989 if (doKeyPair) {
990 key2->isFreeObject = FREE_ALLOWED_KEY;
991 if (!meta_freeobject_set(key2, k2Template, k2AttrCount,
992 B_FALSE))
993 return (CKR_FUNCTION_FAILED);
996 } else if (doKeyPair) {
998 * If this is a keypair operation, the second key cannot be
999 * a FreeObject if the first is not. Both keys will have the
1000 * same fate when it comes to provider choices
1002 key2->isFreeObject = FREE_DISABLED;
1003 key2->isFreeToken = FREE_DISABLED;
1006 if ((key1->isToken) || ((doKeyPair) && (key2->isToken))) {
1008 * Token objects can only be generated in the token object
1009 * slot. If token object slot doesn't support generating
1010 * the key, it will just not be done.
1012 token_only = B_TRUE;
1015 rv = get_slotlist_for_mech(pMechanism->mechanism,
1016 &(session->mech_support_info), &slots, &slotCount, token_only,
1017 &mech_info);
1019 if (rv != CKR_OK) {
1020 goto finish;
1023 rv = meta_slot_object_alloc(&slot_key1);
1024 if (doKeyPair && rv == CKR_OK)
1025 rv = meta_slot_object_alloc(&slot_key2);
1026 if (rv != CKR_OK)
1027 goto finish;
1029 /* Attempt to generate key on slots until one succeeds. */
1030 for (i = 0; i < slotCount; i++) {
1031 CK_SESSION_HANDLE hSession;
1032 CK_SLOT_ID fw_st_id;
1034 gen_session = NULL;
1036 slotnum = slots[i]->slotnum;
1038 if (session->op1.session != NULL) {
1039 if ((session->op1.session)->slotnum == slotnum) {
1040 gen_session = session->op1.session;
1042 * set it to NULL for now, assign it to
1043 * gen_session again if it is successful
1045 session->op1.session = NULL;
1046 } else {
1047 gen_session = NULL;
1051 if (gen_session == NULL) {
1052 rv = meta_get_slot_session(slotnum, &gen_session,
1053 session->session_flags);
1054 if (rv != CKR_OK) {
1055 goto loop_cleanup;
1060 * If this is a freetoken, make sure the templates are
1061 * approriate for the slot being used.
1063 if (key1->isFreeToken == FREE_ENABLED) {
1064 rv = meta_freetoken_set(slotnum,
1065 &current_token1_value, k1Template, k1AttrCount);
1066 if (rv != CKR_OK)
1067 goto loop_cleanup;
1070 if (doKeyPair && key2->isFreeToken == FREE_ENABLED) {
1071 rv = meta_freetoken_set(slotnum,
1072 &current_token2_value, k2Template, k2AttrCount);
1073 if (rv != CKR_OK)
1074 goto loop_cleanup;
1077 fw_st_id = gen_session->fw_st_id;
1078 hSession = gen_session->hSession;
1080 if (doKeyPair) {
1081 rv = FUNCLIST(fw_st_id)->C_GenerateKeyPair(hSession,
1082 pMechanism, k1Template, k1AttrCount,
1083 k2Template, k2AttrCount,
1084 &slot_key1->hObject, &slot_key2->hObject);
1085 } else {
1086 rv = FUNCLIST(fw_st_id)->C_GenerateKey(hSession,
1087 pMechanism, k1Template, k1AttrCount,
1088 &slot_key1->hObject);
1091 if (rv == CKR_OK)
1092 break;
1094 loop_cleanup:
1095 if (i == 0) {
1096 save_rv = rv;
1099 if (gen_session) {
1100 meta_release_slot_session(gen_session);
1101 gen_session = NULL;
1104 if (rv != CKR_OK) {
1105 rv = save_rv;
1106 goto finish;
1109 rv = meta_object_get_attr(gen_session, slot_key1->hObject, key1);
1110 if (rv != CKR_OK) {
1111 goto finish;
1114 if (key2) {
1115 rv = meta_object_get_attr(gen_session, slot_key2->hObject,
1116 key2);
1117 if (rv != CKR_OK) {
1118 goto finish;
1122 /* Allow FreeToken to activate onto token obj list */
1123 if (key1->isFreeToken == FREE_ENABLED)
1124 key1->isToken = B_TRUE;
1126 meta_slot_object_activate(slot_key1, gen_session, key1->isToken);
1127 key1->clones[slotnum] = slot_key1;
1128 key1->master_clone_slotnum = slotnum;
1129 slot_key1 = NULL;
1130 if (key1->isFreeObject == FREE_ENABLED) {
1131 rv = meta_freeobject_clone(session, key1);
1132 if (rv != CKR_OK)
1133 goto finish;
1136 if (doKeyPair) {
1137 /* Allow FreeToken to activate onto token obj list */
1138 if (key2->isFreeToken == FREE_ENABLED)
1139 key2->isToken = B_TRUE;
1141 meta_slot_object_activate(slot_key2, gen_session,
1142 key2->isToken);
1143 key2->clones[slotnum] = slot_key2;
1144 key2->master_clone_slotnum = slotnum;
1145 slot_key2 = NULL;
1146 if (key2->isFreeObject == FREE_ENABLED) {
1147 rv = meta_freeobject_clone(session, key2);
1148 if (rv != CKR_OK)
1149 goto finish;
1153 finish:
1154 if (slot_key1) {
1155 meta_slot_object_dealloc(slot_key1);
1158 if (slot_key2) {
1159 meta_slot_object_dealloc(slot_key2);
1162 /* Save the session in case it can be used later */
1163 if (rv == CKR_OK) {
1165 * If currently stored session is not the one being in use now,
1166 * release the previous one and store the current one
1168 if ((session->op1.session) &&
1169 (session->op1.session != gen_session)) {
1170 meta_release_slot_session(session->op1.session);
1173 /* Save the session */
1174 session->op1.session = gen_session;
1177 return (rv);
1182 * meta_wrap_key
1185 CK_RV
1186 meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism,
1187 meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key,
1188 CK_ULONG *wrapped_key_len)
1190 CK_RV rv, save_rv;
1191 slot_session_t *wrap_session = NULL;
1192 slot_object_t *slot_wrappingkey, *slot_inputkey;
1193 mechinfo_t **slots = NULL;
1194 unsigned long i, slotCount = 0;
1195 CK_ULONG slotnum;
1196 CK_MECHANISM_INFO mech_info;
1199 * If the key to be wrapped is a token object,
1200 * the operation can only be done in the token object slot.
1202 mech_info.flags = CKF_WRAP;
1203 rv = get_slotlist_for_mech(pMechanism->mechanism,
1204 &(session->mech_support_info), &slots, &slotCount,
1205 inputkey->isToken, &mech_info);
1207 if (rv != CKR_OK) {
1208 return (rv);
1211 /* Attempt to wrap key on slots until one succeeds. */
1212 for (i = 0; i < slotCount; i++) {
1214 slotnum = slots[i]->slotnum;
1215 wrap_session = NULL;
1217 if (session->op1.session != NULL) {
1218 if ((session->op1.session)->slotnum == slotnum) {
1219 wrap_session = session->op1.session;
1221 * set it to NULL for now, assign it to
1222 * wrap_session again if it is successful
1224 session->op1.session = NULL;
1225 } else {
1226 wrap_session = NULL;
1230 if (wrap_session == NULL) {
1231 rv = meta_get_slot_session(slotnum, &wrap_session,
1232 session->session_flags);
1233 if (rv != CKR_OK) {
1234 goto loop_cleanup;
1238 rv = meta_object_get_clone(wrappingkey, slotnum,
1239 wrap_session, &slot_wrappingkey);
1240 if (rv != CKR_OK)
1241 goto loop_cleanup;
1243 rv = meta_object_get_clone(inputkey, slotnum,
1244 wrap_session, &slot_inputkey);
1245 if (rv != CKR_OK)
1246 goto loop_cleanup;
1248 rv = FUNCLIST(wrap_session->fw_st_id)->C_WrapKey(
1249 wrap_session->hSession, pMechanism,
1250 slot_wrappingkey->hObject, slot_inputkey->hObject,
1251 wrapped_key, wrapped_key_len);
1253 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
1254 break;
1256 loop_cleanup:
1257 if (i == 0) {
1258 save_rv = rv;
1261 if (wrap_session) {
1262 meta_release_slot_session(wrap_session);
1263 wrap_session = NULL;
1266 if (rv != CKR_OK) {
1267 if (rv != CKR_BUFFER_TOO_SMALL) {
1268 if (i == slotCount) {
1269 rv = save_rv;
1274 finish:
1275 /* Save the session in case it can be used later */
1276 if (rv == CKR_OK) {
1278 * If currently stored session is not the one being in use now,
1279 * release the previous one and store the current one
1281 if ((session->op1.session) &&
1282 (session->op1.session != wrap_session)) {
1283 meta_release_slot_session(session->op1.session);
1286 /* Save the session */
1287 session->op1.session = wrap_session;
1289 return (rv);
1295 * meta_unwrap_key
1298 CK_RV
1299 meta_unwrap_key(meta_session_t *session,
1300 CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key,
1301 CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len,
1302 CK_ATTRIBUTE *template, CK_ULONG template_size,
1303 meta_object_t *unwrapped_key)
1305 CK_RV rv, save_rv;
1306 CK_OBJECT_HANDLE hUnwrappedKey;
1307 slot_session_t *unwrap_session = NULL;
1308 slot_object_t *slot_unwrappingkey, *slot_unwrapped_key;
1309 mechinfo_t **slots = NULL;
1310 unsigned long i, slotCount = 0;
1311 CK_ULONG slotnum;
1312 CK_MECHANISM_INFO mech_info;
1314 /* Can't create token objects in a read-only session. */
1315 if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
1316 unwrapped_key->isToken) {
1317 return (CKR_SESSION_READ_ONLY);
1321 * If the the resulting unwrapped key
1322 * needs to be a token object, the operation can only
1323 * be performed in the token slot, if it is supported.
1325 mech_info.flags = CKF_UNWRAP;
1326 rv = get_slotlist_for_mech(pMechanism->mechanism,
1327 &(session->mech_support_info), &slots, &slotCount,
1328 unwrapped_key->isToken, &mech_info);
1330 if (rv != CKR_OK) {
1331 return (rv);
1334 rv = meta_slot_object_alloc(&slot_unwrapped_key);
1335 if (rv != CKR_OK) {
1336 goto finish;
1339 /* Attempt to unwrap key on slots until one succeeds. */
1340 for (i = 0; i < slotCount; i++) {
1342 slotnum = slots[i]->slotnum;
1343 unwrap_session = NULL;
1345 if (session->op1.session != NULL) {
1346 if ((session->op1.session)->slotnum == slotnum) {
1347 unwrap_session = session->op1.session;
1349 * set it to NULL for now, assign it to
1350 * unwrap_session again if it is successful
1352 session->op1.session = NULL;
1353 } else {
1354 unwrap_session = NULL;
1358 if (unwrap_session == NULL) {
1359 rv = meta_get_slot_session(slotnum, &unwrap_session,
1360 session->session_flags);
1361 if (rv != CKR_OK) {
1362 goto loop_cleanup;
1366 rv = meta_object_get_clone(unwrapping_key, slotnum,
1367 unwrap_session, &slot_unwrappingkey);
1368 if (rv != CKR_OK)
1369 goto loop_cleanup;
1371 rv = FUNCLIST(unwrap_session->fw_st_id)->C_UnwrapKey(
1372 unwrap_session->hSession, pMechanism,
1373 slot_unwrappingkey->hObject, wrapped_key, wrapped_key_len,
1374 template, template_size, &hUnwrappedKey);
1376 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
1377 break;
1378 loop_cleanup:
1379 if (i == 0) {
1380 save_rv = rv;
1383 if (unwrap_session) {
1384 meta_release_slot_session(unwrap_session);
1385 unwrap_session = NULL;
1390 if (rv != CKR_OK) {
1391 if (rv != CKR_BUFFER_TOO_SMALL) {
1392 rv = save_rv;
1394 goto finish;
1398 slot_unwrapped_key->hObject = hUnwrappedKey;
1399 unwrapped_key->clones[slotnum] = slot_unwrapped_key;
1400 unwrapped_key->master_clone_slotnum = slotnum;
1401 rv = meta_object_get_attr(unwrap_session,
1402 slot_unwrapped_key->hObject, unwrapped_key);
1403 if (rv != CKR_OK) {
1404 goto finish;
1406 meta_slot_object_activate(slot_unwrapped_key, unwrap_session,
1407 unwrapped_key->isToken);
1408 slot_unwrapped_key = NULL;
1410 finish:
1411 if (slot_unwrapped_key) {
1412 meta_slot_object_dealloc(slot_unwrapped_key);
1415 /* Save the session in case it can be used later */
1416 if (rv == CKR_OK) {
1418 * If currently stored session is not the one being in use now,
1419 * release the previous one and store the current one
1421 if ((session->op1.session) &&
1422 (session->op1.session != unwrap_session)) {
1423 meta_release_slot_session(session->op1.session);
1426 /* Save the session */
1427 session->op1.session = unwrap_session;
1430 return (rv);
1435 * meta_derive_key
1437 * Core implementation for C_DeriveKey. This function is a bit gross because
1438 * of PKCS#11 kludges that pass extra object handles in the mechanism
1439 * parameters. Normally C_DeriveKey takes a single existing key as input,
1440 * and creates a single new key as output. But a few mechanisms take 2 keys
1441 * as input, and the two SSL/TLS mechanisms create 4 keys as output.
1443 * When an extra input key (basekey2) is set, we set *phBaseKey2 to the clone's
1444 * object handle. phBaseKey2 is provided by the caller so we don't have to
1445 * trudge down into different mechanism parameters to set it when issuing the
1446 * operation.
1448 * For the SSL/TLS mechanisms, newKey2/newKey3/newKey4 will be set. We pull
1449 * the new handles from pMech->pParameter in order to fill in the appropriate
1450 * meta_object fields.
1452 CK_RV
1453 meta_derive_key(meta_session_t *session, CK_MECHANISM *pMechanism,
1454 meta_object_t *basekey1, meta_object_t *basekey2,
1455 CK_OBJECT_HANDLE *phBaseKey2,
1456 CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount,
1457 meta_object_t *newKey1, meta_object_t *newKey2,
1458 meta_object_t *newKey3, meta_object_t *newKey4)
1460 CK_RV rv, save_rv;
1461 CK_OBJECT_HANDLE hDerivedKey;
1463 CK_ULONG slotnum;
1464 boolean_t isSSL = B_FALSE;
1465 boolean_t isTLSPRF = B_FALSE;
1466 mechinfo_t **slots = NULL;
1467 unsigned long i, slot_count = 0;
1468 slot_session_t *derive_session = NULL;
1469 slot_object_t *slot_basekey1 = NULL, *slot_basekey2 = NULL;
1470 slot_object_t *slotkey1 = NULL, *slotkey2 = NULL, *slotkey3 = NULL,
1471 *slotkey4 = NULL;
1472 CK_MECHANISM_INFO mech_info;
1473 CK_BBOOL current_token_value = FALSE;
1476 * if the derived key needs to be a token object, can only
1477 * perform the derive operation in the token slot
1479 (void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount,
1480 &(newKey1->isToken));
1481 (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulAttributeCount,
1482 &(newKey1->isPrivate));
1483 (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulAttributeCount,
1484 &(newKey1->isSensitive));
1486 if (newKey1->isToken)
1487 current_token_value = TRUE;
1489 /* Can't create token objects in a read-only session. */
1490 if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
1491 newKey1->isToken) {
1492 rv = CKR_SESSION_READ_ONLY;
1493 goto finish;
1496 if (meta_freeobject_check(session, newKey1, pMechanism, pTemplate,
1497 ulAttributeCount, 0)) {
1499 if (newKey1->isPrivate && !metaslot_logged_in())
1500 return (CKR_USER_NOT_LOGGED_IN);
1502 if (!meta_freeobject_set(newKey1, pTemplate, ulAttributeCount,
1503 B_FALSE))
1504 return (CKR_FUNCTION_FAILED);
1507 mech_info.flags = CKF_DERIVE;
1508 rv = get_slotlist_for_mech(pMechanism->mechanism,
1509 &(session->mech_support_info), &slots, &slot_count,
1510 newKey1->isToken, &mech_info);
1512 if (rv != CKR_OK) {
1513 return (rv);
1516 if (pMechanism->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE ||
1517 pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE)
1518 isSSL = B_TRUE;
1520 else if (pMechanism->mechanism == CKM_TLS_PRF)
1521 isTLSPRF = B_TRUE;
1523 rv = meta_slot_object_alloc(&slotkey1);
1524 if (isSSL) {
1525 if (rv == CKR_OK)
1526 rv = meta_slot_object_alloc(&slotkey2);
1527 if (rv == CKR_OK)
1528 rv = meta_slot_object_alloc(&slotkey3);
1529 if (rv == CKR_OK)
1530 rv = meta_slot_object_alloc(&slotkey4);
1532 if (rv != CKR_OK) {
1533 goto finish;
1536 for (i = 0; i < slot_count; i++) {
1537 slotnum = slots[i]->slotnum;
1539 derive_session = NULL;
1541 if (session->op1.session != NULL) {
1542 if ((session->op1.session)->slotnum == slotnum) {
1543 derive_session = session->op1.session;
1545 * set it to NULL for now, assign it to
1546 * derive_session again if it is successful
1548 session->op1.session = NULL;
1549 } else {
1550 derive_session = NULL;
1554 if (derive_session == NULL) {
1555 rv = meta_get_slot_session(slotnum, &derive_session,
1556 session->session_flags);
1557 if (rv != CKR_OK) {
1558 goto loop_cleanup;
1562 rv = meta_object_get_clone(basekey1, slotnum,
1563 derive_session, &slot_basekey1);
1564 if (rv != CKR_OK)
1565 goto loop_cleanup;
1567 if (basekey2) {
1568 rv = meta_object_get_clone(basekey2, slotnum,
1569 derive_session, &slot_basekey2);
1570 if (rv != CKR_OK)
1571 goto loop_cleanup;
1573 /* Pass the handle somewhere in the mech params. */
1574 *phBaseKey2 = slot_basekey2->hObject;
1577 if (newKey1->isFreeToken == FREE_ENABLED) {
1578 rv = meta_freetoken_set(slotnum, &current_token_value,
1579 pTemplate, ulAttributeCount);
1580 if (rv != CKR_OK)
1581 goto loop_cleanup;
1584 rv = FUNCLIST(derive_session->fw_st_id)->C_DeriveKey(
1585 derive_session->hSession, pMechanism,
1586 slot_basekey1->hObject, pTemplate, ulAttributeCount,
1587 (isSSL || isTLSPRF) ? NULL : &hDerivedKey);
1589 if (rv == CKR_OK)
1590 break;
1591 loop_cleanup:
1592 if (i == 0) {
1593 save_rv = rv;
1596 if (derive_session) {
1597 meta_release_slot_session(derive_session);
1598 derive_session = NULL;
1600 /* No need to cleanup clones, so we can reuse them later. */
1603 if (rv != CKR_OK) {
1604 rv = save_rv;
1605 goto finish;
1608 if (isTLSPRF)
1609 goto finish;
1612 * These SSL/TLS are unique in that the parameter in the API for
1613 * the new key is unused (NULL). Instead, there are 4 keys which
1614 * are derived, and are passed back through the mechanism params.
1615 * Both mechs use the same mechanism parameter type.
1617 if (isSSL) {
1618 CK_SSL3_KEY_MAT_PARAMS *keyparams;
1619 CK_SSL3_KEY_MAT_OUT *keys;
1621 /* NULL checks already done by caller */
1622 keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMechanism->pParameter;
1623 keys = keyparams->pReturnedKeyMaterial;
1625 slotkey1->hObject = keys->hClientMacSecret;
1626 slotkey2->hObject = keys->hServerMacSecret;
1627 slotkey3->hObject = keys->hClientKey;
1628 slotkey4->hObject = keys->hServerKey;
1630 rv = meta_object_get_attr(derive_session,
1631 slotkey1->hObject, newKey1);
1632 if (rv != CKR_OK) {
1633 goto finish;
1636 rv = meta_object_get_attr(derive_session,
1637 slotkey2->hObject, newKey2);
1638 if (rv != CKR_OK) {
1639 goto finish;
1642 rv = meta_object_get_attr(derive_session,
1643 slotkey3->hObject, newKey3);
1644 if (rv != CKR_OK) {
1645 goto finish;
1648 rv = meta_object_get_attr(derive_session,
1649 slotkey4->hObject, newKey4);
1650 if (rv != CKR_OK) {
1651 goto finish;
1654 newKey1->clones[slotnum] = slotkey1;
1655 newKey2->clones[slotnum] = slotkey2;
1656 newKey3->clones[slotnum] = slotkey3;
1657 newKey4->clones[slotnum] = slotkey4;
1659 newKey1->master_clone_slotnum = slotnum;
1660 newKey2->master_clone_slotnum = slotnum;
1661 newKey3->master_clone_slotnum = slotnum;
1662 newKey4->master_clone_slotnum = slotnum;
1664 meta_slot_object_activate(slotkey1, derive_session,
1665 newKey1->isToken);
1666 slotkey1 = NULL;
1667 meta_slot_object_activate(slotkey2, derive_session,
1668 newKey2->isToken);
1669 slotkey2 = NULL;
1670 meta_slot_object_activate(slotkey3, derive_session,
1671 newKey3->isToken);
1672 slotkey3 = NULL;
1673 meta_slot_object_activate(slotkey4, derive_session,
1674 newKey4->isToken);
1675 slotkey4 = NULL;
1677 } else {
1678 slotkey1->hObject = hDerivedKey;
1679 newKey1->clones[slotnum] = slotkey1;
1680 newKey1->master_clone_slotnum = slotnum;
1682 rv = meta_object_get_attr(derive_session,
1683 slotkey1->hObject, newKey1);
1684 if (rv != CKR_OK) {
1685 goto finish;
1688 /* Allow FreeToken to activate onto token obj list */
1689 if (newKey1->isFreeToken == FREE_ENABLED)
1690 newKey1->isToken = B_TRUE;
1692 meta_slot_object_activate(slotkey1, derive_session,
1693 newKey1->isToken);
1694 slotkey1 = NULL;
1697 if (newKey1->isFreeObject == FREE_ENABLED)
1698 (void) meta_freeobject_clone(session, newKey1);
1701 finish:
1702 if (slotkey1) {
1703 meta_slot_object_dealloc(slotkey1);
1705 if (slotkey2) {
1706 meta_slot_object_dealloc(slotkey2);
1708 if (slotkey3) {
1709 meta_slot_object_dealloc(slotkey3);
1711 if (slotkey4) {
1712 meta_slot_object_dealloc(slotkey4);
1715 /* Save the session in case it can be used later */
1716 if (rv == CKR_OK) {
1718 * If currently stored session is not the one being in use now,
1719 * release the previous one and store the current one
1721 if ((session->op1.session) &&
1722 (session->op1.session != derive_session)) {
1723 meta_release_slot_session(session->op1.session);
1726 /* Save the session */
1727 session->op1.session = derive_session;
1730 return (rv);
1735 * Check the following 4 environment variables for user/application's
1736 * configuration for metaslot. User's configuration takes precedence
1737 * over the system wide configuration for metaslot
1739 * ${METASLOT_ENABLED}
1740 * ${METASLOT_OBJECTSTORE_SLOT}
1741 * ${METASLOT_OBJECTSTORE_TOKEN}
1742 * ${METASLOT_AUTO_KEY_MIGRATE}
1744 * ${_METASLOT_ENABLE_THRESHOLD} - private environmental variable to
1745 * enable the treshold checking which is disabled by default.
1747 * values defined in these environment variables will be stored in the
1748 * global variable "metaslot_config". Variable threshold_chk_disabled is an
1749 * exception.
1751 void
1752 get_user_metaslot_config()
1754 char *env_val = NULL;
1757 * Check to see if any environment variable is defined
1758 * by the user for configuring metaslot.
1760 bzero(&metaslot_config, sizeof (metaslot_config));
1762 /* METASLOT_ENABLED */
1763 env_val = getenv("METASLOT_ENABLED");
1764 if (env_val) {
1765 metaslot_config.enabled_specified = B_TRUE;
1766 if (strcasecmp(env_val, TRUE_STRING) == 0) {
1767 metaslot_config.enabled = B_TRUE;
1768 } else if (strcasecmp(env_val, FALSE_STRING) == 0) {
1769 metaslot_config.enabled = B_FALSE;
1770 } else {
1771 /* value is neither 1 or 0, ignore this value */
1772 metaslot_config.enabled_specified = B_FALSE;
1776 /* METASLOT_AUTO_KEY_MIGRATE */
1777 env_val = getenv("METASLOT_AUTO_KEY_MIGRATE");
1778 if (env_val) {
1779 metaslot_config.auto_key_migrate_specified = B_TRUE;
1780 if (strcasecmp(env_val, TRUE_STRING) == 0) {
1781 metaslot_config.auto_key_migrate = B_TRUE;
1782 } else if (strcasecmp(env_val, FALSE_STRING) == 0) {
1783 metaslot_config.auto_key_migrate = B_FALSE;
1784 } else {
1785 /* value is neither 1 or 0, ignore this value */
1786 metaslot_config.auto_key_migrate_specified = B_FALSE;
1790 /* METASLOT_OBJECTSTORE_SLOT */
1791 env_val = getenv("METASLOT_OBJECTSTORE_SLOT");
1792 if (env_val) {
1793 metaslot_config.keystore_slot_specified = B_TRUE;
1794 (void) strlcpy((char *)metaslot_config.keystore_slot, env_val,
1795 SLOT_DESCRIPTION_SIZE);
1798 /* METASLOT_OBJECTSTORE_TOKEN */
1799 env_val = getenv("METASLOT_OBJECTSTORE_TOKEN");
1800 if (env_val) {
1801 metaslot_config.keystore_token_specified = B_TRUE;
1802 (void) strlcpy((char *)metaslot_config.keystore_token, env_val,
1803 TOKEN_LABEL_SIZE);
1806 /* _METASLOT_ENABLE_THRESHOLD */
1807 env_val = getenv("_METASLOT_ENABLE_THRESHOLD");
1808 if (env_val) {
1809 threshold_chk_enabled = B_TRUE;