@@ -1,9 +1,3067 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_PCSCLITE_H -#include +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_PTHREAD_H +# include +#endif + +#define CK_PTR * +#define CK_DEFINE_FUNCTION(returnType, name) returnType name +#define CK_DECLARE_FUNCTION(returnType, name) returnType name +#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name) +#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name) +#ifndef NULL_PTR +# define NULL_PTR 0 +#endif + +#include "pkcs11.h" + +#ifndef CACKEY_CRYPTOKI_VERSION_CODE +# define CACKEY_CRYPTOKI_VERSION_CODE 0x021e00 +#endif + +#ifdef CACKEY_DEBUG +# ifdef HAVE_STDIO_H +# include +# endif + +# define CACKEY_DEBUG_PRINTF(x...) { fprintf(stderr, "%s(): ", __func__); fprintf(stderr, x); fprintf(stderr, "\n"); } +# define CACKEY_DEBUG_PRINTBUF(f, x, y) { unsigned char *buf; unsigned long idx; buf = (unsigned char *) (x); fprintf(stderr, "%s(): %s (%s/%lu = {%02x", __func__, f, #x, (unsigned long) (y), buf[0]); for (idx = 1; idx < (y); idx++) { fprintf(stderr, ", %02x", buf[idx]); }; fprintf(stderr, "})\n"); } +# define CACKEY_DEBUG_PERROR(x) { fprintf(stderr, "%s(): ", __func__); perror(x); } +# define free(x) { CACKEY_DEBUG_PRINTF("FREE(%p) (%s)", x, #x); free(x); } + +static void *CACKEY_DEBUG_FUNC_MALLOC(size_t size, const char *func) { + void *retval; + + retval = malloc(size); + + fprintf(stderr, "%s(): ", func); + fprintf(stderr, "MALLOC() = %p", retval); + fprintf(stderr, "\n"); + + return(retval); +} + +static void *CACKEY_DEBUG_FUNC_REALLOC(void *ptr, size_t size, const char *func) { + void *retval; + + retval = realloc(ptr, size); + + if (retval != ptr) { + fprintf(stderr, "%s(): ", func); + fprintf(stderr, "REALLOC(%p) = %p", ptr, retval); + fprintf(stderr, "\n"); + } + + return(retval); +} + +# define malloc(x) CACKEY_DEBUG_FUNC_MALLOC(x, __func__) +# define realloc(x, y) CACKEY_DEBUG_FUNC_REALLOC(x, y, __func__) +#else +# define CACKEY_DEBUG_PRINTF(x...) /**/ +# define CACKEY_DEBUG_PRINTBUF(f, x, y) /**/ +# define CACKEY_DEBUG_PERROR(x) /**/ +#endif + +#ifndef CKA_TRUST_SERVER_AUTH +# define CKA_TRUST_SERVER_AUTH 0xce536358 +#endif +#ifndef CKA_TRUST_CLIENT_AUTH +# define CKA_TRUST_CLIENT_AUTH 0xce536359 +#endif +#ifndef CKA_TRUST_CODE_SIGNING +# define CKA_TRUST_CODE_SIGNING 0xce53635a +#endif +#ifndef CKA_TRUST_EMAIL_PROTECTION +# define CKA_TRUST_EMAIL_PROTECTION 0xce53635b +#endif + +struct cackey_identity { + CK_ATTRIBUTE *attributes; + CK_ULONG attributes_count; +}; + +struct cackey_session { + int active; + + CK_SLOT_ID slotID; + CK_STATE state; + CK_FLAGS flags; + CK_ULONG ulDeviceError; + CK_VOID_PTR pApplication; + CK_NOTIFY Notify; + + struct cackey_identity *identities; + unsigned long identities_count; + + int search_active; + CK_ATTRIBUTE_PTR search_query; + CK_ULONG search_query_count; + unsigned long search_curr_id; + + int sign_active; + CK_MECHANISM_TYPE sign_mechanism; + CK_BYTE_PTR sign_buf; + unsigned long sign_buflen; + unsigned long sign_bufused; + + int decrypt_active; + CK_MECHANISM_TYPE decrypt_mechanism; + CK_VOID_PTR decrypt_mech_parm; + CK_ULONG decrypt_mech_parmlen; +}; + +static void *cackey_biglock = NULL; +static struct cackey_session cackey_sessions[8]; +static int cackey_initialized = 0; +static int cackey_biglock_init = 0; +CK_C_INITIALIZE_ARGS cackey_args; + +static unsigned long cackey_getversion(void) { + static unsigned long retval = 255; + unsigned long major = 0; + unsigned long minor = 0; + char *major_str = NULL; + char *minor_str = NULL; + + CACKEY_DEBUG_PRINTF("Called."); + + if (retval != 255) { + CACKEY_DEBUG_PRINTF("Returning 0x%lx (cached).", retval); + + return(retval); + } + + retval = 0; + +#ifdef PACKAGE_VERSION + major_str = PACKAGE_VERSION; + if (major_str) { + major = strtoul(major_str, &minor_str, 10); + + if (minor_str) { + minor = strtoul(minor_str + 1, NULL, 10); + } + } + + retval = (major << 16) | (minor << 8); #endif + CACKEY_DEBUG_PRINTF("Returning 0x%lx", retval); + + return(retval); +} + +/* Returns 0 on success */ +static int cackey_mutex_create(void **mutex) { + pthread_mutex_t *pthread_mutex; + int pthread_retval; + CK_RV custom_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if ((cackey_args.flags & CKF_OS_LOCKING_OK) == CKF_OS_LOCKING_OK) { + pthread_mutex = malloc(sizeof(*pthread_mutex)); + if (!pthread_mutex) { + CACKEY_DEBUG_PRINTF("Failed to allocate memory."); + + return(-1); + } + + pthread_retval = pthread_mutex_init(pthread_mutex, NULL); + if (pthread_retval != 0) { + CACKEY_DEBUG_PRINTF("pthread_mutex_init() returned error (%i).", pthread_retval); + + return(-1); + } + + *mutex = pthread_mutex; + } else { + if (cackey_args.CreateMutex) { + custom_retval = cackey_args.CreateMutex(mutex); + + if (custom_retval != CKR_OK) { + CACKEY_DEBUG_PRINTF("cackey_args.CreateMutex() returned error (%li).", (long) custom_retval); + + return(-1); + } + } + } + + CACKEY_DEBUG_PRINTF("Returning sucessfully (0)"); + + return(0); +} + +/* Returns 0 on success */ +static int cackey_mutex_lock(void *mutex) { + pthread_mutex_t *pthread_mutex; + int pthread_retval; + CK_RV custom_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if ((cackey_args.flags & CKF_OS_LOCKING_OK) == CKF_OS_LOCKING_OK) { + pthread_mutex = mutex; + + pthread_retval = pthread_mutex_lock(pthread_mutex); + if (pthread_retval != 0) { + CACKEY_DEBUG_PRINTF("pthread_mutex_lock() returned error (%i).", pthread_retval); + + return(-1); + } + } else { + if (cackey_args.LockMutex) { + custom_retval = cackey_args.LockMutex(mutex); + + if (custom_retval != CKR_OK) { + CACKEY_DEBUG_PRINTF("cackey_args.LockMutex() returned error (%li).", (long) custom_retval); + + return(-1); + } + } + } + + CACKEY_DEBUG_PRINTF("Returning sucessfully (0)"); + + return(0); +} + +/* Returns 0 on success */ +static int cackey_mutex_unlock(void *mutex) { + pthread_mutex_t *pthread_mutex; + int pthread_retval; + CK_RV custom_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if ((cackey_args.flags & CKF_OS_LOCKING_OK) == CKF_OS_LOCKING_OK) { + pthread_mutex = mutex; + + pthread_retval = pthread_mutex_unlock(pthread_mutex); + if (pthread_retval != 0) { + CACKEY_DEBUG_PRINTF("pthread_mutex_unlock() returned error (%i).", pthread_retval); + + return(-1); + } + } else { + if (cackey_args.UnlockMutex) { + custom_retval = cackey_args.UnlockMutex(mutex); + + if (custom_retval != CKR_OK) { + CACKEY_DEBUG_PRINTF("cackey_args.UnlockMutex() returned error (%li).", (long) custom_retval); + + return(-1); + } + } + } + + CACKEY_DEBUG_PRINTF("Returning sucessfully (0)"); + + return(0); +} + +static CK_ATTRIBUTE_PTR cackey_get_attributes(CK_OBJECT_CLASS objectclass, void *identity, unsigned long identity_num, CK_ULONG_PTR pulCount) { + static CK_BBOOL ck_true = 1; + static CK_BBOOL ck_false = 0; + CK_ULONG numattrs = 0, retval_count; + CK_ATTRIBUTE_TYPE curr_attr_type; + CK_ATTRIBUTE curr_attr, *retval; + CK_VOID_PTR pValue; + CK_ULONG ulValueLen; + CK_OBJECT_CLASS ck_object_class; + CK_CERTIFICATE_TYPE ck_certificate_type; + CK_KEY_TYPE ck_key_type; + CK_UTF8CHAR ucTmpBuf[1024]; + unsigned char certificate[16384]; + ssize_t getcert_ret, certificate_len = -1, x509_read_ret; + int fd; + int pValue_free; + + CACKEY_DEBUG_PRINTF("Called (objectClass = %lu, identity_num = %lu).", (unsigned long) objectclass, identity_num); + + if (objectclass != CKO_CERTIFICATE && objectclass != CKO_PUBLIC_KEY && objectclass != CKO_PRIVATE_KEY) { + CACKEY_DEBUG_PRINTF("Returning 0 objects (NULL), invalid object class"); + + return(NULL); + } + + retval_count = 16; + retval = malloc(retval_count * sizeof(*retval)); + + /* XXX: Get Cert */ + certificate_len = -1; + + if (certificate_len == -1) { + CACKEY_DEBUG_PRINTF("Returning 0 objects (NULL), this identity does not have an X.509 certificate associated with it and will not work"); + + return(NULL); + } + + for (curr_attr_type = 0; curr_attr_type < 0xce53635f; curr_attr_type++) { + if (curr_attr_type == 0x800) { + curr_attr_type = 0xce536300; + } + + pValue_free = 0; + pValue = NULL; + ulValueLen = (CK_LONG) -1; + + switch (curr_attr_type) { + case CKA_CLASS: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_CLASS (0x%08lx) ...", (unsigned long) curr_attr_type); + + ck_object_class = objectclass; + + pValue = &ck_object_class; + ulValueLen = sizeof(ck_object_class); + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_OBJECT_CLASS *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_TOKEN: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_TOKEN (0x%08lx) ...", (unsigned long) curr_attr_type); + + pValue = &ck_true; + ulValueLen = sizeof(ck_true); + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_MODIFIABLE: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_MODIFIABLE (0x%08lx) ...", (unsigned long) curr_attr_type); + + pValue = &ck_false; + ulValueLen = sizeof(ck_false); + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_LABEL: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_LABEL (0x%08lx) ...", (unsigned long) curr_attr_type); + + /* XXX: Determine name */ + + CACKEY_DEBUG_PRINTF(" ... returning %s (%p/%lu)", (char *) ((CK_UTF8CHAR *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_VALUE: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_VALUE (0x%08lx) ...", (unsigned long) curr_attr_type); + + switch (objectclass) { + case CKO_PRIVATE_KEY: + CACKEY_DEBUG_PRINTF(" ... but not getting it because we are a private key."); + + break; + case CKO_PUBLIC_KEY: + /* XXX: TODO */ + + break; + case CKO_CERTIFICATE: + pValue = certificate; + ulValueLen = certificate_len; + + break; + } + + CACKEY_DEBUG_PRINTF(" ... returning %p/%lu", pValue, (unsigned long) ulValueLen); + + break; + case CKA_ISSUER: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_ISSUER (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass != CKO_CERTIFICATE) { + CACKEY_DEBUG_PRINTF(" ... but not getting it because we are not a certificate."); + + break; + } + + if (certificate_len >= 0) { + x509_read_ret = x509_to_issuer(certificate, certificate_len, &pValue); + if (x509_read_ret < 0) { + pValue = NULL; + } else { + ulValueLen = x509_read_ret; + } + } + + CACKEY_DEBUG_PRINTF(" ... returning %p/%lu", pValue, (unsigned long) ulValueLen); + + break; + case CKA_SERIAL_NUMBER: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_SERIAL_NUMBER (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass != CKO_CERTIFICATE) { + CACKEY_DEBUG_PRINTF(" ... but not getting it because we are not a certificate."); + + break; + } + + if (certificate_len >= 0) { + x509_read_ret = x509_to_serial(certificate, certificate_len, &pValue); + if (x509_read_ret < 0) { + pValue = NULL; + } else { + ulValueLen = x509_read_ret; + } + } + + CACKEY_DEBUG_PRINTF(" ... returning (%p/%lu)", pValue, (unsigned long) ulValueLen); + + break; + case CKA_SUBJECT: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_SUBJECT (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass != CKO_CERTIFICATE) { + CACKEY_DEBUG_PRINTF(" ... but not getting it because we are not a certificate."); + + break; + } + + if (certificate_len >= 0) { + x509_read_ret = x509_to_subject(certificate, certificate_len, &pValue); + if (x509_read_ret < 0) { + pValue = NULL; + } else { + ulValueLen = x509_read_ret; + } + } + + CACKEY_DEBUG_PRINTF(" ... returning %p/%lu", pValue, (unsigned long) ulValueLen); + + break; + case CKA_ID: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_ID (0x%08lx) ...", (unsigned long) curr_attr_type); + + ucTmpBuf[0] = ((identity_num + 1) >> 8) & 0xff; + ucTmpBuf[1] = (identity_num + 1) & 0xff; + + pValue = &ucTmpBuf; + ulValueLen = 2; + + CACKEY_DEBUG_PRINTF(" ... returning %p/%lu", pValue, (unsigned long) ulValueLen); + + break; + case CKA_CERTIFICATE_TYPE: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_CERTIFICATE_TYPE (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass != CKO_CERTIFICATE) { + CACKEY_DEBUG_PRINTF(" ... but not getting it because we are not a certificate."); + + break; + } + + /* We only support one certificate type */ + ck_certificate_type = CKC_X_509; + + pValue = &ck_certificate_type; + ulValueLen = sizeof(ck_certificate_type); + + CACKEY_DEBUG_PRINTF(" ... returning CKC_X_509 (%lu) (%p/%lu)", (unsigned long) *((CK_CERTIFICATE_TYPE *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_KEY_TYPE: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_KEY_TYPE (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass != CKO_PRIVATE_KEY && objectclass != CKO_PUBLIC_KEY) { + CACKEY_DEBUG_PRINTF(" ... but not getting it because we are not a key."); + + break; + } + + /* We only support one key type */ + ck_key_type = CKK_RSA; + + pValue = &ck_key_type; + ulValueLen = sizeof(ck_key_type); + + CACKEY_DEBUG_PRINTF(" ... returning CKK_RSA (%lu) (%p/%lu)", (unsigned long) *((CK_CERTIFICATE_TYPE *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_SIGN: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_SIGN (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass == CKO_PRIVATE_KEY) { + pValue = &ck_true; + ulValueLen = sizeof(ck_true); + } else { + pValue = &ck_false; + ulValueLen = sizeof(ck_false); + } + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_DECRYPT: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_DECRYPT (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass == CKO_PRIVATE_KEY || objectclass == CKO_PUBLIC_KEY) { + pValue = &ck_true; + ulValueLen = sizeof(ck_true); + } else { + pValue = &ck_false; + ulValueLen = sizeof(ck_false); + } + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_TRUST_SERVER_AUTH: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_TRUST_SERVER_AUTH (0x%08lx) ...", (unsigned long) curr_attr_type); + + pValue = &ck_true; + ulValueLen = sizeof(ck_true); + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_TRUST_CLIENT_AUTH: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_TRUST_CLIENT_AUTH (0x%08lx) ...", (unsigned long) curr_attr_type); + + pValue = &ck_true; + ulValueLen = sizeof(ck_true); + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_TRUST_CODE_SIGNING: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_TRUST_CODE_SIGNING (0x%08lx) ...", (unsigned long) curr_attr_type); + + pValue = &ck_true; + ulValueLen = sizeof(ck_true); + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_TRUST_EMAIL_PROTECTION: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_TRUST_EMAIL_PROTECTION (0x%08lx) ...", (unsigned long) curr_attr_type); + + pValue = &ck_true; + ulValueLen = sizeof(ck_true); + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + default: + pValue = NULL; + ulValueLen = (CK_LONG) -1; + break; + } + + if (((CK_LONG) ulValueLen) != ((CK_LONG) -1)) { + /* Push curr_attr onto the stack */ + curr_attr.type = curr_attr_type; + curr_attr.ulValueLen = ulValueLen; + + curr_attr.pValue = malloc(curr_attr.ulValueLen); + memcpy(curr_attr.pValue, pValue, curr_attr.ulValueLen); + + if (pValue_free && pValue) { + free(pValue); + } + + if (numattrs >= retval_count) { + retval_count *= 2; + retval = realloc(retval, retval_count * sizeof(*retval)); + } + + memcpy(&retval[numattrs], &curr_attr, sizeof(curr_attr)); + numattrs++; + } + } + + if (numattrs != 0) { + retval_count = numattrs; + retval = realloc(retval, retval_count * sizeof(*retval)); + } else { + free(retval); + + retval = NULL; + } + + *pulCount = numattrs; + + CACKEY_DEBUG_PRINTF("Returning %lu objects (%p).", numattrs, retval); + + return(retval); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) { + CK_C_INITIALIZE_ARGS CK_PTR args; + uint32_t idx; + int mutex_init_ret; + + CACKEY_DEBUG_PRINTF("Called."); + + if (pInitArgs != NULL) { + args = pInitArgs; + memcpy(&cackey_args, args, sizeof(cackey_args)); + + if (args->CreateMutex == NULL || args->DestroyMutex == NULL || args->LockMutex == NULL || args->UnlockMutex == NULL) { + if (args->CreateMutex != NULL || args->DestroyMutex != NULL || args->LockMutex != NULL || args->UnlockMutex != NULL) { + CACKEY_DEBUG_PRINTF("Error. Some, but not All threading primitives provided."); + + return(CKR_ARGUMENTS_BAD); + } + } + + if (args->pReserved != NULL) { + CACKEY_DEBUG_PRINTF("Error. pReserved is not NULL."); + + return(CKR_ARGUMENTS_BAD); + } + } else { + cackey_args.CreateMutex = NULL; + cackey_args.DestroyMutex = NULL; + cackey_args.LockMutex = NULL; + cackey_args.UnlockMutex = NULL; + cackey_args.flags = 0; + } + + if (cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Already initialized."); + + return(CKR_CRYPTOKI_ALREADY_INITIALIZED); + } + + for (idx = 0; idx < (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])); idx++) { + cackey_sessions[idx].active = 0; + } + + cackey_initialized = 1; + + if (!cackey_biglock_init) { + mutex_init_ret = cackey_mutex_create(&cackey_biglock); + + if (mutex_init_ret != 0) { + CACKEY_DEBUG_PRINTF("Error. Mutex initialization failed."); + + return(CKR_CANT_LOCK); + } + + cackey_biglock_init = 1; + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Finalize)(CK_VOID_PTR pReserved) { + uint32_t idx; + + CACKEY_DEBUG_PRINTF("Called."); + + if (pReserved != NULL) { + CACKEY_DEBUG_PRINTF("Error. pReserved is not NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + for (idx = 0; idx < (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])); idx++) { + if (cackey_sessions[idx].active) { + C_CloseSession(idx); + } + } + + cackey_initialized = 0; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)(CK_INFO_PTR pInfo) { + static CK_UTF8CHAR manufacturerID[] = "U.S. Government"; + static CK_UTF8CHAR libraryDescription[] = "SSH Agent PKCS#11"; + + CACKEY_DEBUG_PRINTF("Called."); + + if (pInfo == NULL) { + CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + pInfo->cryptokiVersion.major = ((CACKEY_CRYPTOKI_VERSION_CODE) >> 16) & 0xff; + pInfo->cryptokiVersion.minor = ((CACKEY_CRYPTOKI_VERSION_CODE) >> 8) & 0xff; + + memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); + memcpy(pInfo->manufacturerID, manufacturerID, sizeof(manufacturerID) - 1); + + pInfo->flags = 0x00; + + memset(pInfo->libraryDescription, ' ', sizeof(pInfo->libraryDescription)); + memcpy(pInfo->libraryDescription, libraryDescription, sizeof(libraryDescription) - 1); + + pInfo->libraryVersion.major = (cackey_getversion() >> 16) & 0xff; + pInfo->libraryVersion.minor = (cackey_getversion() >> 8) & 0xff; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +/* We only support 1 slot. If the slot exists, the token exists. */ +CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { + CK_ULONG count, slot_present = 0, currslot; + int fd; + + CACKEY_DEBUG_PRINTF("Called."); + + if (pulCount == NULL) { + CACKEY_DEBUG_PRINTF("Error. pulCount is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + /* XXX: Determine if slot is present */ + + if (pSlotList == NULL) { + *pulCount = slot_present; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); + } + + count = *pulCount; + if (count < slot_present) { + CACKEY_DEBUG_PRINTF("Error. User allocated %lu entries, but we have %lu entries.", count, slot_present); + + return(CKR_BUFFER_TOO_SMALL); + } + + for (currslot = 0; currslot < slot_present; currslot++) { + pSlotList[currslot] = currslot; + } + + *pulCount = slot_present; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); + + tokenPresent = tokenPresent; /* Supress unused variable warning */ +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetSlotInfo)(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { + static CK_UTF8CHAR manufacturerID[] = "U.S. Government"; + static CK_UTF8CHAR slotDescription[] = "SSH Agent Slot"; + + CACKEY_DEBUG_PRINTF("Called."); + + if (pInfo == NULL) { + CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (slotID != 0) { + /* Again, we only support one slot -- slot 0 */ + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", slotID); + + return(CKR_SLOT_ID_INVALID); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + memset(pInfo->slotDescription, ' ', sizeof(pInfo->slotDescription)); + memcpy(pInfo->slotDescription, slotDescription, sizeof(slotDescription) - 1); + + memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); + memcpy(pInfo->manufacturerID, manufacturerID, sizeof(manufacturerID) - 1); + + pInfo->flags = CKF_TOKEN_PRESENT; + + pInfo->hardwareVersion.major = (cackey_getversion() >> 16) & 0xff; + pInfo->hardwareVersion.minor = (cackey_getversion() >> 8) & 0xff; + + pInfo->firmwareVersion.major = 0x00; + pInfo->firmwareVersion.minor = 0x00; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { + static CK_UTF8CHAR manufacturerID[] = "U.S. Government"; + static CK_UTF8CHAR defaultLabel[] = "Unknown Token"; + static CK_UTF8CHAR model[] = "SSH Agent Token"; + int fd, bytestocopy; + + CACKEY_DEBUG_PRINTF("Called."); + + if (pInfo == NULL) { + CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (slotID != 0) { + /* Again, we only support one slot -- slot 0 */ + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", slotID); + + return(CKR_SLOT_ID_INVALID); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + /* XXX: Verify connection is valid */ + if (0) { + CACKEY_DEBUG_PRINTF("Error. Tried to connect to slot, but failed. fd = %i", fd); + + return(CKR_SLOT_ID_INVALID); + } + + /* XXX: Get list of identities */ + if (0) { + CACKEY_DEBUG_PRINTF("Error. No identities found in slot."); + + return(CKR_TOKEN_NOT_PRESENT); + } + + memset(pInfo->label, ' ', sizeof(pInfo->label)); + if (1) { + memcpy(pInfo->label, defaultLabel, sizeof(defaultLabel) - 1); + } else { + } + + memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); + memcpy(pInfo->manufacturerID, manufacturerID, sizeof(manufacturerID) - 1); + + memset(pInfo->model, ' ', sizeof(pInfo->model)); + memcpy(pInfo->model, model, sizeof(model) - 1); + + memset(pInfo->serialNumber, ' ', sizeof(pInfo->serialNumber)); + + memset(pInfo->utcTime, ' ', sizeof(pInfo->utcTime)); + + pInfo->hardwareVersion.major = (cackey_getversion() >> 16) & 0xff; + pInfo->hardwareVersion.minor = (cackey_getversion() >> 8) & 0xff; + + pInfo->firmwareVersion.major = 0x00; + pInfo->firmwareVersion.minor = 0x00; + + pInfo->flags = CKF_WRITE_PROTECTED | CKF_USER_PIN_INITIALIZED | CKF_PROTECTED_AUTHENTICATION_PATH | CKF_TOKEN_INITIALIZED; + + pInfo->ulMaxSessionCount = (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])) - 1; + pInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION; + pInfo->ulMaxRwSessionCount = 0; + pInfo->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION; + pInfo->ulMaxPinLen = 128; + pInfo->ulMinPinLen = 0; + pInfo->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION; + pInfo->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION; + pInfo->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION; + pInfo->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_WaitForSlotEvent)(CK_FLAGS flags, CK_SLOT_ID_PTR pSlotID, CK_VOID_PTR pReserved) { + CACKEY_DEBUG_PRINTF("Called."); + + if (pReserved != NULL) { + CACKEY_DEBUG_PRINTF("Error. pReserved is not NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismList)(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (pulCount == NULL) { + CACKEY_DEBUG_PRINTF("Error. pulCount is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (pMechanismList == NULL) { + *pulCount = 3; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); + } + + if (*pulCount < 3) { + CACKEY_DEBUG_PRINTF("Error. Buffer too small."); + + return(CKR_BUFFER_TOO_SMALL); + } + + pMechanismList[0] = CKM_RSA_PKCS; + pMechanismList[1] = CKM_SHA1_RSA_PKCS; + *pulCount = 2; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismInfo)(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { + CACKEY_DEBUG_PRINTF("Called."); + + if (slotID != 0) { + /* Again, we only support one slot -- slot 0 */ + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", slotID); + + return(CKR_SLOT_ID_INVALID); + } + + if (pInfo == NULL) { + CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + /* XXX: This is untested, and further I'm not really sure if this is correct. */ + switch (type) { + case CKM_RSA_PKCS: + pInfo->ulMinKeySize = 512; + pInfo->ulMaxKeySize = 8192; + pInfo->flags = CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY; + break; + case CKM_RSA_X_509: + pInfo->ulMinKeySize = 512; + pInfo->ulMaxKeySize = 8192; + pInfo->flags = CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY; + break; + case CKM_SHA1_RSA_PKCS: + pInfo->ulMinKeySize = 512; + pInfo->ulMaxKeySize = 8192; + pInfo->flags = CKF_HW | CKF_SIGN | CKF_VERIFY; + break; + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +/* We don't support this method. */ +CK_DEFINE_FUNCTION(CK_RV, C_InitToken)(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_TOKEN_WRITE_PROTECTED (%i)", CKR_TOKEN_WRITE_PROTECTED); + + return(CKR_TOKEN_WRITE_PROTECTED); +} + +/* We don't support this method. */ +CK_DEFINE_FUNCTION(CK_RV, C_InitPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_TOKEN_WRITE_PROTECTED (%i)", CKR_TOKEN_WRITE_PROTECTED); + + return(CKR_TOKEN_WRITE_PROTECTED); +} + +/* We don't support this method. */ +CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewPinLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession) { + struct cackey_identity *identities; + unsigned long idx, num_ids, id_idx, curr_id_type, curr_ssh_id_idx; + CK_BYTE sigbuf[1024]; + ssize_t sigbuflen; + int mutex_retval; + int found_session = 0; + int fd; + + CACKEY_DEBUG_PRINTF("Called."); + + if (slotID != 0) { + /* We only support one slot -- slot 0 */ + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", slotID); + + return(CKR_SLOT_ID_INVALID); + } + + if ((flags & CKF_SERIAL_SESSION) != CKF_SERIAL_SESSION) { + return(CKR_SESSION_PARALLEL_NOT_SUPPORTED); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + /* Verify that the card is actually in the slot. */ + /* XXX: Talk to card */ + if (0) { + if (0) { + CACKEY_DEBUG_PRINTF("Error. Card not present. Returning CKR_DEVICE_REMOVED"); + + return(CKR_DEVICE_REMOVED); + } + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + for (idx = 1; idx < (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])); idx++) { + if (!cackey_sessions[idx].active) { + found_session = 1; + + *phSession = idx; + + cackey_sessions[idx].active = 1; + cackey_sessions[idx].slotID = slotID; + cackey_sessions[idx].state = CKS_RO_PUBLIC_SESSION; + cackey_sessions[idx].flags = flags; + cackey_sessions[idx].ulDeviceError = 0; + cackey_sessions[idx].pApplication = pApplication; + cackey_sessions[idx].Notify = notify; + + cackey_sessions[idx].identities = NULL; + cackey_sessions[idx].identities_count = 0; + + if (0) { + num_ids = 0; + /* XXX: Determine number of IDs */ + + /* Convert number of IDs to number of objects */ + num_ids = (CKO_PRIVATE_KEY - CKO_CERTIFICATE + 1) * num_ids; + + identities = malloc(num_ids * sizeof(*identities)); + + id_idx = 0; + for (;;) { + for (curr_id_type = CKO_CERTIFICATE; curr_id_type <= CKO_PRIVATE_KEY; curr_id_type++) { + /* XXX: Determine base index */ + + identities[id_idx].attributes = cackey_get_attributes(curr_id_type, NULL, -1, &identities[id_idx].attributes_count); + + if (identities[id_idx].attributes == NULL) { + identities[id_idx].attributes_count = 0; + } + + id_idx++; + } + } + + cackey_sessions[idx].identities = identities; + cackey_sessions[idx].identities_count = num_ids; + } + + cackey_sessions[idx].search_active = 0; + + cackey_sessions[idx].sign_active = 0; + + cackey_sessions[idx].decrypt_active = 0; + + break; + } + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!found_session) { + CACKEY_DEBUG_PRINTF("Returning CKR_SESSION_COUNT (%i)", CKR_SESSION_COUNT); + + return(CKR_SESSION_COUNT); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_CloseSession)(CK_SESSION_HANDLE hSession) { + CK_ATTRIBUTE *curr_attr; + unsigned long id_idx, attr_idx; + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + cackey_sessions[hSession].active = 0; + if (cackey_sessions[hSession].identities) { + for (id_idx = 0; id_idx < cackey_sessions[hSession].identities_count; id_idx++) { + if (cackey_sessions[hSession].identities[id_idx].attributes) { + for (attr_idx = 0; attr_idx < cackey_sessions[hSession].identities[id_idx].attributes_count; attr_idx++) { + curr_attr = &cackey_sessions[hSession].identities[id_idx].attributes[attr_idx]; + + if (curr_attr->pValue) { + free(curr_attr->pValue); + } + } + + free(cackey_sessions[hSession].identities[id_idx].attributes); + } + } + + free(cackey_sessions[hSession].identities); + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_CloseAllSessions)(CK_SLOT_ID slotID) { + uint32_t idx; + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (slotID != 0) { + /* Again, we only support one slot -- slot 0 */ + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", slotID); + + return(CKR_SLOT_ID_INVALID); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + for (idx = 0; idx < (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])); idx++) { + if (cackey_sessions[idx].active) { + if (cackey_sessions[idx].slotID != slotID) { + continue; + } + + cackey_mutex_unlock(cackey_biglock); + C_CloseSession(idx); + cackey_mutex_lock(cackey_biglock); + } + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetSessionInfo)(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (pInfo == NULL) { + CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + pInfo->slotID = cackey_sessions[hSession].slotID; + pInfo->state = cackey_sessions[hSession].state; + pInfo->flags = cackey_sessions[hSession].flags; + pInfo->ulDeviceError = cackey_sessions[hSession].ulDeviceError; + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetOperationState)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SetOperationState)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (userType != CKU_USER) { + CACKEY_DEBUG_PRINTF("Error. We only support USER mode, asked for %lu mode.", (unsigned long) userType) + + return(CKR_USER_TYPE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + cackey_sessions[hSession].state = CKS_RO_USER_FUNCTIONS; + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) { + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + cackey_sessions[hSession].state = CKS_RO_PUBLIC_SESSION; + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_CopyObject)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DestroyObject)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetObjectSize)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetAttributeValue)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { + CK_ATTRIBUTE *curr_attr; + struct cackey_identity *identity; + unsigned long identity_idx, attr_idx, sess_attr_idx, num_ids; + int mutex_retval; + CK_RV retval = CKR_OK; + CK_VOID_PTR pValue; + CK_ULONG ulValueLen; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (hObject == 0) { + CACKEY_DEBUG_PRINTF("Error. Object handle out of range."); + + return(CKR_OBJECT_HANDLE_INVALID); + } + + if (ulCount == 0) { + /* Short circuit, if zero objects were specified return zero items immediately */ + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i) (short circuit)", CKR_OK); + + return(CKR_OK); + } + + if (pTemplate == NULL) { + CACKEY_DEBUG_PRINTF("Error. pTemplate is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + identity_idx = hObject - 1; + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + num_ids = cackey_sessions[hSession].identities_count; + + if (identity_idx >= num_ids) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Object handle out of range. identity_idx = %lu, num_ids = %lu.", (unsigned long) identity_idx, (unsigned long) num_ids); + + return(CKR_OBJECT_HANDLE_INVALID); + } + + identity = &cackey_sessions[hSession].identities[identity_idx]; + + for (attr_idx = 0; attr_idx < ulCount; attr_idx++) { + curr_attr = &pTemplate[attr_idx]; + + pValue = NULL; + ulValueLen = (CK_LONG) -1; + + CACKEY_DEBUG_PRINTF("Looking for attribute 0x%08lx (identity:%lu) ...", (unsigned long) curr_attr->type, (unsigned long) identity_idx); + + for (sess_attr_idx = 0; sess_attr_idx < identity->attributes_count; sess_attr_idx++) { + if (identity->attributes[sess_attr_idx].type == curr_attr->type) { + CACKEY_DEBUG_PRINTF(" ... found it, pValue = %p, ulValueLen = %lu", identity->attributes[sess_attr_idx].pValue, identity->attributes[sess_attr_idx].ulValueLen); + + pValue = identity->attributes[sess_attr_idx].pValue; + ulValueLen = identity->attributes[sess_attr_idx].ulValueLen; + } + } + + if (curr_attr->pValue && pValue) { + if (curr_attr->ulValueLen >= ulValueLen) { + memcpy(curr_attr->pValue, pValue, ulValueLen); + } else { + ulValueLen = (CK_LONG) -1; + + retval = CKR_BUFFER_TOO_SMALL; + } + } + + curr_attr->ulValueLen = ulValueLen; + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (retval == CKR_ATTRIBUTE_TYPE_INVALID) { + CACKEY_DEBUG_PRINTF("Returning CKR_ATTRIBUTE_TYPE_INVALID (%i)", (int) retval); + } else if (retval == CKR_BUFFER_TOO_SMALL) { + CACKEY_DEBUG_PRINTF("Returning CKR_BUFFER_TOO_SMALL (%i)", (int) retval); + } else if (retval == CKR_OK) { + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", (int) retval); + } else { + CACKEY_DEBUG_PRINTF("Returning %i", (int) retval); + } + + return(retval); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SetAttributeValue)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (cackey_sessions[hSession].search_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Search already active."); + + return(CKR_OPERATION_ACTIVE); + } + + if (pTemplate != NULL) { + if (ulCount != 0) { + cackey_sessions[hSession].search_query_count = ulCount; + cackey_sessions[hSession].search_query = malloc(ulCount * sizeof(*pTemplate)); + + memcpy(cackey_sessions[hSession].search_query, pTemplate, ulCount * sizeof(*pTemplate)); + } else { + cackey_sessions[hSession].search_query_count = 0; + cackey_sessions[hSession].search_query = NULL; + } + } else { + if (ulCount != 0) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Search query specified as NULL, but number of query terms not specified as 0."); + + return(CKR_ARGUMENTS_BAD); + } + + cackey_sessions[hSession].search_query_count = 0; + cackey_sessions[hSession].search_query = NULL; + } + + cackey_sessions[hSession].search_active = 1; + cackey_sessions[hSession].search_curr_id = 0; + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_FindObjects)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { + struct cackey_identity *curr_id; + CK_ATTRIBUTE *curr_attr; + CK_ULONG curr_id_idx, curr_out_id_idx, curr_attr_idx, sess_attr_idx; + CK_ULONG matched_count, prev_matched_count; + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (pulObjectCount == NULL) { + CACKEY_DEBUG_PRINTF("Error. pulObjectCount is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (phObject == NULL && ulMaxObjectCount == 0) { + /* Short circuit, if zero objects were specified return zero items immediately */ + *pulObjectCount = 0; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i) (short circuit)", CKR_OK); + + return(CKR_OK); + } + + if (phObject == NULL) { + CACKEY_DEBUG_PRINTF("Error. phObject is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (ulMaxObjectCount == 0) { + CACKEY_DEBUG_PRINTF("Error. Maximum number of objects specified as zero."); + + return(CKR_ARGUMENTS_BAD); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (!cackey_sessions[hSession].search_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Search not active."); + + return(CKR_OPERATION_NOT_INITIALIZED); + } + + curr_id_idx = 0; + curr_out_id_idx = 0; + for (curr_id_idx = cackey_sessions[hSession].search_curr_id; curr_id_idx < cackey_sessions[hSession].identities_count && ulMaxObjectCount; curr_id_idx++) { + curr_id = &cackey_sessions[hSession].identities[curr_id_idx]; + + CACKEY_DEBUG_PRINTF("Processing identity:%lu", (unsigned long) curr_id_idx); + + matched_count = 0; + + for (curr_attr_idx = 0; curr_attr_idx < cackey_sessions[hSession].search_query_count; curr_attr_idx++) { + prev_matched_count = matched_count; + + curr_attr = &cackey_sessions[hSession].search_query[curr_attr_idx]; + + CACKEY_DEBUG_PRINTF(" Checking for attribute 0x%08lx in identity:%i...", (unsigned long) curr_attr->type, (int) curr_id_idx); + CACKEY_DEBUG_PRINTBUF(" Value looking for:", curr_attr->pValue, curr_attr->ulValueLen); + + for (sess_attr_idx = 0; sess_attr_idx < curr_id->attributes_count; sess_attr_idx++) { + if (curr_id->attributes[sess_attr_idx].type == curr_attr->type) { + CACKEY_DEBUG_PRINTF(" ... found matching type ..."); + CACKEY_DEBUG_PRINTBUF(" ... our value:", curr_id->attributes[sess_attr_idx].pValue, curr_id->attributes[sess_attr_idx].ulValueLen); + + if (curr_attr->pValue == NULL) { + CACKEY_DEBUG_PRINTF(" ... found wildcard match"); + + matched_count++; + + break; + } + + if (curr_attr->ulValueLen == curr_id->attributes[sess_attr_idx].ulValueLen && memcmp(curr_attr->pValue, curr_id->attributes[sess_attr_idx].pValue, curr_id->attributes[sess_attr_idx].ulValueLen) == 0) { + CACKEY_DEBUG_PRINTF(" ... found exact match"); + + matched_count++; + + break; + } + } + } + + /* If the attribute could not be matched, do not try to match additional attributes */ + if (prev_matched_count == matched_count) { + break; + } + } + + if (matched_count == cackey_sessions[hSession].search_query_count) { + CACKEY_DEBUG_PRINTF(" ... All %i attributes checked for found, adding identity:%i to returned list", (int) cackey_sessions[hSession].search_query_count, (int) curr_id_idx); + + phObject[curr_out_id_idx] = curr_id_idx + 1; + + ulMaxObjectCount--; + + curr_out_id_idx++; + } else { + CACKEY_DEBUG_PRINTF(" ... Not all %i (only found %i) attributes checked for found, not adding identity:%i", (int) cackey_sessions[hSession].search_query_count, (int) matched_count, (int) curr_id_idx); + } + } + cackey_sessions[hSession].search_curr_id = curr_id_idx; + *pulObjectCount = curr_out_id_idx; + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i), num objects = %lu", CKR_OK, *pulObjectCount); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsFinal)(CK_SESSION_HANDLE hSession) { + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (!cackey_sessions[hSession].search_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Search not active."); + + return(CKR_OPERATION_NOT_INITIALIZED); + } + + cackey_sessions[hSession].search_active = 0; + if (cackey_sessions[hSession].search_query) { + free(cackey_sessions[hSession].search_query); + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_EncryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Encrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_EncryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_EncryptFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { + int mutex_retval; + + hKey--; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (pMechanism == NULL) { + CACKEY_DEBUG_PRINTF("Error. pMechanism is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (pMechanism->mechanism != CKM_RSA_PKCS) { + CACKEY_DEBUG_PRINTF("Error. pMechanism->mechanism not specified as CKM_RSA_PKCS"); + + return(CKR_MECHANISM_PARAM_INVALID); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (cackey_sessions[hSession].decrypt_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Decrypt already in progress."); + + return(CKR_OPERATION_ACTIVE); + } + + if (hKey >= cackey_sessions[hSession].identities_count) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Key handle out of range."); + + return(CKR_KEY_HANDLE_INVALID); + } + + cackey_sessions[hSession].decrypt_active = 1; + + cackey_sessions[hSession].decrypt_mechanism = pMechanism->mechanism; + cackey_sessions[hSession].decrypt_mech_parm = pMechanism->pParameter; + cackey_sessions[hSession].decrypt_mech_parmlen = pMechanism->ulParameterLen; + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Decrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { + CK_ULONG datalen_update, datalen_final; + CK_RV decrypt_ret; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (pulDataLen == NULL) { + CACKEY_DEBUG_PRINTF("Error. pulDataLen is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + datalen_update = *pulDataLen; + + decrypt_ret = C_DecryptUpdate(hSession, pEncryptedData, ulEncryptedDataLen, pData, &datalen_update); + if (decrypt_ret != CKR_OK) { + CACKEY_DEBUG_PRINTF("Error. DecryptUpdate() returned failure (rv = %lu).", (unsigned long) decrypt_ret); + + return(decrypt_ret); + } + + if (pData) { + pData += datalen_update; + } + datalen_final = *pulDataLen - datalen_update; + + decrypt_ret = C_DecryptFinal(hSession, pData, &datalen_final); + if (decrypt_ret != CKR_OK) { + CACKEY_DEBUG_PRINTF("Error. DecryptFinal() returned failure (rv = %lu).", (unsigned long) decrypt_ret); + + return(decrypt_ret); + } + + *pulDataLen = datalen_update + datalen_final; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { + static CK_BYTE buf[16384]; + ssize_t buflen; + CK_RV retval = CKR_GENERAL_ERROR; + int mutex_retval; + int fd; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (pEncryptedPart == NULL && ulEncryptedPartLen == 0) { + /* Short circuit if we are asked to decrypt nothing... */ + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i) (short circuit)", CKR_OK); + + return(CKR_OK); + } + + if (pEncryptedPart == NULL) { + CACKEY_DEBUG_PRINTF("Error. pEncryptedPart is NULL, but ulEncryptedPartLen is not 0."); + + return(CKR_ARGUMENTS_BAD); + } + + if (ulEncryptedPartLen == 0) { + CACKEY_DEBUG_PRINTF("Error. ulEncryptedPartLen is 0, but pPart is not NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (pulPartLen == NULL) { + CACKEY_DEBUG_PRINTF("Error. pulPartLen is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (!cackey_sessions[hSession].decrypt_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Decrypt not active."); + + return(CKR_OPERATION_NOT_INITIALIZED); + } + + switch (cackey_sessions[hSession].decrypt_mechanism) { + case CKM_RSA_PKCS: + buflen = -1; + + /* XXX: Ask card to decrypt */ + + if (buflen < 0) { + /* Decryption failed. */ + retval = CKR_GENERAL_ERROR; + } else if (((unsigned long) buflen) > *pulPartLen && pPart) { + /* Decrypted data too large */ + retval = CKR_BUFFER_TOO_SMALL; + } else { + if (pPart) { + memcpy(pPart, buf, buflen); + } + + *pulPartLen = buflen; + + retval = CKR_OK; + } + + break; + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning %i", (int) retval); + + return(retval); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) { + int mutex_retval; + int terminate_decrypt = 1; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (pulLastPartLen == NULL) { + CACKEY_DEBUG_PRINTF("Error. pulLastPartLen is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (!cackey_sessions[hSession].decrypt_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Decrypt not active."); + + return(CKR_OPERATION_NOT_INITIALIZED); + } + + *pulLastPartLen = 0; + + if (pLastPart == NULL) { + terminate_decrypt = 0; + } + + if (terminate_decrypt) { + cackey_sessions[hSession].decrypt_active = 0; + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DigestInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Digest)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DigestUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DigestKey)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DigestFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SignInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { + int mutex_retval; + + hKey--; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (pMechanism == NULL) { + CACKEY_DEBUG_PRINTF("Error. pMechanism is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (pMechanism->mechanism != CKM_RSA_PKCS && pMechanism->mechanism != CKM_SHA1_RSA_PKCS) { + CACKEY_DEBUG_PRINTF("Error. pMechanism->mechanism not specified as CKM_RSA_PKCS or CKM_SHA1_RSA_PKCS"); + + return(CKR_MECHANISM_PARAM_INVALID); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (cackey_sessions[hSession].sign_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Sign already in progress."); + + return(CKR_OPERATION_ACTIVE); + } + + if (hKey >= cackey_sessions[hSession].identities_count) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Key handle out of range."); + + return(CKR_KEY_HANDLE_INVALID); + } + + cackey_sessions[hSession].sign_active = 1; + + cackey_sessions[hSession].sign_mechanism = pMechanism->mechanism; + + cackey_sessions[hSession].sign_buflen = 128; + cackey_sessions[hSession].sign_bufused = 0; + cackey_sessions[hSession].sign_buf = malloc(sizeof(*cackey_sessions[hSession].sign_buf) * cackey_sessions[hSession].sign_buflen); + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Sign)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { + CK_RV sign_ret; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + sign_ret = C_SignUpdate(hSession, pData, ulDataLen); + if (sign_ret != CKR_OK) { + CACKEY_DEBUG_PRINTF("Error. SignUpdate() returned failure (rv = %lu).", (unsigned long) sign_ret); + + return(sign_ret); + } + + sign_ret = C_SignFinal(hSession, pSignature, pulSignatureLen); + if (sign_ret != CKR_OK) { + CACKEY_DEBUG_PRINTF("Error. SignFinal() returned failure (rv = %lu).", (unsigned long) sign_ret); + + return(sign_ret); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SignUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { + int mutex_retval; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (pPart == NULL && ulPartLen == 0) { + /* Short circuit if we are asked to sign nothing... */ + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i) (short circuit)", CKR_OK); + + return(CKR_OK); + } + + if (pPart == NULL) { + CACKEY_DEBUG_PRINTF("Error. pPart is NULL, but ulPartLen is not 0."); + + return(CKR_ARGUMENTS_BAD); + } + + if (ulPartLen == 0) { + CACKEY_DEBUG_PRINTF("Error. ulPartLen is 0, but pPart is not NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (!cackey_sessions[hSession].sign_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Sign not active."); + + return(CKR_OPERATION_NOT_INITIALIZED); + } + + switch (cackey_sessions[hSession].sign_mechanism) { + case CKM_RSA_PKCS: + /* Accumulate directly */ + if ((cackey_sessions[hSession].sign_bufused + ulPartLen) > cackey_sessions[hSession].sign_buflen) { + cackey_sessions[hSession].sign_buflen *= 2; + + cackey_sessions[hSession].sign_buf = realloc(cackey_sessions[hSession].sign_buf, sizeof(*cackey_sessions[hSession].sign_buf) * cackey_sessions[hSession].sign_buflen); + } + + memcpy(cackey_sessions[hSession].sign_buf + cackey_sessions[hSession].sign_bufused, pPart, ulPartLen); + + cackey_sessions[hSession].sign_bufused += ulPartLen; + + break; + case CKM_SHA1_RSA_PKCS: + /* Accumulate into a SHA1 hash */ + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); + break; + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SignFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { + static CK_BYTE sigbuf[1024]; + ssize_t sigbuflen; + CK_RV retval = CKR_GENERAL_ERROR; + int terminate_sign = 1; + int mutex_retval; + int fd; + + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + if (pulSignatureLen == NULL) { + CACKEY_DEBUG_PRINTF("Error. pulSignatureLen is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + if (hSession == 0 || hSession >= (sizeof(cackey_sessions) / sizeof(cackey_sessions[0]))) { + CACKEY_DEBUG_PRINTF("Error. Session out of range."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + if (!cackey_sessions[hSession].active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Session not active."); + + return(CKR_SESSION_HANDLE_INVALID); + } + + if (!cackey_sessions[hSession].sign_active) { + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Error. Sign not active."); + + return(CKR_OPERATION_NOT_INITIALIZED); + } + + switch (cackey_sessions[hSession].sign_mechanism) { + case CKM_RSA_PKCS: + sigbuflen = -1; + + /* XXX: Ask card to sign */ + + if (sigbuflen < 0) { + /* Signing failed. */ + retval = CKR_GENERAL_ERROR; + } else if (((unsigned long) sigbuflen) > *pulSignatureLen && pSignature) { + /* Signed data too large */ + retval = CKR_BUFFER_TOO_SMALL; + + terminate_sign = 0; + } else { + terminate_sign = 0; + + if (pSignature) { + memcpy(pSignature, sigbuf, sigbuflen); + + terminate_sign = 1; + } + + *pulSignatureLen = sigbuflen; + + retval = CKR_OK; + } + + break; + case CKM_SHA1_RSA_PKCS: + /* Accumulate into a SHA1 hash */ + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); + break; + } + + if (terminate_sign) { + if (cackey_sessions[hSession].sign_buf) { + free(cackey_sessions[hSession].sign_buf); + } + + cackey_sessions[hSession].sign_active = 0; + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } + + CACKEY_DEBUG_PRINTF("Returning %i", (int) retval); + + return(retval); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SignRecoverInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SignRecover)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_Verify)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecoverInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecover)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DigestEncryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptDigestUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SignEncryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptVerifyUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GenerateKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_WrapKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_DeriveKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_SeedRandom)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_DEFINE_FUNCTION(CK_RV, C_GenerateRandom)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) { + CACKEY_DEBUG_PRINTF("Called."); + + if (!cackey_initialized) { + CACKEY_DEBUG_PRINTF("Error. Not initialized."); + + return(CKR_CRYPTOKI_NOT_INITIALIZED); + } + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); + + return(CKR_FUNCTION_NOT_SUPPORTED); +} + +/* Deprecated Function */ +CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionStatus)(CK_SESSION_HANDLE hSession) { + CACKEY_DEBUG_PRINTF("Called."); + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_PARALLEL (%i)", CKR_FUNCTION_NOT_PARALLEL); + + return(CKR_FUNCTION_NOT_PARALLEL); + + hSession = hSession; /* Supress unused variable warning */ +} + +/* Deprecated Function */ +CK_DEFINE_FUNCTION(CK_RV, C_CancelFunction)(CK_SESSION_HANDLE hSession) { + CACKEY_DEBUG_PRINTF("Called."); + + CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_PARALLEL (%i)", CKR_FUNCTION_NOT_PARALLEL); + + return(CKR_FUNCTION_NOT_PARALLEL); + + hSession = hSession; /* Supress unused variable warning */ +} + +CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { + CK_FUNCTION_LIST_PTR pFunctionList; + + CACKEY_DEBUG_PRINTF("Called."); + + if (ppFunctionList == NULL) { + CACKEY_DEBUG_PRINTF("Error. ppFunctionList is NULL."); + + return(CKR_ARGUMENTS_BAD); + } + + pFunctionList = malloc(sizeof(*pFunctionList)); + + pFunctionList->version.major = ((CACKEY_CRYPTOKI_VERSION_CODE) >> 16) & 0xff; + pFunctionList->version.minor = ((CACKEY_CRYPTOKI_VERSION_CODE) >> 8) & 0xff; + + pFunctionList->C_Initialize = C_Initialize; + pFunctionList->C_Finalize = C_Finalize; + pFunctionList->C_GetInfo = C_GetInfo; + pFunctionList->C_GetSlotList = C_GetSlotList; + pFunctionList->C_GetSlotInfo = C_GetSlotInfo; + pFunctionList->C_GetTokenInfo = C_GetTokenInfo; + pFunctionList->C_WaitForSlotEvent = C_WaitForSlotEvent; + pFunctionList->C_GetMechanismList = C_GetMechanismList; + pFunctionList->C_GetMechanismInfo = C_GetMechanismInfo; + pFunctionList->C_InitToken = C_InitToken; + pFunctionList->C_InitPIN = C_InitPIN; + pFunctionList->C_SetPIN = C_SetPIN; + pFunctionList->C_OpenSession = C_OpenSession; + pFunctionList->C_CloseSession = C_CloseSession; + pFunctionList->C_CloseAllSessions = C_CloseAllSessions; + pFunctionList->C_GetSessionInfo = C_GetSessionInfo; + pFunctionList->C_GetOperationState = C_GetOperationState; + pFunctionList->C_SetOperationState = C_SetOperationState; + pFunctionList->C_Login = C_Login; + pFunctionList->C_Logout = C_Logout; + pFunctionList->C_CreateObject = C_CreateObject; + pFunctionList->C_CopyObject = C_CopyObject; + pFunctionList->C_DestroyObject = C_DestroyObject; + pFunctionList->C_GetObjectSize = C_GetObjectSize; + pFunctionList->C_GetAttributeValue = C_GetAttributeValue; + pFunctionList->C_SetAttributeValue = C_SetAttributeValue; + pFunctionList->C_FindObjectsInit = C_FindObjectsInit; + pFunctionList->C_FindObjects = C_FindObjects; + pFunctionList->C_FindObjectsFinal = C_FindObjectsFinal; + pFunctionList->C_EncryptInit = C_EncryptInit; + pFunctionList->C_Encrypt = C_Encrypt; + pFunctionList->C_EncryptUpdate = C_EncryptUpdate; + pFunctionList->C_EncryptFinal = C_EncryptFinal; + pFunctionList->C_DecryptInit = C_DecryptInit; + pFunctionList->C_Decrypt = C_Decrypt; + pFunctionList->C_DecryptUpdate = C_DecryptUpdate; + pFunctionList->C_DecryptFinal = C_DecryptFinal; + pFunctionList->C_DigestInit = C_DigestInit; + pFunctionList->C_Digest = C_Digest; + pFunctionList->C_DigestUpdate = C_DigestUpdate; + pFunctionList->C_DigestKey = C_DigestKey; + pFunctionList->C_DigestFinal = C_DigestFinal; + pFunctionList->C_SignInit = C_SignInit; + pFunctionList->C_Sign = C_Sign; + pFunctionList->C_SignUpdate = C_SignUpdate; + pFunctionList->C_SignFinal = C_SignFinal; + pFunctionList->C_SignRecoverInit = C_SignRecoverInit; + pFunctionList->C_SignRecover = C_SignRecover; + pFunctionList->C_VerifyInit = C_VerifyInit; + pFunctionList->C_Verify = C_Verify; + pFunctionList->C_VerifyUpdate = C_VerifyUpdate; + pFunctionList->C_VerifyFinal = C_VerifyFinal; + pFunctionList->C_VerifyRecoverInit = C_VerifyRecoverInit; + pFunctionList->C_VerifyRecover = C_VerifyRecover; + pFunctionList->C_DigestEncryptUpdate = C_DigestEncryptUpdate; + pFunctionList->C_DecryptDigestUpdate = C_DecryptDigestUpdate; + pFunctionList->C_SignEncryptUpdate = C_SignEncryptUpdate; + pFunctionList->C_DecryptVerifyUpdate = C_DecryptVerifyUpdate; + pFunctionList->C_GenerateKey = C_GenerateKey; + pFunctionList->C_GenerateKeyPair = C_GenerateKeyPair; + pFunctionList->C_WrapKey = C_WrapKey; + pFunctionList->C_UnwrapKey = C_UnwrapKey; + pFunctionList->C_DeriveKey = C_DeriveKey; + pFunctionList->C_SeedRandom = C_SeedRandom; + pFunctionList->C_GenerateRandom = C_GenerateRandom; + pFunctionList->C_GetFunctionStatus = C_GetFunctionStatus; + pFunctionList->C_CancelFunction = C_CancelFunction; + pFunctionList->C_GetFunctionList = C_GetFunctionList; + + *ppFunctionList = pFunctionList; + + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + + return(CKR_OK); +}