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 /*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26
27 #include <pthread.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <security/cryptoki.h>
33 #include "kmsGlobal.h"
34 #include "kmsObject.h"
35 #include "kmsSession.h"
36
37 CK_RV
C_CreateObject(CK_SESSION_HANDLE hSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phObject)38 C_CreateObject(CK_SESSION_HANDLE hSession,
39 CK_ATTRIBUTE_PTR pTemplate,
40 CK_ULONG ulCount,
41 CK_OBJECT_HANDLE_PTR phObject)
42 {
43
44 CK_RV rv;
45 kms_session_t *session_p;
46 boolean_t ses_lock_held = B_FALSE;
47
48 if (!kms_initialized)
49 return (CKR_CRYPTOKI_NOT_INITIALIZED);
50
51 if ((pTemplate == NULL) || (ulCount == 0) ||
52 (phObject == NULL)) {
53 return (CKR_ARGUMENTS_BAD);
54 }
55
56 /*
57 * Obtain the session pointer. Also, increment the session
58 * reference count.
59 */
60 rv = handle2session(hSession, &session_p);
61 if (rv != CKR_OK)
62 return (rv);
63
64 /* Create a new object. */
65 rv = kms_add_object(pTemplate, ulCount, phObject, session_p);
66
67 /*
68 * Decrement the session reference count.
69 * We do not hold the session lock.
70 */
71 REFRELE(session_p, ses_lock_held);
72
73 return (rv);
74 }
75
76 CK_RV
C_CopyObject(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phNewObject)77 C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
78 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
79 CK_OBJECT_HANDLE_PTR phNewObject)
80 {
81
82 CK_RV rv;
83 kms_session_t *session_p;
84 boolean_t ses_lock_held = B_FALSE;
85 kms_object_t *old_object;
86 kms_object_t *new_object = NULL;
87 int i;
88
89 if (!kms_initialized)
90 return (CKR_CRYPTOKI_NOT_INITIALIZED);
91
92 /* Check arguments */
93 if (((ulCount > 0) && (pTemplate == NULL)) ||
94 (phNewObject == NULL)) {
95 return (CKR_ARGUMENTS_BAD);
96 }
97
98 /*
99 * Obtain the session pointer. Also, increment the session
100 * reference count.
101 */
102 rv = handle2session(hSession, &session_p);
103 if (rv != CKR_OK)
104 return (rv);
105
106 /* Obtain the object pointer. */
107 HANDLE2OBJECT(hObject, old_object, rv);
108 if (rv != CKR_OK) {
109 /*
110 * Decrement the session reference count.
111 * We do not hold the session lock.
112 */
113 REFRELE(session_p, ses_lock_held);
114 return (rv);
115 }
116
117 (void) pthread_mutex_lock(&old_object->object_mutex);
118
119 if (old_object->is_lib_obj) {
120 /*
121 * Copy the old object to a new object.
122 * The 3rd argument with TRUE value indicates that
123 * everything in the object will be duplicated.
124 */
125 rv = kms_copy_object(old_object, &new_object, B_TRUE,
126 session_p);
127 (void) pthread_mutex_unlock(&old_object->object_mutex);
128 if ((rv != CKR_OK) || (new_object == NULL)) {
129 /*
130 * Most likely we ran out of space.
131 * Decrement the session reference count.
132 * We do not hold the session lock.
133 */
134 OBJ_REFRELE(old_object);
135 REFRELE(session_p, ses_lock_held);
136 return (rv);
137 }
138
139 new_object->is_lib_obj = B_TRUE;
140
141 /* Modify the object attribute if requested */
142 for (i = 0; i < ulCount; i++) {
143 /* Set the requested attribute into the new object. */
144 rv = kms_set_attribute(new_object, &pTemplate[i],
145 B_TRUE);
146
147 if (rv != CKR_OK) {
148 kms_cleanup_object(new_object);
149 OBJ_REFRELE(old_object);
150 REFRELE(session_p, ses_lock_held);
151 return (rv);
152 }
153 }
154
155 /* Insert the new object into this session's object list. */
156 kms_add_object_to_session(new_object, session_p);
157
158 /*
159 * Decrement the session reference count.
160 * We do not hold the session lock.
161 */
162 OBJ_REFRELE(old_object);
163 REFRELE(session_p, ses_lock_held);
164
165 /* set handle of the new object */
166 *phNewObject = (CK_ULONG)new_object;
167
168 }
169
170 return (rv);
171
172 failed_cleanup:
173 if (new_object != NULL) {
174 (void) kms_free_object(new_object);
175 }
176
177 OBJ_REFRELE(old_object);
178 REFRELE(session_p, ses_lock_held);
179 return (rv);
180 }
181
182 CK_RV
C_DestroyObject(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject)183 C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
184 {
185 CK_RV rv;
186 kms_object_t *object_p;
187 kms_session_t *session_p = (kms_session_t *)(hSession);
188 kms_slot_t *pslot;
189 boolean_t ses_lock_held = B_FALSE;
190 CK_SESSION_HANDLE creating_session;
191
192 if (!kms_initialized)
193 return (CKR_CRYPTOKI_NOT_INITIALIZED);
194
195 /*
196 * The reason that we don't call handle2session is because
197 * the argument hSession may not be the creating_session of
198 * the object to be destroyed, and we want to avoid the lock
199 * contention. The handle2session will be called later for
200 * the creating_session.
201 */
202 if ((session_p == NULL) ||
203 (session_p->magic_marker != KMSTOKEN_SESSION_MAGIC)) {
204 return (CKR_SESSION_HANDLE_INVALID);
205 }
206 /* Obtain the object pointer without incrementing reference count. */
207 HANDLE2OBJECT_DESTROY(hObject, object_p, rv);
208 if (rv != CKR_OK) {
209 return (rv);
210 }
211
212 /* Only session objects can be destroyed at a read-only session. */
213 if ((session_p->ses_RO) &&
214 (object_p->bool_attr_mask & TOKEN_BOOL_ON)) {
215 return (CKR_SESSION_READ_ONLY);
216 }
217
218
219 /*
220 * If the object is a session object, obtain the session handle
221 * which object belongs to. For a token object, we will use the
222 * session handle from the caller, because the session used to
223 * create the token object may no longer exist.
224 */
225 if (!(object_p->bool_attr_mask & TOKEN_BOOL_ON))
226 creating_session = object_p->session_handle;
227 else
228 creating_session = hSession;
229
230 rv = handle2session(creating_session, &session_p);
231 if (rv != CKR_OK) {
232 return (rv);
233 }
234
235 /*
236 * Set OBJECT_IS_DELETING flag so any access to this
237 * object will be rejected.
238 */
239 (void) pthread_mutex_lock(&object_p->object_mutex);
240 if (object_p->obj_delete_sync & OBJECT_IS_DELETING) {
241 (void) pthread_mutex_unlock(&object_p->object_mutex);
242 REFRELE(session_p, ses_lock_held);
243 return (CKR_OBJECT_HANDLE_INVALID);
244 }
245 object_p->obj_delete_sync |= OBJECT_IS_DELETING;
246 (void) pthread_mutex_unlock(&object_p->object_mutex);
247
248 if (object_p->bool_attr_mask & TOKEN_BOOL_ON) {
249 /*
250 * The first FALSE boolean argument indicates that the caller
251 * does not hold the slot lock. The second FALSE boolean
252 * argument indicates that the caller wants to clean up the
253 * object in the HW provider also.
254 */
255 pslot = get_slotinfo();
256 rv = kms_delete_token_object(pslot, session_p, object_p,
257 B_FALSE, B_FALSE);
258 } else {
259 /*
260 * The first FALSE boolean argument indicates that the caller
261 * does not hold the session lock. The second FALSE boolean
262 * argument indicates that the caller wants to clean the object
263 * in the HW provider also.
264 */
265 rv = kms_delete_object(session_p, object_p, B_FALSE,
266 B_FALSE);
267 }
268 /*
269 * Decrement the session reference count.
270 * We do not hold the session lock.
271 */
272 REFRELE(session_p, ses_lock_held);
273 return (rv);
274 }
275
276 CK_RV
C_GetAttributeValue(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)277 C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
278 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
279 {
280
281 CK_RV rv = CKR_OK, rv1 = CKR_OK;
282 kms_object_t *object_p;
283 kms_session_t *session_p;
284 boolean_t ses_lock_held = B_FALSE;
285 int i;
286
287 if (!kms_initialized)
288 return (CKR_CRYPTOKI_NOT_INITIALIZED);
289
290 if ((pTemplate == NULL) || (ulCount == 0))
291 return (CKR_ARGUMENTS_BAD);
292
293 /*
294 * Obtain the session pointer. Also, increment the session
295 * reference count.
296 */
297 rv = handle2session(hSession, &session_p);
298 if (rv != CKR_OK)
299 return (rv);
300
301 /* Obtain the object pointer. */
302 HANDLE2OBJECT(hObject, object_p, rv);
303 if (rv != CKR_OK) {
304 /*
305 * Decrement the session reference count.
306 * We do not hold the session lock.
307 */
308 REFRELE(session_p, ses_lock_held);
309 return (rv);
310 }
311
312 /* Acquire the lock on the object. */
313 (void) pthread_mutex_lock(&object_p->object_mutex);
314
315 /*
316 * The object was created in the library. The library
317 * contains the value information of each attribute.
318 */
319 for (i = 0; i < ulCount; i++) {
320 /*
321 * Get the value of each attribute in the template.
322 * (We must process EVERY attribute in the template.)
323 */
324 rv = kms_get_attribute(object_p, &pTemplate[i]);
325 if (rv != CKR_OK)
326 rv1 = rv;
327 }
328 (void) pthread_mutex_unlock(&object_p->object_mutex);
329
330 clean_exit:
331 /*
332 * Decrement the session reference count.
333 * We do not hold the session lock.
334 */
335 OBJ_REFRELE(object_p);
336 REFRELE(session_p, ses_lock_held);
337 rv = rv1;
338 return (rv);
339 }
340
341 CK_RV
C_SetAttributeValue(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)342 C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
343 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
344 {
345 CK_RV rv = CKR_OK;
346 kms_object_t *object_p;
347 kms_object_t *new_object = NULL;
348 kms_session_t *session_p;
349 boolean_t ses_lock_held = B_FALSE;
350 int i;
351
352 if (!kms_initialized)
353 return (CKR_CRYPTOKI_NOT_INITIALIZED);
354
355 if ((pTemplate == NULL) || (ulCount == 0))
356 return (CKR_ARGUMENTS_BAD);
357
358 /*
359 * Obtain the session pointer. Also, increment the session
360 * reference count.
361 */
362 rv = handle2session(hSession, &session_p);
363 if (rv != CKR_OK)
364 return (rv);
365
366 /* Obtain the object pointer. */
367 HANDLE2OBJECT(hObject, object_p, rv);
368 if (rv != CKR_OK) {
369 /*
370 * Decrement the session reference count.
371 * We do not hold the session lock.
372 */
373 REFRELE(session_p, ses_lock_held);
374 return (rv);
375 }
376
377 /* lock the object */
378 (void) pthread_mutex_lock(&object_p->object_mutex);
379
380 /*
381 * If the object was created in the HW provider, changing its
382 * attributes' values need to be done in the provider too.
383 */
384 if (!object_p->is_lib_obj) {
385
386 /* Cannot modify a token object with a READ-ONLY session */
387 if (session_p->ses_RO &&
388 (object_p->bool_attr_mask & TOKEN_BOOL_ON)) {
389 (void) pthread_mutex_unlock(&object_p->object_mutex);
390 rv = CKR_SESSION_READ_ONLY;
391 goto clean_exit;
392 }
393 }
394
395 /*
396 * if we come here, the object must have been created in the
397 * library. The work will be done completely in the library.
398 *
399 * Copy the old object to a new object. We work on the copied
400 * version because in case of error we still keep the old one
401 * intact.
402 */
403 rv = kms_copy_object(object_p, &new_object, B_FALSE, NULL);
404 (void) pthread_mutex_unlock(&object_p->object_mutex);
405 if ((rv != CKR_OK) || (new_object == NULL)) {
406 /*
407 * Most likely we ran out of space.
408 * Decrement the session reference count.
409 * We do not hold the session lock.
410 */
411 goto clean_exit;
412 }
413
414 for (i = 0; i < ulCount; i++) {
415 /* Set the requested attribute into the new object. */
416 rv = kms_set_attribute(new_object, &pTemplate[i], B_FALSE);
417
418 if (rv != CKR_OK) {
419 kms_cleanup_object(new_object);
420 goto clean_exit;
421 }
422 }
423
424 /*
425 * We've successfully set all the requested attributes.
426 * Merge the new object with the old object, then destory
427 * the new one. The reason to do the merging is because we
428 * have to keep the original object handle (address of object).
429 */
430 (void) pthread_mutex_lock(&object_p->object_mutex);
431 kms_merge_object(object_p, new_object);
432 (void) pthread_mutex_unlock(&object_p->object_mutex);
433
434 clean_exit:
435 if (new_object != NULL)
436 (void) kms_free_object(new_object);
437
438 /*
439 * Decrement the session reference count.
440 * We do not hold the session lock.
441 */
442 OBJ_REFRELE(object_p);
443 REFRELE(session_p, ses_lock_held);
444
445 return (rv);
446 }
447
448 CK_RV
C_GetObjectSize(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ULONG_PTR pulSize)449 C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
450 CK_ULONG_PTR pulSize)
451 {
452
453 CK_RV rv = CKR_OK;
454 kms_object_t *object_p;
455 kms_session_t *session_p;
456 boolean_t ses_lock_held = B_FALSE;
457
458 if (!kms_initialized)
459 return (CKR_CRYPTOKI_NOT_INITIALIZED);
460
461 /* Check if pulSize is valid */
462 if (pulSize == NULL) {
463 return (CKR_ARGUMENTS_BAD);
464 }
465
466 /*
467 * Obtain the session pointer. Also, increment the session
468 * reference count.
469 */
470 rv = handle2session(hSession, &session_p);
471 if (rv != CKR_OK)
472 return (rv);
473
474 /* Obtain the object pointer. */
475 HANDLE2OBJECT(hObject, object_p, rv);
476 if (rv != CKR_OK) {
477 /*
478 * Decrement the session reference count.
479 * We do not hold the session lock.
480 */
481 REFRELE(session_p, ses_lock_held);
482 return (rv);
483 }
484
485 /* Acquire the lock on the object. */
486 (void) pthread_mutex_lock(&object_p->object_mutex);
487
488 rv = kms_get_object_size(object_p, pulSize);
489
490 (void) pthread_mutex_unlock(&object_p->object_mutex);
491
492 /*
493 * Decrement the session reference count.
494 * We do not hold the session lock.
495 */
496 OBJ_REFRELE(object_p);
497 REFRELE(session_p, ses_lock_held);
498 return (rv);
499 }
500
501 CK_RV
C_FindObjectsInit(CK_SESSION_HANDLE sh,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)502 C_FindObjectsInit(CK_SESSION_HANDLE sh, CK_ATTRIBUTE_PTR pTemplate,
503 CK_ULONG ulCount)
504 {
505 CK_RV rv;
506 kms_session_t *session_p;
507 boolean_t ses_lock_held = B_FALSE;
508
509 if (!kms_initialized)
510 return (CKR_CRYPTOKI_NOT_INITIALIZED);
511
512 /* Check the arguments */
513 if ((ulCount > 0) && (pTemplate == NULL)) {
514 return (CKR_ARGUMENTS_BAD);
515 }
516
517 /*
518 * Obtain the session pointer. Also, increment the session
519 * reference count.
520 */
521 rv = handle2session(sh, &session_p);
522 if (rv != CKR_OK)
523 return (rv);
524
525 /* Acquire the session lock */
526 (void) pthread_mutex_lock(&session_p->session_mutex);
527 ses_lock_held = B_TRUE;
528
529 /* Check to see if find operation is already active */
530 if (session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE) {
531 /* decrement the session count, and unlock the mutex */
532 REFRELE(session_p, ses_lock_held);
533 return (CKR_OPERATION_ACTIVE);
534 } else {
535 /*
536 * This active flag will remain ON until application calls
537 * C_FindObjectsFinal.
538 */
539 session_p->find_objects.flags = CRYPTO_OPERATION_ACTIVE;
540 }
541 (void) pthread_mutex_unlock(&session_p->session_mutex);
542
543 /*
544 * If the KMS provider supports object creation, we call the
545 * CRYPTO_OBJECT_FIND_INIT to initialize object finding.
546 * Otherwise, all the objects are created in the library and we
547 * do the find objects solely in the library.
548 */
549 rv = kms_find_objects_init(session_p, pTemplate, ulCount);
550 if (rv != CKR_OK) {
551 (void) pthread_mutex_lock(&session_p->session_mutex);
552 session_p->find_objects.flags = 0;
553 (void) pthread_mutex_unlock(&session_p->session_mutex);
554 }
555 /* decrement the session count, and unlock the mutex */
556 REFRELE(session_p, ses_lock_held);
557 return (rv);
558 }
559
560 CK_RV
C_FindObjects(CK_SESSION_HANDLE sh,CK_OBJECT_HANDLE_PTR phObject,CK_ULONG ulMaxObjectCount,CK_ULONG_PTR pulObjectCount)561 C_FindObjects(CK_SESSION_HANDLE sh, CK_OBJECT_HANDLE_PTR phObject,
562 CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
563 {
564 CK_RV rv = CKR_OK;
565 kms_slot_t *pslot = NULL;
566 kms_session_t *session_p;
567 boolean_t ses_lock_held = B_FALSE;
568
569 if (!kms_initialized)
570 return (CKR_CRYPTOKI_NOT_INITIALIZED);
571
572 /* check for invalid arguments */
573 if (((phObject == NULL) && (ulMaxObjectCount != 0)) ||
574 (pulObjectCount == NULL)) {
575 return (CKR_ARGUMENTS_BAD);
576 }
577
578 if (ulMaxObjectCount == 0) {
579 /* don't need to do anything, just return */
580 *pulObjectCount = 0;
581 return (CKR_OK);
582 }
583
584 /*
585 * Obtain the session pointer. Also, increment the session
586 * reference count.
587 */
588 rv = handle2session(sh, &session_p);
589 if (rv != CKR_OK)
590 return (rv);
591
592 /* Acquire the slot lock */
593 pslot = get_slotinfo();
594 (void) pthread_mutex_lock(&pslot->sl_mutex);
595
596 /* Acquire the session lock */
597 (void) pthread_mutex_lock(&session_p->session_mutex);
598 ses_lock_held = B_TRUE;
599
600 /* Check to see if find operation is active */
601 if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
602 rv = CKR_OPERATION_NOT_INITIALIZED;
603 goto clean_exit;
604 }
605
606 /*
607 * Similar to C_FindObjectInit(), if the KMS provider supports object
608 * creation, we need to find objects.
609 * Otherwise, all the objects are created in the library and we do
610 * the find objects solely in the library.
611 */
612
613 rv = kms_find_objects(session_p, phObject,
614 ulMaxObjectCount, pulObjectCount);
615
616 clean_exit:
617 /* decrement the session count, and release the session lock */
618 REFRELE(session_p, ses_lock_held);
619
620 /* release the slot lock */
621 if (pslot)
622 (void) pthread_mutex_unlock(&pslot->sl_mutex);
623
624 return (rv);
625 }
626
627 CK_RV
C_FindObjectsFinal(CK_SESSION_HANDLE sh)628 C_FindObjectsFinal(CK_SESSION_HANDLE sh)
629 {
630 kms_session_t *session_p;
631 CK_RV rv;
632 boolean_t ses_lock_held = B_FALSE;
633
634 if (!kms_initialized)
635 return (CKR_CRYPTOKI_NOT_INITIALIZED);
636
637 /*
638 * Obtain the session pointer. Also, increment the session
639 * reference count.
640 */
641 rv = handle2session(sh, &session_p);
642 if (rv != CKR_OK)
643 return (rv);
644
645 /* Acquire the session lock */
646 (void) pthread_mutex_lock(&session_p->session_mutex);
647 ses_lock_held = B_TRUE;
648
649 /* Check to see if find operation is active */
650 if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
651 REFRELE(session_p, ses_lock_held);
652 return (CKR_OPERATION_NOT_INITIALIZED);
653 }
654
655 /*
656 * Similar to C_FindObjectInit(), if the KMS provider supports object
657 * creation, we need to finalize the search on the KMS side.
658 */
659 kms_find_objects_final(session_p);
660
661 /* decrement the session count, and release the lock */
662 REFRELE(session_p, ses_lock_held);
663 return (rv);
664 }
665