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