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