| /* |
| * exported pkcs11 functions for the software token |
| * |
| * Copyright (C) 2019 James.Bottomley@HansenPartnership.com |
| * |
| * SPDX-License-Identifier: LGPL-2.1-only |
| */ |
| |
| #include <string.h> |
| #include <stdio.h> |
| |
| #include "openssl-pkcs11.h" |
| |
| /* according to PKCS11 attribute values have to be space padded */ |
| #define min(x, y) ((x) < (y)?(x):(y)) |
| #define ATTRIB(x, y) do { \ |
| memset(x, ' ', sizeof(x)); \ |
| memcpy(x, y, min(strlen(y), sizeof(x))); \ |
| } while(0) |
| |
| static CK_FUNCTION_LIST module_functions; |
| |
| /* key type (public or private) is encoded in the lowest bit |
| * of the object. The upper bits are the shifted section number */ |
| enum obj_type { |
| KEY_PUBLIC = 0, |
| KEY_PRIVATE = 1, |
| KEY_CERT = 2, |
| }; |
| |
| static inline int obj_to_section(int obj) |
| { |
| return obj >> 2; |
| } |
| |
| static inline int section_to_obj(int sec) |
| { |
| return sec << 2; |
| } |
| |
| static inline enum obj_type obj_type(int obj) |
| { |
| return obj & 3; |
| } |
| |
| static inline int obj_to_attr(int obj) |
| { |
| switch (obj_type(obj)) { |
| case KEY_PUBLIC: |
| return BOOL_FOR_PUBLIC; |
| case KEY_PRIVATE: |
| return BOOL_FOR_PRIVATE; |
| case KEY_CERT: |
| return BOOL_FOR_CERT; |
| } |
| return 0; /* notreached; gcc error */ |
| } |
| |
| /* trick: certificates are the only object to have CKA_VALUE */ |
| static inline int has_cert(int sec_num) |
| { |
| return cache_get_by_secnum(sec_num, "CKA_VALUE", NULL) != NULL; |
| } |
| |
| static inline CK_OBJECT_CLASS obj_to_class(int obj) |
| { |
| switch (obj_type(obj)) { |
| case KEY_PUBLIC: |
| return CKO_PUBLIC_KEY; |
| case KEY_PRIVATE: |
| return CKO_PRIVATE_KEY; |
| case KEY_CERT: |
| return CKO_CERTIFICATE; |
| } |
| return 0; /* notreached; gcc error */ |
| } |
| |
| CK_RV |
| C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list) |
| { |
| if (!list) |
| return CKR_ARGUMENTS_BAD; |
| |
| *list = &module_functions; |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_Initialize(CK_VOID_PTR args) |
| { |
| if (!args) { |
| /* args communicate threading information, just say we |
| * can't do threading */ |
| return CKR_CANT_LOCK; |
| } |
| if (parse_ini_file()) |
| return CKR_OK; |
| else |
| return CKR_GENERAL_ERROR; |
| } |
| |
| CK_RV |
| C_Finalize(CK_VOID_PTR dummy) |
| { |
| free_ini_file(); |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_GetInfo(CK_INFO_PTR info) |
| { |
| if (!info) |
| return CKR_ARGUMENTS_BAD; |
| |
| memset(info, 0, sizeof(*info)); |
| /* conform to pkcs11 spec version 2.20 */ |
| info->cryptokiVersion.major = 2; |
| info->cryptokiVersion.minor = 20; |
| |
| info->libraryVersion.major = LIBRARY_VERSION_MAJOR; |
| info->libraryVersion.minor = LIBRARY_VERSION_MINOR; |
| info->flags = 0; |
| ATTRIB(info->manufacturerID, |
| cache_get_default(GLOBAL_SECTION_NUM, "manufacturer id", |
| PACKAGE_NAME)); |
| ATTRIB(info->libraryDescription, |
| cache_get_default(GLOBAL_SECTION_NUM, "library description", |
| PACKAGE_STRING)); |
| |
| return CKR_OK; |
| } |
| |
| /* |
| * Each non global section corresponds to a key slot. We number the |
| * slots from 1...n because slot 0 would be the global section |
| */ |
| CK_RV |
| C_GetSlotList(CK_BBOOL present, CK_SLOT_ID_PTR list, CK_ULONG_PTR count) |
| { |
| int c = cache_get_sections(), i; |
| |
| if (c == 0 || c == 1) { |
| /* no slots can cause a failure so we need to pretend |
| * to have at least one */ |
| if (list) |
| *list = 0; |
| *count = 1; |
| |
| return CKR_OK; |
| } |
| if (list) |
| for (i = 1; i < c; i++) |
| *list++ = i; |
| if (count) |
| *count = c - 1; |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_GetTokenInfo(CK_SLOT_ID slot, CK_TOKEN_INFO_PTR info) |
| { |
| const char *section, *serial; |
| int count = cache_get_sections(); |
| |
| if (!info) |
| return CKR_ARGUMENTS_BAD; |
| memset(info, 0, sizeof(*info)); |
| if (slot < 1) { |
| /* pretend slot is empty */ |
| return CKR_OK; |
| } else if (slot > count) |
| return CKR_ARGUMENTS_BAD; |
| |
| section = cache_get_section(slot); |
| serial = cache_get_by_secnum(slot, "serial", NULL); |
| |
| ATTRIB(info->manufacturerID, PACKAGE_NAME); |
| ATTRIB(info->model, PACKAGE_VERSION); |
| ATTRIB(info->label, section); |
| ATTRIB(info->serialNumber, serial); |
| |
| info->flags = CKF_LOGIN_REQUIRED|CKF_TOKEN_INITIALIZED|CKF_USER_PIN_INITIALIZED; |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_GetSlotInfo(CK_SLOT_ID slot, CK_SLOT_INFO_PTR info) |
| { |
| const char *section; |
| |
| if (!info) |
| return CKR_ARGUMENTS_BAD; |
| if (slot > cache_get_sections()) |
| return CKR_ARGUMENTS_BAD; |
| section = cache_get_section(slot); |
| memset(info, 0, sizeof(*info)); |
| info->firmwareVersion.major = LIBRARY_VERSION_MAJOR; |
| info->firmwareVersion.minor = LIBRARY_VERSION_MINOR; |
| |
| info->hardwareVersion.major = LIBRARY_VERSION_MAJOR; |
| info->hardwareVersion.minor = LIBRARY_VERSION_MINOR; |
| info->flags = 0; |
| ATTRIB(info->manufacturerID, |
| cache_get_default(GLOBAL_SECTION_NUM, "manufacturer id", |
| PACKAGE_NAME)); |
| ATTRIB(info->slotDescription, |
| cache_get_default(slot, "slot description", |
| section)); |
| info->flags = CKF_TOKEN_PRESENT; |
| |
| return CKR_OK; |
| } |
| |
| static int session_init(CK_SESSION_HANDLE handle) |
| { |
| return (int)(unsigned long)cache_get_by_secnum(handle, "session_init", NULL); |
| } |
| |
| static int logged_in(CK_SESSION_HANDLE handle) |
| { |
| const char *pkey = cache_get_by_secnum(handle, "pkey", NULL); |
| |
| return pkey != NULL; |
| } |
| |
| CK_RV C_OpenSession(CK_SLOT_ID slot, CK_FLAGS flags, CK_VOID_PTR app, |
| CK_NOTIFY notify, CK_SESSION_HANDLE_PTR handle) |
| { |
| int init; |
| |
| if (!handle) |
| return CKR_ARGUMENTS_BAD; |
| if (slot > cache_get_sections() - 1) |
| return CKR_ARGUMENTS_BAD; |
| init = session_init(slot); |
| |
| init++; |
| cache_add_by_secnum(slot, "session_init", (const char *)(long)init, |
| CACHE_INT); |
| *handle = slot; |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_CloseSession(CK_SESSION_HANDLE handle) |
| { |
| int init = session_init(handle); |
| |
| if (!init) |
| return CKR_SESSION_HANDLE_INVALID; |
| --init; |
| cache_add_by_secnum(handle, "session_init", (const char *)(long)init, |
| CACHE_INT); |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_CloseAllSessions(CK_SLOT_ID slot) |
| { |
| int i; |
| const int count = cache_get_sections() - 1; |
| |
| for (i = 1; i < count; i++) |
| cache_add_by_secnum(slot, "session_init", 0, CACHE_INT); |
| |
| return CKR_OK; |
| } |
| |
| static void attr_long_from_cache(int sec, CK_ATTRIBUTE_PTR attr, |
| const char *key, int key_type) |
| { |
| int len = 0; |
| const char *value = cache_get_by_secnum(sec, key, &len); |
| |
| if (len != CACHE_INT) { |
| attr->ulValueLen = 0; |
| return; |
| } |
| |
| if (attr->pValue) |
| *((CK_LONG *)attr->pValue) = (unsigned long)value; |
| attr->ulValueLen = sizeof(CK_LONG); |
| } |
| |
| static void attr_bool_from_cache(int sec, CK_ATTRIBUTE_PTR attr, |
| const char *key, int key_type) |
| { |
| int len = 0; |
| unsigned long value = (unsigned long)cache_get_by_secnum(sec, key, &len); |
| |
| if (len != CACHE_INT) { |
| /* all booleans return false from not found */ |
| value = 0; |
| } else if (value & key_type) { |
| value = 1; |
| } else { |
| value = 0; |
| } |
| |
| if (attr->pValue) |
| *((CK_BYTE *)attr->pValue) = value; |
| |
| attr->ulValueLen = sizeof(CK_BYTE); |
| } |
| |
| static void attr_from_cache(int sec, CK_ATTRIBUTE_PTR attr, const char *key, |
| int key_type) |
| { |
| int len; |
| const char *value = cache_get_by_secnum(sec, key, &len); |
| |
| if (!value) { |
| attr->ulValueLen = 0; |
| return; |
| } |
| |
| if (attr->pValue) |
| memcpy(attr->pValue, value, len); |
| attr->ulValueLen = len; |
| } |
| |
| static void |
| getattribute(unsigned long obj, CK_ATTRIBUTE_PTR attr) |
| { |
| int sec = obj_to_section(obj); |
| int key_type = obj_to_attr(obj); |
| |
| switch (attr->type) { |
| case CKA_CLASS: |
| attr_from_cache(sec, attr, "CKA_CLASS", key_type); |
| if (attr->ulValueLen != 0) |
| break; |
| if (attr->pValue) |
| *((CK_OBJECT_CLASS *)attr->pValue) = obj_to_class(obj); |
| attr->ulValueLen = sizeof(CK_OBJECT_CLASS); |
| break; |
| case CKA_ID: |
| attr_from_cache(sec, attr, "id", key_type); |
| break; |
| case CKA_LABEL: { |
| const char *val; |
| int len; |
| |
| val = cache_get_by_secnum(sec, "label", &len); |
| if (!val) { |
| val = cache_get_section(sec); |
| len = strlen(val); |
| } |
| if (attr->pValue) |
| memcpy(attr->pValue, val, len); |
| attr->ulValueLen = len; |
| break; |
| } |
| |
| #define X(x, s, f) \ |
| case x: \ |
| f(sec, attr, s, key_type); \ |
| break |
| #define Xa(x) X(x, #x, attr_from_cache) |
| #define Xl(x) X(x, #x, attr_long_from_cache) |
| #define Xb(x) X(x, #x, attr_bool_from_cache) |
| |
| Xa(CKA_MODULUS); |
| Xa(CKA_PUBLIC_EXPONENT); |
| Xa(CKA_EC_POINT); |
| Xa(CKA_EC_PARAMS); |
| Xa(CKA_VALUE); |
| Xa(CKA_ISSUER); |
| Xa(CKA_SUBJECT); |
| Xa(CKA_SERIAL_NUMBER); |
| Xl(CKA_MODULUS_BITS); |
| Xl(CKA_KEY_TYPE); |
| Xl(CKA_CERTIFICATE_TYPE); |
| Xb(CKA_TOKEN); |
| Xb(CKA_WRAP); |
| Xb(CKA_UNWRAP); |
| Xb(CKA_TRUSTED); |
| Xb(CKA_SENSITIVE); |
| Xb(CKA_EXTRACTABLE); |
| Xb(CKA_NEVER_EXTRACTABLE); |
| Xb(CKA_ALWAYS_AUTHENTICATE); |
| Xb(CKA_ENCRYPT); |
| Xb(CKA_VERIFY); |
| Xb(CKA_VERIFY_RECOVER); |
| Xb(CKA_DERIVE); |
| Xb(CKA_PRIVATE); |
| Xb(CKA_SIGN); |
| Xb(CKA_DECRYPT); |
| default: |
| attr->ulValueLen = 0; |
| break; |
| } |
| } |
| |
| static void set_find(CK_SESSION_HANDLE handle, int cur_find, |
| CK_OBJECT_CLASS find_restriction) |
| { |
| cache_add_by_secnum(handle, "cur_find", |
| (const char *)(unsigned long)cur_find, CACHE_INT); |
| cache_add_by_secnum(handle, "find_restriction", |
| (const char *)(unsigned long)find_restriction, |
| CACHE_INT); |
| } |
| |
| static void get_find(CK_SESSION_HANDLE handle, int *cur_find, |
| CK_OBJECT_CLASS *find_restriction) |
| { |
| *cur_find = (int)(long)cache_get_by_secnum(handle, "cur_find", NULL); |
| *find_restriction = (CK_OBJECT_CLASS)(long) |
| cache_get_by_secnum(handle, "find_restriction", NULL); |
| } |
| |
| CK_RV |
| C_FindObjectsInit(CK_SESSION_HANDLE handle, CK_ATTRIBUTE_PTR template, |
| CK_ULONG count) |
| { |
| int i; |
| CK_ATTRIBUTE attr; |
| char *buf[1024]; |
| const int obj = section_to_obj(handle); /* only look up public attributes */ |
| int cur_find = -1; |
| CK_OBJECT_CLASS find_restriction = 0; |
| |
| if (!session_init(handle)) |
| return CKR_SESSION_HANDLE_INVALID; |
| |
| attr.pValue = buf; |
| |
| for (i = 0; i < count; i++) { |
| if (template[i].type == CKA_CLASS) { |
| find_restriction = *((CK_OBJECT_CLASS *)template[i].pValue); |
| continue; |
| } |
| attr.type = template[i].type; |
| getattribute(obj, &attr); |
| if (attr.ulValueLen != template[i].ulValueLen || |
| memcmp(attr.pValue, template[i].pValue, attr.ulValueLen) != 0) |
| goto fail; |
| } |
| if (find_restriction != CKO_PUBLIC_KEY && |
| find_restriction != CKO_PRIVATE_KEY && |
| find_restriction != CKO_CERTIFICATE) |
| goto fail; |
| if (!find_restriction) { |
| cur_find = 1; |
| if (logged_in(handle)) |
| cur_find++; |
| if (has_cert(handle)) |
| cur_find++; |
| } else { |
| /* only one key */ |
| if (find_restriction == CKO_PRIVATE_KEY && !logged_in(handle)) |
| goto fail; |
| |
| if (find_restriction == CKO_CERTIFICATE && !has_cert(handle)) |
| goto fail; |
| |
| cur_find = 1; |
| } |
| fail: |
| set_find(handle, cur_find, find_restriction); |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_FindObjects(CK_SESSION_HANDLE handle, CK_OBJECT_HANDLE_PTR objs, |
| CK_ULONG max, CK_ULONG_PTR count) |
| { |
| const int pub_obj = section_to_obj(handle) | KEY_PUBLIC; |
| const int priv_obj = section_to_obj(handle) | KEY_PRIVATE; |
| const int cert_obj = section_to_obj(handle) | KEY_CERT; |
| int cur_find; |
| CK_OBJECT_CLASS find_restriction; |
| |
| get_find(handle, &cur_find, &find_restriction); |
| |
| if (cur_find > 0 && max >= cur_find) { |
| if (find_restriction != 0) { |
| *count = 1; |
| switch (find_restriction) { |
| case CKO_PRIVATE_KEY: |
| objs[0] = priv_obj; |
| break; |
| |
| case CKO_PUBLIC_KEY: |
| objs[0] = pub_obj; |
| break; |
| |
| case CKO_CERTIFICATE: |
| objs[0] = cert_obj; |
| break; |
| |
| default: |
| *count = 0; |
| } |
| } else { |
| /* no find restriction: are we logged in and do we have certificates? */ |
| if (logged_in(handle)) { |
| *count = 2; |
| objs[0] = pub_obj; |
| objs[1] = priv_obj; |
| } else { |
| *count = 1; |
| objs[0] = pub_obj; |
| } |
| if (has_cert(handle)) { |
| objs[*count] = cert_obj; |
| (*count)++; |
| } |
| } |
| } else { |
| *count = 0; |
| } |
| cur_find -= *count; |
| |
| set_find(handle, cur_find, find_restriction); |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_FindObjectsFinal(CK_SESSION_HANDLE handle) |
| { |
| set_find(handle, -1, 0); |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_GetAttributeValue(CK_SESSION_HANDLE handle, CK_OBJECT_HANDLE obj, |
| CK_ATTRIBUTE_PTR attr, CK_ULONG count) |
| { |
| int i; |
| |
| if (obj_to_section(obj) != handle && handle >= cache_get_sections()) |
| return CKR_ARGUMENTS_BAD; |
| |
| for (i = 0; i < count; i++) { |
| getattribute(obj, &attr[i]); |
| } |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_GetSessionInfo(CK_SESSION_HANDLE handle, CK_SESSION_INFO_PTR info) |
| { |
| if (!info) |
| return CKR_ARGUMENTS_BAD; |
| if (!session_init(handle)) |
| return CKR_SESSION_HANDLE_INVALID; |
| memset(info, 0, sizeof(*info)); |
| info->state = logged_in(handle) ? |
| CKS_RO_USER_FUNCTIONS : CKS_RO_PUBLIC_SESSION; |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_Login(CK_SESSION_HANDLE handle, CK_USER_TYPE type, |
| CK_UTF8CHAR_PTR pin, CK_ULONG pin_len) |
| { |
| int rc; |
| |
| if (type != CKU_USER) |
| return CKR_ARGUMENTS_BAD; |
| rc = crypto_load_private_key(handle, pin, pin_len); |
| if (rc) |
| return CKR_PIN_INCORRECT; |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_Logout(CK_SESSION_HANDLE handle) |
| { |
| crypto_free_private_key(handle); |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_GetMechanismList(CK_SLOT_ID slot, CK_MECHANISM_TYPE_PTR mechs, |
| CK_ULONG_PTR count) |
| { |
| crypto_fill_mechanism_list(slot, mechs, count); |
| |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_GetMechanismInfo(CK_SLOT_ID slot, CK_MECHANISM_TYPE type, |
| CK_MECHANISM_INFO_PTR info) |
| { |
| if (!crypto_check_mechanism(slot, type, info)) { |
| fprintf(stderr, "Bad Mechanism: 0x%lx\n", type); |
| return CKR_ARGUMENTS_BAD; |
| } |
| return CKR_OK; |
| } |
| |
| void *opstate; |
| |
| CK_RV |
| C_SignInit(CK_SESSION_HANDLE handle, CK_MECHANISM_PTR mech, |
| CK_OBJECT_HANDLE key) |
| { |
| if (obj_type(key) != KEY_PRIVATE || obj_to_section(key) != handle) |
| return CKR_ARGUMENTS_BAD; |
| opstate = crypto_sign_init(handle, mech); |
| if (opstate) |
| return CKR_OK; |
| return CKR_ARGUMENTS_BAD; |
| } |
| |
| CK_RV |
| C_Sign(CK_SESSION_HANDLE handle, CK_BYTE_PTR data, CK_ULONG data_len, |
| CK_BYTE_PTR sig, CK_ULONG_PTR sig_len) |
| { |
| if (crypto_sign(handle, opstate, data, data_len, sig, sig_len)) |
| return CKR_ARGUMENTS_BAD; |
| return CKR_OK; |
| } |
| |
| CK_RV |
| C_DecryptInit(CK_SESSION_HANDLE handle, CK_MECHANISM_PTR mech, |
| CK_OBJECT_HANDLE key) |
| { |
| if (obj_type(key) != KEY_PRIVATE || obj_to_section(key) != handle) |
| return CKR_ARGUMENTS_BAD; |
| opstate = crypto_decrypt_init(handle, mech); |
| if (opstate) |
| return CKR_OK; |
| return CKR_ARGUMENTS_BAD; |
| } |
| |
| CK_RV |
| C_Decrypt(CK_SESSION_HANDLE handle, CK_BYTE_PTR enc_data, CK_ULONG enc_len, |
| CK_BYTE_PTR data, CK_ULONG_PTR data_len) |
| { |
| if (crypto_decrypt(opstate, enc_data, enc_len, data, data_len)) |
| return CKR_ARGUMENTS_BAD; |
| return CKR_OK; |
| } |
| |
| #define F(X) \ |
| static CK_RV U_##X(void) \ |
| { \ |
| fprintf(stderr, "Unimplemented: " #X "\n"); \ |
| return CKR_FUNCTION_NOT_SUPPORTED; \ |
| } |
| |
| #define U(X) \ |
| .X = (CK_##X)U_##X |
| |
| F(C_CancelFunction) |
| F(C_CopyObject) |
| F(C_CreateObject) |
| F(C_DecryptDigestUpdate) |
| F(C_DecryptFinal) |
| F(C_DecryptUpdate) |
| F(C_DecryptVerifyUpdate) |
| F(C_DeriveKey) |
| F(C_DestroyObject) |
| F(C_Digest) |
| F(C_DigestEncryptUpdate) |
| F(C_DigestFinal) |
| F(C_DigestInit) |
| F(C_DigestKey) |
| F(C_DigestUpdate) |
| F(C_Encrypt) |
| F(C_EncryptFinal) |
| F(C_EncryptInit) |
| F(C_EncryptUpdate) |
| F(C_GenerateKey) |
| F(C_GenerateKeyPair) |
| F(C_GenerateRandom) |
| F(C_GetFunctionStatus) |
| F(C_GetObjectSize) |
| F(C_GetOperationState) |
| F(C_InitPIN) |
| F(C_InitToken) |
| F(C_SeedRandom) |
| F(C_SetAttributeValue) |
| F(C_SetOperationState) |
| F(C_SetPIN) |
| F(C_SignEncryptUpdate) |
| F(C_SignFinal) |
| F(C_SignRecover) |
| F(C_SignRecoverInit) |
| F(C_SignUpdate) |
| F(C_UnwrapKey) |
| F(C_Verify) |
| F(C_VerifyFinal) |
| F(C_VerifyInit) |
| F(C_VerifyRecover) |
| F(C_VerifyRecoverInit) |
| F(C_VerifyUpdate) |
| F(C_WaitForSlotEvent) |
| F(C_WrapKey) |
| |
| static CK_FUNCTION_LIST module_functions = { |
| .version = { |
| .major = LIBRARY_VERSION_MAJOR, |
| .minor = LIBRARY_VERSION_MINOR, |
| }, |
| .C_GetFunctionList = C_GetFunctionList, |
| .C_Initialize = C_Initialize, |
| .C_Finalize = C_Finalize, |
| .C_GetInfo = C_GetInfo, |
| .C_GetSlotList = C_GetSlotList, |
| .C_GetTokenInfo = C_GetTokenInfo, |
| .C_GetSlotInfo = C_GetSlotInfo, |
| .C_OpenSession = C_OpenSession, |
| .C_CloseSession = C_CloseSession, |
| .C_CloseAllSessions = C_CloseAllSessions, |
| .C_FindObjectsInit = C_FindObjectsInit, |
| .C_FindObjects = C_FindObjects, |
| .C_FindObjectsFinal = C_FindObjectsFinal, |
| .C_GetAttributeValue = C_GetAttributeValue, |
| .C_GetSessionInfo = C_GetSessionInfo, |
| .C_Login = C_Login, |
| .C_Logout = C_Logout, |
| .C_GetMechanismList = C_GetMechanismList, |
| .C_GetMechanismInfo = C_GetMechanismInfo, |
| .C_SignInit = C_SignInit, |
| .C_Sign = C_Sign, |
| .C_DecryptInit = C_DecryptInit, |
| .C_Decrypt = C_Decrypt, |
| U(C_CancelFunction), |
| U(C_CopyObject), |
| U(C_CreateObject), |
| U(C_DecryptDigestUpdate), |
| U(C_DecryptFinal), |
| U(C_DecryptUpdate), |
| U(C_DecryptVerifyUpdate), |
| U(C_DeriveKey), |
| U(C_DestroyObject), |
| U(C_Digest), |
| U(C_DigestEncryptUpdate), |
| U(C_DigestFinal), |
| U(C_DigestInit), |
| U(C_DigestKey), |
| U(C_DigestUpdate), |
| U(C_Encrypt), |
| U(C_EncryptFinal), |
| U(C_EncryptInit), |
| U(C_EncryptUpdate), |
| U(C_GenerateKey), |
| U(C_GenerateKeyPair), |
| U(C_GenerateRandom), |
| U(C_GetFunctionStatus), |
| U(C_GetObjectSize), |
| U(C_GetOperationState), |
| U(C_InitPIN), |
| U(C_InitToken), |
| U(C_SeedRandom), |
| U(C_SetAttributeValue), |
| U(C_SetOperationState), |
| U(C_SetPIN), |
| U(C_SignEncryptUpdate), |
| U(C_SignFinal), |
| U(C_SignRecover), |
| U(C_SignRecoverInit), |
| U(C_SignUpdate), |
| U(C_UnwrapKey), |
| U(C_Verify), |
| U(C_VerifyFinal), |
| U(C_VerifyInit), |
| U(C_VerifyRecover), |
| U(C_VerifyRecoverInit), |
| U(C_VerifyUpdate), |
| U(C_WaitForSlotEvent), |
| U(C_WrapKey), |
| }; |