From 4928a4bff079c140d261cb3fefdc07c60c0bdebf Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Fri, 27 Apr 2007 20:37:40 +0000 Subject: A bunch more changes, that implement almost complete find and get support. --- ckcapi-cert.c | 456 ++++++++++----------- ckcapi-object.c | 744 ++++++++++++---------------------- ckcapi-session.c | 168 +++++++- ckcapi-util.c | 336 +++++++++++++-- ckcapi-util.h | 42 +- ckcapi.c | 1167 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ckcapi.dsp | 149 +++++++ ckcapi.dsw | 29 ++ ckcapi.h | 160 ++++++++ cryptoki-capi.c | 1149 ---------------------------------------------------- cryptoki-capi.dsp | 145 ------- cryptoki-capi.dsw | 29 -- cryptoki-capi.h | 99 ----- 13 files changed, 2462 insertions(+), 2211 deletions(-) create mode 100644 ckcapi.c create mode 100644 ckcapi.dsp create mode 100644 ckcapi.dsw create mode 100644 ckcapi.h delete mode 100644 cryptoki-capi.c delete mode 100644 cryptoki-capi.dsp delete mode 100644 cryptoki-capi.dsw delete mode 100644 cryptoki-capi.h 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 +#include + +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)) @@ -135,218 +140,6 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type, return copy_static_data(data, len, &val, sizeof(CK_ULONG)); } -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) @@ -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 #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, @@ -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 -#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 +#include #include - - - #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 + */ + +/* 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 + * . + * + * 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 + */ + + 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 @@ -4,13 +4,6 @@ #include -/* -------------------------------------------------------------------------------- - * 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/ckcapi.c b/ckcapi.c new file mode 100644 index 0000000..971b034 --- /dev/null +++ b/ckcapi.c @@ -0,0 +1,1167 @@ + +#include +#include +#include + +#include "ckcapi.h" + +/* ------------------------------------------------------------------- + * GLOBALS / DEFINES + */ + +/* TODO: Use a random number */ +static CK_ULONG slot_id = 33; +static int cryptoki_initialized = 0; +static HANDLE global_mutex = NULL; + +#define CRYPTOKI_VERSION_MAJOR 2 +#define CRYPTOKI_VERSION_MINOR 11 +#define MANUFACTURER_ID "Cryptoki CAPI " +#define LIBRARY_DESCRIPTION "Cryptoki CAPI Provider " +#define LIBRARY_VERSION_MAJOR 1 +#define LIBRARY_VERSION_MINOR 1 +#define SLOT_DESCRIPTION "Windows CAPI Certificates and Keys " +#define HARDWARE_VERSION_MAJOR 0 +#define HARDWARE_VERSION_MINOR 0 +#define FIRMWARE_VERSION_MAJOR 0 +#define FIRMWARE_VERSION_MINOR 0 +#define SLOT_TOKEN_SERIAL "1.0 " +#define SLOT_TOKEN_MODEL "1.0 " +#define MAX_PIN_LEN 256 +#define MIN_PIN_LEN 1 + +/* ------------------------------------------------------------------- + * MODULE GLOBAL FUNCTIONS + */ + +void +ckcapi_debug(const char* msg, ...) +{ + char buf[1024]; + va_list va; + + va_start(va, msg); + _vsnprintf(buf, 1024, msg, va); + va_end(va); + + OutputDebugStringA(buf); +} + +/* Bah humbug, MSVC doesn't have __func__ */ +#define ENTER(func) \ + char* _func = #func; \ + ckcapi_debug("%s: enter", _func) + +#define RETURN(ret) \ + return (ckcapi_debug("%s: %d", _func, ret), ret) + +#define PREREQ(cond, ret) \ + if (!(cond)) { ckcapi_debug("%s: %s failed: %d", _func, #cond, ret); return ret; } + +void +ckcapi_lock_global(void) +{ + DWORD r; + + ASSERT(global_mutex); + + r = WaitForSingleObject(global_mutex, INFINITE); + ASSERT(r == WAIT_OBJECT_0); +} + +void +ckcapi_unlock_global(void) +{ + BOOL r; + + ASSERT(global_mutex); + + r = ReleaseMutex(global_mutex); + ASSERT(r); +} + +CK_RV +ckcapi_winerr_to_ckr(DWORD werr) +{ + switch(werr) + { + case ERROR_NOT_ENOUGH_MEMORY: + return CKR_HOST_MEMORY; + break; + case NTE_NO_MEMORY: + return CKR_DEVICE_MEMORY; + break; + case ERROR_MORE_DATA: + return CKR_BUFFER_TOO_SMALL; + case ERROR_INVALID_PARAMETER: /* these params were derived from the */ + case ERROR_INVALID_HANDLE: /* inputs, so if they are bad, the input */ + case NTE_BAD_ALGID: /* data is bad */ + case NTE_BAD_HASH: + return CKR_DATA_INVALID; + break; + case ERROR_BUSY: + case NTE_FAIL: + case NTE_BAD_UID: + return CKR_DEVICE_ERROR; + break; + default: + return CKR_GENERAL_ERROR; + }; +} + + +/* ---------------------------------------------------------------- */ + +static CK_RV +CC_C_Initialize(CK_VOID_PTR init_args) +{ + ENTER(C_Initialize); + PREREQ(!cryptoki_initialized, CKR_CRYPTOKI_ALREADY_INITIALIZED); + + if (init_args != NULL) { + CK_C_INITIALIZE_ARGS_PTR args; + int supplied_ok; + + /* pReserved must be NULL */ + args = init_args; + PREREQ(!args->pReserved, CKR_ARGUMENTS_BAD); + + /* ALL supplied function pointers need to have the value either NULL or non-NULL. */ + supplied_ok = (args->CreateMutex == NULL && args->DestroyMutex == NULL && + args->LockMutex == NULL && args->UnlockMutex == NULL) || + (args->CreateMutex != NULL && args->DestroyMutex != NULL && + args->LockMutex != NULL && args->UnlockMutex != NULL); + PREREQ(supplied_ok, CKR_ARGUMENTS_BAD); + + /* + * When the CKF_OS_LOCKING_OK flag isn't set and mutex function pointers are supplied + * by an application, return an error. DBus must be able to use its own locks. + */ + if(!(args->flags & CKF_OS_LOCKING_OK) && (args->CreateMutex != NULL)) + RETURN(CKR_CANT_LOCK); + } + + if(!global_mutex) + { + global_mutex = CreateMutex(NULL, FALSE, NULL); + if(!global_mutex) + RETURN(CKR_CANT_LOCK); + } + + cryptoki_initialized = 1; + + RETURN(CKR_OK); +} + +static CK_RV +CC_C_Finalize(CK_VOID_PTR pReserved) +{ + ENTER(C_Finalize); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + cryptoki_initialized = 0; + + RETURN(CKR_OK); +} + +static CK_RV +CC_C_GetInfo(CK_INFO_PTR info) +{ + ENTER(C_GetInfo); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(info, CKR_ARGUMENTS_BAD); + + ASSERT(strlen(MANUFACTURER_ID) == 32); + ASSERT(strlen(LIBRARY_DESCRIPTION) == 32); + + info->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; + info->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; + info->libraryVersion.major = LIBRARY_VERSION_MAJOR; + info->libraryVersion.minor = LIBRARY_VERSION_MINOR; + info->flags = 0; + strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32); + strncpy((char*)info->libraryDescription, LIBRARY_DESCRIPTION, 32); + + RETURN(CKR_OK); +} + +static CK_RV +CC_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list) +{ + /* This would be a strange call to receive */ + return C_GetFunctionList(list); +} + +static CK_RV +CC_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count) +{ + ENTER(C_GetSlotList); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(count, CKR_ARGUMENTS_BAD); + + /* Token is always present */ + + /* Application only wants to know the number of slots. */ + if(slot_list == NULL) + { + *count = 1; + RETURN(CKR_OK); + } + + if((*count < 1) && (slot_list != NULL)) + { + *count = 1; + RETURN(CKR_BUFFER_TOO_SMALL); + } + + *count = 1; + slot_list[0] = slot_id; + RETURN(CKR_OK); +} + +static CK_RV +CC_C_GetSlotInfo(CK_SLOT_ID id, CK_SLOT_INFO_PTR info) +{ + ENTER(C_GetSlotInfo); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(info, CKR_ARGUMENTS_BAD); + + /* Make sure the slot ID is valid */ + if(id != slot_id) + RETURN(CKR_SLOT_ID_INVALID); + + ASSERT(strlen(SLOT_DESCRIPTION) == 64); + ASSERT(strlen(MANUFACTURER_ID) == 32); + + /* Provide information about the slot in the provided buffer */ + strncpy((char*)info->slotDescription, SLOT_DESCRIPTION, 64); + strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32); + info->hardwareVersion.major = HARDWARE_VERSION_MAJOR; + info->hardwareVersion.minor = HARDWARE_VERSION_MINOR; + info->firmwareVersion.major = FIRMWARE_VERSION_MAJOR; + info->firmwareVersion.minor = FIRMWARE_VERSION_MINOR; + + /* Token is always present */ + info->flags = CKF_TOKEN_PRESENT; + + RETURN(CKR_OK); +} + +static CK_RV +CC_C_GetTokenInfo(CK_SLOT_ID id, CK_TOKEN_INFO_PTR info) +{ + ENTER(C_GetTokenInfo); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(info, CKR_ARGUMENTS_BAD); + + /* Make sure the slot ID is valid */ + if(id != slot_id) + RETURN(CKR_SLOT_ID_INVALID); + + ASSERT(strlen(SLOT_DESCRIPTION) == 64); + ASSERT(strlen(MANUFACTURER_ID) == 32); + ASSERT(strlen(SLOT_TOKEN_MODEL) == 16); + ASSERT(strlen(SLOT_TOKEN_SERIAL) == 16); + + /* Provide information about a token in the provided buffer */ + strncpy((char*)info->label, SLOT_DESCRIPTION, 32); + strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32); + strncpy((char*)info->model, SLOT_TOKEN_MODEL, 16); + strncpy((char*)info->serialNumber, SLOT_TOKEN_SERIAL, 16); + + /* Protected authentication path: Windows prompts for it's own PINs */ + info->flags = CKF_TOKEN_INITIALIZED | CKF_PROTECTED_AUTHENTICATION_PATH; + info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE; + info->ulSessionCount = CK_EFFECTIVELY_INFINITE; + info->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE; + info->ulRwSessionCount = CK_EFFECTIVELY_INFINITE; + info->ulMaxPinLen = MAX_PIN_LEN; + info->ulMinPinLen = MIN_PIN_LEN; + info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION; + info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION; + info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION; + info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; + info->hardwareVersion.major = HARDWARE_VERSION_MAJOR; + info->hardwareVersion.minor = HARDWARE_VERSION_MINOR; + info->firmwareVersion.major = FIRMWARE_VERSION_MAJOR; + info->firmwareVersion.minor = FIRMWARE_VERSION_MINOR; + memset(info->utcTime, ' ', 16); + + RETURN(CKR_OK); +} + +static CK_RV +CC_C_GetMechanismList(CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list, + CK_ULONG_PTR count) +{ + ENTER(C_GetMechanismList); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(count, CKR_ARGUMENTS_BAD); + + if(id != slot_id) + RETURN(CKR_SLOT_ID_INVALID); + + if(mechanism_list == NULL) + { + *count = 1; + RETURN(CKR_OK); + } + + if(*count < 1) + { + *count = 1; + RETURN(CKR_BUFFER_TOO_SMALL); + } + + mechanism_list[0] = CKM_RSA_PKCS; + *count = 1; + RETURN(CKR_OK); +} + +static CK_RV +CC_C_GetMechanismInfo(CK_SLOT_ID id, CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR info) +{ + ENTER(C_GetMechanismInfo); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(info, CKR_ARGUMENTS_BAD); + + if(id != slot_id) + RETURN(CKR_SLOT_ID_INVALID); + + /* unsupported mechanism */ + if(type != CKM_RSA_PKCS) + RETURN(CKR_MECHANISM_INVALID); + + info->ulMinKeySize = 384; + info->ulMaxKeySize = 16384; + info->flags = 0; /* TODO: Choose which we'll implement */ + RETURN(CKR_OK); +} + +static CK_RV +CC_C_InitToken(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len, + CK_UTF8CHAR_PTR label) +{ + ENTER(C_InitToken); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) +{ + ENTER(C_WaitForSlotEvent); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* + * PKCS#11 GRAY AREA: What happens when we know we'll *never* + * have any slot events, and someone calls us without CKR_DONT_BLOCK? + * In case there's a thread dedicated to calling this function in a + * loop, we wait 1 seconds when called without CKR_DONT_BLOCK. + */ + + if(!(flags & CKF_DONT_BLOCK)) + Sleep(1000); + + RETURN(CKR_NO_EVENT); +} + +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) +{ + CkCapiSession* sess; + CK_RV ret; + + ENTER(C_OpenSession); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + if(id != slot_id) + RETURN(CKR_SLOT_ID_INVALID); + + sess = ckcapi_session_create(); + if(sess == NULL) + RETURN(CKR_HOST_MEMORY); + + sess->notify_callback = notify; + sess->user_data = application; + + ret = ckcapi_session_register(sess); + if(ret == CKR_OK) + { + /* ID should have been assigned when registering */ + ASSERT(sess->id > 0); + *session = sess->id; + } + else + { + ckcapi_session_destroy(sess); + } + + RETURN(ret); +} + +static CK_RV +CC_C_CloseSession(CK_SESSION_HANDLE session) +{ + 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_get_lock_ref(session, 1, &sess); + if(ret == CKR_OK) + { + /* This will unref and possibly destroy the session */ + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); +} + +static CK_RV +CC_C_CloseAllSessions(CK_SLOT_ID id) +{ + ENTER(C_CloseAllSession); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + if(id != slot_id) + RETURN(CKR_SLOT_ID_INVALID); + + ckcapi_session_close_all(); + RETURN(CKR_OK); +} + +static CK_RV +CC_C_GetFunctionStatus(CK_SESSION_HANDLE session) +{ + ENTER(C_GetFunctionStatus); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + RETURN(CKR_FUNCTION_NOT_PARALLEL); +} + +static CK_RV +CC_C_CancelFunction(CK_SESSION_HANDLE session) +{ + ENTER(C_CancelFunction); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + RETURN(CKR_FUNCTION_NOT_PARALLEL); +} + +static CK_RV +CC_C_GetSessionInfo(CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info) +{ + ENTER(C_GetSessionInfo); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + // TODO: Implement + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_InitPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR pin, + CK_ULONG pin_len) +{ + ENTER(C_InitPIN); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* We don't support this stuff. We don't support 'SO' logins. */ + RETURN(CKR_USER_NOT_LOGGED_IN); +} + +static CK_RV +CC_C_SetPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR old_pin, + CK_ULONG old_len, CK_UTF8CHAR_PTR new_pin, CK_ULONG new_len) +{ + ENTER(C_SetPIN); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Not supported, Windows takes care of this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_GetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state, + CK_ULONG_PTR operation_state_len) +{ + ENTER(C_GetOperationState); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Nasty, no sirrr */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_SetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state, + CK_ULONG operation_state_len, CK_OBJECT_HANDLE encryption_key, + CK_OBJECT_HANDLE authentication_key) +{ + ENTER(C_SetOperationState); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Nasty, no sirrr */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_Login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type, + CK_UTF8CHAR_PTR pin, CK_ULONG pin_len) +{ + ENTER(C_Login); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement our local concept of logged in */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_Logout(CK_SESSION_HANDLE session) +{ + ENTER(C_Logout); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement our local concept of logged in */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_CreateObject(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR templ, + CK_ULONG count, CK_OBJECT_HANDLE_PTR object) +{ + ENTER(C_CreateObject); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to support this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_CopyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR templ, CK_ULONG count, + CK_OBJECT_HANDLE_PTR new_object) +{ + ENTER(C_CopyObject); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to support this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + + +static CK_RV +CC_C_DestroyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) +{ + ENTER(C_DestroyObject); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to support this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_GetObjectSize(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, + CK_ULONG_PTR size) +{ + ENTER(C_GetObjectSize); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +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); + } + + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); +} + +static CK_RV +CC_C_SetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR templ, CK_ULONG count) +{ + ENTER(C_SetAttributeValue); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_FindObjectsInit(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR templ, + CK_ULONG count) +{ + CkCapiSession* sess; + CK_RV ret; + + ENTER(C_FindObjectsInit); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(!count || templ, CKR_ARGUMENTS_BAD); + + ret = ckcapi_session_get_lock_ref(session, 0, &sess); + if(ret == CKR_OK) + { + ret = ckcapi_session_find_init(sess, templ, count); + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); +} + +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) +{ + CkCapiSession* sess; + CK_RV ret; + + ENTER(C_FindObjects); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + PREREQ(object_count, CKR_ARGUMENTS_BAD); + PREREQ(!max_object_count || objects, CKR_ARGUMENTS_BAD); + + ret = ckcapi_session_get_lock_ref(session, 0, &sess); + if(ret == CKR_OK) + { + ret = ckcapi_session_find(sess, objects, max_object_count, object_count); + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); +} + +static CK_RV +CC_C_FindObjectsFinal(CK_SESSION_HANDLE session) +{ + CkCapiSession* sess; + CK_RV ret; + + ENTER(C_FindObjectsFinal); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + ret = ckcapi_session_get_lock_ref(session, 0, &sess); + if(ret == CKR_OK) + { + ret = ckcapi_session_find_final(sess); + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); +} + +static CK_RV +CC_C_EncryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + ENTER(C_EncryptInit); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_Encrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, + CK_BYTE_PTR encrypted_data, CK_ULONG_PTR encrypted_data_len) +{ + ENTER(C_Encrypt); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_EncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, + CK_ULONG part_len, CK_BYTE_PTR encrypted_part, + CK_ULONG_PTR encrypted_part_len) +{ + ENTER(C_EncryptUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_EncryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_encrypted_part, + CK_ULONG_PTR last_encrypted_part_len) +{ + ENTER(C_EncryptFinal); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DecryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + ENTER(C_DecryptInit); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_Decrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_data, + CK_ULONG encrypted_data_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len) +{ + ENTER(C_Decrypt); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DecryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part, + CK_ULONG encrypted_part_len, CK_BYTE_PTR part, CK_ULONG_PTR part_len) +{ + ENTER(C_DecryptUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DecryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR pLastPart, + CK_ULONG_PTR last_part_len) +{ + ENTER(C_DecryptFinal); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DigestInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism) +{ + ENTER(C_DigestInit); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_Digest(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, + CK_BYTE_PTR digest, CK_ULONG_PTR digest_len) +{ + ENTER(C_Digest); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) +{ + ENTER(C_DigestUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DigestKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) +{ + ENTER(C_DigestKey); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DigestFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR digest, + CK_ULONG_PTR digest_len) +{ + ENTER(C_DigestFinal); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_SignInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + ENTER(C_SignInit); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_Sign(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, + CK_BYTE_PTR signature, CK_ULONG_PTR signature_len) +{ + ENTER(C_Sign); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_SignUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) +{ + ENTER(C_SignUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_SignFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, + CK_ULONG_PTR signature_len) +{ + ENTER(C_SignFinal); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_SignRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + ENTER(C_SignRecoverInit); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_SignRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, + CK_BYTE_PTR signature, CK_ULONG_PTR signature_len) +{ + ENTER(C_SignRecover); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: Implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_VerifyInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + ENTER(C_VerifyInit); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_Verify(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, + CK_BYTE_PTR signature, CK_ULONG signature_len) +{ + ENTER(C_Verify); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_VerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) +{ + ENTER(C_VerifyUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_VerifyFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, + CK_ULONG signature_len) +{ + ENTER(C_VerifyFinal); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_VerifyRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + ENTER(C_VerifyRecoverInit); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_VerifyRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, + CK_ULONG signature_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len) +{ + ENTER(C_VerifyRecover); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DigestEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, + CK_ULONG part_len, CK_BYTE_PTR encrypted_part, + CK_ULONG_PTR encrypted_part_len) +{ + ENTER(C_DigestEncryptUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DecryptDigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part, + CK_ULONG encrypted_part_len, CK_BYTE_PTR part, + CK_ULONG_PTR part_len) +{ + ENTER(C_DecryptDigestUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_SignEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, + CK_ULONG part_len, CK_BYTE_PTR encrypted_part, + CK_ULONG_PTR encrypted_part_len) +{ + ENTER(C_SignEncryptUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DecryptVerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part, + CK_ULONG encrypted_part_len, CK_BYTE_PTR part, + CK_ULONG_PTR part_len) +{ + ENTER(C_DecryptVerifyUpdate); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_GenerateKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_ATTRIBUTE_PTR templ, CK_ULONG count, + CK_OBJECT_HANDLE_PTR key) +{ + ENTER(C_GenerateKey); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Let key generation happen via Windows interfaces */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_GenerateKeyPair(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_ATTRIBUTE_PTR public_key_template, CK_ULONG public_key_attribute_count, + CK_ATTRIBUTE_PTR private_key_template, CK_ULONG private_key_attribute_count, + CK_OBJECT_HANDLE_PTR public_key, CK_OBJECT_HANDLE_PTR private_key) +{ + ENTER(C_GenerateKeyPair); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Let key generation happen via Windows interfaces */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_WrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key, + CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len) +{ + ENTER(C_WrapKey); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_UnwrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE unwrapping_key, CK_BYTE_PTR wrapped_key, + CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR templ, + CK_ULONG count, CK_OBJECT_HANDLE_PTR key) +{ + ENTER(C_UnwrapKey); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* TODO: See if we need to implement this */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_DeriveKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR templ, + CK_ULONG count, CK_OBJECT_HANDLE_PTR key) +{ + ENTER(C_DeriveKey); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Can't do this with RSA */ + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_SeedRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR seed, CK_ULONG seed_len) +{ + ENTER(C_SeedRandom); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* + * TODO: Perhaps at some point in the future we may want + * to see if we can hook into the Windows RNG + */ + + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +CC_C_GenerateRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR random_data, + CK_ULONG random_len) +{ + ENTER(C_GenerateRandom); + PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + /* + * TODO: Perhaps at some point in the future we may want + * to see if we can hook into the Windows RNG + */ + + RETURN(CKR_FUNCTION_NOT_SUPPORTED); +} + +static struct CK_FUNCTION_LIST functionList = { + { 2, 11 }, /* version */ + CC_C_Initialize, + CC_C_Finalize, + CC_C_GetInfo, + CC_C_GetFunctionList, + CC_C_GetSlotList, + CC_C_GetSlotInfo, + CC_C_GetTokenInfo, + CC_C_GetMechanismList, + CC_C_GetMechanismInfo, + CC_C_InitToken, + CC_C_InitPIN, + CC_C_SetPIN, + CC_C_OpenSession, + CC_C_CloseSession, + CC_C_CloseAllSessions, + CC_C_GetSessionInfo, + CC_C_GetOperationState, + CC_C_SetOperationState, + CC_C_Login, + CC_C_Logout, + CC_C_CreateObject, + CC_C_CopyObject, + CC_C_DestroyObject, + CC_C_GetObjectSize, + CC_C_GetAttributeValue, + CC_C_SetAttributeValue, + CC_C_FindObjectsInit, + CC_C_FindObjects, + CC_C_FindObjectsFinal, + CC_C_EncryptInit, + CC_C_Encrypt, + CC_C_EncryptUpdate, + CC_C_EncryptFinal, + CC_C_DecryptInit, + CC_C_Decrypt, + CC_C_DecryptUpdate, + CC_C_DecryptFinal, + CC_C_DigestInit, + CC_C_Digest, + CC_C_DigestUpdate, + CC_C_DigestKey, + CC_C_DigestFinal, + CC_C_SignInit, + CC_C_Sign, + CC_C_SignUpdate, + CC_C_SignFinal, + CC_C_SignRecoverInit, + CC_C_SignRecover, + CC_C_VerifyInit, + CC_C_Verify, + CC_C_VerifyUpdate, + CC_C_VerifyFinal, + CC_C_VerifyRecoverInit, + CC_C_VerifyRecover, + CC_C_DigestEncryptUpdate, + CC_C_DecryptDigestUpdate, + CC_C_SignEncryptUpdate, + CC_C_DecryptVerifyUpdate, + CC_C_GenerateKey, + CC_C_GenerateKeyPair, + CC_C_WrapKey, + CC_C_UnwrapKey, + CC_C_DeriveKey, + CC_C_SeedRandom, + CC_C_GenerateRandom, + CC_C_GetFunctionStatus, + CC_C_CancelFunction, + CC_C_WaitForSlotEvent +}; + +__declspec(dllexport) CK_RV +C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list) +{ + if(!list) + return CKR_ARGUMENTS_BAD; + + *list = &functionList; + return CKR_OK; +} diff --git a/ckcapi.dsp b/ckcapi.dsp new file mode 100644 index 0000000..a5b73e8 --- /dev/null +++ b/ckcapi.dsp @@ -0,0 +1,149 @@ +# Microsoft Developer Studio Project File - Name="cryptoki_capi" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +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 "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 "ckcapi.mak" CFG="cryptoki_capi - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cryptoki_capi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cryptoki_capi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cryptoki_capi - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 + +!ELSEIF "$(CFG)" == "cryptoki_capi - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "cryptoki_capi - Win32 Release" +# Name "cryptoki_capi - Win32 Debug" +# Begin Group "Source Files" + +# 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-session.c" +# End Source File +# Begin Source File + +SOURCE=".\ckcapi-util.c" +# End Source File +# Begin Source File + +SOURCE=.\ckcapi.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=".\ckcapi-util.h" +# End Source File +# Begin Source File + +SOURCE=.\ckcapi.h +# End Source File +# Begin Source File + +SOURCE=.\pkcs11\cryptoki.h +# End Source File +# Begin Source File + +SOURCE=".\pkcs11\pkcs-11v2-20a3.h" +# End Source File +# Begin Source File + +SOURCE=.\pkcs11\pkcs11.h +# End Source File +# Begin Source File + +SOURCE=.\pkcs11\pkcs11f.h +# End Source File +# Begin Source File + +SOURCE=.\pkcs11\pkcs11t.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/ckcapi.dsw b/ckcapi.dsw new file mode 100644 index 0000000..7f71040 --- /dev/null +++ b/ckcapi.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cryptoki_capi"=".\cryptoki_capi.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + 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 + +#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.c b/cryptoki-capi.c deleted file mode 100644 index b100e25..0000000 --- a/cryptoki-capi.c +++ /dev/null @@ -1,1149 +0,0 @@ - -#include -#include -#include - -#include "cryptoki-capi.h" - -/* ------------------------------------------------------------------- - * GLOBALS / DEFINES - */ - -/* TODO: Use a random number */ -static CK_ULONG slot_id = 33; -static int cryptoki_initialized = 0; -static HANDLE global_mutex = NULL; - -#define CRYPTOKI_VERSION_MAJOR 2 -#define CRYPTOKI_VERSION_MINOR 11 -#define MANUFACTURER_ID "Cryptoki CAPI " -#define LIBRARY_DESCRIPTION "Cryptoki CAPI Provider " -#define LIBRARY_VERSION_MAJOR 1 -#define LIBRARY_VERSION_MINOR 1 -#define SLOT_DESCRIPTION "Windows CAPI Certificates and Keys " -#define HARDWARE_VERSION_MAJOR 0 -#define HARDWARE_VERSION_MINOR 0 -#define FIRMWARE_VERSION_MAJOR 0 -#define FIRMWARE_VERSION_MINOR 0 -#define SLOT_TOKEN_SERIAL "1.0 " -#define SLOT_TOKEN_MODEL "1.0 " -#define MAX_PIN_LEN 256 -#define MIN_PIN_LEN 1 - -/* ------------------------------------------------------------------- - * MODULE GLOBAL FUNCTIONS - */ - -void -ckcapi_debug(const char* msg, ...) -{ - char buf[1024]; - va_list va; - - va_start(va, msg); - _vsnprintf(buf, 1024, msg, va); - va_end(va); - - OutputDebugStringA(buf); -} - -/* Bah humbug, MSVC doesn't have __func__ */ -#define ENTER(func) \ - char* _func = #func; \ - ckcapi_debug("%s: enter", _func) - -#define RETURN(ret) \ - return (ckcapi_debug("%s: %d", _func, ret), ret) - -#define PREREQ(cond, ret) \ - if (!(cond)) { ckcapi_debug("%s: %s failed: %d", _func, #cond, ret); return ret; } - -void -ckcapi_lock_global(void) -{ - DWORD r; - - ASSERT(global_mutex); - - r = WaitForSingleObject(global_mutex, INFINITE); - ASSERT(r == WAIT_OBJECT_0); -} - -void -ckcapi_unlock_global(void) -{ - BOOL r; - - ASSERT(global_mutex); - - r = ReleaseMutex(global_mutex); - ASSERT(r); -} - -CK_RV -ckcapi_winerr_to_ckr(DWORD werr) -{ - switch(werr) - { - case ERROR_NOT_ENOUGH_MEMORY: - return CKR_HOST_MEMORY; - break; - case NTE_NO_MEMORY: - return CKR_DEVICE_MEMORY; - break; - case ERROR_MORE_DATA: - return CKR_BUFFER_TOO_SMALL; - case ERROR_INVALID_PARAMETER: /* these params were derived from the */ - case ERROR_INVALID_HANDLE: /* inputs, so if they are bad, the input */ - case NTE_BAD_ALGID: /* data is bad */ - case NTE_BAD_HASH: - return CKR_DATA_INVALID; - break; - case ERROR_BUSY: - case NTE_FAIL: - case NTE_BAD_UID: - return CKR_DEVICE_ERROR; - break; - default: - return CKR_GENERAL_ERROR; - }; -} - - -/* ---------------------------------------------------------------- */ - -static CK_RV -CC_C_Initialize(CK_VOID_PTR init_args) -{ - ENTER(C_Initialize); - PREREQ(!cryptoki_initialized, CKR_CRYPTOKI_ALREADY_INITIALIZED); - - if (init_args != NULL) { - CK_C_INITIALIZE_ARGS_PTR args; - int supplied_ok; - - /* pReserved must be NULL */ - args = init_args; - PREREQ(!args->pReserved, CKR_ARGUMENTS_BAD); - - /* ALL supplied function pointers need to have the value either NULL or non-NULL. */ - supplied_ok = (args->CreateMutex == NULL && args->DestroyMutex == NULL && - args->LockMutex == NULL && args->UnlockMutex == NULL) || - (args->CreateMutex != NULL && args->DestroyMutex != NULL && - args->LockMutex != NULL && args->UnlockMutex != NULL); - PREREQ(supplied_ok, CKR_ARGUMENTS_BAD); - - /* - * When the CKF_OS_LOCKING_OK flag isn't set and mutex function pointers are supplied - * by an application, return an error. DBus must be able to use its own locks. - */ - if(!(args->flags & CKF_OS_LOCKING_OK) && (args->CreateMutex != NULL)) - RETURN(CKR_CANT_LOCK); - } - - if(!global_mutex) - { - global_mutex = CreateMutex(NULL, FALSE, NULL); - if(!global_mutex) - RETURN(CKR_CANT_LOCK); - } - - cryptoki_initialized = 1; - - RETURN(CKR_OK); -} - -static CK_RV -CC_C_Finalize(CK_VOID_PTR pReserved) -{ - ENTER(C_Finalize); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - cryptoki_initialized = 0; - - RETURN(CKR_OK); -} - -static CK_RV -CC_C_GetInfo(CK_INFO_PTR info) -{ - ENTER(C_GetInfo); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - PREREQ(info, CKR_ARGUMENTS_BAD); - - ASSERT(strlen(MANUFACTURER_ID) == 32); - ASSERT(strlen(LIBRARY_DESCRIPTION) == 32); - - info->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; - info->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; - info->libraryVersion.major = LIBRARY_VERSION_MAJOR; - info->libraryVersion.minor = LIBRARY_VERSION_MINOR; - info->flags = 0; - strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32); - strncpy((char*)info->libraryDescription, LIBRARY_DESCRIPTION, 32); - - RETURN(CKR_OK); -} - -static CK_RV -CC_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list) -{ - /* This would be a strange call to receive */ - return C_GetFunctionList(list); -} - -static CK_RV -CC_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count) -{ - ENTER(C_GetSlotList); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - PREREQ(count, CKR_ARGUMENTS_BAD); - - /* Token is always present */ - - /* Application only wants to know the number of slots. */ - if(slot_list == NULL) - { - *count = 1; - RETURN(CKR_OK); - } - - if((*count < 1) && (slot_list != NULL)) - { - *count = 1; - RETURN(CKR_BUFFER_TOO_SMALL); - } - - *count = 1; - slot_list[0] = slot_id; - RETURN(CKR_OK); -} - -static CK_RV -CC_C_GetSlotInfo(CK_SLOT_ID id, CK_SLOT_INFO_PTR info) -{ - ENTER(C_GetSlotInfo); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - PREREQ(info, CKR_ARGUMENTS_BAD); - - /* Make sure the slot ID is valid */ - if(id != slot_id) - RETURN(CKR_SLOT_ID_INVALID); - - ASSERT(strlen(SLOT_DESCRIPTION) == 64); - ASSERT(strlen(MANUFACTURER_ID) == 32); - - /* Provide information about the slot in the provided buffer */ - strncpy((char*)info->slotDescription, SLOT_DESCRIPTION, 64); - strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32); - info->hardwareVersion.major = HARDWARE_VERSION_MAJOR; - info->hardwareVersion.minor = HARDWARE_VERSION_MINOR; - info->firmwareVersion.major = FIRMWARE_VERSION_MAJOR; - info->firmwareVersion.minor = FIRMWARE_VERSION_MINOR; - - /* Token is always present */ - info->flags = CKF_TOKEN_PRESENT; - - RETURN(CKR_OK); -} - -static CK_RV -CC_C_GetTokenInfo(CK_SLOT_ID id, CK_TOKEN_INFO_PTR info) -{ - ENTER(C_GetTokenInfo); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - PREREQ(info, CKR_ARGUMENTS_BAD); - - /* Make sure the slot ID is valid */ - if(id != slot_id) - RETURN(CKR_SLOT_ID_INVALID); - - ASSERT(strlen(SLOT_DESCRIPTION) == 64); - ASSERT(strlen(MANUFACTURER_ID) == 32); - ASSERT(strlen(SLOT_TOKEN_MODEL) == 16); - ASSERT(strlen(SLOT_TOKEN_SERIAL) == 16); - - /* Provide information about a token in the provided buffer */ - strncpy((char*)info->label, SLOT_DESCRIPTION, 32); - strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32); - strncpy((char*)info->model, SLOT_TOKEN_MODEL, 16); - strncpy((char*)info->serialNumber, SLOT_TOKEN_SERIAL, 16); - - /* Protected authentication path: Windows prompts for it's own PINs */ - info->flags = CKF_TOKEN_INITIALIZED | CKF_PROTECTED_AUTHENTICATION_PATH; - info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE; - info->ulSessionCount = CK_EFFECTIVELY_INFINITE; - info->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE; - info->ulRwSessionCount = CK_EFFECTIVELY_INFINITE; - info->ulMaxPinLen = MAX_PIN_LEN; - info->ulMinPinLen = MIN_PIN_LEN; - info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION; - info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION; - info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION; - info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; - info->hardwareVersion.major = HARDWARE_VERSION_MAJOR; - info->hardwareVersion.minor = HARDWARE_VERSION_MINOR; - info->firmwareVersion.major = FIRMWARE_VERSION_MAJOR; - info->firmwareVersion.minor = FIRMWARE_VERSION_MINOR; - memset(info->utcTime, ' ', 16); - - RETURN(CKR_OK); -} - -static CK_RV -CC_C_GetMechanismList(CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list, - CK_ULONG_PTR count) -{ - ENTER(C_GetMechanismList); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - PREREQ(count, CKR_ARGUMENTS_BAD); - - if(id != slot_id) - RETURN(CKR_SLOT_ID_INVALID); - - if(mechanism_list == NULL) - { - *count = 1; - RETURN(CKR_OK); - } - - if(*count < 1) - { - *count = 1; - RETURN(CKR_BUFFER_TOO_SMALL); - } - - mechanism_list[0] = CKM_RSA_PKCS; - *count = 1; - RETURN(CKR_OK); -} - -static CK_RV -CC_C_GetMechanismInfo(CK_SLOT_ID id, CK_MECHANISM_TYPE type, - CK_MECHANISM_INFO_PTR info) -{ - ENTER(C_GetMechanismInfo); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - PREREQ(info, CKR_ARGUMENTS_BAD); - - if(id != slot_id) - RETURN(CKR_SLOT_ID_INVALID); - - /* unsupported mechanism */ - if(type != CKM_RSA_PKCS) - RETURN(CKR_MECHANISM_INVALID); - - info->ulMinKeySize = 384; - info->ulMaxKeySize = 16384; - info->flags = 0; /* TODO: Choose which we'll implement */ - RETURN(CKR_OK); -} - -static CK_RV -CC_C_InitToken(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len, - CK_UTF8CHAR_PTR label) -{ - ENTER(C_InitToken); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) -{ - ENTER(C_WaitForSlotEvent); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* - * PKCS#11 GRAY AREA: What happens when we know we'll *never* - * have any slot events, and someone calls us without CKR_DONT_BLOCK? - * In case there's a thread dedicated to calling this function in a - * loop, we wait 1 seconds when called without CKR_DONT_BLOCK. - */ - - if(!(flags & CKF_DONT_BLOCK)) - Sleep(1000); - - RETURN(CKR_NO_EVENT); -} - -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; - CK_RV ret; - - ENTER(C_OpenSession); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - if(id != slot_id) - RETURN(CKR_SLOT_ID_INVALID); - - sess = ckcapi_session_create(); - if(sess == NULL) - RETURN(CKR_HOST_MEMORY); - - sess->notify_callback = notify; - sess->user_data = application; - - ret = ckcapi_session_register(sess); - if(ret == CKR_OK) - { - /* ID should have been assigned when registering */ - ASSERT(sess->id > 0); - *session = sess->id; - } - else - { - ckcapi_session_destroy(sess); - } - - RETURN(ret); -} - -static CK_RV -CC_C_CloseSession(CK_SESSION_HANDLE session) -{ - Session* 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); - if(ret == CKR_OK) - { - /* This will unref and possibly destroy the session */ - ckcapi_session_unref_unlock(sess); - } - - RETURN(ret); -} - -static CK_RV -CC_C_CloseAllSessions(CK_SLOT_ID id) -{ - ENTER(C_CloseAllSession); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - if(id != slot_id) - RETURN(CKR_SLOT_ID_INVALID); - - ckcapi_session_close_all(); - RETURN(CKR_OK); -} - -static CK_RV -CC_C_GetFunctionStatus(CK_SESSION_HANDLE session) -{ - ENTER(C_GetFunctionStatus); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - RETURN(CKR_FUNCTION_NOT_PARALLEL); -} - -static CK_RV -CC_C_CancelFunction(CK_SESSION_HANDLE session) -{ - ENTER(C_CancelFunction); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - RETURN(CKR_FUNCTION_NOT_PARALLEL); -} - -static CK_RV -CC_C_GetSessionInfo(CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info) -{ - ENTER(C_GetSessionInfo); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - // TODO: Implement - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_InitPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR pin, - CK_ULONG pin_len) -{ - ENTER(C_InitPIN); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* We don't support this stuff. We don't support 'SO' logins. */ - RETURN(CKR_USER_NOT_LOGGED_IN); -} - -static CK_RV -CC_C_SetPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR old_pin, - CK_ULONG old_len, CK_UTF8CHAR_PTR new_pin, CK_ULONG new_len) -{ - ENTER(C_SetPIN); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* Not supported, Windows takes care of this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_GetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state, - CK_ULONG_PTR operation_state_len) -{ - ENTER(C_GetOperationState); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* Nasty, no sirrr */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state, - CK_ULONG operation_state_len, CK_OBJECT_HANDLE encryption_key, - CK_OBJECT_HANDLE authentication_key) -{ - ENTER(C_SetOperationState); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* Nasty, no sirrr */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_Login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type, - CK_UTF8CHAR_PTR pin, CK_ULONG pin_len) -{ - ENTER(C_Login); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement our local concept of logged in */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_Logout(CK_SESSION_HANDLE session) -{ - ENTER(C_Logout); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement our local concept of logged in */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_CreateObject(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR templ, - CK_ULONG count, CK_OBJECT_HANDLE_PTR object) -{ - ENTER(C_CreateObject); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to support this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_CopyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, - CK_ATTRIBUTE_PTR templ, CK_ULONG count, - CK_OBJECT_HANDLE_PTR new_object) -{ - ENTER(C_CopyObject); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to support this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - - -static CK_RV -CC_C_DestroyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) -{ - ENTER(C_DestroyObject); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to support this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_GetObjectSize(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, - CK_ULONG_PTR size) -{ - ENTER(C_GetObjectSize); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_GetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, - CK_ATTRIBUTE_PTR templ, CK_ULONG count) -{ - ENTER(C_GetAttributeValue); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, - CK_ATTRIBUTE_PTR templ, CK_ULONG count) -{ - ENTER(C_SetAttributeValue); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_FindObjectsInit(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR templ, - CK_ULONG count) -{ - Session* 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); - if(ret == CKR_OK) - { - ret = ckcapi_object_find_init(sess, templ, count); - ckcapi_session_unref_unlock(sess); - } - - RETURN(ret); -} - -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; - CK_RV ret; - - ENTER(C_FindObjects); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - PREREQ(object_count, CKR_ARGUMENTS_BAD); - PREREQ(!max_object_count || objects, CKR_ARGUMENTS_BAD); - - ret = ckcapi_session_find_lock_ref(session, 0, &sess); - if(ret == CKR_OK) - { - ret = ckcapi_object_find(sess, objects, max_object_count, object_count); - ckcapi_session_unref_unlock(sess); - } - - RETURN(ret); -} - -static CK_RV -CC_C_FindObjectsFinal(CK_SESSION_HANDLE session) -{ - Session* sess; - CK_RV ret; - - ENTER(C_FindObjectsFinal); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - ret = ckcapi_session_find_lock_ref(session, 0, &sess); - if(ret == CKR_OK) - { - ret = ckcapi_objects_find_final(sess); - ckcapi_session_unref_unlock(sess); - } - - RETURN(ret); -} - -static CK_RV -CC_C_EncryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE key) -{ - ENTER(C_EncryptInit); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_Encrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, - CK_BYTE_PTR encrypted_data, CK_ULONG_PTR encrypted_data_len) -{ - ENTER(C_Encrypt); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_EncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, - CK_ULONG part_len, CK_BYTE_PTR encrypted_part, - CK_ULONG_PTR encrypted_part_len) -{ - ENTER(C_EncryptUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_EncryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_encrypted_part, - CK_ULONG_PTR last_encrypted_part_len) -{ - ENTER(C_EncryptFinal); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DecryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE key) -{ - ENTER(C_DecryptInit); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_Decrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_data, - CK_ULONG encrypted_data_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len) -{ - ENTER(C_Decrypt); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DecryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part, - CK_ULONG encrypted_part_len, CK_BYTE_PTR part, CK_ULONG_PTR part_len) -{ - ENTER(C_DecryptUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DecryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR pLastPart, - CK_ULONG_PTR last_part_len) -{ - ENTER(C_DecryptFinal); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DigestInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism) -{ - ENTER(C_DigestInit); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_Digest(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, - CK_BYTE_PTR digest, CK_ULONG_PTR digest_len) -{ - ENTER(C_Digest); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) -{ - ENTER(C_DigestUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DigestKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) -{ - ENTER(C_DigestKey); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DigestFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR digest, - CK_ULONG_PTR digest_len) -{ - ENTER(C_DigestFinal); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SignInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE key) -{ - ENTER(C_SignInit); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_Sign(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, - CK_BYTE_PTR signature, CK_ULONG_PTR signature_len) -{ - ENTER(C_Sign); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SignUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) -{ - ENTER(C_SignUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SignFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, - CK_ULONG_PTR signature_len) -{ - ENTER(C_SignFinal); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SignRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE key) -{ - ENTER(C_SignRecoverInit); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SignRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, - CK_BYTE_PTR signature, CK_ULONG_PTR signature_len) -{ - ENTER(C_SignRecover); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: Implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_VerifyInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE key) -{ - ENTER(C_VerifyInit); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_Verify(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, - CK_BYTE_PTR signature, CK_ULONG signature_len) -{ - ENTER(C_Verify); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_VerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) -{ - ENTER(C_VerifyUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_VerifyFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, - CK_ULONG signature_len) -{ - ENTER(C_VerifyFinal); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_VerifyRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE key) -{ - ENTER(C_VerifyRecoverInit); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_VerifyRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, - CK_ULONG signature_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len) -{ - ENTER(C_VerifyRecover); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DigestEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, - CK_ULONG part_len, CK_BYTE_PTR encrypted_part, - CK_ULONG_PTR encrypted_part_len) -{ - ENTER(C_DigestEncryptUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DecryptDigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part, - CK_ULONG encrypted_part_len, CK_BYTE_PTR part, - CK_ULONG_PTR part_len) -{ - ENTER(C_DecryptDigestUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SignEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, - CK_ULONG part_len, CK_BYTE_PTR encrypted_part, - CK_ULONG_PTR encrypted_part_len) -{ - ENTER(C_SignEncryptUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DecryptVerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part, - CK_ULONG encrypted_part_len, CK_BYTE_PTR part, - CK_ULONG_PTR part_len) -{ - ENTER(C_DecryptVerifyUpdate); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_GenerateKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_ATTRIBUTE_PTR templ, CK_ULONG count, - CK_OBJECT_HANDLE_PTR key) -{ - ENTER(C_GenerateKey); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* Let key generation happen via Windows interfaces */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_GenerateKeyPair(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_ATTRIBUTE_PTR public_key_template, CK_ULONG public_key_attribute_count, - CK_ATTRIBUTE_PTR private_key_template, CK_ULONG private_key_attribute_count, - CK_OBJECT_HANDLE_PTR public_key, CK_OBJECT_HANDLE_PTR private_key) -{ - ENTER(C_GenerateKeyPair); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* Let key generation happen via Windows interfaces */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_WrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key, - CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len) -{ - ENTER(C_WrapKey); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_UnwrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE unwrapping_key, CK_BYTE_PTR wrapped_key, - CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR templ, - CK_ULONG count, CK_OBJECT_HANDLE_PTR key) -{ - ENTER(C_UnwrapKey); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* TODO: See if we need to implement this */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_DeriveKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, - CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR templ, - CK_ULONG count, CK_OBJECT_HANDLE_PTR key) -{ - ENTER(C_DeriveKey); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* Can't do this with RSA */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_SeedRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR seed, CK_ULONG seed_len) -{ - ENTER(C_SeedRandom); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* - * TODO: Perhaps at some point in the future we may want - * to see if we can hook into the Windows RNG - */ - - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static CK_RV -CC_C_GenerateRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR random_data, - CK_ULONG random_len) -{ - ENTER(C_GenerateRandom); - PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - - /* - * TODO: Perhaps at some point in the future we may want - * to see if we can hook into the Windows RNG - */ - - RETURN(CKR_FUNCTION_NOT_SUPPORTED); -} - -static struct CK_FUNCTION_LIST functionList = { - { 2, 11 }, /* version */ - CC_C_Initialize, - CC_C_Finalize, - CC_C_GetInfo, - CC_C_GetFunctionList, - CC_C_GetSlotList, - CC_C_GetSlotInfo, - CC_C_GetTokenInfo, - CC_C_GetMechanismList, - CC_C_GetMechanismInfo, - CC_C_InitToken, - CC_C_InitPIN, - CC_C_SetPIN, - CC_C_OpenSession, - CC_C_CloseSession, - CC_C_CloseAllSessions, - CC_C_GetSessionInfo, - CC_C_GetOperationState, - CC_C_SetOperationState, - CC_C_Login, - CC_C_Logout, - CC_C_CreateObject, - CC_C_CopyObject, - CC_C_DestroyObject, - CC_C_GetObjectSize, - CC_C_GetAttributeValue, - CC_C_SetAttributeValue, - CC_C_FindObjectsInit, - CC_C_FindObjects, - CC_C_FindObjectsFinal, - CC_C_EncryptInit, - CC_C_Encrypt, - CC_C_EncryptUpdate, - CC_C_EncryptFinal, - CC_C_DecryptInit, - CC_C_Decrypt, - CC_C_DecryptUpdate, - CC_C_DecryptFinal, - CC_C_DigestInit, - CC_C_Digest, - CC_C_DigestUpdate, - CC_C_DigestKey, - CC_C_DigestFinal, - CC_C_SignInit, - CC_C_Sign, - CC_C_SignUpdate, - CC_C_SignFinal, - CC_C_SignRecoverInit, - CC_C_SignRecover, - CC_C_VerifyInit, - CC_C_Verify, - CC_C_VerifyUpdate, - CC_C_VerifyFinal, - CC_C_VerifyRecoverInit, - CC_C_VerifyRecover, - CC_C_DigestEncryptUpdate, - CC_C_DecryptDigestUpdate, - CC_C_SignEncryptUpdate, - CC_C_DecryptVerifyUpdate, - CC_C_GenerateKey, - CC_C_GenerateKeyPair, - CC_C_WrapKey, - CC_C_UnwrapKey, - CC_C_DeriveKey, - CC_C_SeedRandom, - CC_C_GenerateRandom, - CC_C_GetFunctionStatus, - CC_C_CancelFunction, - CC_C_WaitForSlotEvent -}; - -__declspec(dllexport) CK_RV -C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list) -{ - if(!list) - return CKR_ARGUMENTS_BAD; - - *list = &functionList; - return CKR_OK; -} diff --git a/cryptoki-capi.dsp b/cryptoki-capi.dsp deleted file mode 100644 index 6f93ed3..0000000 --- a/cryptoki-capi.dsp +++ /dev/null @@ -1,145 +0,0 @@ -# Microsoft Developer Studio Project File - Name="cryptoki_capi" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -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 -!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 -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "cryptoki_capi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "cryptoki_capi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "cryptoki_capi - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 - -!ELSEIF "$(CFG)" == "cryptoki_capi - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "cryptoki_capi - Win32 Release" -# Name "cryptoki_capi - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=".\ckcapi-object.c" -# End Source File -# Begin Source File - -SOURCE=".\ckcapi-util.c" -# End Source File -# Begin Source File - -SOURCE=".\cryptoki-capi-session.c" -# End Source File -# Begin Source File - -SOURCE=".\cryptoki-capi.c" -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=".\cryptoki-capi-util.h" -# End Source File -# Begin Source File - -SOURCE=".\cryptoki-capi.h" -# End Source File -# Begin Source File - -SOURCE=.\pkcs11\cryptoki.h -# End Source File -# Begin Source File - -SOURCE=".\pkcs11\pkcs-11v2-20a3.h" -# End Source File -# Begin Source File - -SOURCE=.\pkcs11\pkcs11.h -# End Source File -# Begin Source File - -SOURCE=.\pkcs11\pkcs11f.h -# End Source File -# Begin Source File - -SOURCE=.\pkcs11\pkcs11t.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/cryptoki-capi.dsw b/cryptoki-capi.dsw deleted file mode 100644 index 7f71040..0000000 --- a/cryptoki-capi.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "cryptoki_capi"=".\cryptoki_capi.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - 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 - -#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 */ - -- cgit v1.2.3