#include "ckcapi.h" #include "pkcs11/pkcs11n.h" #include static CkCapiArray* object_array = NULL; static CkCapiHash* object_hash = NULL; static void object_free(CkCapiObject* obj) { ASSERT(obj); ASSERT(obj->obj_funcs); ASSERT(obj->obj_funcs->release); (obj->obj_funcs->release)(obj); } void ckcapi_object_clear_all(void) { size_t i; ckcapi_lock_global(); if(object_hash) { ckcapi_hash_free(object_hash, NULL); object_hash = NULL; } if(object_array) { for(i = 1; i < object_array->len; ++i) { ASSERT(ckcapi_array_index(object_array, CkCapiObject*, i)); object_free(ckcapi_array_index(object_array, CkCapiObject*, i)); } ckcapi_array_free(object_array, TRUE); object_array = NULL; } ckcapi_unlock_global(); } CK_OBJECT_HANDLE ckcapi_object_get_max_handle(void) { if(!object_array) return 0; return object_array->len; } 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; void* key; size_t klen; ASSERT(sess); ASSERT(obj->id == 0); ASSERT(obj->unique_key); ASSERT(obj->unique_len > 0); DBG(("registering object")); 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); /* The type of object is part of the hash */ key = obj->unique_key; klen = obj->unique_len; /* Sanity check, in case calcs went wrong somewhere */ ASSERT(klen < 0xFFFFFF); /* Look in the hash and find a previous object */ prev = ckcapi_hash_get(object_hash, key, klen); 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, key, klen, 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, key, klen, 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, key, klen); } } else { ret = CKR_HOST_MEMORY; } } } ckcapi_unlock_global(); return ret; } 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: case CKA_TRUST_SERVER_AUTH: case CKA_TRUST_CLIENT_AUTH: case CKA_TRUST_CODE_SIGNING: case CKA_TRUST_EMAIL_PROTECTION: case CKA_TRUST_IPSEC_END_SYSTEM: case CKA_TRUST_IPSEC_TUNNEL: case CKA_TRUST_IPSEC_USER: case CKA_TRUST_TIME_STAMPING: 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: case CKA_TRUST_STEP_UP_APPROVED: 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: case CKA_CERT_SHA1_HASH: case CKA_CERT_MD5_HASH: 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: DBG(("unknown attribute type: %x\n", type)); return DATA_UNKNOWN; }; } CK_BBOOL ckcapi_object_data_match_attr(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR match) { CK_ATTRIBUTE attr; CK_RV rv; int dtype; ASSERT(match); ASSERT(objdata); ASSERT(objdata->data_funcs); /* 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 */ attr.type = match->type; attr.pValue = _alloca(match->ulValueLen > 4 ? match->ulValueLen : 4); attr.ulValueLen = match->ulValueLen; switch(dtype) { case DATA_BOOL: rv = (objdata->data_funcs->get_bool)(objdata, &attr); break; case DATA_ULONG: rv = (objdata->data_funcs->get_ulong)(objdata, &attr); break; case DATA_BYTES: rv = (objdata->data_funcs->get_bytes)(objdata, &attr); break; case DATA_DATE: rv = (objdata->data_funcs->get_date)(objdata, &attr); break; default: ASSERT(0 && "unrecognized type"); break; }; /* Unrecognized attribute */ if(rv == CKR_ATTRIBUTE_TYPE_INVALID) return CK_FALSE; /* Value is longer than this one */ if(rv == CKR_BUFFER_TOO_SMALL) return CK_FALSE; /* All other errors */ if(rv != CKR_OK) return CK_FALSE; return (match->ulValueLen == attr.ulValueLen && memcmp(match->pValue, attr.pValue, attr.ulValueLen) == 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); 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, &attrs[i]); break; case DATA_ULONG: rv = (objdata->data_funcs->get_ulong)(objdata, &attrs[i]); break; case DATA_BYTES: rv = (objdata->data_funcs->get_bytes)(objdata, &attrs[i]); break; case DATA_DATE: rv = (objdata->data_funcs->get_date)(objdata, &attrs[i]); 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_OK) { if(rv == CKR_BUFFER_TOO_SMALL) { if(!attrs[i].pValue) rv = CKR_OK; } /* Attribute is sensitive */ else if(rv == CKR_ATTRIBUTE_SENSITIVE) { attrs[i].ulValueLen = (CK_ULONG)-1; } /* Attribute doesn't exist */ else if(rv == CKR_ATTRIBUTE_TYPE_INVALID) { DBG(("O%d: attribute not found: 0x%08x", objdata->object, attrs[i].type)); attrs[i].ulValueLen = (CK_ULONG)-1; } /* A fatal error? */ else { ret = rv; break; } /* Transfer any non-fatal errors outward */ if(rv != CKR_OK && ret == CKR_OK) ret = rv; } } return ret; }