1/*
2 *  OpenVPN -- An application to securely tunnel IP networks
3 *             over a single TCP/UDP port, with support for SSL/TLS-based
4 *             session authentication and key exchange,
5 *             packet encryption, packet authentication, and
6 *             packet compression.
7 *
8 *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 2
12 *  as published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program (see the file COPYING included with this
21 *  distribution); if not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#elif defined(_MSC_VER)
28#include "config-msvc.h"
29#endif
30
31#include "syshead.h"
32
33#if defined(ENABLE_PKCS11)
34
35#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
36#include "basic.h"
37#include "error.h"
38#include "manage.h"
39#include "base64.h"
40#include "pkcs11.h"
41#include "misc.h"
42#include "otime.h"
43#include "console.h"
44#include "pkcs11_backend.h"
45
46static
47time_t
48__mytime (void) {
49	return openvpn_time (NULL);
50}
51
52#if !defined(_WIN32)
53static
54int
55__mygettimeofday (struct timeval *tv) {
56	return gettimeofday (tv, NULL);
57}
58#endif
59
60static
61void
62__mysleep (const unsigned long usec) {
63#if defined(_WIN32)
64	Sleep (usec/1000);
65#else
66	usleep (usec);
67#endif
68}
69
70
71static pkcs11h_engine_system_t s_pkcs11h_sys_engine = {
72	malloc,
73	free,
74	__mytime,
75	__mysleep,
76#if defined(_WIN32)
77	NULL
78#else
79	__mygettimeofday
80#endif
81};
82
83static
84unsigned
85_pkcs11_msg_pkcs112openvpn (
86	const unsigned flags
87) {
88	unsigned openvpn_flags;
89
90	switch (flags) {
91		case PKCS11H_LOG_DEBUG2:
92			openvpn_flags = D_PKCS11_DEBUG;
93		break;
94		case PKCS11H_LOG_DEBUG1:
95			openvpn_flags = D_SHOW_PKCS11;
96		break;
97		case PKCS11H_LOG_INFO:
98			openvpn_flags = M_INFO;
99		break;
100		case PKCS11H_LOG_WARN:
101			openvpn_flags = M_WARN;
102		break;
103		case PKCS11H_LOG_ERROR:
104			openvpn_flags = M_FATAL;
105		break;
106		default:
107			openvpn_flags = M_FATAL;
108		break;
109	}
110
111#if defined(ENABLE_PKCS11_FORCE_DEBUG)
112	openvpn_flags=M_INFO;
113#endif
114
115	return openvpn_flags;
116}
117
118static
119unsigned
120_pkcs11_msg_openvpn2pkcs11 (
121	const unsigned flags
122) {
123	unsigned pkcs11_flags;
124
125	if ((flags & D_PKCS11_DEBUG) != 0) {
126		pkcs11_flags = PKCS11H_LOG_DEBUG2;
127	}
128	else if ((flags & D_SHOW_PKCS11) != 0) {
129		pkcs11_flags = PKCS11H_LOG_DEBUG1;
130	}
131	else if ((flags & M_INFO) != 0) {
132		pkcs11_flags = PKCS11H_LOG_INFO;
133	}
134	else if ((flags & M_WARN) != 0) {
135		pkcs11_flags = PKCS11H_LOG_WARN;
136	}
137	else if ((flags & M_FATAL) != 0) {
138		pkcs11_flags = PKCS11H_LOG_ERROR;
139	}
140	else {
141		pkcs11_flags = PKCS11H_LOG_ERROR;
142	}
143
144#if defined(ENABLE_PKCS11_FORCE_DEBUG)
145	pkcs11_flags = PKCS11H_LOG_DEBUG2;
146#endif
147
148	return pkcs11_flags;
149}
150
151static
152void
153_pkcs11_openvpn_log (
154	void * const global_data,
155	unsigned flags,
156	const char * const szFormat,
157	va_list args
158) {
159	char Buffer[10*1024];
160
161	(void)global_data;
162
163	vsnprintf (Buffer, sizeof (Buffer), szFormat, args);
164	Buffer[sizeof (Buffer)-1] = 0;
165
166	msg (_pkcs11_msg_pkcs112openvpn (flags), "%s", Buffer);
167}
168
169static
170PKCS11H_BOOL
171_pkcs11_openvpn_token_prompt (
172	void * const global_data,
173	void * const user_data,
174	const pkcs11h_token_id_t token,
175	const unsigned retry
176) {
177	struct user_pass token_resp;
178
179	(void)global_data;
180	(void)user_data;
181	(void)retry;
182
183	ASSERT (token!=NULL);
184
185	CLEAR (token_resp);
186	token_resp.defined = false;
187	token_resp.nocache = true;
188	openvpn_snprintf (
189		token_resp.username,
190		sizeof (token_resp.username),
191		"Please insert %s token",
192		token->label
193	);
194
195	if (
196		!get_user_pass (
197			&token_resp,
198			NULL,
199			"token-insertion-request",
200			GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK|GET_USER_PASS_NOFATAL
201		)
202	) {
203		return false;
204	}
205	else {
206		return strcmp (token_resp.password, "ok") == 0;
207	}
208}
209
210static
211PKCS11H_BOOL
212_pkcs11_openvpn_pin_prompt (
213	void * const global_data,
214	void * const user_data,
215	const pkcs11h_token_id_t token,
216	const unsigned retry,
217	char * const pin,
218	const size_t pin_max
219) {
220	struct user_pass token_pass;
221	char prompt[1024];
222
223	(void)global_data;
224	(void)user_data;
225	(void)retry;
226
227	ASSERT (token!=NULL);
228
229	openvpn_snprintf (prompt, sizeof (prompt), "%s token", token->label);
230
231	token_pass.defined = false;
232	token_pass.nocache = true;
233
234	if (
235		!get_user_pass (
236			&token_pass,
237			NULL,
238			prompt,
239			GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL
240		)
241	) {
242		return false;
243	}
244	else {
245		strncpynt (pin, token_pass.password, pin_max);
246		purge_user_pass (&token_pass, true);
247
248		if (strlen (pin) == 0) {
249			return false;
250		}
251		else {
252			return true;
253		}
254	}
255}
256
257bool
258pkcs11_initialize (
259	const bool protected_auth,
260	const int nPINCachePeriod
261) {
262	CK_RV rv = CKR_FUNCTION_FAILED;
263
264	dmsg (
265		D_PKCS11_DEBUG,
266		"PKCS#11: pkcs11_initialize - entered"
267	);
268
269	if ((rv = pkcs11h_engine_setSystem (&s_pkcs11h_sys_engine)) != CKR_OK) {
270		msg (M_FATAL, "PKCS#11: Cannot initialize system engine %ld-'%s'", rv, pkcs11h_getMessage (rv));
271		goto cleanup;
272	}
273
274	if ((rv = pkcs11h_initialize ()) != CKR_OK) {
275		msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv));
276		goto cleanup;
277	}
278
279	if ((rv = pkcs11h_setLogHook (_pkcs11_openvpn_log, NULL)) != CKR_OK) {
280		msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
281		goto cleanup;
282	}
283
284	pkcs11h_setLogLevel (_pkcs11_msg_openvpn2pkcs11 (get_debug_level ()));
285
286	if ((rv = pkcs11h_setForkMode (TRUE)) != CKR_OK) {
287		msg (M_FATAL, "PKCS#11: Cannot set fork mode %ld-'%s'", rv, pkcs11h_getMessage (rv));
288		goto cleanup;
289	}
290
291	if ((rv = pkcs11h_setTokenPromptHook (_pkcs11_openvpn_token_prompt, NULL)) != CKR_OK) {
292		msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
293		goto cleanup;
294	}
295
296	if ((rv = pkcs11h_setPINPromptHook (_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK) {
297		msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
298		goto cleanup;
299	}
300
301	if ((rv = pkcs11h_setProtectedAuthentication (protected_auth)) != CKR_OK) {
302		msg (M_FATAL, "PKCS#11: Cannot set protected authentication mode %ld-'%s'", rv, pkcs11h_getMessage (rv));
303		goto cleanup;
304	}
305
306	if ((rv = pkcs11h_setPINCachePeriod (nPINCachePeriod)) != CKR_OK) {
307		msg (M_FATAL, "PKCS#11: Cannot set Pcache period %ld-'%s'", rv, pkcs11h_getMessage (rv));
308		goto cleanup;
309	}
310
311	rv = CKR_OK;
312
313cleanup:
314	dmsg (
315		D_PKCS11_DEBUG,
316		"PKCS#11: pkcs11_initialize - return %ld-'%s'",
317		rv,
318		pkcs11h_getMessage (rv)
319	);
320
321	return rv == CKR_OK;
322}
323
324void
325pkcs11_terminate () {
326	dmsg (
327		D_PKCS11_DEBUG,
328		"PKCS#11: pkcs11_terminate - entered"
329	);
330
331	pkcs11h_terminate ();
332
333	dmsg (
334		D_PKCS11_DEBUG,
335		"PKCS#11: pkcs11_terminate - return"
336	);
337}
338
339void
340pkcs11_forkFixup () {
341	pkcs11h_forkFixup ();
342}
343
344bool
345pkcs11_addProvider (
346	const char * const provider,
347	const bool protected_auth,
348	const unsigned private_mode,
349	const bool cert_private
350) {
351	CK_RV rv = CKR_OK;
352
353	ASSERT (provider!=NULL);
354
355	dmsg (
356		D_PKCS11_DEBUG,
357		"PKCS#11: pkcs11_addProvider - entered - provider='%s', private_mode=%08x",
358		provider,
359		private_mode
360	);
361
362	msg (
363		M_INFO,
364		"PKCS#11: Adding PKCS#11 provider '%s'",
365		provider
366	);
367
368	if (
369		(rv = pkcs11h_addProvider (
370			provider,
371			provider,
372			protected_auth,
373			private_mode,
374			PKCS11H_SLOTEVENT_METHOD_AUTO,
375			0,
376			cert_private
377		)) != CKR_OK
378	) {
379		msg (M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv));
380	}
381
382	dmsg (
383		D_PKCS11_DEBUG,
384		"PKCS#11: pkcs11_addProvider - return rv=%ld-'%s'",
385		rv,
386		pkcs11h_getMessage (rv)
387	);
388
389	return rv == CKR_OK;
390}
391
392int
393pkcs11_logout() {
394	return pkcs11h_logout () == CKR_OK;
395}
396
397int
398pkcs11_management_id_count () {
399	pkcs11h_certificate_id_list_t id_list = NULL;
400	pkcs11h_certificate_id_list_t t = NULL;
401	CK_RV rv = CKR_OK;
402	int count = 0;
403
404	dmsg (
405		D_PKCS11_DEBUG,
406		"PKCS#11: pkcs11_management_id_count - entered"
407	);
408
409	if (
410		(rv = pkcs11h_certificate_enumCertificateIds (
411			PKCS11H_ENUM_METHOD_CACHE_EXIST,
412			NULL,
413			PKCS11H_PROMPT_MASK_ALLOW_ALL,
414			NULL,
415			&id_list
416		)) != CKR_OK
417	) {
418		msg (M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage (rv));
419		goto cleanup;
420	}
421
422	for (count = 0, t = id_list; t != NULL; t = t->next) {
423		count++;
424	}
425
426cleanup:
427
428	if (id_list != NULL) {
429		pkcs11h_certificate_freeCertificateIdList (id_list);
430		id_list = NULL;
431	}
432
433	dmsg (
434		D_PKCS11_DEBUG,
435		"PKCS#11: pkcs11_management_id_count - return count=%d",
436		count
437	);
438
439	return count;
440}
441
442bool
443pkcs11_management_id_get (
444	const int index,
445	char ** id,
446	char **base64
447) {
448	pkcs11h_certificate_id_list_t id_list = NULL;
449	pkcs11h_certificate_id_list_t entry = NULL;
450#if 0 /* certificate_id seems to be unused -- JY */
451	pkcs11h_certificate_id_t certificate_id = NULL;
452#endif
453	pkcs11h_certificate_t certificate = NULL;
454	CK_RV rv = CKR_OK;
455	unsigned char *certificate_blob = NULL;
456	size_t certificate_blob_size = 0;
457	size_t max;
458	char *internal_id = NULL;
459	char *internal_base64 = NULL;
460	int count = 0;
461	bool success = false;
462
463	ASSERT (id!=NULL);
464	ASSERT (base64!=NULL);
465
466	dmsg (
467		D_PKCS11_DEBUG,
468		"PKCS#11: pkcs11_management_id_get - entered index=%d",
469		index
470	);
471
472	*id = NULL;
473	*base64 = NULL;
474
475	if (
476		(rv = pkcs11h_certificate_enumCertificateIds (
477			PKCS11H_ENUM_METHOD_CACHE_EXIST,
478			NULL,
479			PKCS11H_PROMPT_MASK_ALLOW_ALL,
480			NULL,
481			&id_list
482		)) != CKR_OK
483	) {
484		msg (M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage (rv));
485		goto cleanup;
486	}
487
488	entry = id_list;
489	count = 0;
490	while (entry != NULL && count != index) {
491		count++;
492		entry = entry->next;
493	}
494
495	if (entry == NULL) {
496		dmsg (
497			D_PKCS11_DEBUG,
498			"PKCS#11: pkcs11_management_id_get - no certificate at index=%d",
499			index
500		);
501		goto cleanup;
502	}
503
504	if (
505		(rv = pkcs11h_certificate_serializeCertificateId (
506			NULL,
507			&max,
508			entry->certificate_id
509		)) != CKR_OK
510	) {
511		msg (M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage (rv));
512		goto cleanup;
513	}
514
515	if ((internal_id = (char *)malloc (max)) == NULL) {
516		msg (M_FATAL, "PKCS#11: Cannot allocate memory");
517		goto cleanup;
518	}
519
520	if (
521		(rv = pkcs11h_certificate_serializeCertificateId (
522			internal_id,
523			&max,
524			entry->certificate_id
525		)) != CKR_OK
526	) {
527		msg (M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage (rv));
528		goto cleanup;
529	}
530
531	if (
532		(rv = pkcs11h_certificate_create (
533			entry->certificate_id,
534			NULL,
535			PKCS11H_PROMPT_MASK_ALLOW_ALL,
536			PKCS11H_PIN_CACHE_INFINITE,
537			&certificate
538		)) != CKR_OK
539	) {
540		msg (M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
541		goto cleanup;
542	}
543
544	if (
545		(rv = pkcs11h_certificate_getCertificateBlob (
546			certificate,
547			NULL,
548			&certificate_blob_size
549		)) != CKR_OK
550	) {
551		msg (M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage (rv));
552		goto cleanup;
553	}
554
555	if ((certificate_blob = (unsigned char *)malloc (certificate_blob_size)) == NULL) {
556		msg (M_FATAL, "PKCS#11: Cannot allocate memory");
557		goto cleanup;
558	}
559
560	if (
561		(rv = pkcs11h_certificate_getCertificateBlob (
562			certificate,
563			certificate_blob,
564			&certificate_blob_size
565		)) != CKR_OK
566	) {
567		msg (M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage (rv));
568		goto cleanup;
569	}
570
571	if (openvpn_base64_encode (certificate_blob, certificate_blob_size, &internal_base64) == -1) {
572		msg (M_WARN, "PKCS#11: Cannot encode certificate");
573		goto cleanup;
574	}
575
576	*id = internal_id;
577	internal_id = NULL;
578	*base64 = internal_base64;
579	internal_base64 = NULL;
580	success = true;
581
582cleanup:
583
584	if (id_list != NULL) {
585		pkcs11h_certificate_freeCertificateIdList (id_list);
586		id_list = NULL;
587	}
588
589	if (internal_id != NULL) {
590		free (internal_id);
591		internal_id = NULL;
592	}
593
594	if (internal_base64 != NULL) {
595		free (internal_base64);
596		internal_base64 = NULL;
597	}
598
599	if (certificate_blob != NULL) {
600		free (certificate_blob);
601		certificate_blob = NULL;
602	}
603
604	dmsg (
605		D_PKCS11_DEBUG,
606		"PKCS#11: pkcs11_management_id_get - return success=%d, id='%s'",
607		success ? 1 : 0,
608		*id
609	);
610
611	return success;
612}
613
614int
615tls_ctx_use_pkcs11 (
616	struct tls_root_ctx * const ssl_ctx,
617	bool pkcs11_id_management,
618	const char * const pkcs11_id
619) {
620	pkcs11h_certificate_id_t certificate_id = NULL;
621	pkcs11h_certificate_t certificate = NULL;
622	CK_RV rv = CKR_OK;
623
624	bool ok = false;
625
626	ASSERT (ssl_ctx!=NULL);
627	ASSERT (pkcs11_id_management || pkcs11_id!=NULL);
628
629	dmsg (
630		D_PKCS11_DEBUG,
631		"PKCS#11: tls_ctx_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_id_management=%d, pkcs11_id='%s'",
632		(void *)ssl_ctx,
633		pkcs11_id_management ? 1 : 0,
634		pkcs11_id
635	);
636
637	if (pkcs11_id_management) {
638		struct user_pass id_resp;
639
640		CLEAR (id_resp);
641
642		id_resp.defined = false;
643		id_resp.nocache = true;
644		openvpn_snprintf (
645			id_resp.username,
646			sizeof (id_resp.username),
647			"Please specify PKCS#11 id to use"
648		);
649
650		if (
651			!get_user_pass (
652				&id_resp,
653				NULL,
654				"pkcs11-id-request",
655				GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_STR|GET_USER_PASS_NOFATAL
656			)
657		) {
658			goto cleanup;
659		}
660
661		if (
662			(rv = pkcs11h_certificate_deserializeCertificateId (
663				&certificate_id,
664				id_resp.password
665			)) != CKR_OK
666		) {
667			msg (M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage (rv));
668			goto cleanup;
669		}
670	}
671	else {
672		if (
673			(rv = pkcs11h_certificate_deserializeCertificateId (
674				&certificate_id,
675				pkcs11_id
676			)) != CKR_OK
677		) {
678			msg (M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage (rv));
679			goto cleanup;
680		}
681	}
682
683	if (
684		(rv = pkcs11h_certificate_create (
685			certificate_id,
686			NULL,
687			PKCS11H_PROMPT_MASK_ALLOW_ALL,
688			PKCS11H_PIN_CACHE_INFINITE,
689			&certificate
690		)) != CKR_OK
691	) {
692		msg (M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
693		goto cleanup;
694	}
695
696	if (
697		(pkcs11_init_tls_session (
698		    certificate,
699		    ssl_ctx
700		))
701	) {
702		/* Handled by SSL context free */
703		certificate = NULL;
704		goto cleanup;
705	}
706
707	/* Handled by SSL context free */
708	certificate = NULL;
709	ok = true;
710
711cleanup:
712	if (certificate != NULL) {
713		pkcs11h_certificate_freeCertificate (certificate);
714		certificate = NULL;
715	}
716
717	if (certificate_id != NULL) {
718		pkcs11h_certificate_freeCertificateId (certificate_id);
719		certificate_id = NULL;
720	}
721
722	dmsg (
723		D_PKCS11_DEBUG,
724		"PKCS#11: tls_ctx_use_pkcs11 - return ok=%d, rv=%ld",
725		ok ? 1 : 0,
726		rv
727	);
728
729	return ok ? 1 : 0;
730}
731
732static
733PKCS11H_BOOL
734_pkcs11_openvpn_show_pkcs11_ids_pin_prompt (
735	void * const global_data,
736	void * const user_data,
737	const pkcs11h_token_id_t token,
738	const unsigned retry,
739	char * const pin,
740	const size_t pin_max
741) {
742	struct gc_arena gc = gc_new ();
743	struct buffer pass_prompt = alloc_buf_gc (128, &gc);
744
745	(void)global_data;
746	(void)user_data;
747	(void)retry;
748
749	ASSERT (token!=NULL);
750
751	buf_printf (&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display);
752
753	if (!get_console_input (BSTR (&pass_prompt), false, pin, pin_max)) {
754		msg (M_FATAL, "Cannot read password from stdin");
755	}
756
757	gc_free (&gc);
758
759	if (!strcmp (pin, "cancel")) {
760		return FALSE;
761	}
762	else {
763		return TRUE;
764	}
765}
766
767void
768show_pkcs11_ids (
769	const char * const provider,
770	bool cert_private
771) {
772	struct gc_arena gc = gc_new();
773	pkcs11h_certificate_id_list_t user_certificates = NULL;
774	pkcs11h_certificate_id_list_t current = NULL;
775	CK_RV rv = CKR_FUNCTION_FAILED;
776
777	if ((rv = pkcs11h_initialize ()) != CKR_OK) {
778		msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv));
779		goto cleanup;
780	}
781
782	if ((rv = pkcs11h_setLogHook (_pkcs11_openvpn_log, NULL)) != CKR_OK) {
783		msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
784		goto cleanup;
785	}
786
787	pkcs11h_setLogLevel (_pkcs11_msg_openvpn2pkcs11 (get_debug_level ()));
788
789	if ((rv = pkcs11h_setProtectedAuthentication (TRUE)) != CKR_OK) {
790		msg (M_FATAL, "PKCS#11: Cannot set protected authentication %ld-'%s'", rv, pkcs11h_getMessage (rv));
791		goto cleanup;
792	}
793
794	if ((rv = pkcs11h_setPINPromptHook (_pkcs11_openvpn_show_pkcs11_ids_pin_prompt, NULL)) != CKR_OK) {
795		msg (M_FATAL, "PKCS#11: Cannot set PIN hook %ld-'%s'", rv, pkcs11h_getMessage (rv));
796		goto cleanup;
797	}
798
799	if (
800		(rv = pkcs11h_addProvider (
801			provider,
802			provider,
803			TRUE,
804			0,
805			FALSE,
806			0,
807			cert_private ? TRUE : FALSE
808		)) != CKR_OK
809	) {
810		msg (M_FATAL, "PKCS#11: Cannot add provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv));
811		goto cleanup;
812	}
813
814	if (
815		(rv = pkcs11h_certificate_enumCertificateIds (
816			PKCS11H_ENUM_METHOD_CACHE_EXIST,
817			NULL,
818			PKCS11H_PROMPT_MASK_ALLOW_ALL,
819			NULL,
820			&user_certificates
821		)) != CKR_OK
822	) {
823		msg (M_FATAL, "PKCS#11: Cannot enumerate certificates %ld-'%s'", rv, pkcs11h_getMessage (rv));
824		goto cleanup;
825	}
826
827	msg (
828		M_INFO|M_NOPREFIX|M_NOLF,
829		(
830			"\n"
831			"The following objects are available for use.\n"
832			"Each object shown below may be used as parameter to\n"
833			"--pkcs11-id option please remember to use single quote mark.\n"
834		)
835	);
836	for (current = user_certificates;current != NULL; current = current->next) {
837		pkcs11h_certificate_t certificate = NULL;
838		char *dn = NULL;
839		char serial[1024] = {0};
840		char *ser = NULL;
841		size_t ser_len = 0;
842
843		if (
844			(rv = pkcs11h_certificate_serializeCertificateId (
845				NULL,
846				&ser_len,
847				current->certificate_id
848			)) != CKR_OK
849		) {
850			msg (M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
851			goto cleanup1;
852		}
853
854		if (
855			rv == CKR_OK &&
856			(ser = (char *)malloc (ser_len)) == NULL
857		) {
858			msg (M_FATAL, "PKCS#11: Cannot allocate memory");
859			goto cleanup1;
860		}
861
862		if (
863			(rv = pkcs11h_certificate_serializeCertificateId (
864				ser,
865				&ser_len,
866				current->certificate_id
867			)) != CKR_OK
868		) {
869			msg (M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
870			goto cleanup1;
871		}
872
873		if (
874			(rv = pkcs11h_certificate_create (
875				current->certificate_id,
876				NULL,
877				PKCS11H_PROMPT_MASK_ALLOW_ALL,
878				PKCS11H_PIN_CACHE_INFINITE,
879				&certificate
880			))
881		) {
882			msg (M_FATAL, "PKCS#11: Cannot create certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
883			goto cleanup1;
884		}
885
886		if (
887		      (dn = pkcs11_certificate_dn (
888				certificate,
889				&gc
890		      )) == NULL
891		) {
892			goto cleanup1;
893		}
894
895		if (
896		      (pkcs11_certificate_serial (
897				certificate,
898				serial,
899				sizeof(serial)
900		      ))
901		) {
902			goto cleanup1;
903		}
904
905		msg (
906			M_INFO|M_NOPREFIX|M_NOLF,
907			(
908				"\n"
909				"Certificate\n"
910				"       DN:             %s\n"
911				"       Serial:         %s\n"
912				"       Serialized id:  %s\n"
913			),
914			dn,
915			serial,
916			ser
917		);
918
919	cleanup1:
920
921		if (certificate != NULL) {
922			pkcs11h_certificate_freeCertificate (certificate);
923			certificate = NULL;
924		}
925
926		if (ser != NULL) {
927			free (ser);
928			ser = NULL;
929		}
930	}
931
932cleanup:
933	if (user_certificates != NULL) {
934		pkcs11h_certificate_freeCertificateIdList (user_certificates);
935		user_certificates = NULL;
936	}
937
938	pkcs11h_terminate ();
939	gc_free (&gc);
940}
941
942#else
943#ifdef _MSC_VER  /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
944static void dummy (void) {}
945#endif
946#endif /* ENABLE_PKCS11 */
947