/*
* 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
*/
/*
*/
/*
* Object Management Functions
* (as defined in PKCS#11 spec section 11.7)
*/
#include <strings.h>
#include "metaGlobal.h"
#include <stdio.h>
/*
* Argument related return codes. Will return to the caller immediately,
* and not try the operation on another slot.
*/
};
/*
* Return codes that are related to a specific slot.
* Will try to perform the operation in the next available slot.
* If all attempts failed, will return the error code from the first slot.
*
* This list is here for reference only, it is commented out because
* it doesn't need to be used by the code at this point.
*
* static CK_RV try_again_rv[] = {
* CKR_DEVICE_ERROR,
* CKR_DEVICE_MEMORY,
* CKR_DEVICE_REMOVED,
* CKR_FUNCTION_FAILED,
* CKR_GENERAL_ERROR,
* CKR_HOST_MEMORY,
* CKR_TEMPLATE_INCONSISTENT,
* CKR_ATTRIBUTE_READ_ONLY,
* CKR_ATTRIBUTE_VALUE_INVALID
* };
* static int num_try_again_rv = sizeof (try_again_rv) / sizeof (CK_RV);
*/
/*
* We should never get these return codes because
* MetaSlot is the one that actually created the
* sessions. When we get these errors in C_CreateObject,
* will try to create the object in the next available slot.
* If all attempts failed, will return CKR_FUNCTION_FAILED
* to the caller.
*/
};
/*
* This function is only used by the C_CreateObject and C_CopyObject.
*
* It is used to determine if the operation should be tried on another slot
* based on the return code
*/
static boolean_t
{
int i;
for (i = 0; i < num_stop_rv; i++) {
return (B_FALSE);
}
}
return (B_TRUE);
}
/*
* meta_CreateObject
*
*/
{
return (CKR_ARGUMENTS_BAD);
return (rv);
goto cleanup;
/*
* Create a clone of the object
*/
goto cleanup;
/*
* Set to true (token object) if template has CKA_TOKEN=true;
* otherwise, it is false (session object).
*/
/* Can't create token objects in a read-only session. */
goto cleanup;
}
/*
* Set to true (private object) if template has CKA_PRIVATE=true;
* otherwise, it is false (public object).
*/
/* Assume object is extractable unless template has otherwise */
&(object->isExtractable));
/*
* Set to true (sensitive object) if template has CKA_SENSITIVE=true;
* otherwise, it is false.
*/
&(object->isSensitive));
/*
* Check if this can be a FreeObject.
*
* For creating objects, this check is mostly for preventing
* non-keystore hardware from creating CKA_PRIVATE objects without
* logging in.
*/
NULL)) {
/*
* Make sure we are logged into the keystore if this is a
* private freetoken object.
*/
goto cleanup;
}
goto cleanup;
}
}
/*
* If this is a token object or a FreeToken then create it
* on the keystore slot.
*/
goto cleanup;
goto cleanup;
} else {
/*
* Create a clone of the object in the first available slot.
*
* If creating a clone in a specific slot failed, it will
* either stop and return the error to the user, or try
* again in the next available slot until it succeeds. The
* decision to stop or continue is made based on the return
* code.
*/
/*
* If this is a free token and we are on the keystore
* slot, bypass this because it was already created
*/
goto cleanup;
&hNewObject);
break;
goto cleanup;
/* save first rv for other errors */
if (slot_num == 0)
slot_session = NULL;
}
}
/* Allow FreeToken to activate onto token obj list */
slot_object = NULL;
slot_session = NULL;
} else {
/*
* return either first error code or
* CKR_FUNCTION_FAILED depending on the failure
*/
int i;
for (i = 0; i < num_other_rv; i++) {
goto cleanup;
}
}
/* need to return first rv */
goto cleanup;
}
/*
* always keep a copy of the template for C_CreateObject,
* so clones can be created on other slots if necessary.
* This is done even when the CKA_EXTRACTABLE=FALSE flag
* is set for the object. The supplied template is
* "owned" by metaslot. The application should not be
* penalized just because metaslot choose to try creating
* the object in a slot that's not capable of performing
* any future operation.
*/
CK_ULONG i;
for (i = 0; i < ulCount; i++) {
}
}
return (CKR_OK);
if (slot_object)
if (slot_session)
if (object)
return (rv);
}
/*
* meta_CopyObject
*
*/
{
CK_ULONG i;
return (CKR_ARGUMENTS_BAD);
if (phNewObject == NULL)
return (CKR_ARGUMENTS_BAD);
return (rv);
return (rv);
}
goto finish;
if (!found) {
else
}
/* Can't create token objects in a read-only session. */
(dst_object->isToken)) {
goto finish;
}
if (dst_object->isToken) {
/*
* if the dst object is a token object, and the source
* object is not, the source object needs to be extractable.
* Otherwise, the source object needs to reside in the
* token object slot
*/
if ((!src_object->isExtractable) &&
!= get_keystore_slotnum())) {
goto finish;
}
/* determine if dst is going to be private object or not */
if (!found) {
/* will be the same as the source object */
}
} else {
/* try create the obj in the same slot as the source obj */
}
goto finish;
goto finish;
goto finish;
if (dst_object->isToken) {
/*
* token obj can only be created in the
* token slot. No need to try anywhere else
*/
goto finish;
}
if ((!src_object->isExtractable) ||
(!metaslot_auto_key_migrate))) {
/* source object isn't clonable in another slot */
goto finish;
}
goto finish;
}
slot_session = NULL;
/* Try operation on other slots if the object is clonable */
/* already tried, don't need to try again */
continue;
}
goto finish;
}
goto finish;
break;
}
goto finish;
}
slot_session = NULL;
}
}
goto finish;
}
/* Keep a copy of the template for the future */
/*
* Don't allow attributes to change while
* we look at them.
*/
(void) pthread_rwlock_rdlock(
(void) pthread_rwlock_unlock(
goto finish;
for (i = 0; i < ulCount; i++) {
goto finish;
}
}
/* Allow FreeToken to activate onto token obj list */
} else {
/*
* return either first error code or
* CKR_FUNCTION_FAILED depending on the failure
*/
int j;
for (j = 0; j < num_other_rv; j++) {
goto finish;
}
}
/* need to return first rv */
goto finish;
}
if (dst_slot_object)
if (dst_object)
B_TRUE);
if (slot_session)
}
return (rv);
}
/*
* meta_DestroyObject
*
* This function destroys an object by first removing it from the
* list of valid objects for a given session (if session object) or
* the global token object list. And then, calling C_DestroyObject
* on all the slots on which we have created a clone of this object.
*/
{
return (rv);
return (rv);
}
/* Can't delete token objects from a read-only session. */
return (CKR_SESSION_READ_ONLY);
}
/* Remove object from list of valid meta_objects */
/*
* Actually call C_DestroyObject on all the slots on which we have
* created a clone of this object.
*/
return (rv);
}
/*
* meta_GetObjectSize
*
* NOTES:
* 1) Because the "size" is so poorly defined in the spec, we have deemed
* it useless and won't support it. This is especially true for the
* metaslot, because the multiple providers it uses may each interpret
* the size differently.
*/
/* ARGSUSED */
{
return (CKR_FUNCTION_NOT_SUPPORTED);
}
/*
* meta_GetAttributeValue
*
*/
{
return (CKR_ARGUMENTS_BAD);
return (rv);
return (rv);
}
}
return (rv);
}
/*
* meta_SetAttributeValue
*
* Call C_SetAttributeValue on all the clones. If the operation fails on
* all clones, return the failure.
*
* If the operation fails on some clones and not the others, delete all the
* clones that have failed the operation. If any of the deleted clone is the
* master clone, use one of the remaining clone as the master clone.
*
* If the operation is successful and the master template already exists,
* update the master template with new values.
*/
{
/* Keep track of which slot's SetAttributeValue failed */
return (CKR_ARGUMENTS_BAD);
return (rv);
return (rv);
}
goto finish;
}
/*
* object has no clone, just need to do the operation
* in the master clone slot
*/
ulCount);
}
goto finish;
}
/*
* object might have clones, need to do operation in all clones
*
* If the C_SetAttributeValue() call fails in a clone, the
* clone that failed the operation can not be deleted right
* away. The clone with the failed operation is recorded, and
* the deletion will happen in a separate loop.
*
* This is necessary because if ALL the clones failed
* C_SetAttributeVAlue(), then, the app's call to C_SetAttributeValue()
* is considered failed, and there shouldn't be any changes to the
* object, none of the clones should be deleted.
* On the other hand, if C_SetAttributeValue() fails in some clones
* and succeeds in other clones, the C_SetAttributeValue() operation
* is considered successful, and those clones that failed the
* operation is deleted.
*/
if (clone_failed_op == NULL) {
goto finish;
}
num_clones++;
goto finish;
}
ulCount);
}
}
}
}
if (num_clones_failed == num_clones) {
/* all operations failed */
goto finish;
}
if (num_clones_failed > 0) {
/*
* C_SetAttributeValue in some of the clones failed.
* Find out which ones failed, and delete the clones
* in those failed slots
*/
if (clone_failed_op[slotnum]) {
(void) FUNCLIST(
slot_session->fw_st_id)->
}
}
}
}
if (need_update_master_clone) {
/* make first available clone the master */
break;
}
}
}
if (need_update_master_clone) {
/*
* something is very wrong, can't continue
* it should never be this case.
*/
goto finish;
}
}
/*
* Update the attribute information we keep in our metaslot object
*/
(void) meta_object_get_attr(slot_session,
}
/* if there's a copy of the attributes, keep it up to date */
CK_ULONG i;
/* Make sure no one else is looking at attributes. */
for (i = 0; i < ulCount; i++) {
(void) attribute_set_value(pTemplate + i,
}
}
if (clone_failed_op) {
}
return (rv);
}
static boolean_t
{
int i;
for (i = 0; i < num_objs; i++) {
return (B_TRUE);
}
}
return (B_FALSE);
}
static CK_RV
int *num_results_alloc)
{
/*
* allocate space for storing results if the currently
* allocated space is not enough
*/
sizeof (meta_object_t *) * (*num_results_alloc));
return (CKR_HOST_MEMORY);
}
}
return (CKR_OK);
}
static CK_RV
{
CK_ULONG i;
for (i = 0; i < num_results; i++) {
/*
* a token object is found from the keystore,
* need to create a meta object for it
*/
return (rv);
}
B_TRUE);
return (rv);
}
/* get in the attributes we keep in meta_object */
B_TRUE);
return (rv);
}
B_TRUE);
slot_object = NULL;
}
info->num_matched_objs)) {
return (rv);
}
}
}
return (CKR_OK);
}
static CK_RV
int *num_results_alloc)
{
return (rv);
}
tmp_num_results = 0;
return (rv);
}
return (rv);
}
while (tmp_num_results == FIND_OBJ_BUF_SIZE) {
/* might be more results, need to call C_FindObjects again */
return (rv);
}
return (rv);
}
}
return (rv);
}
/*
* meta_FindObjectsInit
*
* This function actually will do ALL the work of searching for objects
* that match all requirements specified in the template.
*
* Objects that matched the template will be stored in the
* session's data structure. When the subsequent C_FindObjects()
* calls are made, results saved will be returned.
*
*/
{
int num_results_allocated = 0;
return (rv);
return (CKR_OPERATION_ACTIVE);
}
/* see if the template indicates token object only or not */
&tokenTrue);
if (have_token_attr && tokenTrue) {
/*
* only interested in token objects, just need to search
* token object slot
*/
goto finish;
}
goto finish;
}
} else {
goto finish;
}
/*
* if the slot is NOT the token object slot, and
* CKA_TOKEN is not specified, need to specified
* it to be false explicitly. This will prevent
* us from using token objects that doesn't
* belong to the token slot in the case that
* more than one slot supports token objects.
*/
if ((slot_num != keystore_slotnum) &&
(!have_token_attr)) {
sizeof (CK_ATTRIBUTE));
if (newTemplate == NULL) {
goto finish;
}
ulCount * sizeof (CK_ATTRIBUTE));
newTemplate[0].pValue = &false;
newTemplate[0].ulValueLen = sizeof (false);
&(session->find_objs_info),
} else {
&(session->find_objs_info),
}
goto finish;
}
}
}
if (slot_find_session != NULL) {
}
}
}
return (rv);
}
/*
* meta_FindObjects
*
* This function actually doesn't do any real work in search for the
* matching object. All the work is done in FindObjectsInit(). This
* function will only return the matching objects store in the session's
* "find_objs_info" variable.
*
*/
{
int i;
return (rv);
return (CKR_OPERATION_NOT_INITIALIZED);
}
for (i = info->next_result_index;
((num_objs_found < ulMaxObjectCount) &&
(i < info->num_matched_objs));
i++) {
/* sanity check to see if object is still valid */
phObject[num_objs_found++] =
}
}
}
info->next_result_index = i;
return (rv);
}
/*
* meta_FindObjectsFinal
*
*/
{
return (rv);
return (CKR_OPERATION_NOT_INITIALIZED);
}
if (info->matched_objs) {
}
return (rv);
}