View | Details | Raw Unified | Return to bug 1371 | Differences between
and this patch

Collapse All | Expand All

(-)ssh/pkcs11.c (+844 lines)
Line 0 Link Here
1
/*
2
 * Copyright(c) 2005-2006 Alon Bar-Lev.  All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT
18
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
 *(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
 */
24
25
#ifdef ENABLE_PKCS11
26
27
#include <string.h>
28
#include <unistd.h>
29
#include <sys/wait.h>
30
#include <errno.h>
31
#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
32
#include <pkcs11-helper-1.0/pkcs11h-openssl.h>
33
#include "openssl/pem.h"
34
#include "misc.h"
35
#include "buffer.h"
36
#include "xmalloc.h"
37
#include "log.h"
38
#include "pkcs11.h"
39
40
static char *
41
ssh_from_x509(X509 *);
42
43
static time_t
44
mytime(void)
45
{
46
	return time(NULL);
47
}
48
49
static void
50
mysleep(const unsigned long usec)
51
{
52
	usleep((unsigned)usec);
53
}
54
55
static int
56
mygettimeofday(struct timeval *tv)
57
{
58
	return gettimeofday(tv, NULL);
59
}
60
61
static pkcs11h_engine_system_t s_pkcs11h_sys_engine = {
62
	xmalloc,
63
	xfree,
64
	mytime,
65
	mysleep,
66
	mygettimeofday
67
};
68
69
static LogLevel
70
pkcs11_msg_pkcs112openssh(const unsigned flags)
71
{
72
	LogLevel openssh_flags;
73
74
	switch (flags) {
75
	case PKCS11H_LOG_DEBUG2:
76
		openssh_flags = SYSLOG_LEVEL_DEBUG3;
77
		break;
78
	case PKCS11H_LOG_DEBUG1:
79
		openssh_flags = SYSLOG_LEVEL_DEBUG2;
80
		break;
81
	case PKCS11H_LOG_INFO:
82
		openssh_flags = SYSLOG_LEVEL_INFO;
83
		break;
84
	case PKCS11H_LOG_WARN:
85
		openssh_flags = SYSLOG_LEVEL_ERROR;
86
		break;
87
	case PKCS11H_LOG_ERROR:
88
		openssh_flags = SYSLOG_LEVEL_FATAL;
89
		break;
90
	default:
91
		openssh_flags = SYSLOG_LEVEL_FATAL;
92
		break;
93
	}
94
95
	return openssh_flags;
96
}
97
98
static unsigned
99
pkcs11_msg_openssh2pkcs11(const LogLevel flags)
100
{
101
	unsigned pkcs11_flags;
102
103
	switch (flags) {
104
	case SYSLOG_LEVEL_DEBUG3:
105
		pkcs11_flags = PKCS11H_LOG_DEBUG2;
106
		break;
107
	case SYSLOG_LEVEL_DEBUG2:
108
		pkcs11_flags = PKCS11H_LOG_DEBUG1;
109
		break;
110
	case SYSLOG_LEVEL_INFO:
111
		pkcs11_flags = PKCS11H_LOG_INFO;
112
		break;
113
	case SYSLOG_LEVEL_ERROR:
114
		pkcs11_flags = PKCS11H_LOG_WARN;
115
		break;
116
	case SYSLOG_LEVEL_FATAL:
117
		pkcs11_flags = PKCS11H_LOG_ERROR;
118
		break;
119
	default:
120
		pkcs11_flags = PKCS11H_LOG_ERROR;
121
		break;
122
	}
123
124
	return pkcs11_flags;
125
}
126
127
/* ARGSUSED */
128
static void
129
pkcs11_openssh_log(void *const global_data, unsigned flags,
130
	const char *const format, va_list args)
131
{
132
	do_log(pkcs11_msg_pkcs112openssh(flags), format, args);
133
}
134
135
/* ARGSUSED */
136
static PKCS11H_BOOL
137
pkcs11_ssh_token_prompt(void *const global_data,
138
	void *const user_data,
139
	const pkcs11h_token_id_t token, IN const unsigned retry)
140
{
141
	return ask_permission("Please insert token '%s'", token->display);
142
}
143
144
/* ARGSUSED */
145
static PKCS11H_BOOL
146
_pkcs11_ssh_pin_prompt(void *const global_data,
147
	void *const user_data, const pkcs11h_token_id_t token,
148
	const unsigned retry, char *const pin, const size_t pin_max)
149
{
150
	char prompt[1024];
151
	char *passphrase = NULL;
152
	PKCS11H_BOOL ret = FALSE;
153
154
	if (snprintf(prompt, sizeof(prompt), "Please enter PIN for token '%s': ",
155
		token->display) < 0)
156
		goto cleanup;
157
158
	passphrase = read_passphrase(prompt, RP_ALLOW_EOF);
159
160
	if (passphrase == NULL || strlen(passphrase) == 0 ||
161
		strlen(passphrase) > pin_max-1)
162
		goto cleanup;
163
	
164
	strlcpy(pin, passphrase, pin_max);
165
	bzero(passphrase, strlen(passphrase));
166
167
	ret = TRUE;
168
169
cleanup:
170
171
	if (passphrase != NULL)
172
		xfree(passphrase);
173
174
	return ret;
175
}
176
177
static int
178
pkcs11_convert_to_ssh_key(const pkcs11h_certificate_id_t certificate_id, Key **const key,
179
	char **const comment, const int pin_cache_period)
180
{
181
	pkcs11h_certificate_t certificate = NULL;
182
	pkcs11h_certificate_id_t certificate_id_new = NULL;
183
	pkcs11h_openssl_session_t openssl_session = NULL;
184
	Key *internal_key = NULL;
185
	char *internal_comment = NULL;
186
	RSA *rsa = NULL;
187
	size_t temp;
188
	CK_RV rv = CKR_OK;
189
190
	*key = NULL;
191
	*comment = NULL;
192
193
	debug3("PKCS#11: pkcs11_convert_to_ssh_key - entered - certificate=%p, "
194
		"key=%p, comment=%p, pin_cache_period=%d", (void *) certificate,
195
		(void *) key, (void *) comment, pin_cache_period);
196
197
	if ((rv = pkcs11h_certificate_create(certificate_id, NULL,
198
		PKCS11H_PROMPT_MASK_ALLOW_ALL, pin_cache_period,
199
		&certificate)) != CKR_OK) {
200
		error("PKCS#11: Cannot get certificate %ld-'%s'", rv,
201
			pkcs11h_getMessage(rv));
202
		goto cleanup;
203
	}
204
205
	/*
206
	 * New certificate_id is constructed from certificate
207
	 * blob so that it will contian the proper description.
208
	 */
209
210
	if ((rv = pkcs11h_certificate_getCertificateBlob(certificate,
211
				NULL, &temp)) != CKR_OK) {
212
		error("PKCS#11: Cannot get certificate blob %ld-'%s'", rv,
213
			pkcs11h_getMessage(rv));
214
		goto cleanup;
215
	}
216
217
	if ((rv = pkcs11h_certificate_getCertificateId(certificate,
218
		&certificate_id_new)) != CKR_OK) {
219
		error("PKCS#11: Cannot get certificate_id %ld-'%s'", rv,
220
			pkcs11h_getMessage(rv));
221
		goto cleanup;
222
	}
223
224
	if ((internal_comment = xstrdup(certificate_id_new->displayName)) == NULL) {
225
		error("PKCS#11: Memory allocation error");
226
		goto cleanup;
227
	}
228
229
	if ((openssl_session =
230
			pkcs11h_openssl_createSession(certificate)) == NULL) {
231
		error("PKCS#11: Cannot initialize openssl session");
232
		goto cleanup;
233
	}
234
235
	/*
236
	 * will be release by openssl_session
237
	 */
238
	certificate = NULL;
239
240
	if ((rsa = pkcs11h_openssl_session_getRSA(openssl_session)) == NULL) {
241
		error("PKCS#11: Unable get rsa object");
242
		goto cleanup;
243
	}
244
245
	internal_key = key_new_private(KEY_UNSPEC);
246
	internal_key->flags |= KEY_FLAG_EXT;
247
	internal_key->rsa = rsa;
248
	rsa = NULL;
249
	internal_key->type = KEY_RSA;
250
251
	*key = internal_key;
252
	internal_key = NULL;
253
	*comment = internal_comment;
254
	internal_comment = NULL;
255
256
cleanup:
257
	if (internal_key != NULL) {
258
		key_free(internal_key);
259
		internal_key = NULL;
260
	}
261
262
	if (internal_comment != NULL) {
263
		xfree(internal_comment);
264
		internal_comment = NULL;
265
	}
266
267
	if (rsa != NULL) {
268
		RSA_free (rsa);
269
		rsa = NULL;
270
	}
271
272
	if (openssl_session != NULL) {
273
		pkcs11h_openssl_freeSession(openssl_session);
274
		openssl_session = NULL;
275
	}
276
277
	if (certificate_id_new != NULL) {
278
		pkcs11h_certificate_freeCertificateId(certificate_id_new);
279
		certificate_id_new = NULL;
280
	}
281
282
	if (certificate != NULL) {
283
		pkcs11h_certificate_freeCertificate(certificate);
284
		certificate = NULL;
285
	}
286
287
	debug3("PKCS#11: pkcs11_convert_to_ssh_key - return *key=%p", (void *) *key);
288
289
	return *key != NULL;
290
}
291
292
int
293
pkcs11_initialize(const int protected_authentication, const int pin_cache_period)
294
{
295
	CK_RV rv = CKR_FUNCTION_FAILED;
296
297
	debug3("PKCS#11: pkcs11_initialize - entered protected_authentication=%d, "
298
		"pin_cache_period=%d", protected_authentication, pin_cache_period);
299
300
	if ((rv = pkcs11h_engine_setSystem(&s_pkcs11h_sys_engine)) != CKR_OK) {
301
		error("PKCS#11: Cannot set system engine %ld-'%s'", rv,
302
			pkcs11h_getMessage(rv));
303
		goto cleanup;
304
	}
305
306
	if ((rv = pkcs11h_initialize()) != CKR_OK) {
307
		error("PKCS#11: Cannot initialize %ld-'%s'", rv,
308
			pkcs11h_getMessage(rv));
309
		goto cleanup;
310
	}
311
312
	if ((rv = pkcs11h_setLogHook(pkcs11_openssh_log, NULL)) != CKR_OK) {
313
		error("PKCS#11: Cannot set hooks %ld-'%s'", rv,
314
			pkcs11h_getMessage(rv));
315
		goto cleanup;
316
	}
317
318
	pkcs11h_setLogLevel(pkcs11_msg_openssh2pkcs11(get_log_level ()));
319
320
	if ((rv = pkcs11h_setTokenPromptHook(pkcs11_ssh_token_prompt,
321
		NULL)) != CKR_OK) {
322
		error("PKCS#11: Cannot set hooks %ld-'%s'", rv,
323
			pkcs11h_getMessage(rv));
324
		goto cleanup;
325
	}
326
327
	if ((rv = pkcs11h_setPINPromptHook(_pkcs11_ssh_pin_prompt,
328
		NULL)) != CKR_OK) {
329
		error("PKCS#11: Cannot set hooks %ld-'%s'", rv,
330
			pkcs11h_getMessage(rv));
331
		goto cleanup;
332
	}
333
334
	if ((rv = pkcs11h_setProtectedAuthentication(protected_authentication)) !=
335
		CKR_OK) {
336
		error("PKCS#11: Cannot set protected authentication mode %ld-'%s'",
337
			rv, pkcs11h_getMessage(rv));
338
		goto cleanup;
339
	}
340
341
	if ((rv = pkcs11h_setPINCachePeriod(pin_cache_period)) != CKR_OK) {
342
		error("PKCS#11: Cannot set PIN cache period %ld-'%s'", rv,
343
			pkcs11h_getMessage(rv));
344
		goto cleanup;
345
	}
346
347
	rv = CKR_OK;
348
349
cleanup:
350
	debug3("PKCS#11: pkcs11_initialize - return rv=%ld-'%s'",
351
		rv, pkcs11h_getMessage(rv));
352
353
	return rv == CKR_OK;
354
}
355
356
void
357
pkcs11_terminate(void)
358
{
359
	debug3("PKCS#11: pkcs11_terminate - entered");
360
361
	pkcs11h_terminate();
362
363
	debug3("PKCS#11: pkcs11_terminate - return");
364
}
365
366
void
367
pkcs11_free_provider(pkcs11_provider *const provider) {
368
	if (provider != NULL) {
369
		if (provider->provider != NULL)
370
			xfree(provider->provider);
371
		xfree(provider);
372
	}
373
}
374
375
pkcs11_provider *
376
pkcs11_parse_provider(const char *const info)
377
{
378
	pkcs11_provider *provider = NULL;
379
	pkcs11_provider *ret = NULL;
380
	char *split[4];
381
	char *s = NULL;
382
	char *p;
383
	int i;
384
385
	if (info == NULL)
386
		goto cleanup;
387
388
	if ((provider = (pkcs11_provider *) xmalloc(sizeof(*provider))) == NULL)
389
		goto cleanup;
390
391
	memset(provider, 0, sizeof(*provider));
392
	memset(split, 0, sizeof(split));
393
394
	if ((s=xstrdup(info)) == NULL)
395
		goto cleanup;
396
397
	p = s;
398
	i=0;
399
	while(i<4 && p != NULL) {
400
		char *t;
401
		if ((t = strchr(p, ':')) != NULL)
402
			*t = '\x0';
403
		split[i++] = p;
404
		if (t != NULL)
405
			p = t+1;
406
		else
407
			p = NULL;
408
	}
409
410
	/*
411
	 * provider[:protected_authentication[:private_mode[:cert_is_private]]]
412
	 * string:1|0:hex:1|0
413
	 */
414
	if (split[0] != NULL)
415
		provider->provider = xstrdup(split[0]);
416
	if (split[1] != NULL)
417
		provider->protected_authentication = atoi(split[1]) != 0;
418
	if (split[2] != NULL)
419
		sscanf(split[2], "%x", &provider->private_mode);
420
	if (split[3] != NULL)
421
		provider->cert_is_private = atoi(split[3]) != 0;
422
	
423
	if (provider->provider == NULL || strlen(provider->provider) == 0)
424
		goto cleanup;
425
426
	ret = provider;
427
	provider = NULL;
428
429
cleanup:
430
	if (s != NULL)
431
		xfree(s);
432
433
	if (provider != NULL)
434
		pkcs11_free_provider(provider);
435
436
	return ret;
437
}
438
439
int
440
pkcs11_add_provider(const pkcs11_provider *const provider)
441
{
442
	CK_RV rv = CKR_OK;
443
444
	debug3("PKCS#11: pkcs11_add_provider - entered - provider='%s', "
445
		"protected_authentication=%d, private_mode='%08x', cert_is_private=%d",
446
		provider->provider, provider->protected_authentication ? 1 : 0,
447
		provider->private_mode,	provider->cert_is_private ? 1 : 0);
448
449
	debug("PKCS#11: Adding PKCS#11 provider '%s'", provider->provider);
450
451
	if (rv == CKR_OK &&
452
		(rv = pkcs11h_addProvider(provider->provider, provider->provider,
453
			provider->protected_authentication, provider->private_mode,
454
				PKCS11H_SLOTEVENT_METHOD_AUTO,
455
				0, provider->cert_is_private)) != CKR_OK) {
456
		error("PKCS#11: Cannot initialize provider '%s' %ld-'%s'",
457
			provider->provider, rv, pkcs11h_getMessage(rv));
458
	}
459
460
	debug3("PKCS#11: pkcs11_add_provider - return rv=%ld-'%s'",
461
		rv, pkcs11h_getMessage(rv));
462
463
	return rv == CKR_OK;
464
}
465
466
pkcs11_id *
467
pkcs11_id_new(void)
468
{
469
	pkcs11_id *id = (pkcs11_id *) xmalloc(sizeof(*id));
470
	if (id != NULL) {
471
		memset(id, 0, sizeof(*id));
472
		id->pin_cache_period = PKCS11H_PIN_CACHE_INFINITE;
473
	}
474
	return id;
475
}
476
477
void
478
pkcs11_id_free(pkcs11_id *const id)
479
{
480
	if (id != NULL)
481
		xfree(id);
482
}
483
484
int
485
pkcs11_get_key(const pkcs11_id *const id, Key **const key,
486
	char **const comment)
487
{
488
	pkcs11h_certificate_id_t certificate_id = NULL;
489
	CK_RV rv = CKR_OK;
490
491
	debug3("PKCS#11: pkcs11_get_key - entered - id=%p, key=%p, "
492
		"comment=%p", (const void *) id, (void *) key, (void *) comment);
493
494
	debug3("PKCS#11: pkcs11_get_key - id - id=%s, "
495
		"pin_cache_period=%d, cert_file=%s",
496
		id->id, id->pin_cache_period, id->cert_file);
497
498
	if (pkcs11h_certificate_deserializeCertificateId(&certificate_id, id->id)) {
499
		error("PKCS#11: Cannot deserialize id %ld-'%s'", rv,
500
			pkcs11h_getMessage(rv));
501
		goto cleanup;
502
	}
503
504
	if (id->cert_file != NULL && id->cert_file[0] != '\x0') {
505
		X509 *x509 = NULL;
506
		unsigned char *p = NULL;
507
		unsigned char *certificate_blob = NULL;
508
		size_t certificate_blob_size = 0;
509
		int size;
510
		FILE *fp = NULL;
511
512
		if ((fp = fopen(id->cert_file, "r")) == NULL) {
513
			error("PKCS#11: Cannot open file '%s'", id->cert_file);
514
			goto cleanup1;
515
		}
516
517
		if (!PEM_read_X509(fp, &x509, NULL, 0)) {
518
			x509 = NULL;
519
			error("PKCS#11: Cannot read PEM from file '%s'", id->cert_file);
520
			goto cleanup1;
521
		}
522
523
		if ((size = i2d_X509(x509, NULL)) < 0) {
524
			error("PKCS#11: Cannot read decode certificate");
525
			goto cleanup1;
526
		}
527
		certificate_blob_size = (size_t)size;
528
529
		if ((certificate_blob =
530
				(unsigned char *) xmalloc(certificate_blob_size)) == NULL) {
531
			error("PKCS#11: Cannot allocate memory");
532
			goto cleanup1;
533
		}
534
535
		/*
536
		 * i2d_X509 increments p!!!
537
		 */
538
		p = certificate_blob;
539
540
		if ((size = i2d_X509(x509, &p)) < 0) {
541
			error("PKCS#11: Cannot read decode certificate");
542
			goto cleanup1;
543
		}
544
		certificate_blob_size = (size_t)size;
545
546
		if (pkcs11h_certificate_setCertificateIdCertificateBlob
547
			(certificate_id, certificate_blob, certificate_blob_size)
548
			!= CKR_OK) {
549
			error("PKCS#11: Cannot set certificate blob %ld-'%s'", rv,
550
				pkcs11h_getMessage(rv));
551
			goto cleanup1;
552
		}
553
554
	cleanup1:
555
		if (x509 != NULL) {
556
			X509_free(x509);
557
			x509 = NULL;
558
		}
559
560
		if (certificate_blob != NULL) {
561
			xfree(certificate_blob);
562
			certificate_blob = NULL;
563
		}
564
565
		if (fp != NULL) {
566
			fclose(fp);
567
			fp = NULL;
568
		}
569
	}
570
571
	pkcs11_convert_to_ssh_key(certificate_id, key, comment, id->pin_cache_period);
572
573
cleanup:
574
575
	if (certificate_id != NULL) {
576
		pkcs11h_certificate_freeCertificateId(certificate_id);
577
		certificate_id = NULL;
578
	}
579
580
	debug3("PKCS#11: pkcs11_get_key - return rv=%ld, *key=%p", rv, ( void *) *key);
581
582
	return *key != NULL;
583
}
584
585
int
586
pkcs11_get_keys(Key ***const keys, char ***const comments)
587
{
588
#define PKCS11_MAX_KEYS 10
589
	Key **internal_keys = NULL;
590
	char **internal_comments = NULL;
591
	pkcs11h_certificate_id_list_t user_certificates = NULL;
592
	pkcs11h_certificate_id_list_t current = NULL;
593
	CK_RV rv = CKR_FUNCTION_FAILED;
594
	int i;
595
596
	debug3("PKCS#11: pkcs11_get_keys - entered - sshkey=%p, "
597
		"comment=%p",
598
		(void *) keys, (void *) comments);
599
	
600
	*keys = NULL;
601
	*comments = NULL;
602
	
603
	if((internal_keys = (Key **) xcalloc(sizeof(*internal_keys), PKCS11_MAX_KEYS+1)) == NULL) {
604
		rv = CKR_HOST_MEMORY;
605
		goto cleanup;
606
	}
607
608
	if((internal_comments = (char **) xcalloc(sizeof(*internal_comments), PKCS11_MAX_KEYS+1)) == NULL) {
609
		rv = CKR_HOST_MEMORY;
610
		goto cleanup;
611
	}
612
613
	memset(internal_keys, 0, (PKCS11_MAX_KEYS+1)*sizeof(*internal_keys));
614
	memset(internal_comments, 0, (PKCS11_MAX_KEYS+1)*sizeof(*internal_comments));
615
616
	if ((rv = pkcs11h_certificate_enumCertificateIds(
617
		PKCS11H_ENUM_METHOD_CACHE_EXIST, NULL,
618
		PKCS11H_PROMPT_MASK_ALLOW_ALL, NULL,
619
		&user_certificates)) != CKR_OK) {
620
		error("PKCS#11: Cannot enumerate certificates %ld-'%s'", rv,
621
			pkcs11h_getMessage(rv));
622
		goto cleanup;
623
	}
624
625
	i = 0;
626
	for (current = user_certificates; current != NULL && i<PKCS11_MAX_KEYS;
627
		current = current->next) {
628
629
		if (pkcs11_convert_to_ssh_key(current->certificate_id, &internal_keys[i],
630
			&internal_comments[i], PKCS11H_PIN_CACHE_INFINITE)) {
631
			i++;
632
		}
633
	}
634
635
	*keys = internal_keys;
636
	internal_keys = NULL;
637
	*comments = internal_comments;
638
	internal_comments = NULL;
639
	rv = CKR_OK;
640
641
cleanup:
642
	if (user_certificates != NULL) {
643
		pkcs11h_certificate_freeCertificateIdList(user_certificates);
644
		user_certificates = NULL;
645
	}
646
647
	if (internal_keys != NULL) {
648
		Key **t = internal_keys;
649
		while (*t != NULL) {
650
			key_free(*t);
651
			t++;
652
		}
653
		xfree(internal_keys);
654
	}
655
656
	if (internal_comments != NULL) {
657
		char **t = internal_comments;
658
		while (*t != NULL) {
659
			xfree(*t);
660
			t++;
661
		}
662
		xfree(internal_comments);
663
	}
664
665
	debug3("PKCS#11: pkcs11_get_keys - return rv=%ld, *keys=%p", rv, (void *) *keys);
666
667
	return *keys != NULL;
668
#undef PKCS11_MAX_KEYS
669
}
670
671
void
672
pkcs11_show_ids(void)
673
{
674
	pkcs11h_certificate_id_list_t user_certificates = NULL;
675
	pkcs11h_certificate_id_list_t current = NULL;
676
	CK_RV rv = CKR_FUNCTION_FAILED;
677
678
	if ((rv = pkcs11h_certificate_enumCertificateIds(
679
		PKCS11H_ENUM_METHOD_CACHE_EXIST, NULL,
680
		PKCS11H_PROMPT_MASK_ALLOW_ALL, NULL,
681
		&user_certificates)) != CKR_OK) {
682
		error("PKCS#11: Cannot enumerate certificates %ld-'%s'", rv,
683
			pkcs11h_getMessage(rv));
684
		goto cleanup;
685
	}
686
687
	for (current = user_certificates; current != NULL;
688
		current = current->next) {
689
690
		pkcs11h_certificate_t certificate = NULL;
691
		X509 *x509 = NULL;
692
693
		BIO *bio = NULL;
694
		char dn[1024] = { 0 };
695
		char serial[1024] = { 0 };
696
		char *ser = NULL;
697
		char *ssh_key = NULL;
698
		size_t ser_len = 0;
699
		int n;
700
701
		if ((rv = pkcs11h_certificate_serializeCertificateId(NULL,
702
			&ser_len, current->certificate_id)) != CKR_OK) {
703
			error("PKCS#11: Cannot serialize certificate id "
704
				"certificates %ld-'%s'", rv,
705
				pkcs11h_getMessage(rv));
706
			goto cleanup1;
707
		}
708
709
		if ((ser = (char *) xmalloc(ser_len)) == NULL) {
710
			error("PKCS#11: Cannot allocate memory");
711
			goto cleanup1;
712
		}
713
714
		if ((rv = pkcs11h_certificate_serializeCertificateId(ser,
715
			&ser_len, current->certificate_id)) != CKR_OK) {
716
			error("PKCS#11: Cannot serialize certificate "
717
				"id certificates %ld-'%s'",
718
				rv, pkcs11h_getMessage(rv));
719
			goto cleanup1;
720
		}
721
722
		if ((rv = pkcs11h_certificate_create(current->certificate_id,
723
			NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL,
724
			PKCS11H_PIN_CACHE_INFINITE, &certificate)) != CKR_OK) {
725
			error("PKCS#11: Cannot create certificate %ld-'%s'", rv,
726
				pkcs11h_getMessage(rv));
727
			goto cleanup1;
728
		}
729
730
		if ((x509 = pkcs11h_openssl_getX509(certificate)) == NULL) {
731
			error("PKCS#11: Cannot get X509");
732
			goto cleanup1;
733
		}
734
735
		X509_NAME_oneline(X509_get_subject_name(x509), dn, sizeof(dn));
736
737
		if ((bio = BIO_new(BIO_s_mem())) == NULL) {
738
			error("PKCS#11: Cannot create BIO");
739
			goto cleanup1;
740
		}
741
742
		i2a_ASN1_INTEGER(bio, X509_get_serialNumber(x509));
743
		n = BIO_read(bio, serial, sizeof(serial) - 1);
744
		if (n < 0)
745
			serial[0] = '\x0';
746
		else
747
			serial[n] = 0;
748
749
		printf(("\n"
750
				"********************************************\n"
751
				"IDENTITY:\n"
752
				"       DN:             %s\n"
753
				"       Serial:         %s\n"
754
				"       Serialized id:  %s\n"
755
				"\n" "       Certificate:\n"), dn, serial, ser);
756
		PEM_write_X509(stdout, x509);
757
758
		if ((ssh_key = ssh_from_x509(x509)) != NULL) {
759
			printf(("\n" "        SSH:\n" "%s\n"), ssh_key);
760
761
			xfree(ssh_key);
762
		}
763
764
	cleanup1:
765
		if (x509 != NULL) {
766
			X509_free(x509);
767
			x509 = NULL;
768
		}
769
770
		if (bio != NULL) {
771
			BIO_free_all(bio);
772
			bio = NULL;
773
		}
774
775
		if (certificate != NULL) {
776
			pkcs11h_certificate_freeCertificate(certificate);
777
			certificate = NULL;
778
		}
779
780
		if (ser != NULL) {
781
			xfree(ser);
782
			ser = NULL;
783
		}
784
	}
785
786
cleanup:
787
	if (user_certificates != NULL) {
788
		pkcs11h_certificate_freeCertificateIdList(user_certificates);
789
		user_certificates = NULL;
790
	}
791
}
792
793
static char *
794
ssh_from_x509(X509 * x509)
795
{
796
	Buffer b;
797
	EVP_PKEY *pubkey = NULL;
798
	char *ret = NULL;
799
	size_t retsize = 0;
800
	const char *keyname = "ssh-rsa";
801
	int ok = 0;
802
803
	buffer_init(&b);
804
805
	if ((pubkey = X509_get_pubkey(x509)) == NULL)
806
		goto cleanup;
807
808
	if (pubkey->type != EVP_PKEY_RSA)
809
		goto cleanup;
810
811
	buffer_put_cstring(&b, keyname);
812
	buffer_put_bignum2(&b, pubkey->pkey.rsa->e);
813
	buffer_put_bignum2(&b, pubkey->pkey.rsa->n);
814
815
	/* be on the safe side, each byte=4 + 4 suffix + null terminate + keyname */
816
	retsize = buffer_len(&b)*4+4+1+strlen(keyname)+1;
817
	if ((ret = (char *) xmalloc(retsize)) == NULL)
818
		goto cleanup;
819
	snprintf(ret, retsize, "%s ", keyname);
820
	if (uuencode(buffer_ptr(&b), buffer_len(&b), ret+strlen(ret), retsize-strlen(ret)) == -1)
821
		goto cleanup;
822
823
	ok = 1;
824
825
cleanup:
826
827
	if (pubkey != NULL) {
828
		EVP_PKEY_free(pubkey);
829
		pubkey = NULL;
830
	}
831
832
	buffer_free(&b);
833
834
	if (!ok) {
835
		if (ret != NULL) {
836
			xfree(ret);
837
			ret = NULL;
838
		}
839
	}
840
841
	return ret;
842
}
843
844
#endif /* ENABLE_PKCS11 */
(-)ssh/pkcs11.h (+77 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2005-2006 Alon Bar-Lev.  All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
 */
24
25
#ifndef SSH_PKCS11_H
26
#define SSH_PKCS11_H
27
28
#ifdef ENABLE_PKCS11
29
30
#include "key.h"
31
32
typedef struct {
33
	char *provider;
34
	int protected_authentication;
35
	unsigned private_mode;
36
	int cert_is_private;
37
} pkcs11_provider;
38
39
typedef struct {
40
	char *id;
41
	int pin_cache_period;
42
	char *cert_file;
43
} pkcs11_id;
44
45
int
46
pkcs11_initialize(const int, const int);
47
48
void
49
pkcs11_terminate(void);
50
51
void
52
pkcs11_free_provider(pkcs11_provider *const);
53
54
pkcs11_provider *
55
pkcs11_parse_provider(const char *const);
56
57
int
58
pkcs11_add_provider(const pkcs11_provider *const);
59
60
pkcs11_id *
61
pkcs11_id_new(void);
62
63
void
64
pkcs11_id_free(pkcs11_id *const);
65
66
int
67
pkcs11_get_key(const pkcs11_id *const, Key **const, char **const);
68
69
int
70
pkcs11_get_keys(Key ***const, char ***const);
71
72
void
73
pkcs11_show_ids(void);
74
75
#endif /* ENABLE_PKCS11 */
76
77
#endif /* OPENSSH_PKCS11_H */

Return to bug 1371