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