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

Collapse All | Expand All

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

Return to bug 2817