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)
100 {
101 verbose++;
102 return 1;
103 }
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)
109 {
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;
146 }
148 int set_init_args(const char *init_args_orig)
149 {
150 init_args = init_args_orig ? strdup(init_args_orig) : NULL;
151 return 1;
152 }
154 int pkcs11_finish(ENGINE * engine)
155 {
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;
168 }
170 int pkcs11_init(ENGINE * engine)
171 {
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;
182 }
184 int pkcs11_rsa_finish(RSA * rsa)
185 {
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;
198 }
200 static int hex_to_bin(const char *in, unsigned char *out, size_t * outlen)
201 {
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;
246 }
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)
253 {
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;
374 }
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)
382 {
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;
522 }
524 int load_cert_ctrl(ENGINE * e, void *p)
525 {
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;
539 }
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)
544 {
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;
794 }
796 EVP_PKEY *pkcs11_load_public_key(ENGINE * e, const char *s_key_id,
797 UI_METHOD * ui_method, void *callback_data)
798 {
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;
805 }
807 EVP_PKEY *pkcs11_load_private_key(ENGINE * e, const char *s_key_id,
808 UI_METHOD * ui_method, void *callback_data)
809 {
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;
816 }