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
meta_operation_init_defer(CK_FLAGS optype,meta_session_t * session,CK_MECHANISM * pMechanism,meta_object_t * key)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
meta_operation_init(CK_FLAGS optype,meta_session_t * session,CK_MECHANISM * pMechanism,meta_object_t * key)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
meta_operation_init_softtoken(CK_FLAGS optype,meta_session_t * session,CK_MECHANISM * pMechanism,meta_object_t * key)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
meta_GetThreshold(CK_MECHANISM_TYPE mechanism)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
meta_do_operation(CK_FLAGS optype,int mode,meta_session_t * session,meta_object_t * object,CK_BYTE * in,CK_ULONG inLen,CK_BYTE * out,CK_ULONG * outLen)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
free_session_mechanism(meta_session_t * session)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
meta_operation_cleanup(meta_session_t * session,CK_FLAGS optype,boolean_t finished_normally)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
get_slotlist_for_mech(CK_MECHANISM_TYPE mech_type,mech_support_info_t * mech_support_info,mechinfo_t *** slots,unsigned long * slot_count,boolean_t token_only,CK_MECHANISM_INFO * mech_info)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
meta_generate_keys(meta_session_t * session,CK_MECHANISM * pMechanism,CK_ATTRIBUTE * k1Template,CK_ULONG k1AttrCount,meta_object_t * key1,CK_ATTRIBUTE * k2Template,CK_ULONG k2AttrCount,meta_object_t * key2)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 ¤t_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 ¤t_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
meta_wrap_key(meta_session_t * session,CK_MECHANISM * pMechanism,meta_object_t * wrappingkey,meta_object_t * inputkey,CK_BYTE * wrapped_key,CK_ULONG * wrapped_key_len)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
meta_unwrap_key(meta_session_t * session,CK_MECHANISM * pMechanism,meta_object_t * unwrapping_key,CK_BYTE * wrapped_key,CK_ULONG wrapped_key_len,CK_ATTRIBUTE * template,CK_ULONG template_size,meta_object_t * unwrapped_key)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
meta_derive_key(meta_session_t * session,CK_MECHANISM * pMechanism,meta_object_t * basekey1,meta_object_t * basekey2,CK_OBJECT_HANDLE * phBaseKey2,CK_ATTRIBUTE * pTemplate,CK_ULONG ulAttributeCount,meta_object_t * newKey1,meta_object_t * newKey2,meta_object_t * newKey3,meta_object_t * newKey4)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, ¤t_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
get_user_metaslot_config()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