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  * Copyright 2020 Joyent, Inc.
25  */
26 
27 #include <pthread.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <security/cryptoki.h>
32 #include <sys/debug.h>
33 #include "softGlobal.h"
34 #include "softObject.h"
35 #include "softSession.h"
36 #include "softKeystore.h"
37 #include "softKeystoreUtil.h"
38 
39 /*
40  * Add an object to the session's object list.
41  *
42  * This function will acquire the lock on the session, and release
43  * that lock after adding the object to the session's object list.
44  */
45 void
soft_add_object_to_session(soft_object_t * objp,soft_session_t * sp)46 soft_add_object_to_session(soft_object_t *objp, soft_session_t *sp)
47 {
48 
49 	/* Acquire the session lock. */
50 	(void) pthread_mutex_lock(&sp->session_mutex);
51 
52 	/* Insert the new object in front of session's object list. */
53 	if (sp->object_list == NULL) {
54 		sp->object_list = objp;
55 		objp->next = NULL;
56 		objp->prev = NULL;
57 	} else {
58 		sp->object_list->prev = objp;
59 		objp->next = sp->object_list;
60 		objp->prev = NULL;
61 		sp->object_list = objp;
62 	}
63 
64 	/* Release the session lock. */
65 	(void) pthread_mutex_unlock(&sp->session_mutex);
66 }
67 
68 
69 /*
70  * Clean up and release the storage allocated to the object.
71  *
72  * The function is called either with the object lock being held
73  * (by caller soft_delete_object()), or there is no object lock
74  * yet (by soft_build_XXX_object() during creating an object).
75  */
76 void
soft_cleanup_object(soft_object_t * objp)77 soft_cleanup_object(soft_object_t *objp)
78 {
79 	/*
80 	 * Free the storage allocated to big integer attributes.
81 	 */
82 	soft_cleanup_object_bigint_attrs(objp);
83 
84 	/*
85 	 * Free the storage allocated to the extra attribute list.
86 	 */
87 	soft_cleanup_extra_attr(objp);
88 
89 	/*
90 	 * Free the storage allocated to certificate attributes.
91 	 */
92 	soft_cleanup_cert_object(objp);
93 }
94 
95 
96 /*
97  * Create a new object. Copy the attributes that can be modified
98  * (in the boolean attribute mask field and extra attribute list)
99  * from the old object to the new object.
100  *
101  * The caller of this function holds the lock on the old object.
102  */
103 CK_RV
soft_copy_object(soft_object_t * old_object,soft_object_t ** new_object,CK_ULONG object_func,soft_session_t * sp)104 soft_copy_object(soft_object_t *old_object, soft_object_t **new_object,
105     CK_ULONG object_func, soft_session_t *sp)
106 {
107 
108 	CK_RV rv = CKR_OK;
109 	soft_object_t *new_objp = NULL;
110 	CK_ATTRIBUTE_INFO_PTR attrp;
111 
112 	/* Allocate new object. */
113 	new_objp = calloc(1, sizeof (soft_object_t));
114 	if (new_objp == NULL)
115 		return (CKR_HOST_MEMORY);
116 
117 	new_objp->class = old_object->class;
118 	new_objp->bool_attr_mask = old_object->bool_attr_mask;
119 	new_objp->cert_type = old_object->cert_type;
120 	new_objp->object_type = old_object->object_type;
121 
122 	attrp = old_object->extra_attrlistp;
123 	while (attrp) {
124 		/*
125 		 * Copy the attribute_info struct from the old
126 		 * object to a new attribute_info struct, and add
127 		 * that new struct to the extra attribute list
128 		 * of the new object.
129 		 */
130 		rv = soft_copy_extra_attr(attrp, new_objp);
131 		if (rv != CKR_OK) {
132 			soft_cleanup_extra_attr(new_objp);
133 			free(new_objp);
134 			return (rv);
135 		}
136 		attrp = attrp->next;
137 	}
138 
139 	*new_object = new_objp;
140 
141 	if (object_func == SOFT_SET_ATTR_VALUE) {
142 		/* done with copying all information that can be modified */
143 		return (CKR_OK);
144 	}
145 
146 	/*
147 	 * Copy the rest of the object.
148 	 * Certain fields that are not appropriate for coping will be
149 	 * initialized.
150 	 */
151 	new_objp->key_type = old_object->key_type;
152 	new_objp->magic_marker = old_object->magic_marker;
153 	new_objp->mechanism = old_object->mechanism;
154 
155 	switch (object_func) {
156 	case SOFT_COPY_OBJ_ORIG_SH:
157 		new_objp->session_handle = old_object->session_handle;
158 		break;
159 	case SOFT_COPY_OBJECT:
160 		/*
161 		 * Save the session handle of the C_CopyObject function
162 		 * in the new copy of the session object.
163 		 */
164 		new_objp->session_handle = sp->handle;
165 		break;
166 	}
167 
168 	(void) pthread_cond_init(&(new_objp->obj_free_cond), NULL);
169 	(void) pthread_mutex_init(&(new_objp->object_mutex), NULL);
170 	/* copy key related information */
171 	switch (new_objp->class) {
172 		case CKO_PUBLIC_KEY:
173 			rv = soft_copy_public_key_attr(OBJ_PUB(old_object),
174 			    &(OBJ_PUB(new_objp)), new_objp->key_type);
175 			break;
176 		case CKO_PRIVATE_KEY:
177 			rv = soft_copy_private_key_attr(OBJ_PRI(old_object),
178 			    &(OBJ_PRI(new_objp)), new_objp->key_type);
179 			break;
180 		case CKO_SECRET_KEY:
181 			rv = soft_copy_secret_key_attr(OBJ_SEC(old_object),
182 			    &(OBJ_SEC(new_objp)));
183 			break;
184 		case CKO_DOMAIN_PARAMETERS:
185 			rv = soft_copy_domain_attr(OBJ_DOM(old_object),
186 			    &(OBJ_DOM(new_objp)), new_objp->key_type);
187 			break;
188 		case CKO_CERTIFICATE:
189 			rv = soft_copy_certificate(OBJ_CERT(old_object),
190 			    &(OBJ_CERT(new_objp)), new_objp->cert_type);
191 			break;
192 		default:
193 			/* should never be this case */
194 			break;
195 	}
196 	if (rv != CKR_OK) {
197 		/*
198 		 * don't need to cleanup the memory from failure of copying
199 		 * any key related stuff.  Each individual function for
200 		 * copying key attr will free the memory if it fails
201 		 */
202 		soft_cleanup_extra_attr(new_objp);
203 		free(new_objp);
204 	}
205 	return (rv);
206 }
207 
208 
209 /*
210  * Copy the attributes (in the boolean attribute mask field and
211  * extra attribute list) from the new object back to the original
212  * object. Also, clean up and release all the storage in the extra
213  * attribute list of the original object.
214  *
215  * The caller of this function holds the lock on the old object.
216  */
217 void
soft_merge_object(soft_object_t * old_object,soft_object_t * new_object)218 soft_merge_object(soft_object_t *old_object, soft_object_t *new_object)
219 {
220 	old_object->bool_attr_mask = new_object->bool_attr_mask;
221 	soft_cleanup_extra_attr(old_object);
222 	old_object->extra_attrlistp = new_object->extra_attrlistp;
223 }
224 
225 /*
226  * Sets *object_p to the soft_object_t corresponding to hObject. If
227  * hObject is valid, and not in the deleting state, CKR_OK is returned,
228  * otherwise an error is returned. If hObject is valid and refhold is B_TRUE,
229  * the object is also held.
230  */
231 CK_RV
handle2object(CK_OBJECT_HANDLE hObject,soft_object_t ** object_p,boolean_t refhold)232 handle2object(CK_OBJECT_HANDLE hObject, soft_object_t **object_p,
233     boolean_t refhold)
234 {
235 	soft_object_t *obj;
236 	soft_object_t node;
237 
238 	(void) memset(&node, 0, sizeof (node));
239 	node.handle = hObject;
240 
241 	VERIFY0(pthread_mutex_lock(&soft_object_mutex));
242 	if ((obj = avl_find(&soft_object_tree, &node, NULL)) == NULL ||
243 	    obj->magic_marker != SOFTTOKEN_OBJECT_MAGIC) {
244 		VERIFY0(pthread_mutex_unlock(&soft_object_mutex));
245 		return (CKR_OBJECT_HANDLE_INVALID);
246 	}
247 
248 	(void) pthread_mutex_lock(&obj->object_mutex);
249 	VERIFY0(pthread_mutex_unlock(&soft_object_mutex));
250 
251 	if (obj->obj_delete_sync & OBJECT_IS_DELETING) {
252 		(void) pthread_mutex_unlock(&obj->object_mutex);
253 		return (CKR_OBJECT_HANDLE_INVALID);
254 	}
255 
256 	if (refhold)
257 		obj->obj_refcnt++;
258 
259 	(void) pthread_mutex_unlock(&obj->object_mutex);
260 
261 	*object_p = obj;
262 	return (CKR_OK);
263 }
264 
265 CK_ULONG
set_objecthandle(soft_object_t * obj)266 set_objecthandle(soft_object_t *obj)
267 {
268 	avl_index_t where;
269 
270 	(void) pthread_mutex_lock(&soft_object_mutex);
271 
272 	do {
273 		arc4random_buf(&obj->handle, sizeof (obj->handle));
274 		if (obj->handle == CK_INVALID_HANDLE)
275 			continue;
276 	} while (avl_find(&soft_object_tree, obj, &where) != NULL);
277 
278 	avl_insert(&soft_object_tree, obj, where);
279 
280 	(void) pthread_mutex_unlock(&soft_object_mutex);
281 
282 	return (obj->handle);
283 }
284 
285 /*
286  * Create a new object struct, and add it to the session's object list.
287  */
288 CK_RV
soft_add_object(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR objecthandle_p,soft_session_t * sp)289 soft_add_object(CK_ATTRIBUTE_PTR pTemplate,  CK_ULONG ulCount,
290     CK_OBJECT_HANDLE_PTR objecthandle_p, soft_session_t *sp)
291 {
292 
293 	CK_RV rv = CKR_OK;
294 	soft_object_t *new_objp = NULL;
295 
296 	new_objp = calloc(1, sizeof (soft_object_t));
297 	if (new_objp == NULL) {
298 		return (CKR_HOST_MEMORY);
299 	}
300 
301 	new_objp->extra_attrlistp = NULL;
302 
303 	/*
304 	 * Validate attribute template and fill in the attributes
305 	 * in the soft_object_t.
306 	 */
307 	rv = soft_build_object(pTemplate, ulCount, new_objp);
308 	if (rv != CKR_OK) {
309 		goto fail_cleanup1;
310 	}
311 
312 	rv = soft_pin_expired_check(new_objp);
313 	if (rv != CKR_OK) {
314 		goto fail_cleanup2;
315 	}
316 
317 	rv = soft_object_write_access_check(sp, new_objp);
318 	if (rv != CKR_OK) {
319 		goto fail_cleanup2;
320 	}
321 
322 	/* Initialize the rest of stuffs in soft_object_t. */
323 	(void) pthread_cond_init(&new_objp->obj_free_cond, NULL);
324 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
325 	new_objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
326 	new_objp->obj_refcnt = 0;
327 	new_objp->obj_delete_sync = 0;
328 
329 	/* Write the new token object to the keystore */
330 	if (IS_TOKEN_OBJECT(new_objp)) {
331 		if (!soft_keystore_status(KEYSTORE_INITIALIZED)) {
332 			rv = CKR_DEVICE_REMOVED;
333 			goto fail_cleanup2;
334 		}
335 		new_objp->version = 1;
336 		rv = soft_put_object_to_keystore(new_objp);
337 		if (rv != CKR_OK) {
338 			(void) pthread_cond_destroy(&new_objp->obj_free_cond);
339 			(void) pthread_mutex_destroy(&new_objp->object_mutex);
340 			goto fail_cleanup2;
341 		}
342 		new_objp->session_handle = CK_INVALID_HANDLE;
343 		soft_add_token_object_to_slot(new_objp);
344 
345 		*objecthandle_p = set_objecthandle(new_objp);
346 
347 		return (CKR_OK);
348 	}
349 
350 	new_objp->session_handle = sp->handle;
351 
352 	/* Add the new object to the session's object list. */
353 	soft_add_object_to_session(new_objp, sp);
354 
355 	*objecthandle_p = set_objecthandle(new_objp);
356 
357 	return (CKR_OK);
358 
359 fail_cleanup2:
360 	/*
361 	 * When any error occurs after soft_build_object(), we will need to
362 	 * clean up the memory allocated by the soft_build_object().
363 	 */
364 	soft_cleanup_object(new_objp);
365 
366 fail_cleanup1:
367 	if (new_objp) {
368 		/*
369 		 * The storage allocated inside of this object should have
370 		 * been cleaned up by the soft_build_object() if it failed.
371 		 * Therefore, we can safely free the object.
372 		 */
373 		free(new_objp);
374 	}
375 
376 	return (rv);
377 
378 }
379 
380 
381 /*
382  * Remove an object from the session's object list.
383  *
384  * The caller of this function holds the session lock.
385  */
386 CK_RV
soft_remove_object_from_session(soft_object_t * objp,soft_session_t * sp)387 soft_remove_object_from_session(soft_object_t *objp, soft_session_t *sp)
388 {
389 	soft_object_t *tmp_objp;
390 	boolean_t found = B_FALSE;
391 
392 	/*
393 	 * Remove the object from the session's object list.
394 	 */
395 	if ((sp == NULL) ||
396 	    (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
397 		return (CKR_SESSION_HANDLE_INVALID);
398 	}
399 
400 	if ((sp->object_list == NULL) || (objp == NULL) ||
401 	    (objp->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
402 		return (CKR_OBJECT_HANDLE_INVALID);
403 	}
404 
405 	tmp_objp = sp->object_list;
406 	while (tmp_objp) {
407 		if (tmp_objp == objp) {
408 			found = B_TRUE;
409 			break;
410 		}
411 		tmp_objp = tmp_objp->next;
412 	}
413 	if (!found)
414 		return (CKR_OBJECT_HANDLE_INVALID);
415 
416 	if (sp->object_list == objp) {
417 		/* Object is the first one in the list. */
418 		if (objp->next) {
419 			sp->object_list = objp->next;
420 			objp->next->prev = NULL;
421 		} else {
422 			/* Object is the only one in the list. */
423 			sp->object_list = NULL;
424 		}
425 	} else {
426 		/* Object is not the first one in the list. */
427 		if (objp->next) {
428 			/* Object is in the middle of the list. */
429 			objp->prev->next = objp->next;
430 			objp->next->prev = objp->prev;
431 		} else {
432 			/* Object is the last one in the list. */
433 			objp->prev->next = NULL;
434 		}
435 	}
436 	return (CKR_OK);
437 }
438 
439 /*
440  * This function adds the to-be-freed session object to a linked list.
441  * When the number of objects queued in the linked list reaches the
442  * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first
443  * object (FIFO) in the list.
444  */
445 void
object_delay_free(soft_object_t * objp)446 object_delay_free(soft_object_t *objp)
447 {
448 	soft_object_t *tmp;
449 
450 	(void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
451 
452 	/* Add the newly deleted object at the end of the list */
453 	objp->next = NULL;
454 	if (obj_delay_freed.first == NULL) {
455 		obj_delay_freed.last = objp;
456 		obj_delay_freed.first = objp;
457 	} else {
458 		obj_delay_freed.last->next = objp;
459 		obj_delay_freed.last = objp;
460 	}
461 
462 	if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
463 		/*
464 		 * Free the first object in the list only if
465 		 * the total count reaches maximum threshold.
466 		 */
467 		obj_delay_freed.count--;
468 		tmp = obj_delay_freed.first->next;
469 		free(obj_delay_freed.first);
470 		obj_delay_freed.first = tmp;
471 	}
472 	(void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
473 }
474 
475 static void
soft_delete_object_cleanup(soft_object_t * objp,boolean_t force)476 soft_delete_object_cleanup(soft_object_t *objp, boolean_t force)
477 {
478 	/* Acquire the lock on the object. */
479 	(void) pthread_mutex_lock(&objp->object_mutex);
480 
481 	/*
482 	 * Make sure another thread hasn't freed the object.
483 	 */
484 	if (objp->magic_marker != SOFTTOKEN_OBJECT_MAGIC) {
485 		(void) pthread_mutex_unlock(&objp->object_mutex);
486 		return;
487 	}
488 
489 	/*
490 	 * The deletion of an object must be blocked when the object
491 	 * reference count is not zero. This means if any object related
492 	 * operation starts prior to the delete object operation gets in,
493 	 * the object deleting thread must wait for the non-deleting
494 	 * operation to be completed before it can proceed the delete
495 	 * operation.
496 	 *
497 	 * Unless we are being forced to shut everything down, this only
498 	 * happens if the libraries _fini() is running not of someone
499 	 * explicitly called C_Finalize().
500 	 */
501 	if (force)
502 		objp->obj_refcnt = 0;
503 
504 	while (objp->obj_refcnt != 0) {
505 		/*
506 		 * We set the OBJECT_REFCNT_WAITING flag before we put
507 		 * this deleting thread in a wait state, so other non-deleting
508 		 * operation thread will signal to wake it up only when
509 		 * the object reference count becomes zero and this flag
510 		 * is set.
511 		 */
512 		objp->obj_delete_sync |= OBJECT_REFCNT_WAITING;
513 		(void) pthread_cond_wait(&objp->obj_free_cond,
514 		    &objp->object_mutex);
515 	}
516 
517 	objp->obj_delete_sync &= ~OBJECT_REFCNT_WAITING;
518 
519 	/* Mark object as no longer valid. */
520 	objp->magic_marker = 0;
521 
522 	(void) pthread_cond_destroy(&objp->obj_free_cond);
523 
524 	/*
525 	 * Cleanup the contents of this object such as free all the
526 	 * storage allocated for this object.
527 	 */
528 	soft_cleanup_object(objp);
529 
530 	(void) pthread_mutex_lock(&soft_object_mutex);
531 	avl_remove(&soft_object_tree, objp);
532 	(void) pthread_mutex_unlock(&soft_object_mutex);
533 
534 	/* Reset OBJECT_IS_DELETING flag. */
535 	objp->obj_delete_sync &= ~OBJECT_IS_DELETING;
536 
537 	(void) pthread_mutex_unlock(&objp->object_mutex);
538 	/* Destroy the object lock */
539 	(void) pthread_mutex_destroy(&objp->object_mutex);
540 
541 	/* Free the object itself */
542 	if (IS_TOKEN_OBJECT(objp))
543 		free(objp);
544 	else
545 		/*
546 		 * Delay freeing the session object as S1WS/NSS uses session
547 		 * objects for its SSL Handshake.
548 		 */
549 		(void) object_delay_free(objp);
550 }
551 
552 /*
553  * Delete an object:
554  * - Remove the object from the session's object list.
555  *   Holding the lock on the session which the object was created at
556  *   is needed to do this.
557  * - Release the storage allocated to the object.
558  *
559  * The boolean argument lock_held is used to indicate that whether
560  * the caller holds the session lock or not.
561  * - When called by soft_delete_all_objects_in_session() -- the
562  *   lock_held = TRUE.
563  *
564  * When the caller does not hold the session lock, this function
565  * will acquire that lock in order to proceed, and also release
566  * that lock before returning to caller.
567  */
568 void
soft_delete_object(soft_session_t * sp,soft_object_t * objp,boolean_t force,boolean_t lock_held)569 soft_delete_object(soft_session_t *sp, soft_object_t *objp,
570     boolean_t force, boolean_t lock_held)
571 {
572 
573 	/*
574 	 * Check to see if the caller holds the lock on the session.
575 	 * If not, we need to acquire that lock in order to proceed.
576 	 */
577 	if (!lock_held) {
578 		/* Acquire the session lock. */
579 		(void) pthread_mutex_lock(&sp->session_mutex);
580 	}
581 
582 	/* Remove the object from the session's object list first. */
583 	if (soft_remove_object_from_session(objp, sp) != CKR_OK) {
584 		if (!lock_held) {
585 			(void) pthread_mutex_unlock(&sp->session_mutex);
586 		}
587 		return;
588 	}
589 
590 	if (!lock_held) {
591 		/*
592 		 * If the session lock is obtained by this function,
593 		 * then release that lock after removing the object
594 		 * from session's object list.
595 		 * We want the releasing of the object storage to
596 		 * be done without holding the session lock.
597 		 */
598 		(void) pthread_mutex_unlock(&sp->session_mutex);
599 	}
600 
601 	soft_delete_object_cleanup(objp, force);
602 }
603 
604 
605 /*
606  * Delete all the objects in a session. The caller holds the lock
607  * on the session.
608  */
609 void
soft_delete_all_objects_in_session(soft_session_t * sp,boolean_t force)610 soft_delete_all_objects_in_session(soft_session_t *sp, boolean_t force)
611 {
612 	soft_object_t *objp = sp->object_list;
613 	soft_object_t *objp1;
614 
615 	/* Delete all the objects in the session. */
616 	while (objp) {
617 		objp1 = objp->next;
618 
619 		/*
620 		 * Delete an object by calling soft_delete_object()
621 		 * with a TRUE boolean argument indicating that
622 		 * the caller holds the lock on the session.
623 		 */
624 		soft_delete_object(sp, objp, force, B_TRUE);
625 
626 		objp = objp1;
627 	}
628 }
629 
630 static CK_RV
add_to_search_result(soft_object_t * obj,find_context_t * fcontext,CK_ULONG * num_result_alloc)631 add_to_search_result(soft_object_t *obj, find_context_t *fcontext,
632     CK_ULONG *num_result_alloc)
633 {
634 	/*
635 	 * allocate space for storing results if the currently
636 	 * allocated space is not enough
637 	 */
638 	if (*num_result_alloc <= fcontext->num_results) {
639 		fcontext->objs_found = realloc(fcontext->objs_found,
640 		    sizeof (soft_object_t *) * (*num_result_alloc + BUFSIZ));
641 		if (fcontext->objs_found == NULL) {
642 			return (CKR_HOST_MEMORY);
643 		}
644 		*num_result_alloc += BUFSIZ;
645 	}
646 
647 	(fcontext->objs_found)[(fcontext->num_results)++] = obj;
648 	return (CKR_OK);
649 }
650 
651 static CK_RV
search_for_objects(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,find_context_t * fcontext)652 search_for_objects(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
653     find_context_t *fcontext)
654 {
655 	soft_session_t *session_p;
656 	soft_object_t *obj;
657 	CK_OBJECT_CLASS pclasses[6]; /* classes attrs possibly exist */
658 	CK_ULONG num_pclasses;	/* number of possible classes */
659 	CK_ULONG num_result_alloc = 0; /* spaces allocated for results */
660 	CK_RV rv = CKR_OK;
661 	/* whether CKA_TOKEN flag specified or not */
662 	boolean_t token_specified = B_FALSE;
663 	/* value of CKA_TOKEN flag, if specified */
664 	boolean_t token_flag_val = B_FALSE;
665 	CK_ULONG i;
666 
667 	if (ulCount > 0) {
668 		/* there are some search requirement */
669 		soft_process_find_attr(pclasses, &num_pclasses,
670 		    pTemplate, ulCount);
671 	}
672 
673 	for (i = 0; i < ulCount; i++) {
674 		if (pTemplate[i].type == CKA_PRIVATE) {
675 			(void) pthread_mutex_lock(&soft_giant_mutex);
676 			if (soft_slot.userpin_change_needed) {
677 				(void) pthread_mutex_unlock(&soft_giant_mutex);
678 				return (CKR_PIN_EXPIRED);
679 			}
680 			(void) pthread_mutex_unlock(&soft_giant_mutex);
681 		}
682 	}
683 
684 	/*
685 	 * look through template and see if it explicitly specifies
686 	 * whether we need to look for token objects or not
687 	 */
688 	for (i = 0; i < ulCount; i++) {
689 		if (pTemplate[i].type == CKA_TOKEN) {
690 			token_specified = B_TRUE;
691 			token_flag_val = *((CK_BBOOL *)pTemplate[i].pValue);
692 			break;
693 		}
694 	}
695 
696 	/*
697 	 * Need go through token objects if it explicitly say so, or
698 	 * it is not mentioned in the template.  And this will ONLY be
699 	 * done when the keystore exists. Otherwise, we will skip re-loading
700 	 * the token objects.
701 	 *
702 	 * If a session has not logged into the token, only public
703 	 * objects, if any, will be searched.  If a session is logged
704 	 * into the token, all public and private objects in the keystore
705 	 * are searched.
706 	 */
707 	if (((token_flag_val) || (!token_specified)) &&
708 	    soft_keystore_status(KEYSTORE_INITIALIZED)) {
709 		/* acquire token session lock */
710 		(void) pthread_mutex_lock(&soft_slot.slot_mutex);
711 		rv = refresh_token_objects();
712 		if (rv != CKR_OK) {
713 			(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
714 			return (rv);
715 		}
716 		obj = soft_slot.token_object_list;
717 		while (obj) {
718 			(void) pthread_mutex_lock(&obj->object_mutex);
719 			if (((token_specified) && (ulCount > 1)) ||
720 			    ((!token_specified) && (ulCount > 0))) {
721 				if (soft_find_match_attrs(obj, pclasses,
722 				    num_pclasses, pTemplate, ulCount)) {
723 					rv = add_to_search_result(
724 					    obj, fcontext, &num_result_alloc);
725 				}
726 			} else {
727 				/* no search criteria, just record the object */
728 				rv = add_to_search_result(obj, fcontext,
729 				    &num_result_alloc);
730 			}
731 			(void) pthread_mutex_unlock(&obj->object_mutex);
732 			if (rv != CKR_OK) {
733 				(void) pthread_mutex_unlock
734 				    (&soft_slot.slot_mutex);
735 				return (rv);
736 			}
737 			obj = obj->next;
738 		}
739 		(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
740 	}
741 
742 	if (token_flag_val) {
743 		/* no need to look through session objects */
744 		return (rv);
745 	}
746 
747 	/* Acquire the global session list lock */
748 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
749 
750 	/*
751 	 * Go through all objects in each session.
752 	 * Acquire individual session lock for the session
753 	 * we are searching.
754 	 */
755 	session_p = soft_session_list;
756 	while (session_p) {
757 		(void) pthread_mutex_lock(&session_p->session_mutex);
758 
759 		obj = session_p->object_list;
760 		while (obj) {
761 			(void) pthread_mutex_lock(&obj->object_mutex);
762 			if (ulCount > 0) {
763 				if (soft_find_match_attrs(obj, pclasses,
764 				    num_pclasses, pTemplate, ulCount)) {
765 					rv = add_to_search_result(
766 					    obj, fcontext, &num_result_alloc);
767 				}
768 			} else {
769 				/* no search criteria, just record the object */
770 				rv = add_to_search_result(obj, fcontext,
771 				    &num_result_alloc);
772 			}
773 			(void) pthread_mutex_unlock(&obj->object_mutex);
774 			if (rv != CKR_OK) {
775 				(void) pthread_mutex_unlock(
776 				    &session_p->session_mutex);
777 				goto cleanup;
778 			}
779 			obj = obj->next;
780 		}
781 		(void) pthread_mutex_unlock(&session_p->session_mutex);
782 		session_p = session_p->next;
783 	}
784 
785 cleanup:
786 	/* Release the global session list lock */
787 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
788 	return (rv);
789 }
790 
791 /*
792  * Initialize the context for C_FindObjects() calls
793  */
794 CK_RV
soft_find_objects_init(soft_session_t * sp,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)795 soft_find_objects_init(soft_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
796     CK_ULONG ulCount)
797 {
798 
799 	CK_RV rv = CKR_OK;
800 	CK_OBJECT_CLASS class; /* for soft_validate_attr(). Value unused */
801 	find_context_t *fcontext;
802 
803 	if (ulCount) {
804 		rv = soft_validate_attr(pTemplate, ulCount, &class);
805 		/* Make sure all attributes in template are valid */
806 		if (rv != CKR_OK) {
807 			return (rv);
808 		}
809 	}
810 
811 
812 	/* prepare the find context */
813 	fcontext = calloc(1, sizeof (find_context_t));
814 	if (fcontext == NULL) {
815 		return (CKR_HOST_MEMORY);
816 	}
817 
818 	rv = search_for_objects(pTemplate, ulCount, fcontext);
819 	if (rv != CKR_OK) {
820 		free(fcontext);
821 		return (rv);
822 	}
823 
824 	/* store the find_context in the session */
825 	sp->find_objects.context = (CK_VOID_PTR)fcontext;
826 
827 	return (rv);
828 }
829 
830 void
soft_find_objects_final(soft_session_t * sp)831 soft_find_objects_final(soft_session_t *sp)
832 {
833 	find_context_t *fcontext;
834 
835 	fcontext = sp->find_objects.context;
836 	sp->find_objects.context = NULL;
837 	sp->find_objects.flags = 0;
838 	if (fcontext->objs_found != NULL) {
839 		free(fcontext->objs_found);
840 	}
841 
842 	free(fcontext);
843 }
844 
845 void
soft_find_objects(soft_session_t * sp,CK_OBJECT_HANDLE * obj_found,CK_ULONG max_obj_requested,CK_ULONG * found_obj_count)846 soft_find_objects(soft_session_t *sp, CK_OBJECT_HANDLE *obj_found,
847     CK_ULONG max_obj_requested, CK_ULONG *found_obj_count)
848 {
849 	find_context_t *fcontext;
850 	CK_ULONG num_obj_found = 0;
851 	CK_ULONG i;
852 	soft_object_t *obj;
853 
854 	fcontext = sp->find_objects.context;
855 
856 	for (i = fcontext->next_result_index;
857 	    ((num_obj_found < max_obj_requested) &&
858 	    (i < fcontext->num_results));
859 	    i++) {
860 		obj = fcontext->objs_found[i];
861 		if (obj != NULL) {
862 			(void) pthread_mutex_lock(&obj->object_mutex);
863 			/* a sanity check to make sure the obj is still valid */
864 			if (obj->magic_marker == SOFTTOKEN_OBJECT_MAGIC) {
865 				obj_found[num_obj_found] = obj->handle;
866 				num_obj_found++;
867 			}
868 			(void) pthread_mutex_unlock(&obj->object_mutex);
869 		}
870 	}
871 	fcontext->next_result_index = i;
872 	*found_obj_count = num_obj_found;
873 }
874 
875 /*
876  * Below are the token object related functions
877  */
878 void
soft_add_token_object_to_slot(soft_object_t * objp)879 soft_add_token_object_to_slot(soft_object_t *objp)
880 {
881 
882 	(void) pthread_mutex_lock(&soft_slot.slot_mutex);
883 
884 	/* Insert the new object in front of slot's token object list. */
885 	if (soft_slot.token_object_list == NULL) {
886 		soft_slot.token_object_list = objp;
887 		objp->next = NULL;
888 		objp->prev = NULL;
889 	} else {
890 		soft_slot.token_object_list->prev = objp;
891 		objp->next = soft_slot.token_object_list;
892 		objp->prev = NULL;
893 		soft_slot.token_object_list = objp;
894 	}
895 
896 	(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
897 
898 }
899 
900 void
soft_remove_token_object_from_slot(soft_object_t * objp,boolean_t lock_held)901 soft_remove_token_object_from_slot(soft_object_t *objp, boolean_t lock_held)
902 {
903 
904 	if (!lock_held)
905 		(void) pthread_mutex_lock(&soft_slot.slot_mutex);
906 
907 	/*
908 	 * Remove the object from the slot's token object list.
909 	 */
910 	if (soft_slot.token_object_list == objp) {
911 		/* Object is the first one in the list. */
912 		if (objp->next) {
913 			soft_slot.token_object_list = objp->next;
914 			objp->next->prev = NULL;
915 		} else {
916 			/* Object is the only one in the list. */
917 			soft_slot.token_object_list = NULL;
918 		}
919 	} else {
920 		/* Object is not the first one in the list. */
921 		if (objp->next) {
922 			/* Object is in the middle of the list. */
923 			objp->prev->next = objp->next;
924 			objp->next->prev = objp->prev;
925 		} else {
926 			/* Object is the last one in the list. */
927 			objp->prev->next = NULL;
928 		}
929 	}
930 
931 	if (!lock_held)
932 		(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
933 }
934 
935 void
soft_delete_token_object(soft_object_t * objp,boolean_t persistent,boolean_t lock_held)936 soft_delete_token_object(soft_object_t *objp, boolean_t persistent,
937     boolean_t lock_held)
938 {
939 
940 	if (!lock_held)
941 		(void) pthread_mutex_lock(&soft_slot.slot_mutex);
942 	if (persistent)
943 		/* Delete the object from the keystore. */
944 		(void) soft_keystore_del_obj(&objp->ks_handle, B_FALSE);
945 
946 	/* Remove the object from the slot's token object list. */
947 	soft_remove_token_object_from_slot(objp, B_TRUE);
948 	if (!lock_held)
949 		(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
950 
951 	soft_delete_object_cleanup(objp, B_FALSE);
952 }
953 
954 void
soft_delete_all_in_core_token_objects(token_obj_type_t type)955 soft_delete_all_in_core_token_objects(token_obj_type_t type)
956 {
957 
958 	soft_object_t *objp;
959 	soft_object_t *objp1;
960 
961 	(void) pthread_mutex_lock(&soft_slot.slot_mutex);
962 	objp = soft_slot.token_object_list;
963 
964 	switch (type) {
965 	case PRIVATE_TOKEN:
966 		while (objp) {
967 			objp1 = objp->next;
968 			if (objp->object_type == TOKEN_PRIVATE) {
969 				soft_delete_token_object(objp, B_FALSE, B_TRUE);
970 			}
971 			objp = objp1;
972 		}
973 		break;
974 
975 	case PUBLIC_TOKEN:
976 		while (objp) {
977 			objp1 = objp->next;
978 			if (objp->object_type == TOKEN_PUBLIC) {
979 				soft_delete_token_object(objp, B_FALSE, B_TRUE);
980 			}
981 			objp = objp1;
982 		}
983 		break;
984 
985 	case ALL_TOKEN:
986 		while (objp) {
987 			objp1 = objp->next;
988 			soft_delete_token_object(objp, B_FALSE, B_TRUE);
989 			objp = objp1;
990 		}
991 		break;
992 	}
993 
994 	(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
995 
996 }
997 
998 /*
999  * Mark all the token objects in the global list to be valid.
1000  */
1001 void
soft_validate_token_objects(boolean_t validate)1002 soft_validate_token_objects(boolean_t validate)
1003 {
1004 
1005 	soft_object_t *objp;
1006 
1007 	(void) pthread_mutex_lock(&soft_slot.slot_mutex);
1008 
1009 	objp = soft_slot.token_object_list;
1010 
1011 	while (objp) {
1012 		if (validate)
1013 			objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
1014 		else
1015 			objp->magic_marker = 0;
1016 
1017 		objp = objp->next;
1018 	}
1019 
1020 	(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
1021 
1022 }
1023 
1024 /*
1025  * Verify user's write access rule to the token object.
1026  */
1027 CK_RV
soft_object_write_access_check(soft_session_t * sp,soft_object_t * objp)1028 soft_object_write_access_check(soft_session_t *sp, soft_object_t *objp)
1029 {
1030 
1031 	/*
1032 	 * This function is called by C_CreateObject, C_CopyObject,
1033 	 * C_DestroyObject, C_SetAttributeValue, C_GenerateKey,
1034 	 * C_GenerateKeyPairs, C_DeriveKey. All of them will write
1035 	 * the token object to the keystore.
1036 	 */
1037 	(void) pthread_mutex_lock(&soft_giant_mutex);
1038 	if (!soft_slot.authenticated) {
1039 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1040 		/* User is not logged in */
1041 		if (sp->flags & CKF_RW_SESSION) {
1042 			/*
1043 			 * For R/W Public Session:
1044 			 * we allow write access to public session or token
1045 			 * object, but not for private token/session object.
1046 			 */
1047 			if ((objp->object_type == TOKEN_PRIVATE) ||
1048 			    (objp->object_type == SESSION_PRIVATE)) {
1049 				return (CKR_USER_NOT_LOGGED_IN);
1050 			}
1051 		} else {
1052 			/*
1053 			 * For R/O Public Session:
1054 			 * we allow write access to public session object.
1055 			 */
1056 			if (objp->object_type != SESSION_PUBLIC)
1057 				return (CKR_SESSION_READ_ONLY);
1058 		}
1059 	} else {
1060 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1061 		/* User is logged in */
1062 		if (!(sp->flags & CKF_RW_SESSION)) {
1063 			/*
1064 			 * For R/O User Function Session:
1065 			 * we allow write access to public or private
1066 			 * session object, but not for public or private
1067 			 * token object.
1068 			 */
1069 			if ((objp->object_type == TOKEN_PUBLIC) ||
1070 			    (objp->object_type == TOKEN_PRIVATE)) {
1071 				return (CKR_SESSION_READ_ONLY);
1072 			}
1073 		}
1074 	}
1075 
1076 	return (CKR_OK);
1077 }
1078 
1079 /*
1080  * Verify if user is required to setpin when accessing the
1081  * private token/session object.
1082  */
1083 CK_RV
soft_pin_expired_check(soft_object_t * objp)1084 soft_pin_expired_check(soft_object_t *objp)
1085 {
1086 
1087 	/*
1088 	 * This function is called by C_CreateObject, C_CopyObject,
1089 	 * C_DestroyObject, C_GenerateKey,
1090 	 * C_GenerateKeyPairs, C_DeriveKey.
1091 	 * All of them will return CKR_PIN_EXPIRED if the
1092 	 * "userpin_change_needed" is set.
1093 	 *
1094 	 * The following functions will not be necessary to call
1095 	 * this routine even though CKR_PIN_EXPIRED is one of the
1096 	 * valid error code they might return. These functions are:
1097 	 * C_EncryptInit, C_DecryptInit, C_DigestInit, C_SignInit,
1098 	 * C_SignRecoverInit, C_VerifyInit, C_VerifyRecoverInit.
1099 	 * This is because they will not get the object handle
1100 	 * before the above functions are called.
1101 	 */
1102 
1103 	(void) pthread_mutex_lock(&soft_giant_mutex);
1104 	if (soft_slot.userpin_change_needed) {
1105 		/*
1106 		 * Access private token/session object but user's
1107 		 * PIN is expired or never set.
1108 		 */
1109 		if ((objp->object_type == TOKEN_PRIVATE) ||
1110 		    (objp->object_type == SESSION_PRIVATE)) {
1111 			(void) pthread_mutex_unlock(&soft_giant_mutex);
1112 			return (CKR_PIN_EXPIRED);
1113 		}
1114 	}
1115 
1116 	(void) pthread_mutex_unlock(&soft_giant_mutex);
1117 	return (CKR_OK);
1118 }
1119 
1120 /*
1121  * Copy the selected fields from new token object to old
1122  * token object.
1123  */
1124 CK_RV
soft_copy_to_old_object(soft_object_t * new,soft_object_t * old)1125 soft_copy_to_old_object(soft_object_t *new, soft_object_t *old)
1126 {
1127 
1128 	CK_RV rv = CKR_OK;
1129 	CK_ATTRIBUTE_INFO_PTR attrp;
1130 
1131 	old->class = new->class;
1132 	old->bool_attr_mask = new->bool_attr_mask;
1133 	soft_cleanup_extra_attr(old);
1134 	attrp = new->extra_attrlistp;
1135 	while (attrp) {
1136 		rv = soft_copy_extra_attr(attrp, old);
1137 		if (rv != CKR_OK) {
1138 			soft_cleanup_extra_attr(old);
1139 			return (rv);
1140 		}
1141 		attrp = attrp->next;
1142 	}
1143 
1144 	/* Done with copying all information that can be modified */
1145 	return (CKR_OK);
1146 }
1147 
1148 /*
1149  * Update an existing object with new data from keystore.
1150  */
1151 CK_RV
soft_update_object(ks_obj_t * ks_obj,soft_object_t * old_obj)1152 soft_update_object(ks_obj_t *ks_obj, soft_object_t *old_obj)
1153 {
1154 
1155 	soft_object_t *new_object;
1156 	CK_RV rv;
1157 
1158 	new_object = calloc(1, sizeof (soft_object_t));
1159 	if (new_object == NULL)
1160 		return (CKR_HOST_MEMORY);
1161 
1162 	rv = soft_keystore_unpack_obj(new_object, ks_obj);
1163 	if (rv != CKR_OK) {
1164 		soft_cleanup_object(new_object);
1165 		free(new_object);
1166 		return (rv);
1167 	}
1168 	rv = soft_copy_to_old_object(new_object, old_obj);
1169 
1170 	soft_cleanup_object(new_object);
1171 	free(new_object);
1172 	return (CKR_OK);
1173 }
1174 
1175 
1176 CK_RV
soft_keystore_load_latest_object(soft_object_t * old_obj)1177 soft_keystore_load_latest_object(soft_object_t *old_obj)
1178 {
1179 
1180 	uint_t version;
1181 	ks_obj_t *ks_obj = NULL;
1182 	CK_RV rv = CKR_OK;
1183 
1184 	/*
1185 	 * Get the current version number from the keystore for
1186 	 * the specified token object.
1187 	 */
1188 	if (soft_keystore_get_object_version(&old_obj->ks_handle, &version,
1189 	    B_FALSE) == 1)
1190 		return (CKR_FUNCTION_FAILED);
1191 
1192 	/*
1193 	 * If the keystore version is newer than the in-core version,
1194 	 * re-read the token object from the keystore.
1195 	 */
1196 	if (old_obj->version != version) {
1197 		rv = soft_keystore_get_single_obj(&old_obj->ks_handle,
1198 		    &ks_obj, B_FALSE);
1199 		if (rv != CKR_OK)
1200 			return (rv);
1201 		old_obj->version = version;
1202 
1203 		/*
1204 		 * Update an existing object with new data from keystore.
1205 		 */
1206 		rv = soft_update_object(ks_obj, old_obj);
1207 		free(ks_obj->buf);
1208 		free(ks_obj);
1209 	}
1210 
1211 	return (rv);
1212 }
1213 
1214 /*
1215  * Insert an object into a list of soft_object_t objects.  It is assumed
1216  * that the object to be inserted doesn't previously belong to any list
1217  */
1218 static void
insert_into_list(soft_object_t ** list,soft_object_t ** end_of_list,soft_object_t * objp)1219 insert_into_list(soft_object_t **list, soft_object_t **end_of_list,
1220     soft_object_t *objp)
1221 {
1222 	if (*list == NULL) {
1223 		*list = objp;
1224 		objp->next = NULL;
1225 		objp->prev = NULL;
1226 		*end_of_list = objp;
1227 	} else {
1228 		(*list)->prev = objp;
1229 		objp->next = *list;
1230 		objp->prev = NULL;
1231 		*list = objp;
1232 	}
1233 }
1234 
1235 /*
1236  * Move an object from an existing list into a new list of
1237  * soft_object_t objects.
1238  */
1239 static void
move_into_list(soft_object_t ** existing_list,soft_object_t ** new_list,soft_object_t ** end_of_list,soft_object_t * objp)1240 move_into_list(soft_object_t **existing_list, soft_object_t **new_list,
1241     soft_object_t **end_of_list, soft_object_t *objp)
1242 {
1243 
1244 	/* first, remove object from existing list */
1245 	if (objp == *existing_list) {
1246 		/* first item in list */
1247 		if (objp->next) {
1248 			*existing_list = objp->next;
1249 			objp->next->prev = NULL;
1250 		} else {
1251 			*existing_list = NULL;
1252 		}
1253 	} else {
1254 		if (objp->next) {
1255 			objp->prev->next = objp->next;
1256 			objp->next->prev = objp->prev;
1257 		} else {
1258 			objp->prev->next = NULL;
1259 		}
1260 	}
1261 
1262 	/* then, add into new list */
1263 	insert_into_list(new_list, end_of_list, objp);
1264 }
1265 
1266 /*
1267  * Insert "new_list" into "existing_list", new list will always be inserted
1268  * into the front of existing list
1269  */
1270 static void
insert_list_into_list(soft_object_t ** existing_list,soft_object_t * new_list,soft_object_t * end_new_list)1271 insert_list_into_list(soft_object_t **existing_list,
1272     soft_object_t *new_list, soft_object_t *end_new_list)
1273 {
1274 
1275 	if (new_list == NULL) {
1276 		return;
1277 	}
1278 
1279 	if (*existing_list == NULL) {
1280 		*existing_list = new_list;
1281 	} else {
1282 		(*existing_list)->prev = end_new_list;
1283 		end_new_list->next = *existing_list;
1284 		*existing_list = new_list;
1285 	}
1286 }
1287 
1288 static void
delete_all_objs_in_list(soft_object_t * list)1289 delete_all_objs_in_list(soft_object_t *list)
1290 {
1291 	soft_object_t *objp, *objp_next;
1292 
1293 	if (list == NULL) {
1294 		return;
1295 	}
1296 
1297 	objp = list;
1298 	while (objp) {
1299 		objp_next = objp->next;
1300 		soft_delete_object_cleanup(objp, B_FALSE);
1301 		objp = objp_next;
1302 	}
1303 }
1304 
1305 /*
1306  * Makes sure that the list of in-core token objects are up to date
1307  * with respect to the on disk keystore.  Other process/applications
1308  * might have modified the keystore since the objects are last loaded
1309  *
1310  * If there's any error from refreshing the token object list (eg: unable
1311  * to read, unable to unpack and object...etc), the in-core list
1312  * will be restored back to the state before the refresh.  An error
1313  * will be returned to indicate the failure.
1314  *
1315  * It is assumed that the caller holds the lock for the token slot
1316  */
1317 CK_RV
refresh_token_objects()1318 refresh_token_objects()
1319 {
1320 	uint_t on_disk_ks_version;
1321 	ks_obj_t *on_disk_list = NULL, *tmp_on_disk, *next_on_disk;
1322 	soft_object_t *in_core_obj, *tmp_incore_obj, *new_objp = NULL;
1323 	CK_RV rv = CKR_OK;
1324 
1325 	/* deleted in-core objects */
1326 	soft_object_t *del_objs_list = NULL;
1327 	soft_object_t *end_del_objs_list = NULL;
1328 
1329 	/* modified in-core objects */
1330 	soft_object_t *mod_objs_list = NULL;
1331 	soft_object_t *end_mod_objs_list = NULL;
1332 
1333 	/*
1334 	 * copy of modified in-core objects, in case we need
1335 	 * undo the change
1336 	 */
1337 	soft_object_t *copy_of_mod_objs_list = NULL;
1338 	soft_object_t *end_copy_of_mod_objs_list = NULL;
1339 
1340 	/* objects to be added to the in-core list */
1341 	soft_object_t *added_objs_list = NULL;
1342 	soft_object_t *end_added_objs_list = NULL;
1343 
1344 	if (soft_keystore_get_version(&on_disk_ks_version, B_FALSE) != 0) {
1345 		return (CKR_FUNCTION_FAILED);
1346 	}
1347 
1348 	(void) pthread_mutex_lock(&soft_giant_mutex);
1349 	if (on_disk_ks_version == soft_slot.ks_version) {
1350 		/* no change */
1351 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1352 		return (CKR_OK);
1353 	}
1354 
1355 	if (soft_slot.authenticated) {
1356 		/* get both public and private objects */
1357 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1358 		rv = soft_keystore_get_objs(ALL_TOKENOBJS, &on_disk_list,
1359 		    B_FALSE);
1360 	} else {
1361 		/* get both public objects only */
1362 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1363 		rv = soft_keystore_get_objs(PUB_TOKENOBJS, &on_disk_list,
1364 		    B_FALSE);
1365 	}
1366 	if (rv != CKR_OK) {
1367 		return (rv);
1368 	}
1369 
1370 	/*
1371 	 * The in-core tokens list will be updated as follows:
1372 	 *
1373 	 * Go through each item in the in-core tokens list.
1374 	 * Try to match the in-core object with one of the
1375 	 * objects from the on-disk list.  If a match is made,
1376 	 * check the version number, and update in-core object
1377 	 * as necessary.
1378 	 *
1379 	 * If there's no match between in-core object with on-disk
1380 	 * object, that means the object is deleted since
1381 	 * last loaded.  Will remove object from in-core list.
1382 	 *
1383 	 * When doing the matching of on-disk object list above,
1384 	 * Delete every matched on-disk object from the on-disk list
1385 	 * regardless the in-core object need to be deleted or not
1386 	 *
1387 	 * At the end of matching the in-core tokens list, if
1388 	 * any object is still left on the on-disk object list,
1389 	 * those are all new objects added since last load,
1390 	 * include all of them to the in-core list
1391 	 *
1392 	 * Since we need to be able to revert the in-core list
1393 	 * back to original state if there's any error with the refresh,
1394 	 * we need to do the following.
1395 	 * When an in-core object is "deleted", it is not immediately
1396 	 * deleted.  It is moved to the list of "deleted_objects".
1397 	 * When an in-core object is "modified", a copy of the
1398 	 * unmodified object is made.  After the object is modified,
1399 	 * it is temporarily moved to the "mod_objects" list
1400 	 * from the in-core list.
1401 	 * When the refresh is completed without any error,
1402 	 * the actual deleted objects and unmodified objects is deleted.
1403 	 */
1404 	in_core_obj = soft_slot.token_object_list;
1405 	while (in_core_obj) {
1406 		/* try to match object with on_disk_list */
1407 		ks_obj_t *ondisk_obj, *prev_ondisk_obj;
1408 		boolean_t found = B_FALSE;
1409 		soft_object_t *obj_copy;
1410 
1411 		ondisk_obj = on_disk_list;
1412 		prev_ondisk_obj = NULL;
1413 
1414 		/* larval object that has not been written to disk */
1415 		if (in_core_obj->ks_handle.name[0] == '\0') {
1416 			in_core_obj = in_core_obj->next;
1417 			continue;
1418 		}
1419 
1420 		while ((!found) && (ondisk_obj != NULL)) {
1421 
1422 			if (strcmp((char *)((ondisk_obj->ks_handle).name),
1423 			    (char *)((in_core_obj->ks_handle).name)) == 0) {
1424 
1425 				/* found a match */
1426 				found = B_TRUE;
1427 
1428 				/* update in-core obj if necessary */
1429 				if (ondisk_obj->obj_version !=
1430 				    in_core_obj->version) {
1431 					/* make a copy of before updating */
1432 					rv = soft_copy_object(in_core_obj,
1433 					    &obj_copy, SOFT_COPY_OBJ_ORIG_SH,
1434 					    NULL);
1435 					if (rv != CKR_OK) {
1436 						goto cleanup;
1437 					}
1438 					insert_into_list(
1439 					    &copy_of_mod_objs_list,
1440 					    &end_copy_of_mod_objs_list,
1441 					    obj_copy);
1442 
1443 					rv = soft_update_object(ondisk_obj,
1444 					    in_core_obj);
1445 					if (rv != CKR_OK) {
1446 						goto cleanup;
1447 					}
1448 					move_into_list(
1449 					    &(soft_slot.token_object_list),
1450 					    &mod_objs_list, &end_mod_objs_list,
1451 					    in_core_obj);
1452 				}
1453 
1454 				/* remove processed obj from on disk list */
1455 				if (ondisk_obj == on_disk_list) {
1456 					/* first item */
1457 					on_disk_list = ondisk_obj->next;
1458 				} else {
1459 					prev_ondisk_obj->next =
1460 					    ondisk_obj->next;
1461 				}
1462 				free(ondisk_obj->buf);
1463 				free(ondisk_obj);
1464 			} else {
1465 				prev_ondisk_obj = ondisk_obj;
1466 				ondisk_obj = ondisk_obj->next;
1467 			}
1468 		}
1469 
1470 		if (!found) {
1471 			tmp_incore_obj = in_core_obj->next;
1472 			move_into_list(&(soft_slot.token_object_list),
1473 			    &del_objs_list, &end_del_objs_list, in_core_obj);
1474 			in_core_obj = tmp_incore_obj;
1475 		} else {
1476 			in_core_obj = in_core_obj->next;
1477 		}
1478 	}
1479 
1480 	/*
1481 	 * At this point, if there's still anything on the on_disk_list, they
1482 	 * are all newly added objects since in-core list last loaded.
1483 	 * include all of them into the in-core list
1484 	 */
1485 	next_on_disk = on_disk_list;
1486 	while (next_on_disk) {
1487 		new_objp = calloc(1, sizeof (soft_object_t));
1488 		if (new_objp == NULL) {
1489 			rv = CKR_HOST_MEMORY;
1490 			goto cleanup;
1491 		}
1492 
1493 		/* Convert the keystore format to memory format */
1494 		rv = soft_keystore_unpack_obj(new_objp, next_on_disk);
1495 		if (rv != CKR_OK) {
1496 			soft_cleanup_object(new_objp);
1497 			free(new_objp);
1498 			goto cleanup;
1499 		}
1500 
1501 		insert_into_list(&added_objs_list, &end_added_objs_list,
1502 		    new_objp);
1503 
1504 		/* free the on_disk object */
1505 		tmp_on_disk = next_on_disk;
1506 		next_on_disk = tmp_on_disk->next;
1507 		free(tmp_on_disk->buf);
1508 		free(tmp_on_disk);
1509 	}
1510 
1511 	if (rv == CKR_OK) {
1512 		(void) pthread_mutex_lock(&soft_giant_mutex);
1513 		soft_slot.ks_version = on_disk_ks_version;
1514 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1515 
1516 		/* add the new objects into in-core list */
1517 		insert_list_into_list(&(soft_slot.token_object_list),
1518 		    added_objs_list, end_added_objs_list);
1519 
1520 		/* add modified objects back into the in-core list */
1521 		insert_list_into_list(&(soft_slot.token_object_list),
1522 		    mod_objs_list, end_mod_objs_list);
1523 
1524 		/* actually remove deleted objs, and copy of modified objs */
1525 		delete_all_objs_in_list(copy_of_mod_objs_list);
1526 		delete_all_objs_in_list(del_objs_list);
1527 	}
1528 
1529 	return (rv);
1530 
1531 cleanup:
1532 	next_on_disk = on_disk_list;
1533 	while (next_on_disk) {
1534 		tmp_on_disk = next_on_disk;
1535 		next_on_disk = tmp_on_disk->next;
1536 		free(tmp_on_disk->buf);
1537 		free(tmp_on_disk);
1538 	}
1539 
1540 	/*
1541 	 * restore the in-core list back to the original state by adding
1542 	 * copy of original objects and deleted objects back to list
1543 	 */
1544 	insert_list_into_list(&(soft_slot.token_object_list),
1545 	    del_objs_list, end_del_objs_list);
1546 	insert_list_into_list(&(soft_slot.token_object_list),
1547 	    copy_of_mod_objs_list, end_copy_of_mod_objs_list);
1548 
1549 	/*
1550 	 * remove the modified objects, and newly objects list
1551 	 */
1552 	delete_all_objs_in_list(mod_objs_list);
1553 	delete_all_objs_in_list(added_objs_list);
1554 	return (rv);
1555 }
1556 
1557 CK_RV
dup_bigint_attr(biginteger_t * bi,CK_BYTE * buf,CK_ULONG buflen)1558 dup_bigint_attr(biginteger_t *bi, CK_BYTE *buf, CK_ULONG buflen)
1559 {
1560 	bi->big_value_len = buflen;
1561 	if ((bi->big_value = malloc(buflen)) == NULL) {
1562 		return (CKR_HOST_MEMORY);
1563 	}
1564 	(void) memcpy(bi->big_value, buf, buflen);
1565 	return (CKR_OK);
1566 }
1567