/* * pkcs11-tool.c: Tool for poking around pkcs11 modules/tokens * * Copyright (C) 2002 Olaf Kirch * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "util.h" #ifdef HAVE_OPENSSL #include "openssl/evp.h" #include "openssl/x509.h" #include "openssl/err.h" #endif #define NEED_SESSION_RO 0x01 #define NEED_SESSION_RW 0x02 #define NO_SLOT ((CK_SLOT_ID) -1) #define NO_MECHANISM ((CK_MECHANISM_TYPE) -1) enum { OPT_MODULE = 0x100, OPT_SLOT, }; const struct option options[] = { { "show-info", 0, 0, 'I' }, { "list-slots", 0, 0, 'L' }, { "list-mechanisms", 0, 0, 'M' }, { "list-objects", 0, 0, 'O' }, { "sign", 0, 0, 's' }, { "hash", 0, 0, 'h' }, { "mechanism", 1, 0, 'm' }, { "login", 0, 0, 'l' }, { "pin", 1, 0, 'p' }, { "change-pin", 0, 0, 'c' }, { "slot", 1, 0, OPT_SLOT }, { "input-file", 1, 0, 'i' }, { "output-file", 1, 0, 'o' }, { "module", 1, 0, OPT_MODULE }, { "quiet", 0, 0, 'q' }, { "test", 0, 0, 't' }, { 0, 0, 0, 0 } }; const char *option_help[] = { "Show global token information", "List slots available on the token", "Show slot information", "List mechanisms supported by the token", "Sign some data", "Hash some data", "Specify mechanism (use -M for a list of supported mechanisms)", "Log into the token first (not needed when using --pin)", "Supply PIN on the command line (if used in scripts: careful!)", "Change your (user) PIN", "Specify the slot to use", "Specify the input file", "Specify the output file", "Specify the module to load", "Quiet operation", "Test (best used with the --login or --pin option)", }; const char * app_name = "pkcs11-tool"; /* for utils.c */ static int opt_quiet = 0; static const char * opt_input = NULL; static const char * opt_output = NULL; static const char * opt_module = NULL; static CK_SLOT_ID opt_slot = NO_SLOT; static CK_MECHANISM_TYPE opt_mechanism = NO_MECHANISM; static sc_pkcs11_module_t *module = NULL; static CK_FUNCTION_LIST_PTR p11 = NULL; static CK_SLOT_ID_PTR p11_slots = NULL; static CK_ULONG p11_num_slots = 0; struct flag_info { CK_FLAGS value; const char * name; }; struct mech_info { CK_MECHANISM_TYPE mech; const char * name; const char * short_name; }; static void show_cryptoki_info(void); static void list_slots(void); static void show_token(CK_SLOT_ID); static void list_mechs(CK_SLOT_ID); static void list_objects(CK_SESSION_HANDLE); static int change_pin(CK_SLOT_ID, CK_SESSION_HANDLE); static void show_object(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void show_key(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, int); static void show_cert(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void sign_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void hash_data(CK_SLOT_ID, CK_SESSION_HANDLE); static int find_object(CK_SESSION_HANDLE, CK_OBJECT_CLASS, CK_OBJECT_HANDLE_PTR, const unsigned char *, size_t id_len, int obj_index); static CK_MECHANISM_TYPE find_mechanism(CK_SLOT_ID, CK_FLAGS, int stop_if_not_found); static void get_token_info(CK_SLOT_ID, CK_TOKEN_INFO_PTR); static void get_mechanisms(CK_SLOT_ID, CK_MECHANISM_TYPE_PTR *, CK_ULONG_PTR); static void p11_fatal(const char *, CK_RV); static const char * p11_slot_info_flags(CK_FLAGS); static const char * p11_token_info_flags(CK_FLAGS); static const char * p11_utf8_to_local(CK_UTF8CHAR *, size_t); static const char * p11_flag_names(struct flag_info *, CK_FLAGS); static const char * p11_mechanism_to_name(CK_MECHANISM_TYPE); static CK_MECHANISM_TYPE p11_name_to_mechanism(const char *); static void p11_perror(const char *, CK_RV); static const char * CKR2Str(CK_ULONG res); static int p11_test(CK_SLOT_ID slot, CK_SESSION_HANDLE session); /* win32 needs this in open(2) */ #ifndef O_BINARY # define O_BINARY 0 #endif int main(int argc, char * const argv[]) { CK_SESSION_HANDLE session = CK_INVALID_HANDLE; CK_OBJECT_HANDLE object = CK_INVALID_HANDLE; char *opt_pin = NULL; int err = 0, c, long_optind = 0; int do_show_info = 0; int do_list_slots = 0; int do_list_mechs = 0; int do_list_objects = 0; int do_sign = 0; int do_hash = 0; int do_test = 0; int need_session = 0; int opt_login = 0; int do_change_pin = 0; int action_count = 0; CK_RV rv; while (1) { c = getopt_long(argc, argv, "ILMOhi:lm:o:p:scqt", options, &long_optind); if (c == -1) break; switch (c) { case 'I': do_show_info = 1; action_count++; break; case 'L': do_list_slots = 1; action_count++; break; case 'M': do_list_mechs = 1; action_count++; break; case 'O': need_session |= NEED_SESSION_RO; do_list_objects = 1; action_count++; break; case 'h': need_session |= NEED_SESSION_RO; do_hash = 1; action_count++; break; case 'i': opt_input = optarg; break; case 'l': need_session |= NEED_SESSION_RW; opt_login = 1; break; case 'm': opt_mechanism = p11_name_to_mechanism(optarg); break; case 'o': opt_output = optarg; break; case 'p': need_session |= NEED_SESSION_RW; opt_login = 1; opt_pin = optarg; break; case 'c': do_change_pin = 1; need_session |= CKF_SERIAL_SESSION; /* no need for a R/W session */ action_count++; break; case 's': need_session |= NEED_SESSION_RW; do_sign = 1; action_count++; break; case 't': do_test = 1; action_count++; break; case 'q': opt_quiet++; break; case OPT_SLOT: opt_slot = (CK_SLOT_ID) atoi(optarg); break; case OPT_MODULE: opt_module = optarg; break; default: print_usage_and_die(); } } if (action_count == 0) print_usage_and_die(); module = C_LoadModule(opt_module, &p11); if (module == NULL) fatal("Failed to load pkcs11 module"); rv = p11->C_Initialize(NULL); if (rv != CKR_OK) p11_fatal("C_Initialize", rv); if (do_show_info) show_cryptoki_info(); /* Get the list of slots */ rv = p11->C_GetSlotList(FALSE, p11_slots, &p11_num_slots); if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL) p11_fatal("C_GetSlotList", rv); p11_slots = (CK_SLOT_ID *) calloc(p11_num_slots, sizeof(CK_SLOT_ID)); if (p11_slots == NULL) { perror("calloc failed"); err = 1; goto end; } rv = p11->C_GetSlotList(FALSE, p11_slots, &p11_num_slots); if (rv != CKR_OK) p11_fatal("C_GetSlotList", rv); if (do_list_slots) list_slots(); if (p11_num_slots == 0) { fprintf(stderr, "No slots...\n"); err = 1; goto end; } if (opt_slot == NO_SLOT) opt_slot = p11_slots[0]; /* XXX: add wait for slot event */ if (do_list_mechs) list_mechs(opt_slot); if (do_sign) { CK_TOKEN_INFO info; get_token_info(opt_slot, &info); if (!(info.flags & CKF_TOKEN_INITIALIZED)) fatal("Token not initialized\n"); if (info.flags & CKF_LOGIN_REQUIRED) opt_login++; } if (need_session) { int flags = CKF_SERIAL_SESSION; if (need_session & NEED_SESSION_RW) flags |= CKF_RW_SESSION; rv = p11->C_OpenSession(opt_slot, flags, NULL, NULL, &session); if (rv != CKR_OK) p11_fatal("C_OpenSession", rv); } if (do_change_pin) /* To be sure we won't mix things up with the -l or -p options, * we safely stop here. */ return change_pin(opt_slot, session); if (opt_login) { char *pin; CK_TOKEN_INFO info; get_token_info(opt_slot, &info); /* Identify which pin to enter */ if (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) pin = NULL; else { if (opt_pin == NULL) pin = getpass("Please enter PIN: "); else pin = opt_pin; if (!pin || !*pin) return 1; } rv = p11->C_Login(session, CKU_USER, (CK_UTF8CHAR *) pin, pin == NULL ? 0 : strlen(pin)); if (rv != CKR_OK) p11_fatal("C_Login", rv); } if (do_sign) { if (!find_object(session, CKO_PRIVATE_KEY, &object, NULL, 0, 0)) fatal("Private key not found"); } if (do_list_objects) list_objects(session); if (do_sign) sign_data(opt_slot, session, object); if (do_hash) hash_data(opt_slot, session); if (do_test) p11_test(opt_slot, session); end: if (session) p11->C_CloseSession(session); if (p11) p11->C_Finalize(NULL_PTR); if (module) C_UnloadModule(module); return err; } void show_cryptoki_info(void) { CK_INFO info; CK_RV rv; rv = p11->C_GetInfo(&info); if (rv != CKR_OK) p11_fatal("C_GetInfo", rv); printf("Cryptoki version %u.%u\n", info.cryptokiVersion.major, info.cryptokiVersion.minor); printf("Manufacturer %s\n", p11_utf8_to_local(info.manufacturerID, sizeof(info.manufacturerID))); printf("Library %s (ver %u.%u)\n", p11_utf8_to_local(info.libraryDescription, sizeof(info.libraryDescription)), info.libraryVersion.major, info.libraryVersion.minor); } void list_slots(void) { CK_SLOT_INFO info; CK_ULONG n; CK_RV rv; if (!p11_num_slots) { printf("No slots found\n"); return; } printf("Available slots:\n"); for (n = 0; n < p11_num_slots; n++) { printf("Slot %-2u ", (unsigned int) p11_slots[n]); rv = p11->C_GetSlotInfo(p11_slots[n], &info); if (rv != CKR_OK) { printf("(GetSlotInfo failed, error %u)\n", (unsigned int) rv); continue; } if (opt_quiet && !(info.flags & CKF_TOKEN_PRESENT)) { printf("(empty)\n"); continue; } printf("%s\n", p11_utf8_to_local(info.slotDescription, sizeof(info.slotDescription))); if (!opt_quiet) { printf(" manufacturer: %s\n", p11_utf8_to_local(info.manufacturerID, sizeof(info.manufacturerID))); printf(" hardware ver: %u.%u\n", info.hardwareVersion.major, info.hardwareVersion.minor); printf(" firmware ver: %u.%u\n", info.firmwareVersion.major, info.firmwareVersion.minor); printf(" flags: %s\n", p11_slot_info_flags(info.flags)); } if (info.flags & CKF_TOKEN_PRESENT) show_token(p11_slots[n]); } } void show_token(CK_SLOT_ID slot) { CK_TOKEN_INFO info; get_token_info(slot, &info); if (!(info.flags & CKF_TOKEN_INITIALIZED) && opt_quiet) { printf(" token state: uninitialized\n"); return; } printf(" token label: %s\n", p11_utf8_to_local(info.label, sizeof(info.label))); printf(" token manuf: %s\n", p11_utf8_to_local(info.manufacturerID, sizeof(info.manufacturerID))); printf(" token model: %s\n", p11_utf8_to_local(info.model, sizeof(info.model))); printf(" token flags: %s\n", p11_token_info_flags(info.flags)); } void list_mechs(CK_SLOT_ID slot) { CK_MECHANISM_TYPE *mechs = NULL; CK_ULONG n, num_mechs = 0; CK_RV rv; get_mechanisms(slot, &mechs, &num_mechs); printf("Supported mechanisms:\n"); for (n = 0; n < num_mechs; n++) { CK_MECHANISM_INFO info; printf(" %s", p11_mechanism_to_name(mechs[n])); rv = p11->C_GetMechanismInfo(slot, mechs[n], &info); if (rv == CKR_OK) { if (info.flags & CKF_DIGEST) printf(", digest"); if (info.flags & CKF_SIGN) printf(", sign"); if (info.flags & CKF_VERIFY) printf(", verify"); if (info.flags & CKF_UNWRAP) printf(", unwrap"); if (info.flags & CKF_HW) printf(", hw"); info.flags &= ~(CKF_DIGEST|CKF_SIGN|CKF_VERIFY|CKF_HW|CKF_UNWRAP); if (info.flags) printf(", other flags=0x%x", (unsigned int) info.flags); } printf("\n"); } } void list_objects(CK_SESSION_HANDLE sess) { CK_OBJECT_HANDLE object; CK_ULONG count; CK_RV rv; rv = p11->C_FindObjectsInit(sess, NULL, 0); if (rv != CKR_OK) p11_fatal("C_FindObjectsInit", rv); while (1) { rv = p11->C_FindObjects(sess, &object, 1, &count); if (rv != CKR_OK) p11_fatal("C_FindObjects", rv); if (count == 0) break; show_object(sess, object); } p11->C_FindObjectsFinal(sess); } int change_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess) { char old_buf[21], *old_pin = NULL; char new_buf[21], *new_pin = NULL; CK_TOKEN_INFO info; CK_RV rv; get_token_info(slot, &info); if (!(info.flags & CKF_PROTECTED_AUTHENTICATION_PATH)) { old_pin = getpass("Please enter the current PIN: "); if (!old_pin || !*old_pin || strlen(old_pin) > 20) return 1; strcpy(old_buf, old_pin); old_pin = old_buf; new_pin = getpass("Please enter the new PIN: "); if (!new_pin || !*new_pin || strlen(new_pin) > 20) return 1; strcpy(new_buf, new_pin); new_pin = getpass("Please enter the new PIN again: "); if (!new_pin || !*new_pin || strcmp(new_buf, new_pin) != 0) { printf(" different new PINs, exiting\n"); return -1; } } rv = p11->C_SetPIN(sess, old_pin, old_pin == NULL ? 0 : strlen(old_pin), new_pin, new_pin == NULL ? 0 : strlen(new_pin)); if (rv != CKR_OK) p11_fatal("C_SetPIN", rv); printf("PIN successfully changed\n"); return 0; } void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) { unsigned char buffer[512]; CK_MECHANISM mech; CK_RV rv; CK_ULONG sig_len; int fd, r; if (opt_mechanism == NO_MECHANISM) { opt_mechanism = find_mechanism(slot, CKF_SIGN|CKF_HW, 1); printf("Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); } memset(&mech, 0, sizeof(mech)); mech.mechanism = opt_mechanism; rv = p11->C_SignInit(session, &mech, key); if (rv != CKR_OK) p11_fatal("C_SignInit", rv); if (opt_input == NULL) fd = 0; else if ((fd = open(opt_input, O_RDONLY|O_BINARY)) < 0) fatal("Cannot open %s: %m", opt_input); while ((r = read(fd, buffer, sizeof(buffer))) > 0) { rv = p11->C_SignUpdate(session, buffer, r); if (rv != CKR_OK) p11_fatal("C_SignUpdate", rv); } if (rv < 0) fatal("failed to read from %s: %m", opt_input? opt_input : ""); if (fd != 0) close(fd); sig_len = sizeof(buffer); rv = p11->C_SignFinal(session, buffer, &sig_len); if (rv != CKR_OK) p11_fatal("C_SignFinal", rv); if (opt_output == NULL) fd = 1; else if ((fd = open(opt_output, O_CREAT|O_TRUNC|O_WRONLY, 0666)) < 0) fatal("failed to open %s: %m", opt_output); r = write(fd, buffer, sig_len); if (r < 0) fatal("Failed to write to %s: %m", opt_output); if (fd != 1) close(fd); } void hash_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { unsigned char buffer[64]; CK_MECHANISM mech; CK_RV rv; CK_ULONG hash_len; int fd, r; if (opt_mechanism == NO_MECHANISM) { opt_mechanism = find_mechanism(slot, CKF_DIGEST, 1); printf("Using digest algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); } memset(&mech, 0, sizeof(mech)); mech.mechanism = opt_mechanism; rv = p11->C_DigestInit(session, &mech); if (rv != CKR_OK) p11_fatal("C_DigestInit", rv); if (opt_input == NULL) fd = 0; else if ((fd = open(opt_input, O_RDONLY)) < 0) fatal("Cannot open %s: %m", opt_input); while ((r = read(fd, buffer, sizeof(buffer))) > 0) { rv = p11->C_DigestUpdate(session, buffer, r); if (rv != CKR_OK) p11_fatal("C_DigestUpdate", rv); } if (rv < 0) fatal("failed to read from %s: %m", opt_input? opt_input : ""); if (fd != 0) close(fd); hash_len = sizeof(buffer); rv = p11->C_DigestFinal(session, buffer, &hash_len); if (rv != CKR_OK) p11_fatal("C_DigestFinal", rv); if (opt_output == NULL) fd = 1; else if ((fd = open(opt_output, O_CREAT|O_TRUNC|O_WRONLY, 0666)) < 0) fatal("failed to open %s: %m", opt_output); r = write(fd, buffer, hash_len); if (r < 0) fatal("Failed to write to %s: %m", opt_output); if (fd != 1) close(fd); } int find_object(CK_SESSION_HANDLE sess, CK_OBJECT_CLASS cls, CK_OBJECT_HANDLE_PTR ret, const unsigned char *id, size_t id_len, int obj_index) { CK_ATTRIBUTE attrs[2]; unsigned int nattrs = 0; CK_ULONG count; CK_RV rv; int i; attrs[0].type = CKA_CLASS; attrs[0].pValue = &cls; attrs[0].ulValueLen = sizeof(cls); nattrs++; if (id) { attrs[nattrs].type = CKA_ID; attrs[nattrs].pValue = (void *) id; attrs[nattrs].ulValueLen = id_len; nattrs++; } rv = p11->C_FindObjectsInit(sess, attrs, nattrs); if (rv != CKR_OK) p11_fatal("C_FindObjectsInit", rv); for (i = 0; i < obj_index; i++) { rv = p11->C_FindObjects(sess, ret, 1, &count); if (rv != CKR_OK) p11_fatal("C_FindObjects", rv); if (count == 0) goto done; } rv = p11->C_FindObjects(sess, ret, 1, &count); if (rv != CKR_OK) p11_fatal("C_FindObjects", rv); done: p11->C_FindObjectsFinal(sess); return count; } CK_MECHANISM_TYPE find_mechanism(CK_SLOT_ID slot, CK_FLAGS flags, int stop_if_not_found) { CK_MECHANISM_TYPE *mechs = NULL, result; CK_MECHANISM_INFO info; CK_ULONG n, count = 0; CK_RV rv; get_mechanisms(slot, &mechs, &count); result = NO_MECHANISM; for (n = 0; n < count; n++) { rv = p11->C_GetMechanismInfo(slot, mechs[n], &info); if (rv != CKR_OK) continue; if ((info.flags & flags) == flags) { result = mechs[n]; break; } } if (stop_if_not_found && result == NO_MECHANISM) fatal("No appropriate mechanism found"); free(mechs); return result; } #define ATTR_METHOD(ATTR, TYPE) \ TYPE \ get##ATTR(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) \ { \ TYPE type; \ CK_ATTRIBUTE attr = { CKA_##ATTR, &type, sizeof(type) }; \ CK_RV rv; \ \ rv = p11->C_GetAttributeValue(sess, obj, &attr, 1); \ if (rv != CKR_OK) \ p11_fatal("C_GetAttributeValue(" #ATTR ")", rv); \ return type; \ } #define VARATTR_METHOD(ATTR, TYPE) \ TYPE * \ get##ATTR(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, CK_ULONG_PTR pulCount) \ { \ CK_ATTRIBUTE attr = { CKA_##ATTR, NULL, 0 }; \ CK_RV rv; \ \ rv = p11->C_GetAttributeValue(sess, obj, &attr, 1); \ if (rv == CKR_OK) { \ if (!(attr.pValue = calloc(1, attr.ulValueLen + 1))) \ fatal("out of memory in get" #ATTR ": %m"); \ rv = p11->C_GetAttributeValue(sess, obj, &attr, 1); \ } \ if (rv != CKR_OK) \ p11_fatal("C_GetAttributeValue(" #ATTR ")", rv); \ if (pulCount) \ *pulCount = attr.ulValueLen / sizeof(TYPE); \ return (TYPE *) attr.pValue; \ } /* * Define attribute accessors */ ATTR_METHOD(CLASS, CK_OBJECT_CLASS); ATTR_METHOD(TOKEN, CK_BBOOL); ATTR_METHOD(LOCAL, CK_BBOOL); ATTR_METHOD(SENSITIVE, CK_BBOOL); ATTR_METHOD(ALWAYS_SENSITIVE, CK_BBOOL); ATTR_METHOD(NEVER_EXTRACTABLE, CK_BBOOL); ATTR_METHOD(PRIVATE, CK_BBOOL); ATTR_METHOD(MODIFIABLE, CK_BBOOL); ATTR_METHOD(ENCRYPT, CK_BBOOL); ATTR_METHOD(DECRYPT, CK_BBOOL); ATTR_METHOD(SIGN, CK_BBOOL); ATTR_METHOD(SIGN_RECOVER, CK_BBOOL); ATTR_METHOD(VERIFY, CK_BBOOL); ATTR_METHOD(VERIFY_RECOVER, CK_BBOOL); ATTR_METHOD(WRAP, CK_BBOOL); ATTR_METHOD(UNWRAP, CK_BBOOL); ATTR_METHOD(DERIVE, CK_BBOOL); ATTR_METHOD(EXTRACTABLE, CK_BBOOL); ATTR_METHOD(KEY_TYPE, CK_KEY_TYPE); ATTR_METHOD(CERTIFICATE_TYPE, CK_CERTIFICATE_TYPE); ATTR_METHOD(MODULUS_BITS, CK_ULONG); VARATTR_METHOD(LABEL, char); VARATTR_METHOD(ID, unsigned char); VARATTR_METHOD(VALUE, unsigned char); void show_object(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) { CK_OBJECT_CLASS cls = getCLASS(sess, obj); switch (cls) { case CKO_PUBLIC_KEY: show_key(sess, obj, 1); break; case CKO_PRIVATE_KEY: show_key(sess, obj, 0); break; case CKO_CERTIFICATE: show_cert(sess, obj); break; default: printf("Object %u, type %u\n", (unsigned int) obj, (unsigned int) cls); } } void show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int pub) { CK_KEY_TYPE key_type = getKEY_TYPE(sess, obj); CK_ULONG size; unsigned char *id; char *label, *sepa; printf("%s Key Object", pub? "Public" : "Private"); switch (key_type) { case CKK_RSA: printf("; RSA %lu bits\n", getMODULUS_BITS(sess, obj)); break; default: printf("; unknown key algorithm %lu\n", key_type); break; } if ((label = getLABEL(sess, obj, NULL)) != NULL) { printf(" label: %s\n", label); free(label); } if ((id = getID(sess, obj, &size)) != NULL && size) { unsigned int n; printf(" ID: "); for (n = 0; n < size; n++) printf("%02x", id[n]); printf("\n"); free(id); } printf(" Usage: "); sepa = ""; if (getENCRYPT(sess, obj)) { printf("%sencrypt", sepa); sepa = ", "; } if (getDECRYPT(sess, obj)) { printf("%sdecrypt", sepa); sepa = ", "; } if (getSIGN(sess, obj)) { printf("%ssign", sepa); sepa = ", "; } if (getVERIFY(sess, obj)) { printf("%sverify", sepa); sepa = ", "; } if (getWRAP(sess, obj)) { printf("%swrap", sepa); sepa = ", "; } if (getUNWRAP(sess, obj)) { printf("%sunwrap", sepa); sepa = ", "; } if (!*sepa) printf("none"); printf("\n"); } void show_cert(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) { CK_CERTIFICATE_TYPE cert_type = getCERTIFICATE_TYPE(sess, obj); CK_ULONG size; unsigned char *id; char *label; printf("Certificate Object, type = "); switch (cert_type) { case CKC_X_509: printf("X.509 cert\n"); break; case CKC_X_509_ATTR_CERT: printf("X.509 attribute cert\n"); break; case CKC_VENDOR_DEFINED: printf("vendor defined"); break; default: printf("; unknown cert type\n"); break; } if ((label = getLABEL(sess, obj, NULL)) != NULL) { printf(" label: %s\n", label); free(label); } if ((id = getID(sess, obj, &size)) != NULL && size) { unsigned int n; printf(" ID: "); for (n = 0; n < size; n++) printf("%02x", id[n]); printf("\n"); free(id); } } void get_token_info(CK_SLOT_ID slot, CK_TOKEN_INFO_PTR info) { CK_RV rv; rv = p11->C_GetTokenInfo(slot, info); if (rv != CKR_OK) p11_fatal("C_GetTokenInfo", rv); } void get_mechanisms(CK_SLOT_ID slot, CK_MECHANISM_TYPE_PTR *pList, CK_ULONG_PTR pulCount) { CK_RV rv; rv = p11->C_GetMechanismList(slot, *pList, pulCount); *pList = (CK_MECHANISM_TYPE *) calloc(*pulCount, sizeof(*pList)); if (*pList == NULL) fatal("calloc failed: %m"); rv = p11->C_GetMechanismList(slot, *pList, pulCount); if (rv != CKR_OK) p11_fatal("C_GetMechanismList", rv); } static int test_digest(CK_SLOT_ID slot) { int errors = 0; CK_RV rv; CK_SESSION_HANDLE session; CK_MECHANISM ck_mech = { CKM_MD5, NULL, 0 }; CK_ULONG i, j; unsigned char data[100]; unsigned char hash1[64], hash2[64]; CK_ULONG hashLen1, hashLen2; CK_MECHANISM_TYPE firstMechType; CK_MECHANISM_TYPE mechTypes[] = { CKM_MD5, CKM_SHA_1, CKM_RIPEMD160, 0xffffff }; unsigned char *digests[] = { (unsigned char *) "\x7a\x08\xb0\x7e\x84\x64\x17\x03\xe5\xf2\xc8\x36\xaa\x59\xa1\x70", (unsigned char *) "\x29\xb0\xe7\x87\x82\x71\x64\x5f\xff\xb7\xee\xc7\xdb\x4a\x74\x73\xa1\xc0\x0b\xc1", (unsigned char *) "\xda\x79\xa5\x8f\xb8\x83\x3d\x61\xf6\x32\x16\x17\xe3\xfd\xf0\x56\x26\x5f\xb7\xcd" }; CK_ULONG digestLens[] = { 16, 20, 20 }; firstMechType = find_mechanism(slot, CKF_DIGEST, 0); if (firstMechType == NO_MECHANISM) { printf("Digests: not implemented\n"); return errors; } else printf("Digests:\n"); rv = p11->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &session); if (rv != CKR_OK) p11_fatal("C_OpenSession", rv); /* 1st test */ ck_mech.mechanism = firstMechType; rv = p11->C_DigestInit(session, &ck_mech); if (rv != CKR_OK) p11_fatal("C_DigestInit", rv); rv = p11->C_DigestUpdate(session, data, 5); if (rv == CKR_FUNCTION_NOT_SUPPORTED) { printf(" Note: C_DigestUpdate(), DigestFinal() not supported\n"); /* finish the digest operation */ hashLen2 = sizeof(hash2); rv = p11->C_Digest(session, data, sizeof(data), hash2, &hashLen2); if (rv != CKR_OK) p11_fatal("C_Digest", rv); } else { if (rv != CKR_OK) p11_fatal("C_DigestUpdate", rv); rv = p11->C_DigestUpdate(session, data + 5, 50); if (rv != CKR_OK) p11_fatal("C_DigestUpdate", rv); rv = p11->C_DigestUpdate(session, data + 55, sizeof(data) - 55); if (rv != CKR_OK) p11_fatal("C_DigestUpdate", rv); hashLen1 = sizeof(hash1); rv = p11->C_DigestFinal(session, hash1, &hashLen1); if (rv != CKR_OK) p11_fatal("C_DigestFinal", rv); rv = p11->C_DigestInit(session, &ck_mech); if (rv != CKR_OK) p11_fatal("C_DigestInit", rv); hashLen2 = sizeof(hash2); rv = p11->C_Digest(session, data, sizeof(data), hash2, &hashLen2); if (rv != CKR_OK) p11_fatal("C_Digest", rv); if (hashLen1 != hashLen2) { errors++; printf(" ERR: digest lengths returned by C_DigestFinal() different from C_Digest()\n"); } else if (memcmp(hash1, hash2, hashLen1) != 0) { errors++; printf(" ERR: digests returned by C_DigestFinal() different from C_Digest()\n"); } else printf(" all 4 digest functions seem to work\n"); } /* 2nd test */ /* input = "01234567890123456...456789" */ for (i = 0; i < 10; i++) for (j = 0; j < 10; j++) data[10 * i + j] = (unsigned char) (0x30 + j); for (i = 0; mechTypes[i] != 0xffffff; i++) { ck_mech.mechanism = mechTypes[i]; rv = p11->C_DigestInit(session, &ck_mech); if (rv == CKR_MECHANISM_INVALID) continue; /* mechanism not implemented, don't test */ if (rv != CKR_OK) p11_fatal("C_DigestInit", rv); printf(" %s: ", p11_mechanism_to_name(mechTypes[i])); hashLen1 = sizeof(hash1); rv = p11->C_Digest(session, data, sizeof(data), hash1, &hashLen1); if (rv != CKR_OK) p11_fatal("C_Digest", rv); if (hashLen1 != digestLens[i]) { errors++; printf("ERR: wrong digest length: %ld instead of %ld\n", hashLen1, digestLens[i]); } else if (memcmp(hash1, digests[i], hashLen1) != 0) { errors++; printf("ERR: wrong digest value\n"); } else printf("OK\n"); } /* 3rd test */ ck_mech.mechanism = firstMechType; rv = p11->C_DigestInit(session, &ck_mech); if (rv != CKR_OK) p11_fatal("C_DigestInit", rv); hashLen2 = 1; /* too short */ rv = p11->C_Digest(session, data, sizeof(data), hash2, &hashLen2); if (rv != CKR_BUFFER_TOO_SMALL) { errors++; printf(" ERR: C_Digest() didn't return CKR_BUFFER_TOO_SMALL but %s (0x%0x)\n", CKR2Str(rv), (int) rv); } /* output buffer = NULL */ rv = p11->C_Digest(session, data, sizeof(data), NULL, &hashLen2); if (rv != CKR_OK) { errors++; printf(" ERR: C_Digest() didn't return CKR_OK for a NULL output buffer, but %s (0x%0x)\n", CKR2Str(rv), (int) rv); } rv = p11->C_Digest(session, data, sizeof(data), hash2, &hashLen2); if (rv == CKR_OPERATION_NOT_INITIALIZED) { printf(" ERR: digest operation ended prematurely\n"); errors++; } else if (rv != CKR_OK) p11_fatal("C_Sign", rv); rv = p11->C_CloseSession(session); if (rv != CKR_OK) p11_fatal("C_CloseSession", rv); return errors; } #ifdef HAVE_OPENSSL EVP_PKEY *get_public_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE privKeyObject) { unsigned char *id; CK_ULONG idLen; CK_OBJECT_HANDLE pubkeyObject; unsigned char *pubkey, *pubkey_sav; CK_ULONG pubkeyLen; EVP_PKEY *pkey; id = NULL; id = getID(session, privKeyObject, &idLen); if (id == NULL) { printf("private key has no ID, can't lookup the corresponding pubkey for verification\n"); return NULL; } if (!find_object(session, CKO_PUBLIC_KEY, &pubkeyObject, id, idLen, 0)) { free(id); printf("coudn't find the corresponding pubkey for validation\n"); return NULL; } free(id); pubkey = getVALUE(session, pubkeyObject, &pubkeyLen); if (pubkey == NULL) { printf("couldn't get the pubkey VALUE attribute, no validation done\n"); return NULL; } pubkey_sav = pubkey; /* The function below may change pubkey */ pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &pubkey, pubkeyLen); free(pubkey_sav); if (pkey == NULL) { printf(" couldn't parse pubkey, no verification done\n"); /* ERR_print_errors_fp(stderr); */ return NULL; } return pkey; } #endif int sign_verify(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_MECHANISM *ck_mech, CK_OBJECT_HANDLE privKeyObject, unsigned char *data, CK_ULONG dataLen, unsigned char *verifyData, CK_ULONG verifyDataLen, int modLenBytes, int evp_md_index) { int errors = 0; CK_RV rv; unsigned char sig1[1024]; CK_ULONG sigLen1; #ifdef HAVE_OPENSSL int err; EVP_PKEY *pkey; EVP_MD_CTX md_ctx; const EVP_MD *evp_mds[] = { EVP_sha1(), EVP_sha1(), EVP_sha1(), EVP_md5(), EVP_ripemd160(), }; #endif rv = p11->C_SignInit(session, ck_mech, privKeyObject); /* mechanism not implemented, don't test */ if (rv == CKR_MECHANISM_INVALID) return errors; if (rv != CKR_OK) p11_fatal("C_SignInit", rv); printf(" %s: ", p11_mechanism_to_name(ck_mech->mechanism)); sigLen1 = sizeof(sig1); rv = p11->C_Sign(session, data, dataLen, sig1, &sigLen1); if (rv != CKR_OK) p11_fatal("C_Sign", rv); if (sigLen1 != modLenBytes) { errors++; printf(" ERR: wrong signature length: %u instead of %u\n", (unsigned int) sigLen1, (unsigned int) modLenBytes); } #ifndef HAVE_OPENSSL printf("unable to verify signature (compile with HAVE_OPENSSL)\n"); #else if (!(pkey = get_public_key(session, privKeyObject))) return errors; EVP_VerifyInit(&md_ctx, evp_mds[evp_md_index]); EVP_VerifyUpdate(&md_ctx, verifyData, verifyDataLen); err = EVP_VerifyFinal(&md_ctx, sig1, sigLen1, pkey); if (err == 0) { printf("ERR: verification failed\n"); errors++; } else if (err != 1) { printf("openssl error during verification: 0x%0x (%d)\n", err, err); /* ERR_print_errors_fp(stderr); */ } else printf("OK\n"); /* free(cert); */ #endif return errors; } /* * Test signature functions */ static int test_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { int errors = 0; CK_RV rv; CK_OBJECT_HANDLE privKeyObject; CK_SESSION_HANDLE sess; CK_MECHANISM ck_mech = { CKM_MD5, NULL, 0 }; CK_MECHANISM_TYPE firstMechType; CK_SESSION_INFO sessionInfo; CK_ULONG i, j; unsigned char data[200]; CK_ULONG modLenBytes; CK_ULONG dataLen; unsigned char sig1[1024], sig2[1024]; CK_ULONG sigLen1, sigLen2; unsigned char verifyData[100]; char *label; CK_MECHANISM_TYPE mechTypes[] = { CKM_RSA_X_509, CKM_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_MD5_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, 0xffffff }; unsigned char *datas[] = { /* PCKS1_wrap(SHA1_encode(SHA-1(verifyData))), * is done further on */ NULL, /* SHA1_encode(SHA-1(verifyData)) */ (unsigned char *) "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14\x29\xb0\xe7\x87\x82\x71\x64\x5f\xff\xb7\xee\xc7\xdb\x4a\x74\x73\xa1\xc0\x0b\xc1", verifyData, verifyData, verifyData, }; CK_ULONG dataLens[] = { 0, /* should be modulus length, is done further on */ 35, sizeof(verifyData), sizeof(verifyData), sizeof(verifyData), }; rv = p11->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &sess); if (rv != CKR_OK) p11_fatal("C_OpenSession", rv); rv = p11->C_GetSessionInfo(sess, &sessionInfo); if (rv != CKR_OK) p11_fatal("C_OpenSession", rv); if ((sessionInfo.state & CKS_RO_USER_FUNCTIONS) == 0) { printf("Signatures: not logged in, skipping signature tests\n"); return errors; } firstMechType = find_mechanism(slot, CKF_SIGN | CKF_HW, 0); if (firstMechType == NO_MECHANISM) { printf("Signatures: not implemented\n"); return errors; } else if (!find_object(sess, CKO_PRIVATE_KEY, &privKeyObject, NULL, 0, 0)) { printf("Signatures: no private key found in this slot\n"); return errors; } else { printf("Signatures (currently only RSA signatures)"); if ((label = getLABEL(sess, privKeyObject, NULL)) != NULL) { printf(", key = %s", label); free(label); } printf(" :\n"); } data[0] = 0; modLenBytes = (getMODULUS_BITS(sess, privKeyObject) + 7) / 8; /* 1st test */ switch (firstMechType) { case CKM_RSA_PKCS: dataLen = 35; break; case CKM_RSA_X_509: dataLen = modLenBytes; break; default: dataLen = sizeof(data); /* let's hope it's OK */ break; } ck_mech.mechanism = firstMechType; rv = p11->C_SignInit(sess, &ck_mech, privKeyObject); if (rv != CKR_OK) p11_fatal("C_SignInit", rv); rv = p11->C_SignUpdate(sess, data, 5); if (rv == CKR_FUNCTION_NOT_SUPPORTED) { printf(" Note: C_SignUpdate(), SignFinal() not supported\n"); /* finish the digest operation */ sigLen2 = sizeof(sig2); rv = p11->C_Sign(sess, data, dataLen, sig2, &sigLen2); if (rv != CKR_OK) p11_fatal("C_Sign", rv); } else { if (rv != CKR_OK) p11_fatal("C_SignUpdate", rv); rv = p11->C_SignUpdate(sess, data + 5, 10); if (rv != CKR_OK) p11_fatal("C_SignUpdate", rv); rv = p11->C_SignUpdate(sess, data + 15, dataLen - 15); if (rv != CKR_OK) p11_fatal("C_SignUpdate", rv); sigLen1 = sizeof(sig1); rv = p11->C_SignFinal(sess, sig1, &sigLen1); if (rv != CKR_OK) p11_fatal("C_SignFinal", rv); rv = p11->C_SignInit(sess, &ck_mech, privKeyObject); if (rv != CKR_OK) p11_fatal("C_SignInit", rv); sigLen2 = sizeof(sig2); rv = p11->C_Sign(sess, data, dataLen, sig2, &sigLen2); if (rv != CKR_OK) p11_fatal("C_Sign", rv); if (sigLen1 != sigLen2) { errors++; printf(" ERR: signature lengths returned by C_SignFinal() different from C_Sign()\n"); } else if (memcmp(sig1, sig2, sigLen1) != 0) { errors++; printf(" ERR: signatures returned by C_SignFinal() different from C_Sign()\n"); } else printf(" all 4 signature functions seem to work\n"); } /* 2nd test */ ck_mech.mechanism = firstMechType; rv = p11->C_SignInit(sess, &ck_mech, privKeyObject); if (rv != CKR_OK) p11_fatal("C_SignInit", rv); sigLen2 = 1; /* too short */ rv = p11->C_Sign(sess, data, dataLen, sig2, &sigLen2); if (rv != CKR_BUFFER_TOO_SMALL) { errors++; printf(" ERR: C_Sign() didn't return CKR_BUFFER_TOO_SMALL but %s (0x%0x)\n", CKR2Str(rv), (int) rv); } /* output buf = NULL */ rv = p11->C_Sign(sess, data, dataLen, NULL, &sigLen2); if (rv != CKR_OK) { errors++; printf(" ERR: C_Sign() didn't return CKR_OK for a NULL output buf, but %s (0x%0x)\n", CKR2Str(rv), (int) rv); } rv = p11->C_Sign(sess, data, dataLen, sig2, &sigLen2); if (rv == CKR_OPERATION_NOT_INITIALIZED) { printf(" ERR: signature operation ended prematurely\n"); errors++; } else if (rv != CKR_OK) p11_fatal("C_Sign", rv); /* 3rd test */ /* input = "01234567890123456...456789" */ for (i = 0; i < 10; i++) for (j = 0; j < 10; j++) verifyData[10 * i + j] = (unsigned char) (0x30 + j); /* Fill in data[0] and dataLens[0] */ dataLen = modLenBytes; data[1] = 0x01; memset(data + 2, 0xFF, dataLen - 3 - dataLens[1]); data[dataLen - 36] = 0x00; memcpy(data + (dataLen - dataLens[1]), datas[1], dataLens[1]); datas[0] = data; dataLens[0] = dataLen; printf(" testing signature mechanisms:\n"); for (i = 0; mechTypes[i] != 0xffffff; i++) { ck_mech.mechanism = mechTypes[i]; errors += sign_verify(slot, sess, &ck_mech, privKeyObject, datas[i], dataLens[i], verifyData, sizeof(verifyData), modLenBytes, i); } /* 4rd test: the other signature keys */ for (i = 0; mechTypes[i] != 0xffffff; i++) if (i == firstMechType) break; ck_mech.mechanism = mechTypes[i]; j = 1; /* j-th signature key */ while (find_object(sess, CKO_PRIVATE_KEY, &privKeyObject, NULL, 0, j++) != 0) { printf(" testing key %d ", (int) (j-1)); if ((label = getLABEL(sess, privKeyObject, NULL)) != NULL) { printf("(%s) ", label); free(label); } printf("with 1 signature mechanism\n"); errors += sign_verify(slot, sess, &ck_mech, privKeyObject, datas[i], dataLens[i], verifyData, sizeof(verifyData), modLenBytes, i); } return errors; } #ifdef HAVE_OPENSSL static int wrap_unwrap(CK_SLOT_ID slot, CK_SESSION_HANDLE session, const EVP_CIPHER *algo, CK_OBJECT_HANDLE privKeyObject) { CK_OBJECT_HANDLE cipherKeyObject; CK_RV rv; EVP_PKEY *pkey; EVP_CIPHER_CTX seal_ctx; unsigned char keybuf[512], *key = keybuf; int key_len; unsigned char iv[32], ciphered[1024], cleartext[1024]; int ciphered_len, cleartext_len, len; CK_MECHANISM mech; CK_ULONG key_type = CKM_DES_CBC; CK_ATTRIBUTE key_template = { CKA_KEY_TYPE, &key_type, sizeof(key_type) }; pkey = get_public_key(session, privKeyObject); if (pkey == NULL) return 0; printf(" %s: ", OBJ_nid2sn(EVP_CIPHER_nid(algo))); EVP_SealInit(&seal_ctx, algo, &key, &key_len, iv, &pkey, 1); /* Encrypt something */ len = sizeof(ciphered); EVP_SealUpdate(&seal_ctx, ciphered, &len, "hello world", 11); ciphered_len = len; len = sizeof(ciphered) - ciphered_len; EVP_SealFinal(&seal_ctx, ciphered + ciphered_len, &len); ciphered_len += len; mech.mechanism = CKM_RSA_PKCS; rv = p11->C_UnwrapKey(session, &mech, privKeyObject, key, key_len, &key_template, 1, &cipherKeyObject); /* mechanism not implemented, don't test */ if (rv == CKR_MECHANISM_INVALID) return 0; if (rv != CKR_OK) { p11_perror("C_UnwrapKey failed", rv); return 1; } /* Try to decrypt */ key = getVALUE(session, cipherKeyObject, (unsigned long *) &key_len); if (key == NULL) { printf(" Could not get unwrapped key\n"); return 1; } if (key_len != EVP_CIPHER_key_length(algo)) { printf(" Key length mismatch (%d != %d)\n", key_len, EVP_CIPHER_key_length(algo)); return 1; } EVP_DecryptInit(&seal_ctx, algo, key, iv); len = sizeof(cleartext); EVP_DecryptUpdate(&seal_ctx, cleartext, &len, ciphered, ciphered_len); cleartext_len = len; len = sizeof(cleartext) - len; EVP_DecryptFinal(&seal_ctx, cleartext + cleartext_len, &len); cleartext_len += len; if (cleartext_len != 11 || memcmp(cleartext, "hello world", 11)) { printf(" resulting cleartext doesn't match input\n"); return 1; } printf("OK\n"); return 0; } #endif /* * Test unwrap functions */ static int test_unwrap(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { int errors = 0; CK_RV rv; CK_OBJECT_HANDLE privKeyObject; CK_SESSION_HANDLE sess; CK_MECHANISM_TYPE firstMechType; CK_SESSION_INFO sessionInfo; CK_ULONG j; char *label; rv = p11->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &sess); if (rv != CKR_OK) p11_fatal("C_OpenSession", rv); rv = p11->C_GetSessionInfo(sess, &sessionInfo); if (rv != CKR_OK) p11_fatal("C_OpenSession", rv); if ((sessionInfo.state & CKS_RO_USER_FUNCTIONS) == 0) { printf("Key unwrap: not logged in, skipping key unwrap tests\n"); return errors; } firstMechType = find_mechanism(slot, CKF_UNWRAP | CKF_HW, 0); if (firstMechType == NO_MECHANISM) { printf("Unwrap: not implemented\n"); return errors; } printf("Key unwrap (RSA)\n"); for (j = 0; find_object(sess, CKO_PRIVATE_KEY, &privKeyObject, NULL, 0, j); j++) { printf(" testing key %ld ", j); if ((label = getLABEL(sess, privKeyObject, NULL)) != NULL) { printf("(%s) ", label); free(label); } printf("\n"); #ifndef HAVE_OPENSSL printf("No OpenSSL support, unable to validate C_Unwrap\n"); #else errors += wrap_unwrap(slot, sess, EVP_des_cbc(), privKeyObject); errors += wrap_unwrap(slot, sess, EVP_des_ede3_cbc(), privKeyObject); errors += wrap_unwrap(slot, sess, EVP_bf_cbc(), privKeyObject); errors += wrap_unwrap(slot, sess, EVP_cast5_cfb(), privKeyObject); #endif } return errors; } static int test_random(CK_SLOT_ID slot) { CK_SESSION_HANDLE session; CK_BYTE buf1[100], buf2[100]; CK_BYTE seed1[100]; CK_RV rv; int errors = 0; printf("C_SeedRandom() and C_GenerateRandom():\n"); rv = p11->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &session); if (rv != CKR_OK) p11_fatal("C_OpenSession", rv); rv = p11->C_SeedRandom(session, seed1, 10); if (rv == CKR_RANDOM_NO_RNG || rv == CKR_FUNCTION_NOT_SUPPORTED) { printf(" not implemented\n"); return 0; } if (rv == CKR_RANDOM_SEED_NOT_SUPPORTED) printf(" seeding (C_SeedRandom) not supported\n"); else if (rv != CKR_OK) { p11_perror("C_SeedRandom", rv); return 1; } rv = p11->C_GenerateRandom(session, buf1, 10); if (rv != CKR_OK) { p11_perror("C_GenerateRandom", rv); return 1; } rv = p11->C_GenerateRandom(session, buf1, 100); if (rv != CKR_OK) { p11_perror("C_GenerateRandom", rv); return 1; } rv = p11->C_GenerateRandom(session, buf1, 0); if (rv != CKR_OK) { p11_perror("C_GenerateRandom(,,0)", rv); return 1; } rv = p11->C_GenerateRandom(session, NULL, 100); if (rv != CKR_OK) { p11_perror("C_GenerateRandom(,NULL,)", rv); return 1; } if (memcmp(buf1, buf2, 100) == 0) { printf(" ERR: C_GenerateRandom returned twice the same value!!!\n"); errors++; } printf(" seems to be OK\n"); return 0; } static int test_card_detection(int wait_for_event) { char buffer[256]; CK_SLOT_ID slot_id; CK_RV rv; printf("Testing card detection%s\n", wait_for_event? " using C_WaitForSlotEvent" : ""); while (1) { printf("Please press return to continue, x to exit: "); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL || buffer[0] == 'x') break; if (wait_for_event) { printf("Calling C_WaitForSlotEvent: "); fflush(stdout); rv = p11->C_WaitForSlotEvent(0, &slot_id, NULL); if (rv != CKR_OK) { printf("failed.\n"); p11_perror("C_WaitForSlotEvent", rv); return 1; } printf("event on slot %u\n", (unsigned int) slot_id); } list_slots(); } return 0; } static int p11_test(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { int errors = 0; errors += test_random(slot); errors += test_digest(slot); errors += test_signature(slot, session); errors += test_unwrap(slot, session); errors += test_card_detection(0); errors += test_card_detection(1); if (errors == 0) printf("No errors\n"); else printf("%d errors\n", errors); return errors; } const char * p11_flag_names(struct flag_info *list, CK_FLAGS value) { static char buffer[1024]; const char *sepa = ""; buffer[0] = '\0'; while (list->value) { if (list->value & value) { strcat(buffer, sepa); strcat(buffer, list->name); value &= ~list->value; sepa = ", "; } list++; } if (value) { sprintf(buffer+strlen(buffer), "%sother flags=0x%x", sepa, (unsigned int) value); } return buffer; } const char * p11_slot_info_flags(CK_FLAGS value) { static struct flag_info slot_flags[] = { { CKF_TOKEN_PRESENT, "token present" }, { CKF_REMOVABLE_DEVICE, "removable device" }, { CKF_HW_SLOT, "hardware slot" }, { 0 } }; return p11_flag_names(slot_flags, value); } const char * p11_token_info_flags(CK_FLAGS value) { static struct flag_info slot_flags[] = { { CKF_RNG, "rng" }, { CKF_WRITE_PROTECTED, "readonly" }, { CKF_LOGIN_REQUIRED, "login required" }, { CKF_USER_PIN_INITIALIZED, "PIN initialized" }, { CKF_PROTECTED_AUTHENTICATION_PATH, "PIN pad present" }, { CKF_TOKEN_INITIALIZED, "token initialized" }, { 0 } }; return p11_flag_names(slot_flags, value); } const char * p11_utf8_to_local(CK_UTF8CHAR *string, size_t len) { static char buffer[512]; size_t n, m; while (len && string[len-1] == ' ') len--; /* For now, simply copy this thing */ for (n = m = 0; n < sizeof(buffer) - 1; n++) { if (m >= len) break; buffer[n] = string[m++]; } buffer[n] = '\0'; return buffer; } void p11_fatal(const char *func, CK_RV rv) { fatal("PKCS11 function %s failed: rv = %s (0x%0x)\n", func, CKR2Str(rv), (unsigned int) rv); } void p11_perror(const char *msg, CK_RV rv) { fprintf(stderr, " ERR: %s failed: %s (0x%0x)\n", msg, CKR2Str(rv), (unsigned int) rv); } static struct mech_info p11_mechanisms[] = { { CKM_RSA_PKCS_KEY_PAIR_GEN, "RSA-PKCS-KEY-PAIR-GEN" }, { CKM_RSA_PKCS, "RSA-PKCS" }, { CKM_RSA_9796, "RSA-9796" }, { CKM_RSA_X_509, "RSA-X-509" }, { CKM_MD2_RSA_PKCS, "MD2-RSA-PKCS" }, { CKM_MD5_RSA_PKCS, "MD5-RSA-PKCS", "rsa-md5" }, { CKM_SHA1_RSA_PKCS, "SHA1-RSA-PKCS", "rsa-sha1" }, { CKM_RIPEMD128_RSA_PKCS, "RIPEMD128-RSA-PKCS" }, { CKM_RIPEMD160_RSA_PKCS, "RIPEMD160-RSA-PKCS", "rsa-ripemd160" }, { CKM_RSA_PKCS_OAEP, "RSA-PKCS-OAEP" }, { CKM_RSA_X9_31_KEY_PAIR_GEN,"RSA-X9-31-KEY-PAIR-GEN" }, { CKM_RSA_X9_31, "RSA-X9-31" }, { CKM_SHA1_RSA_X9_31, "SHA1-RSA-X9-31" }, { CKM_RSA_PKCS_PSS, "RSA-PKCS-PSS" }, { CKM_SHA1_RSA_PKCS_PSS, "SHA1-RSA-PKCS-PSS" }, { CKM_DSA_KEY_PAIR_GEN, "DSA-KEY-PAIR-GEN" }, { CKM_DSA, "DSA" }, { CKM_DSA_SHA1, "DSA-SHA1" }, { CKM_DH_PKCS_KEY_PAIR_GEN,"DH-PKCS-KEY-PAIR-GEN" }, { CKM_DH_PKCS_DERIVE, "DH-PKCS-DERIVE" }, { CKM_X9_42_DH_KEY_PAIR_GEN,"X9-42-DH-KEY-PAIR-GEN" }, { CKM_X9_42_DH_DERIVE, "X9-42-DH-DERIVE" }, { CKM_X9_42_DH_HYBRID_DERIVE,"X9-42-DH-HYBRID-DERIVE" }, { CKM_X9_42_MQV_DERIVE, "X9-42-MQV-DERIVE" }, { CKM_RC2_KEY_GEN, "RC2-KEY-GEN" }, { CKM_RC2_ECB, "RC2-ECB" }, { CKM_RC2_CBC, "RC2-CBC" }, { CKM_RC2_MAC, "RC2-MAC" }, { CKM_RC2_MAC_GENERAL, "RC2-MAC-GENERAL" }, { CKM_RC2_CBC_PAD, "RC2-CBC-PAD" }, { CKM_RC4_KEY_GEN, "RC4-KEY-GEN" }, { CKM_RC4, "RC4" }, { CKM_DES_KEY_GEN, "DES-KEY-GEN" }, { CKM_DES_ECB, "DES-ECB" }, { CKM_DES_CBC, "DES-CBC" }, { CKM_DES_MAC, "DES-MAC" }, { CKM_DES_MAC_GENERAL, "DES-MAC-GENERAL" }, { CKM_DES_CBC_PAD, "DES-CBC-PAD" }, { CKM_DES2_KEY_GEN, "DES2-KEY-GEN" }, { CKM_DES3_KEY_GEN, "DES3-KEY-GEN" }, { CKM_DES3_ECB, "DES3-ECB" }, { CKM_DES3_CBC, "DES3-CBC" }, { CKM_DES3_MAC, "DES3-MAC" }, { CKM_DES3_MAC_GENERAL, "DES3-MAC-GENERAL" }, { CKM_DES3_CBC_PAD, "DES3-CBC-PAD" }, { CKM_CDMF_KEY_GEN, "CDMF-KEY-GEN" }, { CKM_CDMF_ECB, "CDMF-ECB" }, { CKM_CDMF_CBC, "CDMF-CBC" }, { CKM_CDMF_MAC, "CDMF-MAC" }, { CKM_CDMF_MAC_GENERAL, "CDMF-MAC-GENERAL" }, { CKM_CDMF_CBC_PAD, "CDMF-CBC-PAD" }, { CKM_MD2, "MD2" }, { CKM_MD2_HMAC, "MD2-HMAC" }, { CKM_MD2_HMAC_GENERAL, "MD2-HMAC-GENERAL" }, { CKM_MD5, "MD5" }, { CKM_MD5_HMAC, "MD5-HMAC" }, { CKM_MD5_HMAC_GENERAL, "MD5-HMAC-GENERAL" }, { CKM_SHA_1, "SHA-1" }, { CKM_SHA_1_HMAC, "SHA-1-HMAC" }, { CKM_SHA_1_HMAC_GENERAL, "SHA-1-HMAC-GENERAL" }, { CKM_RIPEMD128, "RIPEMD128" }, { CKM_RIPEMD128_HMAC, "RIPEMD128-HMAC" }, { CKM_RIPEMD128_HMAC_GENERAL,"RIPEMD128-HMAC-GENERAL" }, { CKM_RIPEMD160, "RIPEMD160" }, { CKM_RIPEMD160_HMAC, "RIPEMD160-HMAC" }, { CKM_RIPEMD160_HMAC_GENERAL,"RIPEMD160-HMAC-GENERAL" }, { CKM_CAST_KEY_GEN, "CAST-KEY-GEN" }, { CKM_CAST_ECB, "CAST-ECB" }, { CKM_CAST_CBC, "CAST-CBC" }, { CKM_CAST_MAC, "CAST-MAC" }, { CKM_CAST_MAC_GENERAL, "CAST-MAC-GENERAL" }, { CKM_CAST_CBC_PAD, "CAST-CBC-PAD" }, { CKM_CAST3_KEY_GEN, "CAST3-KEY-GEN" }, { CKM_CAST3_ECB, "CAST3-ECB" }, { CKM_CAST3_CBC, "CAST3-CBC" }, { CKM_CAST3_MAC, "CAST3-MAC" }, { CKM_CAST3_MAC_GENERAL, "CAST3-MAC-GENERAL" }, { CKM_CAST3_CBC_PAD, "CAST3-CBC-PAD" }, { CKM_CAST5_KEY_GEN, "CAST5-KEY-GEN" }, { CKM_CAST5_ECB, "CAST5-ECB" }, { CKM_CAST5_CBC, "CAST5-CBC" }, { CKM_CAST5_MAC, "CAST5-MAC" }, { CKM_CAST5_MAC_GENERAL, "CAST5-MAC-GENERAL" }, { CKM_CAST5_CBC_PAD, "CAST5-CBC-PAD" }, { CKM_RC5_KEY_GEN, "RC5-KEY-GEN" }, { CKM_RC5_ECB, "RC5-ECB" }, { CKM_RC5_CBC, "RC5-CBC" }, { CKM_RC5_MAC, "RC5-MAC" }, { CKM_RC5_MAC_GENERAL, "RC5-MAC-GENERAL" }, { CKM_RC5_CBC_PAD, "RC5-CBC-PAD" }, { CKM_IDEA_KEY_GEN, "IDEA-KEY-GEN" }, { CKM_IDEA_ECB, "IDEA-ECB" }, { CKM_IDEA_CBC, "IDEA-CBC" }, { CKM_IDEA_MAC, "IDEA-MAC" }, { CKM_IDEA_MAC_GENERAL, "IDEA-MAC-GENERAL" }, { CKM_IDEA_CBC_PAD, "IDEA-CBC-PAD" }, { CKM_GENERIC_SECRET_KEY_GEN,"GENERIC-SECRET-KEY-GEN" }, { CKM_CONCATENATE_BASE_AND_KEY,"CONCATENATE-BASE-AND-KEY" }, { CKM_CONCATENATE_BASE_AND_DATA,"CONCATENATE-BASE-AND-DATA" }, { CKM_CONCATENATE_DATA_AND_BASE,"CONCATENATE-DATA-AND-BASE" }, { CKM_XOR_BASE_AND_DATA, "XOR-BASE-AND-DATA" }, { CKM_EXTRACT_KEY_FROM_KEY,"EXTRACT-KEY-FROM-KEY" }, { CKM_SSL3_PRE_MASTER_KEY_GEN,"SSL3-PRE-MASTER-KEY-GEN" }, { CKM_SSL3_MASTER_KEY_DERIVE,"SSL3-MASTER-KEY-DERIVE" }, { CKM_SSL3_KEY_AND_MAC_DERIVE,"SSL3-KEY-AND-MAC-DERIVE" }, { CKM_SSL3_MASTER_KEY_DERIVE_DH,"SSL3-MASTER-KEY-DERIVE-DH" }, { CKM_TLS_PRE_MASTER_KEY_GEN,"TLS-PRE-MASTER-KEY-GEN" }, { CKM_TLS_MASTER_KEY_DERIVE,"TLS-MASTER-KEY-DERIVE" }, { CKM_TLS_KEY_AND_MAC_DERIVE,"TLS-KEY-AND-MAC-DERIVE" }, { CKM_TLS_MASTER_KEY_DERIVE_DH,"TLS-MASTER-KEY-DERIVE-DH" }, { CKM_SSL3_MD5_MAC, "SSL3-MD5-MAC" }, { CKM_SSL3_SHA1_MAC, "SSL3-SHA1-MAC" }, { CKM_MD5_KEY_DERIVATION, "MD5-KEY-DERIVATION" }, { CKM_MD2_KEY_DERIVATION, "MD2-KEY-DERIVATION" }, { CKM_SHA1_KEY_DERIVATION,"SHA1-KEY-DERIVATION" }, { CKM_PBE_MD2_DES_CBC, "PBE-MD2-DES-CBC" }, { CKM_PBE_MD5_DES_CBC, "PBE-MD5-DES-CBC" }, { CKM_PBE_MD5_CAST_CBC, "PBE-MD5-CAST-CBC" }, { CKM_PBE_MD5_CAST3_CBC, "PBE-MD5-CAST3-CBC" }, { CKM_PBE_MD5_CAST5_CBC, "PBE-MD5-CAST5-CBC" }, { CKM_PBE_SHA1_CAST5_CBC, "PBE-SHA1-CAST5-CBC" }, { CKM_PBE_SHA1_RC4_128, "PBE-SHA1-RC4-128" }, { CKM_PBE_SHA1_RC4_40, "PBE-SHA1-RC4-40" }, { CKM_PBE_SHA1_DES3_EDE_CBC,"PBE-SHA1-DES3-EDE-CBC" }, { CKM_PBE_SHA1_DES2_EDE_CBC,"PBE-SHA1-DES2-EDE-CBC" }, { CKM_PBE_SHA1_RC2_128_CBC,"PBE-SHA1-RC2-128-CBC" }, { CKM_PBE_SHA1_RC2_40_CBC,"PBE-SHA1-RC2-40-CBC" }, { CKM_PKCS5_PBKD2, "PKCS5-PBKD2" }, { CKM_PBA_SHA1_WITH_SHA1_HMAC,"PBA-SHA1-WITH-SHA1-HMAC" }, { CKM_KEY_WRAP_LYNKS, "KEY-WRAP-LYNKS" }, { CKM_KEY_WRAP_SET_OAEP, "KEY-WRAP-SET-OAEP" }, { CKM_SKIPJACK_KEY_GEN, "SKIPJACK-KEY-GEN" }, { CKM_SKIPJACK_ECB64, "SKIPJACK-ECB64" }, { CKM_SKIPJACK_CBC64, "SKIPJACK-CBC64" }, { CKM_SKIPJACK_OFB64, "SKIPJACK-OFB64" }, { CKM_SKIPJACK_CFB64, "SKIPJACK-CFB64" }, { CKM_SKIPJACK_CFB32, "SKIPJACK-CFB32" }, { CKM_SKIPJACK_CFB16, "SKIPJACK-CFB16" }, { CKM_SKIPJACK_CFB8, "SKIPJACK-CFB8" }, { CKM_SKIPJACK_WRAP, "SKIPJACK-WRAP" }, { CKM_SKIPJACK_PRIVATE_WRAP,"SKIPJACK-PRIVATE-WRAP" }, { CKM_SKIPJACK_RELAYX, "SKIPJACK-RELAYX" }, { CKM_KEA_KEY_PAIR_GEN, "KEA-KEY-PAIR-GEN" }, { CKM_KEA_KEY_DERIVE, "KEA-KEY-DERIVE" }, { CKM_FORTEZZA_TIMESTAMP, "FORTEZZA-TIMESTAMP" }, { CKM_BATON_KEY_GEN, "BATON-KEY-GEN" }, { CKM_BATON_ECB128, "BATON-ECB128" }, { CKM_BATON_ECB96, "BATON-ECB96" }, { CKM_BATON_CBC128, "BATON-CBC128" }, { CKM_BATON_COUNTER, "BATON-COUNTER" }, { CKM_BATON_SHUFFLE, "BATON-SHUFFLE" }, { CKM_BATON_WRAP, "BATON-WRAP" }, { CKM_ECDSA_KEY_PAIR_GEN, "ECDSA-KEY-PAIR-GEN" }, { CKM_ECDSA, "ECDSA" }, { CKM_ECDSA_SHA1, "ECDSA-SHA1" }, { CKM_ECDH1_DERIVE, "ECDH1-DERIVE" }, { CKM_ECDH1_COFACTOR_DERIVE,"ECDH1-COFACTOR-DERIVE" }, { CKM_ECMQV_DERIVE, "ECMQV-DERIVE" }, { CKM_JUNIPER_KEY_GEN, "JUNIPER-KEY-GEN" }, { CKM_JUNIPER_ECB128, "JUNIPER-ECB128" }, { CKM_JUNIPER_CBC128, "JUNIPER-CBC128" }, { CKM_JUNIPER_COUNTER, "JUNIPER-COUNTER" }, { CKM_JUNIPER_SHUFFLE, "JUNIPER-SHUFFLE" }, { CKM_JUNIPER_WRAP, "JUNIPER-WRAP" }, { CKM_FASTHASH, "FASTHASH" }, { CKM_AES_KEY_GEN, "AES-KEY-GEN" }, { CKM_AES_ECB, "AES-ECB" }, { CKM_AES_CBC, "AES-CBC" }, { CKM_AES_MAC, "AES-MAC" }, { CKM_AES_MAC_GENERAL, "AES-MAC-GENERAL" }, { CKM_AES_CBC_PAD, "AES-CBC-PAD" }, { CKM_DSA_PARAMETER_GEN, "DSA-PARAMETER-GEN" }, { CKM_DH_PKCS_PARAMETER_GEN,"DH-PKCS-PARAMETER-GEN" }, { CKM_X9_42_DH_PARAMETER_GEN,"X9-42-DH-PARAMETER-GEN" }, { NO_MECHANISM, NULL } }; static const char * p11_mechanism_to_name(CK_MECHANISM_TYPE mech) { static char temp[64]; struct mech_info *mi; for (mi = p11_mechanisms; mi->name; mi++) { if (mi->mech == mech) return mi->name; } snprintf(temp, sizeof(temp), "mechtype-%lu", mech); return temp; } CK_MECHANISM_TYPE p11_name_to_mechanism(const char *name) { struct mech_info *mi; for (mi = p11_mechanisms; mi->name; mi++) { if (!strcasecmp(mi->name, name) || (mi->short_name && !strcasecmp(mi->short_name, name))) return mi->mech; } fatal("Unknown PKCS11 mechanism \"%s\"\n", name); return NO_MECHANISM; /* gcc food */ } static const char * CKR2Str(CK_ULONG res) { switch (res) { case CKR_OK: return "CKR_OK"; case CKR_CANCEL: return "CKR_CANCEL"; case CKR_HOST_MEMORY: return "CKR_HOST_MEMORY"; case CKR_SLOT_ID_INVALID: return "CKR_SLOT_ID_INVALID"; case CKR_GENERAL_ERROR: return "CKR_GENERAL_ERROR"; case CKR_FUNCTION_FAILED: return "CKR_FUNCTION_FAILED"; case CKR_ARGUMENTS_BAD: return "CKR_ARGUMENTS_BAD"; case CKR_NO_EVENT: return "CKR_NO_EVENT"; case CKR_NEED_TO_CREATE_THREADS: return "CKR_NEED_TO_CREATE_THREADS"; case CKR_CANT_LOCK: return "CKR_CANT_LOCK"; case CKR_ATTRIBUTE_READ_ONLY: return "CKR_ATTRIBUTE_READ_ONLY"; case CKR_ATTRIBUTE_SENSITIVE: return "CKR_ATTRIBUTE_SENSITIVE"; case CKR_ATTRIBUTE_TYPE_INVALID: return "CKR_ATTRIBUTE_TYPE_INVALID"; case CKR_ATTRIBUTE_VALUE_INVALID: return "CKR_ATTRIBUTE_VALUE_INVALID"; case CKR_DATA_INVALID: return "CKR_DATA_INVALID"; case CKR_DATA_LEN_RANGE: return "CKR_DATA_LEN_RANGE"; case CKR_DEVICE_ERROR: return "CKR_DEVICE_ERROR"; case CKR_DEVICE_MEMORY: return "CKR_DEVICE_MEMORY"; case CKR_DEVICE_REMOVED: return "CKR_DEVICE_REMOVED"; case CKR_ENCRYPTED_DATA_INVALID: return "CKR_ENCRYPTED_DATA_INVALID"; case CKR_ENCRYPTED_DATA_LEN_RANGE: return "CKR_ENCRYPTED_DATA_LEN_RANGE"; case CKR_FUNCTION_CANCELED: return "CKR_FUNCTION_CANCELED"; case CKR_FUNCTION_NOT_PARALLEL: return "CKR_FUNCTION_NOT_PARALLEL"; case CKR_FUNCTION_NOT_SUPPORTED: return "CKR_FUNCTION_NOT_SUPPORTED"; case CKR_KEY_HANDLE_INVALID: return "CKR_KEY_HANDLE_INVALID"; case CKR_KEY_SIZE_RANGE: return "CKR_KEY_SIZE_RANGE"; case CKR_KEY_TYPE_INCONSISTENT: return "CKR_KEY_TYPE_INCONSISTENT"; case CKR_KEY_NOT_NEEDED: return "CKR_KEY_NOT_NEEDED"; case CKR_KEY_CHANGED: return "CKR_KEY_CHANGED"; case CKR_KEY_NEEDED: return "CKR_KEY_NEEDED"; case CKR_KEY_INDIGESTIBLE: return "CKR_KEY_INDIGESTIBLE"; case CKR_KEY_FUNCTION_NOT_PERMITTED: return "CKR_KEY_FUNCTION_NOT_PERMITTED"; case CKR_KEY_NOT_WRAPPABLE: return "CKR_KEY_NOT_WRAPPABLE"; case CKR_KEY_UNEXTRACTABLE: return "CKR_KEY_UNEXTRACTABLE"; case CKR_MECHANISM_INVALID: return "CKR_MECHANISM_INVALID"; case CKR_MECHANISM_PARAM_INVALID: return "CKR_MECHANISM_PARAM_INVALID"; case CKR_OBJECT_HANDLE_INVALID: return "CKR_OBJECT_HANDLE_INVALID"; case CKR_OPERATION_ACTIVE: return "CKR_OPERATION_ACTIVE"; case CKR_OPERATION_NOT_INITIALIZED: return "CKR_OPERATION_NOT_INITIALIZED"; case CKR_PIN_INCORRECT: return "CKR_PIN_INCORRECT"; case CKR_PIN_INVALID: return "CKR_PIN_INVALID"; case CKR_PIN_LEN_RANGE: return "CKR_PIN_LEN_RANGE"; case CKR_PIN_EXPIRED: return "CKR_PIN_EXPIRED"; case CKR_PIN_LOCKED: return "CKR_PIN_LOCKED"; case CKR_SESSION_CLOSED: return "CKR_SESSION_CLOSED"; case CKR_SESSION_COUNT: return "CKR_SESSION_COUNT"; case CKR_SESSION_HANDLE_INVALID: return "CKR_SESSION_HANDLE_INVALID"; case CKR_SESSION_PARALLEL_NOT_SUPPORTED: return "CKR_SESSION_PARALLEL_NOT_SUPPORTED"; case CKR_SESSION_READ_ONLY: return "CKR_SESSION_READ_ONLY"; case CKR_SESSION_EXISTS: return "CKR_SESSION_EXISTS"; case CKR_SESSION_READ_ONLY_EXISTS: return "CKR_SESSION_READ_ONLY_EXISTS"; case CKR_SESSION_READ_WRITE_SO_EXISTS: return "CKR_SESSION_READ_WRITE_SO_EXISTS"; case CKR_SIGNATURE_INVALID: return "CKR_SIGNATURE_INVALID"; case CKR_SIGNATURE_LEN_RANGE: return "CKR_SIGNATURE_LEN_RANGE"; case CKR_TEMPLATE_INCOMPLETE: return "CKR_TEMPLATE_INCOMPLETE"; case CKR_TEMPLATE_INCONSISTENT: return "CKR_TEMPLATE_INCONSISTENT"; case CKR_TOKEN_NOT_PRESENT: return "CKR_TOKEN_NOT_PRESENT"; case CKR_TOKEN_NOT_RECOGNIZED: return "CKR_TOKEN_NOT_RECOGNIZED"; case CKR_TOKEN_WRITE_PROTECTED: return "CKR_TOKEN_WRITE_PROTECTED"; case CKR_UNWRAPPING_KEY_HANDLE_INVALID: return "CKR_UNWRAPPING_KEY_HANDLE_INVALID"; case CKR_UNWRAPPING_KEY_SIZE_RANGE: return "CKR_UNWRAPPING_KEY_SIZE_RANGE"; case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT"; case CKR_USER_ALREADY_LOGGED_IN: return "CKR_USER_ALREADY_LOGGED_IN"; case CKR_USER_NOT_LOGGED_IN: return "CKR_USER_NOT_LOGGED_IN"; case CKR_USER_PIN_NOT_INITIALIZED: return "CKR_USER_PIN_NOT_INITIALIZED"; case CKR_USER_TYPE_INVALID: return "CKR_USER_TYPE_INVALID"; case CKR_USER_ANOTHER_ALREADY_LOGGED_IN: return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN"; case CKR_USER_TOO_MANY_TYPES: return "CKR_USER_TOO_MANY_TYPES"; case CKR_WRAPPED_KEY_INVALID: return "CKR_WRAPPED_KEY_INVALID"; case CKR_WRAPPED_KEY_LEN_RANGE: return "CKR_WRAPPED_KEY_LEN_RANGE"; case CKR_WRAPPING_KEY_HANDLE_INVALID: return "CKR_WRAPPING_KEY_HANDLE_INVALID"; case CKR_WRAPPING_KEY_SIZE_RANGE: return "CKR_WRAPPING_KEY_SIZE_RANGE"; case CKR_WRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT"; case CKR_RANDOM_SEED_NOT_SUPPORTED: return "CKR_RANDOM_SEED_NOT_SUPPORTED"; case CKR_RANDOM_NO_RNG: return "CKR_RANDOM_NO_RNG"; case CKR_DOMAIN_PARAMS_INVALID: return "CKR_DOMAIN_PARAMS_INVALID"; case CKR_BUFFER_TOO_SMALL: return "CKR_BUFFER_TOO_SMALL"; case CKR_SAVED_STATE_INVALID: return "CKR_SAVED_STATE_INVALID"; case CKR_INFORMATION_SENSITIVE: return "CKR_INFORMATION_SENSITIVE"; case CKR_STATE_UNSAVEABLE: return "CKR_STATE_UNSAVEABLE"; case CKR_CRYPTOKI_NOT_INITIALIZED: return "CKR_CRYPTOKI_NOT_INITIALIZED"; case CKR_CRYPTOKI_ALREADY_INITIALIZED: return "CKR_CRYPTOKI_ALREADY_INITIALIZED"; case CKR_MUTEX_BAD: return "CKR_MUTEX_BAD"; case CKR_MUTEX_NOT_LOCKED: return "CKR_MUTEX_NOT_LOCKED"; case CKR_VENDOR_DEFINED: return "CKR_VENDOR_DEFINED"; } return "unknown PKCS11 error"; }