~ubuntu-branches/ubuntu/oneiric/openvpn/oneiric

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