#include "ckcapi.h" #include #include #include static CkCapiArray* object_array = NULL; static CkCapiHash* object_hash = NULL; static void object_free(CkCapiObject* obj) { ASSERT(obj); ASSERT(obj->obj_funcs.release); (obj->obj_funcs.release)(obj); } CkCapiObject* ckcapi_object_lookup(CkCapiSession* sess, CK_OBJECT_HANDLE obj) { /* This must be called without any locks held */ CkCapiObject* ret = NULL; ASSERT(sess); ASSERT(obj > 0); ckcapi_lock_global(); if(object_array && obj < object_array->len) ret = ckcapi_array_index(object_array, CkCapiObject*, obj); ckcapi_unlock_global(); return ret; } CK_RV ckcapi_object_register(CkCapiSession* sess, CkCapiObject* obj) { CkCapiObject* prev; CK_RV ret = CKR_OK; ASSERT(sess); ASSERT(obj->id == 0); ASSERT(obj->unique_key); ASSERT(obj->unique_len); DBGS(sess, "registering new session"); ckcapi_lock_global(); if(!object_array) { object_array = ckcapi_array_sized_new(0, 1, sizeof(CkCapiObject*), 16); if(object_array) { /* A blank entry for '0' */ CkCapiObject* blank = NULL; ckcapi_array_append(object_array, blank); } object_hash = ckcapi_hash_new(); if(!object_array || !object_hash) { /* Allocation failed above */ ret = CKR_HOST_MEMORY; } } if(ret == CKR_OK) { ASSERT(object_array); ASSERT(object_hash); /* Look in the hash and find a previous object */ prev = ckcapi_hash_get(object_hash, obj->unique_key, obj->unique_len); if(prev) { /* Register it in the previous object's place */ obj->id = prev->id; ASSERT(prev->id < object_array->len); if(ckcapi_hash_set(object_hash, obj->unique_key, obj->unique_len, obj)) { ckcapi_array_index(object_array, CkCapiObject*, obj->id) = obj; object_free(prev); DBGO(obj, "found old object id"); } else { ret = CKR_HOST_MEMORY; } } else { /* Register it at the end of the array */ obj->id = object_array->len; ASSERT(obj->id > 0); if(ckcapi_hash_set(object_hash, obj->unique_key, obj->unique_len, obj)) { if(ckcapi_array_append(object_array, obj)) { DBGO(obj, "registered new object id"); } else { ret = CKR_HOST_MEMORY; /* Roll back our addition */ ckcapi_hash_rem(object_hash, obj->unique_key, obj->unique_len); } } else { ret = CKR_HOST_MEMORY; } } } ckcapi_unlock_global(); return ret; } CK_RV ckcapi_object_load_data(CkCapiObject* obj, CkCapiObjectData* objdata) { ASSERT(obj); ASSERT(obj->id); ASSERT(obj->obj_funcs.load_data); memset(objdata, 0, sizeof(*objdata)); return (obj->obj_funcs.load_data)(obj, objdata); } void ckcapi_object_data_release(CkCapiObjectData* objdata) { ASSERT(objdata->data_funcs.release); (objdata->data_funcs.release)(objdata->data); memset(objdata, 0, sizeof(*objdata)); } CK_RV ckcapi_object_load_data_for(CkCapiSession* sess, CK_OBJECT_HANDLE hand, CkCapiObjectData* objdata) { CkCapiObject* obj; obj = ckcapi_object_lookup(sess, hand); if(!obj) return CKR_OBJECT_HANDLE_INVALID; return ckcapi_object_load_data(obj, objdata); } enum { DATA_UNKNOWN = 0, DATA_BOOL, DATA_ULONG, DATA_DATE, DATA_BYTES }; int attribute_data_type(CK_ATTRIBUTE_TYPE type) { switch(type) { // CK_ULONG attribute types case CKA_CLASS: case CKA_CERTIFICATE_TYPE: case CKA_CERTIFICATE_CATEGORY: case CKA_KEY_TYPE: case CKA_MODULUS_BITS: case CKA_PRIME_BITS: case CKA_SUBPRIME_BITS: /* case CKA_SUB_PRIME_BITS: */ case CKA_VALUE_BITS: case CKA_VALUE_LEN: case CKA_KEY_GEN_MECHANISM: case CKA_HW_FEATURE_TYPE: case CKA_PIXEL_X: case CKA_PIXEL_Y: case CKA_RESOLUTION: case CKA_CHAR_ROWS: case CKA_CHAR_COLUMNS: case CKA_BITS_PER_PIXEL: case CKA_MECHANISM_TYPE: case CKA_JAVA_MIDP_SECURITY_DOMAIN: return DATA_ULONG; // CK_BBOOL attribute types case CKA_TOKEN: case CKA_PRIVATE: case CKA_MODIFIABLE: case CKA_TRUSTED: case CKA_SENSITIVE: case CKA_DECRYPT: case CKA_SIGN: case CKA_SIGN_RECOVER: case CKA_UNWRAP: case CKA_EXTRACTABLE: case CKA_NEVER_EXTRACTABLE: case CKA_ALWAYS_SENSITIVE: case CKA_WRAP_WITH_TRUSTED: case CKA_ALWAYS_AUTHENTICATE: case CKA_ENCRYPT: case CKA_WRAP: case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_DERIVE: case CKA_LOCAL: case CKA_RESET_ON_INIT: case CKA_HAS_RESET: case CKA_COLOR: return DATA_BOOL; // Raw or string data case CKA_LABEL: case CKA_APPLICATION: case CKA_VALUE: case CKA_OBJECT_ID: case CKA_CHECK_VALUE: case CKA_ISSUER: case CKA_SERIAL_NUMBER: case CKA_SUBJECT: case CKA_ID: case CKA_URL: case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: case CKA_HASH_OF_ISSUER_PUBLIC_KEY: case CKA_AC_ISSUER: case CKA_OWNER: case CKA_ATTR_TYPES: case CKA_MODULUS: case CKA_PUBLIC_EXPONENT: case CKA_PRIVATE_EXPONENT: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: case CKA_PRIME: case CKA_SUBPRIME: case CKA_BASE: case CKA_ECDSA_PARAMS: /* case CKA_EC_PARAMS: */ case CKA_EC_POINT: case CKA_CHAR_SETS: case CKA_ENCODING_METHODS: case CKA_MIME_TYPES: case CKA_REQUIRED_CMS_ATTRIBUTES: case CKA_DEFAULT_CMS_ATTRIBUTES: case CKA_SUPPORTED_CMS_ATTRIBUTES: return DATA_BYTES; // CK_DATE data case CKA_START_DATE: case CKA_END_DATE: return DATA_DATE; // Arrays are nasty case CKA_WRAP_TEMPLATE: case CKA_ALLOWED_MECHANISMS: case CKA_UNWRAP_TEMPLATE: default: return DATA_UNKNOWN; }; } CK_BBOOL ckcapi_object_data_match_attr(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR match) { CK_VOID_PTR value; CK_ULONG len; CK_RV rv; int dtype; ASSERT(match); ASSERT(objdata && objdata->data); /* Get the data type of the attribute */ dtype = attribute_data_type(match->type); if(dtype == DATA_UNKNOWN) return CK_FALSE; /* We only do byte matching */ if(match->pValue == NULL) return CK_FALSE; /* Only load as much data as is needed */ value = _alloca(match->ulValueLen > 4 ? match->ulValueLen : 4); len = match->ulValueLen; switch(dtype) { case DATA_BOOL: rv = (objdata->data_funcs.get_bool)(objdata->data, match->type, value, &len); break; case DATA_ULONG: rv = (objdata->data_funcs.get_ulong)(objdata->data, match->type, value, &len); break; case DATA_BYTES: rv = (objdata->data_funcs.get_bytes)(objdata->data, match->type, value, &len); break; case DATA_DATE: rv = (objdata->data_funcs.get_date)(objdata->data, match->type, value, &len); break; default: ASSERT(0 && "unrecognized type"); break; }; /* Value is longer than this one */ if(rv == CKR_BUFFER_TOO_SMALL) return CK_FALSE; if(rv != CKR_OK) return CK_FALSE; return (match->ulValueLen == len && memcmp(match->pValue, value, len) == 0); } CK_BBOOL ckcapi_object_data_match(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR matches, CK_ULONG count) { CK_ULONG i; for(i = 0; i < count; ++i) { if(!ckcapi_object_data_match_attr(objdata, &matches[i])) return CK_FALSE; } return CK_TRUE; } CK_RV ckcapi_object_data_get_attrs(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs, CK_ULONG count) { CK_ULONG i; CK_RV rv, ret = CKR_OK; ASSERT(objdata && objdata->data); ASSERT(!count || attrs); for(i = 0; i < count; ++i) { /* Get the data type of the attribute */ switch(attribute_data_type(attrs[i].type)) { case DATA_BOOL: rv = (objdata->data_funcs.get_bool)(objdata->data, attrs[i].type, attrs[i].pValue, &attrs[i].ulValueLen); break; case DATA_ULONG: rv = (objdata->data_funcs.get_ulong)(objdata->data, attrs[i].type, attrs[i].pValue, &attrs[i].ulValueLen); break; case DATA_BYTES: rv = (objdata->data_funcs.get_bytes)(objdata->data, attrs[i].type, attrs[i].pValue, &attrs[i].ulValueLen); break; case DATA_DATE: rv = (objdata->data_funcs.get_date)(objdata->data, attrs[i].type, attrs[i].pValue, &attrs[i].ulValueLen); break; case DATA_UNKNOWN: rv = CKR_ATTRIBUTE_TYPE_INVALID; break; default: ASSERT(0 && "unrecognized type"); break; }; /* Not an error if they were just requesting the size */ if(rv == CKR_BUFFER_TOO_SMALL) { if(!attrs[i].pValue) rv = CKR_OK; } /* Is it a fatal error? */ else if(rv != CKR_ATTRIBUTE_TYPE_INVALID) { ret = rv; break; } /* Transfer any non-fatal errors outward */ if(rv != CKR_OK && ret == CKR_OK) { ret = rv; } } return ret; }