/* * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (c) 2002 Juha Yrjölä. All rights reserved. * Copyright (c) 2001 Markus Friedl. * Copyright (c) 2002 Olaf Kirch * Copyright (c) 2003 Kevin Stefanik * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /***************************************************************************** ChangeLog (01/04/2013): Added following new functionalities - API to list objects on the token - API to store certificate to token - API to generate & store RSA key pair to token - API to get RSA public key from token - API to Delete object from token *****************************************************************************/ #include #include #include #include #include #include #include #include "engine_pkcs11.h" #ifdef _WIN32 #define strncasecmp strnicmp #endif #define fail(msg) { fprintf(stderr,msg); return NULL;} /** The maximum length of an internally-allocated PIN */ #define MAX_PIN_LENGTH 32 /* Maximum size of a token object */ #define MAX_OBJECT_SIZE 5000 static int do_login(PKCS11_SLOT *slot); static int pkcs11_store_cert ( ENGINE * e, int slot_nr, unsigned char *cert_id, size_t cert_id_len, char *cert_label, X509 *x ); static int parse_cert_store_string ( const char *cert_store_str, int *slot, unsigned char *id, size_t * id_len, char **label, char **cert_file ); static int parse_key_gen_string ( const char *key_gen_str, int *slot, int *key_size, unsigned char *id, size_t * id_len, char **label ); static int pkcs11_gen_key ( ENGINE * e, int slot_nr, unsigned int key_size, unsigned char *key_id, size_t key_id_len, char *key_label ); static int pkcs11_del_obj ( ENGINE * e, int slot_nr, char *type_str, unsigned char *id, size_t id_len, char *label ); static int parse_del_obj_string ( const char *del_obj_str, int *slot, char **type, unsigned char *id, size_t * id_len, char **label ); static int parse_key_string ( const char *pubkey_get_str, int *slot, unsigned char *id, size_t * id_len, char **label, char **key_file ); static PKCS11_CTX *ctx = NULL; /** * The PIN used for login. Cache for the get_pin function. * The memory for this PIN is always owned internally, * and may be freed as necessary. Before freeing, the PIN * must be whitened, to prevent security holes. */ static char *pin = NULL; static int pin_length = 0; static int verbose = 0; static char *module = NULL; static char *init_args = NULL; int set_module(const char *modulename) { module = modulename ? strdup(modulename) : NULL; return 1; } /** * Set the PIN used for login. A copy of the PIN shall be made. * * If the PIN cannot be assigned, the value 0 shall be returned * and errno shall be set as follows: * * EINVAL - a NULL PIN was supplied * ENOMEM - insufficient memory to copy the PIN * * @param _pin the pin to use for login. Must not be NULL. * * @return 1 on success, 0 on failure. */ int set_pin(const char *_pin) { /* Pre-condition check */ if (_pin == NULL) { errno = EINVAL; return 0; } /* Copy the PIN. If the string cannot be copied, NULL shall be returned and errno shall be set. */ pin = strdup(_pin); if (pin != NULL) pin_length = strlen(pin); return (pin != NULL); } int inc_verbose(void) { verbose++; return 1; } /* either get the pin code from the supplied callback data, or get the pin * via asking our self. In both cases keep a copy of the pin code in the * pin variable (strdup'ed copy). */ static int get_pin(UI_METHOD * ui_method, void *callback_data) { UI *ui; struct { const void *password; const char *prompt_info; } *mycb = callback_data; /* pin in the call back data, copy and use */ if (mycb != NULL && mycb->password) { pin = (char *)calloc(MAX_PIN_LENGTH, sizeof(char)); if (!pin) return 0; strncpy(pin,mycb->password,MAX_PIN_LENGTH); pin_length = MAX_PIN_LENGTH; return 1; } /* call ui to ask for a pin */ ui = UI_new(); if (ui_method != NULL) UI_set_method(ui, ui_method); if (callback_data != NULL) UI_set_app_data(ui, callback_data); if (!UI_add_input_string (ui, "PKCS#11 token PIN: ", 0, pin, 1, MAX_PIN_LENGTH)) { fprintf(stderr, "UI_add_input_string failed\n"); UI_free(ui); return 0; } if (UI_process(ui)) { fprintf(stderr, "UI_process failed\n"); UI_free(ui); return 0; } UI_free(ui); return 1; } int set_init_args(const char *init_args_orig) { init_args = init_args_orig ? strdup(init_args_orig) : NULL; return 1; } int pkcs11_finish(ENGINE * engine) { if (verbose) { fprintf(stderr, "engine finish\n"); } if (ctx) { PKCS11_CTX_unload(ctx); PKCS11_CTX_free(ctx); ctx = NULL; } if (pin != NULL) { OPENSSL_cleanse(pin, pin_length); free(pin); pin = NULL; pin_length = 0; } return 1; } int pkcs11_init(ENGINE * engine) { if (verbose) { fprintf(stderr, "initializing engine\n"); } ctx = PKCS11_CTX_new(); PKCS11_CTX_init_args(ctx, init_args); if (PKCS11_CTX_load(ctx, module) < 0) { fprintf(stderr, "unable to load module %s\n", module); return 0; } return 1; } int pkcs11_rsa_finish(RSA * rsa) { if (pin) { OPENSSL_cleanse(pin, pin_length); free(pin); pin = NULL; pin_length = 0; } if (module) { free(module); module = NULL; } /* need to free RSA_ex_data? */ return 1; } static int hex_to_bin(const char *in, unsigned char *out, size_t * outlen) { size_t left, count = 0; if (in == NULL || *in == '\0') { *outlen = 0; return 1; } left = *outlen; while (*in != '\0') { int byte = 0, nybbles = 2; while (nybbles-- && *in && *in != ':') { char c; byte <<= 4; c = *in++; if ('0' <= c && c <= '9') c -= '0'; else if ('a' <= c && c <= 'f') c = c - 'a' + 10; else if ('A' <= c && c <= 'F') c = c - 'A' + 10; else { fprintf(stderr, "hex_to_bin(): invalid char '%c' in hex string\n", c); *outlen = 0; return 0; } byte |= c; } if (*in == ':') in++; if (left <= 0) { fprintf(stderr, "hex_to_bin(): hex string too long\n"); *outlen = 0; return 0; } out[count++] = (unsigned char)byte; left--; } *outlen = count; return 1; } /* parse string containing slot and id information */ static int parse_slot_id_string(const char *slot_id, int *slot, unsigned char *id, size_t * id_len, char **label) { int n, i; if (!slot_id) return 0; /* support for several formats */ #define HEXDIGITS "01234567890ABCDEFabcdef" #define DIGITS "0123456789" /* first: pure hex number (id, slot is 0) */ if (strspn(slot_id, HEXDIGITS) == strlen(slot_id)) { /* ah, easiest case: only hex. */ if ((strlen(slot_id) + 1) / 2 > *id_len) { fprintf(stderr, "id string too long!\n"); return 0; } *slot = 0; return hex_to_bin(slot_id, id, id_len); } /* second: slot:id. slot is an digital int. */ if (sscanf(slot_id, "%d", &n) == 1) { i = strspn(slot_id, DIGITS); if (slot_id[i] != ':') { fprintf(stderr, "could not parse string!\n"); return 0; } i++; if (slot_id[i] == 0) { *slot = n; *id_len = 0; return 1; } if (strspn(slot_id + i, HEXDIGITS) + i != strlen(slot_id)) { fprintf(stderr, "could not parse string!\n"); return 0; } /* ah, rest is hex */ if ((strlen(slot_id) - i + 1) / 2 > *id_len) { fprintf(stderr, "id string too long!\n"); return 0; } *slot = n; return hex_to_bin(slot_id + i, id, id_len); } /* third: id_ */ if (strncmp(slot_id, "id_", 3) == 0) { if (strspn(slot_id + 3, HEXDIGITS) + 3 != strlen(slot_id)) { fprintf(stderr, "could not parse string!\n"); return 0; } /* ah, rest is hex */ if ((strlen(slot_id) - 3 + 1) / 2 > *id_len) { fprintf(stderr, "id string too long!\n"); return 0; } *slot = 0; return hex_to_bin(slot_id + 3, id, id_len); } /* label_