diff options
-rw-r--r-- | ckcapi-cert.c | 456 | ||||
-rw-r--r-- | ckcapi-object.c | 744 | ||||
-rw-r--r-- | ckcapi-session.c | 168 | ||||
-rw-r--r-- | ckcapi-util.c | 336 | ||||
-rw-r--r-- | ckcapi-util.h | 42 | ||||
-rw-r--r-- | ckcapi.c (renamed from cryptoki-capi.c) | 48 | ||||
-rw-r--r-- | ckcapi.dsp (renamed from cryptoki-capi.dsp) | 18 | ||||
-rw-r--r-- | ckcapi.dsw (renamed from cryptoki-capi.dsw) | 0 | ||||
-rw-r--r-- | ckcapi.h | 160 | ||||
-rw-r--r-- | cryptoki-capi.h | 99 |
10 files changed, 1161 insertions, 910 deletions
diff --git a/ckcapi-cert.c b/ckcapi-cert.c index d1b9b32..7436307 100644 --- a/ckcapi-cert.c +++ b/ckcapi-cert.c @@ -1,18 +1,25 @@ +#include "ckcapi.h" -typedef struct _CertRef -{ - +#include <memory.h> +#include <wincrypt.h> + +typedef struct _CertObject +{ + CkCapiObject obj; + const char* store; + BYTE* key_id; + DWORD key_id_len; } -CertRef; +CertObject; static CK_RV copy_static_data(CK_VOID_PTR val, CK_ULONG_PTR len, CK_VOID_PTR data, DWORD cb) { if(cb == 0) - return CKR_CANCEL; + return CKR_ATTRIBUTE_TYPE_INVALID; if(!val) { @@ -39,7 +46,6 @@ cert_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type, CK_BBOOL val; ASSERT(obj); - ASSERT(ret); switch(type) { @@ -79,7 +85,7 @@ cert_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type, /* TODO: Implement */ default: - return CK_CANCEL; + return CKR_ATTRIBUTE_TYPE_INVALID; }; return copy_static_data(data, len, &val, sizeof(CK_BBOOL)); @@ -93,7 +99,6 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type, CK_ULONG val; ASSERT(obj); - ASSERT(ret); switch(type) { @@ -102,7 +107,7 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type, * Object class. * - Always CKO_CERTIFICATE for certificates. */ - case CKA_OBJECT_CLASS: + case CKA_CLASS: val = CKO_CERTIFICATE; break; @@ -123,7 +128,7 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type, /* TODO: Implement */ default: - return CK_CANCEL; + return CKR_ATTRIBUTE_TYPE_INVALID; }; if(*len < sizeof(CK_ULONG)) @@ -137,218 +142,6 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type, static CK_RV cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, - CkCapiAttrAction action, CK_ATTRIBUTE_PTR attr) -{ - PCCERT_CONTEXT cert = (PCCERT_CONTEXT)obj; - CK_VOID_PTR val; - CK_ULONG len; - size_t maxa; - BOOL r; - - - DWORD size = *len; - - int allocated = 0; - - ASSERT(obj); - ASSERT(ret); - - /* - * We don't need to retrieve the full value of any of - * these fields if we don't have to. Just calculate - * the max amount to retrieve, so we can compare, or - * notify caller of real length. - */ - maxa = attr->ulValueLen; - if(maxa == 0) - maxa = 4; - /* Keep dynamic allocations under a 64k. */ - if(maxa > 0xFFFF) - maxa = 0xFFFF; - - switch(type) - { - - /* - * Description of the object. - * - We use CAPI's CERT_FRIENDLY_NAME_PROP_ID property, - * converted into UTF8. - * - Yes this is slow, but this is not really a property - * that's searched on or retrieved intensively. - */ - case CKA_LABEL: - { - DWORD size = maxa * sizeof(WCHAR); - WCHAR* utf16; -xxxxxx, this is wrong, second call may be needed - /* Get the UTF16 string, a worst case of twice as long as UTF8 */ - WCHAR* utf16 = alloca(size); - r = CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, - utf16, &size); - if(!r) - { - DWORD err = GetLastError(); - if(err == ERROR_MORE_DATA) - { - /* Truncate long names */ - utf16[maxa - 1] = 0; - r = TRUE; - } - else if (err != CRYPT_E_NOT_FOUND) - { - return ckcapi_winerr_to_ckr(err); - } - } - - if(r) - { - /* Convert it */ - if(!ckcapi_util_utf16_to_utf8(utf16, &val, &len)) - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - allocated = 1; - } - else - { - /* We always like to have a decent label */ - val = "Unnamed Certificate"; - len = strlen(val); - allocated = 0; - } - } - break; - - /* - * A byte array unique to this certificate. The CKA_ID of - * matching certificates and private keys should match. - * Should match the key identifier in an X.509v3 certificate. - * - * We use CAPI's CERT_KEY_IDENTIFIER_PROP_ID property directly. - */ - case CKA_ID: - { - BOOL r; - - val = alloca(size); - r = CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, - val, &size); - if(!r) - { - DWORD err = GetLastError(); - if(err == CRYPT_E_NOT_FOUND) - return CKR_CANCEL; - if(err != ERROR_MORE_DATA) - return ckcapi_winerr_to_ckr(err); - } - - *len = size; - } - break; - - /* - * DER-encoding of the certificate subject name. - * - * We use CAPI's CERT_CONTEXT pCertInfo->Subject field - * directly. - */ - case CKA_SUBJECT: - if(cert->pCertInfo->Subject.pbData == NULL || - cert->pCertInfo->Subject.cbData == 0) - return CKR_CANCEL; - val = cert->pCertInfo->Subject.pbData; - len = cert->pCertInfo->Subject.cbData; - break; - - /* - * DER-encoding of the certificate issuer name. - * - * We use CAPI's CERT_CONTEXT pCertInfo->Issuer field - * directly. - */ - case CKA_ISSUER: - if(cert->pCertInfo->Issuer.pbData == NULL || - cert->pCertInfo->Issuer.cbData == 0) - return CKR_CANCEL; - val = cert->pCertInfo->Issuer.pbData; - len = cert->pCertInfo->Issuer.cbData; - break; - - /* - * DER-encoding of the certificate serial number. - * - * TODO: - * BOOL rc = CryptEncodeObject(X509_ASN_ENCODING, - * X509_MULTI_BYTE_INTEGER, - * &certContext->pCertInfo->SerialNumber, - * co->derSerial, - * &size); - */ - case CKA_SERIAL_NUMBER: - { - BOOL r; - DWORD size = *len; - - r = CryptEncodeObject(X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, - &cert->pCertInfo->SerialNumber, val, *len); - if(!r) - { - DWORD err = GetLastError(); - if(err == ERROR_FILE_NOT_FOUND) - return CKR_GENERAL_ERROR; - if(err != ERROR_MORE_DATA) - return ckcapi_winerr_to_ckr(err); - } - - len = size; - } - break; - - /* - * BER-encoding of the full certificate. - * - * We use CAPI's CERT_CONTEXT pbCertEncoded field directly. - */ - case CKA_VALUE: - if(cert->pbCertEncoded == NULL || - cert->cbCertEncoded == 0) - return CKR_CANCEL; - val = cert->pbCertEncoded; - len = cert->cbCertEncoded; - break; - break; - - /* - * If CKA_VALUE not specified, this is where the full - * certificate can be found. - * - * We don't support this. All our certificates are present - * in full. - */ - case CKA_URL: - return CKR_CANCEL; - - /* - * Checksum - * - TODO: Work out what to do here - */ - case CKA_CHECKSUM: - break; - - /* - * TODO: Should we support these? - */ - CKA_HASH_OF_SUBJECT_PUBLIC_KEY - CKA_HASH_OF_ISSUER_PUBLIC_KEY - break; - - /* Not supported */ - - default: - break - }; -}; - -static CK_RV -cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, CK_VOID_PTR data, CK_ULONG_PTR len) { PCCERT_CONTEXT cert = (PCCERT_CONTEXT)obj; @@ -372,8 +165,8 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, /* Get the UTF16 string, a worst case of twice as long as UTF8 */ (*len) *= sizeof(WCHAR); - utf16 = alloca(*len); - r = CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, + utf16 = _alloca(*len); + if(!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, utf16, (DWORD*)len)) { DWORD err = GetLastError(); @@ -384,7 +177,9 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, } /* Convert the data into the buffer */ - return ckcapi_util_utf16_to_utf8(utf16, data, len)); + if(!WideCharToMultiByte(CP_UTF8, 0, utf16, -1, data, *len, "?", NULL)) + return ckcapi_winerr_to_ckr(GetLastError()); + return CKR_OK; } break; @@ -402,7 +197,7 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, { DWORD err = GetLastError(); if(err == CRYPT_E_NOT_FOUND) - return CKR_CANCEL; + return CKR_ATTRIBUTE_TYPE_INVALID; return ckcapi_winerr_to_ckr(err); } } @@ -474,27 +269,28 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, * Checksum * - TODO: Work out what to do here */ - case CKA_CHECKSUM: + case CKA_CHECK_VALUE: break; /* * TODO: Should we support these? */ - CKA_HASH_OF_SUBJECT_PUBLIC_KEY - CKA_HASH_OF_ISSUER_PUBLIC_KEY + case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: + case CKA_HASH_OF_ISSUER_PUBLIC_KEY: break; /* Not supported */ default: - break + break; }; - return CKR_CANCEL; + return CKR_ATTRIBUTE_TYPE_INVALID; } -static xxx -cert_date_attribute() +static CK_RV +cert_date_attribute(void* obj, CK_ATTRIBUTE_TYPE type, + CK_VOID_PTR data, CK_ULONG_PTR len) { switch(type) { @@ -505,7 +301,6 @@ cert_date_attribute() * pCertInfo->NotBefore; */ case CKA_START_DATE: - xxxx; break; /* @@ -514,7 +309,198 @@ cert_date_attribute() * pCertInfo->NotBefore; */ case CKA_END_DATE: - xxxx; break; }; + + return CKR_ATTRIBUTE_TYPE_INVALID; +} + +static void +cert_release(void* data) +{ + PCCERT_CONTEXT cert = (PCCERT_CONTEXT)data; + ASSERT(cert); + CertFreeCertificateContext(cert); +} + +static const CkCapiObjectDataVtable cert_objdata_vtable = { + cert_bool_attribute, + cert_ulong_attribute, + cert_bytes_attribute, + cert_date_attribute, + cert_release, +}; + +static CK_RV +cert_load(CkCapiObject* obj, CkCapiObjectData* objdata) +{ + CertObject* cobj = (CertObject*)obj; + HCERTSTORE store; + PCCERT_CONTEXT cert; + CRYPT_HASH_BLOB blob; + + ASSERT(cobj); + ASSERT(objdata); + + ASSERT(cobj->store); + store = CertOpenSystemStore((HCRYPTPROV)NULL, cobj->store); + if(!store) + return ckcapi_winerr_to_ckr(GetLastError()); + + ASSERT(cobj->key_id); + ASSERT(cobj->key_id_len); + blob.pbData = cobj->key_id; + blob.cbData = cobj->key_id_len; + + cert = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, CERT_FIND_KEY_IDENTIFIER, &blob, NULL); + + CertCloseStore(store, 0); + + if(!cert) + { + DWORD err = GetLastError(); + + /* TODO: Is this right for a deleted certificate? */ + ASSERT(err != E_INVALIDARG); + if(err == CRYPT_E_NOT_FOUND) + return CKR_OBJECT_HANDLE_INVALID; + else + return ckcapi_winerr_to_ckr(GetLastError()); + } + + objdata->data = (void*)cert; + objdata->data_funcs = cert_objdata_vtable; + return CKR_OK; +} + + +static void +cert_object_release(void* data) +{ + CertObject* cobj = (CertObject*)data; + ASSERT(cobj); + free(cobj); +} + +static const CkCapiObjectVtable cert_object_vtable = { + cert_load, + cert_object_release, +}; + +static CK_RV +register_cert_object(CkCapiSession* sess, const char* store, PCCERT_CONTEXT cert, + CK_OBJECT_HANDLE_PTR id) +{ + CertObject* cobj; + CK_RV ret; + DWORD len; + + if(!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &len)) + { + DBG(("cannot get certificate key identifier: %d", GetLastError())); + return CKR_ATTRIBUTE_TYPE_INVALID; + } + + cobj = calloc(sizeof(CertObject) + len, 1); + if(!cobj) + return CKR_HOST_MEMORY; + + /* Store keyid in allocated area after CertObject */ + cobj->key_id = (BYTE*)(cobj + 1); + cobj->key_id_len = len; + + if(!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, + cobj->key_id, &(cobj->key_id_len))) + { + DBG(("cannot read certificate key identifier: %d", GetLastError())); + free(cobj); + return CKR_ATTRIBUTE_TYPE_INVALID; + } + + cobj->store = store; + cobj->obj.id = 0; + cobj->obj.unique_key = cobj->key_id; + cobj->obj.unique_len = cobj->key_id_len; + cobj->obj.obj_funcs = cert_object_vtable; + cobj->obj.data_funcs = cert_objdata_vtable; + + ret = ckcapi_object_register(sess, &(cobj->obj)); + if(ret != CKR_OK) + { + free(cobj); + return ret; + } + + ASSERT(cobj->obj.id != 0); + *id = cobj->obj.id; + return CKR_OK; +} + +CK_RV +ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name, + CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr) +{ + PCCERT_CONTEXT cert = NULL; + CK_OBJECT_HANDLE obj; + HCERTSTORE store; + CkCapiObjectData objdata; + DWORD err; + CK_RV ret = CKR_OK; + + store = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); + if(store == NULL) + { + err = GetLastError(); + + /* Store not found, we don't care */ + if(err == ERROR_FILE_NOT_FOUND) + return CKR_OK; + + else + return ckcapi_winerr_to_ckr(err); + } + + /* Match each certificate */ + while((cert = CertEnumCertificatesInStore(store, cert)) != NULL) + { + objdata.data = (void*)cert; + objdata.data_funcs = cert_objdata_vtable; + + if(ckcapi_object_data_match(&objdata, match, count)) + { + ret = register_cert_object(sess, store, cert, &obj); + if(ret != CKR_OK) + break; + + ckcapi_array_append(arr, obj); + } + } + + ASSERT(store); + CertCloseStore(store, 0); + + return ret; +} + +CK_RV +ckcapi_cert_find_all(CkCapiSession* sess, CK_ATTRIBUTE_PTR match, + CK_ULONG count, CkCapiArray* arr) +{ + CK_RV ret; + + ret = ckcapi_cert_find_in_store(sess, "My", match, count, arr); + if(ret == CKR_OK) + ret = ckcapi_cert_find_in_store(sess, "AddressBook", match, count, arr); + if(ret == CKR_OK) + ret = ckcapi_cert_find_in_store(sess, "CA", match, count, arr); + if(ret == CKR_OK) + ret = ckcapi_cert_find_in_store(sess, "Root", match, count, arr); + if(ret == CKR_OK) + ret = ckcapi_cert_find_in_store(sess, "Trust", match, count, arr); + if(ret == CKR_OK) + ret = ckcapi_cert_find_in_store(sess, "TrustedPeople", match, count, arr); + if(ret == CKR_OK) + ret = ckcapi_cert_find_in_store(sess, "AuthRoot", match, count, arr); + return ret; } diff --git a/ckcapi-object.c b/ckcapi-object.c index 531ad2f..c02c365 100644 --- a/ckcapi-object.c +++ b/ckcapi-object.c @@ -1,9 +1,165 @@ -#include "cryptoki-capi.h" +#include "ckcapi.h" + +#include <memory.h> #include <wtypes.h> #include <wincrypt.h> +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, @@ -13,7 +169,6 @@ enum DATA_BYTES }; - int attribute_data_type(CK_ATTRIBUTE_TYPE type) { @@ -27,7 +182,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type) case CKA_MODULUS_BITS: case CKA_PRIME_BITS: case CKA_SUBPRIME_BITS: - case CKA_SUB_PRIME_BITS: + /* case CKA_SUB_PRIME_BITS: */ case CKA_VALUE_BITS: case CKA_VALUE_LEN: case CKA_KEY_GEN_MECHANISM: @@ -40,7 +195,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type) case CKA_BITS_PER_PIXEL: case CKA_MECHANISM_TYPE: case CKA_JAVA_MIDP_SECURITY_DOMAIN: - return DATA_ULONG: + return DATA_ULONG; // CK_BBOOL attribute types case CKA_TOKEN: @@ -56,7 +211,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type) case CKA_NEVER_EXTRACTABLE: case CKA_ALWAYS_SENSITIVE: case CKA_WRAP_WITH_TRUSTED: - case CKA_ALWAYS_AUTHENTICATE + case CKA_ALWAYS_AUTHENTICATE: case CKA_ENCRYPT: case CKA_WRAP: case CKA_VERIFY: @@ -96,7 +251,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type) case CKA_SUBPRIME: case CKA_BASE: case CKA_ECDSA_PARAMS: - case CKA_EC_PARAMS: + /* case CKA_EC_PARAMS: */ case CKA_EC_POINT: case CKA_CHAR_SETS: case CKA_ENCODING_METHODS: @@ -120,536 +275,133 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type) }; } -CK_RV -attribute_fill(CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_TYPE type, - CK_VOID_PTR* val, CK_ULONG len) +CK_BBOOL +ckcapi_object_data_match_attr(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR match) { - ASSERT(attr); - ASSERT(val); - ASSERT(len); - - attr->type = type; + CK_VOID_PTR value; + CK_ULONG len; + CK_RV rv; + int dtype; - if(attr->pValue && attr->ulValueLen < len) - { - attr->ulValueLen = len; - return CKR_BUFFER_TOO_SMALL; - } - - else if(!attr->pValue) - { - attr->ulValueLen = len; - return CKR_OK; - } + ASSERT(match); + ASSERT(objdata && objdata->data); - else - { - memcpy(attr->pValue, &val, len); - attr->ulValueLen = len; - return CKR_OK; - } -} + /* Get the data type of the attribute */ + dtype = attribute_data_type(match->type); + if(dtype == DATA_UNKNOWN) + return CK_FALSE; -CK_RV -attribute_match(CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_TYPE type, - CK_VOID_PTR* val, CK_ULONG len) -{ - ASSERT(attr); - ASSERT(val); - ASSERT(len); - - if(attr->pValue && attr->ulValueLen == len && - memcmp(attr->pValue, &val, len); - return CKR_OK; - return CKR_CANCEL; -} + /* We only do byte matching */ + if(match->pValue == NULL) + return CK_FALSE; -/* -------------------------------------------------------------------------- - * CERTIFICATES - */ + /* Only load as much data as is needed */ + value = _alloca(match->ulValueLen > 4 ? match->ulValueLen : 4); + len = match->ulValueLen; -static CK_RV -cert_bool_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert, - CK_ATTRIBUTE_PTR attr, CK_BBOOL fill) -{ - CK_BBOOL val; - switch(type) + switch(dtype) { - /* - * Resides on the token - * - Always true for CAPI objects. - */ - case CKA_TOKEN: - val = CK_TRUE; + case DATA_BOOL: + rv = (objdata->data_funcs.get_bool)(objdata->data, match->type, value, &len); break; - - /* - * Private vs. Public object. - * - Always false for certificates. - */ - case CKA_PRIVATE: - val = CK_FALSE; + case DATA_ULONG: + rv = (objdata->data_funcs.get_ulong)(objdata->data, match->type, value, &len); break; - - /* - * If object can be modified. - * - Currently always false. In the future with additional - * functionality this may change. - */ - case CKA_MODIFIABLE: - val = CK_FALSE; + case DATA_BYTES: + rv = (objdata->data_funcs.get_bytes)(objdata->data, match->type, value, &len); break; - - /* - * Whether the certificate can be trusted for the application - * in which it was created. - * - Use CertGetCertificateChain to build up a chain - * for this certificate, and then look in the CERT_CHAIN_CONTEXT - * TrustStatus field. - */ - case CKA_TRUSTED: - /* TODO: Implement */ - - default: - return CK_CANCEL; - }; - - if(fill) - return attribute_fill(attr, type, &val, sizeof(CK_BBOOL)); - else - return attribute_match(attr, type, &val, sizeof(CK_BBOOL)); -} - -static CK_RV -cert_ulong_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert, - CK_ATTRIBUTE_PTR attr, CK_BBOOL fill) -{ - CK_ULONG val; - switch(type) - { - - /* - * Object class. - * - Always CKO_CERTIFICATE for certificates. - */ - case CKA_OBJECT_CLASS: - val = CKO_CERTIFICATE; + case DATA_DATE: + rv = (objdata->data_funcs.get_date)(objdata->data, match->type, value, &len); break; - - /* - * Type of certificate. - * - Always X509. - */ - case CKA_CERTIFICATE_TYPE: - val = CKC_X_509; - break; - - /* - * Whether a CA, user certificate, other. - * - Get certificate szOID_ENHANCED_KEY_USAGE - * extension or CERT_CTL_PROP_ID and look into CTL_USAGE structure. - */ - case CKA_CERTIFICATE_CATEGORY: - /* TODO: Implement */ - default: - return CK_CANCEL; - }; - - if(fill) - return attribute_fill(attr, type, &val, sizeof(CK_ULONG)); - else - return attribute_match(attr, type, &val, sizeof(CK_ULONG)); -} - -static CK_RV -cert_bytes_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert, - CK_ATTRIBUTE_PTR attr, CK_BBOOL fill) -{ - switch(type) - { - - /* - * Description of the object. - * - We use CAPI's CERT_FRIENDLY_NAME_PROP_ID property, - * converted into UTF8. - */ - case CKA_LABEL: - xxxxx - break; - - /* - * A byte array unique to this certificate. The CKA_ID of - * matching certificates and private keys should match. - * Should match the key identifier in an X.509v3 certificate. - * - * We use CAPI's CERT_KEY_IDENTIFIER_PROP_ID property directly. - */ - case CKA_ID: - xxxxx + ASSERT(0 && "unrecognized type"); break; - - /* - * DER-encoding of the certificate subject name. - * - * We use CAPI's CERT_CONTEXT pCertInfo->Subject field - * directly. - */ - case CKA_SUBJECT: - xxxxx - break; - - /* - * DER-encoding of the certificate issuer name. - * - * We use CAPI's CERT_CONTEXT pCertInfo->Issuer field - * directly. - */ - case CKA_ISSUER: - xxxxx - break; - - /* - * DER-encoding of the certificate serial number. - * - * TODO: - * BOOL rc = CryptEncodeObject(X509_ASN_ENCODING, - * X509_MULTI_BYTE_INTEGER, - * &certContext->pCertInfo->SerialNumber, - * co->derSerial, - * &size); - */ - case CKA_SERIAL_NUMBER: - xxxxx - break; - - /* - * BER-encoding of the full certificate. - * - * We use CAPI's CERT_CONTEXT pbCertEncoded field directly. - */ - case CKA_VALUE: - xxxxx - break; - - /* - * If CKA_VALUE not specified, this is where the full - * certificate can be found. - * - * We don't support this. All our certificates are present - * in full. - */ - case CKA_URL: - break; - - /* - * Checksum - * - TODO: Work out what to do here - */ - case CKA_CHECKSUM: - break; - - /* - * TODO: Should we support these? - */ - CKA_HASH_OF_SUBJECT_PUBLIC_KEY - CKA_HASH_OF_ISSUER_PUBLIC_KEY - break; - - /* Not supported */ - - default: - break }; -}; -static xxx -cert_date_attribute() -{ - switch(type) - { - - /* - * Start date for the certificate. - * - TODO: Work out where to get this. - */ - pCertInfo->NotBefore; - case CKA_START_DATE: - xxxx; - break; - - /* - * End date for the certificate. - * - TODO: Work out where to get this. - */ - pCertInfo->NotAfter; - case CKA_END_DATE: - xxxx; - break; - }; -} -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - -static CK_RV -cert_ulong_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert, - CK_ATTRIBUTE_PTR attr) -{ - CK_ATTRIBUTE_PTR ret; - CK_BBOOL val; - - switch(type) - { - case CKA_TOKEN: - val = CK_TRUE; - break; - case CKA_PRIVATE: - case CKA_MODIFIABLE: - val = CK_FALSE; - break; - }; - - /* If attr is initialized, just do a match */ - if(attr.type == type) - { - if(attr->pValue && attr->ulValueLen == sizeof(CK_BBOOL) && - memcmp(attr->pValue, &val, sizeof(CK_BBOOL)); - return CKR_OK; - return CKR_CANCEL; - } - - /* Otherwise fill in the value */ - else - { - return prep_attribute(attr, type, &val, sizeof(CK_BBOOL); - } -} - -static CK_ATTRIBUTE_PTR -cert_load_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert) -{ - CK_BBOOL vval = CK_FALSE; - CK_ULONG uval = 0; - CK_VOID_PTR val; - CK_ULONG n_val; - - switch(type) - { - case CKA_CLASS: - uval = CKO_CERTIFICATE; - break; - case CKA_TOKEN; - - } -} - -static CK_BBOOL -cert_match_attr(CK_ATTRIBUTE_PTR match, PCCERT_CONTEXT cert) -{ - CK_ATTRIBUTE_PTR attr; - CK_BBOOL ret; - - attr = cert_load_attribute(match->type, cert); - if(!attr) + /* Value is longer than this one */ + if(rv == CKR_BUFFER_TOO_SMALL) + return CK_FALSE; + if(rv != CKR_OK) return CK_FALSE; - ret = (attr->ulValueLen == match->ulValueLen && - memcmp(attr->pValue, match->pValue, attr->ulValueLen) == 0); - - free_attribute(attr); - return ret; + return (match->ulValueLen == len && + memcmp(match->pValue, value, len) == 0); } -static CK_BBOOL -cert_match(CK_ATTRIBUTE_PTR matches, CK_ULONG count, - PCCERT_CONTEXT cert) +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(!cert_match_attr(&match[i], cert)) + if(!ckcapi_object_data_match_attr(objdata, &matches[i])) return CK_FALSE; } return CK_TRUE; } -static CK_RV -gather_store_certs(const char* store_name, Array* arr, - CK_ATTRIBUTE_PTR match, CK_ULONG count) +CK_RV +ckcapi_object_data_get_attrs(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs, + CK_ULONG count) { - PCCERT_CONTEXT cert = NULL; - CK_OBJECT_HANDLE obj; - HCERTSTORE store; - DWORD err; - CK_RV ret = CKR_OK; - - store = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); - if(store == NULL) - { - err = GetLastError(); - - /* Store not found, we don't care */ - if(err == ERROR_FILE_NOT_FOUND) - return CKR_OK; + CK_ULONG i; + CK_RV rv, ret = CKR_OK; - else - return ckcapi_winerr_to_ckr(err); - } + ASSERT(objdata && objdata->data); + ASSERT(!count || attrs); - /* Match each certificate */ - while((cert = CertEnumCertificatesInStore(store, cert)) != NULL) + for(i = 0; i < count; ++i) { - if(match_cert(match, count, cert)) + /* Get the data type of the attribute */ + switch(attribute_data_type(attrs[i].type)) { - obj = register_cert(store, cert); - if(!obj) - { - ret = CKR_HOST_MEMORY; - break; - } - - ckcapi_util_array_append(arr, obj); + 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; } - } - ASSERT(store); - CertCloseStore(store, 0); - - return ret; -} - -/* ---------------------------------------------------------------------------- - * FIND - */ - -BOOL -get_ulong_attribute(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR templ, - CK_ULONG count, CK_ULONG* val) -{ - CK_ULONG i; - - ASSERT(val); - ASSERT(!count || templ); + /* Is it a fatal error? */ + else if(rv != CKR_ATTRIBUTE_TYPE_INVALID) + { + ret = rv; + break; + } - for(i = 0; i < count; ++i) - { - if(templ[i].type == type) + /* Transfer any non-fatal errors outward */ + if(rv != CKR_OK && ret == CKR_OK) { - *val = *((CK_ULONG*)templ[i].pValue); - return TRUE; + ret = rv; } } - return FALSE; -} - - - - -CK_RV -gather_objects(Array* arr, CK_ATTRIBUTE_PTR match, CK_ULONG count) -{ - CK_OBJECT_CLASS ocls = CK_INVALID_HANDLE; - CK_RV ret = CKR_OK; - - get_ulong_attribute(CKA_CLASS, match, count, &ocls); - switch(ocls) - { - /* all different classes */ - case CK_INVALID_HANDLE: - case CKO_CERTIFICATE: - ret = gather_certificates(arr, match, count); - break; - case CKO_PUBLIC_KEY: - case CKO_PRIVATE_KEY: - default: - break; - }; - return ret; -} - -void -cleanup_find_operation(Session* sess) -{ - ASSERT(sess->operation_type == OPERATION_FIND); - if(sess->operation_data) - ckcapi_util_array_free((Array*)sess->operation_data, TRUE); - sess->operation_type = OPERATION_NONE; - sess->operation_data = NULL; - sess->operation_cancel = NULL; -} - -CK_RV -ckcapi_object_find_init(Session* sess, CK_ATTRIBUTE_PTR match, - CK_ULONG count) -{ - Array* arr; - CK_RV ret; - - ASSERT(sess); - ASSERT(!count || match); - - if(sess->operation_type != OPERATION_NONE) - return CKR_OPERATION_ACTIVE; - - arr = ckcapi_util_array_new(0, 1, sizeof(CK_OBJECT_HANDLE)); - if(!arr) - return CKR_HOST_MEMORY; - - ret = gather_objects(arr, match, count); - if(ret != CKR_OK) - { - ckcapi_util_array_free(arr, TRUE); - return ret; - } - - sess->operation_type = OPERATION_FIND; - sess->operation_data = arr; - sess->operation_cancel = cleanup_find_operation; - - return CKR_OK; -} - -CK_RV -ckcapi_object_find(Session* sess, CK_OBJECT_HANDLE_PTR objects, - CK_ULONG max_object_count, CK_ULONG_PTR object_count) -{ - Array* arr; - size_t i; - - ASSERT(sess); - ASSERT(object_count); - ASSERT(!max_object_count || objects); - - if(sess->operation_type != OPERATION_FIND) - return CKR_OPERATION_NOT_INITIALIZED; - - if(!max_object_count) - { - *object_count = 0; - return CKR_OK; - } - - arr = (Array*)sess->operation_data; - *object_count = (max_object_count > arr->len ? arr->len : max_object_count); - for(i = 0; i < *object_count; ++i) - objects[i] = ckcapi_util_array_index(arr, CK_OBJECT_HANDLE, i); - ckcapi_util_array_remove_range(arr, 0, *object_count); - - return CKR_OK; -} - -CK_RV -ckcapi_objects_find_final(Session* sess) -{ - ASSERT(sess); - - if(sess->operation_type != OPERATION_FIND) - return CKR_OPERATION_NOT_INITIALIZED; - - cleanup_find_operation(sess); - return CKR_OK; -} - +}
\ No newline at end of file diff --git a/ckcapi-session.c b/ckcapi-session.c index dc700c1..1076fbd 100644 --- a/ckcapi-session.c +++ b/ckcapi-session.c @@ -1,10 +1,10 @@ #include <stdlib.h> -#include "cryptoki-capi.h" +#include "ckcapi.h" typedef struct _SessionList { - Session **list; + CkCapiSession **list; size_t lmax; } SessionList; @@ -12,10 +12,10 @@ typedef struct _SessionList { static SessionList the_sessions = { NULL, 0 }; -Session* +CkCapiSession* ckcapi_session_create(void) { - Session* sess = calloc(1, sizeof(Session)); + CkCapiSession* sess = calloc(1, sizeof(CkCapiSession)); if(!sess) return NULL; @@ -31,7 +31,7 @@ ckcapi_session_create(void) } CK_RV -ckcapi_session_register(Session* sess) +ckcapi_session_register(CkCapiSession* sess) { CK_ULONG id = 0; CK_RV ret = CKR_OK; @@ -67,13 +67,13 @@ ckcapi_session_register(Session* sess) /* Couldn't find a handle, reallocate */ if(id == 0) { - Session** buf; + CkCapiSession** buf; size_t oldmax, newmax; oldmax = the_sessions.lmax; newmax = oldmax + 16; - buf = realloc(the_sessions.list, newmax * sizeof(Session*)); + buf = realloc(the_sessions.list, newmax * sizeof(CkCapiSession*)); if(!buf) { DBGS(sess, ("couldn't allocate session list, out of memory")); @@ -116,7 +116,7 @@ ckcapi_session_register(Session* sess) } void -ckcapi_session_destroy(Session* sess) +ckcapi_session_destroy(CkCapiSession* sess) { ASSERT(sess); ASSERT(sess->refs == 0); @@ -141,10 +141,10 @@ ckcapi_session_destroy(Session* sess) } static CK_RV -find_lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id, - int remove, Session** sess_ret) +lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id, + int remove, CkCapiSession** sess_ret) { - Session *sess; + CkCapiSession *sess; DWORD r; ASSERT(sessions); @@ -185,7 +185,7 @@ find_lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id, } } - /* Lock the CallSession */ + /* Lock the CallCkCapiSession */ r = WaitForSingleObject(sess->mutex, INFINITE); ASSERT(r == WAIT_OBJECT_0); @@ -225,7 +225,7 @@ find_lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id, } CK_RV -ckcapi_session_find_lock_ref(CK_ULONG id, int remove, Session **sess) +ckcapi_session_get_lock_ref(CK_ULONG id, int remove, CkCapiSession **sess) { /* This must be called without any locks held */ @@ -241,7 +241,7 @@ ckcapi_session_find_lock_ref(CK_ULONG id, int remove, Session **sess) ckcapi_lock_global(); - ret = find_lock_ref_internal (&the_sessions, id, remove, sess); + ret = lock_ref_internal (&the_sessions, id, remove, sess); ckcapi_unlock_global(); @@ -249,9 +249,9 @@ ckcapi_session_find_lock_ref(CK_ULONG id, int remove, Session **sess) } void -ckcapi_session_unref_unlock(Session* sess) +ckcapi_session_unref_unlock(CkCapiSession* sess) { - /* The CallSession must be locked at this point */ + /* The CallCkCapiSession must be locked at this point */ int refs; BOOL r; @@ -284,7 +284,7 @@ ckcapi_session_close_all() /* This must be called without any locks held */ SessionList sessions; - Session *sess; + CkCapiSession *sess; size_t i; CK_RV ret; @@ -313,7 +313,7 @@ ckcapi_session_close_all() if(!sessions.list[i]) continue; - ret = find_lock_ref_internal (&sessions, i, 1, &sess); + ret = lock_ref_internal (&sessions, i, 1, &sess); ASSERT(ret == CKR_OK); ckcapi_session_unref_unlock(sess); @@ -327,3 +327,135 @@ ckcapi_session_close_all() } } +/* ---------------------------------------------------------------------------- + * FIND OPERATION + */ + +static BOOL +get_ulong_attribute(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR templ, + CK_ULONG count, CK_ULONG* val) +{ + CK_ULONG i; + + ASSERT(val); + ASSERT(!count || templ); + + for(i = 0; i < count; ++i) + { + if(templ[i].type == type) + { + *val = *((CK_ULONG*)templ[i].pValue); + return TRUE; + } + } + + return FALSE; +} + +static CK_RV +gather_objects(CkCapiSession* sess, CK_ATTRIBUTE_PTR match, + CK_ULONG count, CkCapiArray* arr) +{ + CK_OBJECT_CLASS ocls = CK_INVALID_HANDLE; + CK_RV ret = CKR_OK; + + get_ulong_attribute(CKA_CLASS, match, count, &ocls); + switch(ocls) + { + /* all different classes */ + case CK_INVALID_HANDLE: + case CKO_CERTIFICATE: + ret = ckcapi_cert_find_all(sess, match, count, arr); + break; + case CKO_PUBLIC_KEY: + case CKO_PRIVATE_KEY: + default: + break; + }; + + return ret; +} + +void +cleanup_find_operation(CkCapiSession* sess) +{ + ASSERT(sess->operation_type == OPERATION_FIND); + if(sess->operation_data) + ckcapi_array_free((CkCapiArray*)sess->operation_data, TRUE); + sess->operation_type = OPERATION_NONE; + sess->operation_data = NULL; + sess->operation_cancel = NULL; +} + +CK_RV +ckcapi_session_find_init(CkCapiSession* sess, CK_ATTRIBUTE_PTR match, + CK_ULONG count) +{ + CkCapiArray* arr; + CK_RV ret; + + ASSERT(sess); + ASSERT(!count || match); + + if(sess->operation_type != OPERATION_NONE) + return CKR_OPERATION_ACTIVE; + + arr = ckcapi_array_new(0, 1, sizeof(CK_OBJECT_HANDLE)); + if(!arr) + return CKR_HOST_MEMORY; + + ret = gather_objects(sess, match, count, arr); + if(ret != CKR_OK) + { + ckcapi_array_free(arr, TRUE); + return ret; + } + + sess->operation_type = OPERATION_FIND; + sess->operation_data = arr; + sess->operation_cancel = cleanup_find_operation; + + return CKR_OK; +} + +CK_RV +ckcapi_session_find(CkCapiSession* sess, CK_OBJECT_HANDLE_PTR objects, + CK_ULONG max_object_count, CK_ULONG_PTR object_count) +{ + CkCapiArray* arr; + size_t i; + + ASSERT(sess); + ASSERT(object_count); + ASSERT(!max_object_count || objects); + + if(sess->operation_type != OPERATION_FIND) + return CKR_OPERATION_NOT_INITIALIZED; + + if(!max_object_count) + { + *object_count = 0; + return CKR_OK; + } + + arr = (CkCapiArray*)sess->operation_data; + *object_count = (max_object_count > arr->len ? arr->len : max_object_count); + for(i = 0; i < *object_count; ++i) + objects[i] = ckcapi_array_index(arr, CK_OBJECT_HANDLE, i); + ckcapi_array_remove_range(arr, 0, *object_count); + + return CKR_OK; +} + +CK_RV +ckcapi_session_find_final(CkCapiSession* sess) +{ + ASSERT(sess); + + if(sess->operation_type != OPERATION_FIND) + return CKR_OPERATION_NOT_INITIALIZED; + + cleanup_find_operation(sess); + return CKR_OK; +} + diff --git a/ckcapi-util.c b/ckcapi-util.c index d8d182b..6969c2e 100644 --- a/ckcapi-util.c +++ b/ckcapi-util.c @@ -1,17 +1,16 @@ -#include "cryptoki-capi-util.h" +#include "ckcapi-util.h" +#include <sys/types.h> +#include <stdlib.h> #include <string.h> - - - #define MIN_ARRAY_SIZE 16 typedef struct _RealArray { - Array pub; + CkCapiArray pub; size_t alloc; size_t elt_size; int zero_terminated : 1; @@ -44,7 +43,7 @@ maybe_expand(RealArray *array, size_t len) array->zero_terminated); if(want_alloc > array->alloc) - { + { want_alloc = nearest_pow(want_alloc); want_alloc = want_alloc > MIN_ARRAY_SIZE ? want_alloc : MIN_ARRAY_SIZE; @@ -53,21 +52,21 @@ maybe_expand(RealArray *array, size_t len) return 0; array->pub.data = mem; - memset((char*)array->pub.data + array->alloc, 0, want_alloc - array->alloc); + memset((char*)array->pub.data + array->alloc, 0, want_alloc - array->alloc); array->alloc = want_alloc; } return 1; } -Array* -ckcapi_util_array_new(int zero_terminated, int clear, size_t elt_size) +CkCapiArray* +ckcapi_array_new(int zero_terminated, int clear, size_t elt_size) { - return ckcapi_util_array_sized_new(zero_terminated, clear, elt_size, 0); + return ckcapi_array_sized_new(zero_terminated, clear, elt_size, 0); } -Array* -ckcapi_util_array_sized_new(int zero_terminated, int clear, size_t elt_size, +CkCapiArray* +ckcapi_array_sized_new(int zero_terminated, int clear, size_t elt_size, size_t reserved_size) { RealArray *array = malloc(sizeof(RealArray)); @@ -87,11 +86,11 @@ ckcapi_util_array_sized_new(int zero_terminated, int clear, size_t elt_size, array_zero_terminate(array); } - return (Array*)array; + return (CkCapiArray*)array; } void* -ckcapi_util_array_free(Array* array, int free_segment) +ckcapi_array_free(CkCapiArray* array, int free_segment) { void* segment; @@ -99,10 +98,10 @@ ckcapi_util_array_free(Array* array, int free_segment) return NULL; if(free_segment) - { + { free(array->data); segment = NULL; - } + } else segment = array->data; @@ -111,7 +110,7 @@ ckcapi_util_array_free(Array* array, int free_segment) } int -ckcapi_util_array_append_vals(Array* parray, const void* data, size_t len) +ckcapi_array_append_vals(CkCapiArray* parray, const void* data, size_t len) { RealArray* array = (RealArray*)parray; if(!maybe_expand(array, len)) @@ -127,7 +126,7 @@ ckcapi_util_array_append_vals(Array* parray, const void* data, size_t len) } void -ckcapi_util_array_remove_index(Array* parray, unsigned int index) +ckcapi_array_remove_index(CkCapiArray* parray, unsigned int index) { RealArray* array = (RealArray*)parray; @@ -136,16 +135,16 @@ ckcapi_util_array_remove_index(Array* parray, unsigned int index) if(index != array->pub.len - 1) memmove(array_elt_pos (array, index), - array_elt_pos (array, index + 1), - array_elt_len (array, array->pub.len - index - 1)); + array_elt_pos (array, index + 1), + array_elt_len (array, array->pub.len - index - 1)); array->pub.len -= 1; - array_elt_zero (array, array->pub.len, 1); + array_elt_zero (array, array->pub.len, 1); } void -ckcapi_util_array_remove_range(Array* parray, unsigned int index, size_t length) +ckcapi_array_remove_range(CkCapiArray* parray, unsigned int index, size_t length) { RealArray *array = (RealArray*)parray; @@ -162,6 +161,297 @@ ckcapi_util_array_remove_range(Array* parray, unsigned int index, size_t length) (array->pub.len - (index + length)) * array->elt_size); array->pub.len -= length; - array_elt_zero(array, array->pub.len, length); + array_elt_zero(array, array->pub.len, length); +} + + +/* + * Originally from apache 2.0 + * Modifications for general use by <nielsen@memberwebs.com> + */ + +/* Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#define KEY_DATA(he) ((he)->key) + +/* + * The internal form of a hash table. + * + * The table is an array indexed by the hash of the key; collisions + * are resolved by hanging a linked list of hash entries off each + * element of the array. Although this is a really simple design it + * isn't too bad given that pools have a low allocation overhead. + */ + +typedef struct _HashEntry +{ + struct _HashEntry* next; + unsigned int hash; + const void* key; + size_t klen; + const void* val; } +HashEntry; + +/* + * The size of the array is always a power of two. We use the maximum + * index rather than the size so that we can use bitwise-AND for + * modular arithmetic. + * The count of hash entries may be greater depending on the chosen + * collision rate. + */ +struct _CkCapiHash +{ + HashEntry** array; + size_t count; + size_t max; +}; + +#define INITIAL_MAX 15 /* tunable == 2^n - 1 */ + +/* + * Hash creation functions. + */ + +static HashEntry** +alloc_array(CkCapiHash* ht, size_t max) +{ + return calloc(sizeof(*(ht->array)) * (max + 1), 1); +} + +CkCapiHash* +ckcapi_hash_new() +{ + CkCapiHash* ht = malloc(sizeof(CkCapiHash)); + if(ht) + { + ht->count = 0; + ht->max = INITIAL_MAX; + ht->array = alloc_array(ht, ht->max); + if(!ht->array) + { + free(ht); + ht = NULL; + } + } + return ht; +} + +void +ckcapi_hash_free(CkCapiHash* ht) +{ + HashEntry* he; + HashEntry* next; + size_t i; + + for(i = 0; i < ht->max; ++i) + { + for(he = ht->array[i]; he; ) + { + next = he->next; + free(he); + he = next; + } + } + + if(ht->array) + free(ht->array); + free(ht); +} + +/* + * Expanding a hash table + */ +static int +expand_array(CkCapiHash* ht) +{ + HashEntry** new_array; + size_t new_max; + HashEntry* he; + size_t i; + + new_max = ht->max * 2 + 1; + new_array = alloc_array(ht, new_max); + + if(!new_array) + return 0; + + for(i = 0; i < ht->max; ++i) + { + for(he = ht->array[i]; he; he = he->next) + { + unsigned int i = he->hash & new_max; + he->next = new_array[i]; + new_array[i] = he; + } + } + + if(ht->array) + free(ht->array); + + ht->array = new_array; + ht->max = new_max; + return 1; +} + +/* + * This is where we keep the details of the hash function and control + * the maximum collision rate. + * + * If val is non-NULL it creates and initializes a new hash entry if + * there isn't already one there; it returns an updatable pointer so + * that hash entries can be removed. + */ + +static HashEntry** +find_entry(CkCapiHash* ht, const void* key, size_t klen, const void* val) +{ + HashEntry** hep; + HashEntry* he; + const unsigned char* p; + unsigned int hash; + size_t i; + + /* + * This is the popular `times 33' hash algorithm which is used by + * perl and also appears in Berkeley DB. This is one of the best + * known hash functions for strings because it is both computed + * very fast and distributes very well. + * + * The originator may be Dan Bernstein but the code in Berkeley DB + * cites Chris Torek as the source. The best citation I have found + * is "Chris Torek, Hash function for text in C, Usenet message + * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich + * Salz's USENIX 1992 paper about INN which can be found at + * <http://citeseer.nj.nec.com/salz92internetnews.html>. + * + * The magic of number 33, i.e. why it works better than many other + * constants, prime or not, has never been adequately explained by + * anyone. So I try an explanation: if one experimentally tests all + * multipliers between 1 and 256 (as I did while writing a low-level + * data structure library some time ago) one detects that even + * numbers are not useable at all. The remaining 128 odd numbers + * (except for the number 1) work more or less all equally well. + * They all distribute in an acceptable way and this way fill a hash + * table with an average percent of approx. 86%. + * + * If one compares the chi^2 values of the variants (see + * Bob Jenkins ``Hashing Frequently Asked Questions'' at + * http://burtleburtle.net/bob/hash/hashfaq.html for a description + * of chi^2), the number 33 not even has the best value. But the + * number 33 and a few other equally good numbers like 17, 31, 63, + * 127 and 129 have nevertheless a great advantage to the remaining + * numbers in the large set of possible multipliers: their multiply + * operation can be replaced by a faster operation based on just one + * shift plus either a single addition or subtraction operation. And + * because a hash function has to both distribute good _and_ has to + * be very fast to compute, those few numbers should be preferred. + * + * -- Ralf S. Engelschall <rse@engelschall.com> + */ + + hash = 0; + for(p = key, i = klen; i; i--, p++) + hash = hash * 33 + *p; + + /* scan linked list */ + for(hep = &ht->array[hash & ht->max], he = *hep; + he; hep = &he->next, he = *hep) + { + if(he->hash == hash && he->klen == klen && + memcmp(KEY_DATA(he), key, klen) == 0) + break; + } + + if(he || !val) + return hep; + + /* add a new entry for non-NULL val */ + he = malloc(sizeof(*he)); + if(he) + { + /* Key points to external data */ + he->key = key; + he->klen = klen; + + he->next = NULL; + he->hash = hash; + he->val = val; + + *hep = he; + ht->count++; + } + + return hep; +} + +void* +ckcapi_hash_get(CkCapiHash* ht, const void *key, size_t klen) +{ + HashEntry** he = find_entry(ht, key, klen, NULL); + if(he && *he) + return (void*)((*he)->val); + else + return NULL; +} + +int +ckcapi_hash_set(CkCapiHash* ht, const void* key, size_t klen, void* val) +{ + HashEntry** hep = find_entry(ht, key, klen, val); + if(hep && *hep) + { + /* replace entry */ + (*hep)->val = val; + + /* check that the collision rate isn't too high */ + if(ht->count > ht->max) + { + if(!expand_array(ht)) + return 0; + } + + return 1; + } + + return 0; +} + +void* +ckcapi_hash_rem(CkCapiHash* ht, const void* key, size_t klen) +{ + HashEntry** hep = find_entry(ht, key, klen, NULL); + void* val = NULL; + + if(hep && *hep) + { + HashEntry* old = *hep; + *hep = (*hep)->next; + --ht->count; + val = (void*)old->val; + free(old); + } + + return val; +} + +size_t +ckcapi_hash_count(CkCapiHash* ht) +{ + return ht->count; +} diff --git a/ckcapi-util.h b/ckcapi-util.h index b37ea39..ea3d5e2 100644 --- a/ckcapi-util.h +++ b/ckcapi-util.h @@ -5,13 +5,6 @@ #include <stdlib.h> /* -------------------------------------------------------------------------------- - * WINDOWS - */ - -CK_RV ckcapi_util_win_to_cryptoki_err (DWORD werr); - - -/* -------------------------------------------------------------------------------- * ARRAYS */ @@ -20,27 +13,42 @@ typedef struct _Array void* data; size_t len; } -Array; +CkCapiArray; -#define ckcapi_util_array_append(a,v) \ - ckcapi_util_array_append_vals(a, &(v), 1) -#define ckcapi_util_array_index(a,t,i) \ +#define ckcapi_array_append(a,v) \ + ckcapi_array_append_vals(a, &(v), 1) +#define ckcapi_array_index(a,t,i) \ (((t*) (a)->data) [(i)]) -Array* ckcapi_util_array_new (int zero_terminated, int zero, +CkCapiArray* ckcapi_array_new (int zero_terminated, int zero, size_t element_size); -Array* ckcapi_util_array_sized_new (int zero_terminated, int zero, +CkCapiArray* ckcapi_array_sized_new (int zero_terminated, int zero, size_t element_size, size_t reserved_size); -void* ckcapi_util_array_free (Array* array, int free_segment); +void* ckcapi_array_free (CkCapiArray* array, int free_segment); -int ckcapi_util_array_append_vals (Array* array, const void* data, +int ckcapi_array_append_vals (CkCapiArray* array, const void* data, size_t num); -void ckcapi_util_array_remove_index (Array* array, unsigned int index); +void ckcapi_array_remove_index (CkCapiArray* array, unsigned int index); -void ckcapi_util_array_remove_range (Array* array, unsigned int index, +void ckcapi_array_remove_range (CkCapiArray* array, unsigned int index, size_t count); + +/* -------------------------------------------------------------------------------- + * HASHTABLE + */ + +struct _CkCapiHash; +typedef struct _CkCapiHash CkCapiHash; + +CkCapiHash* ckcapi_hash_new(); +void ckcapi_hash_free(CkCapiHash* ht); +size_t ckcapi_hash_count(CkCapiHash* ht); +void* ckcapi_hash_get(CkCapiHash* ht, const void* key, size_t klen); +int ckcapi_hash_set(CkCapiHash* ht, const void* key, size_t klen, void* val); +void* ckcapi_hash_rem(CkCapiHash* ht, const void* key, size_t klen); + #endif /* __CKCAPI_UTIL_H__ */
\ No newline at end of file diff --git a/cryptoki-capi.c b/ckcapi.c index b100e25..971b034 100644 --- a/cryptoki-capi.c +++ b/ckcapi.c @@ -3,7 +3,7 @@ #include <stdarg.h> #include <stdio.h> -#include "cryptoki-capi.h" +#include "ckcapi.h" /* ------------------------------------------------------------------- * GLOBALS / DEFINES @@ -371,7 +371,7 @@ static CK_RV CC_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR application, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR session) { - Session* sess; + CkCapiSession* sess; CK_RV ret; ENTER(C_OpenSession); @@ -405,14 +405,14 @@ CC_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR application, static CK_RV CC_C_CloseSession(CK_SESSION_HANDLE session) { - Session* sess; + CkCapiSession* sess; CK_RV ret; ENTER(C_CloseSession); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); /* The 'remove' flag removes it from the main session list */ - ret = ckcapi_session_find_lock_ref(session, 1, &sess); + ret = ckcapi_session_get_lock_ref(session, 1, &sess); if(ret == CKR_OK) { /* This will unref and possibly destroy the session */ @@ -576,11 +576,29 @@ static CK_RV CC_C_GetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR templ, CK_ULONG count) { + CkCapiSession* sess; + CkCapiObjectData objdata; + CK_RV ret; + ENTER(C_GetAttributeValue); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(object, CKR_OBJECT_HANDLE_INVALID); + PREREQ(!count || templ, CKR_ARGUMENTS_BAD); + + ret = ckcapi_session_get_lock_ref(session, 0, &sess); + if(ret == CKR_OK) + { + ret = ckcapi_object_load_data_for(sess, object, &objdata); + if(ret == CKR_OK) + { + ret = ckcapi_object_data_get_attrs(&objdata, templ, count); + ckcapi_object_data_release(&objdata); + } - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); } static CK_RV @@ -598,17 +616,17 @@ static CK_RV CC_C_FindObjectsInit(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR templ, CK_ULONG count) { - Session* sess; + CkCapiSession* sess; CK_RV ret; ENTER(C_FindObjectsInit); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); PREREQ(!count || templ, CKR_ARGUMENTS_BAD); - ret = ckcapi_session_find_lock_ref(session, 0, &sess); + ret = ckcapi_session_get_lock_ref(session, 0, &sess); if(ret == CKR_OK) { - ret = ckcapi_object_find_init(sess, templ, count); + ret = ckcapi_session_find_init(sess, templ, count); ckcapi_session_unref_unlock(sess); } @@ -619,7 +637,7 @@ static CK_RV CC_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects, CK_ULONG max_object_count, CK_ULONG_PTR object_count) { - Session* sess; + CkCapiSession* sess; CK_RV ret; ENTER(C_FindObjects); @@ -627,10 +645,10 @@ CC_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects, PREREQ(object_count, CKR_ARGUMENTS_BAD); PREREQ(!max_object_count || objects, CKR_ARGUMENTS_BAD); - ret = ckcapi_session_find_lock_ref(session, 0, &sess); + ret = ckcapi_session_get_lock_ref(session, 0, &sess); if(ret == CKR_OK) { - ret = ckcapi_object_find(sess, objects, max_object_count, object_count); + ret = ckcapi_session_find(sess, objects, max_object_count, object_count); ckcapi_session_unref_unlock(sess); } @@ -640,16 +658,16 @@ CC_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects, static CK_RV CC_C_FindObjectsFinal(CK_SESSION_HANDLE session) { - Session* sess; + CkCapiSession* sess; CK_RV ret; ENTER(C_FindObjectsFinal); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - ret = ckcapi_session_find_lock_ref(session, 0, &sess); + ret = ckcapi_session_get_lock_ref(session, 0, &sess); if(ret == CKR_OK) { - ret = ckcapi_objects_find_final(sess); + ret = ckcapi_session_find_final(sess); ckcapi_session_unref_unlock(sess); } diff --git a/cryptoki-capi.dsp b/ckcapi.dsp index 6f93ed3..a5b73e8 100644 --- a/cryptoki-capi.dsp +++ b/ckcapi.dsp @@ -8,12 +8,12 @@ CFG=cryptoki_capi - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "cryptoki-capi.mak". +!MESSAGE NMAKE /f "ckcapi.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "cryptoki-capi.mak" CFG="cryptoki_capi - Win32 Debug" +!MESSAGE NMAKE /f "ckcapi.mak" CFG="cryptoki_capi - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE @@ -90,19 +90,23 @@ LINK32=link.exe # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File +SOURCE=".\ckcapi-cert.c" +# End Source File +# Begin Source File + SOURCE=".\ckcapi-object.c" # End Source File # Begin Source File -SOURCE=".\ckcapi-util.c" +SOURCE=".\ckcapi-session.c" # End Source File # Begin Source File -SOURCE=".\cryptoki-capi-session.c" +SOURCE=".\ckcapi-util.c" # End Source File # Begin Source File -SOURCE=".\cryptoki-capi.c" +SOURCE=.\ckcapi.c # End Source File # End Group # Begin Group "Header Files" @@ -110,11 +114,11 @@ SOURCE=".\cryptoki-capi.c" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File -SOURCE=".\cryptoki-capi-util.h" +SOURCE=".\ckcapi-util.h" # End Source File # Begin Source File -SOURCE=".\cryptoki-capi.h" +SOURCE=.\ckcapi.h # End Source File # Begin Source File diff --git a/cryptoki-capi.dsw b/ckcapi.dsw index 7f71040..7f71040 100644 --- a/cryptoki-capi.dsw +++ b/ckcapi.dsw diff --git a/ckcapi.h b/ckcapi.h new file mode 100644 index 0000000..6442a8d --- /dev/null +++ b/ckcapi.h @@ -0,0 +1,160 @@ +#ifndef CKCAPI_H +#define CKCAPI_H + +#ifndef ASSERT +#include "assert.h" +#define ASSERT assert +#endif + +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x400 +#include <windows.h> + +#define CRYPTOKI_EXPORTS +#include "pkcs11/cryptoki.h" + +#include "ckcapi-util.h" + +struct _CkCapiObject; +struct _CkCapiSession; + +/* ------------------------------------------------------------------ + * cryptoki-capi.c + */ + +#define DBG(args) \ + ckcapi_debug args + +void ckcapi_debug(const char* msg, ...); +void ckcapi_lock_global(void); +void ckcapi_unlock_global(void); +CK_RV ckcapi_winerr_to_ckr (DWORD werr); + +/* ------------------------------------------------------------------ + * cryptoki-capi-session.c + */ + +/* For operation_type in CkCapiSession */ +enum +{ + OPERATION_NONE = 0, + OPERATION_FIND = 1, +}; + +typedef void (*CkCapiSessionCancel) (struct _CkCapiSession* sess); + +typedef struct _CkCapiSession +{ + CK_ULONG id; /* Unique ID for this session */ + int in_call; /* Whether this session is use in PKCS#11 function */ + + int operation_type; /* Whether an operation is happening or not */ + void* operation_data; /* Data for this operation */ + CkCapiSessionCancel operation_cancel; /* Callback to cancel operation when necessary */ + + CK_NOTIFY notify_callback; /* Application specified callback */ + CK_VOID_PTR user_data; /* Argument for above */ + + int refs; /* Reference count */ + HANDLE mutex; /* Mutex for protecting this structure */ +} +CkCapiSession; + +#define DBGS(sess, msg) \ + ckcapi_debug("S%d: %s", (sess) ? (sess)->id : 0, (msg)) + +CkCapiSession* ckcapi_session_create(void); +void ckcapi_session_destroy(CkCapiSession* sess); +CK_RV ckcapi_session_register(CkCapiSession* sess); +CK_RV ckcapi_session_get_lock_ref(CK_ULONG id, int remove, CkCapiSession **sess); +void ckcapi_session_unref_unlock(CkCapiSession* sess); +void ckcapi_session_close_all(); + +CK_RV ckcapi_session_find_init (CkCapiSession* sess, CK_ATTRIBUTE_PTR templ, CK_ULONG count); +CK_RV ckcapi_session_find (CkCapiSession* sess, CK_OBJECT_HANDLE_PTR objects, + CK_ULONG max_object_count, CK_ULONG_PTR object_count); +CK_RV ckcapi_session_find_final (CkCapiSession* sess); + + + +/* ------------------------------------------------------------------ + * ckcapi-object.c + */ + +typedef CK_RV (*CkCapiGetAttribute)(void* obj, CK_ATTRIBUTE_TYPE type, + CK_VOID_PTR data, CK_ULONG_PTR len); + +typedef void (*CkCapiRelease)(void* value); + +typedef struct _CkCapiObjectDataVtable +{ + CkCapiGetAttribute get_bool; + CkCapiGetAttribute get_ulong; + CkCapiGetAttribute get_bytes; + CkCapiGetAttribute get_date; + CkCapiRelease release; +} +CkCapiObjectDataVtable; + +typedef struct _CkCapiObjectData +{ + void* data; + CkCapiObjectDataVtable data_funcs; +} +CkCapiObjectData; + +typedef CK_RV (*CkCapiLoadData)(struct _CkCapiObject* obj, CkCapiObjectData* objdata); + +typedef struct _CkCapiObjectVtable +{ + CkCapiLoadData load_data; + CkCapiRelease release; +} +CkCapiObjectVtable; + +typedef struct _CkCapiObject +{ + CK_OBJECT_HANDLE id; + void* unique_key; + size_t unique_len; + CkCapiObjectVtable obj_funcs; + CkCapiObjectDataVtable data_funcs; +} +CkCapiObject; + +#define DBGO(obj, msg) \ + ckcapi_debug("O%d: %s", (obj) ? (obj)->id : 0, (msg)) + +CkCapiObject* ckcapi_object_lookup (CkCapiSession* sess, CK_OBJECT_HANDLE obj); + +CK_RV ckcapi_object_register (CkCapiSession* sess, CkCapiObject* obj); + +CK_RV ckcapi_object_load_data (CkCapiObject* obj, CkCapiObjectData* objdata); + +CK_RV ckcapi_object_load_data_for (CkCapiSession* sess, CK_OBJECT_HANDLE hand, + CkCapiObjectData* objdata); + +CK_BBOOL ckcapi_object_data_match (CkCapiObjectData* objdata, + CK_ATTRIBUTE_PTR matches, CK_ULONG count); + +CK_BBOOL ckcapi_object_data_match_attr (CkCapiObjectData* objdata, + CK_ATTRIBUTE_PTR match); + +CK_RV ckcapi_object_data_get_attrs (CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs, + CK_ULONG count); + +void ckcapi_object_data_release (CkCapiObjectData* objdata); + +/* ------------------------------------------------------------------- + * ckcapi-cert.c + */ + +CK_RV ckcapi_cert_find_all (CkCapiSession* sess, CK_ATTRIBUTE_PTR match, + CK_ULONG count, CkCapiArray* arr); + +CK_RV ckcapi_cert_find_in_store (CkCapiSession* sess, const char* store_name, + CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr); + + +#endif /* CRYPTOKI_CAPI_H */ + diff --git a/cryptoki-capi.h b/cryptoki-capi.h deleted file mode 100644 index a5dc9d5..0000000 --- a/cryptoki-capi.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef CRYPTOKI_CAPI_H -#define CRYPTOKI_CAPI_H - -#ifndef ASSERT -#include "assert.h" -#define ASSERT assert -#endif - -#define WIN32_LEAN_AND_MEAN -#define _WIN32_WINNT 0x400 -#include <windows.h> - -#define CRYPTOKI_EXPORTS -#include "pkcs11/cryptoki.h" - -#include "cryptoki-capi-util.h" - -struct _Object; -struct _Session; - -/* ------------------------------------------------------------------ - * cryptoki-capi.c - */ - -#define DBG(args) \ - ckcapi_debug args - -void ckcapi_debug(const char* msg, ...); -void ckcapi_lock_global(void); -void ckcapi_unlock_global(void); -CK_RV ckcapi_winerr_to_ckr (DWORD werr); - -/* ------------------------------------------------------------------ - * cryptoki-capi-session.c - */ - -/* For operation_type in Session */ -enum -{ - OPERATION_NONE = 0, - OPERATION_FIND = 1, -}; - -typedef void (*SessionCancel) (struct _Session* sess); - -typedef struct _Session -{ - CK_ULONG id; /* Unique ID for this session */ - int in_call; /* Whether this session is use in PKCS#11 function */ - - int operation_type; /* Whether an operation is happening or not */ - void* operation_data; /* Data for this operation */ - SessionCancel operation_cancel; /* Callback to cancel operation when necessary */ - - CK_NOTIFY notify_callback; /* Application specified callback */ - CK_VOID_PTR user_data; /* Argument for above */ - - int refs; /* Reference count */ - HANDLE mutex; /* Mutex for protecting this structure */ -} -Session; - -#define DBGS(sess, msg) \ - ckcapi_debug("S%d: %s", (sess) ? (sess)->id : 0, (msg)) - -Session* ckcapi_session_create(void); -void ckcapi_session_destroy(Session* sess); -CK_RV ckcapi_session_register(Session* sess); -CK_RV ckcapi_session_find_lock_ref(CK_ULONG id, int remove, Session **sess); -void ckcapi_session_unref_unlock(Session* sess); -void ckcapi_session_close_all(); - - -/* ------------------------------------------------------------------ - * cryptoki-capi-object.c - */ - -typedef struct _Object -{ - CK_ULONG id; /* Unique ID for this object */ - - CK_ATTRIBUTE_PTR attrs; /* All the attributes of this object */ - CK_ULONG n_attrs; /* Number of attributes */ -} -Object; - -/* -Object* ckcapi_object_create(Session* sess, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs); -void ckcapi_object_destroy(Session* sess, Object* obj); -*/ - -CK_RV ckcapi_object_find_init (Session* sess, CK_ATTRIBUTE_PTR templ, CK_ULONG count); -CK_RV ckcapi_object_find (Session* sess, CK_OBJECT_HANDLE_PTR objects, - CK_ULONG max_object_count, CK_ULONG_PTR object_count); -CK_RV ckcapi_objects_find_final (Session* sess); - - -#endif /* CRYPTOKI_CAPI_H */ - |