xref: /titanic_50/usr/src/lib/pkcs11/pkcs11_softtoken/common/softObject.c (revision 8461248208fabd3a8230615f8615e5bf1b4dcdcb)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <pthread.h>
30 #include <stdlib.h>
31 #include <security/cryptoki.h>
32 #include "softGlobal.h"
33 #include "softObject.h"
34 #include "softSession.h"
35 #include "softKeystore.h"
36 #include "softKeystoreUtil.h"
37 
38 
39 CK_RV
40 C_CreateObject(CK_SESSION_HANDLE hSession,
41     CK_ATTRIBUTE_PTR pTemplate,
42     CK_ULONG ulCount,
43     CK_OBJECT_HANDLE_PTR phObject)
44 {
45 
46 	CK_RV rv;
47 	soft_session_t *session_p;
48 	boolean_t lock_held = B_FALSE;
49 
50 	if (!softtoken_initialized)
51 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
52 
53 	/*
54 	 * Obtain the session pointer. Also, increment the session
55 	 * reference count.
56 	 */
57 	rv = handle2session(hSession, &session_p);
58 	if (rv != CKR_OK)
59 		return (rv);
60 
61 	if ((pTemplate == NULL) || (ulCount == 0) ||
62 	    (phObject == NULL)) {
63 		rv = CKR_ARGUMENTS_BAD;
64 		goto clean_exit;
65 	}
66 
67 	/* Create a new object. */
68 	rv = soft_add_object(pTemplate, ulCount, phObject, session_p);
69 
70 clean_exit:
71 	/*
72 	 * Decrement the session reference count.
73 	 * We do not hold the session lock.
74 	 */
75 	SES_REFRELE(session_p, lock_held);
76 	return (rv);
77 }
78 
79 CK_RV
80 C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
81     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
82     CK_OBJECT_HANDLE_PTR phNewObject)
83 {
84 
85 	CK_RV rv;
86 	soft_session_t *session_p;
87 	boolean_t lock_held = B_FALSE;
88 	soft_object_t *old_object, *new_object = NULL;
89 	ulong_t i;
90 
91 	if (!softtoken_initialized)
92 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
93 
94 	/*
95 	 * Obtain the session pointer. Also, increment the session
96 	 * reference count.
97 	 */
98 	rv = handle2session(hSession, &session_p);
99 	if (rv != CKR_OK)
100 		return (rv);
101 
102 	/* Check arguments */
103 	if (((ulCount > 0) && (pTemplate == NULL)) ||
104 	    (phNewObject == NULL)) {
105 		rv = CKR_ARGUMENTS_BAD;
106 		goto clean_exit;
107 	}
108 
109 	/* Obtain the object pointer. */
110 	HANDLE2OBJECT(hObject, old_object, rv);
111 	if (rv != CKR_OK) {
112 		goto clean_exit;
113 	}
114 
115 	/*
116 	 * Copy the old object to a new object.
117 	 * The 3rd argument with SOFT_COPY_OBJ value indicates that
118 	 * everything in the object will be duplicated for C_CopyObject.
119 	 * The 4th argument has the session pointer that will be
120 	 * saved in the new copy of the session object.
121 	 */
122 	(void) pthread_mutex_lock(&old_object->object_mutex);
123 	rv = soft_copy_object(old_object, &new_object, SOFT_COPY_OBJECT,
124 	    session_p);
125 
126 	if ((rv != CKR_OK) || (new_object == NULL)) {
127 		/* Most likely we ran out of space. */
128 		(void) pthread_mutex_unlock(&old_object->object_mutex);
129 		goto clean_exit1;
130 	}
131 
132 	/* No need to hold the lock on the old object. */
133 	(void) pthread_mutex_unlock(&old_object->object_mutex);
134 
135 	/* Modifiy the objects if requested */
136 	for (i = 0; i < ulCount; i++) {
137 		/* Set the requested attribute into the new object. */
138 		rv = soft_set_attribute(new_object, &pTemplate[i], B_TRUE);
139 		if (rv != CKR_OK) {
140 			goto fail;
141 		}
142 	}
143 
144 	rv = soft_pin_expired_check(new_object);
145 	if (rv != CKR_OK) {
146 		goto fail;
147 	}
148 
149 	/*
150 	 * Does the new object violate the creation rule or access rule?
151 	 */
152 	rv = soft_object_write_access_check(session_p, new_object);
153 	if (rv != CKR_OK) {
154 		goto fail;
155 	}
156 
157 	/*
158 	 * If the new object is a token object, it will be added
159 	 * to token object list and write to disk.
160 	 */
161 	if (IS_TOKEN_OBJECT(new_object)) {
162 		new_object->version = 1;
163 		/*
164 		 * Write to the keystore file.
165 		 */
166 		rv = soft_put_object_to_keystore(new_object);
167 		if (rv != CKR_OK) {
168 			goto fail;
169 		}
170 
171 		new_object->session_handle = (CK_SESSION_HANDLE)NULL;
172 		/*
173 		 * Add the newly created token object to the global
174 		 * token object list in the slot struct.
175 		 */
176 		soft_add_token_object_to_slot(new_object);
177 		OBJ_REFRELE(old_object);
178 		SES_REFRELE(session_p, lock_held);
179 		*phNewObject = (CK_ULONG)new_object;
180 
181 		return (CKR_OK);
182 	}
183 
184 	/* Insert new object into this session's object list */
185 	soft_add_object_to_session(new_object, session_p);
186 
187 	/*
188 	 * Decrement the session reference count.
189 	 * We do not hold the session lock.
190 	 */
191 	OBJ_REFRELE(old_object);
192 	SES_REFRELE(session_p, lock_held);
193 
194 	/* set handle of the new object */
195 	*phNewObject = (CK_ULONG)new_object;
196 
197 	return (rv);
198 
199 fail:
200 	soft_cleanup_object(new_object);
201 	free(new_object);
202 
203 clean_exit1:
204 	OBJ_REFRELE(old_object);
205 clean_exit:
206 	SES_REFRELE(session_p, lock_held);
207 	return (rv);
208 }
209 
210 CK_RV
211 C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
212 {
213 
214 	CK_RV rv;
215 	soft_object_t *object_p;
216 	soft_session_t *session_p = (soft_session_t *)(hSession);
217 	boolean_t lock_held = B_FALSE;
218 	CK_SESSION_HANDLE creating_session;
219 
220 
221 	if (!softtoken_initialized)
222 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
223 
224 	/*
225 	 * The reason that we don't call handle2session is because
226 	 * the argument hSession may not be the creating_session of
227 	 * the object to be destroyed, and we want to avoid the lock
228 	 * contention. The handle2session will be called later for
229 	 * the creating_session.
230 	 */
231 	if ((session_p == NULL) ||
232 	    (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
233 		return (CKR_SESSION_HANDLE_INVALID);
234 	}
235 
236 	/* Obtain the object pointer. */
237 	HANDLE2OBJECT_DESTROY(hObject, object_p, rv);
238 	if (rv != CKR_OK) {
239 		return (rv);
240 	}
241 
242 	/* Obtain the session handle which object belongs to. */
243 	creating_session = object_p->session_handle;
244 
245 	if (creating_session == NULL) {
246 		/*
247 		 * This is a token object to be deleted.
248 		 * For token object, there is no creating session concept,
249 		 * therefore, creating_session is always NULL.
250 		 */
251 		rv = soft_pin_expired_check(object_p);
252 		if (rv != CKR_OK) {
253 			return (rv);
254 		}
255 
256 		/* Obtain the session pointer just for validity check. */
257 		rv = handle2session(hSession, &session_p);
258 		if (rv != CKR_OK) {
259 			return (rv);
260 		}
261 
262 		rv = soft_object_write_access_check(session_p, object_p);
263 		if (rv != CKR_OK) {
264 			SES_REFRELE(session_p, lock_held);
265 			return (rv);
266 		}
267 
268 		/*
269 		 * Set OBJECT_IS_DELETING flag so any access to this
270 		 * object will be rejected.
271 		 */
272 		(void) pthread_mutex_lock(&object_p->object_mutex);
273 		object_p->obj_delete_sync |= OBJECT_IS_DELETING;
274 		(void) pthread_mutex_unlock(&object_p->object_mutex);
275 		SES_REFRELE(session_p, lock_held);
276 
277 		/*
278 		 * Delete a token object by calling soft_delete_token_object()
279 		 * with the second argument B_TRUE indicating to delete the
280 		 * object from keystore and the third argument B_FALSE
281 		 * indicating that the caller does not hold the slot mutex.
282 		 */
283 		soft_delete_token_object(object_p, B_TRUE, B_FALSE);
284 		return (CKR_OK);
285 	}
286 
287 	/*
288 	 * Obtain the session pointer. Also, increment the session
289 	 * reference count.
290 	 */
291 	rv = handle2session(creating_session, &session_p);
292 	if (rv != CKR_OK) {
293 		return (rv);
294 	}
295 
296 	/*
297 	 * Set OBJECT_IS_DELETING flag so any access to this
298 	 * object will be rejected.
299 	 */
300 	(void) pthread_mutex_lock(&object_p->object_mutex);
301 	object_p->obj_delete_sync |= OBJECT_IS_DELETING;
302 	(void) pthread_mutex_unlock(&object_p->object_mutex);
303 
304 	/*
305 	 * Delete an object by calling soft_delete_object()
306 	 * with a FALSE boolean argument indicating that
307 	 * the caller does not hold the session lock.
308 	 */
309 	soft_delete_object(session_p, object_p, B_FALSE);
310 
311 	/*
312 	 * Decrement the session reference count.
313 	 * We do not hold the session lock.
314 	 */
315 	SES_REFRELE(session_p, lock_held);
316 
317 	return (rv);
318 }
319 
320 
321 CK_RV
322 C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
323     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
324 {
325 
326 	CK_RV rv = CKR_OK, rv1 = CKR_OK;
327 	soft_object_t *object_p;
328 	soft_session_t *session_p;
329 	boolean_t lock_held = B_FALSE;
330 	ulong_t i;
331 
332 	if (!softtoken_initialized)
333 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
334 
335 	/*
336 	 * Obtain the session pointer. Also, increment the session
337 	 * reference count.
338 	 */
339 	rv = handle2session(hSession, &session_p);
340 	if (rv != CKR_OK)
341 		return (rv);
342 
343 	if ((pTemplate == NULL) || (ulCount == 0)) {
344 		/*
345 		 * Decrement the session reference count.
346 		 * We do not hold the session lock.
347 		 */
348 		SES_REFRELE(session_p, lock_held);
349 		return (CKR_ARGUMENTS_BAD);
350 	}
351 
352 	/* Obtain the object pointer. */
353 	HANDLE2OBJECT(hObject, object_p, rv);
354 	if (rv != CKR_OK) {
355 		/*
356 		 * Decrement the session reference count.
357 		 * We do not hold the session lock.
358 		 */
359 		SES_REFRELE(session_p, lock_held);
360 		return (rv);
361 	}
362 
363 	if (IS_TOKEN_OBJECT(object_p)) {
364 
365 		rv = soft_keystore_load_latest_object(object_p);
366 		if (rv != CKR_OK) {
367 			OBJ_REFRELE(object_p);
368 			SES_REFRELE(session_p, lock_held);
369 			return (rv);
370 		}
371 	}
372 
373 	/* Acquire the lock on the object. */
374 	(void) pthread_mutex_lock(&object_p->object_mutex);
375 
376 	for (i = 0; i < ulCount; i++) {
377 		/*
378 		 * Get the value of each attribute in the template.
379 		 * (We must process EVERY attribute in the template.)
380 		 */
381 		rv = soft_get_attribute(object_p, &pTemplate[i]);
382 		if (rv != CKR_OK)
383 			/* At least we catch some type of error. */
384 			rv1 = rv;
385 	}
386 
387 	/* Release the object lock */
388 	(void) pthread_mutex_unlock(&object_p->object_mutex);
389 
390 	/*
391 	 * Decrement the session reference count.
392 	 * We do not hold the session lock.
393 	 */
394 	OBJ_REFRELE(object_p);
395 	SES_REFRELE(session_p, lock_held);
396 
397 	rv = rv1;
398 	return (rv);
399 }
400 
401 
402 CK_RV
403 C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
404     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
405 {
406 	CK_RV rv = CKR_OK;
407 	soft_object_t *object_p;
408 	soft_object_t *new_object = NULL;
409 	soft_session_t *session_p;
410 	boolean_t lock_held = B_FALSE;
411 	ulong_t i;
412 
413 	if (!softtoken_initialized)
414 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
415 
416 	/*
417 	 * Obtain the session pointer. Also, increment the session
418 	 * reference count.
419 	 */
420 	rv = handle2session(hSession, &session_p);
421 	if (rv != CKR_OK)
422 		return (rv);
423 
424 	if ((pTemplate == NULL) || (ulCount == 0)) {
425 		/*
426 		 * Decrement the session reference count.
427 		 * We do not hold the session lock.
428 		 */
429 		SES_REFRELE(session_p, lock_held);
430 		return (CKR_ARGUMENTS_BAD);
431 	}
432 
433 	/* Obtain the object pointer. */
434 	HANDLE2OBJECT(hObject, object_p, rv);
435 	if (rv != CKR_OK) {
436 		/*
437 		 * Decrement the session reference count.
438 		 * We do not hold the session lock.
439 		 */
440 		SES_REFRELE(session_p, lock_held);
441 		return (rv);
442 	}
443 
444 	if (object_p->bool_attr_mask & NOT_MODIFIABLE_BOOL_ON) {
445 		rv = CKR_ATTRIBUTE_READ_ONLY;
446 		goto fail_1;
447 	}
448 
449 	/*
450 	 * Start working on the object, so we need to set the write lock so that
451 	 * no one can write to it but still can read it.
452 	 */
453 	if (IS_TOKEN_OBJECT(object_p)) {
454 		rv = soft_keystore_load_latest_object(object_p);
455 		if (rv != CKR_OK) {
456 			goto fail_1;
457 		}
458 	}
459 
460 	/*
461 	 * Copy the old object to a new object. We work on the copied
462 	 * version because in case of error we still keep the old one
463 	 * intact.
464 	 * The 3rd argument with SOFT_SET_ATTR_VALUE value indicates that
465 	 * not everything will be duplicated for C_SetAttributeValue.
466 	 * Information not duplicated are those attributes that are not
467 	 * modifiable.
468 	 */
469 	(void) pthread_mutex_lock(&object_p->object_mutex);
470 	rv = soft_copy_object(object_p, &new_object, SOFT_SET_ATTR_VALUE, NULL);
471 
472 	if ((rv != CKR_OK) || (new_object == NULL)) {
473 		/* Most likely we ran out of space. */
474 		(void) pthread_mutex_unlock(&object_p->object_mutex);
475 		/*
476 		 * Decrement the session reference count.
477 		 * We do not hold the session lock.
478 		 */
479 		goto fail_1;
480 	}
481 
482 	/*
483 	 * No need to hold the lock on the old object, because we
484 	 * will be working on the new scratch object.
485 	 */
486 	(void) pthread_mutex_unlock(&object_p->object_mutex);
487 
488 	rv = soft_object_write_access_check(session_p, new_object);
489 	if (rv != CKR_OK) {
490 		goto fail;
491 	}
492 
493 	for (i = 0; i < ulCount; i++) {
494 		/* Set the requested attribute into the new object. */
495 		rv = soft_set_attribute(new_object, &pTemplate[i], B_FALSE);
496 
497 		if (rv != CKR_OK) {
498 			goto fail;
499 		}
500 	}
501 
502 	/*
503 	 * We've successfully set all the requested attributes.
504 	 * Merge the new object with the old object, then destory
505 	 * the new one. The reason to do the merging is because we
506 	 * have to keep the original object handle (address of object).
507 	 */
508 	(void) pthread_mutex_lock(&object_p->object_mutex);
509 
510 	soft_merge_object(object_p, new_object);
511 
512 	/*
513 	 * The object has been modified, so we write it back to keystore.
514 	 */
515 	if (IS_TOKEN_OBJECT(object_p)) {
516 		object_p->version++;
517 		rv = soft_modify_object_to_keystore(object_p);
518 	}
519 
520 	(void) pthread_mutex_unlock(&object_p->object_mutex);
521 	free(new_object);
522 
523 	/*
524 	 * Decrement the session reference count.
525 	 * We do not hold the session lock.
526 	 */
527 	OBJ_REFRELE(object_p);
528 	SES_REFRELE(session_p, lock_held);
529 	return (rv);
530 
531 fail:
532 	soft_cleanup_object(new_object);
533 	free(new_object);
534 
535 fail_1:
536 	OBJ_REFRELE(object_p);
537 	SES_REFRELE(session_p, lock_held);
538 
539 	return (rv);
540 }
541 
542 /*ARGSUSED*/
543 CK_RV
544 C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
545     CK_ULONG_PTR pulSize)
546 {
547 	if (!softtoken_initialized)
548 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
549 
550 	return (CKR_FUNCTION_NOT_SUPPORTED);
551 }
552 
553 CK_RV
554 C_FindObjectsInit(CK_SESSION_HANDLE sh, CK_ATTRIBUTE_PTR pTemplate,
555     CK_ULONG ulCount)
556 {
557 
558 	CK_RV		rv;
559 	soft_session_t	*session_p;
560 	boolean_t lock_held = B_TRUE;
561 
562 	if (!softtoken_initialized)
563 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
564 
565 	/*
566 	 * Obtain the session pointer. Also, increment the session
567 	 * reference count.
568 	 */
569 	rv = handle2session(sh, &session_p);
570 	if (rv != CKR_OK)
571 		return (rv);
572 
573 	/* Check the arguments */
574 	if ((ulCount > 0) && (pTemplate == NULL)) {
575 		/* decrement the session count, we do not hold the lock */
576 		lock_held = B_FALSE;
577 		SES_REFRELE(session_p, lock_held);
578 		return (CKR_ARGUMENTS_BAD);
579 	}
580 
581 	/* Acquire the session lock */
582 	(void) pthread_mutex_lock(&session_p->session_mutex);
583 
584 	/* Check to see if find operation is already active */
585 	if (session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE) {
586 		/* decrement the session count, and unlock the mutex */
587 		SES_REFRELE(session_p, lock_held);
588 		return (CKR_OPERATION_ACTIVE);
589 	} else {
590 		/*
591 		 * This active flag will remain ON until application calls
592 		 * C_FindObjectsFinal.
593 		 */
594 		session_p->find_objects.flags = CRYPTO_OPERATION_ACTIVE;
595 	}
596 
597 	(void) pthread_mutex_unlock(&session_p->session_mutex);
598 
599 	rv = soft_find_objects_init(session_p,  pTemplate, ulCount);
600 
601 	if (rv != CKR_OK) {
602 		(void) pthread_mutex_lock(&session_p->session_mutex);
603 		session_p->find_objects.flags = 0;
604 		(void) pthread_mutex_unlock(&session_p->session_mutex);
605 	}
606 
607 	/* decrement the session count, and unlock the mutex */
608 	lock_held = B_FALSE;
609 	SES_REFRELE(session_p, lock_held);
610 	return (rv);
611 }
612 
613 CK_RV
614 C_FindObjects(CK_SESSION_HANDLE sh,
615     CK_OBJECT_HANDLE_PTR phObject,
616     CK_ULONG ulMaxObjectCount,
617     CK_ULONG_PTR pulObjectCount)
618 {
619 	soft_session_t	*session_p;
620 	CK_RV rv = CKR_OK;
621 	boolean_t lock_held = B_TRUE;
622 
623 	if (!softtoken_initialized)
624 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
625 
626 	/*
627 	 * Obtain the session pointer. Also, increment the session
628 	 * reference count.
629 	 */
630 	rv = handle2session(sh, &session_p);
631 	if (rv != CKR_OK)
632 		return (rv);
633 
634 	/* check for invalid arguments */
635 	if (((phObject == NULL) && (ulMaxObjectCount != 0)) ||
636 	    (pulObjectCount == NULL)) {
637 		/* decrement the session count, we do not hold the lock */
638 		lock_held = B_FALSE;
639 		SES_REFRELE(session_p, lock_held);
640 		return (CKR_ARGUMENTS_BAD);
641 	}
642 
643 	if (ulMaxObjectCount == 0) {
644 		/* don't need to do anything, just return */
645 		*pulObjectCount = 0;
646 		/* decrement the session count, we do not hold the lock */
647 		lock_held = B_FALSE;
648 		SES_REFRELE(session_p, lock_held);
649 		return (CKR_OK);
650 	}
651 
652 	/* Acquire the session lock */
653 	(void) pthread_mutex_lock(&session_p->session_mutex);
654 
655 	/* Check to see if find operation is active */
656 	if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
657 		SES_REFRELE(session_p, lock_held);
658 		return (CKR_OPERATION_NOT_INITIALIZED);
659 	}
660 
661 	soft_find_objects(session_p, phObject, ulMaxObjectCount,
662 	    pulObjectCount);
663 
664 	/* decrement the session count, and release the lock */
665 	SES_REFRELE(session_p, lock_held);
666 	return (rv);
667 }
668 
669 CK_RV
670 C_FindObjectsFinal(CK_SESSION_HANDLE sh)
671 {
672 	soft_session_t	*session_p;
673 	CK_RV rv;
674 	boolean_t lock_held = B_TRUE;
675 
676 	if (!softtoken_initialized)
677 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
678 
679 	/*
680 	 * Obtain the session pointer. Also, increment the session
681 	 * reference count.
682 	 */
683 	rv = handle2session(sh, &session_p);
684 	if (rv != CKR_OK)
685 		return (rv);
686 
687 	/* Acquire the session lock */
688 	(void) pthread_mutex_lock(&session_p->session_mutex);
689 
690 	/* Check to see if find operation is active */
691 	if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
692 		SES_REFRELE(session_p, lock_held);
693 		return (CKR_OPERATION_NOT_INITIALIZED);
694 	}
695 
696 	soft_find_objects_final(session_p);
697 
698 	/* decrement the session count, and release the lock */
699 	SES_REFRELE(session_p, lock_held);
700 	return (rv);
701 }
702