/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/cryptoki.h>
#include "softGlobal.h"
#include "softObject.h"
#include "softSession.h"
#include "softKeystore.h"
#include "softKeystoreUtil.h"
/*
* Add an object to the session's object list.
*
* This function will acquire the lock on the session, and release
* that lock after adding the object to the session's object list.
*/
void
{
/* Acquire the session lock. */
/* Insert the new object in front of session's object list. */
} else {
}
/* Release the session lock. */
}
/*
* Clean up and release the storage allocated to the object.
*
* The function is called either with the object lock being held
* (by caller soft_delete_object()), or there is no object lock
* yet (by soft_build_XXX_object() during creating an object).
*/
void
{
/*
* Free the storage allocated to big integer attributes.
*/
/*
* Free the storage allocated to the extra attribute list.
*/
/*
* Free the storage allocated to certificate attributes.
*/
}
/*
* Create a new object. Copy the attributes that can be modified
* (in the boolean attribute mask field and extra attribute list)
* from the old object to the new object.
*
* The caller of this function holds the lock on the old object.
*/
{
/* Allocate new object. */
return (CKR_HOST_MEMORY);
while (attrp) {
/*
* Copy the attribute_info struct from the old
* object to a new attribute_info struct, and add
* that new struct to the extra attribute list
* of the new object.
*/
return (rv);
}
}
*new_object = new_objp;
if (object_func == SOFT_SET_ATTR_VALUE) {
/* done with copying all information that can be modified */
return (CKR_OK);
}
/*
* Copy the rest of the object.
* Certain fields that are not appropriate for coping will be
* initialized.
*/
switch (object_func) {
case SOFT_COPY_OBJ_ORIG_SH:
break;
case SOFT_COPY_OBJECT:
/*
* Save the session handle of the C_CopyObject function
* in the new copy of the session object.
*/
break;
}
/* copy key related information */
case CKO_PUBLIC_KEY:
break;
case CKO_PRIVATE_KEY:
break;
case CKO_SECRET_KEY:
break;
case CKO_DOMAIN_PARAMETERS:
break;
case CKO_CERTIFICATE:
break;
default:
/* should never be this case */
break;
}
/*
* don't need to cleanup the memory from failure of copying
* any key related stuff. Each individual function for
* copying key attr will free the memory if it fails
*/
}
return (rv);
}
/*
* Copy the attributes (in the boolean attribute mask field and
* extra attribute list) from the new object back to the original
* object. Also, clean up and release all the storage in the extra
* attribute list of the original object.
*
* The caller of this function holds the lock on the old object.
*/
void
{
}
/*
* Create a new object struct, and add it to the session's object list.
*/
{
return (CKR_HOST_MEMORY);
}
/*
* Validate attribute template and fill in the attributes
* in the soft_object_t.
*/
goto fail_cleanup1;
}
goto fail_cleanup2;
}
goto fail_cleanup2;
}
/* Initialize the rest of stuffs in soft_object_t. */
new_objp->obj_refcnt = 0;
new_objp->obj_delete_sync = 0;
/* Write the new token object to the keystore */
if (IS_TOKEN_OBJECT(new_objp)) {
if (!soft_keystore_status(KEYSTORE_INITIALIZED)) {
goto fail_cleanup2;
}
goto fail_cleanup2;
}
/*
* Type casting the address of an object struct to
* an object handle.
*/
return (CKR_OK);
}
/* Add the new object to the session's object list. */
/* Type casting the address of an object struct to an object handle. */
return (CKR_OK);
/*
* When any error occurs after soft_build_object(), we will need to
* clean up the memory allocated by the soft_build_object().
*/
if (new_objp) {
/*
* The storage allocated inside of this object should have
* been cleaned up by the soft_build_object() if it failed.
* Therefore, we can safely free the object.
*/
}
return (rv);
}
/*
* Remove an object from the session's object list.
*
* The caller of this function holds the session lock.
*/
{
/*
* Remove the object from the session's object list.
*/
return (CKR_SESSION_HANDLE_INVALID);
}
return (CKR_OBJECT_HANDLE_INVALID);
}
while (tmp_objp) {
break;
}
}
if (!found)
return (CKR_OBJECT_HANDLE_INVALID);
/* Object is the first one in the list. */
} else {
/* Object is the only one in the list. */
}
} else {
/* Object is not the first one in the list. */
/* Object is in the middle of the list. */
} else {
/* Object is the last one in the list. */
}
}
return (CKR_OK);
}
/*
* This function adds the to-be-freed session object to a linked list.
* When the number of objects queued in the linked list reaches the
* maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first
* object (FIFO) in the list.
*/
void
{
/* Add the newly deleted object at the end of the list */
} else {
}
/*
* Free the first object in the list only if
* the total count reaches maximum threshold.
*/
}
}
static void
{
/* Acquire the lock on the object. */
/*
* Make sure another thread hasn't freed the object.
*/
return;
}
/*
* The deletion of an object must be blocked when the object
* reference count is not zero. This means if any object related
* operation starts prior to the delete object operation gets in,
* the object deleting thread must wait for the non-deleting
* operation to be completed before it can proceed the delete
* operation.
*
* Unless we are being forced to shut everything down, this only
* happens if the libraries _fini() is running not of someone
* explicitly called C_Finalize().
*/
if (force)
objp->obj_refcnt = 0;
while (objp->obj_refcnt != 0) {
/*
* We set the OBJECT_REFCNT_WAITING flag before we put
* this deleting thread in a wait state, so other non-deleting
* operation thread will signal to wake it up only when
* the object reference count becomes zero and this flag
* is set.
*/
&objp->object_mutex);
}
/* Mark object as no longer valid. */
objp->magic_marker = 0;
/*
* Cleanup the contents of this object such as free all the
* storage allocated for this object.
*/
/* Reset OBJECT_IS_DELETING flag. */
/* Destroy the object lock */
/* Free the object itself */
if (IS_TOKEN_OBJECT(objp))
else
/*
* objects for its SSL Handshake.
*/
(void) object_delay_free(objp);
}
/*
* Delete an object:
* - Remove the object from the session's object list.
* Holding the lock on the session which the object was created at
* is needed to do this.
* - Release the storage allocated to the object.
*
* The boolean argument lock_held is used to indicate that whether
* the caller holds the session lock or not.
* - When called by soft_delete_all_objects_in_session() -- the
* lock_held = TRUE.
*
* When the caller does not hold the session lock, this function
* will acquire that lock in order to proceed, and also release
* that lock before returning to caller.
*/
void
{
/*
* Check to see if the caller holds the lock on the session.
* If not, we need to acquire that lock in order to proceed.
*/
if (!lock_held) {
/* Acquire the session lock. */
}
/* Remove the object from the session's object list first. */
if (!lock_held) {
}
return;
}
if (!lock_held) {
/*
* If the session lock is obtained by this function,
* then release that lock after removing the object
* from session's object list.
* We want the releasing of the object storage to
* be done without holding the session lock.
*/
}
}
/*
* Delete all the objects in a session. The caller holds the lock
* on the session.
*/
void
{
/* Delete all the objects in the session. */
while (objp) {
/*
* Delete an object by calling soft_delete_object()
* with a TRUE boolean argument indicating that
* the caller holds the lock on the session.
*/
}
}
static CK_RV
{
/*
* allocate space for storing results if the currently
* allocated space is not enough
*/
return (CKR_HOST_MEMORY);
}
*num_result_alloc += BUFSIZ;
}
return (CKR_OK);
}
static CK_RV
{
/* whether CKA_TOKEN flag specified or not */
/* value of CKA_TOKEN flag, if specified */
CK_ULONG i;
if (ulCount > 0) {
/* there are some search requirement */
}
for (i = 0; i < ulCount; i++) {
(void) pthread_mutex_lock(&soft_giant_mutex);
if (soft_slot.userpin_change_needed) {
(void) pthread_mutex_unlock(&soft_giant_mutex);
return (CKR_PIN_EXPIRED);
}
(void) pthread_mutex_unlock(&soft_giant_mutex);
}
}
/*
* look through template and see if it explicitly specifies
* whether we need to look for token objects or not
*/
for (i = 0; i < ulCount; i++) {
break;
}
}
/*
* Need go through token objects if it explicitly say so, or
* it is not mentioned in the template. And this will ONLY be
* done when the keystore exists. Otherwise, we will skip re-loading
* the token objects.
*
* If a session has not logged into the token, only public
* objects, if any, will be searched. If a session is logged
* into the token, all public and private objects in the keystore
* are searched.
*/
if (((token_flag_val) || (!token_specified)) &&
/* acquire token session lock */
rv = refresh_token_objects();
return (rv);
}
while (obj) {
((!token_specified) && (ulCount > 0))) {
}
} else {
/* no search criteria, just record the object */
}
(void) pthread_mutex_unlock
(&soft_slot.slot_mutex);
return (rv);
}
}
}
if (token_flag_val) {
/* no need to look through session objects */
return (rv);
}
/* Acquire the global session list lock */
(void) pthread_mutex_lock(&soft_sessionlist_mutex);
/*
* Go through all objects in each session.
* Acquire individual session lock for the session
* we are searching.
*/
while (session_p) {
while (obj) {
if (ulCount > 0) {
}
} else {
/* no search criteria, just record the object */
}
(void) pthread_mutex_unlock(
goto cleanup;
}
}
}
/* Release the global session list lock */
(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
return (rv);
}
/*
* Initialize the context for C_FindObjects() calls
*/
{
if (ulCount) {
/* Make sure all attributes in template are valid */
return (rv);
}
}
/* prepare the find context */
return (CKR_HOST_MEMORY);
}
return (rv);
}
/* store the find_context in the session */
return (rv);
}
void
{
}
}
void
{
CK_ULONG i;
for (i = fcontext->next_result_index;
((num_obj_found < max_obj_requested) &&
(i < fcontext->num_results));
i++) {
/* a sanity check to make sure the obj is still valid */
}
}
}
fcontext->next_result_index = i;
}
/*
* Below are the token object related functions
*/
void
{
/* Insert the new object in front of slot's token object list. */
} else {
}
}
void
{
if (!lock_held)
/*
* Remove the object from the slot's token object list.
*/
/* Object is the first one in the list. */
} else {
/* Object is the only one in the list. */
}
} else {
/* Object is not the first one in the list. */
/* Object is in the middle of the list. */
} else {
/* Object is the last one in the list. */
}
}
if (!lock_held)
}
void
{
if (!lock_held)
if (persistent)
/* Delete the object from the keystore. */
/* Remove the object from the slot's token object list. */
if (!lock_held)
}
void
{
switch (type) {
case PRIVATE_TOKEN:
while (objp) {
}
}
break;
case PUBLIC_TOKEN:
while (objp) {
}
}
break;
case ALL_TOKEN:
while (objp) {
}
break;
}
}
/*
* Mark all the token objects in the global list to be valid.
*/
void
{
while (objp) {
if (validate)
else
objp->magic_marker = 0;
}
}
/*
* Verify user's write access rule to the token object.
*/
{
/*
* This function is called by C_CreateObject, C_CopyObject,
* C_DestroyObject, C_SetAttributeValue, C_GenerateKey,
* C_GenerateKeyPairs, C_DeriveKey. All of them will write
* the token object to the keystore.
*/
(void) pthread_mutex_lock(&soft_giant_mutex);
if (!soft_slot.authenticated) {
(void) pthread_mutex_unlock(&soft_giant_mutex);
/* User is not logged in */
/*
* For R/W Public Session:
* we allow write access to public session or token
*/
return (CKR_USER_NOT_LOGGED_IN);
}
} else {
/*
* For R/O Public Session:
* we allow write access to public session object.
*/
return (CKR_SESSION_READ_ONLY);
}
} else {
(void) pthread_mutex_unlock(&soft_giant_mutex);
/* User is logged in */
/*
* For R/O User Function Session:
* we allow write access to public or private
* session object, but not for public or private
* token object.
*/
return (CKR_SESSION_READ_ONLY);
}
}
}
return (CKR_OK);
}
/*
* Verify if user is required to setpin when accessing the
*/
{
/*
* This function is called by C_CreateObject, C_CopyObject,
* C_DestroyObject, C_GenerateKey,
* C_GenerateKeyPairs, C_DeriveKey.
* All of them will return CKR_PIN_EXPIRED if the
* "userpin_change_needed" is set.
*
* The following functions will not be necessary to call
* this routine even though CKR_PIN_EXPIRED is one of the
* valid error code they might return. These functions are:
* C_EncryptInit, C_DecryptInit, C_DigestInit, C_SignInit,
* C_SignRecoverInit, C_VerifyInit, C_VerifyRecoverInit.
* This is because they will not get the object handle
* before the above functions are called.
*/
(void) pthread_mutex_lock(&soft_giant_mutex);
if (soft_slot.userpin_change_needed) {
/*
* PIN is expired or never set.
*/
(void) pthread_mutex_unlock(&soft_giant_mutex);
return (CKR_PIN_EXPIRED);
}
}
(void) pthread_mutex_unlock(&soft_giant_mutex);
return (CKR_OK);
}
/*
* Copy the selected fields from new token object to old
* token object.
*/
{
while (attrp) {
return (rv);
}
}
/* Done with copying all information that can be modified */
return (CKR_OK);
}
/*
* Update an existing object with new data from keystore.
*/
{
if (new_object == NULL)
return (CKR_HOST_MEMORY);
return (rv);
}
return (CKR_OK);
}
{
/*
* Get the current version number from the keystore for
* the specified token object.
*/
B_FALSE) == 1)
return (CKR_FUNCTION_FAILED);
/*
* If the keystore version is newer than the in-core version,
* re-read the token object from the keystore.
*/
return (rv);
/*
* Update an existing object with new data from keystore.
*/
}
return (rv);
}
/*
* Insert an object into a list of soft_object_t objects. It is assumed
* that the object to be inserted doesn't previously belong to any list
*/
static void
{
*end_of_list = objp;
} else {
}
}
/*
* Move an object from an existing list into a new list of
* soft_object_t objects.
*/
static void
{
/* first, remove object from existing list */
if (objp == *existing_list) {
/* first item in list */
} else {
*existing_list = NULL;
}
} else {
} else {
}
}
/* then, add into new list */
}
/*
* Insert "new_list" into "existing_list", new list will always be inserted
* into the front of existing list
*/
static void
{
return;
}
if (*existing_list == NULL) {
} else {
}
}
static void
{
return;
}
while (objp) {
}
}
/*
* Makes sure that the list of in-core token objects are up to date
* with respect to the on disk keystore. Other process/applications
* might have modified the keystore since the objects are last loaded
*
* If there's any error from refreshing the token object list (eg: unable
* to read, unable to unpack and object...etc), the in-core list
* will be restored back to the state before the refresh. An error
* will be returned to indicate the failure.
*
* It is assumed that the caller holds the lock for the token slot
*/
{
/* deleted in-core objects */
/* modified in-core objects */
/*
* copy of modified in-core objects, in case we need
* undo the change
*/
/* objects to be added to the in-core list */
return (CKR_FUNCTION_FAILED);
}
(void) pthread_mutex_lock(&soft_giant_mutex);
/* no change */
(void) pthread_mutex_unlock(&soft_giant_mutex);
return (CKR_OK);
}
if (soft_slot.authenticated) {
/* get both public and private objects */
(void) pthread_mutex_unlock(&soft_giant_mutex);
B_FALSE);
} else {
/* get both public objects only */
(void) pthread_mutex_unlock(&soft_giant_mutex);
B_FALSE);
}
return (rv);
}
/*
* The in-core tokens list will be updated as follows:
*
* Go through each item in the in-core tokens list.
* Try to match the in-core object with one of the
* objects from the on-disk list. If a match is made,
* check the version number, and update in-core object
* as necessary.
*
* If there's no match between in-core object with on-disk
* object, that means the object is deleted since
* last loaded. Will remove object from in-core list.
*
* When doing the matching of on-disk object list above,
* Delete every matched on-disk object from the on-disk list
* regardless the in-core object need to be deleted or not
*
* At the end of matching the in-core tokens list, if
* any object is still left on the on-disk object list,
* those are all new objects added since last load,
* include all of them to the in-core list
*
* Since we need to be able to revert the in-core list
* back to original state if there's any error with the refresh,
* we need to do the following.
* When an in-core object is "deleted", it is not immediately
* deleted. It is moved to the list of "deleted_objects".
* When an in-core object is "modified", a copy of the
* unmodified object is made. After the object is modified,
* it is temporarily moved to the "mod_objects" list
* from the in-core list.
* When the refresh is completed without any error,
* the actual deleted objects and unmodified objects is deleted.
*/
while (in_core_obj) {
/* try to match object with on_disk_list */
/* larval object that has not been written to disk */
continue;
}
/* found a match */
/* update in-core obj if necessary */
if (ondisk_obj->obj_version !=
in_core_obj->version) {
/* make a copy of before updating */
NULL);
goto cleanup;
}
obj_copy);
goto cleanup;
}
}
/* remove processed obj from on disk list */
if (ondisk_obj == on_disk_list) {
/* first item */
} else {
}
} else {
}
}
if (!found) {
} else {
}
}
/*
* At this point, if there's still anything on the on_disk_list, they
* are all newly added objects since in-core list last loaded.
* include all of them into the in-core list
*/
while (next_on_disk) {
goto cleanup;
}
/* Convert the keystore format to memory format */
goto cleanup;
}
new_objp);
/* free the on_disk object */
}
(void) pthread_mutex_lock(&soft_giant_mutex);
(void) pthread_mutex_unlock(&soft_giant_mutex);
/* add the new objects into in-core list */
/* add modified objects back into the in-core list */
/* actually remove deleted objs, and copy of modified objs */
}
return (rv);
while (next_on_disk) {
}
/*
* restore the in-core list back to the original state by adding
* copy of original objects and deleted objects back to list
*/
/*
* remove the modified objects, and newly objects list
*/
return (rv);
}
{
return (CKR_HOST_MEMORY);
}
return (CKR_OK);
}