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

Collapse All | Expand All

(-)a/Makefile.in (-1 / +1 lines)
Lines 85-91 LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ Link Here
85
	atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o utf8.o \
85
	atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o utf8.o \
86
	monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
86
	monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
87
	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
87
	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
88
	ssh-pkcs11.o smult_curve25519_ref.o \
88
	ssh-pkcs11.o ssh-pkcs11-uri.o smult_curve25519_ref.o \
89
	poly1305.o chacha.o cipher-chachapoly.o \
89
	poly1305.o chacha.o cipher-chachapoly.o \
90
	ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \
90
	ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \
91
	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \
91
	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \
(-)a/readconf.c (-1 / +14 lines)
Lines 156-162 typedef enum { Link Here
156
	oPubkeyAuthentication,
156
	oPubkeyAuthentication,
157
	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
157
	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
158
	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
158
	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
159
	oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
159
	oHostKeyAlgorithms, oBindAddress, oPKCS11URI, oPKCS11Provider,
160
	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
160
	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
161
	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
161
	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
162
	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
162
	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
Lines 207-215 static struct { Link Here
207
#ifdef ENABLE_PKCS11
207
#ifdef ENABLE_PKCS11
208
	{ "smartcarddevice", oPKCS11Provider },
208
	{ "smartcarddevice", oPKCS11Provider },
209
	{ "pkcs11provider", oPKCS11Provider },
209
	{ "pkcs11provider", oPKCS11Provider },
210
	{ "pkcs11uri", oPKCS11URI },
210
# else
211
# else
211
	{ "smartcarddevice", oUnsupported },
212
	{ "smartcarddevice", oUnsupported },
212
	{ "pkcs11provider", oUnsupported },
213
	{ "pkcs11provider", oUnsupported },
214
	{ "pkcs11uri", oUnsupported },
213
#endif
215
#endif
214
	{ "rsaauthentication", oUnsupported },
216
	{ "rsaauthentication", oUnsupported },
215
	{ "rhostsrsaauthentication", oUnsupported },
217
	{ "rhostsrsaauthentication", oUnsupported },
Lines 1099-1104 parse_char_array: Link Here
1099
		charptr = &options->bind_address;
1101
		charptr = &options->bind_address;
1100
		goto parse_string;
1102
		goto parse_string;
1101
1103
1104
	case oPKCS11URI:
1105
		/* Can't use parse_string becase it would break on equal signs */
1106
		charptr = &options->pkcs11_uri;
1107
		if (s == NULL)
1108
			fatal("%.200s line %d: Missing argument.", filename, linenum);
1109
		if (*activep && *charptr == NULL)
1110
			*charptr = xstrdup(s);
1111
		return 0;
1112
1102
	case oPKCS11Provider:
1113
	case oPKCS11Provider:
1103
		charptr = &options->pkcs11_provider;
1114
		charptr = &options->pkcs11_provider;
1104
		goto parse_string;
1115
		goto parse_string;
Lines 1800-1805 initialize_options(Options * options) Link Here
1800
	options->log_level = SYSLOG_LEVEL_NOT_SET;
1811
	options->log_level = SYSLOG_LEVEL_NOT_SET;
1801
	options->preferred_authentications = NULL;
1812
	options->preferred_authentications = NULL;
1802
	options->bind_address = NULL;
1813
	options->bind_address = NULL;
1814
	options->pkcs11_uri = NULL;
1803
	options->pkcs11_provider = NULL;
1815
	options->pkcs11_provider = NULL;
1804
	options->enable_ssh_keysign = - 1;
1816
	options->enable_ssh_keysign = - 1;
1805
	options->no_host_authentication_for_localhost = - 1;
1817
	options->no_host_authentication_for_localhost = - 1;
Lines 2522-2527 dump_client_config(Options *o, const char *host) Link Here
2522
	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2534
	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2523
	dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2535
	dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2524
#ifdef ENABLE_PKCS11
2536
#ifdef ENABLE_PKCS11
2537
	dump_cfg_string(oPKCS11URI, o->pkcs11_uri);
2525
	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2538
	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2526
#endif
2539
#endif
2527
	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2540
	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
(-)a/readconf.h (+1 lines)
Lines 81-86 typedef struct { Link Here
81
	char   *user_hostfiles[SSH_MAX_HOSTS_FILES];
81
	char   *user_hostfiles[SSH_MAX_HOSTS_FILES];
82
	char   *preferred_authentications;
82
	char   *preferred_authentications;
83
	char   *bind_address;	/* local socket address for connection to sshd */
83
	char   *bind_address;	/* local socket address for connection to sshd */
84
	char   *pkcs11_uri;	/* PKCS#11 URI */
84
	char   *pkcs11_provider; /* PKCS#11 provider */
85
	char   *pkcs11_provider; /* PKCS#11 provider */
85
	int	verify_host_key_dns;	/* Verify host key using DNS */
86
	int	verify_host_key_dns;	/* Verify host key using DNS */
86
87
(-)a/ssh-add.c (+26 lines)
Lines 64-69 Link Here
64
#include "misc.h"
64
#include "misc.h"
65
#include "ssherr.h"
65
#include "ssherr.h"
66
#include "digest.h"
66
#include "digest.h"
67
#include "ssh-pkcs11-uri.h"
67
68
68
/* argv0 */
69
/* argv0 */
69
extern char *__progname;
70
extern char *__progname;
Lines 183-188 delete_all(int agent_fd) Link Here
183
	return ret;
184
	return ret;
184
}
185
}
185
186
187
#ifdef ENABLE_PKCS11
188
static int update_card(int, int, const char *);
189
190
int
191
update_pkcs11_uri(int agent_fd, int adding, const char *pkcs11_uri)
192
{
193
	struct pkcs11_uri *uri;
194
195
	/* dry-run parse to make sure the URI is valid and to report errors */
196
	uri = pkcs11_uri_init();
197
	if (pkcs11_uri_parse((char *) pkcs11_uri, uri) != 0)
198
		fatal("Failed to parse PKCS#11 URI");
199
	pkcs11_uri_cleanup(uri);
200
201
	return update_card(agent_fd, adding, pkcs11_uri);
202
}
203
#endif
204
186
static int
205
static int
187
add_file(int agent_fd, const char *filename, int key_only, int qflag)
206
add_file(int agent_fd, const char *filename, int key_only, int qflag)
188
{
207
{
Lines 434-439 lock_agent(int agent_fd, int lock) Link Here
434
static int
453
static int
435
do_file(int agent_fd, int deleting, int key_only, char *file, int qflag)
454
do_file(int agent_fd, int deleting, int key_only, char *file, int qflag)
436
{
455
{
456
#ifdef ENABLE_PKCS11
457
	if (strlen(file) >= strlen(PKCS11_URI_SCHEME) &&
458
	    strncmp(file, PKCS11_URI_SCHEME,
459
	    strlen(PKCS11_URI_SCHEME)) == 0) {
460
		return update_pkcs11_uri(agent_fd, !deleting, file);
461
	}
462
#endif
437
	if (deleting) {
463
	if (deleting) {
438
		if (delete_file(agent_fd, file, key_only, qflag) == -1)
464
		if (delete_file(agent_fd, file, key_only, qflag) == -1)
439
			return -1;
465
			return -1;
(-)a/ssh-agent.c (-22 / +77 lines)
Lines 534-543 no_identities(SocketEntry *e) Link Here
534
}
534
}
535
535
536
#ifdef ENABLE_PKCS11
536
#ifdef ENABLE_PKCS11
537
static char *
538
sanitize_pkcs11_provider(const char *provider)
539
{
540
	struct pkcs11_uri *uri = NULL;
541
	char *sane_uri, *module_path = NULL; /* default path */
542
	char canonical_provider[PATH_MAX];
543
544
	if (provider == NULL)
545
		return NULL;
546
547
	if (strlen(provider) >= strlen(PKCS11_URI_SCHEME) &&
548
	    strncmp(provider, PKCS11_URI_SCHEME,
549
	    strlen(PKCS11_URI_SCHEME)) == 0) {
550
		/* PKCS#11 URI */
551
		uri = pkcs11_uri_init();
552
		if (uri == NULL) {
553
			error("Failed to init PCKS#11 URI");
554
			return NULL;
555
		}
556
557
		if (pkcs11_uri_parse(provider, uri) != 0) {
558
			error("Failed to parse PKCS#11 URI");
559
			return NULL;
560
		}
561
		/* validate also provider from URI */
562
		if (uri->module_path)
563
			module_path = strdup(uri->module_path);
564
	} else
565
		module_path = strdup(provider); /* simple path */
566
567
	if (module_path != NULL) { /* do not validate default NULL path in URI */
568
		if (realpath(module_path, canonical_provider) == NULL) {
569
			verbose("failed PKCS#11 provider \"%.100s\": realpath: %s",
570
			    module_path, strerror(errno));
571
			free(module_path);
572
			return NULL;
573
		}
574
		free(module_path);
575
		if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) {
576
			verbose("refusing PKCS#11 provider \"%.100s\": "
577
			    "not whitelisted", canonical_provider);
578
			return NULL;
579
		}
580
581
		/* copy verified and sanitized provider path back to the uri */
582
		if (uri) {
583
			free(uri->module_path);
584
			uri->module_path = xstrdup(canonical_provider);
585
		}
586
	}
587
588
	if (uri) {
589
		sane_uri = pkcs11_uri_get(uri);
590
		pkcs11_uri_cleanup(uri);
591
		return sane_uri;
592
	} else {
593
		return xstrdup(canonical_provider); /* simple path */
594
	}
595
}
596
537
static void
597
static void
538
process_add_smartcard_key(SocketEntry *e)
598
process_add_smartcard_key(SocketEntry *e)
539
{
599
{
540
	char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
600
	char *provider = NULL, *pin = NULL, *sane_uri = NULL;
541
	int r, i, count = 0, success = 0, confirm = 0;
601
	int r, i, count = 0, success = 0, confirm = 0;
542
	u_int seconds;
602
	u_int seconds;
543
	time_t death = 0;
603
	time_t death = 0;
Lines 573-600 process_add_smartcard_key(SocketEntry *e) Link Here
573
			goto send;
633
			goto send;
574
		}
634
		}
575
	}
635
	}
576
	if (realpath(provider, canonical_provider) == NULL) {
636
577
		verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
637
	sane_uri = sanitize_pkcs11_provider(provider);
578
		    provider, strerror(errno));
638
	if (sane_uri == NULL)
579
		goto send;
580
	}
581
	if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) {
582
		verbose("refusing PKCS#11 add of \"%.100s\": "
583
		    "provider not whitelisted", canonical_provider);
584
		goto send;
639
		goto send;
585
	}
640
586
	debug("%s: add %.100s", __func__, canonical_provider);
587
	if (lifetime && !death)
641
	if (lifetime && !death)
588
		death = monotime() + lifetime;
642
		death = monotime() + lifetime;
589
643
590
	count = pkcs11_add_provider(canonical_provider, pin, &keys);
644
	debug("%s: add %.100s", __func__, sane_uri);
645
	count = pkcs11_add_provider(sane_uri, pin, &keys);
591
	for (i = 0; i < count; i++) {
646
	for (i = 0; i < count; i++) {
592
		k = keys[i];
647
		k = keys[i];
593
		if (lookup_identity(k) == NULL) {
648
		if (lookup_identity(k) == NULL) {
594
			id = xcalloc(1, sizeof(Identity));
649
			id = xcalloc(1, sizeof(Identity));
595
			id->key = k;
650
			id->key = k;
596
			id->provider = xstrdup(canonical_provider);
651
			id->provider = xstrdup(sane_uri);
597
			id->comment = xstrdup(canonical_provider); /* XXX */
652
			id->comment = xstrdup(sane_uri);
598
			id->death = death;
653
			id->death = death;
599
			id->confirm = confirm;
654
			id->confirm = confirm;
600
			TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
655
			TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
Lines 608-613 process_add_smartcard_key(SocketEntry *e) Link Here
608
send:
663
send:
609
	free(pin);
664
	free(pin);
610
	free(provider);
665
	free(provider);
666
	free(sane_uri);
611
	free(keys);
667
	free(keys);
612
	send_status(e, success);
668
	send_status(e, success);
613
}
669
}
Lines 615-621 send: Link Here
615
static void
671
static void
616
process_remove_smartcard_key(SocketEntry *e)
672
process_remove_smartcard_key(SocketEntry *e)
617
{
673
{
618
	char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
674
	char *provider = NULL, *pin = NULL, *sane_uri;
619
	int r, success = 0;
675
	int r, success = 0;
620
	Identity *id, *nxt;
676
	Identity *id, *nxt;
621
677
Lines 626-655 process_remove_smartcard_key(SocketEntry *e) Link Here
626
	}
682
	}
627
	free(pin);
683
	free(pin);
628
684
629
	if (realpath(provider, canonical_provider) == NULL) {
685
	sane_uri = sanitize_pkcs11_provider(provider);
630
		verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
686
	if (sane_uri == NULL)
631
		    provider, strerror(errno));
632
		goto send;
687
		goto send;
633
	}
634
688
635
	debug("%s: remove %.100s", __func__, canonical_provider);
689
	debug("%s: remove %.100s", __func__, sane_uri);
636
	for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
690
	for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
637
		nxt = TAILQ_NEXT(id, next);
691
		nxt = TAILQ_NEXT(id, next);
638
		/* Skip file--based keys */
692
		/* Skip file--based keys */
639
		if (id->provider == NULL)
693
		if (id->provider == NULL)
640
			continue;
694
			continue;
641
		if (!strcmp(canonical_provider, id->provider)) {
695
		if (!strcmp(sane_uri, id->provider)) {
642
			TAILQ_REMOVE(&idtab->idlist, id, next);
696
			TAILQ_REMOVE(&idtab->idlist, id, next);
643
			free_identity(id);
697
			free_identity(id);
644
			idtab->nentries--;
698
			idtab->nentries--;
645
		}
699
		}
646
	}
700
	}
647
	if (pkcs11_del_provider(canonical_provider) == 0)
701
	if (pkcs11_del_provider(sane_uri) == 0)
648
		success = 1;
702
		success = 1;
649
	else
703
	else
650
		error("%s: pkcs11_del_provider failed", __func__);
704
		error("%s: pkcs11_del_provider failed", __func__);
651
send:
705
send:
652
	free(provider);
706
	free(provider);
707
	free(sane_uri);
653
	send_status(e, success);
708
	send_status(e, success);
654
}
709
}
655
#endif /* ENABLE_PKCS11 */
710
#endif /* ENABLE_PKCS11 */
(-)a/ssh-keygen.c (+1 lines)
Lines 838-843 do_download(struct passwd *pw) Link Here
838
			free(fp);
838
			free(fp);
839
		} else {
839
		} else {
840
			(void) sshkey_write(keys[i], stdout); /* XXX check */
840
			(void) sshkey_write(keys[i], stdout); /* XXX check */
841
			(void) pkcs11_uri_write(keys[i], stdout);
841
			fprintf(stdout, "\n");
842
			fprintf(stdout, "\n");
842
		}
843
		}
843
		sshkey_free(keys[i]);
844
		sshkey_free(keys[i]);
(-)a/ssh-pkcs11-client.c (+3 lines)
Lines 194-199 pkcs11_add_provider(char *name, char *pin, Key ***keysp) Link Here
194
	u_int blen;
194
	u_int blen;
195
	Buffer msg;
195
	Buffer msg;
196
196
197
	debug("%s: called, name = %s", __func__, name);
198
197
	if (fd < 0 && pkcs11_start_helper() < 0)
199
	if (fd < 0 && pkcs11_start_helper() < 0)
198
		return (-1);
200
		return (-1);
199
201
Lines 207-212 pkcs11_add_provider(char *name, char *pin, Key ***keysp) Link Here
207
	if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) {
209
	if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) {
208
		nkeys = buffer_get_int(&msg);
210
		nkeys = buffer_get_int(&msg);
209
		*keysp = xcalloc(nkeys, sizeof(Key *));
211
		*keysp = xcalloc(nkeys, sizeof(Key *));
212
		debug("%s: nkeys = %d", __func__, nkeys);
210
		for (i = 0; i < nkeys; i++) {
213
		for (i = 0; i < nkeys; i++) {
211
			blob = buffer_get_string(&msg, &blen);
214
			blob = buffer_get_string(&msg, &blen);
212
			free(buffer_get_string(&msg, NULL));
215
			free(buffer_get_string(&msg, NULL));
(-)a/ssh-pkcs11-uri.c (+381 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2017 Red Hat
3
 *
4
 * Authors: Jakub Jelen <jjelen@redhat.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include "includes.h"
20
21
#ifdef ENABLE_PKCS11
22
23
#include <stdio.h>
24
#include <string.h>
25
26
#include "sshkey.h"
27
#include "log.h"
28
29
#define CRYPTOKI_COMPAT
30
#include "pkcs11.h"
31
32
#include "ssh-pkcs11-uri.h"
33
34
#define PKCS11_URI_PATH_SEPARATOR ";"
35
#define PKCS11_URI_QUERY_SEPARATOR "&"
36
#define PKCS11_URI_VALUE_SEPARATOR "="
37
#define PKCS11_URI_ID "id"
38
#define PKCS11_URI_TOKEN "token"
39
#define PKCS11_URI_LIB_MANUF "library-manufacturer"
40
#define PKCS11_URI_MANUF "manufacturer"
41
#define PKCS11_URI_MODULE_PATH "module-path"
42
43
/* Keyword tokens. */
44
typedef enum {
45
	pId, pToken, pLibraryManufacturer, pManufacturer, pModulePath,
46
	pBadOption
47
} pkcs11uriOpCodes;
48
49
/* Textual representation of the tokens. */
50
static struct {
51
	const char *name;
52
	pkcs11uriOpCodes opcode;
53
} keywords[] = {
54
	{ PKCS11_URI_ID, pId },
55
	{ PKCS11_URI_TOKEN, pToken },
56
	{ PKCS11_URI_LIB_MANUF, pLibraryManufacturer },
57
	{ PKCS11_URI_MANUF, pManufacturer },
58
	{ PKCS11_URI_MODULE_PATH, pModulePath },
59
	{ NULL, pBadOption }
60
};
61
62
static pkcs11uriOpCodes
63
parse_token(const char *cp)
64
{
65
	u_int i;
66
67
	for (i = 0; keywords[i].name; i++)
68
		if (strncasecmp(cp, keywords[i].name,
69
		    strlen(keywords[i].name)) == 0)
70
			return keywords[i].opcode;
71
72
	return pBadOption;
73
}
74
75
int
76
percent_decode(char *data, char **outp)
77
{
78
	char tmp[3];
79
	char *out, *tmp_end;
80
	char *p = data;
81
	long value;
82
	size_t outlen = 0;
83
84
	out = malloc(strlen(data)+1); /* upper bound */
85
	if (out == NULL)
86
		return -1;
87
	while (*p != '\0') {
88
		switch (*p) {
89
		case '%':
90
			p++;
91
			if (*p == '\0')
92
				goto fail;
93
			tmp[0] = *p++;
94
			if (*p == '\0')
95
				goto fail;
96
			tmp[1] = *p++;
97
			tmp[2] = '\0';
98
			tmp_end = NULL;
99
			value = strtol(tmp, &tmp_end, 16);
100
			if (tmp_end != tmp+2)
101
				goto fail;
102
			else
103
				out[outlen++] = (char) value;
104
			break;
105
		default:
106
			out[outlen++] = *p++;
107
			break;
108
		}
109
	}
110
111
	/* zero terminate */
112
	out[outlen] = '\0';
113
	*outp = out;
114
	return outlen;
115
fail:
116
	free(out);
117
	return -1;
118
}
119
120
struct sshbuf *
121
percent_encode(const char *data, size_t length, const char *whitelist)
122
{
123
	struct sshbuf *b = NULL;
124
	char tmp[4], *cp;
125
	size_t i;
126
127
	if ((b = sshbuf_new()) == NULL)
128
		return NULL;
129
	for (i = 0; i < length; i++) {
130
		cp = strchr(whitelist, data[i]);
131
		/* if c is specified as '\0' pointer to terminator is returned !! */
132
		if (cp != NULL && *cp != '\0') { 
133
			if (sshbuf_put(b, &data[i], 1) != 0)
134
				goto err;
135
		} else
136
			if (snprintf(tmp, 4, "%%%02X", (unsigned char) data[i]) < 3
137
			    || sshbuf_put(b, tmp, 3) != 0)
138
				goto err;
139
	}
140
	if (sshbuf_put(b, "\0", 1) == 0)
141
		return b;
142
err:
143
	sshbuf_free(b);
144
	return NULL;
145
}
146
147
char *
148
pkcs11_uri_append(char *part, const char *separator, const char *key,
149
    struct sshbuf *value)
150
{
151
	char *new_part;
152
	size_t size;
153
154
	if (value == NULL)
155
		return NULL;
156
157
	size = asprintf(&new_part,
158
	    "%s%s%s"  PKCS11_URI_VALUE_SEPARATOR "%s",
159
	    (part != NULL ? part : ""),
160
	    (part != NULL ? separator : ""),
161
	    key, sshbuf_ptr(value));
162
	sshbuf_free(value);
163
	free(part);
164
165
	if (size < 0)
166
		return NULL;
167
	return new_part;
168
}
169
170
char *
171
pkcs11_uri_get(struct pkcs11_uri *uri)
172
{
173
	size_t size = -1;
174
	char *p = NULL, *path = NULL, *query = NULL;
175
176
	/* compose a percent-encoded ID */
177
	if (uri->id_len > 0) {
178
		struct sshbuf *key_id = percent_encode(uri->id, uri->id_len, "");
179
		path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
180
		    PKCS11_URI_ID, key_id);
181
		if (path == NULL)
182
			goto err;
183
	}
184
185
	/* Write token label */
186
	if (uri->token) {
187
		struct sshbuf *label = percent_encode(uri->token, strlen(uri->token),
188
		    PKCS11_URI_WHITELIST);
189
		path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
190
		    PKCS11_URI_TOKEN, label);
191
		if (path == NULL)
192
			goto err;
193
	}
194
195
	/* Write manufacturer */
196
	if (uri->manuf) {
197
		struct sshbuf *manuf = percent_encode(uri->manuf,
198
		    strlen(uri->manuf), PKCS11_URI_WHITELIST);
199
		path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
200
		    PKCS11_URI_MANUF, manuf);
201
		if (path == NULL)
202
			goto err;
203
	}
204
205
	/* Write module_path */
206
	if (uri->module_path) {
207
		struct sshbuf *module = percent_encode(uri->module_path,
208
		    strlen(uri->module_path), PKCS11_URI_WHITELIST "/");
209
		query = pkcs11_uri_append(query, PKCS11_URI_QUERY_SEPARATOR,
210
		    PKCS11_URI_MODULE_PATH, module);
211
		if (query == NULL)
212
			goto err;
213
	}
214
215
	size = asprintf(&p, PKCS11_URI_SCHEME "%s%s%s",
216
	    path != NULL ? path : "",
217
	    query != NULL ? "?" : "",
218
	    query != NULL ? query : "");
219
err:
220
	free(query);
221
	free(path);
222
	if (size < 0)
223
		return NULL;
224
	return p;
225
}
226
227
struct pkcs11_uri *
228
pkcs11_uri_init()
229
{
230
	struct pkcs11_uri *d = calloc(1, sizeof(struct pkcs11_uri));
231
	return d;
232
}
233
234
void
235
pkcs11_uri_cleanup(struct pkcs11_uri *pkcs11)
236
{
237
	free(pkcs11->id);
238
	free(pkcs11->module_path);
239
	free(pkcs11->token);
240
	free(pkcs11->lib_manuf);
241
	free(pkcs11->manuf);
242
	free(pkcs11);
243
}
244
245
int
246
pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11)
247
{
248
	char *saveptr1, *saveptr2, *str1, *str2, *tok;
249
	int rv = 0, len;
250
	char *p = NULL;
251
252
	size_t scheme_len = strlen(PKCS11_URI_SCHEME);
253
	if (strlen(uri) < scheme_len || /* empty URI matches everything */
254
	    strncmp(uri, PKCS11_URI_SCHEME, scheme_len) != 0) {
255
		error("%s: The '%s' does not look like PKCS#11 URI",
256
		    __func__, uri);
257
		return -1;
258
	}
259
260
	if (pkcs11 == NULL) {
261
		error("%s: Bad arguments. The pkcs11 can't be null", __func__);
262
		return -1;
263
	}
264
265
	/* skip URI schema name */
266
	p = strdup(uri);
267
	str1 = p;
268
269
	/* everything before ? */
270
	tok = strtok_r(str1, "?", &saveptr1);
271
	if (tok == NULL) {
272
		free(p);
273
		error("%s: pk11-path expected, got EOF", __func__);
274
		return -1;
275
	}
276
277
	/* skip URI schema name:
278
	 * the scheme ensures that there is at least something before "?"
279
	 * allowing empty pk11-path. Resulting token at worst pointing to
280
	 * \0 byte */
281
	tok = tok + scheme_len;
282
283
	/* parse pk11-path */
284
	for (str2 = tok; ; str2 = NULL) {
285
		char **charptr;
286
		pkcs11uriOpCodes opcode;
287
		tok = strtok_r(str2, PKCS11_URI_PATH_SEPARATOR, &saveptr2);
288
		if (tok == NULL)
289
			break;
290
		opcode = parse_token(tok);
291
		if (opcode == pBadOption) {
292
			error("Unknown key in PKCS#11 URI: %s", tok);
293
			return -1;
294
		}
295
296
		char *arg = tok + strlen(keywords[opcode].name) + 1; /* separator "=" */
297
		switch (opcode) {
298
		case pId:
299
			/* CKA_ID */
300
			if (pkcs11->id != NULL) {
301
				error("%s: The id already set in the PKCS#11 URI",
302
					__func__);
303
				rv = -1;
304
			}
305
			len = percent_decode(arg, &pkcs11->id);
306
			if (len <= 0) {
307
				error("%s: Failed to percent-decode CKA_ID: %s",
308
				    __func__, arg);
309
				rv = -1;
310
			} else
311
				pkcs11->id_len = len;
312
			debug3("%s: Setting CKA_ID = %s from PKCS#11 URI",
313
			    __func__, arg);
314
			break;
315
		case pToken:
316
			/* CK_TOKEN_INFO -> label */
317
			charptr = &pkcs11->token;
318
 parse_string:
319
			if (*charptr != NULL) {
320
				error("%s: The %s already set in the PKCS#11 URI",
321
				    keywords[opcode].name, __func__);
322
				rv = -1;
323
			}
324
			percent_decode(arg, charptr);
325
			debug3("%s: Setting %s = %s from PKCS#11 URI",
326
			    __func__, keywords[opcode].name, *charptr);
327
			break;
328
329
		case pManufacturer:
330
			/* CK_TOKEN_INFO -> manufacturerID */
331
			charptr = &pkcs11->manuf;
332
			goto parse_string;
333
334
		case pLibraryManufacturer:
335
			/* CK_INFO -> manufacturerID */
336
			charptr = &pkcs11->lib_manuf;
337
			goto parse_string;
338
339
		case pBadOption:
340
		default:
341
			/* Unrecognized attribute in the URI path SHOULD be error */
342
			error("%s: Unknown part of path in PKCS#11 URI: %s",
343
			    __func__, tok);
344
			rv = -1;
345
		}
346
	}
347
348
	tok = strtok_r(NULL, "?", &saveptr1);
349
	if (tok == NULL) {
350
		free(p);
351
		return rv;
352
	}
353
	/* parse pk11-query (optional) */
354
	for (str2 = tok; ; str2 = NULL) {
355
		size_t key_len = strlen(PKCS11_URI_MODULE_PATH) + 1;
356
		tok = strtok_r(str2, PKCS11_URI_QUERY_SEPARATOR, &saveptr2);
357
		if (tok == NULL)
358
			break;
359
		if (strncasecmp(tok, PKCS11_URI_MODULE_PATH
360
		    PKCS11_URI_VALUE_SEPARATOR, key_len) == 0) {
361
			/* module-path is PKCS11Provider */
362
			if (pkcs11->module_path != NULL) {
363
				error("%s: Multiple module-path attributes are"
364
				    "not supported the PKCS#11 URI", __func__);
365
				rv = -1;
366
			}
367
			percent_decode(tok + key_len, &pkcs11->module_path);
368
			debug3("%s: Setting PKCS11Provider = %s from PKCS#11 URI\n",
369
			    __func__, pkcs11->module_path);
370
		/* } else if ( pin-value ) { */
371
		} else {
372
			/* Unrecognized attribute in the URI query SHOULD be ignored */
373
			error("%s: Unknown part of query in PKCS#11 URI: %s",
374
			    __func__, tok);
375
		}
376
	}
377
	free(p);
378
	return rv;
379
}
380
381
#endif /* ENABLE_PKCS11 */
(-)a/ssh-pkcs11-uri.h (+42 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2017 Red Hat
3
 *
4
 * Authors: Jakub Jelen <jjelen@redhat.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#define PKCS11_URI_SCHEME "pkcs11:"
20
#define PKCS11_DEFAULT_PROVIDER "/usr/lib64/p11-kit-proxy.so"
21
22
#define PKCS11_URI_WHITELIST	"abcdefghijklmnopqrstuvwxyz" \
23
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
24
				"0123456789_-.()"
25
26
struct pkcs11_uri {
27
	/* path */
28
	char *id;
29
	size_t id_len;
30
	char *token;
31
	char *lib_manuf;
32
	char *manuf;
33
	/* query */
34
	char *module_path;
35
};
36
37
struct pkcs11_uri *pkcs11_uri_init();
38
void pkcs11_uri_cleanup(struct pkcs11_uri *);
39
int	pkcs11_uri_parse(const char *, struct pkcs11_uri *);
40
struct pkcs11_uri *pkcs11_uri_init();
41
char * pkcs11_uri_get(struct pkcs11_uri *uri);
42
(-)a/ssh-pkcs11.c (-30 / +171 lines)
Lines 50-55 struct pkcs11_slotinfo { Link Here
50
50
51
struct pkcs11_provider {
51
struct pkcs11_provider {
52
	char			*name;
52
	char			*name;
53
	char			*module_path;
53
	void			*handle;
54
	void			*handle;
54
	CK_FUNCTION_LIST	*function_list;
55
	CK_FUNCTION_LIST	*function_list;
55
	CK_INFO			info;
56
	CK_INFO			info;
Lines 74-79 struct pkcs11_key { Link Here
74
75
75
int pkcs11_interactive = 0;
76
int pkcs11_interactive = 0;
76
77
78
/*
79
 * This can't be in the ssh-pkcs11-uri, becase we can not depend on
80
 * PKCS structures in ssh-agent (using client-helper communication)
81
 */
82
int
83
pkcs11_uri_write(const struct sshkey *key, FILE *f)
84
{
85
	char *p = NULL;
86
	struct pkcs11_uri uri;
87
	struct pkcs11_key *k11;
88
89
	/* sanity - is it a RSA key with associated app_data? */
90
	if (key->type != KEY_RSA ||
91
	    (k11 = RSA_get_app_data(key->rsa)) == NULL)
92
		return -1;
93
94
	/* omit type -- we are looking for private-public or private-certificate pairs */
95
	uri.id = k11->keyid;
96
	uri.id_len = k11->keyid_len;
97
	uri.token = k11->provider->slotinfo[k11->slotidx].token.label;
98
	uri.module_path = k11->provider->module_path;
99
	uri.lib_manuf = k11->provider->info.manufacturerID;
100
	uri.manuf = k11->provider->slotinfo[k11->slotidx].token.manufacturerID;
101
102
	p = pkcs11_uri_get(&uri);
103
	/* do not cleanup -- we do not allocate here, only reference */
104
	if (p == NULL)
105
		return -1;
106
107
	fprintf(f, " %s", p);
108
	free(p);
109
	return 0;
110
}
111
77
int
112
int
78
pkcs11_init(int interactive)
113
pkcs11_init(int interactive)
79
{
114
{
Lines 124-129 pkcs11_provider_unref(struct pkcs11_provider *p) Link Here
124
			error("pkcs11_provider_unref: %p still valid", p);
159
			error("pkcs11_provider_unref: %p still valid", p);
125
		free(p->slotlist);
160
		free(p->slotlist);
126
		free(p->slotinfo);
161
		free(p->slotinfo);
162
		free(p->name);
163
		free(p->module_path);
127
		free(p);
164
		free(p);
128
	}
165
	}
129
}
166
}
Lines 155-173 pkcs11_provider_lookup(char *provider_id) Link Here
155
	return (NULL);
192
	return (NULL);
156
}
193
}
157
194
195
int pkcs11_del_provider_by_uri(struct pkcs11_uri *);
196
158
/* unregister provider by name */
197
/* unregister provider by name */
159
int
198
int
160
pkcs11_del_provider(char *provider_id)
199
pkcs11_del_provider(char *provider_id)
200
{
201
	int rv;
202
	struct pkcs11_uri *uri;
203
204
	debug("%s: called, provider_id = %s", __func__, provider_id);
205
206
	uri = pkcs11_uri_init();
207
	if (uri == NULL)
208
		fatal("Failed to init PCKS#11 URI");
209
210
	if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) &&
211
	    strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) {
212
		if (pkcs11_uri_parse(provider_id, uri) != 0)
213
			fatal("Failed to parse PKCS#11 URI");
214
	} else {
215
		uri->module_path = strdup(provider_id);
216
	}
217
218
	rv = pkcs11_del_provider_by_uri(uri);
219
	pkcs11_uri_cleanup(uri);
220
	return rv;
221
}
222
223
/* unregister provider by PKCS#11 URI */
224
int
225
pkcs11_del_provider_by_uri(struct pkcs11_uri *uri)
161
{
226
{
162
	struct pkcs11_provider *p;
227
	struct pkcs11_provider *p;
228
	int rv = -1;
229
	char *provider_uri = pkcs11_uri_get(uri);
230
231
	debug3("%s(%s): called", __func__, provider_uri);
163
232
164
	if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
233
	if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) {
165
		TAILQ_REMOVE(&pkcs11_providers, p, next);
234
		TAILQ_REMOVE(&pkcs11_providers, p, next);
166
		pkcs11_provider_finalize(p);
235
		pkcs11_provider_finalize(p);
167
		pkcs11_provider_unref(p);
236
		pkcs11_provider_unref(p);
168
		return (0);
237
		rv = 0;
169
	}
238
	}
170
	return (-1);
239
	free(provider_uri);
240
	return rv;
171
}
241
}
172
242
173
/* openssl callback for freeing an RSA key */
243
/* openssl callback for freeing an RSA key */
Lines 381-387 pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) Link Here
381
	if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
451
	if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
382
	    CKF_SERIAL_SESSION, NULL, NULL, &session))
452
	    CKF_SERIAL_SESSION, NULL, NULL, &session))
383
	    != CKR_OK) {
453
	    != CKR_OK) {
384
		error("C_OpenSession failed: %lu", rv);
454
		error("C_OpenSession failed for slot %lu: %lu", slotidx, rv);
385
		return (-1);
455
		return (-1);
386
	}
456
	}
387
	if (login_required && pin) {
457
	if (login_required && pin) {
Lines 405-424 pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) Link Here
405
 * keysp points to an (possibly empty) array with *nkeys keys.
475
 * keysp points to an (possibly empty) array with *nkeys keys.
406
 */
476
 */
407
static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG,
477
static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG,
408
    CK_ATTRIBUTE [], CK_ATTRIBUTE [3], struct sshkey ***, int *)
478
    CK_ATTRIBUTE [], size_t, CK_ATTRIBUTE [3], struct sshkey ***, int *)
409
	__attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE))));
479
	__attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE))));
410
480
411
static int
481
static int
412
pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
482
pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
413
    struct sshkey ***keysp, int *nkeys)
483
    struct sshkey ***keysp, int *nkeys, struct pkcs11_uri *uri)
414
{
484
{
485
	size_t filter_size = 1;
415
	CK_OBJECT_CLASS	pubkey_class = CKO_PUBLIC_KEY;
486
	CK_OBJECT_CLASS	pubkey_class = CKO_PUBLIC_KEY;
416
	CK_OBJECT_CLASS	cert_class = CKO_CERTIFICATE;
487
	CK_OBJECT_CLASS	cert_class = CKO_CERTIFICATE;
417
	CK_ATTRIBUTE		pubkey_filter[] = {
488
	CK_ATTRIBUTE		pubkey_filter[] = {
418
		{ CKA_CLASS, NULL, sizeof(pubkey_class) }
489
		{ CKA_CLASS, NULL, sizeof(pubkey_class) },
490
		{ CKA_ID, NULL, 0 }
419
	};
491
	};
420
	CK_ATTRIBUTE		cert_filter[] = {
492
	CK_ATTRIBUTE		cert_filter[] = {
421
		{ CKA_CLASS, NULL, sizeof(cert_class) }
493
		{ CKA_CLASS, NULL, sizeof(cert_class) },
494
		{ CKA_ID, NULL, 0 }
422
	};
495
	};
423
	CK_ATTRIBUTE		pubkey_attribs[] = {
496
	CK_ATTRIBUTE		pubkey_attribs[] = {
424
		{ CKA_ID, NULL, 0 },
497
		{ CKA_ID, NULL, 0 },
Lines 433-442 pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
433
	pubkey_filter[0].pValue = &pubkey_class;
506
	pubkey_filter[0].pValue = &pubkey_class;
434
	cert_filter[0].pValue = &cert_class;
507
	cert_filter[0].pValue = &cert_class;
435
508
436
	if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs,
509
	if (uri->id != NULL) {
437
	    keysp, nkeys) < 0 ||
510
		pubkey_filter[1].pValue = uri->id;
438
	    pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs,
511
		pubkey_filter[1].ulValueLen = uri->id_len;
439
	    keysp, nkeys) < 0)
512
		cert_filter[1].pValue = uri->id;
513
		cert_filter[1].ulValueLen = uri->id_len;
514
		filter_size = 2;
515
	}
516
517
	if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, filter_size,
518
	    pubkey_attribs, keysp, nkeys) < 0 ||
519
	    pkcs11_fetch_keys_filter(p, slotidx, cert_filter, filter_size,
520
	    cert_attribs, keysp, nkeys) < 0)
440
		return (-1);
521
		return (-1);
441
	return (0);
522
	return (0);
442
}
523
}
Lines 454-466 pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key) Link Here
454
535
455
static int
536
static int
456
pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
537
pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
457
    CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3],
538
    CK_ATTRIBUTE filter[], size_t filter_size, CK_ATTRIBUTE attribs[3],
458
    struct sshkey ***keysp, int *nkeys)
539
    struct sshkey ***keysp, int *nkeys)
459
{
540
{
460
	struct sshkey		*key;
541
	struct sshkey		*key;
461
	RSA			*rsa;
542
	RSA			*rsa;
462
	X509 			*x509;
543
	X509 			*x509;
463
	EVP_PKEY		*evp;
544
	EVP_PKEY		*evp = NULL;
464
	int			i;
545
	int			i;
465
	const u_char		*cp;
546
	const u_char		*cp;
466
	CK_RV			rv;
547
	CK_RV			rv;
Lines 473-479 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
473
	f = p->function_list;
554
	f = p->function_list;
474
	session = p->slotinfo[slotidx].session;
555
	session = p->slotinfo[slotidx].session;
475
	/* setup a filter the looks for public keys */
556
	/* setup a filter the looks for public keys */
476
	if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) {
557
	if ((rv = f->C_FindObjectsInit(session, filter, filter_size)) != CKR_OK) {
477
		error("C_FindObjectsInit failed: %lu", rv);
558
		error("C_FindObjectsInit failed: %lu", rv);
478
		return (-1);
559
		return (-1);
479
	}
560
	}
Lines 547-552 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
547
			}
628
			}
548
			if (x509)
629
			if (x509)
549
				X509_free(x509);
630
				X509_free(x509);
631
			if (evp)
632
				EVP_PKEY_free(evp);
550
		}
633
		}
551
		if (rsa)
634
		if (rsa)
552
			RSA_get0_key(rsa, &n, &e, NULL);
635
			RSA_get0_key(rsa, &n, &e, NULL);
Lines 581-586 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
581
/* register a new provider, fails if provider already exists */
664
/* register a new provider, fails if provider already exists */
582
int
665
int
583
pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
666
pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
667
{
668
	int rv;
669
	struct pkcs11_uri *uri;
670
671
	debug("%s: called, provider_id = %s", __func__, provider_id);
672
673
	uri = pkcs11_uri_init();
674
	if (uri == NULL)
675
		fatal("Failed to init PCKS#11 URI");
676
677
	if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) &&
678
	    strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) {
679
		if (pkcs11_uri_parse(provider_id, uri) != 0)
680
			fatal("Failed to parse PKCS#11 URI");
681
	} else {
682
		uri->module_path = strdup(provider_id);
683
	}
684
685
	rv = pkcs11_add_provider_by_uri(uri, pin, keyp);
686
	pkcs11_uri_cleanup(uri);
687
	return rv;
688
}
689
690
int
691
pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***keyp)
584
{
692
{
585
	int nkeys, need_finalize = 0;
693
	int nkeys, need_finalize = 0;
586
	struct pkcs11_provider *p = NULL;
694
	struct pkcs11_provider *p = NULL;
Lines 590-600 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) Link Here
590
	CK_FUNCTION_LIST *f = NULL;
698
	CK_FUNCTION_LIST *f = NULL;
591
	CK_TOKEN_INFO *token;
699
	CK_TOKEN_INFO *token;
592
	CK_ULONG i;
700
	CK_ULONG i;
701
	char *provider_id = strdup(uri->module_path);
702
	char *provider_uri = pkcs11_uri_get(uri);
703
704
	/* if no provider specified, fallback to p11-kit */
705
	if (provider_id == NULL) {
706
		provider_id = strdup(PKCS11_DEFAULT_PROVIDER);
707
	}
708
709
	debug("%s: called, provider_uri = %s", __func__, provider_uri);
593
710
594
	*keyp = NULL;
711
	*keyp = NULL;
595
	if (pkcs11_provider_lookup(provider_id) != NULL) {
712
	if (pkcs11_provider_lookup(provider_uri) != NULL) {
596
		debug("%s: provider already registered: %s",
713
		debug("%s: provider already registered: %s",
597
		    __func__, provider_id);
714
		    __func__, provider_uri);
598
		goto fail;
715
		goto fail;
599
	}
716
	}
600
	/* open shared pkcs11-libarary */
717
	/* open shared pkcs11-libarary */
Lines 607-637 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) Link Here
607
		goto fail;
724
		goto fail;
608
	}
725
	}
609
	p = xcalloc(1, sizeof(*p));
726
	p = xcalloc(1, sizeof(*p));
610
	p->name = xstrdup(provider_id);
727
	p->name = provider_uri;
728
	p->module_path = provider_id;
611
	p->handle = handle;
729
	p->handle = handle;
612
	/* setup the pkcs11 callbacks */
730
	/* setup the pkcs11 callbacks */
613
	if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
731
	if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
614
		error("C_GetFunctionList for provider %s failed: %lu",
732
		error("C_GetFunctionList for provider %s failed: %lu",
615
		    provider_id, rv);
733
		    provider_uri, rv);
616
		goto fail;
734
		goto fail;
617
	}
735
	}
618
	p->function_list = f;
736
	p->function_list = f;
619
	if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
737
	if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
620
		error("C_Initialize for provider %s failed: %lu",
738
		error("C_Initialize for provider %s failed: %lu",
621
		    provider_id, rv);
739
		    provider_uri, rv);
622
		goto fail;
740
		goto fail;
623
	}
741
	}
624
	need_finalize = 1;
742
	need_finalize = 1;
625
	if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
743
	if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
626
		error("C_GetInfo for provider %s failed: %lu",
744
		error("C_GetInfo for provider %s failed: %lu",
627
		    provider_id, rv);
745
		    provider_uri, rv);
628
		goto fail;
746
		goto fail;
629
	}
747
	}
630
	rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
748
	rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
749
	if (uri->lib_manuf != NULL &&
750
	    strcmp(uri->lib_manuf, p->info.manufacturerID)) {
751
		debug("%s: Skipping provider %s not matching library_manufacturer",
752
		    __func__, p->info.manufacturerID);
753
		goto fail;
754
	}
631
	rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
755
	rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
632
	debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
756
	debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
633
	    " libraryDescription <%s> libraryVersion %d.%d",
757
	    " libraryDescription <%s> libraryVersion %d.%d",
634
	    provider_id,
758
	    provider_uri,
635
	    p->info.manufacturerID,
759
	    p->info.manufacturerID,
636
	    p->info.cryptokiVersion.major,
760
	    p->info.cryptokiVersion.major,
637
	    p->info.cryptokiVersion.minor,
761
	    p->info.cryptokiVersion.minor,
Lines 644-657 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) Link Here
644
	}
768
	}
645
	if (p->nslots == 0) {
769
	if (p->nslots == 0) {
646
		debug("%s: provider %s returned no slots", __func__,
770
		debug("%s: provider %s returned no slots", __func__,
647
		    provider_id);
771
		    provider_uri);
648
		goto fail;
772
		goto fail;
649
	}
773
	}
650
	p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
774
	p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
651
	if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
775
	if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
652
	    != CKR_OK) {
776
	    != CKR_OK) {
653
		error("C_GetSlotList for provider %s failed: %lu",
777
		error("C_GetSlotList for provider %s failed: %lu",
654
		    provider_id, rv);
778
		    provider_uri, rv);
655
		goto fail;
779
		goto fail;
656
	}
780
	}
657
	p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
781
	p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
Lines 662-700 pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) Link Here
662
		if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
786
		if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
663
		    != CKR_OK) {
787
		    != CKR_OK) {
664
			error("C_GetTokenInfo for provider %s slot %lu "
788
			error("C_GetTokenInfo for provider %s slot %lu "
665
			    "failed: %lu", provider_id, (unsigned long)i, rv);
789
			    "failed: %lu", provider_uri, (unsigned long)i, rv);
666
			continue;
790
			continue;
667
		}
791
		}
668
		if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
792
		if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
669
			debug2("%s: ignoring uninitialised token in "
793
			debug2("%s: ignoring uninitialised token in "
670
			    "provider %s slot %lu", __func__,
794
			    "provider %s slot %lu", __func__,
671
			    provider_id, (unsigned long)i);
795
			    provider_uri, (unsigned long)i);
672
			continue;
796
			continue;
673
		}
797
		}
674
		rmspace(token->label, sizeof(token->label));
798
		rmspace(token->label, sizeof(token->label));
675
		rmspace(token->manufacturerID, sizeof(token->manufacturerID));
799
		rmspace(token->manufacturerID, sizeof(token->manufacturerID));
676
		rmspace(token->model, sizeof(token->model));
800
		rmspace(token->model, sizeof(token->model));
677
		rmspace(token->serialNumber, sizeof(token->serialNumber));
801
		rmspace(token->serialNumber, sizeof(token->serialNumber));
802
		if (uri->token != NULL &&
803
		    strcmp(token->label, uri->token) != 0) {
804
			debug2("%s: ignoring token not matching label (%s) "
805
			    "specified by PKCS#11 URI in slot %lu", __func__,
806
			    token->label, (unsigned long)i);
807
			continue;
808
		}
809
		if (uri->manuf != NULL &&
810
		    strcmp(token->manufacturerID, uri->manuf) != 0) {
811
			debug2("%s: ignoring token not matching requrested "
812
			    "manufacturerID (%s) specified by PKCS#11 URI in "
813
			    "slot %lu", __func__,
814
			    token->manufacturerID, (unsigned long)i);
815
			continue;
816
		}
678
		debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
817
		debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
679
		    "model <%s> serial <%s> flags 0x%lx",
818
		    "model <%s> serial <%s> flags 0x%lx",
680
		    provider_id, (unsigned long)i,
819
		    provider_uri, (unsigned long)i,
681
		    token->label, token->manufacturerID, token->model,
820
		    token->label, token->manufacturerID, token->model,
682
		    token->serialNumber, token->flags);
821
		    token->serialNumber, token->flags);
683
		/* open session, login with pin and retrieve public keys */
822
		/* open session, login with pin and retrieve public keys */
684
		if (pkcs11_open_session(p, i, pin) == 0)
823
		if (pkcs11_open_session(p, i, pin) == 0)
685
			pkcs11_fetch_keys(p, i, keyp, &nkeys);
824
			pkcs11_fetch_keys(p, i, keyp, &nkeys, uri);
686
	}
825
	}
687
	if (nkeys > 0) {
826
	if (nkeys > 0) {
688
		TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
827
		TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
689
		p->refcount++;	/* add to provider list */
828
		p->refcount++;	/* add to provider list */
690
		return (nkeys);
829
		return (nkeys);
691
	}
830
	}
692
	debug("%s: provider %s returned no keys", __func__, provider_id);
831
	debug("%s: provider %s returned no keys", __func__, provider_uri);
693
	/* don't add the provider, since it does not have any keys */
832
	/* don't add the provider, since it does not have any keys */
694
fail:
833
fail:
695
	if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
834
	if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
696
		error("C_Finalize for provider %s failed: %lu",
835
		error("C_Finalize for provider %s failed: %lu",
697
		    provider_id, rv);
836
		    provider_uri, rv);
698
	if (p) {
837
	if (p) {
699
		free(p->slotlist);
838
		free(p->slotlist);
700
		free(p->slotinfo);
839
		free(p->slotinfo);
Lines 702-707 fail: Link Here
702
	}
841
	}
703
	if (handle)
842
	if (handle)
704
		dlclose(handle);
843
		dlclose(handle);
844
	free(provider_id);
845
	free(provider_uri);
705
	return (-1);
846
	return (-1);
706
}
847
}
707
848
(-)a/ssh-pkcs11.h (+5 lines)
Lines 14-23 Link Here
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
16
 */
17
18
#include "ssh-pkcs11-uri.h"
19
17
int	pkcs11_init(int);
20
int	pkcs11_init(int);
18
void	pkcs11_terminate(void);
21
void	pkcs11_terminate(void);
19
int	pkcs11_add_provider(char *, char *, struct sshkey ***);
22
int	pkcs11_add_provider(char *, char *, struct sshkey ***);
23
int	pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***);
20
int	pkcs11_del_provider(char *);
24
int	pkcs11_del_provider(char *);
25
int	pkcs11_uri_write(const struct sshkey *, FILE *);
21
26
22
#if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11)
27
#if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11)
23
#undef ENABLE_PKCS11
28
#undef ENABLE_PKCS11
(-)a/ssh.c (-6 / +26 lines)
Lines 721-726 main(int ac, char **av) Link Here
721
			options.gss_deleg_creds = 1;
721
			options.gss_deleg_creds = 1;
722
			break;
722
			break;
723
		case 'i':
723
		case 'i':
724
#ifdef ENABLE_PKCS11
725
			if (strlen(optarg) > strlen(PKCS11_URI_SCHEME) &&
726
			    strncmp(optarg, PKCS11_URI_SCHEME,
727
			    strlen(PKCS11_URI_SCHEME)) == 0) {
728
				options.pkcs11_uri = strdup(optarg);
729
				break;
730
			}
731
#endif
724
			p = tilde_expand_filename(optarg, original_real_uid);
732
			p = tilde_expand_filename(optarg, original_real_uid);
725
			if (stat(p, &st) < 0)
733
			if (stat(p, &st) < 0)
726
				fprintf(stderr, "Warning: Identity file %s "
734
				fprintf(stderr, "Warning: Identity file %s "
Lines 1948-1953 load_public_identity_files(struct passwd *pw) Link Here
1948
#ifdef ENABLE_PKCS11
1956
#ifdef ENABLE_PKCS11
1949
	struct sshkey **keys;
1957
	struct sshkey **keys;
1950
	int nkeys;
1958
	int nkeys;
1959
	struct pkcs11_uri *uri;
1951
#endif /* PKCS11 */
1960
#endif /* PKCS11 */
1952
1961
1953
	n_ids = n_certs = 0;
1962
	n_ids = n_certs = 0;
Lines 1957-1979 load_public_identity_files(struct passwd *pw) Link Here
1957
	memset(certificates, 0, sizeof(certificates));
1966
	memset(certificates, 0, sizeof(certificates));
1958
1967
1959
#ifdef ENABLE_PKCS11
1968
#ifdef ENABLE_PKCS11
1960
	if (options.pkcs11_provider != NULL &&
1969
	uri = pkcs11_uri_init();
1970
	if (uri == NULL)
1971
		fatal("Failed to init PCKS#11 URI");
1972
1973
	if (options.pkcs11_uri != NULL &&
1974
	    pkcs11_uri_parse(options.pkcs11_uri, uri) != 0)
1975
		fatal("Failed to parse PKCS#11 URI");
1976
1977
	/* we need to merge URI and provider together */
1978
	if (options.pkcs11_provider != NULL && uri->module_path == NULL)
1979
		uri->module_path = strdup(options.pkcs11_provider);
1980
1981
	if ((options.pkcs11_uri != NULL || options.pkcs11_provider != NULL) &&
1982
	    pkcs11_init(!options.batch_mode) == 0 &&
1961
	    options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
1983
	    options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
1962
	    (pkcs11_init(!options.batch_mode) == 0) &&
1984
	    (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys)) > 0) {
1963
	    (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL,
1964
	    &keys)) > 0) {
1965
		for (i = 0; i < nkeys; i++) {
1985
		for (i = 0; i < nkeys; i++) {
1966
			if (n_ids >= SSH_MAX_IDENTITY_FILES) {
1986
			if (n_ids >= SSH_MAX_IDENTITY_FILES) {
1967
				key_free(keys[i]);
1987
				key_free(keys[i]);
1968
				continue;
1988
				continue;
1969
			}
1989
			}
1970
			identity_keys[n_ids] = keys[i];
1990
			identity_keys[n_ids] = keys[i];
1971
			identity_files[n_ids] =
1991
			identity_files[n_ids] = pkcs11_uri_get(uri);
1972
			    xstrdup(options.pkcs11_provider); /* XXX */
1973
			n_ids++;
1992
			n_ids++;
1974
		}
1993
		}
1975
		free(keys);
1994
		free(keys);
1976
	}
1995
	}
1996
	pkcs11_uri_cleanup(uri);
1977
#endif /* ENABLE_PKCS11 */
1997
#endif /* ENABLE_PKCS11 */
1978
	if ((pw = getpwuid(original_real_uid)) == NULL)
1998
	if ((pw = getpwuid(original_real_uid)) == NULL)
1979
		fatal("load_public_identity_files: getpwuid failed");
1999
		fatal("load_public_identity_files: getpwuid failed");
(-)a/ssh_config.5 (-2 / +10 lines)
Lines 1145-1150 The argument to this keyword is the PKCS#11 shared library Link Here
1145
.Xr ssh 1
1145
.Xr ssh 1
1146
should use to communicate with a PKCS#11 token providing the user's
1146
should use to communicate with a PKCS#11 token providing the user's
1147
private RSA key.
1147
private RSA key.
1148
.It Cm PKCS11URI
1149
Specifies the key to use by PKCS#11 URI.
1150
The argument to this keyword is a subset of the PKCS#11 URI as defined
1151
in RFC 7512 (implemented path arguments
1152
.Cm id ,
1153
.Cm manufacturer ,
1154
.Cm token
1155
and query argument
1156
.Cm module-path
1157
). The URI can not be in quotes.
1148
.It Cm Port
1158
.It Cm Port
1149
Specifies the port number to connect on the remote host.
1159
Specifies the port number to connect on the remote host.
1150
The default is 22.
1160
The default is 22.
1151
- 
1152
* test PKCS#11 URI parser, generator
1161
* test PKCS#11 URI parser, generator
1153
* test percent_encodeer and decoder
1162
* test percent_encodeer and decoder
1154
--
1155
Makefile.in                       |  16 ++
1163
Makefile.in                       |  16 ++
1156
regress/Makefile                  |   1 +
1164
regress/Makefile                  |   1 +
1157
regress/unittests/Makefile        |   2 +-
1165
regress/unittests/Makefile        |   2 +-
1158
regress/unittests/pkcs11/Makefile |   9 ++
1166
regress/unittests/pkcs11/Makefile |   9 ++
1159
regress/unittests/pkcs11/tests.c  | 314 ++++++++++++++++++++++++++++++++++++++
1167
regress/unittests/pkcs11/tests.c  | 314 ++++++++++++++++++++++++++++++++++++++
1160
5 files changed, 341 insertions(+), 1 deletion(-)
1168
5 files changed, 341 insertions(+), 1 deletion(-)
1161
create mode 100644 regress/unittests/pkcs11/Makefile
1169
create mode 100644 regress/unittests/pkcs11/Makefile
1162
create mode 100644 regress/unittests/pkcs11/tests.c
1170
create mode 100644 regress/unittests/pkcs11/tests.c
(-)a/Makefile.in (+16 lines)
Lines 240-245 clean: regressclean Link Here
240
	rm -f regress/unittests/match/test_match$(EXEEXT)
240
	rm -f regress/unittests/match/test_match$(EXEEXT)
241
	rm -f regress/unittests/utf8/*.o
241
	rm -f regress/unittests/utf8/*.o
242
	rm -f regress/unittests/utf8/test_utf8$(EXEEXT)
242
	rm -f regress/unittests/utf8/test_utf8$(EXEEXT)
243
	rm -f regress/unittests/pkcs11/*.o
244
	rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT)
243
	rm -f regress/misc/kexfuzz/*.o
245
	rm -f regress/misc/kexfuzz/*.o
244
	rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT)
246
	rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT)
245
	(cd openbsd-compat && $(MAKE) clean)
247
	(cd openbsd-compat && $(MAKE) clean)
Lines 268-273 distclean: regressclean Link Here
268
	rm -f regress/unittests/match/test_match
270
	rm -f regress/unittests/match/test_match
269
	rm -f regress/unittests/utf8/*.o
271
	rm -f regress/unittests/utf8/*.o
270
	rm -f regress/unittests/utf8/test_utf8
272
	rm -f regress/unittests/utf8/test_utf8
273
	rm -f regress/unittests/pkcs11/*.o
274
	rm -f regress/unittests/pkcs11/test_sshbuf
271
	rm -f regress/unittests/misc/kexfuzz
275
	rm -f regress/unittests/misc/kexfuzz
272
	(cd openbsd-compat && $(MAKE) distclean)
276
	(cd openbsd-compat && $(MAKE) distclean)
273
	if test -d pkg ; then \
277
	if test -d pkg ; then \
Lines 429-434 regress-prep: Link Here
429
	$(MKDIR_P) `pwd`/regress/unittests/kex
433
	$(MKDIR_P) `pwd`/regress/unittests/kex
430
	$(MKDIR_P) `pwd`/regress/unittests/match
434
	$(MKDIR_P) `pwd`/regress/unittests/match
431
	$(MKDIR_P) `pwd`/regress/unittests/utf8
435
	$(MKDIR_P) `pwd`/regress/unittests/utf8
436
	$(MKDIR_P) `pwd`/regress/unittests/pkcs11
432
	$(MKDIR_P) `pwd`/regress/misc/kexfuzz
437
	$(MKDIR_P) `pwd`/regress/misc/kexfuzz
433
	[ -f `pwd`/regress/Makefile ] || \
438
	[ -f `pwd`/regress/Makefile ] || \
434
	    ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
439
	    ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
Lines 548-553 regress/unittests/utf8/test_utf8$(EXEEXT): \ Link Here
548
	    regress/unittests/test_helper/libtest_helper.a \
553
	    regress/unittests/test_helper/libtest_helper.a \
549
	    -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
554
	    -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
550
555
556
UNITTESTS_TEST_PKCS11_OBJS=\
557
	regress/unittests/pkcs11/tests.o
558
559
regress/unittests/pkcs11/test_pkcs11$(EXEEXT): \
560
    ${UNITTESTS_TEST_PKCS11_OBJS} \
561
    regress/unittests/test_helper/libtest_helper.a libssh.a
562
	$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_PKCS11_OBJS) \
563
	    regress/unittests/test_helper/libtest_helper.a \
564
	    -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
565
551
MISC_KEX_FUZZ_OBJS=\
566
MISC_KEX_FUZZ_OBJS=\
552
	regress/misc/kexfuzz/kexfuzz.o
567
	regress/misc/kexfuzz/kexfuzz.o
553
568
Lines 567-572 regress-binaries: regress/modpipe$(EXEEXT) \ Link Here
567
	regress/unittests/kex/test_kex$(EXEEXT) \
582
	regress/unittests/kex/test_kex$(EXEEXT) \
568
	regress/unittests/match/test_match$(EXEEXT) \
583
	regress/unittests/match/test_match$(EXEEXT) \
569
	regress/unittests/utf8/test_utf8$(EXEEXT) \
584
	regress/unittests/utf8/test_utf8$(EXEEXT) \
585
	regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \
570
	regress/misc/kexfuzz/kexfuzz$(EXEEXT)
586
	regress/misc/kexfuzz/kexfuzz$(EXEEXT)
571
587
572
tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS)
588
tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS)
(-)a/regress/Makefile (+1 lines)
Lines 225-230 unit: Link Here
225
		V="" ; \
225
		V="" ; \
226
		test "x${USE_VALGRIND}" = "x" || \
226
		test "x${USE_VALGRIND}" = "x" || \
227
		    V=${.CURDIR}/valgrind-unit.sh ; \
227
		    V=${.CURDIR}/valgrind-unit.sh ; \
228
		$$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \
228
		$$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
229
		$$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
229
		$$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
230
		$$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
230
			-d ${.CURDIR}/unittests/sshkey/testdata ; \
231
			-d ${.CURDIR}/unittests/sshkey/testdata ; \
(-)a/regress/unittests/Makefile (-1 / +1 lines)
Lines 1-6 Link Here
1
#	$OpenBSD: Makefile,v 1.9 2017/03/14 01:20:29 dtucker Exp $
1
#	$OpenBSD: Makefile,v 1.9 2017/03/14 01:20:29 dtucker Exp $
2
2
3
REGRESS_FAIL_EARLY?=	yes
3
REGRESS_FAIL_EARLY?=	yes
4
SUBDIR=	test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion
4
SUBDIR=	test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion pkcs11
5
5
6
.include <bsd.subdir.mk>
6
.include <bsd.subdir.mk>
(-)a/regress/unittests/pkcs11/Makefile (+9 lines)
Line 0 Link Here
1
2
PROG=test_pkcs11
3
SRCS=tests.c
4
REGRESS_TARGETS=run-regress-${PROG}
5
6
run-regress-${PROG}: ${PROG}
7
	env ${TEST_ENV} ./${PROG}
8
9
.include <bsd.regress.mk>
(-)a/regress/unittests/pkcs11/tests.c (-2 / +314 lines)
Line 0 Link Here
0
- 
1
/*
2
 * Copyright (c) 2017 Red Hat
3
 *
4
 * Authors: Jakub Jelen <jjelen@redhat.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include "includes.h"
20
21
#include <locale.h>
22
#include <string.h>
23
24
#include "../test_helper/test_helper.h"
25
26
#include "ssh-pkcs11-uri.h"
27
28
#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL)
29
30
/* prototypes are not public -- specify them here internally for tests */
31
struct sshbuf *percent_encode(const char *, size_t, char *);
32
int percent_decode(char *, char **);
33
34
void
35
compare_uri(struct pkcs11_uri *a, struct pkcs11_uri *b)
36
{
37
	ASSERT_PTR_NE(a, NULL);
38
	ASSERT_PTR_NE(b, NULL);
39
	ASSERT_SIZE_T_EQ(a->id_len, b->id_len);
40
	ASSERT_MEM_EQ(a->id, b->id, a->id_len);
41
	if (b->module_path != NULL)
42
		ASSERT_STRING_EQ(a->module_path, b->module_path);
43
	else /* both should be null */
44
		ASSERT_PTR_EQ(a->module_path, b->module_path);
45
	if (b->token != NULL)
46
		ASSERT_STRING_EQ(a->token, b->token);
47
	else /* both should be null */
48
		ASSERT_PTR_EQ(a->token, b->token);
49
	if (b->manuf != NULL)
50
		ASSERT_STRING_EQ(a->manuf, b->manuf);
51
	else /* both should be null */
52
		ASSERT_PTR_EQ(a->manuf, b->manuf);
53
	if (b->lib_manuf != NULL)
54
		ASSERT_STRING_EQ(a->lib_manuf, b->lib_manuf);
55
	else /* both should be null */
56
		ASSERT_PTR_EQ(a->lib_manuf, b->lib_manuf);
57
}
58
59
void
60
check_parse_rv(char *uri, struct pkcs11_uri *expect, int expect_rv)
61
{
62
	char *buf = NULL, *str;
63
	struct pkcs11_uri *pkcs11uri = NULL;
64
	int rv;
65
66
	if (expect_rv == 0)
67
		str = "Valid";
68
	else
69
		str = "Invalid";
70
	asprintf(&buf, "%s PKCS#11 URI parsing: %s", str, uri);
71
	TEST_START(buf);
72
	free(buf);
73
	pkcs11uri = pkcs11_uri_init();
74
	rv = pkcs11_uri_parse(uri, pkcs11uri);
75
	ASSERT_INT_EQ(rv, expect_rv);
76
	if (rv == 0) /* in case of failure result is undefined */
77
		compare_uri(pkcs11uri, expect);
78
	pkcs11_uri_cleanup(pkcs11uri);
79
	free(expect);
80
	TEST_DONE();
81
}
82
83
void
84
check_parse(char *uri, struct pkcs11_uri *expect)
85
{
86
	check_parse_rv(uri, expect, 0);
87
}
88
89
struct pkcs11_uri *
90
compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf,
91
    char *manuf, char *module_path)
92
{
93
	struct pkcs11_uri *uri = pkcs11_uri_init();
94
	if (id_len > 0) {
95
		uri->id_len = id_len;
96
		uri->id = id;
97
	}
98
	uri->module_path = module_path;
99
	uri->token = token;
100
	uri->lib_manuf = lib_manuf;
101
	uri->manuf = manuf;
102
	return uri;
103
}
104
105
static void
106
test_parse_valid(void)
107
{
108
	/* path arguments */
109
	check_parse("pkcs11:id=%01",
110
	    compose_uri("\x01", 1, NULL, NULL, NULL, NULL));
111
	check_parse("pkcs11:id=%00%01",
112
	    compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL));
113
	check_parse("pkcs11:token=SSH%20Keys",
114
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL));
115
	check_parse("pkcs11:library-manufacturer=OpenSC",
116
	    compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL));
117
	check_parse("pkcs11:manufacturer=piv_II",
118
	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL));
119
	/* query arguments */
120
	check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
121
	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so"));
122
123
	/* combinations */
124
	/* ID SHOULD be percent encoded */
125
	check_parse("pkcs11:token=SSH%20Key;id=0",
126
	    compose_uri("0", 1, "SSH Key", NULL, NULL, NULL));
127
	check_parse(
128
	    "pkcs11:manufacturer=CAC?module-path=/usr/lib64/p11-kit-proxy.so",
129
	    compose_uri(NULL, 0, NULL, NULL, "CAC",
130
	    "/usr/lib64/p11-kit-proxy.so"));
131
132
	/* empty path component matches everything */
133
	check_parse("pkcs11:", EMPTY_URI);
134
135
	/* empty string is a valid to match against (and different from NULL) */
136
	check_parse("pkcs11:token=",
137
	    compose_uri(NULL, 0, "", NULL, NULL, NULL));
138
	/* Percent character needs to be percent-encoded */
139
	check_parse("pkcs11:token=%25",
140
	     compose_uri(NULL, 0, "%", NULL, NULL, NULL));
141
}
142
143
static void
144
test_parse_invalid(void)
145
{
146
	/* Invalid percent encoding */
147
	check_parse_rv("pkcs11:id=%0", EMPTY_URI, -1);
148
	/* Invalid percent encoding */
149
	check_parse_rv("pkcs11:id=%ZZ", EMPTY_URI, -1);
150
	/* Space MUST be percent encoded -- XXX not enforced yet */
151
	check_parse("pkcs11:token=SSH Keys",
152
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL));
153
	/* MUST NOT contain duplicate attributes of the same name */
154
	check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1);
155
	/* Unrecognized attribute in path SHOULD be error */
156
	check_parse_rv("pkcs11:key_name=SSH", EMPTY_URI, -1);
157
	/* Unrecognized attribute in query SHOULD be ignored */
158
	check_parse("pkcs11:?key_name=SSH", EMPTY_URI);
159
}
160
161
void
162
check_gen(char *expect, struct pkcs11_uri *uri)
163
{
164
	char *buf = NULL, *uri_str;
165
166
	asprintf(&buf, "Valid PKCS#11 URI generation: %s", expect);
167
	TEST_START(buf);
168
	free(buf);
169
	uri_str = pkcs11_uri_get(uri);
170
	ASSERT_PTR_NE(uri_str, NULL);
171
	ASSERT_STRING_EQ(uri_str, expect);
172
	free(uri_str);
173
	TEST_DONE();
174
}
175
176
static void
177
test_generate_valid(void)
178
{
179
	/* path arguments */
180
	check_gen("pkcs11:id=%01",
181
	    compose_uri("\x01", 1, NULL, NULL, NULL, NULL));
182
	check_gen("pkcs11:id=%00%01",
183
	    compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL));
184
	check_gen("pkcs11:token=SSH%20Keys", /* space must be percent encoded */
185
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL));
186
	/* library-manufacturer is not implmented now */
187
	/*check_gen("pkcs11:library-manufacturer=OpenSC",
188
	    compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL));*/
189
	check_gen("pkcs11:manufacturer=piv_II",
190
	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL));
191
	/* query arguments */
192
	check_gen("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
193
	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so"));
194
195
	/* combinations */
196
	check_gen("pkcs11:id=%02;token=SSH%20Keys",
197
	    compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL));
198
	check_gen("pkcs11:id=%EE%02?module-path=/usr/lib64/p11-kit-proxy.so",
199
	    compose_uri("\xEE\x02", 2, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so"));
200
201
	/* empty path component matches everything */
202
	check_gen("pkcs11:", EMPTY_URI);
203
204
}
205
206
void
207
check_encode(char *source, size_t len, char *whitelist, char *expect)
208
{
209
	char *buf = NULL;
210
	struct sshbuf *b;
211
212
	asprintf(&buf, "percent_encode: expected %s", expect);
213
	TEST_START(buf);
214
	free(buf);
215
216
	b = percent_encode(source, len, whitelist);
217
	ASSERT_STRING_EQ(sshbuf_ptr(b), expect);
218
	sshbuf_free(b);
219
	TEST_DONE();
220
}
221
222
static void
223
test_percent_encode_multibyte(void)
224
{
225
	/* SHOULD be encoded as octets according to the UTF-8 character encoding */
226
227
	/* multi-byte characters are "for free" */
228
	check_encode("$", 1, "", "%24");
229
	check_encode("¢", 2, "", "%C2%A2");
230
	check_encode("€", 3, "", "%E2%82%AC");
231
	check_encode("𐍈", 4, "", "%F0%90%8D%88");
232
233
	/* CK_UTF8CHAR is unsigned char (1 byte) */
234
	/* labels SHOULD be normalized to NFC [UAX15] */
235
236
}
237
238
static void
239
test_percent_encode(void)
240
{
241
	/* Without whitelist encodes everything (for CKA_ID) */
242
	check_encode("A*", 2, "", "%41%2A");
243
	check_encode("\x00", 1, "", "%00");
244
	check_encode("\x7F", 1, "", "%7F");
245
	check_encode("\x80", 1, "", "%80");
246
	check_encode("\xff", 1, "", "%FF");
247
248
	/* Default whitelist encodes anything but safe letters */
249
	check_encode("test" "\x00" "0alpha", 11, PKCS11_URI_WHITELIST,
250
	    "test%000alpha");
251
	check_encode(" ", 1, PKCS11_URI_WHITELIST,
252
	    "%20"); /* Space MUST be percent encoded */
253
	check_encode("/", 1, PKCS11_URI_WHITELIST,
254
	    "%2F"); /* '/' delimiter MUST be percent encoded (in the path) */
255
	check_encode("?", 1, PKCS11_URI_WHITELIST,
256
	    "%3F"); /* delimiter '?' MUST be percent encoded (in the path) */
257
	check_encode("#", 1, PKCS11_URI_WHITELIST,
258
	    "%23"); /* '#' MUST be always percent encoded */
259
	check_encode("key=value;separator?query&amp;#anch", 35, PKCS11_URI_WHITELIST,
260
	    "key%3Dvalue%3Bseparator%3Fquery%26amp%3B%23anch");
261
262
	/* Components in query can have '/' unencoded (useful for paths) */
263
	check_encode("/path/to.file", 13, PKCS11_URI_WHITELIST "/",
264
	    "/path/to.file");
265
}
266
267
void
268
check_decode(char *source, char *expect, int expect_len)
269
{
270
	char *buf = NULL, *out = NULL;
271
	int rv;
272
273
	asprintf(&buf, "percent_decode: %s", source);
274
	TEST_START(buf);
275
	free(buf);
276
277
	rv = percent_decode(source, &out);
278
	ASSERT_INT_EQ(rv, expect_len);
279
	if (rv >= 0)
280
		ASSERT_MEM_EQ(out, expect, expect_len);
281
	free(out);
282
	TEST_DONE();
283
}
284
285
static void
286
test_percent_decode(void)
287
{
288
	/* simple valid cases */
289
	check_decode("%00", "\x00", 1);
290
	check_decode("%FF", "\xFF", 1);
291
292
	/* normal strings shold be kept intact */
293
	check_decode("strings are left", "strings are left", 16);
294
	check_decode("10%25 of trees", "10% of trees", 12);
295
296
	/* make sure no more than 2 bytes are parsed */
297
	check_decode("%222", "\x22" "2", 2);
298
299
	/* invalid expects failure */
300
	check_decode("%0", "", -1);
301
	check_decode("%Z", "", -1);
302
	check_decode("%FG", "", -1);
303
}
304
305
void
306
tests(void)
307
{
308
	test_percent_encode();
309
	test_percent_encode_multibyte();
310
	test_percent_decode();
311
	test_parse_valid();
312
	test_parse_invalid();
313
	test_generate_valid();
314
}
1
* soft-pkcs11.so  from people.su.se/~lha/soft-pkcs11
315
* soft-pkcs11.so  from people.su.se/~lha/soft-pkcs11
2
 * Return correct CKR for unknown attributes
316
 * Return correct CKR for unknown attributes
3
 * Adjust and build it with regress tests (allowing agent-pkcs11 test)
317
 * Adjust and build it with regress tests (allowing agent-pkcs11 test)
4
* Test PKCS#11 URIs support with soft-pkcs11
318
* Test PKCS#11 URIs support with soft-pkcs11
5
 * Direct usage from commandline (URI, provider and combination)
319
 * Direct usage from commandline (URI, provider and combination)
6
 * Usage from configuration files
320
 * Usage from configuration files
7
 * Usage in ssh-agent (add, sign, remove)
321
 * Usage in ssh-agent (add, sign, remove)
8
 * Make sure it is built with correct paths
322
 * Make sure it is built with correct paths
9
--
10
Makefile.in           |    6 +
323
Makefile.in           |    6 +
11
regress/Makefile      |    1 +
324
regress/Makefile      |    1 +
12
regress/locl.h        |   78 ++
325
regress/locl.h        |   78 ++
13
regress/pkcs11.sh     |  250 ++++++
326
regress/pkcs11.sh     |  250 ++++++
14
regress/soft-pkcs11.c | 2051 +++++++++++++++++++++++++++++++++++++++++++++++++
327
regress/soft-pkcs11.c | 2051 +++++++++++++++++++++++++++++++++++++++++++++++++
15
5 files changed, 2386 insertions(+)
328
5 files changed, 2386 insertions(+)
16
create mode 100644 regress/locl.h
329
create mode 100644 regress/locl.h
17
create mode 100644 regress/pkcs11.sh
330
create mode 100644 regress/pkcs11.sh
18
create mode 100644 regress/soft-pkcs11.c
331
create mode 100644 regress/soft-pkcs11.c
(-)a/Makefile.in (+6 lines)
Lines 452-457 regress/netcat$(EXEEXT): $(srcdir)/regress/netcat.c $(REGRESSLIBS) Link Here
452
	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/netcat.c \
452
	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/netcat.c \
453
	$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
453
	$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
454
454
455
regress/soft-pkcs11.so: $(srcdir)/regress/soft-pkcs11.c $(REGRESSLIBS)
456
	$(CC) $(CFLAGS) $(CPPFLAGS) -fpic -c $(srcdir)/regress/soft-pkcs11.c \
457
	 -o $(srcdir)/regress/soft-pkcs11.o
458
	$(CC) -shared -o $@ $(srcdir)/regress/soft-pkcs11.o
459
455
regress/check-perm$(EXEEXT): $(srcdir)/regress/check-perm.c $(REGRESSLIBS)
460
regress/check-perm$(EXEEXT): $(srcdir)/regress/check-perm.c $(REGRESSLIBS)
456
	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/check-perm.c \
461
	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/check-perm.c \
457
	$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
462
	$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
Lines 573-578 regress/misc/kexfuzz/kexfuzz$(EXEEXT): ${MISC_KEX_FUZZ_OBJS} libssh.a Link Here
573
regress-binaries: regress/modpipe$(EXEEXT) \
578
regress-binaries: regress/modpipe$(EXEEXT) \
574
	regress/setuid-allowed$(EXEEXT) \
579
	regress/setuid-allowed$(EXEEXT) \
575
	regress/netcat$(EXEEXT) \
580
	regress/netcat$(EXEEXT) \
581
	regress/soft-pkcs11.so \
576
	regress/check-perm$(EXEEXT) \
582
	regress/check-perm$(EXEEXT) \
577
	regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
583
	regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
578
	regress/unittests/sshkey/test_sshkey$(EXEEXT) \
584
	regress/unittests/sshkey/test_sshkey$(EXEEXT) \
(-)a/regress/Makefile (+1 lines)
Lines 110-115 CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \ Link Here
110
		pidfile putty.rsa2 ready regress.log \
110
		pidfile putty.rsa2 ready regress.log \
111
		remote_pid revoked-* rsa rsa-agent rsa-agent.pub rsa.pub \
111
		remote_pid revoked-* rsa rsa-agent rsa-agent.pub rsa.pub \
112
		rsa1 rsa1-agent rsa1-agent.pub rsa1.pub rsa_ssh2_cr.prv \
112
		rsa1 rsa1-agent rsa1-agent.pub rsa1.pub rsa_ssh2_cr.prv \
113
		soft-pkcs11.so soft-pkcs11.o \
113
		rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \
114
		rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \
114
		scp-ssh-wrapper.scp setuid-allowed sftp-server.log \
115
		scp-ssh-wrapper.scp setuid-allowed sftp-server.log \
115
		sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
116
		sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
(-)a/regress/locl.h (+78 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2004, Stockholms universitet
3
 * (Stockholm University, 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 university 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
 * AND 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 COPYRIGHT OWNER OR CONTRIBUTORS BE
25
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
 * POSSIBILITY OF SUCH DAMAGE.
32
 */
33
34
/* $Id: locl.h,v 1.5 2005/08/28 15:30:31 lha Exp $ */
35
36
#ifdef HAVE_CONFIG_H
37
#include <config.h>
38
#endif
39
40
#include <openssl/err.h>
41
#include <openssl/evp.h>
42
#include <openssl/pem.h>
43
#include <openssl/rand.h>
44
#include <openssl/x509.h>
45
46
#include <ctype.h>
47
#include <errno.h>
48
#include <pwd.h>
49
#include <stdarg.h>
50
#define _GNU_SOURCE
51
#include <stdio.h>
52
#include <stdlib.h>
53
#include <string.h>
54
#include <unistd.h>
55
56
#include "../pkcs11.h"
57
58
#define OPENSSL_ASN1_MALLOC_ENCODE(T, B, BL, S, R)			\
59
{									\
60
  unsigned char *p;							\
61
  (BL) = i2d_##T((S), NULL);						\
62
  if ((BL) <= 0) {							\
63
     (R) = EINVAL;							\
64
  } else {								\
65
    (B) = malloc((BL));							\
66
    if ((B) == NULL) {							\
67
       (R) = ENOMEM;							\
68
    } else {								\
69
        p = (B);							\
70
        (R) = 0;							\
71
        (BL) = i2d_##T((S), &p);					\
72
        if ((BL) <= 0) {						\
73
           free((B));                                          		\
74
           (R) = EINVAL;						\
75
        }								\
76
    }									\
77
  }									\
78
}
(-)a/regress/pkcs11.sh (+250 lines)
Line 0 Link Here
1
# 
2
#  Copyright (c) 2017 Red Hat
3
# 
4
#  Authors: Jakub Jelen <jjelen@redhat.com>
5
# 
6
#  Permission to use, copy, modify, and distribute this software for any
7
#  purpose with or without fee is hereby granted, provided that the above
8
#  copyright notice and this permission notice appear in all copies.
9
# 
10
#  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
#  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
#  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
#  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
#  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
#  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
#  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18
tid="pkcs11 tests with soft token"
19
20
TEST_SSH_PIN=""
21
TEST_SSH_PKCS11=$OBJ/soft-pkcs11.so
22
23
test -f "$TEST_SSH_PKCS11" || fatal "$TEST_SSH_PKCS11 does not exist"
24
25
# requires ssh-agent built with correct path to ssh-pkcs11-helper
26
# otherwise it fails to start the helper
27
strings ${TEST_SSH_SSHAGENT} | grep "$TEST_SSH_SSHPKCS11HELPER"
28
if [ $? -ne 0 ]; then
29
	fatal "Needs to reconfigure with --libexecdir=\`pwd\` or so"
30
fi
31
32
# setup environment for soft-pkcs11 token
33
SOFTPKCS11RC=$OBJ/pkcs11.info
34
rm -f $SOFTPKCS11RC
35
export SOFTPKCS11RC
36
# prevent ssh-agent from calling ssh-askpass
37
SSH_ASKPASS=/usr/bin/true
38
export SSH_ASKPASS
39
unset DISPLAY
40
41
# start command w/o tty, so ssh accepts pin from stdin (from agent-pkcs11.sh)
42
notty() {
43
	perl -e 'use POSIX; POSIX::setsid(); 
44
	    if (fork) { wait; exit($? >> 8); } else { exec(@ARGV) }' "$@"
45
}
46
47
create_key() {
48
	ID=$1
49
	LABEL=$2
50
	rm -f $OBJ/pkcs11-${ID}.key $OBJ/pkcs11-${ID}.crt
51
	openssl genrsa -out $OBJ/pkcs11-${ID}.key 2048 > /dev/null 2>&1
52
	chmod 600 $OBJ/pkcs11-${ID}.key 
53
	openssl req -key $OBJ/pkcs11-${ID}.key -new -x509 \
54
	    -out $OBJ/pkcs11-${ID}.crt -text -subj '/CN=pkcs11 test' >/dev/null
55
	printf "${ID}\t${LABEL}\t$OBJ/pkcs11-${ID}.crt\t$OBJ/pkcs11-${ID}.key\n" \
56
	    >> $SOFTPKCS11RC
57
}
58
59
trace "Create a key pairs on soft token"
60
ID1="02"
61
ID2="04"
62
create_key "$ID1" "SSH RSA Key"
63
create_key "$ID2" "SSH RSA Key 2"
64
65
trace "List the keys in the ssh-keygen with PKCS#11 URIs"
66
${SSHKEYGEN} -D ${TEST_SSH_PKCS11} > $OBJ/token_keys
67
if [ $? -ne 0 ]; then
68
	fail "keygen fails to enumerate keys on PKCS#11 token"
69
fi
70
grep "pkcs11:" $OBJ/token_keys > /dev/null
71
if [ $? -ne 0 ]; then
72
	fail "The keys from ssh-keygen do not contain PKCS#11 URI as a comment"
73
fi
74
tail -n 1 $OBJ/token_keys > $OBJ/authorized_keys_$USER
75
76
77
trace "Simple connect with ssh (without PKCS#11 URI)"
78
echo ${TEST_SSH_PIN} | notty ${SSH} -I ${TEST_SSH_PKCS11} \
79
    -F $OBJ/ssh_proxy somehost exit 5
80
r=$?
81
if [ $r -ne 5 ]; then
82
	fail "ssh connect with pkcs11 failed (exit code $r)"
83
fi
84
85
86
trace "Connect with PKCS#11 URI"
87
trace "  (second key should succeed)"
88
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
89
    -i "pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" somehost exit 5
90
r=$?
91
if [ $r -ne 5 ]; then
92
	fail "ssh connect with PKCS#11 URI failed (exit code $r)"
93
fi
94
95
trace "  (first key should fail)"
96
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
97
     -i "pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}" somehost exit 5
98
r=$?
99
if [ $r -eq 5 ]; then
100
	fail "ssh connect with PKCS#11 URI succeeded (should fail)"
101
fi
102
103
104
trace "Test PKCS#11 URI specification in configuration files"
105
echo "PKCS11URI pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" \
106
    >> $OBJ/ssh_proxy
107
trace "  (second key should succeed)"
108
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
109
r=$?
110
if [ $r -ne 5 ]; then
111
	fail "ssh connect with PKCS#11 URI in config failed (exit code $r)"
112
fi
113
114
trace "  (first key should fail)"
115
head -n 1 $OBJ/token_keys > $OBJ/authorized_keys_$USER
116
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
117
r=$?
118
if [ $r -eq 5 ]; then
119
	fail "ssh connect with PKCS#11 URI in config succeeded (should fail)"
120
fi
121
sed -i -e "/PKCS11URI/d" $OBJ/ssh_proxy
122
123
trace "Test PKCS#11 URI specification in configuration files with bogus spaces"
124
echo "PKCS11URI     pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}    " \
125
    >> $OBJ/ssh_proxy
126
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
127
r=$?
128
if [ $r -ne 5 ]; then
129
	fail "ssh connect with PKCS#11 URI with bogus spaces in config failed" \
130
	    "(exit code $r)"
131
fi
132
sed -i -e "/PKCS11URI/d" $OBJ/ssh_proxy
133
134
135
trace "Combination of PKCS11Provider and PKCS11URI on commandline"
136
trace "  (first key should succeed)"
137
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
138
    -i "pkcs11:id=${ID1}" -I ${TEST_SSH_PKCS11} somehost exit 5
139
r=$?
140
if [ $r -ne 5 ]; then
141
	fail "ssh connect with PKCS#11 URI and provider combination" \
142
	    "failed (exit code $r)"
143
fi
144
145
trace "  (second key should fail)"
146
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
147
    -i "pkcs11:id=${ID2}" -I ${TEST_SSH_PKCS11} somehost exit 5
148
r=$?
149
if [ $r -eq 5 ]; then
150
	fail "ssh connect with PKCS#11 URI and provider combination" \
151
	    "succeeded (should fail)"
152
fi
153
154
155
trace "SSH Agent can work with PKCS#11 URI"
156
trace "start the agent"
157
eval `${SSHAGENT} -s -P "${OBJ}/*"` > /dev/null
158
159
r=$?
160
if [ $r -ne 0 ]; then
161
	fail "could not start ssh-agent: exit code $r"
162
else
163
	trace "add whole provider to agent"
164
	echo ${TEST_SSH_PIN} | notty ${SSHADD} \
165
	    "pkcs11:?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
166
	r=$?
167
	if [ $r -ne 0 ]; then
168
		fail "ssh-add failed with whole provider: exit code $r"
169
	fi
170
171
	trace " pkcs11 list via agent (all keys)"
172
	${SSHADD} -l > /dev/null 2>&1
173
	r=$?
174
	if [ $r -ne 0 ]; then
175
		fail "ssh-add -l failed with whole provider: exit code $r"
176
	fi
177
178
	trace " pkcs11 connect via agent (all keys)"
179
	${SSH} -F $OBJ/ssh_proxy somehost exit 5
180
	r=$?
181
	if [ $r -ne 5 ]; then
182
		fail "ssh connect failed with whole provider (exit code $r)"
183
	fi
184
185
	trace " remove pkcs11 keys (all keys)"
186
	${SSHADD} -d "pkcs11:?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
187
	r=$?
188
	if [ $r -ne 0 ]; then
189
		fail "ssh-add -d failed with whole provider: exit code $r"
190
	fi
191
192
	trace "add only first key to the agent"
193
	echo ${TEST_SSH_PIN} | notty ${SSHADD} \
194
	    "pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
195
	r=$?
196
	if [ $r -ne 0 ]; then
197
		fail "ssh-add failed with first key: exit code $r"
198
	fi
199
200
	trace " pkcs11 connect via agent (first key)"
201
	${SSH} -F $OBJ/ssh_proxy somehost exit 5
202
	r=$?
203
	if [ $r -ne 5 ]; then
204
		fail "ssh connect failed with first key (exit code $r)"
205
	fi
206
207
	trace " remove first pkcs11 key"
208
	${SSHADD} -d "pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}" \
209
	    > /dev/null 2>&1
210
	r=$?
211
	if [ $r -ne 0 ]; then
212
		fail "ssh-add -d failed with first key: exit code $r"
213
	fi
214
215
	trace "add only second key to the agent"
216
	echo ${TEST_SSH_PIN} | notty ${SSHADD} \
217
	    "pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
218
	r=$?
219
	if [ $r -ne 0 ]; then
220
		fail "ssh-add failed with second key: exit code $r"
221
	fi
222
223
	trace " pkcs11 connect via agent (second key should fail)"
224
	${SSH} -F $OBJ/ssh_proxy somehost exit 5
225
	r=$?
226
	if [ $r -eq 5 ]; then
227
		fail "ssh connect passed without key (should fail)"
228
	fi
229
230
	trace " remove second pkcs11 key"
231
	${SSHADD} -d "pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" \
232
	    > /dev/null 2>&1
233
	r=$?
234
	if [ $r -ne 0 ]; then
235
		fail "ssh-add -d failed with second key: exit code $r"
236
	fi
237
238
	trace " remove already-removed pkcs11 key should fail"
239
	${SSHADD} -d "pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}" \
240
	    > /dev/null 2>&1
241
	r=$?
242
	if [ $r -eq 0 ]; then
243
		fail "ssh-add -d passed with non-existing key (should fail)"
244
	fi
245
246
	trace "kill agent"
247
	${SSHAGENT} -k > /dev/null
248
fi
249
250
rm -rf $OBJ/.tokens $OBJ/token_keys
(-)a/regress/soft-pkcs11.c (-2 / +2051 lines)
Line 0 Link Here
0
- 
1
/*
2
 * Copyright (c) 2004-2006, Stockholms universitet
3
 * (Stockholm University, 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 university 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
 * AND 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 COPYRIGHT OWNER OR CONTRIBUTORS BE
25
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
 * POSSIBILITY OF SUCH DAMAGE.
32
 */
33
34
#include "locl.h"
35
36
/* RCSID("$Id: main.c,v 1.24 2006/01/11 12:42:53 lha Exp $"); */
37
38
#define OBJECT_ID_MASK		0xfff
39
#define HANDLE_OBJECT_ID(h)	((h) & OBJECT_ID_MASK)
40
#define OBJECT_ID(obj)		HANDLE_OBJECT_ID((obj)->object_handle)
41
42
struct st_attr {
43
    CK_ATTRIBUTE attribute;
44
    int secret;
45
};
46
47
struct st_object {
48
    CK_OBJECT_HANDLE object_handle;
49
    struct st_attr *attrs;
50
    int num_attributes;
51
    enum {
52
	STO_T_CERTIFICATE,
53
	STO_T_PRIVATE_KEY,
54
	STO_T_PUBLIC_KEY
55
    } type;
56
    union {
57
	X509 *cert;
58
	EVP_PKEY *public_key;
59
	struct {
60
	    const char *file;
61
	    EVP_PKEY *key;
62
	    X509 *cert;
63
	} private_key;
64
    } u;
65
};
66
67
static struct soft_token {
68
    CK_VOID_PTR application;
69
    CK_NOTIFY notify;
70
    struct {
71
	struct st_object **objs;
72
	int num_objs;
73
    } object;
74
    struct {
75
	int hardware_slot;
76
	int app_error_fatal;
77
	int login_done;
78
    } flags;
79
    int open_sessions;
80
    struct session_state {
81
	CK_SESSION_HANDLE session_handle;
82
83
	struct {
84
	    CK_ATTRIBUTE *attributes;
85
	    CK_ULONG num_attributes;
86
	    int next_object;
87
	} find;
88
89
	int encrypt_object;
90
	CK_MECHANISM_PTR encrypt_mechanism;
91
	int decrypt_object;
92
	CK_MECHANISM_PTR decrypt_mechanism;
93
	int sign_object;
94
	CK_MECHANISM_PTR sign_mechanism;
95
	int verify_object;
96
	CK_MECHANISM_PTR verify_mechanism;
97
	int digest_object;
98
    } state[10];
99
#define MAX_NUM_SESSION (sizeof(soft_token.state)/sizeof(soft_token.state[0]))
100
    FILE *logfile;
101
} soft_token;
102
103
static void
104
application_error(const char *fmt, ...)
105
{
106
    va_list ap;
107
    va_start(ap, fmt);
108
    vprintf(fmt, ap);
109
    va_end(ap);
110
    if (soft_token.flags.app_error_fatal)
111
	abort();
112
}
113
114
static void
115
st_logf(const char *fmt, ...)
116
{
117
    va_list ap;
118
    if (soft_token.logfile == NULL)
119
	return;
120
    va_start(ap, fmt);
121
    vfprintf(soft_token.logfile, fmt, ap);
122
    va_end(ap);
123
    fflush(soft_token.logfile);
124
}
125
126
static void
127
snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...)
128
{
129
    int len;
130
    va_list ap;
131
    len = vsnprintf(str, size, fmt, ap);
132
    va_end(ap);
133
    if (len < 0 || len > (int) size)
134
	return;
135
    while(len < (int) size)
136
	str[len++] = fillchar;
137
}
138
139
#ifndef TEST_APP
140
#define printf error_use_st_logf
141
#endif
142
143
#define VERIFY_SESSION_HANDLE(s, state)			\
144
{							\
145
    CK_RV ret;						\
146
    ret = verify_session_handle(s, state);		\
147
    if (ret != CKR_OK) {				\
148
	/* return CKR_OK */;				\
149
    }							\
150
}
151
152
static CK_RV
153
verify_session_handle(CK_SESSION_HANDLE hSession,
154
		      struct session_state **state)
155
{
156
    size_t i;
157
158
    for (i = 0; i < MAX_NUM_SESSION; i++){
159
	if (soft_token.state[i].session_handle == hSession)
160
	    break;
161
    }
162
    if (i == MAX_NUM_SESSION) {
163
	application_error("use of invalid handle: 0x%08lx\n",
164
			  (unsigned long)hSession);
165
	return CKR_SESSION_HANDLE_INVALID;
166
    }
167
    if (state)
168
	*state = &soft_token.state[i];
169
    return CKR_OK;
170
}
171
172
static CK_RV
173
object_handle_to_object(CK_OBJECT_HANDLE handle,
174
			struct st_object **object)
175
{
176
    int i = HANDLE_OBJECT_ID(handle);
177
178
    *object = NULL;
179
    if (i >= soft_token.object.num_objs)
180
	return CKR_ARGUMENTS_BAD;
181
    if (soft_token.object.objs[i] == NULL)
182
	return CKR_ARGUMENTS_BAD;
183
    if (soft_token.object.objs[i]->object_handle != handle)
184
	return CKR_ARGUMENTS_BAD;
185
    *object = soft_token.object.objs[i];
186
    return CKR_OK;
187
}
188
189
static int
190
attributes_match(const struct st_object *obj,
191
		 const CK_ATTRIBUTE *attributes,
192
		 CK_ULONG num_attributes)
193
{
194
    CK_ULONG i;
195
    int j;
196
    st_logf("attributes_match: %ld\n", (unsigned long)OBJECT_ID(obj));
197
198
    for (i = 0; i < num_attributes; i++) {
199
	int match = 0;
200
	for (j = 0; j < obj->num_attributes; j++) {
201
	    if (attributes[i].type == obj->attrs[j].attribute.type &&
202
		attributes[i].ulValueLen == obj->attrs[j].attribute.ulValueLen &&
203
		memcmp(attributes[i].pValue, obj->attrs[j].attribute.pValue,
204
		       attributes[i].ulValueLen) == 0) {
205
		match = 1;
206
		break;
207
	    }
208
	}
209
	if (match == 0) {
210
	    st_logf("type %d attribute have no match\n", attributes[i].type);
211
	    return 0;
212
	}
213
    }
214
    st_logf("attribute matches\n");
215
    return 1;
216
}
217
218
static void
219
print_attributes(const CK_ATTRIBUTE *attributes,
220
		 CK_ULONG num_attributes)
221
{
222
    CK_ULONG i;
223
224
    st_logf("find objects: attrs: %lu\n", (unsigned long)num_attributes);
225
226
    for (i = 0; i < num_attributes; i++) {
227
	st_logf("  type: ");
228
	switch (attributes[i].type) {
229
	case CKA_TOKEN: {
230
	    CK_BBOOL *ck_true;
231
	    if (attributes[i].ulValueLen != sizeof(CK_BBOOL)) {
232
		application_error("token attribute wrong length\n");
233
		break;
234
	    }
235
	    ck_true = attributes[i].pValue;
236
	    st_logf("token: %s", *ck_true ? "TRUE" : "FALSE");
237
	    break;
238
	}
239
	case CKA_CLASS: {
240
	    CK_OBJECT_CLASS *class;
241
	    if (attributes[i].ulValueLen != sizeof(CK_ULONG)) {
242
		application_error("class attribute wrong length\n");
243
		break;
244
	    }
245
	    class = attributes[i].pValue;
246
	    st_logf("class ");
247
	    switch (*class) {
248
	    case CKO_CERTIFICATE:
249
		st_logf("certificate");
250
		break;
251
	    case CKO_PUBLIC_KEY:
252
		st_logf("public key");
253
		break;
254
	    case CKO_PRIVATE_KEY:
255
		st_logf("private key");
256
		break;
257
	    case CKO_SECRET_KEY:
258
		st_logf("secret key");
259
		break;
260
	    case CKO_DOMAIN_PARAMETERS:
261
		st_logf("domain parameters");
262
		break;
263
	    default:
264
		st_logf("[class %lx]", (long unsigned)*class);
265
		break;
266
	    }
267
	    break;
268
	}
269
	case CKA_PRIVATE:
270
	    st_logf("private");
271
	    break;
272
	case CKA_LABEL:
273
	    st_logf("label");
274
	    break;
275
	case CKA_APPLICATION:
276
	    st_logf("application");
277
	    break;
278
	case CKA_VALUE:
279
	    st_logf("value");
280
	    break;
281
	case CKA_ID:
282
	    st_logf("id");
283
	    break;
284
	default:
285
	    st_logf("[unknown 0x%08lx]", (unsigned long)attributes[i].type);
286
	    break;
287
	}
288
	st_logf("\n");
289
    }
290
}
291
292
static struct st_object *
293
add_st_object(void)
294
{
295
    struct st_object *o, **objs;
296
    int i;
297
298
    o = malloc(sizeof(*o));
299
    if (o == NULL)
300
	return NULL;
301
    memset(o, 0, sizeof(*o));
302
    o->attrs = NULL;
303
    o->num_attributes = 0;
304
    
305
    for (i = 0; i < soft_token.object.num_objs; i++) {
306
	if (soft_token.object.objs == NULL) {
307
	    soft_token.object.objs[i] = o;
308
	    break;
309
	}
310
    }
311
    if (i == soft_token.object.num_objs) {
312
	objs = realloc(soft_token.object.objs,
313
		       (soft_token.object.num_objs + 1) * sizeof(soft_token.object.objs[0]));
314
	if (objs == NULL) {
315
	    free(o);
316
	    return NULL;
317
	}
318
	soft_token.object.objs = objs;
319
	soft_token.object.objs[soft_token.object.num_objs++] = o;
320
    }	
321
    soft_token.object.objs[i]->object_handle =
322
	(random() & (~OBJECT_ID_MASK)) | i;
323
324
    return o;
325
}
326
327
static CK_RV
328
add_object_attribute(struct st_object *o, 
329
		     int secret,
330
		     CK_ATTRIBUTE_TYPE type,
331
		     CK_VOID_PTR pValue,
332
		     CK_ULONG ulValueLen)
333
{
334
    struct st_attr *a;
335
    int i;
336
337
    i = o->num_attributes;
338
    a = realloc(o->attrs, (i + 1) * sizeof(o->attrs[0]));
339
    if (a == NULL)
340
	return CKR_DEVICE_MEMORY;
341
    o->attrs = a;
342
    o->attrs[i].secret = secret;
343
    o->attrs[i].attribute.type = type;
344
    o->attrs[i].attribute.pValue = malloc(ulValueLen);
345
    if (o->attrs[i].attribute.pValue == NULL && ulValueLen != 0)
346
	return CKR_DEVICE_MEMORY;
347
    memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen);
348
    o->attrs[i].attribute.ulValueLen = ulValueLen;
349
    o->num_attributes++;
350
351
    return CKR_OK;
352
}
353
354
static CK_RV
355
add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
356
{
357
    switch (key_type) {
358
    case CKK_RSA: {
359
	CK_BYTE *modulus = NULL;
360
	size_t modulus_len = 0;
361
	CK_ULONG modulus_bits = 0;
362
	CK_BYTE *exponent = NULL;
363
	size_t exponent_len = 0;
364
365
	modulus_bits = BN_num_bits(key->pkey.rsa->n);
366
367
	modulus_len = BN_num_bytes(key->pkey.rsa->n);
368
	modulus = malloc(modulus_len);
369
	BN_bn2bin(key->pkey.rsa->n, modulus);
370
	
371
	exponent_len = BN_num_bytes(key->pkey.rsa->e);
372
	exponent = malloc(exponent_len);
373
	BN_bn2bin(key->pkey.rsa->e, exponent);
374
	
375
	add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
376
	add_object_attribute(o, 0, CKA_MODULUS_BITS,
377
			     &modulus_bits, sizeof(modulus_bits));
378
	add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
379
			     exponent, exponent_len);
380
381
	RSA_set_method(key->pkey.rsa, RSA_PKCS1_SSLeay());
382
383
	free(modulus);
384
	free(exponent);
385
    }
386
    default:
387
	/* XXX */
388
	break;
389
    }
390
    return CKR_OK;
391
}
392
393
394
static int
395
pem_callback(char *buf, int num, int w, void *key)
396
{
397
    return -1;
398
}
399
400
401
static CK_RV
402
add_certificate(char *label,
403
		const char *cert_file,
404
		const char *private_key_file,
405
		char *id,
406
		int anchor)
407
{
408
    struct st_object *o = NULL;
409
    CK_BBOOL bool_true = CK_TRUE;
410
    CK_BBOOL bool_false = CK_FALSE;
411
    CK_OBJECT_CLASS c;
412
    CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
413
    CK_KEY_TYPE key_type;
414
    CK_MECHANISM_TYPE mech_type;
415
    void *cert_data = NULL;
416
    size_t cert_length;
417
    void *subject_data = NULL;
418
    size_t subject_length;
419
    void *issuer_data = NULL;
420
    size_t issuer_length;
421
    void *serial_data = NULL;
422
    size_t serial_length;
423
    CK_RV ret = CKR_GENERAL_ERROR;
424
    X509 *cert;
425
    EVP_PKEY *public_key;
426
427
    size_t id_len = strlen(id);
428
429
    {
430
	FILE *f;
431
	
432
	f = fopen(cert_file, "r");
433
	if (f == NULL) {
434
	    st_logf("failed to open file %s\n", cert_file);
435
	    return CKR_GENERAL_ERROR;
436
	}
437
438
	cert = PEM_read_X509(f, NULL, NULL, NULL);
439
	fclose(f);
440
	if (cert == NULL) {
441
	    st_logf("failed reading PEM cert\n");
442
	    return CKR_GENERAL_ERROR;
443
	}
444
445
	OPENSSL_ASN1_MALLOC_ENCODE(X509, cert_data, cert_length, cert, ret);
446
	if (ret)
447
	    goto out;
448
449
	OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, issuer_data, issuer_length, 
450
				   X509_get_issuer_name(cert), ret);
451
	if (ret)
452
	    goto out;
453
454
	OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, subject_data, subject_length, 
455
				   X509_get_subject_name(cert), ret);
456
	if (ret)
457
	    goto out;
458
459
	OPENSSL_ASN1_MALLOC_ENCODE(ASN1_INTEGER, serial_data, serial_length, 
460
				   X509_get_serialNumber(cert), ret);
461
	if (ret)
462
	    goto out;
463
464
    }
465
466
    st_logf("done parsing, adding to internal structure\n");
467
468
    o = add_st_object();
469
    if (o == NULL) {
470
	ret = CKR_DEVICE_MEMORY;
471
	goto out;
472
    }
473
    o->type = STO_T_CERTIFICATE;
474
    o->u.cert = cert;
475
    public_key = X509_get_pubkey(o->u.cert);
476
477
    switch (EVP_PKEY_type(public_key->type)) {
478
    case EVP_PKEY_RSA:
479
	key_type = CKK_RSA;
480
	break;
481
    case EVP_PKEY_DSA:
482
	key_type = CKK_DSA;
483
	break;
484
    default:
485
	/* XXX */
486
	break;
487
    }
488
489
    c = CKO_CERTIFICATE;
490
    add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
491
    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
492
    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
493
    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
494
    add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));
495
496
    add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type));
497
    add_object_attribute(o, 0, CKA_ID, id, id_len);
498
499
    add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
500
    add_object_attribute(o, 0, CKA_ISSUER, issuer_data, issuer_length);
501
    add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data, serial_length);
502
    add_object_attribute(o, 0, CKA_VALUE, cert_data, cert_length);
503
    if (anchor)
504
	add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));
505
    else
506
	add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false));
507
508
    st_logf("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o));
509
510
    o = add_st_object();
511
    if (o == NULL) {
512
	ret = CKR_DEVICE_MEMORY;
513
	goto out;
514
    }
515
    o->type = STO_T_PUBLIC_KEY;
516
    o->u.public_key = public_key;
517
518
    c = CKO_PUBLIC_KEY;
519
    add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
520
    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
521
    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
522
    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
523
    add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));
524
525
    add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
526
    add_object_attribute(o, 0, CKA_ID, id, id_len);
527
    add_object_attribute(o, 0, CKA_START_DATE, "", 1); /* XXX */
528
    add_object_attribute(o, 0, CKA_END_DATE, "", 1); /* XXX */
529
    add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
530
    add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
531
    mech_type = CKM_RSA_X_509;
532
    add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
533
534
    add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
535
    add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true));
536
    add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true));
537
    add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false));
538
    add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true));
539
    add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));
540
541
    add_pubkey_info(o, key_type, public_key);
542
543
    st_logf("add key ok: %lx\n", (unsigned long)OBJECT_ID(o));
544
545
    if (private_key_file) {
546
	CK_FLAGS flags;
547
	FILE *f;
548
549
	o = add_st_object();
550
	if (o == NULL) {
551
	    ret = CKR_DEVICE_MEMORY;
552
	    goto out;
553
	}
554
	o->type = STO_T_PRIVATE_KEY;
555
	o->u.private_key.file = strdup(private_key_file);
556
	o->u.private_key.key = NULL;
557
558
	o->u.private_key.cert = cert;
559
560
	c = CKO_PRIVATE_KEY;
561
	add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
562
	add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
563
	add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false));
564
	add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
565
	add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));
566
567
	add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
568
	add_object_attribute(o, 0, CKA_ID, id, id_len);
569
	add_object_attribute(o, 0, CKA_START_DATE, "", 1); /* XXX */
570
	add_object_attribute(o, 0, CKA_END_DATE, "", 1); /* XXX */
571
	add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
572
	add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
573
	mech_type = CKM_RSA_X_509;
574
	add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
575
576
	add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
577
	add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true));
578
	add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true));
579
	flags = 0;
580
	add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags));
581
582
	add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true));
583
	add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true));
584
	add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false));
585
	add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true));
586
	add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true));
587
	add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false));
588
589
	add_pubkey_info(o, key_type, public_key);
590
591
	f = fopen(private_key_file, "r");
592
	if (f == NULL) {
593
	    st_logf("failed to open private key\n");
594
	    return CKR_GENERAL_ERROR;
595
	}
596
597
	o->u.private_key.key = PEM_read_PrivateKey(f, NULL, pem_callback, NULL);
598
	fclose(f);
599
	if (o->u.private_key.key == NULL) {
600
	    st_logf("failed to read private key a startup\n");
601
	    /* don't bother with this failure for now, 
602
	       fix it at C_Login time */;
603
	} else {
604
	    /* XXX verify keytype */
605
606
	    if (key_type == CKK_RSA)
607
		RSA_set_method(o->u.private_key.key->pkey.rsa, 
608
			       RSA_PKCS1_SSLeay());
609
610
	    if (X509_check_private_key(cert, o->u.private_key.key) != 1) {
611
		EVP_PKEY_free(o->u.private_key.key);	    
612
		o->u.private_key.key = NULL;
613
		st_logf("private key doesn't verify\n");
614
	    } else {
615
		st_logf("private key usable\n");
616
		soft_token.flags.login_done = 1;
617
	    }
618
	}
619
    }
620
621
    ret = CKR_OK;
622
 out:
623
    if (ret != CKR_OK) {
624
	st_logf("something went wrong when adding cert!\n");
625
626
	/* XXX wack o */;
627
    }
628
    free(cert_data);
629
    free(serial_data);
630
    free(issuer_data);
631
    free(subject_data);
632
633
    return ret;
634
}
635
636
static void
637
find_object_final(struct session_state *state)
638
{
639
    if (state->find.attributes) {
640
	CK_ULONG i;
641
642
	for (i = 0; i < state->find.num_attributes; i++) {
643
	    if (state->find.attributes[i].pValue)
644
		free(state->find.attributes[i].pValue);
645
	}
646
	free(state->find.attributes);
647
	state->find.attributes = NULL;
648
	state->find.num_attributes = 0;
649
	state->find.next_object = -1;
650
    }
651
}
652
653
static void
654
reset_crypto_state(struct session_state *state)
655
{
656
    state->encrypt_object = -1;
657
    if (state->encrypt_mechanism)
658
	free(state->encrypt_mechanism);
659
    state->encrypt_mechanism = NULL_PTR;
660
    state->decrypt_object = -1;
661
    if (state->decrypt_mechanism)
662
	free(state->decrypt_mechanism);
663
    state->decrypt_mechanism = NULL_PTR;
664
    state->sign_object = -1;
665
    if (state->sign_mechanism)
666
	free(state->sign_mechanism);
667
    state->sign_mechanism = NULL_PTR;
668
    state->verify_object = -1;
669
    if (state->verify_mechanism)
670
	free(state->verify_mechanism);
671
    state->verify_mechanism = NULL_PTR;
672
    state->digest_object = -1;
673
}
674
675
static void
676
close_session(struct session_state *state)
677
{
678
    if (state->find.attributes) {
679
	application_error("application didn't do C_FindObjectsFinal\n");
680
	find_object_final(state);
681
    }
682
683
    state->session_handle = CK_INVALID_HANDLE;
684
    soft_token.application = NULL_PTR;
685
    soft_token.notify = NULL_PTR;
686
    reset_crypto_state(state);
687
}
688
689
static const char *
690
has_session(void)
691
{
692
    return soft_token.open_sessions > 0 ? "yes" : "no";
693
}
694
695
static void
696
read_conf_file(const char *fn)
697
{
698
    char buf[1024], *cert, *key, *id, *label, *s, *p;
699
    int anchor;
700
    FILE *f;
701
702
    f = fopen(fn, "r");
703
    if (f == NULL) {
704
	st_logf("can't open configuration file %s\n", fn);
705
	return;
706
    }
707
708
    while(fgets(buf, sizeof(buf), f) != NULL) {
709
	buf[strcspn(buf, "\n")] = '\0';
710
711
	anchor = 0;
712
713
	st_logf("line: %s\n", buf);
714
715
	p = buf;
716
	while (isspace(*p))
717
	    p++;
718
	if (*p == '#')
719
	    continue;
720
	while (isspace(*p))
721
	    p++;
722
723
	s = NULL;
724
	id = strtok_r(p, "\t", &s);
725
	if (id == NULL)
726
	    continue;
727
	label = strtok_r(NULL, "\t", &s);
728
	if (label == NULL)
729
	    continue;
730
	cert = strtok_r(NULL, "\t", &s);
731
	if (cert == NULL)
732
	    continue;
733
	key = strtok_r(NULL, "\t", &s);
734
735
	/* XXX */
736
	if (strcmp(id, "anchor") == 0) {
737
	    id = "\x00\x00";
738
	    anchor = 1;
739
	}
740
741
	st_logf("adding: %s\n", label);
742
743
	add_certificate(label, cert, key, id, anchor);
744
    }
745
}
746
747
static CK_RV
748
func_not_supported(void)
749
{
750
    st_logf("function not supported\n");
751
    return CKR_FUNCTION_NOT_SUPPORTED;
752
}
753
754
CK_RV
755
C_Initialize(CK_VOID_PTR a)
756
{
757
    CK_C_INITIALIZE_ARGS_PTR args = a;
758
    st_logf("Initialize\n");
759
    size_t i;
760
761
    OpenSSL_add_all_algorithms();
762
    ERR_load_crypto_strings();
763
764
    srandom(getpid() ^ time(NULL));
765
766
    for (i = 0; i < MAX_NUM_SESSION; i++) {
767
	soft_token.state[i].session_handle = CK_INVALID_HANDLE;
768
	soft_token.state[i].find.attributes = NULL;
769
	soft_token.state[i].find.num_attributes = 0;
770
	soft_token.state[i].find.next_object = -1;
771
	reset_crypto_state(&soft_token.state[i]);
772
    }
773
774
    soft_token.flags.hardware_slot = 1;
775
    soft_token.flags.app_error_fatal = 0;
776
    soft_token.flags.login_done = 0;
777
778
    soft_token.object.objs = NULL;
779
    soft_token.object.num_objs = 0;
780
    
781
    soft_token.logfile = NULL;
782
#if 1
783
//     soft_token.logfile = stdout;
784
#endif
785
#if 0
786
    soft_token.logfile = fopen("/tmp/log-pkcs11.txt", "a");
787
#endif
788
789
    if (a != NULL_PTR) {
790
	st_logf("\tCreateMutex:\t%p\n", args->CreateMutex);
791
	st_logf("\tDestroyMutext\t%p\n", args->DestroyMutex);
792
	st_logf("\tLockMutext\t%p\n", args->LockMutex);
793
	st_logf("\tUnlockMutext\t%p\n", args->UnlockMutex);
794
	st_logf("\tFlags\t%04x\n", (unsigned int)args->flags);
795
    }
796
797
    {
798
	char *fn = NULL, *home = NULL;
799
800
	if (getuid() == geteuid()) {
801
	    fn = getenv("SOFTPKCS11RC");
802
	    if (fn)
803
		fn = strdup(fn);
804
	    home = getenv("HOME");
805
	}
806
	if (fn == NULL && home == NULL) {
807
	    struct passwd *pw = getpwuid(getuid());	
808
	    if(pw != NULL)
809
		home = pw->pw_dir;
810
	}
811
	if (fn == NULL) {
812
	    if (home)
813
		asprintf(&fn, "%s/.soft-token.rc", home);
814
	    else
815
		fn = strdup("/etc/soft-token.rc");
816
	}
817
818
	read_conf_file(fn);
819
	free(fn);
820
    }
821
822
    return CKR_OK;
823
}
824
825
CK_RV
826
C_Finalize(CK_VOID_PTR args)
827
{
828
    size_t i;
829
830
    st_logf("Finalize\n");
831
832
    for (i = 0; i < MAX_NUM_SESSION; i++) {
833
	if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) {
834
	    application_error("application finalized without "
835
			      "closing session\n");
836
	    close_session(&soft_token.state[i]);
837
	}
838
    }
839
840
    return CKR_OK;
841
}
842
843
CK_RV
844
C_GetInfo(CK_INFO_PTR args)
845
{
846
    st_logf("GetInfo\n");
847
848
    memset(args, 17, sizeof(*args));
849
    args->cryptokiVersion.major = 2;
850
    args->cryptokiVersion.minor = 10;
851
    snprintf_fill((char *)args->manufacturerID, 
852
		  sizeof(args->manufacturerID),
853
		  ' ',
854
		  "SoftToken");
855
    snprintf_fill((char *)args->libraryDescription, 
856
		  sizeof(args->libraryDescription), ' ',
857
		  "SoftToken");
858
    args->libraryVersion.major = 1;
859
    args->libraryVersion.minor = 8;
860
861
    return CKR_OK;
862
}
863
864
extern CK_FUNCTION_LIST funcs;
865
866
CK_RV
867
C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
868
{
869
    *ppFunctionList = &funcs;
870
    return CKR_OK;
871
}
872
873
CK_RV
874
C_GetSlotList(CK_BBOOL tokenPresent,
875
	      CK_SLOT_ID_PTR pSlotList,
876
	      CK_ULONG_PTR   pulCount)
877
{
878
    st_logf("GetSlotList: %s\n",
879
	    tokenPresent ? "tokenPresent" : "token not Present");
880
    if (pSlotList)
881
	pSlotList[0] = 1;
882
    *pulCount = 1;
883
    return CKR_OK;
884
}
885
886
CK_RV
887
C_GetSlotInfo(CK_SLOT_ID slotID,
888
	      CK_SLOT_INFO_PTR pInfo)
889
{
890
    st_logf("GetSlotInfo: slot: %d : %s\n", (int)slotID, has_session());
891
892
    memset(pInfo, 18, sizeof(*pInfo));
893
894
    if (slotID != 1)
895
	return CKR_ARGUMENTS_BAD;
896
897
    snprintf_fill((char *)pInfo->slotDescription, 
898
		  sizeof(pInfo->slotDescription),
899
		  ' ',
900
		  "SoftToken (slot)");
901
    snprintf_fill((char *)pInfo->manufacturerID,
902
		  sizeof(pInfo->manufacturerID),
903
		  ' ',
904
		  "SoftToken (slot)");
905
    pInfo->flags = CKF_TOKEN_PRESENT;
906
    if (soft_token.flags.hardware_slot)
907
	pInfo->flags |= CKF_HW_SLOT;
908
    pInfo->hardwareVersion.major = 1;
909
    pInfo->hardwareVersion.minor = 0;
910
    pInfo->firmwareVersion.major = 1;
911
    pInfo->firmwareVersion.minor = 0;
912
    
913
    return CKR_OK;
914
}
915
916
CK_RV
917
C_GetTokenInfo(CK_SLOT_ID slotID,
918
	       CK_TOKEN_INFO_PTR pInfo)
919
{
920
    st_logf("GetTokenInfo: %s\n", has_session()); 
921
922
    memset(pInfo, 19, sizeof(*pInfo));
923
924
    snprintf_fill((char *)pInfo->label, 
925
		  sizeof(pInfo->label),
926
		  ' ',
927
		  "SoftToken (token)");
928
    snprintf_fill((char *)pInfo->manufacturerID, 
929
		  sizeof(pInfo->manufacturerID),
930
		  ' ',
931
		  "SoftToken (token)");
932
    snprintf_fill((char *)pInfo->model,
933
		  sizeof(pInfo->model),
934
		  ' ',
935
		  "SoftToken (token)");
936
    snprintf_fill((char *)pInfo->serialNumber, 
937
		  sizeof(pInfo->serialNumber),
938
		  ' ',
939
		  "4711");
940
    pInfo->flags = 
941
	CKF_TOKEN_INITIALIZED | 
942
	CKF_USER_PIN_INITIALIZED;
943
944
    if (soft_token.flags.login_done == 0)
945
	pInfo->flags |= CKF_LOGIN_REQUIRED;
946
947
    /* CFK_RNG |
948
       CKF_RESTORE_KEY_NOT_NEEDED |
949
    */
950
    pInfo->ulMaxSessionCount = MAX_NUM_SESSION;
951
    pInfo->ulSessionCount = soft_token.open_sessions;
952
    pInfo->ulMaxRwSessionCount = MAX_NUM_SESSION;
953
    pInfo->ulRwSessionCount = soft_token.open_sessions;
954
    pInfo->ulMaxPinLen = 1024;
955
    pInfo->ulMinPinLen = 0;
956
    pInfo->ulTotalPublicMemory = 4711;
957
    pInfo->ulFreePublicMemory = 4712;
958
    pInfo->ulTotalPrivateMemory = 4713;
959
    pInfo->ulFreePrivateMemory = 4714;
960
    pInfo->hardwareVersion.major = 2;
961
    pInfo->hardwareVersion.minor = 0;
962
    pInfo->firmwareVersion.major = 2;
963
    pInfo->firmwareVersion.minor = 0;
964
965
    return CKR_OK;
966
}
967
968
CK_RV
969
C_GetMechanismList(CK_SLOT_ID slotID,
970
		   CK_MECHANISM_TYPE_PTR pMechanismList,
971
		   CK_ULONG_PTR pulCount)
972
{
973
    st_logf("GetMechanismList\n");
974
975
    *pulCount = 2;
976
    if (pMechanismList == NULL_PTR)
977
	return CKR_OK;
978
    pMechanismList[0] = CKM_RSA_X_509;
979
    pMechanismList[1] = CKM_RSA_PKCS;
980
981
    return CKR_OK;
982
}
983
984
CK_RV
985
C_GetMechanismInfo(CK_SLOT_ID slotID,
986
		   CK_MECHANISM_TYPE type,
987
		   CK_MECHANISM_INFO_PTR pInfo)
988
{
989
    st_logf("GetMechanismInfo: slot %d type: %d\n",
990
	    (int)slotID, (int)type);
991
    return CKR_FUNCTION_NOT_SUPPORTED;
992
}
993
994
CK_RV
995
C_InitToken(CK_SLOT_ID slotID,
996
	    CK_UTF8CHAR_PTR pPin,
997
	    CK_ULONG ulPinLen,
998
	    CK_UTF8CHAR_PTR pLabel)
999
{
1000
    st_logf("InitToken: slot %d\n", (int)slotID);
1001
    return CKR_FUNCTION_NOT_SUPPORTED;
1002
}
1003
1004
CK_RV
1005
C_OpenSession(CK_SLOT_ID slotID,
1006
	      CK_FLAGS flags,
1007
	      CK_VOID_PTR pApplication,
1008
	      CK_NOTIFY Notify,
1009
	      CK_SESSION_HANDLE_PTR phSession)
1010
{
1011
    size_t i;
1012
1013
    st_logf("OpenSession: slot: %d\n", (int)slotID);
1014
    
1015
    if (soft_token.open_sessions == MAX_NUM_SESSION)
1016
	return CKR_SESSION_COUNT;
1017
1018
    soft_token.application = pApplication;
1019
    soft_token.notify = Notify;
1020
1021
    for (i = 0; i < MAX_NUM_SESSION; i++)
1022
	if (soft_token.state[i].session_handle == CK_INVALID_HANDLE)
1023
	    break;
1024
    if (i == MAX_NUM_SESSION)
1025
	abort();
1026
1027
    soft_token.open_sessions++;
1028
1029
    soft_token.state[i].session_handle =
1030
	(CK_SESSION_HANDLE)(random() & 0xfffff);
1031
    *phSession = soft_token.state[i].session_handle;
1032
1033
    return CKR_OK;
1034
}
1035
1036
CK_RV
1037
C_CloseSession(CK_SESSION_HANDLE hSession)
1038
{
1039
    struct session_state *state;
1040
    st_logf("CloseSession\n");
1041
1042
    if (verify_session_handle(hSession, &state) != CKR_OK)
1043
	application_error("closed session not open");
1044
    else
1045
	close_session(state);
1046
1047
    return CKR_OK;
1048
}
1049
1050
CK_RV
1051
C_CloseAllSessions(CK_SLOT_ID slotID)
1052
{
1053
    size_t i;
1054
1055
    st_logf("CloseAllSessions\n");
1056
1057
    for (i = 0; i < MAX_NUM_SESSION; i++)
1058
	if (soft_token.state[i].session_handle != CK_INVALID_HANDLE)
1059
	    close_session(&soft_token.state[i]);
1060
1061
    return CKR_OK;
1062
}
1063
1064
CK_RV
1065
C_GetSessionInfo(CK_SESSION_HANDLE hSession,
1066
		 CK_SESSION_INFO_PTR pInfo)
1067
{
1068
    st_logf("GetSessionInfo\n");
1069
    
1070
    VERIFY_SESSION_HANDLE(hSession, NULL);
1071
1072
    memset(pInfo, 20, sizeof(*pInfo));
1073
1074
    pInfo->slotID = 1;
1075
    if (soft_token.flags.login_done)
1076
	pInfo->state = CKS_RO_USER_FUNCTIONS;
1077
    else
1078
	pInfo->state = CKS_RO_PUBLIC_SESSION;
1079
    pInfo->flags = CKF_SERIAL_SESSION;
1080
    pInfo->ulDeviceError = 0;
1081
1082
    return CKR_OK;
1083
}
1084
1085
CK_RV
1086
C_Login(CK_SESSION_HANDLE hSession,
1087
	CK_USER_TYPE userType,
1088
	CK_UTF8CHAR_PTR pPin,
1089
	CK_ULONG ulPinLen)
1090
{
1091
    char *pin = NULL;
1092
    int i;
1093
1094
    st_logf("Login\n");
1095
1096
    VERIFY_SESSION_HANDLE(hSession, NULL);
1097
1098
    if (pPin != NULL_PTR) {
1099
	asprintf(&pin, "%.*s", (int)ulPinLen, pPin);
1100
	st_logf("type: %d password: %s\n", (int)userType, pin);
1101
    }
1102
1103
    for (i = 0; i < soft_token.object.num_objs; i++) {
1104
	struct st_object *o = soft_token.object.objs[i];
1105
	FILE *f;
1106
1107
	if (o->type != STO_T_PRIVATE_KEY)
1108
	    continue;
1109
1110
	if (o->u.private_key.key)
1111
	    continue;
1112
1113
	f = fopen(o->u.private_key.file, "r");
1114
	if (f == NULL) {
1115
	    st_logf("can't open private file: %s\n", o->u.private_key.file);
1116
	    continue;
1117
	}
1118
	
1119
	o->u.private_key.key = PEM_read_PrivateKey(f, NULL, NULL, pin);
1120
	fclose(f);
1121
	if (o->u.private_key.key == NULL) {
1122
	    st_logf("failed to read key: %s error: %s\n",
1123
		    o->u.private_key.file, 
1124
		    ERR_error_string(ERR_get_error(), NULL));
1125
	    /* just ignore failure */;
1126
	    continue;
1127
	}
1128
1129
	/* XXX check keytype */
1130
	RSA_set_method(o->u.private_key.key->pkey.rsa, RSA_PKCS1_SSLeay());
1131
1132
	if (X509_check_private_key(o->u.private_key.cert, o->u.private_key.key) != 1) {
1133
	    EVP_PKEY_free(o->u.private_key.key);	    
1134
	    o->u.private_key.key = NULL;
1135
	    st_logf("private key %s doesn't verify\n", o->u.private_key.file);
1136
	    continue;
1137
	}
1138
1139
	soft_token.flags.login_done = 1;
1140
    }
1141
    free(pin);
1142
    
1143
    return soft_token.flags.login_done ? CKR_OK : CKR_PIN_INCORRECT;
1144
}
1145
1146
CK_RV
1147
C_Logout(CK_SESSION_HANDLE hSession)
1148
{
1149
    st_logf("Logout\n");
1150
    VERIFY_SESSION_HANDLE(hSession, NULL);
1151
    return CKR_FUNCTION_NOT_SUPPORTED;
1152
}
1153
1154
CK_RV
1155
C_GetObjectSize(CK_SESSION_HANDLE hSession,
1156
		CK_OBJECT_HANDLE hObject,
1157
		CK_ULONG_PTR pulSize)
1158
{
1159
    st_logf("GetObjectSize\n");
1160
    VERIFY_SESSION_HANDLE(hSession, NULL);
1161
    return CKR_FUNCTION_NOT_SUPPORTED;
1162
}
1163
1164
CK_RV
1165
C_GetAttributeValue(CK_SESSION_HANDLE hSession,
1166
		    CK_OBJECT_HANDLE hObject,
1167
		    CK_ATTRIBUTE_PTR pTemplate,
1168
		    CK_ULONG ulCount)
1169
{
1170
    struct session_state *state;
1171
    struct st_object *obj;
1172
    CK_ULONG i;
1173
    CK_RV ret;
1174
    int j;
1175
1176
    st_logf("GetAttributeValue: %lx\n",
1177
	    (unsigned long)HANDLE_OBJECT_ID(hObject));
1178
    VERIFY_SESSION_HANDLE(hSession, &state);
1179
1180
    if ((ret = object_handle_to_object(hObject, &obj)) != CKR_OK) {
1181
	st_logf("object not found: %lx\n",
1182
		(unsigned long)HANDLE_OBJECT_ID(hObject));
1183
	return ret;
1184
    }
1185
1186
    ret = CKR_OK;
1187
    for (i = 0; i < ulCount; i++) {
1188
	st_logf("	getting 0x%08lx\n", (unsigned long)pTemplate[i].type);
1189
	for (j = 0; j < obj->num_attributes; j++) {
1190
	    if (obj->attrs[j].secret) {
1191
		pTemplate[i].ulValueLen = (CK_ULONG)-1;
1192
		break;
1193
	    }
1194
	    if (pTemplate[i].type == obj->attrs[j].attribute.type) {
1195
		if (pTemplate[i].pValue != NULL_PTR && obj->attrs[j].secret == 0) {
1196
		    if (pTemplate[i].ulValueLen >= obj->attrs[j].attribute.ulValueLen)
1197
			memcpy(pTemplate[i].pValue, obj->attrs[j].attribute.pValue,
1198
			       obj->attrs[j].attribute.ulValueLen);
1199
		}
1200
		pTemplate[i].ulValueLen = obj->attrs[j].attribute.ulValueLen;
1201
		break;
1202
	    }
1203
	}
1204
	if (j == obj->num_attributes) {
1205
	    st_logf("key type: 0x%08lx not found\n", (unsigned long)pTemplate[i].type);
1206
	    pTemplate[i].ulValueLen = (CK_ULONG)-1;
1207
            ret = CKR_ATTRIBUTE_TYPE_INVALID;
1208
	}
1209
1210
    }
1211
    return ret;
1212
}
1213
1214
CK_RV
1215
C_FindObjectsInit(CK_SESSION_HANDLE hSession,
1216
		  CK_ATTRIBUTE_PTR pTemplate,
1217
		  CK_ULONG ulCount)
1218
{
1219
    struct session_state *state;
1220
1221
    st_logf("FindObjectsInit\n");
1222
1223
    VERIFY_SESSION_HANDLE(hSession, &state);
1224
1225
    if (state->find.next_object != -1) {
1226
	application_error("application didn't do C_FindObjectsFinal\n");
1227
	find_object_final(state);
1228
    }
1229
    if (ulCount) {
1230
	CK_ULONG i;
1231
1232
	print_attributes(pTemplate, ulCount);
1233
1234
	state->find.attributes = 
1235
	    calloc(1, ulCount * sizeof(state->find.attributes[0]));
1236
	if (state->find.attributes == NULL)
1237
	    return CKR_DEVICE_MEMORY;
1238
	for (i = 0; i < ulCount; i++) {
1239
	    state->find.attributes[i].pValue = 
1240
		malloc(pTemplate[i].ulValueLen);
1241
	    if (state->find.attributes[i].pValue == NULL) {
1242
		find_object_final(state);
1243
		return CKR_DEVICE_MEMORY;
1244
	    }
1245
	    memcpy(state->find.attributes[i].pValue,
1246
		   pTemplate[i].pValue, pTemplate[i].ulValueLen);
1247
	    state->find.attributes[i].type = pTemplate[i].type;
1248
	    state->find.attributes[i].ulValueLen = pTemplate[i].ulValueLen;
1249
	}
1250
	state->find.num_attributes = ulCount;
1251
	state->find.next_object = 0;
1252
    } else {
1253
	st_logf("find all objects\n");
1254
	state->find.attributes = NULL;
1255
	state->find.num_attributes = 0;
1256
	state->find.next_object = 0;
1257
    }
1258
1259
    return CKR_OK;
1260
}
1261
1262
CK_RV
1263
C_FindObjects(CK_SESSION_HANDLE hSession,
1264
	      CK_OBJECT_HANDLE_PTR phObject,
1265
	      CK_ULONG ulMaxObjectCount,
1266
	      CK_ULONG_PTR pulObjectCount)
1267
{
1268
    struct session_state *state;
1269
    int i;
1270
1271
    st_logf("FindObjects\n");
1272
1273
    VERIFY_SESSION_HANDLE(hSession, &state);
1274
1275
    if (state->find.next_object == -1) {
1276
	application_error("application didn't do C_FindObjectsInit\n");
1277
	return CKR_ARGUMENTS_BAD;
1278
    }
1279
    if (ulMaxObjectCount == 0) {
1280
	application_error("application asked for 0 objects\n");
1281
	return CKR_ARGUMENTS_BAD;
1282
    }
1283
    *pulObjectCount = 0;
1284
    for (i = state->find.next_object; i < soft_token.object.num_objs; i++) {
1285
	st_logf("FindObjects: %d\n", i);
1286
	state->find.next_object = i + 1;
1287
	if (attributes_match(soft_token.object.objs[i],
1288
			     state->find.attributes,
1289
			     state->find.num_attributes)) {
1290
	    *phObject++ = soft_token.object.objs[i]->object_handle;
1291
	    ulMaxObjectCount--;
1292
	    (*pulObjectCount)++;
1293
	    if (ulMaxObjectCount == 0)
1294
		break;
1295
	}
1296
    }
1297
    return CKR_OK;
1298
}
1299
1300
CK_RV
1301
C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
1302
{
1303
    struct session_state *state;
1304
1305
    st_logf("FindObjectsFinal\n");
1306
    VERIFY_SESSION_HANDLE(hSession, &state);
1307
    find_object_final(state);
1308
    return CKR_OK;
1309
}
1310
1311
static CK_RV
1312
commonInit(CK_ATTRIBUTE *attr_match, int attr_match_len,
1313
	   const CK_MECHANISM_TYPE *mechs, int mechs_len,
1314
	   const CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey,
1315
	   struct st_object **o)
1316
{
1317
    CK_RV ret;
1318
    int i;
1319
1320
    *o = NULL;
1321
    if ((ret = object_handle_to_object(hKey, o)) != CKR_OK)
1322
	return ret;
1323
1324
    ret = attributes_match(*o, attr_match, attr_match_len);
1325
    if (!ret) {
1326
	application_error("called commonInit on key that doesn't "
1327
			  "support required attr");
1328
	return CKR_ARGUMENTS_BAD;
1329
    }
1330
1331
    for (i = 0; i < mechs_len; i++)
1332
	if (mechs[i] == pMechanism->mechanism)
1333
	    break;
1334
    if (i == mechs_len) {
1335
	application_error("called mech (%08lx) not supported\n",
1336
			  pMechanism->mechanism);
1337
	return CKR_ARGUMENTS_BAD;
1338
    }
1339
    return CKR_OK;
1340
}
1341
1342
1343
static CK_RV
1344
dup_mechanism(CK_MECHANISM_PTR *dup, const CK_MECHANISM_PTR pMechanism)
1345
{
1346
    CK_MECHANISM_PTR p;
1347
1348
    p = malloc(sizeof(*p));
1349
    if (p == NULL)
1350
	return CKR_DEVICE_MEMORY;
1351
1352
    if (*dup)
1353
	free(*dup);
1354
    *dup = p;
1355
    memcpy(p, pMechanism, sizeof(*p));
1356
1357
    return CKR_OK;
1358
}
1359
1360
1361
CK_RV
1362
C_EncryptInit(CK_SESSION_HANDLE hSession,
1363
	      CK_MECHANISM_PTR pMechanism,
1364
	      CK_OBJECT_HANDLE hKey)
1365
{
1366
    struct session_state *state;
1367
    CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 };
1368
    CK_BBOOL bool_true = CK_TRUE;
1369
    CK_ATTRIBUTE attr[] = {
1370
	{ CKA_ENCRYPT, &bool_true, sizeof(bool_true) }
1371
    };
1372
    struct st_object *o;
1373
    CK_RV ret;
1374
1375
    st_logf("EncryptInit\n");
1376
    VERIFY_SESSION_HANDLE(hSession, &state);
1377
    
1378
    ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), 
1379
		     mechs, sizeof(mechs)/sizeof(mechs[0]),
1380
		     pMechanism, hKey, &o);
1381
    if (ret)
1382
	return ret;
1383
1384
    ret = dup_mechanism(&state->encrypt_mechanism, pMechanism);
1385
    if (ret == CKR_OK) 
1386
	state->encrypt_object = OBJECT_ID(o);
1387
			
1388
    return ret;
1389
}
1390
1391
CK_RV
1392
C_Encrypt(CK_SESSION_HANDLE hSession,
1393
	  CK_BYTE_PTR pData,
1394
	  CK_ULONG ulDataLen,
1395
	  CK_BYTE_PTR pEncryptedData,
1396
	  CK_ULONG_PTR pulEncryptedDataLen)
1397
{
1398
    struct session_state *state;
1399
    struct st_object *o;
1400
    void *buffer = NULL;
1401
    CK_RV ret;
1402
    RSA *rsa;
1403
    int padding, len, buffer_len, padding_len;
1404
1405
    st_logf("Encrypt\n");
1406
1407
    VERIFY_SESSION_HANDLE(hSession, &state);
1408
1409
    if (state->encrypt_object == -1)
1410
	return CKR_ARGUMENTS_BAD;
1411
1412
    o = soft_token.object.objs[state->encrypt_object];
1413
1414
    if (o->u.public_key == NULL) {
1415
	st_logf("public key NULL\n");
1416
	return CKR_ARGUMENTS_BAD;
1417
    }
1418
1419
    rsa = o->u.public_key->pkey.rsa;
1420
1421
    if (rsa == NULL)
1422
	return CKR_ARGUMENTS_BAD;
1423
1424
    RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
1425
1426
    buffer_len = RSA_size(rsa);
1427
1428
    buffer = malloc(buffer_len);
1429
    if (buffer == NULL) {
1430
	ret = CKR_DEVICE_MEMORY;
1431
	goto out;
1432
    }
1433
1434
    ret = CKR_OK;
1435
    switch(state->encrypt_mechanism->mechanism) {
1436
    case CKM_RSA_PKCS:
1437
	padding = RSA_PKCS1_PADDING;
1438
	padding_len = RSA_PKCS1_PADDING_SIZE;
1439
	break;
1440
    case CKM_RSA_X_509:
1441
	padding = RSA_NO_PADDING;
1442
	padding_len = 0;
1443
	break;
1444
    default:
1445
	ret = CKR_FUNCTION_NOT_SUPPORTED;
1446
	goto out;
1447
    }
1448
1449
    if (buffer_len + padding_len < (long) ulDataLen) {
1450
	ret = CKR_ARGUMENTS_BAD;
1451
	goto out;
1452
    }
1453
1454
    if (pulEncryptedDataLen == NULL) {
1455
	st_logf("pulEncryptedDataLen NULL\n");
1456
	ret = CKR_ARGUMENTS_BAD;
1457
	goto out;
1458
    }
1459
1460
    if (pData == NULL_PTR) {
1461
	st_logf("data NULL\n");
1462
	ret = CKR_ARGUMENTS_BAD;
1463
	goto out;
1464
    }
1465
1466
    len = RSA_public_encrypt(ulDataLen, pData, buffer, rsa, padding);
1467
    if (len <= 0) {
1468
	ret = CKR_DEVICE_ERROR;
1469
	goto out;
1470
    }
1471
    if (len > buffer_len)
1472
	abort();
1473
	
1474
    if (pEncryptedData != NULL_PTR)
1475
	memcpy(pEncryptedData, buffer, len);
1476
    *pulEncryptedDataLen = len;
1477
1478
 out:
1479
    if (buffer) {
1480
	memset(buffer, 0, buffer_len);
1481
	free(buffer);
1482
    }
1483
    return ret;
1484
}
1485
1486
CK_RV
1487
C_EncryptUpdate(CK_SESSION_HANDLE hSession,
1488
		CK_BYTE_PTR pPart,
1489
		CK_ULONG ulPartLen,
1490
		CK_BYTE_PTR pEncryptedPart,
1491
		CK_ULONG_PTR pulEncryptedPartLen)
1492
{
1493
    st_logf("EncryptUpdate\n");
1494
    VERIFY_SESSION_HANDLE(hSession, NULL);
1495
    return CKR_FUNCTION_NOT_SUPPORTED;
1496
}
1497
1498
1499
CK_RV
1500
C_EncryptFinal(CK_SESSION_HANDLE hSession,
1501
	       CK_BYTE_PTR pLastEncryptedPart,
1502
	       CK_ULONG_PTR pulLastEncryptedPartLen)
1503
{
1504
    st_logf("EncryptFinal\n");
1505
    VERIFY_SESSION_HANDLE(hSession, NULL);
1506
    return CKR_FUNCTION_NOT_SUPPORTED;
1507
}
1508
1509
1510
/* C_DecryptInit initializes a decryption operation. */
1511
CK_RV
1512
C_DecryptInit(CK_SESSION_HANDLE hSession,
1513
	      CK_MECHANISM_PTR pMechanism,
1514
	      CK_OBJECT_HANDLE hKey)
1515
{
1516
    struct session_state *state;
1517
    CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 };
1518
    CK_BBOOL bool_true = CK_TRUE;
1519
    CK_ATTRIBUTE attr[] = {
1520
	{ CKA_DECRYPT, &bool_true, sizeof(bool_true) }
1521
    };
1522
    struct st_object *o;
1523
    CK_RV ret;
1524
1525
    st_logf("DecryptInit\n");
1526
    VERIFY_SESSION_HANDLE(hSession, &state);
1527
    
1528
    ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), 
1529
		     mechs, sizeof(mechs)/sizeof(mechs[0]),
1530
		     pMechanism, hKey, &o);
1531
    if (ret)
1532
	return ret;
1533
1534
    ret = dup_mechanism(&state->decrypt_mechanism, pMechanism);
1535
    if (ret == CKR_OK) 
1536
	state->decrypt_object = OBJECT_ID(o);
1537
1538
    return CKR_OK;
1539
}
1540
1541
1542
CK_RV
1543
C_Decrypt(CK_SESSION_HANDLE hSession,
1544
	  CK_BYTE_PTR       pEncryptedData,
1545
	  CK_ULONG          ulEncryptedDataLen,
1546
	  CK_BYTE_PTR       pData,
1547
	  CK_ULONG_PTR      pulDataLen)
1548
{
1549
    struct session_state *state;
1550
    struct st_object *o;
1551
    void *buffer = NULL;
1552
    CK_RV ret;
1553
    RSA *rsa;
1554
    int padding, len, buffer_len, padding_len;
1555
1556
    st_logf("Decrypt\n");
1557
1558
    VERIFY_SESSION_HANDLE(hSession, &state);
1559
1560
    if (state->decrypt_object == -1)
1561
	return CKR_ARGUMENTS_BAD;
1562
1563
    o = soft_token.object.objs[state->decrypt_object];
1564
1565
    if (o->u.private_key.key == NULL) {
1566
	st_logf("private key NULL\n");
1567
	return CKR_ARGUMENTS_BAD;
1568
    }
1569
1570
    rsa = o->u.private_key.key->pkey.rsa;
1571
1572
    if (rsa == NULL)
1573
	return CKR_ARGUMENTS_BAD;
1574
1575
    RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
1576
1577
    buffer_len = RSA_size(rsa);
1578
1579
    buffer = malloc(buffer_len);
1580
    if (buffer == NULL) {
1581
	ret = CKR_DEVICE_MEMORY;
1582
	goto out;
1583
    }
1584
1585
    ret = CKR_OK;
1586
    switch(state->decrypt_mechanism->mechanism) {
1587
    case CKM_RSA_PKCS:
1588
	padding = RSA_PKCS1_PADDING;
1589
	padding_len = RSA_PKCS1_PADDING_SIZE;
1590
	break;
1591
    case CKM_RSA_X_509:
1592
	padding = RSA_NO_PADDING;
1593
	padding_len = 0;
1594
	break;
1595
    default:
1596
	ret = CKR_FUNCTION_NOT_SUPPORTED;
1597
	goto out;
1598
    }
1599
1600
    if (buffer_len + padding_len < (long) ulEncryptedDataLen) {
1601
	ret = CKR_ARGUMENTS_BAD;
1602
	goto out;
1603
    }
1604
1605
    if (pulDataLen == NULL) {
1606
	st_logf("pulDataLen NULL\n");
1607
	ret = CKR_ARGUMENTS_BAD;
1608
	goto out;
1609
    }
1610
1611
    if (pEncryptedData == NULL_PTR) {
1612
	st_logf("data NULL\n");
1613
	ret = CKR_ARGUMENTS_BAD;
1614
	goto out;
1615
    }
1616
1617
    len = RSA_private_decrypt(ulEncryptedDataLen, pEncryptedData, buffer, 
1618
			      rsa, padding);
1619
    if (len <= 0) {
1620
	ret = CKR_DEVICE_ERROR;
1621
	goto out;
1622
    }
1623
    if (len > buffer_len)
1624
	abort();
1625
	
1626
    if (pData != NULL_PTR)
1627
	memcpy(pData, buffer, len);
1628
    *pulDataLen = len;
1629
1630
 out:
1631
    if (buffer) {
1632
	memset(buffer, 0, buffer_len);
1633
	free(buffer);
1634
    }
1635
    return ret;
1636
}
1637
1638
1639
CK_RV
1640
C_DecryptUpdate(CK_SESSION_HANDLE hSession,
1641
		CK_BYTE_PTR pEncryptedPart,
1642
		CK_ULONG ulEncryptedPartLen,
1643
		CK_BYTE_PTR pPart,
1644
		CK_ULONG_PTR pulPartLen)
1645
1646
{
1647
    st_logf("DecryptUpdate\n");
1648
    VERIFY_SESSION_HANDLE(hSession, NULL);
1649
    return CKR_FUNCTION_NOT_SUPPORTED;
1650
}
1651
1652
1653
CK_RV
1654
C_DecryptFinal(CK_SESSION_HANDLE hSession,
1655
	       CK_BYTE_PTR pLastPart,
1656
	       CK_ULONG_PTR pulLastPartLen)
1657
{
1658
    st_logf("DecryptFinal\n");
1659
    VERIFY_SESSION_HANDLE(hSession, NULL);
1660
    return CKR_FUNCTION_NOT_SUPPORTED;
1661
}
1662
1663
CK_RV
1664
C_DigestInit(CK_SESSION_HANDLE hSession,
1665
	     CK_MECHANISM_PTR pMechanism)
1666
{
1667
    st_logf("DigestInit\n");
1668
    VERIFY_SESSION_HANDLE(hSession, NULL);
1669
    return CKR_FUNCTION_NOT_SUPPORTED;
1670
}
1671
1672
CK_RV
1673
C_SignInit(CK_SESSION_HANDLE hSession,
1674
	   CK_MECHANISM_PTR pMechanism,
1675
	   CK_OBJECT_HANDLE hKey)
1676
{
1677
    struct session_state *state;
1678
    CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 };
1679
    CK_BBOOL bool_true = CK_TRUE;
1680
    CK_ATTRIBUTE attr[] = {
1681
	{ CKA_SIGN, &bool_true, sizeof(bool_true) }
1682
    };
1683
    struct st_object *o;
1684
    CK_RV ret;
1685
1686
    st_logf("SignInit\n");
1687
    VERIFY_SESSION_HANDLE(hSession, &state);
1688
    
1689
    ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), 
1690
		     mechs, sizeof(mechs)/sizeof(mechs[0]),
1691
		     pMechanism, hKey, &o);
1692
    if (ret)
1693
	return ret;
1694
1695
    ret = dup_mechanism(&state->sign_mechanism, pMechanism);
1696
    if (ret == CKR_OK) 
1697
	state->sign_object = OBJECT_ID(o);
1698
1699
    return CKR_OK;
1700
}
1701
1702
CK_RV
1703
C_Sign(CK_SESSION_HANDLE hSession,
1704
       CK_BYTE_PTR pData,
1705
       CK_ULONG ulDataLen,
1706
       CK_BYTE_PTR pSignature,
1707
       CK_ULONG_PTR pulSignatureLen)
1708
{
1709
    struct session_state *state;
1710
    struct st_object *o;
1711
    void *buffer = NULL;
1712
    CK_RV ret;
1713
    RSA *rsa;
1714
    int padding, len, buffer_len;
1715
    size_t padding_len;
1716
1717
    st_logf("Sign\n");
1718
    VERIFY_SESSION_HANDLE(hSession, &state);
1719
1720
    if (state->sign_object == -1)
1721
	return CKR_ARGUMENTS_BAD;
1722
1723
    o = soft_token.object.objs[state->sign_object];
1724
1725
    if (o->u.private_key.key == NULL) {
1726
	st_logf("private key NULL\n");
1727
	return CKR_ARGUMENTS_BAD;
1728
    }
1729
1730
    rsa = o->u.private_key.key->pkey.rsa;
1731
1732
    if (rsa == NULL)
1733
	return CKR_ARGUMENTS_BAD;
1734
1735
    RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
1736
1737
    buffer_len = RSA_size(rsa);
1738
1739
    buffer = malloc(buffer_len);
1740
    if (buffer == NULL) {
1741
	ret = CKR_DEVICE_MEMORY;
1742
	goto out;
1743
    }
1744
1745
    switch(state->sign_mechanism->mechanism) {
1746
    case CKM_RSA_PKCS:
1747
	padding = RSA_PKCS1_PADDING;
1748
	padding_len = RSA_PKCS1_PADDING_SIZE;
1749
	break;
1750
    case CKM_RSA_X_509:
1751
	padding = RSA_NO_PADDING;
1752
	padding_len = 0;
1753
	break;
1754
    default:
1755
	ret = CKR_FUNCTION_NOT_SUPPORTED;
1756
	goto out;
1757
    }
1758
1759
    if ((size_t) buffer_len < ulDataLen + padding_len) {
1760
	ret = CKR_ARGUMENTS_BAD;
1761
	goto out;
1762
    }
1763
1764
    if (pulSignatureLen == NULL) {
1765
	st_logf("signature len NULL\n");
1766
	ret = CKR_ARGUMENTS_BAD;
1767
	goto out;
1768
    }
1769
1770
    if (pData == NULL_PTR) {
1771
	st_logf("data NULL\n");
1772
	ret = CKR_ARGUMENTS_BAD;
1773
	goto out;
1774
    }
1775
1776
    len = RSA_private_encrypt(ulDataLen, pData, buffer, rsa, padding);
1777
    st_logf("private encrypt done\n");
1778
    if (len <= 0) {
1779
	ret = CKR_DEVICE_ERROR;
1780
	goto out;
1781
    }
1782
    if (len > buffer_len)
1783
	abort();
1784
	
1785
    if (pSignature != NULL_PTR)
1786
	memcpy(pSignature, buffer, len);
1787
    *pulSignatureLen = len;
1788
1789
    ret = CKR_OK;
1790
1791
 out:
1792
    if (buffer) {
1793
	memset(buffer, 0, buffer_len);
1794
	free(buffer);
1795
    }
1796
    return ret;
1797
}
1798
1799
CK_RV
1800
C_SignUpdate(CK_SESSION_HANDLE hSession,
1801
	     CK_BYTE_PTR pPart,
1802
	     CK_ULONG ulPartLen)
1803
{
1804
    st_logf("SignUpdate\n");
1805
    VERIFY_SESSION_HANDLE(hSession, NULL);
1806
    return CKR_FUNCTION_NOT_SUPPORTED;
1807
}
1808
1809
1810
CK_RV
1811
C_SignFinal(CK_SESSION_HANDLE hSession,
1812
	    CK_BYTE_PTR pSignature,
1813
	    CK_ULONG_PTR pulSignatureLen)
1814
{
1815
    st_logf("SignUpdate\n");
1816
    VERIFY_SESSION_HANDLE(hSession, NULL);
1817
    return CKR_FUNCTION_NOT_SUPPORTED;
1818
}
1819
1820
CK_RV
1821
C_VerifyInit(CK_SESSION_HANDLE hSession,
1822
	     CK_MECHANISM_PTR pMechanism,
1823
	     CK_OBJECT_HANDLE hKey)
1824
{
1825
    struct session_state *state;
1826
    CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 };
1827
    CK_BBOOL bool_true = CK_TRUE;
1828
    CK_ATTRIBUTE attr[] = {
1829
	{ CKA_VERIFY, &bool_true, sizeof(bool_true) }
1830
    };
1831
    struct st_object *o;
1832
    CK_RV ret;
1833
1834
    st_logf("VerifyInit\n");
1835
    VERIFY_SESSION_HANDLE(hSession, &state);
1836
    
1837
    ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), 
1838
		     mechs, sizeof(mechs)/sizeof(mechs[0]),
1839
		     pMechanism, hKey, &o);
1840
    if (ret)
1841
	return ret;
1842
1843
    ret = dup_mechanism(&state->verify_mechanism, pMechanism);
1844
    if (ret == CKR_OK) 
1845
	state->verify_object = OBJECT_ID(o);
1846
			
1847
    return ret;
1848
}
1849
1850
CK_RV
1851
C_Verify(CK_SESSION_HANDLE hSession,
1852
	 CK_BYTE_PTR pData,
1853
	 CK_ULONG ulDataLen,
1854
	 CK_BYTE_PTR pSignature,
1855
	 CK_ULONG ulSignatureLen)
1856
{
1857
    struct session_state *state;
1858
    struct st_object *o;
1859
    void *buffer = NULL;
1860
    CK_RV ret;
1861
    RSA *rsa;
1862
    int padding, len, buffer_len;
1863
1864
    st_logf("Verify\n");
1865
    VERIFY_SESSION_HANDLE(hSession, &state);
1866
1867
    if (state->verify_object == -1)
1868
	return CKR_ARGUMENTS_BAD;
1869
1870
    o = soft_token.object.objs[state->verify_object];
1871
1872
    if (o->u.public_key == NULL) {
1873
	st_logf("public key NULL\n");
1874
	return CKR_ARGUMENTS_BAD;
1875
    }
1876
1877
    rsa = o->u.public_key->pkey.rsa;
1878
1879
    if (rsa == NULL)
1880
	return CKR_ARGUMENTS_BAD;
1881
1882
    RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
1883
1884
    buffer_len = RSA_size(rsa);
1885
1886
    buffer = malloc(buffer_len);
1887
    if (buffer == NULL) {
1888
	ret = CKR_DEVICE_MEMORY;
1889
	goto out;
1890
    }
1891
1892
    ret = CKR_OK;
1893
    switch(state->verify_mechanism->mechanism) {
1894
    case CKM_RSA_PKCS:
1895
	padding = RSA_PKCS1_PADDING;
1896
	break;
1897
    case CKM_RSA_X_509:
1898
	padding = RSA_NO_PADDING;
1899
	break;
1900
    default:
1901
	ret = CKR_FUNCTION_NOT_SUPPORTED;
1902
	goto out;
1903
    }
1904
1905
    if (buffer_len < (long) ulDataLen) {
1906
	ret = CKR_ARGUMENTS_BAD;
1907
	goto out;
1908
    }
1909
1910
    if (pSignature == NULL) {
1911
	st_logf("signature NULL\n");
1912
	ret = CKR_ARGUMENTS_BAD;
1913
	goto out;
1914
    }
1915
1916
    if (pData == NULL_PTR) {
1917
	st_logf("data NULL\n");
1918
	ret = CKR_ARGUMENTS_BAD;
1919
	goto out;
1920
    }
1921
1922
    len = RSA_public_decrypt(ulDataLen, pData, buffer, rsa, padding);
1923
    st_logf("private encrypt done\n");
1924
    if (len <= 0) {
1925
	ret = CKR_DEVICE_ERROR;
1926
	goto out;
1927
    }
1928
    if (len > buffer_len)
1929
	abort();
1930
	
1931
    if ((size_t) len != ulSignatureLen) {
1932
	ret = CKR_GENERAL_ERROR;
1933
	goto out;
1934
    }
1935
	
1936
    if (memcmp(pSignature, buffer, len) != 0) {
1937
	ret = CKR_GENERAL_ERROR;
1938
	goto out;
1939
    }
1940
1941
 out:
1942
    if (buffer) {
1943
	memset(buffer, 0, buffer_len);
1944
	free(buffer);
1945
    }
1946
    return ret;
1947
}
1948
1949
1950
CK_RV
1951
C_VerifyUpdate(CK_SESSION_HANDLE hSession,
1952
	       CK_BYTE_PTR pPart,
1953
	       CK_ULONG ulPartLen)
1954
{
1955
    st_logf("VerifyUpdate\n");
1956
    VERIFY_SESSION_HANDLE(hSession, NULL);
1957
    return CKR_FUNCTION_NOT_SUPPORTED;
1958
}
1959
1960
CK_RV
1961
C_VerifyFinal(CK_SESSION_HANDLE hSession,
1962
	      CK_BYTE_PTR pSignature,
1963
	      CK_ULONG ulSignatureLen)
1964
{
1965
    st_logf("VerifyFinal\n");
1966
    VERIFY_SESSION_HANDLE(hSession, NULL);
1967
    return CKR_FUNCTION_NOT_SUPPORTED;
1968
}
1969
1970
CK_RV
1971
C_GenerateRandom(CK_SESSION_HANDLE hSession,
1972
		 CK_BYTE_PTR RandomData,
1973
		 CK_ULONG ulRandomLen)
1974
{
1975
    st_logf("GenerateRandom\n");
1976
    VERIFY_SESSION_HANDLE(hSession, NULL);
1977
    return CKR_FUNCTION_NOT_SUPPORTED;
1978
}
1979
1980
1981
CK_FUNCTION_LIST funcs = {
1982
    { 2, 11 },
1983
    C_Initialize,
1984
    C_Finalize,
1985
    C_GetInfo,
1986
    C_GetFunctionList,
1987
    C_GetSlotList,
1988
    C_GetSlotInfo,
1989
    C_GetTokenInfo,
1990
    C_GetMechanismList,
1991
    C_GetMechanismInfo,
1992
    C_InitToken,
1993
    (void *)func_not_supported, /* C_InitPIN */
1994
    (void *)func_not_supported, /* C_SetPIN */
1995
    C_OpenSession,
1996
    C_CloseSession,
1997
    C_CloseAllSessions,
1998
    C_GetSessionInfo,
1999
    (void *)func_not_supported, /* C_GetOperationState */
2000
    (void *)func_not_supported, /* C_SetOperationState */
2001
    C_Login,
2002
    C_Logout,
2003
    (void *)func_not_supported, /* C_CreateObject */
2004
    (void *)func_not_supported, /* C_CopyObject */
2005
    (void *)func_not_supported, /* C_DestroyObject */
2006
    (void *)func_not_supported, /* C_GetObjectSize */
2007
    C_GetAttributeValue,
2008
    (void *)func_not_supported, /* C_SetAttributeValue */
2009
    C_FindObjectsInit,
2010
    C_FindObjects,
2011
    C_FindObjectsFinal,
2012
    C_EncryptInit,
2013
    C_Encrypt,
2014
    C_EncryptUpdate,
2015
    C_EncryptFinal,
2016
    C_DecryptInit,
2017
    C_Decrypt,
2018
    C_DecryptUpdate,
2019
    C_DecryptFinal,
2020
    C_DigestInit,
2021
    (void *)func_not_supported, /* C_Digest */
2022
    (void *)func_not_supported, /* C_DigestUpdate */
2023
    (void *)func_not_supported, /* C_DigestKey */
2024
    (void *)func_not_supported, /* C_DigestFinal */
2025
    C_SignInit,
2026
    C_Sign,
2027
    C_SignUpdate,
2028
    C_SignFinal,
2029
    (void *)func_not_supported, /* C_SignRecoverInit */
2030
    (void *)func_not_supported, /* C_SignRecover */
2031
    C_VerifyInit,
2032
    C_Verify,
2033
    C_VerifyUpdate,
2034
    C_VerifyFinal,
2035
    (void *)func_not_supported, /* C_VerifyRecoverInit */
2036
    (void *)func_not_supported, /* C_VerifyRecover */
2037
    (void *)func_not_supported, /* C_DigestEncryptUpdate */
2038
    (void *)func_not_supported, /* C_DecryptDigestUpdate */
2039
    (void *)func_not_supported, /* C_SignEncryptUpdate */
2040
    (void *)func_not_supported, /* C_DecryptVerifyUpdate */
2041
    (void *)func_not_supported, /* C_GenerateKey */
2042
    (void *)func_not_supported, /* C_GenerateKeyPair */
2043
    (void *)func_not_supported, /* C_WrapKey */
2044
    (void *)func_not_supported, /* C_UnwrapKey */
2045
    (void *)func_not_supported, /* C_DeriveKey */
2046
    (void *)func_not_supported, /* C_SeedRandom */
2047
    C_GenerateRandom,
2048
    (void *)func_not_supported, /* C_GetFunctionStatus */
2049
    (void *)func_not_supported, /* C_CancelFunction */
2050
    (void *)func_not_supported  /* C_WaitForSlotEvent */
2051
};
1
* PKCS#11 whitelist
2052
* PKCS#11 whitelist
2
* PIN is not required for removing card
2053
* PIN is not required for removing card
3
* Make sure ssh-agent is built with correct paths to helper
2054
* Make sure ssh-agent is built with correct paths to helper
4
--
5
regress/agent-pkcs11.sh | 13 ++++++++++---
2055
regress/agent-pkcs11.sh | 13 ++++++++++---
6
1 file changed, 10 insertions(+), 3 deletions(-)
2056
1 file changed, 10 insertions(+), 3 deletions(-)
(-)a/regress/agent-pkcs11.sh (-5 / +10 lines)
Lines 4-13 Link Here
4
tid="pkcs11 agent test"
4
tid="pkcs11 agent test"
5
5
6
TEST_SSH_PIN=""
6
TEST_SSH_PIN=""
7
TEST_SSH_PKCS11=/usr/local/lib/soft-pkcs11.so.0.0
7
TEST_SSH_PKCS11=$OBJ/soft-pkcs11.so
8
8
9
test -f "$TEST_SSH_PKCS11" || fatal "$TEST_SSH_PKCS11 does not exist"
9
test -f "$TEST_SSH_PKCS11" || fatal "$TEST_SSH_PKCS11 does not exist"
10
10
11
# requires ssh-agent built with correct path to ssh-pkcs11-helper
12
# otherwise it fails to start the helper
13
strings ${TEST_SSH_SSHAGENT} | grep "$TEST_SSH_SSHPKCS11HELPER"
14
if [ $? -ne 0 ]; then
15
	fatal "Needs to reconfigure with --libexecdir=\`pwd\` or so"
16
fi
17
11
# setup environment for soft-pkcs11 token
18
# setup environment for soft-pkcs11 token
12
SOFTPKCS11RC=$OBJ/pkcs11.info
19
SOFTPKCS11RC=$OBJ/pkcs11.info
13
export SOFTPKCS11RC
20
export SOFTPKCS11RC
Lines 23-29 notty() { Link Here
23
}
30
}
24
31
25
trace "start agent"
32
trace "start agent"
26
eval `${SSHAGENT} -s` > /dev/null
33
eval `${SSHAGENT} -s -P "${OBJ}/*"` > /dev/null
27
r=$?
34
r=$?
28
if [ $r -ne 0 ]; then
35
if [ $r -ne 0 ]; then
29
	fail "could not start ssh-agent: exit code $r"
36
	fail "could not start ssh-agent: exit code $r"
Lines 60-66 else Link Here
60
	fi
67
	fi
61
68
62
	trace "remove pkcs11 keys"
69
	trace "remove pkcs11 keys"
63
	echo ${TEST_SSH_PIN} | notty ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1
70
	${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1
64
	r=$?
71
	r=$?
65
	if [ $r -ne 0 ]; then
72
	if [ $r -ne 0 ]; then
66
		fail "ssh-add -e failed: exit code $r"
73
		fail "ssh-add -e failed: exit code $r"
67
- 
68
option
74
option
69
--
70
regress/pkcs11.sh | 9 +++++++++
75
regress/pkcs11.sh | 9 +++++++++
71
ssh-pkcs11.c      | 7 ++++---
76
ssh-pkcs11.c      | 7 ++++---
72
2 files changed, 13 insertions(+), 3 deletions(-)
77
2 files changed, 13 insertions(+), 3 deletions(-)
(-)a/regress/pkcs11.sh (+9 lines)
Lines 151-156 if [ $r -eq 5 ]; then Link Here
151
	    "succeeded (should fail)"
151
	    "succeeded (should fail)"
152
fi
152
fi
153
153
154
trace "Regress: Missing provider in PKCS11URI option"
155
${SSH} -F $OBJ/ssh_proxy \
156
    -o PKCS11URI='pkcs11:token=segfault' somehost exit 5
157
r=$?
158
if [ $r -eq 139 ]; then
159
	fail "ssh connect with missing provider_id from configuration option" \
160
	    "crashed (exit code $r)"
161
fi
162
154
163
155
trace "SSH Agent can work with PKCS#11 URI"
164
trace "SSH Agent can work with PKCS#11 URI"
156
trace "start the agent"
165
trace "start the agent"
(-)a/ssh-pkcs11.c (-5 / +4 lines)
Lines 698-710 pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***k Link Here
698
	CK_FUNCTION_LIST *f = NULL;
698
	CK_FUNCTION_LIST *f = NULL;
699
	CK_TOKEN_INFO *token;
699
	CK_TOKEN_INFO *token;
700
	CK_ULONG i;
700
	CK_ULONG i;
701
	char *provider_id = strdup(uri->module_path);
701
	char *provider_id = NULL;
702
	char *provider_uri = pkcs11_uri_get(uri);
702
	char *provider_uri = pkcs11_uri_get(uri);
703
703
704
	/* if no provider specified, fallback to p11-kit */
704
	/* if no provider specified, fallback to p11-kit */
705
	if (provider_id == NULL) {
705
	if (uri->module_path == NULL)
706
		provider_id = strdup(PKCS11_DEFAULT_PROVIDER);
706
		provider_id = strdup(PKCS11_DEFAULT_PROVIDER);
707
	}
707
	else
708
		provider_id = strdup(uri->module_path);
708
709
709
	debug("%s: called, provider_uri = %s", __func__, provider_uri);
710
	debug("%s: called, provider_uri = %s", __func__, provider_uri);
710
711
711
- 
712
configure time
712
configure time
713
--
714
configure.ac     | 37 +++++++++++++++++++++++++++++++++++++
713
configure.ac     | 37 +++++++++++++++++++++++++++++++++++++
715
ssh-pkcs11-uri.h |  2 --
714
ssh-pkcs11-uri.h |  2 --
716
ssh-pkcs11.c     | 12 ++++++++----
715
ssh-pkcs11.c     | 12 ++++++++----
717
3 files changed, 45 insertions(+), 6 deletions(-)
716
3 files changed, 45 insertions(+), 6 deletions(-)
(-)a/configure.ac (+37 lines)
Lines 1840-1851 AC_LINK_IFELSE( Link Here
1840
	[AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).])
1840
	[AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).])
1841
])
1841
])
1842
1842
1843
SCARD_MSG="yes"
1843
disable_pkcs11=
1844
disable_pkcs11=
1844
AC_ARG_ENABLE([pkcs11],
1845
AC_ARG_ENABLE([pkcs11],
1845
	[  --disable-pkcs11        disable PKCS#11 support code [no]],
1846
	[  --disable-pkcs11        disable PKCS#11 support code [no]],
1846
	[
1847
	[
1847
		if test "x$enableval" = "xno" ; then
1848
		if test "x$enableval" = "xno" ; then
1848
			disable_pkcs11=1
1849
			disable_pkcs11=1
1850
			SCARD_MSG="no"
1849
		fi
1851
		fi
1850
	]
1852
	]
1851
)
1853
)
Lines 1858-1863 if test "x$openssl" = "xyes" && test "x$disable_pkcs11" = "x"; then Link Here
1858
	)
1860
	)
1859
fi
1861
fi
1860
1862
1863
# Check whether we have a p11-kit, we got default provider on command line
1864
DEFAULT_PKCS11_PROVIDER_MSG="no"
1865
AC_ARG_WITH([default-pkcs11-provider],
1866
	[  --with-default-pkcs11-provider[[=PATH]]   Use default pkcs11 provider (p11-kit detected by default)],
1867
	[ if test "x$withval" != "xno" && test "x$disable_pkcs11" = "x"; then
1868
		if test "x$withval" = "xyes" ; then
1869
			AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
1870
			if test "x$PKGCONFIG" != "xno"; then
1871
				AC_MSG_CHECKING([if $PKGCONFIG knows about p11-kit])
1872
				if "$PKGCONFIG" "p11-kit-1"; then
1873
					AC_MSG_RESULT([yes])
1874
					use_pkgconfig_for_p11kit=yes
1875
				else
1876
					AC_MSG_RESULT([no])
1877
				fi
1878
			fi
1879
		else
1880
			PKCS11_PATH="${withval}"
1881
		fi
1882
		if test "x$use_pkgconfig_for_p11kit" = "xyes"; then
1883
			PKCS11_PATH=`$PKGCONFIG --variable=proxy_module p11-kit-1`
1884
		fi
1885
		AC_CHECK_FILE("$PKCS11_PATH",
1886
			[ AC_DEFINE_UNQUOTED([PKCS11_DEFAULT_PROVIDER], ["$PKCS11_PATH"], [Path to default PKCS#11 provider (p11-kit proxy)])
1887
			  DEFAULT_PKCS11_PROVIDER_MSG="$PKCS11_PATH"
1888
			],
1889
			[ AC_MSG_ERROR([Requested PKCS11 provided not found]) ]
1890
		)
1891
	else
1892
		AC_MSG_WARN([Needs PKCS11 support to enable default pkcs11 provider])
1893
	fi ]
1894
)
1895
1896
1861
# IRIX has a const char return value for gai_strerror()
1897
# IRIX has a const char return value for gai_strerror()
1862
AC_CHECK_FUNCS([gai_strerror], [
1898
AC_CHECK_FUNCS([gai_strerror], [
1863
	AC_DEFINE([HAVE_GAI_STRERROR])
1899
	AC_DEFINE([HAVE_GAI_STRERROR])
Lines 5134-5139 echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" Link Here
5134
echo "                  BSD Auth support: $BSD_AUTH_MSG"
5170
echo "                  BSD Auth support: $BSD_AUTH_MSG"
5135
echo "              Random number source: $RAND_MSG"
5171
echo "              Random number source: $RAND_MSG"
5136
echo "             Privsep sandbox style: $SANDBOX_STYLE"
5172
echo "             Privsep sandbox style: $SANDBOX_STYLE"
5173
echo "          Default PKCS#11 provider: $DEFAULT_PKCS11_PROVIDER_MSG"
5137
5174
5138
echo ""
5175
echo ""
5139
5176
(-)a/ssh-pkcs11-uri.h (-2 lines)
Lines 17-24 Link Here
17
 */
17
 */
18
18
19
#define PKCS11_URI_SCHEME "pkcs11:"
19
#define PKCS11_URI_SCHEME "pkcs11:"
20
#define PKCS11_DEFAULT_PROVIDER "/usr/lib64/p11-kit-proxy.so"
21
22
#define PKCS11_URI_WHITELIST	"abcdefghijklmnopqrstuvwxyz" \
20
#define PKCS11_URI_WHITELIST	"abcdefghijklmnopqrstuvwxyz" \
23
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
21
				"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
24
				"0123456789_-.()"
22
				"0123456789_-.()"
(-)a/ssh-pkcs11.c (-6 / +8 lines)
Lines 701-714 pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***k Link Here
701
	char *provider_id = NULL;
701
	char *provider_id = NULL;
702
	char *provider_uri = pkcs11_uri_get(uri);
702
	char *provider_uri = pkcs11_uri_get(uri);
703
703
704
	debug("%s: called, provider_uri = %s", __func__, provider_uri);
705
704
	/* if no provider specified, fallback to p11-kit */
706
	/* if no provider specified, fallback to p11-kit */
705
	if (uri->module_path == NULL)
707
	if (uri->module_path == NULL) {
708
#ifdef PKCS11_DEFAULT_PROVIDER
706
		provider_id = strdup(PKCS11_DEFAULT_PROVIDER);
709
		provider_id = strdup(PKCS11_DEFAULT_PROVIDER);
707
	else
710
#else
711
		error("%s: No module path provided", __func__);
712
#endif
713
	} else
708
		provider_id = strdup(uri->module_path);
714
		provider_id = strdup(uri->module_path);
709
715
710
	debug("%s: called, provider_uri = %s", __func__, provider_uri);
711
712
	*keyp = NULL;
716
	*keyp = NULL;
713
	if (pkcs11_provider_lookup(provider_uri) != NULL) {
717
	if (pkcs11_provider_lookup(provider_uri) != NULL) {
714
		debug("%s: provider already registered: %s",
718
		debug("%s: provider already registered: %s",
715
- 
716
--
717
ssh-pkcs11-uri.c | 14 +++++++-------
719
ssh-pkcs11-uri.c | 14 +++++++-------
718
1 file changed, 7 insertions(+), 7 deletions(-)
720
1 file changed, 7 insertions(+), 7 deletions(-)
(-)a/ssh-pkcs11-uri.c (-9 / +7 lines)
Lines 289-295 pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11) Link Here
289
			break;
289
			break;
290
		opcode = parse_token(tok);
290
		opcode = parse_token(tok);
291
		if (opcode == pBadOption) {
291
		if (opcode == pBadOption) {
292
			error("Unknown key in PKCS#11 URI: %s", tok);
292
			verbose("Unknown key in PKCS#11 URI: %s", tok);
293
			return -1;
293
			return -1;
294
		}
294
		}
295
295
Lines 298-310 pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11) Link Here
298
		case pId:
298
		case pId:
299
			/* CKA_ID */
299
			/* CKA_ID */
300
			if (pkcs11->id != NULL) {
300
			if (pkcs11->id != NULL) {
301
				error("%s: The id already set in the PKCS#11 URI",
301
				verbose("%s: The id already set in the PKCS#11 URI",
302
					__func__);
302
					__func__);
303
				rv = -1;
303
				rv = -1;
304
			}
304
			}
305
			len = percent_decode(arg, &pkcs11->id);
305
			len = percent_decode(arg, &pkcs11->id);
306
			if (len <= 0) {
306
			if (len <= 0) {
307
				error("%s: Failed to percent-decode CKA_ID: %s",
307
				verbose("%s: Failed to percent-decode CKA_ID: %s",
308
				    __func__, arg);
308
				    __func__, arg);
309
				rv = -1;
309
				rv = -1;
310
			} else
310
			} else
Lines 317-323 pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11) Link Here
317
			charptr = &pkcs11->token;
317
			charptr = &pkcs11->token;
318
 parse_string:
318
 parse_string:
319
			if (*charptr != NULL) {
319
			if (*charptr != NULL) {
320
				error("%s: The %s already set in the PKCS#11 URI",
320
				verbose("%s: The %s already set in the PKCS#11 URI",
321
				    keywords[opcode].name, __func__);
321
				    keywords[opcode].name, __func__);
322
				rv = -1;
322
				rv = -1;
323
			}
323
			}
Lines 339-345 pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11) Link Here
339
		case pBadOption:
339
		case pBadOption:
340
		default:
340
		default:
341
			/* Unrecognized attribute in the URI path SHOULD be error */
341
			/* Unrecognized attribute in the URI path SHOULD be error */
342
			error("%s: Unknown part of path in PKCS#11 URI: %s",
342
			verbose("%s: Unknown part of path in PKCS#11 URI: %s",
343
			    __func__, tok);
343
			    __func__, tok);
344
			rv = -1;
344
			rv = -1;
345
		}
345
		}
Lines 360-366 pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11) Link Here
360
		    PKCS11_URI_VALUE_SEPARATOR, key_len) == 0) {
360
		    PKCS11_URI_VALUE_SEPARATOR, key_len) == 0) {
361
			/* module-path is PKCS11Provider */
361
			/* module-path is PKCS11Provider */
362
			if (pkcs11->module_path != NULL) {
362
			if (pkcs11->module_path != NULL) {
363
				error("%s: Multiple module-path attributes are"
363
				verbose("%s: Multiple module-path attributes are"
364
				    "not supported the PKCS#11 URI", __func__);
364
				    "not supported the PKCS#11 URI", __func__);
365
				rv = -1;
365
				rv = -1;
366
			}
366
			}
Lines 370-376 pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11) Link Here
370
		/* } else if ( pin-value ) { */
370
		/* } else if ( pin-value ) { */
371
		} else {
371
		} else {
372
			/* Unrecognized attribute in the URI query SHOULD be ignored */
372
			/* Unrecognized attribute in the URI query SHOULD be ignored */
373
			error("%s: Unknown part of query in PKCS#11 URI: %s",
373
			verbose("%s: Unknown part of query in PKCS#11 URI: %s",
374
			    __func__, tok);
374
			    __func__, tok);
375
		}
375
		}
376
	}
376
	}
377
- 
378
--
379
regress/pkcs11.sh                | 35 ++++++++++++++++++
377
regress/pkcs11.sh                | 35 ++++++++++++++++++
380
regress/unittests/pkcs11/tests.c | 57 ++++++++++++++++++-----------
378
regress/unittests/pkcs11/tests.c | 57 ++++++++++++++++++-----------
381
ssh-agent.c                      |  2 +-
379
ssh-agent.c                      |  2 +-
382
ssh-pkcs11-uri.c                 | 20 ++++++++++-
380
ssh-pkcs11-uri.c                 | 20 ++++++++++-
383
ssh-pkcs11-uri.h                 |  1 +
381
ssh-pkcs11-uri.h                 |  1 +
384
ssh-pkcs11.c                     | 78 +++++++++++++++++++++++++---------------
382
ssh-pkcs11.c                     | 78 +++++++++++++++++++++++++---------------
385
6 files changed, 142 insertions(+), 51 deletions(-)
383
6 files changed, 142 insertions(+), 51 deletions(-)
(-)a/regress/pkcs11.sh (+35 lines)
Lines 100-105 if [ $r -eq 5 ]; then Link Here
100
	fail "ssh connect with PKCS#11 URI succeeded (should fail)"
100
	fail "ssh connect with PKCS#11 URI succeeded (should fail)"
101
fi
101
fi
102
102
103
trace "Connect with various filtering options in PKCS#11 URI"
104
trace "  (by object label, second key should succeed)"
105
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
106
    -i "pkcs11:object=SSH%20RSA%20Key%202?module-path=${TEST_SSH_PKCS11}" somehost exit 5
107
r=$?
108
if [ $r -ne 5 ]; then
109
	fail "ssh connect with PKCS#11 URI failed (exit code $r)"
110
fi
111
112
trace "  (by object label, first key should fail)"
113
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
114
     -i "pkcs11:object=SSH%20RSA%20Key?module-path=${TEST_SSH_PKCS11}" somehost exit 5
115
r=$?
116
if [ $r -eq 5 ]; then
117
	fail "ssh connect with PKCS#11 URI succeeded (should fail)"
118
fi
119
120
trace "  (by token label, second key should succeed)"
121
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
122
    -i "pkcs11:id=${ID2};token=SoftToken%20(token)?module-path=${TEST_SSH_PKCS11}" somehost exit 5
123
r=$?
124
if [ $r -ne 5 ]; then
125
	fail "ssh connect with PKCS#11 URI failed (exit code $r)"
126
fi
127
128
trace "  (by wrong token label, should fail)"
129
echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
130
     -i "pkcs11:token=SoftToken?module-path=${TEST_SSH_PKCS11}" somehost exit 5
131
r=$?
132
if [ $r -eq 5 ]; then
133
	fail "ssh connect with PKCS#11 URI succeeded (should fail)"
134
fi
135
136
137
103
138
104
trace "Test PKCS#11 URI specification in configuration files"
139
trace "Test PKCS#11 URI specification in configuration files"
105
echo "PKCS11URI pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" \
140
echo "PKCS11URI pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" \
(-)a/regress/unittests/pkcs11/tests.c (-21 / +36 lines)
Lines 25-31 Link Here
25
25
26
#include "ssh-pkcs11-uri.h"
26
#include "ssh-pkcs11-uri.h"
27
27
28
#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL)
28
#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL)
29
29
30
/* prototypes are not public -- specify them here internally for tests */
30
/* prototypes are not public -- specify them here internally for tests */
31
struct sshbuf *percent_encode(const char *, size_t, char *);
31
struct sshbuf *percent_encode(const char *, size_t, char *);
Lines 38-43 compare_uri(struct pkcs11_uri *a, struct pkcs11_uri *b) Link Here
38
	ASSERT_PTR_NE(b, NULL);
38
	ASSERT_PTR_NE(b, NULL);
39
	ASSERT_SIZE_T_EQ(a->id_len, b->id_len);
39
	ASSERT_SIZE_T_EQ(a->id_len, b->id_len);
40
	ASSERT_MEM_EQ(a->id, b->id, a->id_len);
40
	ASSERT_MEM_EQ(a->id, b->id, a->id_len);
41
	if (b->object != NULL)
42
		ASSERT_STRING_EQ(a->object, b->object);
43
	else /* both should be null */
44
		ASSERT_PTR_EQ(a->object, b->object);
41
	if (b->module_path != NULL)
45
	if (b->module_path != NULL)
42
		ASSERT_STRING_EQ(a->module_path, b->module_path);
46
		ASSERT_STRING_EQ(a->module_path, b->module_path);
43
	else /* both should be null */
47
	else /* both should be null */
Lines 88-94 check_parse(char *uri, struct pkcs11_uri *expect) Link Here
88
92
89
struct pkcs11_uri *
93
struct pkcs11_uri *
90
compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf,
94
compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf,
91
    char *manuf, char *module_path)
95
    char *manuf, char *module_path, char *object)
92
{
96
{
93
	struct pkcs11_uri *uri = pkcs11_uri_init();
97
	struct pkcs11_uri *uri = pkcs11_uri_init();
94
	if (id_len > 0) {
98
	if (id_len > 0) {
Lines 99-104 compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf, Link Here
99
	uri->token = token;
103
	uri->token = token;
100
	uri->lib_manuf = lib_manuf;
104
	uri->lib_manuf = lib_manuf;
101
	uri->manuf = manuf;
105
	uri->manuf = manuf;
106
	uri->object = object;
102
	return uri;
107
	return uri;
103
}
108
}
104
109
Lines 107-143 test_parse_valid(void) Link Here
107
{
112
{
108
	/* path arguments */
113
	/* path arguments */
109
	check_parse("pkcs11:id=%01",
114
	check_parse("pkcs11:id=%01",
110
	    compose_uri("\x01", 1, NULL, NULL, NULL, NULL));
115
	    compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL));
111
	check_parse("pkcs11:id=%00%01",
116
	check_parse("pkcs11:id=%00%01",
112
	    compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL));
117
	    compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL));
113
	check_parse("pkcs11:token=SSH%20Keys",
118
	check_parse("pkcs11:token=SSH%20Keys",
114
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL));
119
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL));
115
	check_parse("pkcs11:library-manufacturer=OpenSC",
120
	check_parse("pkcs11:library-manufacturer=OpenSC",
116
	    compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL));
121
	    compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL));
117
	check_parse("pkcs11:manufacturer=piv_II",
122
	check_parse("pkcs11:manufacturer=piv_II",
118
	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL));
123
	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL));
124
	check_parse("pkcs11:object=SIGN%20Key",
125
	    compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "SIGN Key"));
119
	/* query arguments */
126
	/* query arguments */
120
	check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
127
	check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
121
	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so"));
128
	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL));
122
129
123
	/* combinations */
130
	/* combinations */
124
	/* ID SHOULD be percent encoded */
131
	/* ID SHOULD be percent encoded */
125
	check_parse("pkcs11:token=SSH%20Key;id=0",
132
	check_parse("pkcs11:token=SSH%20Key;id=0",
126
	    compose_uri("0", 1, "SSH Key", NULL, NULL, NULL));
133
	    compose_uri("0", 1, "SSH Key", NULL, NULL, NULL, NULL));
127
	check_parse(
134
	check_parse(
128
	    "pkcs11:manufacturer=CAC?module-path=/usr/lib64/p11-kit-proxy.so",
135
	    "pkcs11:manufacturer=CAC?module-path=/usr/lib64/p11-kit-proxy.so",
129
	    compose_uri(NULL, 0, NULL, NULL, "CAC",
136
	    compose_uri(NULL, 0, NULL, NULL, "CAC",
130
	    "/usr/lib64/p11-kit-proxy.so"));
137
	    "/usr/lib64/p11-kit-proxy.so", NULL));
138
	check_parse(
139
	    "pkcs11:object=RSA%20Key?module-path=/usr/lib64/pkcs11/opencryptoki.so",
140
	    compose_uri(NULL, 0, NULL, NULL, NULL,
141
	    "/usr/lib64/pkcs11/opencryptoki.so", "RSA Key"));
131
142
132
	/* empty path component matches everything */
143
	/* empty path component matches everything */
133
	check_parse("pkcs11:", EMPTY_URI);
144
	check_parse("pkcs11:", EMPTY_URI);
134
145
135
	/* empty string is a valid to match against (and different from NULL) */
146
	/* empty string is a valid to match against (and different from NULL) */
136
	check_parse("pkcs11:token=",
147
	check_parse("pkcs11:token=",
137
	    compose_uri(NULL, 0, "", NULL, NULL, NULL));
148
	    compose_uri(NULL, 0, "", NULL, NULL, NULL, NULL));
138
	/* Percent character needs to be percent-encoded */
149
	/* Percent character needs to be percent-encoded */
139
	check_parse("pkcs11:token=%25",
150
	check_parse("pkcs11:token=%25",
140
	     compose_uri(NULL, 0, "%", NULL, NULL, NULL));
151
	     compose_uri(NULL, 0, "%", NULL, NULL, NULL, NULL));
141
}
152
}
142
153
143
static void
154
static void
Lines 149-155 test_parse_invalid(void) Link Here
149
	check_parse_rv("pkcs11:id=%ZZ", EMPTY_URI, -1);
160
	check_parse_rv("pkcs11:id=%ZZ", EMPTY_URI, -1);
150
	/* Space MUST be percent encoded -- XXX not enforced yet */
161
	/* Space MUST be percent encoded -- XXX not enforced yet */
151
	check_parse("pkcs11:token=SSH Keys",
162
	check_parse("pkcs11:token=SSH Keys",
152
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL));
163
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL));
153
	/* MUST NOT contain duplicate attributes of the same name */
164
	/* MUST NOT contain duplicate attributes of the same name */
154
	check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1);
165
	check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1);
155
	/* Unrecognized attribute in path SHOULD be error */
166
	/* Unrecognized attribute in path SHOULD be error */
Lines 178-202 test_generate_valid(void) Link Here
178
{
189
{
179
	/* path arguments */
190
	/* path arguments */
180
	check_gen("pkcs11:id=%01",
191
	check_gen("pkcs11:id=%01",
181
	    compose_uri("\x01", 1, NULL, NULL, NULL, NULL));
192
	    compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL));
182
	check_gen("pkcs11:id=%00%01",
193
	check_gen("pkcs11:id=%00%01",
183
	    compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL));
194
	    compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL));
184
	check_gen("pkcs11:token=SSH%20Keys", /* space must be percent encoded */
195
	check_gen("pkcs11:token=SSH%20Keys", /* space must be percent encoded */
185
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL));
196
	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL));
186
	/* library-manufacturer is not implmented now */
197
	/* library-manufacturer is not implmented now */
187
	/*check_gen("pkcs11:library-manufacturer=OpenSC",
198
	/*check_gen("pkcs11:library-manufacturer=OpenSC",
188
	    compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL));*/
199
	    compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL));*/
189
	check_gen("pkcs11:manufacturer=piv_II",
200
	check_gen("pkcs11:manufacturer=piv_II",
190
	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL));
201
	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL));
202
	check_gen("pkcs11:object=RSA%20Key",
203
	    compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "RSA Key"));
191
	/* query arguments */
204
	/* query arguments */
192
	check_gen("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
205
	check_gen("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
193
	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so"));
206
	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL));
194
207
195
	/* combinations */
208
	/* combinations */
196
	check_gen("pkcs11:id=%02;token=SSH%20Keys",
209
	check_gen("pkcs11:id=%02;token=SSH%20Keys",
197
	    compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL));
210
	    compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL, NULL));
198
	check_gen("pkcs11:id=%EE%02?module-path=/usr/lib64/p11-kit-proxy.so",
211
	check_gen("pkcs11:id=%EE%02?module-path=/usr/lib64/p11-kit-proxy.so",
199
	    compose_uri("\xEE\x02", 2, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so"));
212
	    compose_uri("\xEE\x02", 2, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL));
213
	check_gen("pkcs11:object=Encryption%20Key;manufacturer=piv_II",
214
	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, "Encryption Key"));
200
215
201
	/* empty path component matches everything */
216
	/* empty path component matches everything */
202
	check_gen("pkcs11:", EMPTY_URI);
217
	check_gen("pkcs11:", EMPTY_URI);
(-)a/ssh-agent.c (-1 / +1 lines)
Lines 671-677 send: Link Here
671
static void
671
static void
672
process_remove_smartcard_key(SocketEntry *e)
672
process_remove_smartcard_key(SocketEntry *e)
673
{
673
{
674
	char *provider = NULL, *pin = NULL, *sane_uri;
674
	char *provider = NULL, *pin = NULL, *sane_uri = NULL;
675
	int r, success = 0;
675
	int r, success = 0;
676
	Identity *id, *nxt;
676
	Identity *id, *nxt;
677
677
(-)a/ssh-pkcs11-uri.c (-1 / +19 lines)
Lines 36-48 Link Here
36
#define PKCS11_URI_VALUE_SEPARATOR "="
36
#define PKCS11_URI_VALUE_SEPARATOR "="
37
#define PKCS11_URI_ID "id"
37
#define PKCS11_URI_ID "id"
38
#define PKCS11_URI_TOKEN "token"
38
#define PKCS11_URI_TOKEN "token"
39
#define PKCS11_URI_OBJECT "object"
39
#define PKCS11_URI_LIB_MANUF "library-manufacturer"
40
#define PKCS11_URI_LIB_MANUF "library-manufacturer"
40
#define PKCS11_URI_MANUF "manufacturer"
41
#define PKCS11_URI_MANUF "manufacturer"
41
#define PKCS11_URI_MODULE_PATH "module-path"
42
#define PKCS11_URI_MODULE_PATH "module-path"
42
43
43
/* Keyword tokens. */
44
/* Keyword tokens. */
44
typedef enum {
45
typedef enum {
45
	pId, pToken, pLibraryManufacturer, pManufacturer, pModulePath,
46
	pId, pToken, pObject, pLibraryManufacturer, pManufacturer, pModulePath,
46
	pBadOption
47
	pBadOption
47
} pkcs11uriOpCodes;
48
} pkcs11uriOpCodes;
48
49
Lines 53-58 static struct { Link Here
53
} keywords[] = {
54
} keywords[] = {
54
	{ PKCS11_URI_ID, pId },
55
	{ PKCS11_URI_ID, pId },
55
	{ PKCS11_URI_TOKEN, pToken },
56
	{ PKCS11_URI_TOKEN, pToken },
57
	{ PKCS11_URI_OBJECT, pObject },
56
	{ PKCS11_URI_LIB_MANUF, pLibraryManufacturer },
58
	{ PKCS11_URI_LIB_MANUF, pLibraryManufacturer },
57
	{ PKCS11_URI_MANUF, pManufacturer },
59
	{ PKCS11_URI_MANUF, pManufacturer },
58
	{ PKCS11_URI_MODULE_PATH, pModulePath },
60
	{ PKCS11_URI_MODULE_PATH, pModulePath },
Lines 182-187 pkcs11_uri_get(struct pkcs11_uri *uri) Link Here
182
			goto err;
184
			goto err;
183
	}
185
	}
184
186
187
	/* Write object label */
188
	if (uri->object) {
189
		struct sshbuf *label = percent_encode(uri->object, strlen(uri->object),
190
		    PKCS11_URI_WHITELIST);
191
		path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
192
		    PKCS11_URI_OBJECT, label);
193
		if (path == NULL)
194
			goto err;
195
	}
196
185
	/* Write token label */
197
	/* Write token label */
186
	if (uri->token) {
198
	if (uri->token) {
187
		struct sshbuf *label = percent_encode(uri->token, strlen(uri->token),
199
		struct sshbuf *label = percent_encode(uri->token, strlen(uri->token),
Lines 237-242 pkcs11_uri_cleanup(struct pkcs11_uri *pkcs11) Link Here
237
	free(pkcs11->id);
249
	free(pkcs11->id);
238
	free(pkcs11->module_path);
250
	free(pkcs11->module_path);
239
	free(pkcs11->token);
251
	free(pkcs11->token);
252
	free(pkcs11->object);
240
	free(pkcs11->lib_manuf);
253
	free(pkcs11->lib_manuf);
241
	free(pkcs11->manuf);
254
	free(pkcs11->manuf);
242
	free(pkcs11);
255
	free(pkcs11);
Lines 326-331 pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11) Link Here
326
			    __func__, keywords[opcode].name, *charptr);
339
			    __func__, keywords[opcode].name, *charptr);
327
			break;
340
			break;
328
341
342
		case pObject:
343
			/* CK_TOKEN_INFO -> manufacturerID */
344
			charptr = &pkcs11->object;
345
			goto parse_string;
346
329
		case pManufacturer:
347
		case pManufacturer:
330
			/* CK_TOKEN_INFO -> manufacturerID */
348
			/* CK_TOKEN_INFO -> manufacturerID */
331
			charptr = &pkcs11->manuf;
349
			charptr = &pkcs11->manuf;
(-)a/ssh-pkcs11-uri.h (+1 lines)
Lines 26-31 struct pkcs11_uri { Link Here
26
	char *id;
26
	char *id;
27
	size_t id_len;
27
	size_t id_len;
28
	char *token;
28
	char *token;
29
	char *object;
29
	char *lib_manuf;
30
	char *lib_manuf;
30
	char *manuf;
31
	char *manuf;
31
	/* query */
32
	/* query */
(-)a/ssh-pkcs11.c (-29 / +50 lines)
Lines 70-75 struct pkcs11_key { Link Here
70
	int			(*orig_finish)(RSA *rsa);
70
	int			(*orig_finish)(RSA *rsa);
71
	RSA_METHOD		*rsa_method;
71
	RSA_METHOD		*rsa_method;
72
	char			*keyid;
72
	char			*keyid;
73
	char			*label;
73
	int			keyid_len;
74
	int			keyid_len;
74
};
75
};
75
76
Lines 77-83 int pkcs11_interactive = 0; Link Here
77
78
78
/*
79
/*
79
 * This can't be in the ssh-pkcs11-uri, becase we can not depend on
80
 * This can't be in the ssh-pkcs11-uri, becase we can not depend on
80
 * PKCS structures in ssh-agent (using client-helper communication)
81
 * PKCS#11 structures in ssh-agent (using client-helper communication)
81
 */
82
 */
82
int
83
int
83
pkcs11_uri_write(const struct sshkey *key, FILE *f)
84
pkcs11_uri_write(const struct sshkey *key, FILE *f)
Lines 95-100 pkcs11_uri_write(const struct sshkey *key, FILE *f) Link Here
95
	uri.id = k11->keyid;
96
	uri.id = k11->keyid;
96
	uri.id_len = k11->keyid_len;
97
	uri.id_len = k11->keyid_len;
97
	uri.token = k11->provider->slotinfo[k11->slotidx].token.label;
98
	uri.token = k11->provider->slotinfo[k11->slotidx].token.label;
99
	uri.object = k11->label;
98
	uri.module_path = k11->provider->module_path;
100
	uri.module_path = k11->provider->module_path;
99
	uri.lib_manuf = k11->provider->info.manufacturerID;
101
	uri.lib_manuf = k11->provider->info.manufacturerID;
100
	uri.manuf = k11->provider->slotinfo[k11->slotidx].token.manufacturerID;
102
	uri.manuf = k11->provider->slotinfo[k11->slotidx].token.manufacturerID;
Lines 253-258 pkcs11_rsa_finish(RSA *rsa) Link Here
253
		if (k11->provider)
255
		if (k11->provider)
254
			pkcs11_provider_unref(k11->provider);
256
			pkcs11_provider_unref(k11->provider);
255
		free(k11->keyid);
257
		free(k11->keyid);
258
		free(k11->label);
256
		free(k11);
259
		free(k11);
257
	}
260
	}
258
	return (rv);
261
	return (rv);
Lines 381-387 pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa, Link Here
381
/* redirect private key operations for rsa key to pkcs11 token */
384
/* redirect private key operations for rsa key to pkcs11 token */
382
static int
385
static int
383
pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
386
pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
384
    CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
387
    CK_ATTRIBUTE *keyid_attrib, CK_ATTRIBUTE *label_attrib, RSA *rsa)
385
{
388
{
386
	struct pkcs11_key	*k11;
389
	struct pkcs11_key	*k11;
387
	const RSA_METHOD	*def = RSA_get_default_method();
390
	const RSA_METHOD	*def = RSA_get_default_method();
Lines 396-401 pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, Link Here
396
		k11->keyid = xmalloc(k11->keyid_len);
399
		k11->keyid = xmalloc(k11->keyid_len);
397
		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
400
		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
398
	}
401
	}
402
	if (label_attrib->ulValueLen > 0 ) {
403
		k11->label = xmalloc(label_attrib->ulValueLen+1);
404
		memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen);
405
		k11->label[label_attrib->ulValueLen] = 0;
406
	}
399
	k11->orig_finish = RSA_meth_get_finish(def);
407
	k11->orig_finish = RSA_meth_get_finish(def);
400
	if ((k11->rsa_method = RSA_meth_dup(def)) == NULL ||
408
	if ((k11->rsa_method = RSA_meth_dup(def)) == NULL ||
401
	    RSA_meth_set1_name(k11->rsa_method, "pkcs11") == 0 ||
409
	    RSA_meth_set1_name(k11->rsa_method, "pkcs11") == 0 ||
Lines 487-505 pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
487
	CK_OBJECT_CLASS	cert_class = CKO_CERTIFICATE;
495
	CK_OBJECT_CLASS	cert_class = CKO_CERTIFICATE;
488
	CK_ATTRIBUTE		pubkey_filter[] = {
496
	CK_ATTRIBUTE		pubkey_filter[] = {
489
		{ CKA_CLASS, NULL, sizeof(pubkey_class) },
497
		{ CKA_CLASS, NULL, sizeof(pubkey_class) },
490
		{ CKA_ID, NULL, 0 }
498
		{ CKA_ID, NULL, 0 },
499
		{ CKA_LABEL, NULL, 0 }
491
	};
500
	};
492
	CK_ATTRIBUTE		cert_filter[] = {
501
	CK_ATTRIBUTE		cert_filter[] = {
493
		{ CKA_CLASS, NULL, sizeof(cert_class) },
502
		{ CKA_CLASS, NULL, sizeof(cert_class) },
494
		{ CKA_ID, NULL, 0 }
503
		{ CKA_ID, NULL, 0 },
504
		{ CKA_LABEL, NULL, 0 }
495
	};
505
	};
496
	CK_ATTRIBUTE		pubkey_attribs[] = {
506
	CK_ATTRIBUTE		pubkey_attribs[] = {
497
		{ CKA_ID, NULL, 0 },
507
		{ CKA_ID, NULL, 0 },
508
		{ CKA_LABEL, NULL, 0 },
498
		{ CKA_MODULUS, NULL, 0 },
509
		{ CKA_MODULUS, NULL, 0 },
499
		{ CKA_PUBLIC_EXPONENT, NULL, 0 }
510
		{ CKA_PUBLIC_EXPONENT, NULL, 0 }
500
	};
511
	};
501
	CK_ATTRIBUTE		cert_attribs[] = {
512
	CK_ATTRIBUTE		cert_attribs[] = {
502
		{ CKA_ID, NULL, 0 },
513
		{ CKA_ID, NULL, 0 },
514
		{ CKA_LABEL, NULL, 0 },
503
		{ CKA_SUBJECT, NULL, 0 },
515
		{ CKA_SUBJECT, NULL, 0 },
504
		{ CKA_VALUE, NULL, 0 }
516
		{ CKA_VALUE, NULL, 0 }
505
	};
517
	};
Lines 507-517 pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
507
	cert_filter[0].pValue = &cert_class;
519
	cert_filter[0].pValue = &cert_class;
508
520
509
	if (uri->id != NULL) {
521
	if (uri->id != NULL) {
510
		pubkey_filter[1].pValue = uri->id;
522
		pubkey_filter[filter_size].pValue = uri->id;
511
		pubkey_filter[1].ulValueLen = uri->id_len;
523
		pubkey_filter[filter_size].ulValueLen = uri->id_len;
512
		cert_filter[1].pValue = uri->id;
524
		cert_filter[filter_size].pValue = uri->id;
513
		cert_filter[1].ulValueLen = uri->id_len;
525
		cert_filter[filter_size].ulValueLen = uri->id_len;
514
		filter_size = 2;
526
		filter_size++;
527
	}
528
	if (uri->object != NULL) {
529
		pubkey_filter[filter_size].pValue = uri->object;
530
		pubkey_filter[filter_size].ulValueLen = strlen(uri->object);
531
		pubkey_filter[filter_size].type = CKA_LABEL;
532
		cert_filter[filter_size].pValue = uri->object;
533
		cert_filter[filter_size].ulValueLen = strlen(uri->object);
534
		cert_filter[filter_size].type = CKA_LABEL;
535
		filter_size++;
515
	}
536
	}
516
537
517
	if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, filter_size,
538
	if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, filter_size,
Lines 535-541 pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key) Link Here
535
556
536
static int
557
static int
537
pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
558
pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
538
    CK_ATTRIBUTE filter[], size_t filter_size, CK_ATTRIBUTE attribs[3],
559
    CK_ATTRIBUTE filter[], size_t filter_size, CK_ATTRIBUTE attribs[4],
539
    struct sshkey ***keysp, int *nkeys)
560
    struct sshkey ***keysp, int *nkeys)
540
{
561
{
541
	struct sshkey		*key;
562
	struct sshkey		*key;
Lines 543-548 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
543
	X509 			*x509;
564
	X509 			*x509;
544
	EVP_PKEY		*evp = NULL;
565
	EVP_PKEY		*evp = NULL;
545
	int			i;
566
	int			i;
567
	int			nattribs = 4;
546
	const u_char		*cp;
568
	const u_char		*cp;
547
	CK_RV			rv;
569
	CK_RV			rv;
548
	CK_OBJECT_HANDLE	obj;
570
	CK_OBJECT_HANDLE	obj;
Lines 560-566 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
560
	}
582
	}
561
	while (1) {
583
	while (1) {
562
		/* XXX 3 attributes in attribs[] */
584
		/* XXX 3 attributes in attribs[] */
563
		for (i = 0; i < 3; i++) {
585
		for (i = 0; i < nattribs; i++) {
564
			attribs[i].pValue = NULL;
586
			attribs[i].pValue = NULL;
565
			attribs[i].ulValueLen = 0;
587
			attribs[i].ulValueLen = 0;
566
		}
588
		}
Lines 568-589 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
568
		    || nfound == 0)
590
		    || nfound == 0)
569
			break;
591
			break;
570
		/* found a key, so figure out size of the attributes */
592
		/* found a key, so figure out size of the attributes */
571
		if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
593
		if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs))
572
		    != CKR_OK) {
594
		    != CKR_OK) {
573
			error("C_GetAttributeValue failed: %lu", rv);
595
			error("C_GetAttributeValue failed: %lu", rv);
574
			continue;
596
			continue;
575
		}
597
		}
576
		/*
598
		/*
577
		 * Allow CKA_ID (always first attribute) to be empty, but
599
		 * Allow CKA_ID (always first attribute) and CKA_LABEL (second)
578
		 * ensure that none of the others are zero length.
600
		 * to be empty, but ensure that none of the others are zero length.
579
		 * XXX assumes CKA_ID is always first.
601
		 * XXX assumes CKA_ID is always first.
580
		 */
602
		 */
581
		if (attribs[1].ulValueLen == 0 ||
603
		if (attribs[2].ulValueLen == 0 ||
582
		    attribs[2].ulValueLen == 0) {
604
		    attribs[3].ulValueLen == 0) {
583
			continue;
605
			continue;
584
		}
606
		}
585
		/* allocate buffers for attributes */
607
		/* allocate buffers for attributes */
586
		for (i = 0; i < 3; i++) {
608
		for (i = 0; i < nattribs; i++) {
587
			if (attribs[i].ulValueLen > 0) {
609
			if (attribs[i].ulValueLen > 0) {
588
				attribs[i].pValue = xmalloc(
610
				attribs[i].pValue = xmalloc(
589
				    attribs[i].ulValueLen);
611
				    attribs[i].ulValueLen);
Lines 591-621 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
591
		}
613
		}
592
614
593
		/*
615
		/*
594
		 * retrieve ID, modulus and public exponent of RSA key,
616
		 * retrieve ID, label, modulus and public exponent of RSA key,
595
		 * or ID, subject and value for certificates.
617
		 * or ID, label, subject and value for certificates.
596
		 */
618
		 */
597
		rsa = NULL;
619
		rsa = NULL;
598
		if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
620
		if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs))
599
		    != CKR_OK) {
621
		    != CKR_OK) {
600
			error("C_GetAttributeValue failed: %lu", rv);
622
			error("C_GetAttributeValue failed: %lu", rv);
601
		} else if (attribs[1].type == CKA_MODULUS ) {
623
		} else if (attribs[2].type == CKA_MODULUS ) {
602
			if ((rsa = RSA_new()) == NULL) {
624
			if ((rsa = RSA_new()) == NULL) {
603
				error("RSA_new failed");
625
				error("RSA_new failed");
604
			} else {
626
			} else {
605
				BIGNUM *rsa_n, *rsa_e;
627
				BIGNUM *rsa_n, *rsa_e;
606
628
607
				rsa_n = BN_bin2bn(attribs[1].pValue,
629
				rsa_n = BN_bin2bn(attribs[2].pValue,
608
				    attribs[1].ulValueLen, NULL);
609
				rsa_e = BN_bin2bn(attribs[2].pValue,
610
				    attribs[2].ulValueLen, NULL);
630
				    attribs[2].ulValueLen, NULL);
631
				rsa_e = BN_bin2bn(attribs[3].pValue,
632
				    attribs[3].ulValueLen, NULL);
611
				if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) == 0)
633
				if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) == 0)
612
					error("RSA_set0_key failed");
634
					error("RSA_set0_key failed");
613
			}
635
			}
614
		} else {
636
		} else {
615
			cp = attribs[2].pValue;
637
			cp = attribs[3].pValue;
616
			if ((x509 = X509_new()) == NULL) {
638
			if ((x509 = X509_new()) == NULL) {
617
				error("X509_new failed");
639
				error("X509_new failed");
618
			} else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen)
640
			} else if (d2i_X509(&x509, &cp, attribs[3].ulValueLen)
619
			    == NULL) {
641
			    == NULL) {
620
				error("d2i_X509 failed");
642
				error("d2i_X509 failed");
621
			} else if ((evp = X509_get_pubkey(x509)) == NULL ||
643
			} else if ((evp = X509_get_pubkey(x509)) == NULL ||
Lines 634-640 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
634
		if (rsa)
656
		if (rsa)
635
			RSA_get0_key(rsa, &n, &e, NULL);
657
			RSA_get0_key(rsa, &n, &e, NULL);
636
		if (rsa && n && e &&
658
		if (rsa && n && e &&
637
		    pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
659
		    pkcs11_rsa_wrap(p, slotidx, &attribs[0], &attribs[1], rsa) == 0) {
638
			if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
660
			if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
639
				fatal("sshkey_new failed");
661
				fatal("sshkey_new failed");
640
			key->rsa = rsa;
662
			key->rsa = rsa;
Lines 653-659 pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, Link Here
653
		} else if (rsa) {
675
		} else if (rsa) {
654
			RSA_free(rsa);
676
			RSA_free(rsa);
655
		}
677
		}
656
		for (i = 0; i < 3; i++)
678
		for (i = 0; i < nattribs; i++)
657
			free(attribs[i].pValue);
679
			free(attribs[i].pValue);
658
	}
680
	}
659
	if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
681
	if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
660
- 

Return to bug 2817