ks_p11.c revision 1.1.1.2.12.1 1 /* $NetBSD: ks_p11.c,v 1.1.1.2.12.1 2017/08/20 05:44:20 snj Exp $ */
2
3 /*
4 * Copyright (c) 2004 - 2008 Kungliga Tekniska Hgskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "hx_locl.h"
37 #ifdef HAVE_DLFCN_H
38 #include <dlfcn.h>
39 #endif
40
41 #ifdef HAVE_DLOPEN
42
43 #include "ref/pkcs11.h"
44
45 struct p11_slot {
46 int flags;
47 #define P11_SESSION 1
48 #define P11_SESSION_IN_USE 2
49 #define P11_LOGIN_REQ 4
50 #define P11_LOGIN_DONE 8
51 #define P11_TOKEN_PRESENT 16
52 CK_SESSION_HANDLE session;
53 CK_SLOT_ID id;
54 CK_BBOOL token;
55 char *name;
56 hx509_certs certs;
57 char *pin;
58 struct {
59 CK_MECHANISM_TYPE_PTR list;
60 CK_ULONG num;
61 CK_MECHANISM_INFO_PTR *infos;
62 } mechs;
63 };
64
65 struct p11_module {
66 void *dl_handle;
67 CK_FUNCTION_LIST_PTR funcs;
68 CK_ULONG num_slots;
69 unsigned int ref;
70 unsigned int selected_slot;
71 struct p11_slot *slot;
72 };
73
74 #define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args
75
76 static int p11_get_session(hx509_context,
77 struct p11_module *,
78 struct p11_slot *,
79 hx509_lock,
80 CK_SESSION_HANDLE *);
81 static int p11_put_session(struct p11_module *,
82 struct p11_slot *,
83 CK_SESSION_HANDLE);
84 static void p11_release_module(struct p11_module *);
85
86 static int p11_list_keys(hx509_context,
87 struct p11_module *,
88 struct p11_slot *,
89 CK_SESSION_HANDLE,
90 hx509_lock,
91 hx509_certs *);
92
93 /*
94 *
95 */
96
97 struct p11_rsa {
98 struct p11_module *p;
99 struct p11_slot *slot;
100 CK_OBJECT_HANDLE private_key;
101 CK_OBJECT_HANDLE public_key;
102 };
103
104 static int
105 p11_rsa_public_encrypt(int flen,
106 const unsigned char *from,
107 unsigned char *to,
108 RSA *rsa,
109 int padding)
110 {
111 return -1;
112 }
113
114 static int
115 p11_rsa_public_decrypt(int flen,
116 const unsigned char *from,
117 unsigned char *to,
118 RSA *rsa,
119 int padding)
120 {
121 return -1;
122 }
123
124
125 static int
126 p11_rsa_private_encrypt(int flen,
127 const unsigned char *from,
128 unsigned char *to,
129 RSA *rsa,
130 int padding)
131 {
132 struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
133 CK_OBJECT_HANDLE key = p11rsa->private_key;
134 CK_SESSION_HANDLE session;
135 CK_MECHANISM mechanism;
136 CK_ULONG ck_sigsize;
137 int ret;
138
139 if (padding != RSA_PKCS1_PADDING)
140 return -1;
141
142 memset(&mechanism, 0, sizeof(mechanism));
143 mechanism.mechanism = CKM_RSA_PKCS;
144
145 ck_sigsize = RSA_size(rsa);
146
147 ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
148 if (ret)
149 return -1;
150
151 ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));
152 if (ret != CKR_OK) {
153 p11_put_session(p11rsa->p, p11rsa->slot, session);
154 return -1;
155 }
156
157 ret = P11FUNC(p11rsa->p, Sign,
158 (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));
159 p11_put_session(p11rsa->p, p11rsa->slot, session);
160 if (ret != CKR_OK)
161 return -1;
162
163 return ck_sigsize;
164 }
165
166 static int
167 p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
168 RSA * rsa, int padding)
169 {
170 struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
171 CK_OBJECT_HANDLE key = p11rsa->private_key;
172 CK_SESSION_HANDLE session;
173 CK_MECHANISM mechanism;
174 CK_ULONG ck_sigsize;
175 int ret;
176
177 if (padding != RSA_PKCS1_PADDING)
178 return -1;
179
180 memset(&mechanism, 0, sizeof(mechanism));
181 mechanism.mechanism = CKM_RSA_PKCS;
182
183 ck_sigsize = RSA_size(rsa);
184
185 ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
186 if (ret)
187 return -1;
188
189 ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));
190 if (ret != CKR_OK) {
191 p11_put_session(p11rsa->p, p11rsa->slot, session);
192 return -1;
193 }
194
195 ret = P11FUNC(p11rsa->p, Decrypt,
196 (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize));
197 p11_put_session(p11rsa->p, p11rsa->slot, session);
198 if (ret != CKR_OK)
199 return -1;
200
201 return ck_sigsize;
202 }
203
204 static int
205 p11_rsa_init(RSA *rsa)
206 {
207 return 1;
208 }
209
210 static int
211 p11_rsa_finish(RSA *rsa)
212 {
213 struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
214 p11_release_module(p11rsa->p);
215 free(p11rsa);
216 return 1;
217 }
218
219 static const RSA_METHOD p11_rsa_pkcs1_method = {
220 "hx509 PKCS11 PKCS#1 RSA",
221 p11_rsa_public_encrypt,
222 p11_rsa_public_decrypt,
223 p11_rsa_private_encrypt,
224 p11_rsa_private_decrypt,
225 NULL,
226 NULL,
227 p11_rsa_init,
228 p11_rsa_finish,
229 0,
230 NULL,
231 NULL,
232 NULL,
233 NULL
234 };
235
236 /*
237 *
238 */
239
240 static int
241 p11_mech_info(hx509_context context,
242 struct p11_module *p,
243 struct p11_slot *slot,
244 int num)
245 {
246 CK_ULONG i;
247 int ret;
248
249 ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));
250 if (ret) {
251 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
252 "Failed to get mech list count for slot %d",
253 num);
254 return HX509_PKCS11_NO_MECH;
255 }
256 if (i == 0) {
257 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
258 "no mech supported for slot %d", num);
259 return HX509_PKCS11_NO_MECH;
260 }
261 slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));
262 if (slot->mechs.list == NULL) {
263 hx509_set_error_string(context, 0, ENOMEM,
264 "out of memory");
265 return ENOMEM;
266 }
267 slot->mechs.num = i;
268 ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));
269 if (ret) {
270 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
271 "Failed to get mech list for slot %d",
272 num);
273 return HX509_PKCS11_NO_MECH;
274 }
275 assert(i == slot->mechs.num);
276
277 slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));
278 if (slot->mechs.list == NULL) {
279 hx509_set_error_string(context, 0, ENOMEM,
280 "out of memory");
281 return ENOMEM;
282 }
283
284 for (i = 0; i < slot->mechs.num; i++) {
285 slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));
286 if (slot->mechs.infos[i] == NULL) {
287 hx509_set_error_string(context, 0, ENOMEM,
288 "out of memory");
289 return ENOMEM;
290 }
291 ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],
292 slot->mechs.infos[i]));
293 if (ret) {
294 hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
295 "Failed to get mech info for slot %d",
296 num);
297 return HX509_PKCS11_NO_MECH;
298 }
299 }
300
301 return 0;
302 }
303
304 static int
305 p11_init_slot(hx509_context context,
306 struct p11_module *p,
307 hx509_lock lock,
308 CK_SLOT_ID id,
309 int num,
310 struct p11_slot *slot)
311 {
312 CK_SESSION_HANDLE session;
313 CK_SLOT_INFO slot_info;
314 CK_TOKEN_INFO token_info;
315 size_t i;
316 int ret;
317
318 slot->certs = NULL;
319 slot->id = id;
320
321 ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info));
322 if (ret) {
323 hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
324 "Failed to init PKCS11 slot %d",
325 num);
326 return HX509_PKCS11_TOKEN_CONFUSED;
327 }
328
329 for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) {
330 char c = slot_info.slotDescription[i];
331 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0')
332 continue;
333 i++;
334 break;
335 }
336
337 ret = asprintf(&slot->name, "%.*s", (int)i,
338 slot_info.slotDescription);
339 if (ret == -1)
340 return ENOMEM;
341
342 if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0)
343 return 0;
344
345 ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info));
346 if (ret) {
347 hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN,
348 "Failed to init PKCS11 slot %d "
349 "with error 0x%08x",
350 num, ret);
351 return HX509_PKCS11_NO_TOKEN;
352 }
353 slot->flags |= P11_TOKEN_PRESENT;
354
355 if (token_info.flags & CKF_LOGIN_REQUIRED)
356 slot->flags |= P11_LOGIN_REQ;
357
358 ret = p11_get_session(context, p, slot, lock, &session);
359 if (ret)
360 return ret;
361
362 ret = p11_mech_info(context, p, slot, num);
363 if (ret)
364 goto out;
365
366 ret = p11_list_keys(context, p, slot, session, lock, &slot->certs);
367 out:
368 p11_put_session(p, slot, session);
369
370 return ret;
371 }
372
373 static int
374 p11_get_session(hx509_context context,
375 struct p11_module *p,
376 struct p11_slot *slot,
377 hx509_lock lock,
378 CK_SESSION_HANDLE *psession)
379 {
380 CK_RV ret;
381
382 if (slot->flags & P11_SESSION_IN_USE)
383 _hx509_abort("slot already in session");
384
385 if (slot->flags & P11_SESSION) {
386 slot->flags |= P11_SESSION_IN_USE;
387 *psession = slot->session;
388 return 0;
389 }
390
391 ret = P11FUNC(p, OpenSession, (slot->id,
392 CKF_SERIAL_SESSION,
393 NULL,
394 NULL,
395 &slot->session));
396 if (ret != CKR_OK) {
397 if (context)
398 hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION,
399 "Failed to OpenSession for slot id %d "
400 "with error: 0x%08x",
401 (int)slot->id, ret);
402 return HX509_PKCS11_OPEN_SESSION;
403 }
404
405 slot->flags |= P11_SESSION;
406
407 /*
408 * If we have have to login, and haven't tried before and have a
409 * prompter or known to work pin code.
410 *
411 * This code is very conversative and only uses the prompter in
412 * the hx509_lock, the reason is that it's bad to try many
413 * passwords on a pkcs11 token, it might lock up and have to be
414 * unlocked by a administrator.
415 *
416 * XXX try harder to not use pin several times on the same card.
417 */
418
419 if ( (slot->flags & P11_LOGIN_REQ)
420 && (slot->flags & P11_LOGIN_DONE) == 0
421 && (lock || slot->pin))
422 {
423 hx509_prompt prompt;
424 char pin[20];
425 char *str;
426
427 if (slot->pin == NULL) {
428
429 memset(&prompt, 0, sizeof(prompt));
430
431 ret = asprintf(&str, "PIN code for %s: ", slot->name);
432 if (ret == -1 || str == NULL) {
433 if (context)
434 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
435 return ENOMEM;
436 }
437 prompt.prompt = str;
438 prompt.type = HX509_PROMPT_TYPE_PASSWORD;
439 prompt.reply.data = pin;
440 prompt.reply.length = sizeof(pin);
441
442 ret = hx509_lock_prompt(lock, &prompt);
443 if (ret) {
444 free(str);
445 if (context)
446 hx509_set_error_string(context, 0, ret,
447 "Failed to get pin code for slot "
448 "id %d with error: %d",
449 (int)slot->id, ret);
450 return ret;
451 }
452 free(str);
453 } else {
454 strlcpy(pin, slot->pin, sizeof(pin));
455 }
456
457 ret = P11FUNC(p, Login, (slot->session, CKU_USER,
458 (unsigned char*)pin, strlen(pin)));
459 if (ret != CKR_OK) {
460 if (context)
461 hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN,
462 "Failed to login on slot id %d "
463 "with error: 0x%08x",
464 (int)slot->id, ret);
465 switch(ret) {
466 case CKR_PIN_LOCKED:
467 return HX509_PKCS11_PIN_LOCKED;
468 case CKR_PIN_EXPIRED:
469 return HX509_PKCS11_PIN_EXPIRED;
470 case CKR_PIN_INCORRECT:
471 return HX509_PKCS11_PIN_INCORRECT;
472 case CKR_USER_PIN_NOT_INITIALIZED:
473 return HX509_PKCS11_PIN_NOT_INITIALIZED;
474 default:
475 return HX509_PKCS11_LOGIN;
476 }
477 } else
478 slot->flags |= P11_LOGIN_DONE;
479
480 if (slot->pin == NULL) {
481 slot->pin = strdup(pin);
482 if (slot->pin == NULL) {
483 if (context)
484 hx509_set_error_string(context, 0, ENOMEM,
485 "out of memory");
486 return ENOMEM;
487 }
488 }
489 } else
490 slot->flags |= P11_LOGIN_DONE;
491
492 slot->flags |= P11_SESSION_IN_USE;
493
494 *psession = slot->session;
495
496 return 0;
497 }
498
499 static int
500 p11_put_session(struct p11_module *p,
501 struct p11_slot *slot,
502 CK_SESSION_HANDLE session)
503 {
504 if ((slot->flags & P11_SESSION_IN_USE) == 0)
505 _hx509_abort("slot not in session");
506 slot->flags &= ~P11_SESSION_IN_USE;
507
508 return 0;
509 }
510
511 static int
512 iterate_entries(hx509_context context,
513 struct p11_module *p, struct p11_slot *slot,
514 CK_SESSION_HANDLE session,
515 CK_ATTRIBUTE *search_data, int num_search_data,
516 CK_ATTRIBUTE *query, int num_query,
517 int (*func)(hx509_context,
518 struct p11_module *, struct p11_slot *,
519 CK_SESSION_HANDLE session,
520 CK_OBJECT_HANDLE object,
521 void *, CK_ATTRIBUTE *, int), void *ptr)
522 {
523 CK_OBJECT_HANDLE object;
524 CK_ULONG object_count;
525 int ret, ret2, i;
526
527 ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data));
528 if (ret != CKR_OK) {
529 return -1;
530 }
531 while (1) {
532 ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count));
533 if (ret != CKR_OK) {
534 return -1;
535 }
536 if (object_count == 0)
537 break;
538
539 for (i = 0; i < num_query; i++)
540 query[i].pValue = NULL;
541
542 ret = P11FUNC(p, GetAttributeValue,
543 (session, object, query, num_query));
544 if (ret != CKR_OK) {
545 return -1;
546 }
547 for (i = 0; i < num_query; i++) {
548 query[i].pValue = malloc(query[i].ulValueLen);
549 if (query[i].pValue == NULL) {
550 ret = ENOMEM;
551 goto out;
552 }
553 }
554 ret = P11FUNC(p, GetAttributeValue,
555 (session, object, query, num_query));
556 if (ret != CKR_OK) {
557 ret = -1;
558 goto out;
559 }
560
561 ret = (*func)(context, p, slot, session, object, ptr, query, num_query);
562 if (ret)
563 goto out;
564
565 for (i = 0; i < num_query; i++) {
566 if (query[i].pValue)
567 free(query[i].pValue);
568 query[i].pValue = NULL;
569 }
570 }
571 out:
572
573 for (i = 0; i < num_query; i++) {
574 if (query[i].pValue)
575 free(query[i].pValue);
576 query[i].pValue = NULL;
577 }
578
579 ret2 = P11FUNC(p, FindObjectsFinal, (session));
580 if (ret2 != CKR_OK) {
581 return ret2;
582 }
583
584 return ret;
585 }
586
587 static BIGNUM *
588 getattr_bn(struct p11_module *p,
589 struct p11_slot *slot,
590 CK_SESSION_HANDLE session,
591 CK_OBJECT_HANDLE object,
592 unsigned int type)
593 {
594 CK_ATTRIBUTE query;
595 BIGNUM *bn;
596 int ret;
597
598 query.type = type;
599 query.pValue = NULL;
600 query.ulValueLen = 0;
601
602 ret = P11FUNC(p, GetAttributeValue,
603 (session, object, &query, 1));
604 if (ret != CKR_OK)
605 return NULL;
606
607 query.pValue = malloc(query.ulValueLen);
608
609 ret = P11FUNC(p, GetAttributeValue,
610 (session, object, &query, 1));
611 if (ret != CKR_OK) {
612 free(query.pValue);
613 return NULL;
614 }
615 bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);
616 free(query.pValue);
617
618 return bn;
619 }
620
621 static int
622 collect_private_key(hx509_context context,
623 struct p11_module *p, struct p11_slot *slot,
624 CK_SESSION_HANDLE session,
625 CK_OBJECT_HANDLE object,
626 void *ptr, CK_ATTRIBUTE *query, int num_query)
627 {
628 struct hx509_collector *collector = ptr;
629 hx509_private_key key;
630 heim_octet_string localKeyId;
631 int ret;
632 RSA *rsa;
633 struct p11_rsa *p11rsa;
634
635 localKeyId.data = query[0].pValue;
636 localKeyId.length = query[0].ulValueLen;
637
638 ret = hx509_private_key_init(&key, NULL, NULL);
639 if (ret)
640 return ret;
641
642 rsa = RSA_new();
643 if (rsa == NULL)
644 _hx509_abort("out of memory");
645
646 /*
647 * The exponent and modulus should always be present according to
648 * the pkcs11 specification, but some smartcards leaves it out,
649 * let ignore any failure to fetch it.
650 */
651 rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS);
652 rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);
653
654 p11rsa = calloc(1, sizeof(*p11rsa));
655 if (p11rsa == NULL)
656 _hx509_abort("out of memory");
657
658 p11rsa->p = p;
659 p11rsa->slot = slot;
660 p11rsa->private_key = object;
661
662 if (p->ref == 0)
663 _hx509_abort("pkcs11 ref == 0 on alloc");
664 p->ref++;
665 if (p->ref == UINT_MAX)
666 _hx509_abort("pkcs11 ref == UINT_MAX on alloc");
667
668 RSA_set_method(rsa, &p11_rsa_pkcs1_method);
669 ret = RSA_set_app_data(rsa, p11rsa);
670 if (ret != 1)
671 _hx509_abort("RSA_set_app_data");
672
673 hx509_private_key_assign_rsa(key, rsa);
674
675 ret = _hx509_collector_private_key_add(context,
676 collector,
677 hx509_signature_rsa(),
678 key,
679 NULL,
680 &localKeyId);
681
682 if (ret) {
683 hx509_private_key_free(&key);
684 return ret;
685 }
686 return 0;
687 }
688
689 static void
690 p11_cert_release(hx509_cert cert, void *ctx)
691 {
692 struct p11_module *p = ctx;
693 p11_release_module(p);
694 }
695
696
697 static int
698 collect_cert(hx509_context context,
699 struct p11_module *p, struct p11_slot *slot,
700 CK_SESSION_HANDLE session,
701 CK_OBJECT_HANDLE object,
702 void *ptr, CK_ATTRIBUTE *query, int num_query)
703 {
704 struct hx509_collector *collector = ptr;
705 heim_error_t error = NULL;
706 hx509_cert cert;
707 int ret;
708
709 if ((CK_LONG)query[0].ulValueLen == -1 ||
710 (CK_LONG)query[1].ulValueLen == -1)
711 {
712 return 0;
713 }
714
715 cert = hx509_cert_init_data(context, query[1].pValue,
716 query[1].ulValueLen, &error);
717 if (cert == NULL) {
718 ret = heim_error_get_code(error);
719 heim_release(error);
720 return ret;
721 }
722
723 if (p->ref == 0)
724 _hx509_abort("pkcs11 ref == 0 on alloc");
725 p->ref++;
726 if (p->ref == UINT_MAX)
727 _hx509_abort("pkcs11 ref to high");
728
729 _hx509_cert_set_release(cert, p11_cert_release, p);
730
731 {
732 heim_octet_string data;
733
734 data.data = query[0].pValue;
735 data.length = query[0].ulValueLen;
736
737 _hx509_set_cert_attribute(context,
738 cert,
739 &asn1_oid_id_pkcs_9_at_localKeyId,
740 &data);
741 }
742
743 if ((CK_LONG)query[2].ulValueLen != -1) {
744 char *str;
745
746 ret = asprintf(&str, "%.*s",
747 (int)query[2].ulValueLen, (char *)query[2].pValue);
748 if (ret != -1 && str) {
749 hx509_cert_set_friendly_name(cert, str);
750 free(str);
751 }
752 }
753
754 ret = _hx509_collector_certs_add(context, collector, cert);
755 hx509_cert_free(cert);
756
757 return ret;
758 }
759
760
761 static int
762 p11_list_keys(hx509_context context,
763 struct p11_module *p,
764 struct p11_slot *slot,
765 CK_SESSION_HANDLE session,
766 hx509_lock lock,
767 hx509_certs *certs)
768 {
769 struct hx509_collector *collector;
770 CK_OBJECT_CLASS key_class;
771 CK_ATTRIBUTE search_data[] = {
772 {CKA_CLASS, NULL, 0},
773 };
774 CK_ATTRIBUTE query_data[3] = {
775 {CKA_ID, NULL, 0},
776 {CKA_VALUE, NULL, 0},
777 {CKA_LABEL, NULL, 0}
778 };
779 int ret;
780
781 search_data[0].pValue = &key_class;
782 search_data[0].ulValueLen = sizeof(key_class);
783
784 if (lock == NULL)
785 lock = _hx509_empty_lock;
786
787 ret = _hx509_collector_alloc(context, lock, &collector);
788 if (ret)
789 return ret;
790
791 key_class = CKO_PRIVATE_KEY;
792 ret = iterate_entries(context, p, slot, session,
793 search_data, 1,
794 query_data, 1,
795 collect_private_key, collector);
796 if (ret)
797 goto out;
798
799 key_class = CKO_CERTIFICATE;
800 ret = iterate_entries(context, p, slot, session,
801 search_data, 1,
802 query_data, 3,
803 collect_cert, collector);
804 if (ret)
805 goto out;
806
807 ret = _hx509_collector_collect_certs(context, collector, &slot->certs);
808
809 out:
810 _hx509_collector_free(collector);
811
812 return ret;
813 }
814
815
816 static int
817 p11_init(hx509_context context,
818 hx509_certs certs, void **data, int flags,
819 const char *residue, hx509_lock lock)
820 {
821 CK_C_GetFunctionList getFuncs;
822 struct p11_module *p;
823 char *list, *str;
824 int ret;
825
826 *data = NULL;
827
828 list = strdup(residue);
829 if (list == NULL)
830 return ENOMEM;
831
832 p = calloc(1, sizeof(*p));
833 if (p == NULL) {
834 free(list);
835 return ENOMEM;
836 }
837
838 p->ref = 1;
839 p->selected_slot = 0;
840
841 str = strchr(list, ',');
842 if (str)
843 *str++ = '\0';
844 while (str) {
845 char *strnext;
846 strnext = strchr(str, ',');
847 if (strnext)
848 *strnext++ = '\0';
849 if (strncasecmp(str, "slot=", 5) == 0)
850 p->selected_slot = atoi(str + 5);
851 str = strnext;
852 }
853
854 p->dl_handle = dlopen(list, RTLD_NOW);
855 if (p->dl_handle == NULL) {
856 ret = HX509_PKCS11_LOAD;
857 hx509_set_error_string(context, 0, ret,
858 "Failed to open %s: %s", list, dlerror());
859 goto out;
860 }
861
862 getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList");
863 if (getFuncs == NULL) {
864 ret = HX509_PKCS11_LOAD;
865 hx509_set_error_string(context, 0, ret,
866 "C_GetFunctionList missing in %s: %s",
867 list, dlerror());
868 goto out;
869 }
870
871 ret = (*getFuncs)(&p->funcs);
872 if (ret) {
873 ret = HX509_PKCS11_LOAD;
874 hx509_set_error_string(context, 0, ret,
875 "C_GetFunctionList failed in %s", list);
876 goto out;
877 }
878
879 ret = P11FUNC(p, Initialize, (NULL_PTR));
880 if (ret != CKR_OK) {
881 ret = HX509_PKCS11_TOKEN_CONFUSED;
882 hx509_set_error_string(context, 0, ret,
883 "Failed initialize the PKCS11 module");
884 goto out;
885 }
886
887 ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));
888 if (ret) {
889 ret = HX509_PKCS11_TOKEN_CONFUSED;
890 hx509_set_error_string(context, 0, ret,
891 "Failed to get number of PKCS11 slots");
892 goto out;
893 }
894
895 if (p->num_slots == 0) {
896 ret = HX509_PKCS11_NO_SLOT;
897 hx509_set_error_string(context, 0, ret,
898 "Selected PKCS11 module have no slots");
899 goto out;
900 }
901
902
903 {
904 CK_SLOT_ID_PTR slot_ids;
905 int num_tokens = 0;
906 size_t i;
907
908 slot_ids = malloc(p->num_slots * sizeof(*slot_ids));
909 if (slot_ids == NULL) {
910 hx509_clear_error_string(context);
911 ret = ENOMEM;
912 goto out;
913 }
914
915 ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));
916 if (ret) {
917 free(slot_ids);
918 hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
919 "Failed getting slot-list from "
920 "PKCS11 module");
921 ret = HX509_PKCS11_TOKEN_CONFUSED;
922 goto out;
923 }
924
925 p->slot = calloc(p->num_slots, sizeof(p->slot[0]));
926 if (p->slot == NULL) {
927 free(slot_ids);
928 hx509_set_error_string(context, 0, ENOMEM,
929 "Failed to get memory for slot-list");
930 ret = ENOMEM;
931 goto out;
932 }
933
934 for (i = 0; i < p->num_slots; i++) {
935 if ((p->selected_slot != 0) && (slot_ids[i] != (p->selected_slot - 1)))
936 continue;
937 ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);
938 if (!ret) {
939 if (p->slot[i].flags & P11_TOKEN_PRESENT)
940 num_tokens++;
941 }
942 }
943 free(slot_ids);
944 if (ret)
945 goto out;
946 if (num_tokens == 0) {
947 ret = HX509_PKCS11_NO_TOKEN;
948 goto out;
949 }
950 }
951
952 free(list);
953
954 *data = p;
955
956 return 0;
957 out:
958 if (list)
959 free(list);
960 p11_release_module(p);
961 return ret;
962 }
963
964 static void
965 p11_release_module(struct p11_module *p)
966 {
967 size_t i;
968
969 if (p->ref == 0)
970 _hx509_abort("pkcs11 ref to low");
971 if (--p->ref > 0)
972 return;
973
974 for (i = 0; i < p->num_slots; i++) {
975 if (p->slot[i].flags & P11_SESSION_IN_USE)
976 _hx509_abort("pkcs11 module release while session in use");
977 if (p->slot[i].flags & P11_SESSION) {
978 P11FUNC(p, CloseSession, (p->slot[i].session));
979 }
980
981 if (p->slot[i].name)
982 free(p->slot[i].name);
983 if (p->slot[i].pin) {
984 memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));
985 free(p->slot[i].pin);
986 }
987 if (p->slot[i].mechs.num) {
988 free(p->slot[i].mechs.list);
989
990 if (p->slot[i].mechs.infos) {
991 size_t j;
992
993 for (j = 0 ; j < p->slot[i].mechs.num ; j++)
994 free(p->slot[i].mechs.infos[j]);
995 free(p->slot[i].mechs.infos);
996 }
997 }
998 }
999 free(p->slot);
1000
1001 if (p->funcs)
1002 P11FUNC(p, Finalize, (NULL));
1003
1004 if (p->dl_handle)
1005 dlclose(p->dl_handle);
1006
1007 memset(p, 0, sizeof(*p));
1008 free(p);
1009 }
1010
1011 static int
1012 p11_free(hx509_certs certs, void *data)
1013 {
1014 struct p11_module *p = data;
1015 size_t i;
1016
1017 for (i = 0; i < p->num_slots; i++) {
1018 if (p->slot[i].certs)
1019 hx509_certs_free(&p->slot[i].certs);
1020 }
1021 p11_release_module(p);
1022 return 0;
1023 }
1024
1025 struct p11_cursor {
1026 hx509_certs certs;
1027 void *cursor;
1028 };
1029
1030 static int
1031 p11_iter_start(hx509_context context,
1032 hx509_certs certs, void *data, void **cursor)
1033 {
1034 struct p11_module *p = data;
1035 struct p11_cursor *c;
1036 int ret;
1037 size_t i;
1038
1039 c = malloc(sizeof(*c));
1040 if (c == NULL) {
1041 hx509_clear_error_string(context);
1042 return ENOMEM;
1043 }
1044 ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);
1045 if (ret) {
1046 free(c);
1047 return ret;
1048 }
1049
1050 for (i = 0 ; i < p->num_slots; i++) {
1051 if (p->slot[i].certs == NULL)
1052 continue;
1053 ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);
1054 if (ret) {
1055 hx509_certs_free(&c->certs);
1056 free(c);
1057 return ret;
1058 }
1059 }
1060
1061 ret = hx509_certs_start_seq(context, c->certs, &c->cursor);
1062 if (ret) {
1063 hx509_certs_free(&c->certs);
1064 free(c);
1065 return 0;
1066 }
1067 *cursor = c;
1068
1069 return 0;
1070 }
1071
1072 static int
1073 p11_iter(hx509_context context,
1074 hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
1075 {
1076 struct p11_cursor *c = cursor;
1077 return hx509_certs_next_cert(context, c->certs, c->cursor, cert);
1078 }
1079
1080 static int
1081 p11_iter_end(hx509_context context,
1082 hx509_certs certs, void *data, void *cursor)
1083 {
1084 struct p11_cursor *c = cursor;
1085 int ret;
1086 ret = hx509_certs_end_seq(context, c->certs, c->cursor);
1087 hx509_certs_free(&c->certs);
1088 free(c);
1089 return ret;
1090 }
1091
1092 #define MECHFLAG(x) { "unknown-flag-" #x, x }
1093 static struct units mechflags[] = {
1094 MECHFLAG(0x80000000),
1095 MECHFLAG(0x40000000),
1096 MECHFLAG(0x20000000),
1097 MECHFLAG(0x10000000),
1098 MECHFLAG(0x08000000),
1099 MECHFLAG(0x04000000),
1100 {"ec-compress", 0x2000000 },
1101 {"ec-uncompress", 0x1000000 },
1102 {"ec-namedcurve", 0x0800000 },
1103 {"ec-ecparameters", 0x0400000 },
1104 {"ec-f-2m", 0x0200000 },
1105 {"ec-f-p", 0x0100000 },
1106 {"derive", 0x0080000 },
1107 {"unwrap", 0x0040000 },
1108 {"wrap", 0x0020000 },
1109 {"genereate-key-pair", 0x0010000 },
1110 {"generate", 0x0008000 },
1111 {"verify-recover", 0x0004000 },
1112 {"verify", 0x0002000 },
1113 {"sign-recover", 0x0001000 },
1114 {"sign", 0x0000800 },
1115 {"digest", 0x0000400 },
1116 {"decrypt", 0x0000200 },
1117 {"encrypt", 0x0000100 },
1118 MECHFLAG(0x00080),
1119 MECHFLAG(0x00040),
1120 MECHFLAG(0x00020),
1121 MECHFLAG(0x00010),
1122 MECHFLAG(0x00008),
1123 MECHFLAG(0x00004),
1124 MECHFLAG(0x00002),
1125 {"hw", 0x0000001 },
1126 { NULL, 0x0000000 }
1127 };
1128 #undef MECHFLAG
1129
1130 static int
1131 p11_printinfo(hx509_context context,
1132 hx509_certs certs,
1133 void *data,
1134 int (*func)(void *, const char *),
1135 void *ctx)
1136 {
1137 struct p11_module *p = data;
1138 size_t i, j;
1139
1140 _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s",
1141 p->num_slots, p->num_slots > 1 ? "s" : "");
1142
1143 for (i = 0; i < p->num_slots; i++) {
1144 struct p11_slot *s = &p->slot[i];
1145
1146 _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x",
1147 i, (int)s->id, s->name, s->flags);
1148
1149 _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu",
1150 (unsigned long)s->mechs.num);
1151 for (j = 0; j < s->mechs.num; j++) {
1152 const char *mechname = "unknown";
1153 char flags[256], unknownname[40];
1154 #define MECHNAME(s,n) case s: mechname = n; break
1155 switch(s->mechs.list[j]) {
1156 MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen");
1157 MECHNAME(CKM_RSA_PKCS, "rsa-pkcs");
1158 MECHNAME(CKM_RSA_X_509, "rsa-x-509");
1159 MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs");
1160 MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs");
1161 MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs");
1162 MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs");
1163 MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs");
1164 MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs");
1165 MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep");
1166 MECHNAME(CKM_SHA512_HMAC, "sha512-hmac");
1167 MECHNAME(CKM_SHA512, "sha512");
1168 MECHNAME(CKM_SHA384_HMAC, "sha384-hmac");
1169 MECHNAME(CKM_SHA384, "sha384");
1170 MECHNAME(CKM_SHA256_HMAC, "sha256-hmac");
1171 MECHNAME(CKM_SHA256, "sha256");
1172 MECHNAME(CKM_SHA_1, "sha1");
1173 MECHNAME(CKM_MD5, "md5");
1174 MECHNAME(CKM_RIPEMD160, "ripemd-160");
1175 MECHNAME(CKM_DES_ECB, "des-ecb");
1176 MECHNAME(CKM_DES_CBC, "des-cbc");
1177 MECHNAME(CKM_AES_ECB, "aes-ecb");
1178 MECHNAME(CKM_AES_CBC, "aes-cbc");
1179 MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen");
1180 default:
1181 snprintf(unknownname, sizeof(unknownname),
1182 "unknown-mech-%lu",
1183 (unsigned long)s->mechs.list[j]);
1184 mechname = unknownname;
1185 break;
1186 }
1187 #undef MECHNAME
1188 unparse_flags(s->mechs.infos[j]->flags, mechflags,
1189 flags, sizeof(flags));
1190
1191 _hx509_pi_printf(func, ctx, " %s: %s", mechname, flags);
1192 }
1193 }
1194
1195 return 0;
1196 }
1197
1198 static struct hx509_keyset_ops keyset_pkcs11 = {
1199 "PKCS11",
1200 0,
1201 p11_init,
1202 NULL,
1203 p11_free,
1204 NULL,
1205 NULL,
1206 p11_iter_start,
1207 p11_iter,
1208 p11_iter_end,
1209 p11_printinfo,
1210 NULL,
1211 NULL
1212 };
1213
1214 #endif /* HAVE_DLOPEN */
1215
1216 void
1217 _hx509_ks_pkcs11_register(hx509_context context)
1218 {
1219 #ifdef HAVE_DLOPEN
1220 _hx509_ks_register(context, &keyset_pkcs11);
1221 #endif
1222 }
1223