Engine PKCS#11 initial commit
[keystone-linux/engine-pkcs11.git] / src / engine_pkcs11.c
1 /*
2  * Copyright (c) 2002 Juha Yrjölä.  All rights reserved.
3  * Copyright (c) 2001 Markus Friedl.
4  * Copyright (c) 2002 Olaf Kirch
5  * Copyright (c) 2003 Kevin Stefanik
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #include <config.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <openssl/crypto.h>
32 #include <openssl/objects.h>
33 #include <openssl/engine.h>
34 #include <libp11.h>
35 #include "engine_pkcs11.h"
37 #ifdef _WIN32
38 #define strncasecmp strnicmp
39 #endif
41 #define fail(msg) { fprintf(stderr,msg); return NULL;}
43 /** The maximum length of an internally-allocated PIN */
44 #define MAX_PIN_LENGTH   32
46 static PKCS11_CTX *ctx;
48 /** 
49  * The PIN used for login. Cache for the get_pin function.
50  * The memory for this PIN is always owned internally,
51  * and may be freed as necessary. Before freeing, the PIN 
52  * must be whitened, to prevent security holes.
53  */
54 static char *pin = NULL;
55 static int pin_length = 0;
57 static int verbose = 0;
59 static char *module = NULL;
61 static char *init_args = NULL;
63 int set_module(const char *modulename)
64 {
65         module = modulename ? strdup(modulename) : NULL;
66         return 1;
67 }
69 /**
70  * Set the PIN used for login. A copy of the PIN shall be made.
71  *
72  * If the PIN cannot be assigned, the value 0 shall be returned
73  * and errno shall be set as follows:
74  *
75  *   EINVAL - a NULL PIN was supplied
76  *   ENOMEM - insufficient memory to copy the PIN
77  *
78  * @param _pin the pin to use for login. Must not be NULL.
79  *
80  * @return 1 on success, 0 on failure.
81  */
82 int set_pin(const char *_pin)
83 {
84         /* Pre-condition check */
85         if (_pin == NULL) {
86                 errno = EINVAL;
87                 return 0;
88         }
90         /* Copy the PIN. If the string cannot be copied, NULL
91            shall be returned and errno shall be set. */
92         pin = strdup(_pin);
93         if (pin != NULL)
94                 pin_length = strlen(pin);
96         return (pin != NULL);
97 }
99 int inc_verbose(void)
101         verbose++;
102         return 1;
105 /* either get the pin code from the supplied callback data, or get the pin
106  * via asking our self. In both cases keep a copy of the pin code in the
107  * pin variable (strdup'ed copy). */
108 static int get_pin(UI_METHOD * ui_method, void *callback_data)
110         UI *ui;
111         struct {
112                 const void *password;
113                 const char *prompt_info;
114         } *mycb = callback_data;
116         /* pin in the call back data, copy and use */
117         if (mycb != NULL && mycb->password) {
118                 pin = (char *)calloc(MAX_PIN_LENGTH, sizeof(char));
119                 if (!pin)
120                         return 0;
121                 strncpy(pin,mycb->password,MAX_PIN_LENGTH);
122                 pin_length = MAX_PIN_LENGTH;
123                 return 1;
124         }
126         /* call ui to ask for a pin */
127         ui = UI_new();
128         if (ui_method != NULL)
129                 UI_set_method(ui, ui_method);
130         if (callback_data != NULL)
131                 UI_set_app_data(ui, callback_data);
133         if (!UI_add_input_string
134             (ui, "PKCS#11 token PIN: ", 0, pin, 1, MAX_PIN_LENGTH)) {
135                 fprintf(stderr, "UI_add_input_string failed\n");
136                 UI_free(ui);
137                 return 0;
138         }
139         if (UI_process(ui)) {
140                 fprintf(stderr, "UI_process failed\n");
141                 UI_free(ui);
142                 return 0;
143         }
144         UI_free(ui);
145         return 1;
148 int set_init_args(const char *init_args_orig)
150         init_args = init_args_orig ? strdup(init_args_orig) : NULL;
151         return 1;
154 int pkcs11_finish(ENGINE * engine)
156         if (ctx) {
157                 PKCS11_CTX_unload(ctx);
158                 PKCS11_CTX_free(ctx);
159                 ctx = NULL;
160         }
161         if (pin != NULL) {
162                 OPENSSL_cleanse(pin, pin_length);
163                 free(pin);
164                 pin = NULL;
165                 pin_length = 0;
166         }
167         return 1;
170 int pkcs11_init(ENGINE * engine)
172         if (verbose) {
173                 fprintf(stderr, "initializing engine\n");
174         }
175         ctx = PKCS11_CTX_new();
176         PKCS11_CTX_init_args(ctx, init_args);
177         if (PKCS11_CTX_load(ctx, module) < 0) {
178                 fprintf(stderr, "unable to load module %s\n", module);
179                 return 0;
180         }
181         return 1;
184 int pkcs11_rsa_finish(RSA * rsa)
186         if (pin) {
187                 OPENSSL_cleanse(pin, pin_length);
188                 free(pin);
189                 pin = NULL;
190                 pin_length = 0;
191         }
192         if (module) {
193                 free(module);
194                 module = NULL;
195         }
196         /* need to free RSA_ex_data? */
197         return 1;
200 static int hex_to_bin(const char *in, unsigned char *out, size_t * outlen)
202         size_t left, count = 0;
204         if (in == NULL || *in == '\0') {
205                 *outlen = 0;
206                 return 1;
207         }
209         left = *outlen;
211         while (*in != '\0') {
212                 int byte = 0, nybbles = 2;
214                 while (nybbles-- && *in && *in != ':') {
215                         char c;
216                         byte <<= 4;
217                         c = *in++;
218                         if ('0' <= c && c <= '9')
219                                 c -= '0';
220                         else if ('a' <= c && c <= 'f')
221                                 c = c - 'a' + 10;
222                         else if ('A' <= c && c <= 'F')
223                                 c = c - 'A' + 10;
224                         else {
225                                 fprintf(stderr,
226                                         "hex_to_bin(): invalid char '%c' in hex string\n",
227                                         c);
228                                 *outlen = 0;
229                                 return 0;
230                         }
231                         byte |= c;
232                 }
233                 if (*in == ':')
234                         in++;
235                 if (left <= 0) {
236                         fprintf(stderr, "hex_to_bin(): hex string too long\n");
237                         *outlen = 0;
238                         return 0;
239                 }
240                 out[count++] = (unsigned char)byte;
241                 left--;
242         }
244         *outlen = count;
245         return 1;
248 /* parse string containing slot and id information */
250 static int parse_slot_id_string(const char *slot_id, int *slot,
251                                 unsigned char *id, size_t * id_len,
252                                 char **label)
254         int n, i;
256         if (!slot_id)
257                 return 0;
259         /* support for several formats */
260 #define HEXDIGITS "01234567890ABCDEFabcdef"
261 #define DIGITS "0123456789"
263         /* first: pure hex number (id, slot is 0) */
264         if (strspn(slot_id, HEXDIGITS) == strlen(slot_id)) {
265                 /* ah, easiest case: only hex. */
266                 if ((strlen(slot_id) + 1) / 2 > *id_len) {
267                         fprintf(stderr, "id string too long!\n");
268                         return 0;
269                 }
270                 *slot = 0;
271                 return hex_to_bin(slot_id, id, id_len);
272         }
274         /* second: slot:id. slot is an digital int. */
275         if (sscanf(slot_id, "%d", &n) == 1) {
276                 i = strspn(slot_id, DIGITS);
278                 if (slot_id[i] != ':') {
279                         fprintf(stderr, "could not parse string!\n");
280                         return 0;
281                 }
282                 i++;
283                 if (slot_id[i] == 0) {
284                         *slot = n;
285                         *id_len = 0;
286                         return 1;
287                 }
288                 if (strspn(slot_id + i, HEXDIGITS) + i != strlen(slot_id)) {
289                         fprintf(stderr, "could not parse string!\n");
290                         return 0;
291                 }
292                 /* ah, rest is hex */
293                 if ((strlen(slot_id) - i + 1) / 2 > *id_len) {
294                         fprintf(stderr, "id string too long!\n");
295                         return 0;
296                 }
297                 *slot = n;
298                 return hex_to_bin(slot_id + i, id, id_len);
299         }
301         /* third: id_<id>  */
302         if (strncmp(slot_id, "id_", 3) == 0) {
303                 if (strspn(slot_id + 3, HEXDIGITS) + 3 != strlen(slot_id)) {
304                         fprintf(stderr, "could not parse string!\n");
305                         return 0;
306                 }
307                 /* ah, rest is hex */
308                 if ((strlen(slot_id) - 3 + 1) / 2 > *id_len) {
309                         fprintf(stderr, "id string too long!\n");
310                         return 0;
311                 }
312                 *slot = 0;
313                 return hex_to_bin(slot_id + 3, id, id_len);
314         }
316         /* label_<label>  */
317         if (strncmp(slot_id, "label_", 6) == 0) {
318                 *label = strdup(slot_id + 6);
319                 return *label != NULL;
320         }
322         /* last try: it has to be slot_<slot> and then "-id_<cert>" */
324         if (strncmp(slot_id, "slot_", 5) != 0) {
325                 fprintf(stderr, "format not recognized!\n");
326                 return 0;
327         }
329         /* slot is an digital int. */
330         if (sscanf(slot_id + 5, "%d", &n) != 1) {
331                 fprintf(stderr, "slot number not deciphered!\n");
332                 return 0;
333         }
335         i = strspn(slot_id + 5, DIGITS);
337         if (slot_id[i + 5] == 0) {
338                 *slot = n;
339                 *id_len = 0;
340                 return 1; 
341         }
343         if (slot_id[i + 5] != '-') {
344                 fprintf(stderr, "could not parse string!\n");
345                 return 0;
346         }
348         i = 5 + i + 1;
350         /* now followed by "id_" */
351         if (strncmp(slot_id + i, "id_", 3) == 0) {
352                 if (strspn(slot_id + i + 3, HEXDIGITS) + 3 + i !=
353                     strlen(slot_id)) {
354                         fprintf(stderr, "could not parse string!\n");
355                         return 0;
356                 }
357                 /* ah, rest is hex */
358                 if ((strlen(slot_id) - i - 3 + 1) / 2 > *id_len) {
359                         fprintf(stderr, "id string too long!\n");
360                         return 0;
361                 }
362                 *slot = n;
363                 return hex_to_bin(slot_id + i + 3, id, id_len);
364         }
366         /* ... or "label_" */
367         if (strncmp(slot_id + i, "label_", 6) == 0) {
368                 *slot = n;
369                 return (*label = strdup(slot_id + i + 6)) != NULL;
370         }
372         fprintf(stderr, "could not parse string!\n");
373         return 0;
376 #define MAX_VALUE_LEN   200
378 /* prototype for OpenSSL ENGINE_load_cert */
379 /* used by load_cert_ctrl via ENGINE_ctrl for now */
381 static X509 *pkcs11_load_cert(ENGINE * e, const char *s_slot_cert_id)
383         PKCS11_SLOT *slot_list, *slot;
384         PKCS11_SLOT *found_slot = NULL;
385         PKCS11_TOKEN *tok;
386         PKCS11_CERT *certs, *selected_cert = NULL;
387         X509 *x509;
388         unsigned int slot_count, cert_count, n, m;
389         unsigned char cert_id[MAX_VALUE_LEN / 2];
390         size_t cert_id_len = sizeof(cert_id);
391         char *cert_label = NULL;
392         int slot_nr = -1;
393         char flags[64];
395         if (s_slot_cert_id && *s_slot_cert_id) {
396                 n = parse_slot_id_string(s_slot_cert_id, &slot_nr,
397                                          cert_id, &cert_id_len, &cert_label);
398                 if (!n) {
399                         fprintf(stderr,
400                                 "supported formats: <id>, <slot>:<id>, id_<id>, slot_<slot>-id_<id>, label_<label>, slot_<slot>-label_<label>\n");
401                         fprintf(stderr,
402                                 "where <slot> is the slot number as normal integer,\n");
403                         fprintf(stderr,
404                                 "and <id> is the id number as hex string.\n");
405                         fprintf(stderr,
406                                 "and <label> is the textual key label string.\n");
407                         return NULL;
408                 }
409                 if (verbose) {
410                         fprintf(stderr, "Looking in slot %d for certificate: ",
411                                 slot_nr);
412                         if (cert_label == NULL) {
413                                 for (n = 0; n < cert_id_len; n++)
414                                         fprintf(stderr, "%02x", cert_id[n]);
415                                 fprintf(stderr, "\n");
416                         } else
417                                 fprintf(stderr, "label: %s\n", cert_label);
419                 }
420         }
422         if (PKCS11_enumerate_slots(ctx, &slot_list, &slot_count) < 0)
423                 fail("failed to enumerate slots\n");
425         if (verbose) {
426                 fprintf(stderr, "Found %u slot%s\n", slot_count,
427                         (slot_count <= 1) ? "" : "s");
428         }
429         for (n = 0; n < slot_count; n++) {
430                 slot = slot_list + n;
431                 flags[0] = '\0';
432                 if (slot->token) {
433                         if (!slot->token->initialized)
434                                 strcat(flags, "uninitialized, ");
435                         else if (!slot->token->userPinSet)
436                                 strcat(flags, "no pin, ");
437                         if (slot->token->loginRequired)
438                                 strcat(flags, "login, ");
439                         if (slot->token->readOnly)
440                                 strcat(flags, "ro, ");
441                 } else {
442                         strcpy(flags, "no token");
443                 }
444                 if ((m = strlen(flags)) != 0) {
445                         flags[m - 2] = '\0';
446                 }
448                 if (slot_nr != -1 &&
449                         slot_nr == PKCS11_get_slotid_from_slot(slot)) {
450                         found_slot = slot;
451                 }
453                 if (verbose) {
454                         fprintf(stderr, "[%lu] %-25.25s  %-16s",
455                                 PKCS11_get_slotid_from_slot(slot),
456                                 slot->description, flags);
457                         if (slot->token) {
458                                 fprintf(stderr, "  (%s)",
459                                         slot->token->label[0] ?
460                                         slot->token->label : "no label");
461                         }
462                         fprintf(stderr, "\n");
463                 }
464         }
466         if (slot_nr == -1) {
467                 if (!(slot = PKCS11_find_token(ctx, slot_list, slot_count)))
468                         fail("didn't find any tokens\n");
469         } else if (found_slot) {
470                 slot = found_slot; 
471         } else {
472                 fprintf(stderr, "Invalid slot number: %d\n", slot_nr);
473                 PKCS11_release_all_slots(ctx, slot_list, slot_count);
474                 return NULL;
475         }
476         tok = slot->token;
478         if (tok == NULL) {
479                 fprintf(stderr, "Found empty token; \n");
480                 PKCS11_release_all_slots(ctx, slot_list, slot_count);
481                 return NULL;
482         }
484         if (verbose) {
485                 fprintf(stderr, "Found slot:  %s\n", slot->description);
486                 fprintf(stderr, "Found token: %s\n", slot->token->label);
487         }
489         if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
490                 fprintf(stderr, "unable to enumerate certificates\n");
491                 PKCS11_release_all_slots(ctx, slot_list, slot_count);
492                 return NULL;
493         }
495         if (verbose) {
496                 fprintf(stderr, "Found %u cert%s:\n", cert_count,
497                         (cert_count <= 1) ? "" : "s");
498         }
499         if ((s_slot_cert_id && *s_slot_cert_id) && (cert_id_len != 0)) {
500                 for (n = 0; n < cert_count; n++) {
501                         PKCS11_CERT *k = certs + n;
503                         if (cert_id_len != 0 && k->id_len == cert_id_len &&
504                             memcmp(k->id, cert_id, cert_id_len) == 0) {
505                                 selected_cert = k;
506                         }
507                 }
508         } else {
509                 selected_cert = certs;  /* use first */
510         }
512         if (selected_cert == NULL) {
513                 fprintf(stderr, "certificate not found.\n");
514                 PKCS11_release_all_slots(ctx, slot_list, slot_count);
515                 return NULL;
516         }
518         x509 = X509_dup(selected_cert->x509);
519         if (cert_label != NULL)
520                 free(cert_label);
521         return x509;
524 int load_cert_ctrl(ENGINE * e, void *p)
526         struct {
527                 const char *s_slot_cert_id;
528                 X509 *cert;
529         } *parms = p;
531         if (parms->cert != NULL)
532                 return 0;
534         parms->cert = pkcs11_load_cert(e, parms->s_slot_cert_id);
535         if (parms->cert == NULL)
536                 return 0;
538         return 1;
541 static EVP_PKEY *pkcs11_load_key(ENGINE * e, const char *s_slot_key_id,
542                                  UI_METHOD * ui_method, void *callback_data,
543                                  int isPrivate)
545         PKCS11_SLOT *slot_list, *slot;
546         PKCS11_SLOT *found_slot = NULL;
547         PKCS11_TOKEN *tok;
548         PKCS11_KEY *keys, *selected_key = NULL;
549         PKCS11_CERT *certs;
550         EVP_PKEY *pk;
551         unsigned int slot_count, cert_count, key_count, n, m;
552         unsigned char key_id[MAX_VALUE_LEN / 2];
553         size_t key_id_len = sizeof(key_id);
554         char *key_label = NULL;
555         int slot_nr = -1;
556         char flags[64];
558         if (s_slot_key_id && *s_slot_key_id) {
559                 n = parse_slot_id_string(s_slot_key_id, &slot_nr,
560                                          key_id, &key_id_len, &key_label);
562                 if (!n) {
563                         fprintf(stderr,
564                                 "supported formats: <id>, <slot>:<id>, id_<id>, slot_<slot>-id_<id>, label_<label>, slot_<slot>-label_<label>\n");
565                         fprintf(stderr,
566                                 "where <slot> is the slot number as normal integer,\n");
567                         fprintf(stderr,
568                                 "and <id> is the id number as hex string.\n");
569                         fprintf(stderr,
570                                 "and <label> is the textual key label string.\n");
571                         return NULL;
572                 }
573                 if (verbose) {
574                         fprintf(stderr, "Looking in slot %d for key: ",
575                                 slot_nr);
576                         if (key_label == NULL) {
577                                 for (n = 0; n < key_id_len; n++)
578                                         fprintf(stderr, "%02x", key_id[n]);
579                                 fprintf(stderr, "\n");
580                         } else
581                                 fprintf(stderr, "label: %s\n", key_label);
582                 }
583         }
585         if (PKCS11_enumerate_slots(ctx, &slot_list, &slot_count) < 0)
586                 fail("failed to enumerate slots\n");
588         if (verbose) {
589                 fprintf(stderr, "Found %u slot%s\n", slot_count,
590                         (slot_count <= 1) ? "" : "s");
591         }
592         for (n = 0; n < slot_count; n++) {
593                 slot = slot_list + n;
594                 flags[0] = '\0';
595                 if (slot->token) {
596                         if (!slot->token->initialized)
597                                 strcat(flags, "uninitialized, ");
598                         else if (!slot->token->userPinSet)
599                                 strcat(flags, "no pin, ");
600                         if (slot->token->loginRequired)
601                                 strcat(flags, "login, ");
602                         if (slot->token->readOnly)
603                                 strcat(flags, "ro, ");
604                 } else {
605                         strcpy(flags, "no token");
606                 }
607                 if ((m = strlen(flags)) != 0) {
608                         flags[m - 2] = '\0';
609                 }
611                 if (slot_nr != -1 &&
612                         slot_nr == PKCS11_get_slotid_from_slot(slot)) {
613                         found_slot = slot;
614                 }
616                 if (verbose) {
617                         fprintf(stderr, "[%lu] %-25.25s  %-16s",
618                                 PKCS11_get_slotid_from_slot(slot),
619                                 slot->description, flags);
620                         if (slot->token) {
621                                 fprintf(stderr, "  (%s)",
622                                         slot->token->label[0] ?
623                                         slot->token->label : "no label");
624                         }
625                         fprintf(stderr, "\n");
626                 }
627         }
629         if (slot_nr == -1) {
630                 if (!(slot = PKCS11_find_token(ctx, slot_list, slot_count)))
631                         fail("didn't find any tokens\n");
632         } else if (found_slot) {
633                 slot = found_slot;
634         } else {
635                 fprintf(stderr, "Invalid slot number: %d\n", slot_nr);
636                 PKCS11_release_all_slots(ctx, slot_list, slot_count);
637                 return NULL;
638         }
639         tok = slot->token;
641         if (tok == NULL) {
642                 fprintf(stderr, "Found empty token; \n");
643                 PKCS11_release_all_slots(ctx, slot_list, slot_count);
644                 return NULL;
645         }
646 /* Removed for interop with some other pkcs11 libs. */
647 #if 0
648         if (!tok->initialized) {
649                 fprintf(stderr, "Found uninitialized token; \n");
650                 return NULL;
651         }
652 #endif
653         if (isPrivate && !tok->userPinSet && !tok->readOnly) {
654                 fprintf(stderr, "Found slot without user PIN\n");
655                 PKCS11_release_all_slots(ctx, slot_list, slot_count);
656                 return NULL;
657         }
659         if (verbose) {
660                 fprintf(stderr, "Found slot:  %s\n", slot->description);
661                 fprintf(stderr, "Found token: %s\n", slot->token->label);
662         }
664         if (PKCS11_enumerate_certs(tok, &certs, &cert_count))
665                 fail("unable to enumerate certificates\n");
667         if (verbose) {
668                 fprintf(stderr, "Found %u certificate%s:\n", cert_count,
669                         (cert_count <= 1) ? "" : "s");
670                 for (n = 0; n < cert_count; n++) {
671                         PKCS11_CERT *c = certs + n;
672                         char *dn = NULL;
674                         fprintf(stderr, "  %2u    %s", n + 1, c->label);
675                         if (c->x509)
676                                 dn = X509_NAME_oneline(X509_get_subject_name
677                                                        (c->x509), NULL, 0);
678                         if (dn) {
679                                 fprintf(stderr, " (%s)", dn);
680                                 OPENSSL_free(dn);
681                         }
682                         fprintf(stderr, "\n");
683                 }
684         }
686         /* Perform login to the token if required */
687         if (tok->loginRequired) {
688                 /* If the token has a secure login (i.e., an external keypad),
689                    then use a NULL pin. Otherwise, check if a PIN exists. If
690                    not, allocate and obtain a new PIN. */
691                 if (tok->secureLogin) {
692                         /* Free the PIN if it has already been 
693                            assigned (i.e, cached by get_pin) */
694                         if (pin != NULL) {
695                                 OPENSSL_cleanse(pin, pin_length);
696                                 free(pin);
697                                 pin = NULL;
698                                 pin_length = 0;
699                         }
700                 } else if (pin == NULL) {
701                         pin = (char *)calloc(MAX_PIN_LENGTH, sizeof(char));
702                         pin_length = MAX_PIN_LENGTH;
703                         if (pin == NULL) {
704                                 fail("Could not allocate memory for PIN");
705                         }
706                         if (!get_pin(ui_method, callback_data) ) {
707                                 OPENSSL_cleanse(pin, pin_length);
708                                 free(pin);
709                                 pin = NULL;
710                                 pin_length = 0;
711                                 fail("No pin code was entered");
712                         }
713                 }
715                 /* Now login in with the (possibly NULL) pin */
716                 if (PKCS11_login(slot, 0, pin)) {
717                         /* Login failed, so free the PIN if present */
718                         if (pin != NULL) {
719                                 OPENSSL_cleanse(pin, pin_length);
720                                 free(pin);
721                                 pin = NULL;
722                                 pin_length = 0;
723                         }
724                         fail("Login failed\n");
725                 }
726                 /* Login successful, PIN retained in case further logins are 
727                    required. This will occur on subsequent calls to the
728                    pkcs11_load_key function. Subsequent login calls should be
729                    relatively fast (the token should maintain its own login
730                    state), although there may still be a slight performance 
731                    penalty. We could maintain state noting that successful
732                    login has been performed, but this state may not be updated
733                    if the token is removed and reinserted between calls. It
734                    seems safer to retain the PIN and peform a login on each
735                    call to pkcs11_load_key, even if this may not be strictly
736                    necessary. */
737                 /* TODO when does PIN get freed after successful login? */
738                 /* TODO confirm that multiple login attempts do not introduce
739                    significant performance penalties */
741         }
743         /* Make sure there is at least one private key on the token */
744         if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
745                 fail("unable to enumerate keys\n");
746         }
747         if (key_count == 0) {
748                 fail("No keys found.\n");
749         }
751         if (verbose) {
752                 fprintf(stderr, "Found %u key%s:\n", key_count,
753                         (key_count <= 1) ? "" : "s");
754         }
755         if (s_slot_key_id && *s_slot_key_id && (key_id_len != 0 || key_label != NULL)) {
756                 for (n = 0; n < key_count; n++) {
757                         PKCS11_KEY *k = keys + n;
759                         if (verbose) {
760                                 fprintf(stderr, "  %2u %c%c %s\n", n + 1,
761                                         k->isPrivate ? 'P' : ' ',
762                                         k->needLogin ? 'L' : ' ', k->label);
763                         }
764                         if (key_label == NULL) {
765                                 if (key_id_len != 0 && k->id_len == key_id_len
766                                     && memcmp(k->id, key_id, key_id_len) == 0) {
767                                         selected_key = k;
768                                 }
769                         } else {
770                                 if (strcmp(k->label, key_label) == 0) {
771                                         selected_key = k;
772                                 }
773                         }
774                 }
775         } else {
776                 selected_key = keys;    /* use first */
777         }
779         if (selected_key == NULL) {
780                 fprintf(stderr, "key not found.\n");
781                 return NULL;
782         }
784         if (isPrivate) {
785                 pk = PKCS11_get_private_key(selected_key);
786         } else {
787                 /*pk = PKCS11_get_public_key(&keys[0]);
788                    need a get_public_key? */
789                 pk = PKCS11_get_private_key(selected_key);
790         }
791         if (key_label != NULL)
792                 free(key_label);
793         return pk;
796 EVP_PKEY *pkcs11_load_public_key(ENGINE * e, const char *s_key_id,
797                                  UI_METHOD * ui_method, void *callback_data)
799         EVP_PKEY *pk;
801         pk = pkcs11_load_key(e, s_key_id, ui_method, callback_data, 0);
802         if (pk == NULL)
803                 fail("PKCS11_load_public_key returned NULL\n");
804         return pk;
807 EVP_PKEY *pkcs11_load_private_key(ENGINE * e, const char *s_key_id,
808                                   UI_METHOD * ui_method, void *callback_data)
810         EVP_PKEY *pk;
812         pk = pkcs11_load_key(e, s_key_id, ui_method, callback_data, 1);
813         if (pk == NULL)
814                 fail("PKCS11_get_private_key returned NULL\n");
815         return pk;