summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--Makefile.in20
-rw-r--r--configure.ac8
-rw-r--r--pathnames.h7
-rw-r--r--readconf.c16
-rw-r--r--readconf.h4
-rw-r--r--scp.16
-rw-r--r--sftp.16
-rw-r--r--ssh-add.116
-rw-r--r--ssh-add.c20
-rw-r--r--ssh-agent.c101
-rw-r--r--ssh-keygen.114
-rw-r--r--ssh-keygen.c84
-rw-r--r--ssh-pkcs11-client.c229
-rw-r--r--ssh-pkcs11-helper.c349
-rw-r--r--ssh-pkcs11.c544
-rw-r--r--ssh-pkcs11.h19
-rw-r--r--ssh.114
-rw-r--r--ssh.c29
-rw-r--r--ssh_config.518
20 files changed, 1326 insertions, 188 deletions
diff --git a/ChangeLog b/ChangeLog
index 2c815a3ab..776116171 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,16 @@
5 make buffer_get_string_ret() really non-fatal in all cases (it was 5 make buffer_get_string_ret() really non-fatal in all cases (it was
6 using buffer_get_int(), which could fatal() on buffer empty); 6 using buffer_get_int(), which could fatal() on buffer empty);
7 ok markus dtucker 7 ok markus dtucker
8 - markus@cvs.openbsd.org 2010/02/08 10:50:20
9 [pathnames.h readconf.c readconf.h scp.1 sftp.1 ssh-add.1 ssh-add.c]
10 [ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config.5]
11 replace our obsolete smartcard code with PKCS#11.
12 ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-20/pkcs-11v2-20.pdf
13 ssh(1) and ssh-keygen(1) use dlopen(3) directly to talk to a PKCS#11
14 provider (shared library) while ssh-agent(1) delegates PKCS#11 to
15 a forked a ssh-pkcs11-helper process.
16 PKCS#11 is currently a compile time option.
17 feedback and ok djm@; inspired by patches from Alon Bar-Lev
8 18
920100210 1920100210
10 - (djm) add -lselinux to LIBS before calling AC_CHECK_FUNCS for 20 - (djm) add -lselinux to LIBS before calling AC_CHECK_FUNCS for
diff --git a/Makefile.in b/Makefile.in
index d7f338c0f..0c45bfca6 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
1# $Id: Makefile.in,v 1.303 2010/01/08 08:27:57 dtucker Exp $ 1# $Id: Makefile.in,v 1.304 2010/02/11 22:21:02 djm Exp $
2 2
3# uncomment if you run a non bourne compatable shell. Ie. csh 3# uncomment if you run a non bourne compatable shell. Ie. csh
4#SHELL = @SH@ 4#SHELL = @SH@
@@ -25,6 +25,7 @@ SSH_PROGRAM=@bindir@/ssh
25ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass 25ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
26SFTP_SERVER=$(libexecdir)/sftp-server 26SFTP_SERVER=$(libexecdir)/sftp-server
27SSH_KEYSIGN=$(libexecdir)/ssh-keysign 27SSH_KEYSIGN=$(libexecdir)/ssh-keysign
28SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
28RAND_HELPER=$(libexecdir)/ssh-rand-helper 29RAND_HELPER=$(libexecdir)/ssh-rand-helper
29PRIVSEP_PATH=@PRIVSEP_PATH@ 30PRIVSEP_PATH=@PRIVSEP_PATH@
30SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ 31SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
@@ -35,6 +36,7 @@ PATHS= -DSSHDIR=\"$(sysconfdir)\" \
35 -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ 36 -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \
36 -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \ 37 -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \
37 -D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \ 38 -D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
39 -D_PATH_SSH_PKCS11_HELPER=\"$(SSH_PKCS11_HELPER)\" \
38 -D_PATH_SSH_PIDDIR=\"$(piddir)\" \ 40 -D_PATH_SSH_PIDDIR=\"$(piddir)\" \
39 -D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \ 41 -D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \
40 -DSSH_RAND_HELPER=\"$(RAND_HELPER)\" 42 -DSSH_RAND_HELPER=\"$(RAND_HELPER)\"
@@ -60,7 +62,7 @@ EXEEXT=@EXEEXT@
60INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ 62INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
61INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ 63INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
62 64
63TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) 65TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT)
64 66
65LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ 67LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
66 canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \ 68 canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
@@ -71,7 +73,8 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
71 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ 73 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
72 monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ 74 monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
73 kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ 75 kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
74 entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o 76 entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o \
77 ssh-pkcs11.o
75 78
76SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ 79SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
77 sshconnect.o sshconnect1.o sshconnect2.o mux.o \ 80 sshconnect.o sshconnect1.o sshconnect2.o mux.o \
@@ -147,8 +150,8 @@ scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o
147ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o 150ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
148 $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 151 $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
149 152
150ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o 153ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o
151 $(LD) -o $@ ssh-agent.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 154 $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
152 155
153ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o 156ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
154 $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 157 $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
@@ -156,6 +159,9 @@ ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
156ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o 159ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o
157 $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 160 $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
158 161
162ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
163 $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
164
159ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o 165ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
160 $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) 166 $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
161 167
@@ -265,6 +271,7 @@ install-files: scard-install
265 $(INSTALL) -m 0755 $(STRIP_OPT) ssh-rand-helper $(DESTDIR)$(libexecdir)/ssh-rand-helper ; \ 271 $(INSTALL) -m 0755 $(STRIP_OPT) ssh-rand-helper $(DESTDIR)$(libexecdir)/ssh-rand-helper ; \
266 fi 272 fi
267 $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign $(DESTDIR)$(SSH_KEYSIGN) 273 $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign $(DESTDIR)$(SSH_KEYSIGN)
274 $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper $(DESTDIR)$(SSH_PKCS11_HELPER)
268 $(INSTALL) -m 0755 $(STRIP_OPT) sftp $(DESTDIR)$(bindir)/sftp 275 $(INSTALL) -m 0755 $(STRIP_OPT) sftp $(DESTDIR)$(bindir)/sftp
269 $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server $(DESTDIR)$(SFTP_SERVER) 276 $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server $(DESTDIR)$(SFTP_SERVER)
270 $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 277 $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
@@ -368,6 +375,7 @@ uninstall:
368 -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT) 375 -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
369 -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) 376 -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
370 -rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) 377 -rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
378 -rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
371 -rm -f $(DESTDIR)$(RAND_HELPER)$(EXEEXT) 379 -rm -f $(DESTDIR)$(RAND_HELPER)$(EXEEXT)
372 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 380 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
373 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 381 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
@@ -393,6 +401,7 @@ tests interop-tests: $(TARGETS)
393 TEST_SSH_SSHAGENT="$${BUILDDIR}/ssh-agent"; \ 401 TEST_SSH_SSHAGENT="$${BUILDDIR}/ssh-agent"; \
394 TEST_SSH_SSHADD="$${BUILDDIR}/ssh-add"; \ 402 TEST_SSH_SSHADD="$${BUILDDIR}/ssh-add"; \
395 TEST_SSH_SSHKEYGEN="$${BUILDDIR}/ssh-keygen"; \ 403 TEST_SSH_SSHKEYGEN="$${BUILDDIR}/ssh-keygen"; \
404 TEST_SSH_SSHPKCS11HELPER="$${BUILDDIR}/ssh-pkcs11-helper"; \
396 TEST_SSH_SSHKEYSCAN="$${BUILDDIR}/ssh-keyscan"; \ 405 TEST_SSH_SSHKEYSCAN="$${BUILDDIR}/ssh-keyscan"; \
397 TEST_SSH_SFTP="$${BUILDDIR}/sftp"; \ 406 TEST_SSH_SFTP="$${BUILDDIR}/sftp"; \
398 TEST_SSH_SFTPSERVER="$${BUILDDIR}/sftp-server"; \ 407 TEST_SSH_SFTPSERVER="$${BUILDDIR}/sftp-server"; \
@@ -413,6 +422,7 @@ tests interop-tests: $(TARGETS)
413 TEST_SSH_SSHAGENT="$${TEST_SSH_SSHAGENT}" \ 422 TEST_SSH_SSHAGENT="$${TEST_SSH_SSHAGENT}" \
414 TEST_SSH_SSHADD="$${TEST_SSH_SSHADD}" \ 423 TEST_SSH_SSHADD="$${TEST_SSH_SSHADD}" \
415 TEST_SSH_SSHKEYGEN="$${TEST_SSH_SSHKEYGEN}" \ 424 TEST_SSH_SSHKEYGEN="$${TEST_SSH_SSHKEYGEN}" \
425 TEST_SSH_SSHPKCS11HELPER="$${TEST_SSH_SSHPKCS11HELPER}" \
416 TEST_SSH_SSHKEYSCAN="$${TEST_SSH_SSHKEYSCAN}" \ 426 TEST_SSH_SSHKEYSCAN="$${TEST_SSH_SSHKEYSCAN}" \
417 TEST_SSH_SFTP="$${TEST_SSH_SFTP}" \ 427 TEST_SSH_SFTP="$${TEST_SSH_SFTP}" \
418 TEST_SSH_SFTPSERVER="$${TEST_SSH_SFTPSERVER}" \ 428 TEST_SSH_SFTPSERVER="$${TEST_SSH_SFTPSERVER}" \
diff --git a/configure.ac b/configure.ac
index 5fc1d4a46..717d315fd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
1# $Id: configure.ac,v 1.440 2010/02/09 23:19:29 djm Exp $ 1# $Id: configure.ac,v 1.441 2010/02/11 22:21:02 djm Exp $
2# 2#
3# Copyright (c) 1999-2004 Damien Miller 3# Copyright (c) 1999-2004 Damien Miller
4# 4#
@@ -15,7 +15,7 @@
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
17AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org) 17AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org)
18AC_REVISION($Revision: 1.440 $) 18AC_REVISION($Revision: 1.441 $)
19AC_CONFIG_SRCDIR([ssh.c]) 19AC_CONFIG_SRCDIR([ssh.c])
20 20
21AC_CONFIG_HEADER(config.h) 21AC_CONFIG_HEADER(config.h)
@@ -4197,6 +4197,10 @@ else
4197 AC_SUBST(TEST_SSH_IPV6, yes) 4197 AC_SUBST(TEST_SSH_IPV6, yes)
4198fi 4198fi
4199 4199
4200if test "x$enable_pkcs11" != "xno" ; then
4201 AC_DEFINE([ENABLE_PKCS11], [], [Enable for PKCS#11 support])
4202fi
4203
4200AC_EXEEXT 4204AC_EXEEXT
4201AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \ 4205AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \
4202 openbsd-compat/Makefile openbsd-compat/regress/Makefile \ 4206 openbsd-compat/Makefile openbsd-compat/regress/Makefile \
diff --git a/pathnames.h b/pathnames.h
index 80c5d9cbb..32b9e065b 100644
--- a/pathnames.h
+++ b/pathnames.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: pathnames.h,v 1.17 2008/12/29 02:23:26 stevesk Exp $ */ 1/* $OpenBSD: pathnames.h,v 1.18 2010/02/08 10:50:20 markus Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -125,6 +125,11 @@
125#define _PATH_SSH_KEY_SIGN "/usr/libexec/ssh-keysign" 125#define _PATH_SSH_KEY_SIGN "/usr/libexec/ssh-keysign"
126#endif 126#endif
127 127
128/* Location of ssh-keysign for hostbased authentication */
129#ifndef _PATH_SSH_PKCS11_HELPER
130#define _PATH_SSH_PKCS11_HELPER "/usr/libexec/ssh-pkcs11-helper"
131#endif
132
128/* xauth for X11 forwarding */ 133/* xauth for X11 forwarding */
129#ifndef _PATH_XAUTH 134#ifndef _PATH_XAUTH
130#define _PATH_XAUTH "/usr/X11R6/bin/xauth" 135#define _PATH_XAUTH "/usr/X11R6/bin/xauth"
diff --git a/readconf.c b/readconf.c
index d424c1697..8bdc8caf1 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.182 2010/01/09 23:04:13 dtucker Exp $ */ 1/* $OpenBSD: readconf.c,v 1.183 2010/02/08 10:50:20 markus Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -123,7 +123,7 @@ typedef enum {
123 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, 123 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
124 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 124 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
125 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 125 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
126 oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, 126 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
127 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 127 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
128 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 128 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
129 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 129 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
@@ -205,10 +205,12 @@ static struct {
205 { "preferredauthentications", oPreferredAuthentications }, 205 { "preferredauthentications", oPreferredAuthentications },
206 { "hostkeyalgorithms", oHostKeyAlgorithms }, 206 { "hostkeyalgorithms", oHostKeyAlgorithms },
207 { "bindaddress", oBindAddress }, 207 { "bindaddress", oBindAddress },
208#ifdef SMARTCARD 208#ifdef ENABLE_PKCS11
209 { "smartcarddevice", oSmartcardDevice }, 209 { "smartcarddevice", oPKCS11Provider },
210 { "pkcs11provider", oPKCS11Provider },
210#else 211#else
211 { "smartcarddevice", oUnsupported }, 212 { "smartcarddevice", oUnsupported },
213 { "pkcs11provider", oUnsupported },
212#endif 214#endif
213 { "clearallforwardings", oClearAllForwardings }, 215 { "clearallforwardings", oClearAllForwardings },
214 { "enablesshkeysign", oEnableSSHKeysign }, 216 { "enablesshkeysign", oEnableSSHKeysign },
@@ -609,8 +611,8 @@ parse_string:
609 charptr = &options->bind_address; 611 charptr = &options->bind_address;
610 goto parse_string; 612 goto parse_string;
611 613
612 case oSmartcardDevice: 614 case oPKCS11Provider:
613 charptr = &options->smartcard_device; 615 charptr = &options->pkcs11_provider;
614 goto parse_string; 616 goto parse_string;
615 617
616 case oProxyCommand: 618 case oProxyCommand:
@@ -1051,7 +1053,7 @@ initialize_options(Options * options)
1051 options->log_level = SYSLOG_LEVEL_NOT_SET; 1053 options->log_level = SYSLOG_LEVEL_NOT_SET;
1052 options->preferred_authentications = NULL; 1054 options->preferred_authentications = NULL;
1053 options->bind_address = NULL; 1055 options->bind_address = NULL;
1054 options->smartcard_device = NULL; 1056 options->pkcs11_provider = NULL;
1055 options->enable_ssh_keysign = - 1; 1057 options->enable_ssh_keysign = - 1;
1056 options->no_host_authentication_for_localhost = - 1; 1058 options->no_host_authentication_for_localhost = - 1;
1057 options->identities_only = - 1; 1059 options->identities_only = - 1;
diff --git a/readconf.h b/readconf.h
index f7c0b9c6d..4264751c5 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.81 2010/01/09 23:04:13 dtucker Exp $ */ 1/* $OpenBSD: readconf.h,v 1.82 2010/02/08 10:50:20 markus Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -84,7 +84,7 @@ typedef struct {
84 char *user_hostfile2; 84 char *user_hostfile2;
85 char *preferred_authentications; 85 char *preferred_authentications;
86 char *bind_address; /* local socket address for connection to sshd */ 86 char *bind_address; /* local socket address for connection to sshd */
87 char *smartcard_device; /* Smartcard reader device */ 87 char *pkcs11_provider; /* PKCS#11 provider */
88 int verify_host_key_dns; /* Verify host key using DNS */ 88 int verify_host_key_dns; /* Verify host key using DNS */
89 89
90 int num_identity_files; /* Number of files for RSA/DSA identities. */ 90 int num_identity_files; /* Number of files for RSA/DSA identities. */
diff --git a/scp.1 b/scp.1
index 74ee5db13..bc5e259f5 100644
--- a/scp.1
+++ b/scp.1
@@ -9,9 +9,9 @@
9.\" 9.\"
10.\" Created: Sun May 7 00:14:37 1995 ylo 10.\" Created: Sun May 7 00:14:37 1995 ylo
11.\" 11.\"
12.\" $OpenBSD: scp.1,v 1.49 2010/01/09 23:04:13 dtucker Exp $ 12.\" $OpenBSD: scp.1,v 1.50 2010/02/08 10:50:20 markus Exp $
13.\" 13.\"
14.Dd $Mdocdate: January 9 2010 $ 14.Dd $Mdocdate: February 8 2010 $
15.Dt SCP 1 15.Dt SCP 1
16.Os 16.Os
17.Sh NAME 17.Sh NAME
@@ -153,6 +153,7 @@ For full details of the options listed below, and their possible values, see
153.It NoHostAuthenticationForLocalhost 153.It NoHostAuthenticationForLocalhost
154.It NumberOfPasswordPrompts 154.It NumberOfPasswordPrompts
155.It PasswordAuthentication 155.It PasswordAuthentication
156.It PKCS11Provider
156.It Port 157.It Port
157.It PreferredAuthentications 158.It PreferredAuthentications
158.It Protocol 159.It Protocol
@@ -164,7 +165,6 @@ For full details of the options listed below, and their possible values, see
164.It SendEnv 165.It SendEnv
165.It ServerAliveInterval 166.It ServerAliveInterval
166.It ServerAliveCountMax 167.It ServerAliveCountMax
167.It SmartcardDevice
168.It StrictHostKeyChecking 168.It StrictHostKeyChecking
169.It TCPKeepAlive 169.It TCPKeepAlive
170.It UsePrivilegedPort 170.It UsePrivilegedPort
diff --git a/sftp.1 b/sftp.1
index 175dc6520..777b02a58 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: sftp.1,v 1.82 2010/01/13 12:48:34 jmc Exp $ 1.\" $OpenBSD: sftp.1,v 1.83 2010/02/08 10:50:20 markus Exp $
2.\" 2.\"
3.\" Copyright (c) 2001 Damien Miller. All rights reserved. 3.\" Copyright (c) 2001 Damien Miller. All rights reserved.
4.\" 4.\"
@@ -22,7 +22,7 @@
22.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24.\" 24.\"
25.Dd $Mdocdate: January 13 2010 $ 25.Dd $Mdocdate: February 8 2010 $
26.Dt SFTP 1 26.Dt SFTP 1
27.Os 27.Os
28.Sh NAME 28.Sh NAME
@@ -202,6 +202,7 @@ For full details of the options listed below, and their possible values, see
202.It NoHostAuthenticationForLocalhost 202.It NoHostAuthenticationForLocalhost
203.It NumberOfPasswordPrompts 203.It NumberOfPasswordPrompts
204.It PasswordAuthentication 204.It PasswordAuthentication
205.It PKCS11Provider
205.It Port 206.It Port
206.It PreferredAuthentications 207.It PreferredAuthentications
207.It Protocol 208.It Protocol
@@ -213,7 +214,6 @@ For full details of the options listed below, and their possible values, see
213.It SendEnv 214.It SendEnv
214.It ServerAliveInterval 215.It ServerAliveInterval
215.It ServerAliveCountMax 216.It ServerAliveCountMax
216.It SmartcardDevice
217.It StrictHostKeyChecking 217.It StrictHostKeyChecking
218.It TCPKeepAlive 218.It TCPKeepAlive
219.It UsePrivilegedPort 219.It UsePrivilegedPort
diff --git a/ssh-add.1 b/ssh-add.1
index ee9a00ff0..a5dc3311a 100644
--- a/ssh-add.1
+++ b/ssh-add.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-add.1,v 1.48 2009/10/22 15:02:12 sobrado Exp $ 1.\" $OpenBSD: ssh-add.1,v 1.49 2010/02/08 10:50:20 markus Exp $
2.\" 2.\"
3.\" -*- nroff -*- 3.\" -*- nroff -*-
4.\" 4.\"
@@ -37,7 +37,7 @@
37.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 37.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
38.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39.\" 39.\"
40.Dd $Mdocdate: October 22 2009 $ 40.Dd $Mdocdate: February 8 2010 $
41.Dt SSH-ADD 1 41.Dt SSH-ADD 1
42.Os 42.Os
43.Sh NAME 43.Sh NAME
@@ -101,17 +101,17 @@ If no public key is found at a given path,
101will append 101will append
102.Pa .pub 102.Pa .pub
103and retry. 103and retry.
104.It Fl e Ar reader 104.It Fl e Ar pkcs11
105Remove key in smartcard 105Remove key provided by
106.Ar reader . 106.Ar pkcs11 .
107.It Fl L 107.It Fl L
108Lists public key parameters of all identities currently represented 108Lists public key parameters of all identities currently represented
109by the agent. 109by the agent.
110.It Fl l 110.It Fl l
111Lists fingerprints of all identities currently represented by the agent. 111Lists fingerprints of all identities currently represented by the agent.
112.It Fl s Ar reader 112.It Fl s Ar pkcs11
113Add key in smartcard 113Add key provider by
114.Ar reader . 114.Ar pkcs11 .
115.It Fl t Ar life 115.It Fl t Ar life
116Set a maximum lifetime when adding identities to an agent. 116Set a maximum lifetime when adding identities to an agent.
117The lifetime may be specified in seconds or in a time format 117The lifetime may be specified in seconds or in a time format
diff --git a/ssh-add.c b/ssh-add.c
index 084478d78..90e5be20b 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-add.c,v 1.91 2009/08/27 17:44:52 djm Exp $ */ 1/* $OpenBSD: ssh-add.c,v 1.92 2010/02/08 10:50:20 markus Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -211,7 +211,7 @@ update_card(AuthenticationConnection *ac, int add, const char *id)
211 char *pin; 211 char *pin;
212 int ret = -1; 212 int ret = -1;
213 213
214 pin = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN); 214 pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN);
215 if (pin == NULL) 215 if (pin == NULL)
216 return -1; 216 return -1;
217 217
@@ -317,10 +317,8 @@ usage(void)
317 fprintf(stderr, " -X Unlock agent.\n"); 317 fprintf(stderr, " -X Unlock agent.\n");
318 fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); 318 fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n");
319 fprintf(stderr, " -c Require confirmation to sign using identities\n"); 319 fprintf(stderr, " -c Require confirmation to sign using identities\n");
320#ifdef SMARTCARD 320 fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n");
321 fprintf(stderr, " -s reader Add key in smartcard reader.\n"); 321 fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n");
322 fprintf(stderr, " -e reader Remove key in smartcard reader.\n");
323#endif
324} 322}
325 323
326int 324int
@@ -329,7 +327,7 @@ main(int argc, char **argv)
329 extern char *optarg; 327 extern char *optarg;
330 extern int optind; 328 extern int optind;
331 AuthenticationConnection *ac = NULL; 329 AuthenticationConnection *ac = NULL;
332 char *sc_reader_id = NULL; 330 char *pkcs11provider = NULL;
333 int i, ch, deleting = 0, ret = 0; 331 int i, ch, deleting = 0, ret = 0;
334 332
335 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 333 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@@ -371,11 +369,11 @@ main(int argc, char **argv)
371 ret = 1; 369 ret = 1;
372 goto done; 370 goto done;
373 case 's': 371 case 's':
374 sc_reader_id = optarg; 372 pkcs11provider = optarg;
375 break; 373 break;
376 case 'e': 374 case 'e':
377 deleting = 1; 375 deleting = 1;
378 sc_reader_id = optarg; 376 pkcs11provider = optarg;
379 break; 377 break;
380 case 't': 378 case 't':
381 if ((lifetime = convtime(optarg)) == -1) { 379 if ((lifetime = convtime(optarg)) == -1) {
@@ -392,8 +390,8 @@ main(int argc, char **argv)
392 } 390 }
393 argc -= optind; 391 argc -= optind;
394 argv += optind; 392 argv += optind;
395 if (sc_reader_id != NULL) { 393 if (pkcs11provider != NULL) {
396 if (update_card(ac, !deleting, sc_reader_id) == -1) 394 if (update_card(ac, !deleting, pkcs11provider) == -1)
397 ret = 1; 395 ret = 1;
398 goto done; 396 goto done;
399 } 397 }
diff --git a/ssh-agent.c b/ssh-agent.c
index df3a87d9a..f745c2513 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-agent.c,v 1.162 2009/09/01 14:43:17 djm Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.163 2010/02/08 10:50:20 markus Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -76,8 +76,8 @@
76#include "log.h" 76#include "log.h"
77#include "misc.h" 77#include "misc.h"
78 78
79#ifdef SMARTCARD 79#ifdef ENABLE_PKCS11
80#include "scard.h" 80#include "ssh-pkcs11.h"
81#endif 81#endif
82 82
83#if defined(HAVE_SYS_PRCTL_H) 83#if defined(HAVE_SYS_PRCTL_H)
@@ -105,6 +105,7 @@ typedef struct identity {
105 TAILQ_ENTRY(identity) next; 105 TAILQ_ENTRY(identity) next;
106 Key *key; 106 Key *key;
107 char *comment; 107 char *comment;
108 char *provider;
108 u_int death; 109 u_int death;
109 u_int confirm; 110 u_int confirm;
110} Identity; 111} Identity;
@@ -171,6 +172,7 @@ static void
171free_identity(Identity *id) 172free_identity(Identity *id)
172{ 173{
173 key_free(id->key); 174 key_free(id->key);
175 xfree(id->provider);
174 xfree(id->comment); 176 xfree(id->comment);
175 xfree(id); 177 xfree(id);
176} 178}
@@ -549,7 +551,7 @@ process_add_identity(SocketEntry *e, int version)
549 if (lifetime && !death) 551 if (lifetime && !death)
550 death = time(NULL) + lifetime; 552 death = time(NULL) + lifetime;
551 if ((id = lookup_identity(k, version)) == NULL) { 553 if ((id = lookup_identity(k, version)) == NULL) {
552 id = xmalloc(sizeof(Identity)); 554 id = xcalloc(1, sizeof(Identity));
553 id->key = k; 555 id->key = k;
554 TAILQ_INSERT_TAIL(&tab->idlist, id, next); 556 TAILQ_INSERT_TAIL(&tab->idlist, id, next);
555 /* Increment the number of identities. */ 557 /* Increment the number of identities. */
@@ -609,17 +611,17 @@ no_identities(SocketEntry *e, u_int type)
609 buffer_free(&msg); 611 buffer_free(&msg);
610} 612}
611 613
612#ifdef SMARTCARD 614#ifdef ENABLE_PKCS11
613static void 615static void
614process_add_smartcard_key(SocketEntry *e) 616process_add_smartcard_key(SocketEntry *e)
615{ 617{
616 char *sc_reader_id = NULL, *pin; 618 char *provider = NULL, *pin;
617 int i, type, version, success = 0, death = 0, confirm = 0; 619 int i, type, version, count = 0, success = 0, death = 0, confirm = 0;
618 Key **keys, *k; 620 Key **keys = NULL, *k;
619 Identity *id; 621 Identity *id;
620 Idtab *tab; 622 Idtab *tab;
621 623
622 sc_reader_id = buffer_get_string(&e->request, NULL); 624 provider = buffer_get_string(&e->request, NULL);
623 pin = buffer_get_string(&e->request, NULL); 625 pin = buffer_get_string(&e->request, NULL);
624 626
625 while (buffer_len(&e->request)) { 627 while (buffer_len(&e->request)) {
@@ -633,30 +635,22 @@ process_add_smartcard_key(SocketEntry *e)
633 default: 635 default:
634 error("process_add_smartcard_key: " 636 error("process_add_smartcard_key: "
635 "Unknown constraint type %d", type); 637 "Unknown constraint type %d", type);
636 xfree(sc_reader_id);
637 xfree(pin);
638 goto send; 638 goto send;
639 } 639 }
640 } 640 }
641 if (lifetime && !death) 641 if (lifetime && !death)
642 death = time(NULL) + lifetime; 642 death = time(NULL) + lifetime;
643 643
644 keys = sc_get_keys(sc_reader_id, pin); 644 count = pkcs11_add_provider(provider, pin, &keys);
645 xfree(sc_reader_id); 645 for (i = 0; i < count; i++) {
646 xfree(pin);
647
648 if (keys == NULL || keys[0] == NULL) {
649 error("sc_get_keys failed");
650 goto send;
651 }
652 for (i = 0; keys[i] != NULL; i++) {
653 k = keys[i]; 646 k = keys[i];
654 version = k->type == KEY_RSA1 ? 1 : 2; 647 version = k->type == KEY_RSA1 ? 1 : 2;
655 tab = idtab_lookup(version); 648 tab = idtab_lookup(version);
656 if (lookup_identity(k, version) == NULL) { 649 if (lookup_identity(k, version) == NULL) {
657 id = xmalloc(sizeof(Identity)); 650 id = xcalloc(1, sizeof(Identity));
658 id->key = k; 651 id->key = k;
659 id->comment = sc_get_key_label(k); 652 id->provider = xstrdup(provider);
653 id->comment = xstrdup(provider); /* XXX */
660 id->death = death; 654 id->death = death;
661 id->confirm = confirm; 655 id->confirm = confirm;
662 TAILQ_INSERT_TAIL(&tab->idlist, id, next); 656 TAILQ_INSERT_TAIL(&tab->idlist, id, next);
@@ -667,8 +661,13 @@ process_add_smartcard_key(SocketEntry *e)
667 } 661 }
668 keys[i] = NULL; 662 keys[i] = NULL;
669 } 663 }
670 xfree(keys);
671send: 664send:
665 if (pin)
666 xfree(pin);
667 if (provider)
668 xfree(provider);
669 if (keys)
670 xfree(keys);
672 buffer_put_int(&e->output, 1); 671 buffer_put_int(&e->output, 1);
673 buffer_put_char(&e->output, 672 buffer_put_char(&e->output,
674 success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); 673 success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
@@ -677,42 +676,37 @@ send:
677static void 676static void
678process_remove_smartcard_key(SocketEntry *e) 677process_remove_smartcard_key(SocketEntry *e)
679{ 678{
680 char *sc_reader_id = NULL, *pin; 679 char *provider = NULL, *pin = NULL;
681 int i, version, success = 0; 680 int version, success = 0;
682 Key **keys, *k = NULL; 681 Identity *id, *nxt;
683 Identity *id;
684 Idtab *tab; 682 Idtab *tab;
685 683
686 sc_reader_id = buffer_get_string(&e->request, NULL); 684 provider = buffer_get_string(&e->request, NULL);
687 pin = buffer_get_string(&e->request, NULL); 685 pin = buffer_get_string(&e->request, NULL);
688 keys = sc_get_keys(sc_reader_id, pin);
689 xfree(sc_reader_id);
690 xfree(pin); 686 xfree(pin);
691 687
692 if (keys == NULL || keys[0] == NULL) { 688 for (version = 1; version < 3; version++) {
693 error("sc_get_keys failed"); 689 tab = idtab_lookup(version);
694 goto send; 690 for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
695 } 691 nxt = TAILQ_NEXT(id, next);
696 for (i = 0; keys[i] != NULL; i++) { 692 if (!strcmp(provider, id->provider)) {
697 k = keys[i]; 693 TAILQ_REMOVE(&tab->idlist, id, next);
698 version = k->type == KEY_RSA1 ? 1 : 2; 694 free_identity(id);
699 if ((id = lookup_identity(k, version)) != NULL) { 695 tab->nentries--;
700 tab = idtab_lookup(version); 696 }
701 TAILQ_REMOVE(&tab->idlist, id, next);
702 tab->nentries--;
703 free_identity(id);
704 success = 1;
705 } 697 }
706 key_free(k);
707 keys[i] = NULL;
708 } 698 }
709 xfree(keys); 699 if (pkcs11_del_provider(provider) == 0)
710send: 700 success = 1;
701 else
702 error("process_remove_smartcard_key:"
703 " pkcs11_del_provider failed");
704 xfree(provider);
711 buffer_put_int(&e->output, 1); 705 buffer_put_int(&e->output, 1);
712 buffer_put_char(&e->output, 706 buffer_put_char(&e->output,
713 success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); 707 success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
714} 708}
715#endif /* SMARTCARD */ 709#endif /* ENABLE_PKCS11 */
716 710
717/* dispatch incoming messages */ 711/* dispatch incoming messages */
718 712
@@ -797,7 +791,7 @@ process_message(SocketEntry *e)
797 case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: 791 case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
798 process_remove_all_identities(e, 2); 792 process_remove_all_identities(e, 2);
799 break; 793 break;
800#ifdef SMARTCARD 794#ifdef ENABLE_PKCS11
801 case SSH_AGENTC_ADD_SMARTCARD_KEY: 795 case SSH_AGENTC_ADD_SMARTCARD_KEY:
802 case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED: 796 case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
803 process_add_smartcard_key(e); 797 process_add_smartcard_key(e);
@@ -805,7 +799,7 @@ process_message(SocketEntry *e)
805 case SSH_AGENTC_REMOVE_SMARTCARD_KEY: 799 case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
806 process_remove_smartcard_key(e); 800 process_remove_smartcard_key(e);
807 break; 801 break;
808#endif /* SMARTCARD */ 802#endif /* ENABLE_PKCS11 */
809 default: 803 default:
810 /* Unknown message. Respond with failure. */ 804 /* Unknown message. Respond with failure. */
811 error("Unknown message %d", type); 805 error("Unknown message %d", type);
@@ -1009,6 +1003,9 @@ static void
1009cleanup_handler(int sig) 1003cleanup_handler(int sig)
1010{ 1004{
1011 cleanup_socket(); 1005 cleanup_socket();
1006#ifdef ENABLE_PKCS11
1007 pkcs11_terminate();
1008#endif
1012 _exit(2); 1009 _exit(2);
1013} 1010}
1014 1011
@@ -1255,6 +1252,10 @@ main(int ac, char **av)
1255#endif 1252#endif
1256 1253
1257skip: 1254skip:
1255
1256#ifdef ENABLE_PKCS11
1257 pkcs11_init(0);
1258#endif
1258 new_socket(AUTH_SOCKET, sock); 1259 new_socket(AUTH_SOCKET, sock);
1259 if (ac > 0) 1260 if (ac > 0)
1260 parent_alive_interval = 10; 1261 parent_alive_interval = 10;
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index 9e59c16f7..7dc76976a 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keygen.1,v 1.80 2009/10/24 00:48:34 dtucker Exp $ 1.\" $OpenBSD: ssh-keygen.1,v 1.81 2010/02/08 10:50:20 markus Exp $
2.\" 2.\"
3.\" -*- nroff -*- 3.\" -*- nroff -*-
4.\" 4.\"
@@ -37,7 +37,7 @@
37.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 37.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
38.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39.\" 39.\"
40.Dd $Mdocdate: October 24 2009 $ 40.Dd $Mdocdate: February 8 2010 $
41.Dt SSH-KEYGEN 1 41.Dt SSH-KEYGEN 1
42.Os 42.Os
43.Sh NAME 43.Sh NAME
@@ -201,9 +201,10 @@ Requests changing the comment in the private and public key files.
201This operation is only supported for RSA1 keys. 201This operation is only supported for RSA1 keys.
202The program will prompt for the file containing the private keys, for 202The program will prompt for the file containing the private keys, for
203the passphrase if the key has one, and for the new comment. 203the passphrase if the key has one, and for the new comment.
204.It Fl D Ar reader 204.It Fl D Ar pkcs11
205Download the RSA public key stored in the smartcard in 205Download the RSA public keys stored in the
206.Ar reader . 206.Ar pkcs11
207provider.
207.It Fl e 208.It Fl e
208This option will read a private or public OpenSSH key file and 209This option will read a private or public OpenSSH key file and
209print the key in 210print the key in
@@ -313,9 +314,6 @@ for protocol version 1 and
313or 314or
314.Dq dsa 315.Dq dsa
315for protocol version 2. 316for protocol version 2.
316.It Fl U Ar reader
317Upload an existing RSA private key into the smartcard in
318.Ar reader .
319.It Fl v 317.It Fl v
320Verbose mode. 318Verbose mode.
321Causes 319Causes
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 7f5185f8e..005f9c7ab 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.176 2010/01/11 10:51:07 djm Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.177 2010/02/08 10:50:20 markus Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -49,8 +49,8 @@
49#include "hostfile.h" 49#include "hostfile.h"
50#include "dns.h" 50#include "dns.h"
51 51
52#ifdef SMARTCARD 52#ifdef ENABLE_PKCS11
53#include "scard.h" 53#include "ssh-pkcs11.h"
54#endif 54#endif
55 55
56/* Number of bits in the RSA/DSA key. This value can be set on the command line. */ 56/* Number of bits in the RSA/DSA key. This value can be set on the command line. */
@@ -459,51 +459,29 @@ do_print_public(struct passwd *pw)
459 exit(0); 459 exit(0);
460} 460}
461 461
462#ifdef SMARTCARD
463static void 462static void
464do_upload(struct passwd *pw, const char *sc_reader_id) 463do_download(struct passwd *pw, const char *pkcs11provider)
465{
466 Key *prv = NULL;
467 struct stat st;
468 int ret;
469
470 if (!have_identity)
471 ask_filename(pw, "Enter file in which the key is");
472 if (stat(identity_file, &st) < 0) {
473 perror(identity_file);
474 exit(1);
475 }
476 prv = load_identity(identity_file);
477 if (prv == NULL) {
478 error("load failed");
479 exit(1);
480 }
481 ret = sc_put_key(prv, sc_reader_id);
482 key_free(prv);
483 if (ret < 0)
484 exit(1);
485 logit("loading key done");
486 exit(0);
487}
488
489static void
490do_download(struct passwd *pw, const char *sc_reader_id)
491{ 464{
465#ifdef ENABLE_PKCS11
492 Key **keys = NULL; 466 Key **keys = NULL;
493 int i; 467 int i, nkeys;
494 468
495 keys = sc_get_keys(sc_reader_id, NULL); 469 pkcs11_init(0);
496 if (keys == NULL) 470 nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys);
497 fatal("cannot read public key from smartcard"); 471 if (nkeys <= 0)
498 for (i = 0; keys[i]; i++) { 472 fatal("cannot read public key from pkcs11");
473 for (i = 0; i < nkeys; i++) {
499 key_write(keys[i], stdout); 474 key_write(keys[i], stdout);
500 key_free(keys[i]); 475 key_free(keys[i]);
501 fprintf(stdout, "\n"); 476 fprintf(stdout, "\n");
502 } 477 }
503 xfree(keys); 478 xfree(keys);
479 pkcs11_terminate();
504 exit(0); 480 exit(0);
481#else
482 fatal("no pkcs11 support");
483#endif /* ENABLE_PKCS11 */
505} 484}
506#endif /* SMARTCARD */
507 485
508static void 486static void
509do_fingerprint(struct passwd *pw) 487do_fingerprint(struct passwd *pw)
@@ -1044,9 +1022,9 @@ usage(void)
1044 fprintf(stderr, " -b bits Number of bits in the key to create.\n"); 1022 fprintf(stderr, " -b bits Number of bits in the key to create.\n");
1045 fprintf(stderr, " -C comment Provide new comment.\n"); 1023 fprintf(stderr, " -C comment Provide new comment.\n");
1046 fprintf(stderr, " -c Change comment in private and public key files.\n"); 1024 fprintf(stderr, " -c Change comment in private and public key files.\n");
1047#ifdef SMARTCARD 1025#ifdef ENABLE_PKCS11
1048 fprintf(stderr, " -D reader Download public key from smartcard.\n"); 1026 fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n");
1049#endif /* SMARTCARD */ 1027#endif
1050 fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); 1028 fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n");
1051 fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); 1029 fprintf(stderr, " -F hostname Find hostname in known hosts file.\n");
1052 fprintf(stderr, " -f filename Filename of the key file.\n"); 1030 fprintf(stderr, " -f filename Filename of the key file.\n");
@@ -1065,9 +1043,6 @@ usage(void)
1065 fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); 1043 fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n");
1066 fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); 1044 fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n");
1067 fprintf(stderr, " -t type Specify type of key to create.\n"); 1045 fprintf(stderr, " -t type Specify type of key to create.\n");
1068#ifdef SMARTCARD
1069 fprintf(stderr, " -U reader Upload private key to smartcard.\n");
1070#endif /* SMARTCARD */
1071 fprintf(stderr, " -v Verbose.\n"); 1046 fprintf(stderr, " -v Verbose.\n");
1072 fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); 1047 fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n");
1073 fprintf(stderr, " -y Read private key file and print public key.\n"); 1048 fprintf(stderr, " -y Read private key file and print public key.\n");
@@ -1082,12 +1057,12 @@ int
1082main(int argc, char **argv) 1057main(int argc, char **argv)
1083{ 1058{
1084 char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; 1059 char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
1085 char out_file[MAXPATHLEN], *reader_id = NULL; 1060 char out_file[MAXPATHLEN], *pkcs11provider = NULL;
1086 char *rr_hostname = NULL; 1061 char *rr_hostname = NULL;
1087 Key *private, *public; 1062 Key *private, *public;
1088 struct passwd *pw; 1063 struct passwd *pw;
1089 struct stat st; 1064 struct stat st;
1090 int opt, type, fd, download = 0; 1065 int opt, type, fd;
1091 u_int32_t memory = 0, generator_wanted = 0, trials = 100; 1066 u_int32_t memory = 0, generator_wanted = 0, trials = 100;
1092 int do_gen_candidates = 0, do_screen_candidates = 0; 1067 int do_gen_candidates = 0, do_screen_candidates = 0;
1093 BIGNUM *start = NULL; 1068 BIGNUM *start = NULL;
@@ -1120,7 +1095,7 @@ main(int argc, char **argv)
1120 } 1095 }
1121 1096
1122 while ((opt = getopt(argc, argv, 1097 while ((opt = getopt(argc, argv,
1123 "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { 1098 "degiqpclBHvxXyF:b:f:t:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
1124 switch (opt) { 1099 switch (opt) {
1125 case 'b': 1100 case 'b':
1126 bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); 1101 bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
@@ -1192,10 +1167,7 @@ main(int argc, char **argv)
1192 key_type_name = optarg; 1167 key_type_name = optarg;
1193 break; 1168 break;
1194 case 'D': 1169 case 'D':
1195 download = 1; 1170 pkcs11provider = optarg;
1196 /*FALLTHROUGH*/
1197 case 'U':
1198 reader_id = optarg;
1199 break; 1171 break;
1200 case 'v': 1172 case 'v':
1201 if (log_level == SYSLOG_LEVEL_INFO) 1173 if (log_level == SYSLOG_LEVEL_INFO)
@@ -1303,16 +1275,8 @@ main(int argc, char **argv)
1303 exit(0); 1275 exit(0);
1304 } 1276 }
1305 } 1277 }
1306 if (reader_id != NULL) { 1278 if (pkcs11provider != NULL)
1307#ifdef SMARTCARD 1279 do_download(pw, pkcs11provider);
1308 if (download)
1309 do_download(pw, reader_id);
1310 else
1311 do_upload(pw, reader_id);
1312#else /* SMARTCARD */
1313 fatal("no support for smartcards.");
1314#endif /* SMARTCARD */
1315 }
1316 1280
1317 if (do_gen_candidates) { 1281 if (do_gen_candidates) {
1318 FILE *out = fopen(out_file, "w"); 1282 FILE *out = fopen(out_file, "w");
diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
new file mode 100644
index 000000000..6ffdd9364
--- /dev/null
+++ b/ssh-pkcs11-client.c
@@ -0,0 +1,229 @@
1/*
2 * Copyright (c) 2010 Markus Friedl. All rights reserved.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/types.h>
18#include <sys/time.h>
19#include <sys/socket.h>
20
21#include <stdarg.h>
22#include <string.h>
23#include <unistd.h>
24#include <errno.h>
25
26#include "pathnames.h"
27#include "xmalloc.h"
28#include "buffer.h"
29#include "log.h"
30#include "misc.h"
31#include "key.h"
32#include "authfd.h"
33#include "atomicio.h"
34#include "ssh-pkcs11.h"
35
36/* borrows code from sftp-server and ssh-agent */
37
38int fd = -1;
39pid_t pid = -1;
40
41static void
42send_msg(Buffer *m)
43{
44 u_char buf[4];
45 int mlen = buffer_len(m);
46
47 put_u32(buf, mlen);
48 if (atomicio(vwrite, fd, buf, 4) != 4 ||
49 atomicio(vwrite, fd, buffer_ptr(m),
50 buffer_len(m)) != buffer_len(m))
51 error("write to helper failed");
52 buffer_consume(m, mlen);
53}
54
55static int
56recv_msg(Buffer *m)
57{
58 u_int l, len;
59 u_char buf[1024];
60
61 if ((len = atomicio(read, fd, buf, 4)) != 4) {
62 error("read from helper failed: %u", len);
63 return (0); /* XXX */
64 }
65 len = get_u32(buf);
66 if (len > 256 * 1024)
67 fatal("response too long: %u", len);
68 /* read len bytes into m */
69 buffer_clear(m);
70 while (len > 0) {
71 l = len;
72 if (l > sizeof(buf))
73 l = sizeof(buf);
74 if (atomicio(read, fd, buf, l) != l) {
75 error("response from helper failed.");
76 return (0); /* XXX */
77 }
78 buffer_append(m, buf, l);
79 len -= l;
80 }
81 return (buffer_get_char(m));
82}
83
84int
85pkcs11_init(int interactive)
86{
87 return (0);
88}
89
90void
91pkcs11_terminate(void)
92{
93 close(fd);
94}
95
96static int
97pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
98 int padding)
99{
100 Key key;
101 u_char *blob, *signature = NULL;
102 u_int blen, slen = 0;
103 int ret = -1;
104 Buffer msg;
105
106 if (padding != RSA_PKCS1_PADDING)
107 return (-1);
108 key.type = KEY_RSA;
109 key.rsa = rsa;
110 if (key_to_blob(&key, &blob, &blen) == 0)
111 return -1;
112 buffer_init(&msg);
113 buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
114 buffer_put_string(&msg, blob, blen);
115 buffer_put_string(&msg, from, flen);
116 buffer_put_int(&msg, 0);
117 xfree(blob);
118 send_msg(&msg);
119
120 if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) {
121 signature = buffer_get_string(&msg, &slen);
122 if (slen <= (u_int)RSA_size(rsa)) {
123 memcpy(to, signature, slen);
124 ret = slen;
125 }
126 xfree(signature);
127 }
128 return (ret);
129}
130
131/* redirect the private key encrypt operation to the ssh-pkcs11-helper */
132static int
133wrap_key(RSA *rsa)
134{
135 static RSA_METHOD helper_rsa;
136
137 memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa));
138 helper_rsa.name = "ssh-pkcs11-helper";
139 helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt;
140 RSA_set_method(rsa, &helper_rsa);
141 return (0);
142}
143
144static int
145pkcs11_start_helper(void)
146{
147 int pair[2];
148
149 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
150 error("socketpair: %s", strerror(errno));
151 return (-1);
152 }
153 if ((pid = fork()) == -1) {
154 error("fork: %s", strerror(errno));
155 return (-1);
156 } else if (pid == 0) {
157 if ((dup2(pair[1], STDIN_FILENO) == -1) ||
158 (dup2(pair[1], STDOUT_FILENO) == -1)) {
159 fprintf(stderr, "dup2: %s\n", strerror(errno));
160 _exit(1);
161 }
162 close(pair[0]);
163 close(pair[1]);
164 execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER,
165 (char *) 0);
166 fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER,
167 strerror(errno));
168 _exit(1);
169 }
170 close(pair[1]);
171 fd = pair[0];
172 return (0);
173}
174
175int
176pkcs11_add_provider(char *name, char *pin, Key ***keysp)
177{
178 Key *k;
179 int i, nkeys;
180 u_char *blob;
181 u_int blen;
182 Buffer msg;
183
184 if (fd < 0 && pkcs11_start_helper() < 0)
185 return (-1);
186
187 buffer_init(&msg);
188 buffer_put_char(&msg, SSH_AGENTC_ADD_SMARTCARD_KEY);
189 buffer_put_cstring(&msg, name);
190 buffer_put_cstring(&msg, pin);
191 send_msg(&msg);
192 buffer_clear(&msg);
193
194 if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) {
195 nkeys = buffer_get_int(&msg);
196 *keysp = xcalloc(nkeys, sizeof(Key *));
197 for (i = 0; i < nkeys; i++) {
198 blob = buffer_get_string(&msg, &blen);
199 xfree(buffer_get_string(&msg, NULL));
200 k = key_from_blob(blob, blen);
201 wrap_key(k->rsa);
202 (*keysp)[i] = k;
203 xfree(blob);
204 }
205 } else {
206 nkeys = -1;
207 }
208 buffer_free(&msg);
209 return (nkeys);
210}
211
212int
213pkcs11_del_provider(char *name)
214{
215 int ret = -1;
216 Buffer msg;
217
218 buffer_init(&msg);
219 buffer_put_char(&msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY);
220 buffer_put_cstring(&msg, name);
221 buffer_put_cstring(&msg, "");
222 send_msg(&msg);
223 buffer_clear(&msg);
224
225 if (recv_msg(&msg) == SSH_AGENT_SUCCESS)
226 ret = 0;
227 buffer_free(&msg);
228 return (ret);
229}
diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c
new file mode 100644
index 000000000..f9962709b
--- /dev/null
+++ b/ssh-pkcs11-helper.c
@@ -0,0 +1,349 @@
1/*
2 * Copyright (c) 2010 Markus Friedl. All rights reserved.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/queue.h>
18#include <sys/types.h>
19#include <sys/time.h>
20
21#include <stdarg.h>
22#include <string.h>
23#include <unistd.h>
24#include <errno.h>
25
26#include "xmalloc.h"
27#include "buffer.h"
28#include "log.h"
29#include "misc.h"
30#include "key.h"
31#include "authfd.h"
32#include "ssh-pkcs11.h"
33
34/* borrows code from sftp-server and ssh-agent */
35
36struct pkcs11_keyinfo {
37 Key *key;
38 char *providername;
39 TAILQ_ENTRY(pkcs11_keyinfo) next;
40};
41
42TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist;
43
44#define MAX_MSG_LENGTH 10240 /*XXX*/
45
46/* helper */
47#define get_int() buffer_get_int(&iqueue);
48#define get_string(lenp) buffer_get_string(&iqueue, lenp);
49
50/* input and output queue */
51Buffer iqueue;
52Buffer oqueue;
53
54static void
55add_key(Key *k, char *name)
56{
57 struct pkcs11_keyinfo *ki;
58
59 ki = xcalloc(1, sizeof(*ki));
60 ki->providername = xstrdup(name);
61 ki->key = k;
62 TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next);
63}
64
65static void
66del_keys_by_name(char *name)
67{
68 struct pkcs11_keyinfo *ki, *nxt;
69
70 for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) {
71 nxt = TAILQ_NEXT(ki, next);
72 if (!strcmp(ki->providername, name)) {
73 TAILQ_REMOVE(&pkcs11_keylist, ki, next);
74 xfree(ki->providername);
75 key_free(ki->key);
76 free(ki);
77 }
78 }
79}
80
81/* lookup matching 'private' key */
82static Key *
83lookup_key(Key *k)
84{
85 struct pkcs11_keyinfo *ki;
86
87 TAILQ_FOREACH(ki, &pkcs11_keylist, next) {
88 debug("check %p %s", ki, ki->providername);
89 if (key_equal(k, ki->key))
90 return (ki->key);
91 }
92 return (NULL);
93}
94
95static void
96send_msg(Buffer *m)
97{
98 int mlen = buffer_len(m);
99
100 buffer_put_int(&oqueue, mlen);
101 buffer_append(&oqueue, buffer_ptr(m), mlen);
102 buffer_consume(m, mlen);
103}
104
105static void
106process_add(void)
107{
108 char *name, *pin;
109 Key **keys;
110 int i, nkeys;
111 u_char *blob;
112 u_int blen;
113 Buffer msg;
114
115 buffer_init(&msg);
116 name = get_string(NULL);
117 pin = get_string(NULL);
118 if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) {
119 buffer_put_char(&msg, SSH2_AGENT_IDENTITIES_ANSWER);
120 buffer_put_int(&msg, nkeys);
121 for (i = 0; i < nkeys; i++) {
122 key_to_blob(keys[i], &blob, &blen);
123 buffer_put_string(&msg, blob, blen);
124 buffer_put_cstring(&msg, name);
125 xfree(blob);
126 add_key(keys[i], name);
127 }
128 xfree(keys);
129 } else {
130 buffer_put_char(&msg, SSH_AGENT_FAILURE);
131 }
132 xfree(pin);
133 xfree(name);
134 send_msg(&msg);
135 buffer_free(&msg);
136}
137
138static void
139process_del(void)
140{
141 char *name, *pin;
142 Buffer msg;
143
144 buffer_init(&msg);
145 name = get_string(NULL);
146 pin = get_string(NULL);
147 del_keys_by_name(name);
148 if (pkcs11_del_provider(name) == 0)
149 buffer_put_char(&msg, SSH_AGENT_SUCCESS);
150 else
151 buffer_put_char(&msg, SSH_AGENT_FAILURE);
152 xfree(pin);
153 xfree(name);
154 send_msg(&msg);
155 buffer_free(&msg);
156}
157
158static void
159process_sign(void)
160{
161 u_char *blob, *data, *signature = NULL;
162 u_int blen, dlen, slen = 0;
163 int ok = -1, flags, ret;
164 Key *key, *found;
165 Buffer msg;
166
167 blob = get_string(&blen);
168 data = get_string(&dlen);
169 flags = get_int(); /* XXX ignore */
170
171 if ((key = key_from_blob(blob, blen)) != NULL) {
172 if ((found = lookup_key(key)) != NULL) {
173 slen = RSA_size(key->rsa);
174 signature = xmalloc(slen);
175 if ((ret = RSA_private_encrypt(dlen, data, signature,
176 found->rsa, RSA_PKCS1_PADDING)) != -1) {
177 slen = ret;
178 ok = 0;
179 }
180 }
181 key_free(key);
182 }
183 buffer_init(&msg);
184 if (ok == 0) {
185 buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
186 buffer_put_string(&msg, signature, slen);
187 } else {
188 buffer_put_char(&msg, SSH_AGENT_FAILURE);
189 }
190 xfree(data);
191 xfree(blob);
192 if (signature != NULL)
193 xfree(signature);
194 send_msg(&msg);
195 buffer_free(&msg);
196}
197
198static void
199process(void)
200{
201 u_int msg_len;
202 u_int buf_len;
203 u_int consumed;
204 u_int type;
205 u_char *cp;
206
207 buf_len = buffer_len(&iqueue);
208 if (buf_len < 5)
209 return; /* Incomplete message. */
210 cp = buffer_ptr(&iqueue);
211 msg_len = get_u32(cp);
212 if (msg_len > MAX_MSG_LENGTH) {
213 error("bad message len %d", msg_len);
214 cleanup_exit(11);
215 }
216 if (buf_len < msg_len + 4)
217 return;
218 buffer_consume(&iqueue, 4);
219 buf_len -= 4;
220 type = buffer_get_char(&iqueue);
221 switch (type) {
222 case SSH_AGENTC_ADD_SMARTCARD_KEY:
223 debug("process_add");
224 process_add();
225 break;
226 case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
227 debug("process_del");
228 process_del();
229 break;
230 case SSH2_AGENTC_SIGN_REQUEST:
231 debug("process_sign");
232 process_sign();
233 break;
234 default:
235 error("Unknown message %d", type);
236 break;
237 }
238 /* discard the remaining bytes from the current packet */
239 if (buf_len < buffer_len(&iqueue)) {
240 error("iqueue grew unexpectedly");
241 cleanup_exit(255);
242 }
243 consumed = buf_len - buffer_len(&iqueue);
244 if (msg_len < consumed) {
245 error("msg_len %d < consumed %d", msg_len, consumed);
246 cleanup_exit(255);
247 }
248 if (msg_len > consumed)
249 buffer_consume(&iqueue, msg_len - consumed);
250}
251
252void
253cleanup_exit(int i)
254{
255 /* XXX */
256 _exit(i);
257}
258
259int
260main(int argc, char **argv)
261{
262 fd_set *rset, *wset;
263 int in, out, max, log_stderr = 0;
264 ssize_t len, olen, set_size;
265 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
266 LogLevel log_level = SYSLOG_LEVEL_ERROR;
267 char buf[4*4096];
268
269 TAILQ_INIT(&pkcs11_keylist);
270 pkcs11_init(0);
271
272 extern char *optarg;
273 extern char *__progname;
274
275 log_init(__progname, log_level, log_facility, log_stderr);
276
277 in = STDIN_FILENO;
278 out = STDOUT_FILENO;
279
280 max = 0;
281 if (in > max)
282 max = in;
283 if (out > max)
284 max = out;
285
286 buffer_init(&iqueue);
287 buffer_init(&oqueue);
288
289 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
290 rset = (fd_set *)xmalloc(set_size);
291 wset = (fd_set *)xmalloc(set_size);
292
293 for (;;) {
294 memset(rset, 0, set_size);
295 memset(wset, 0, set_size);
296
297 /*
298 * Ensure that we can read a full buffer and handle
299 * the worst-case length packet it can generate,
300 * otherwise apply backpressure by stopping reads.
301 */
302 if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
303 buffer_check_alloc(&oqueue, MAX_MSG_LENGTH))
304 FD_SET(in, rset);
305
306 olen = buffer_len(&oqueue);
307 if (olen > 0)
308 FD_SET(out, wset);
309
310 if (select(max+1, rset, wset, NULL, NULL) < 0) {
311 if (errno == EINTR)
312 continue;
313 error("select: %s", strerror(errno));
314 cleanup_exit(2);
315 }
316
317 /* copy stdin to iqueue */
318 if (FD_ISSET(in, rset)) {
319 len = read(in, buf, sizeof buf);
320 if (len == 0) {
321 debug("read eof");
322 cleanup_exit(0);
323 } else if (len < 0) {
324 error("read: %s", strerror(errno));
325 cleanup_exit(1);
326 } else {
327 buffer_append(&iqueue, buf, len);
328 }
329 }
330 /* send oqueue to stdout */
331 if (FD_ISSET(out, wset)) {
332 len = write(out, buffer_ptr(&oqueue), olen);
333 if (len < 0) {
334 error("write: %s", strerror(errno));
335 cleanup_exit(1);
336 } else {
337 buffer_consume(&oqueue, len);
338 }
339 }
340
341 /*
342 * Process requests from client if we can fit the results
343 * into the output buffer, otherwise stop processing input
344 * and let the output queue drain.
345 */
346 if (buffer_check_alloc(&oqueue, MAX_MSG_LENGTH))
347 process();
348 }
349}
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
new file mode 100644
index 000000000..f82454329
--- /dev/null
+++ b/ssh-pkcs11.c
@@ -0,0 +1,544 @@
1/*
2 * Copyright (c) 2010 Markus Friedl. All rights reserved.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/types.h>
18#include <sys/queue.h>
19#include <stdarg.h>
20#include <stdio.h>
21
22#include <string.h>
23#include <dlfcn.h>
24
25#define CRYPTOKI_COMPAT
26#include "pkcs11.h"
27
28#include "log.h"
29#include "misc.h"
30#include "key.h"
31#include "ssh-pkcs11.h"
32#include "xmalloc.h"
33
34struct pkcs11_slotinfo {
35 CK_TOKEN_INFO token;
36 CK_SESSION_HANDLE session;
37 int logged_in;
38};
39
40struct pkcs11_provider {
41 char *name;
42 void *handle;
43 CK_FUNCTION_LIST *function_list;
44 CK_INFO info;
45 CK_ULONG nslots;
46 CK_SLOT_ID *slotlist;
47 struct pkcs11_slotinfo *slotinfo;
48 int valid;
49 int refcount;
50 TAILQ_ENTRY(pkcs11_provider) next;
51};
52
53TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
54
55struct pkcs11_key {
56 struct pkcs11_provider *provider;
57 CK_ULONG slotidx;
58 int (*orig_finish)(RSA *rsa);
59 RSA_METHOD rsa_method;
60 char *keyid;
61 int keyid_len;
62};
63
64int pkcs11_interactive = 0;
65
66int
67pkcs11_init(int interactive)
68{
69 pkcs11_interactive = interactive;
70 TAILQ_INIT(&pkcs11_providers);
71 return (0);
72}
73
74/*
75 * finalize a provider shared libarary, it's no longer usable.
76 * however, there might still be keys referencing this provider,
77 * so the actuall freeing of memory is handled by pkcs11_provider_unref().
78 * this is called when a provider gets unregistered.
79 */
80static void
81pkcs11_provider_finalize(struct pkcs11_provider *p)
82{
83 CK_RV rv;
84 CK_ULONG i;
85
86 debug("pkcs11_provider_finalize: %p refcount %d valid %d",
87 p, p->refcount, p->valid);
88 if (!p->valid)
89 return;
90 for (i = 0; i < p->nslots; i++) {
91 if (p->slotinfo[i].session &&
92 (rv = p->function_list->C_CloseSession(
93 p->slotinfo[i].session)) != CKR_OK)
94 error("C_CloseSession failed: %lu", rv);
95 }
96 if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
97 error("C_Finalize failed: %lu", rv);
98 p->valid = 0;
99 p->function_list = NULL;
100 dlclose(p->handle);
101}
102
103/*
104 * remove a reference to the provider.
105 * called when a key gets destroyed or when the provider is unregistered.
106 */
107static void
108pkcs11_provider_unref(struct pkcs11_provider *p)
109{
110 debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount);
111 if (--p->refcount <= 0) {
112 if (p->valid)
113 error("pkcs11_provider_unref: %p still valid", p);
114 xfree(p->slotlist);
115 xfree(p->slotinfo);
116 xfree(p);
117 }
118}
119
120/* unregister all providers, keys might still point to the providers */
121void
122pkcs11_terminate(void)
123{
124 struct pkcs11_provider *p;
125
126 while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
127 TAILQ_REMOVE(&pkcs11_providers, p, next);
128 pkcs11_provider_finalize(p);
129 pkcs11_provider_unref(p);
130 }
131}
132
133/* lookup provider by name */
134static struct pkcs11_provider *
135pkcs11_provider_lookup(char *provider_id)
136{
137 struct pkcs11_provider *p;
138
139 TAILQ_FOREACH(p, &pkcs11_providers, next) {
140 debug("check %p %s", p, p->name);
141 if (!strcmp(provider_id, p->name))
142 return (p);
143 }
144 return (NULL);
145}
146
147/* unregister provider by name */
148int
149pkcs11_del_provider(char *provider_id)
150{
151 struct pkcs11_provider *p;
152
153 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
154 TAILQ_REMOVE(&pkcs11_providers, p, next);
155 pkcs11_provider_finalize(p);
156 pkcs11_provider_unref(p);
157 return (0);
158 }
159 return (-1);
160}
161
162/* openssl callback for freeing an RSA key */
163static int
164pkcs11_rsa_finish(RSA *rsa)
165{
166 struct pkcs11_key *k11;
167 int rv = -1;
168
169 if ((k11 = RSA_get_app_data(rsa)) != NULL) {
170 if (k11->orig_finish)
171 rv = k11->orig_finish(rsa);
172 if (k11->provider)
173 pkcs11_provider_unref(k11->provider);
174 if (k11->keyid)
175 xfree(k11->keyid);
176 xfree(k11);
177 }
178 return (rv);
179}
180
181/* openssl callback doing the actual signing operation */
182static int
183pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
184 int padding)
185{
186 struct pkcs11_key *k11;
187 struct pkcs11_slotinfo *si;
188 CK_FUNCTION_LIST *f;
189 CK_OBJECT_HANDLE obj;
190 CK_ULONG tlen = 0, nfound = 0;
191 CK_RV rv;
192 CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY;
193 CK_BBOOL true = CK_TRUE;
194 CK_MECHANISM mech = {
195 CKM_RSA_PKCS, NULL_PTR, 0
196 };
197 CK_ATTRIBUTE key_filter[] = {
198 {CKA_CLASS, &private_key_class, sizeof(private_key_class) },
199 {CKA_ID, NULL, 0},
200 {CKA_SIGN, &true, sizeof(true) }
201 };
202 char *pin, prompt[1024];
203 int rval = -1;
204
205 if ((k11 = RSA_get_app_data(rsa)) == NULL) {
206 error("RSA_get_app_data failed for rsa %p", rsa);
207 return (-1);
208 }
209 if (!k11->provider || !k11->provider->valid) {
210 error("no pkcs11 (valid) provider for rsa %p", rsa);
211 return (-1);
212 }
213 f = k11->provider->function_list;
214 si = &k11->provider->slotinfo[k11->slotidx];
215 if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
216 if (!pkcs11_interactive) {
217 error("need pin");
218 return (-1);
219 }
220 snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
221 si->token.label);
222 pin = read_passphrase(prompt, RP_ALLOW_EOF);
223 if (pin == NULL)
224 return (-1); /* bail out */
225 if ((rv = f->C_Login(si->session, CKU_USER, pin, strlen(pin)))
226 != CKR_OK) {
227 xfree(pin);
228 error("C_Login failed: %lu", rv);
229 return (-1);
230 }
231 xfree(pin);
232 si->logged_in = 1;
233 }
234 key_filter[1].pValue = k11->keyid;
235 key_filter[1].ulValueLen = k11->keyid_len;
236 if ((rv = f->C_FindObjectsInit(si->session, key_filter, 3)) != CKR_OK) {
237 error("C_FindObjectsInit failed: %lu", rv);
238 return (-1);
239 }
240 if ((rv = f->C_FindObjects(si->session, &obj, 1, &nfound)) != CKR_OK ||
241 nfound != 1) {
242 error("C_FindObjects failed (%lu nfound): %lu", nfound, rv);
243 } else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
244 error("C_SignInit failed: %lu", rv);
245 } else {
246 /* XXX handle CKR_BUFFER_TOO_SMALL */
247 tlen = RSA_size(rsa);
248 rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
249 if (rv == CKR_OK)
250 rval = tlen;
251 else
252 error("C_Sign failed: %lu", rv);
253 }
254 if ((rv = f->C_FindObjectsFinal(si->session)) != CKR_OK)
255 error("C_FindObjectsFinal failed: %lu", rv);
256 return (rval);
257}
258
259static int
260pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
261 int padding)
262{
263 return (-1);
264}
265
266/* redirect private key operations for rsa key to pkcs11 token */
267static int
268pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
269 CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
270{
271 struct pkcs11_key *k11;
272 const RSA_METHOD *def = RSA_get_default_method();
273
274 k11 = xcalloc(1, sizeof(*k11));
275 k11->provider = provider;
276 provider->refcount++; /* provider referenced by RSA key */
277 k11->slotidx = slotidx;
278 /* identify key object on smartcard */
279 k11->keyid_len = keyid_attrib->ulValueLen;
280 k11->keyid = xmalloc(k11->keyid_len);
281 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
282 k11->orig_finish = def->finish;
283 memcpy(&k11->rsa_method, def, sizeof(k11->rsa_method));
284 k11->rsa_method.name = "pkcs11";
285 k11->rsa_method.rsa_priv_enc = pkcs11_rsa_private_encrypt;
286 k11->rsa_method.rsa_priv_dec = pkcs11_rsa_private_decrypt;
287 k11->rsa_method.finish = pkcs11_rsa_finish;
288 RSA_set_method(rsa, &k11->rsa_method);
289 RSA_set_app_data(rsa, k11);
290 return (0);
291}
292
293/* remove trailing spaces */
294static void
295rmspace(char *buf, size_t len)
296{
297 size_t i;
298
299 if (!len)
300 return;
301 for (i = len - 1; i > 0; i--)
302 if (i == len - 1 || buf[i] == ' ')
303 buf[i] = '\0';
304 else
305 break;
306}
307
308/*
309 * open a pkcs11 session and login if required.
310 * if pin == NULL we delay login until key use
311 */
312static int
313pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin)
314{
315 CK_RV rv;
316 CK_FUNCTION_LIST *f;
317 CK_SESSION_HANDLE session;
318 int login_required;
319
320 f = p->function_list;
321 login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
322 if (pin && login_required && !strlen(pin)) {
323 error("pin required");
324 return (-1);
325 }
326 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
327 CKF_SERIAL_SESSION, NULL, NULL, &session))
328 != CKR_OK) {
329 error("C_OpenSession failed: %lu", rv);
330 return (-1);
331 }
332 if (login_required && pin) {
333 if ((rv = f->C_Login(session, CKU_USER, pin, strlen(pin)))
334 != CKR_OK) {
335 error("C_Login failed: %lu", rv);
336 if ((rv = f->C_CloseSession(session)) != CKR_OK)
337 error("C_CloseSession failed: %lu", rv);
338 return (-1);
339 }
340 p->slotinfo[slotidx].logged_in = 1;
341 }
342 p->slotinfo[slotidx].session = session;
343 return (0);
344}
345
346/*
347 * lookup public keys for token in slot identified by slotidx,
348 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
349 * keysp points to an (possibly empty) array with *nkeys keys.
350 */
351static int
352pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp,
353 int *nkeys)
354{
355 Key *key;
356 RSA *rsa;
357 int i;
358 CK_RV rv;
359 CK_OBJECT_HANDLE obj;
360 CK_ULONG nfound;
361 CK_SESSION_HANDLE session;
362 CK_FUNCTION_LIST *f;
363 CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY;
364 CK_ATTRIBUTE pubkey_filter[] = {
365 { CKA_CLASS, &pubkey_class, sizeof(pubkey_class) }
366 };
367 CK_ATTRIBUTE attribs[] = {
368 { CKA_ID, NULL, 0 },
369 { CKA_MODULUS, NULL, 0 },
370 { CKA_PUBLIC_EXPONENT, NULL, 0 }
371 };
372
373 f = p->function_list;
374 session = p->slotinfo[slotidx].session;
375 /* setup a filter the looks for public keys */
376 if ((rv = f->C_FindObjectsInit(session, pubkey_filter, 1)) != CKR_OK) {
377 error("C_FindObjectsInit failed: %lu", rv);
378 return (-1);
379 }
380 while (1) {
381 /* XXX 3 attributes in attribs[] */
382 for (i = 0; i < 3; i++) {
383 attribs[i].pValue = NULL;
384 attribs[i].ulValueLen = 0;
385 }
386 if ((rv = f->C_FindObjects(session, &obj, 1, &nfound)) != CKR_OK
387 || nfound == 0)
388 break;
389 /* found a key, so figure out size of the attributes */
390 if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
391 != CKR_OK) {
392 error("C_GetAttributeValue failed: %lu", rv);
393 continue;
394 }
395 /* allocate buffers for attributes, XXX check ulValueLen? */
396 for (i = 0; i < 3; i++)
397 attribs[i].pValue = xmalloc(attribs[i].ulValueLen);
398 /* retrieve ID, modulus and public exponent of RSA key */
399 if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
400 != CKR_OK) {
401 error("C_GetAttributeValue failed: %lu", rv);
402 } else if ((rsa = RSA_new()) == NULL) {
403 error("RSA_new failed");
404 } else {
405 rsa->n = BN_bin2bn(attribs[1].pValue,
406 attribs[1].ulValueLen, NULL);
407 rsa->e = BN_bin2bn(attribs[2].pValue,
408 attribs[2].ulValueLen, NULL);
409 if (rsa->n && rsa->e &&
410 pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
411 key = key_new(KEY_UNSPEC);
412 key->rsa = rsa;
413 key->type = KEY_RSA;
414 key->flags |= KEY_FLAG_EXT;
415 /* expand key array and add key */
416 *keysp = xrealloc(*keysp, *nkeys + 1,
417 sizeof(Key *));
418 (*keysp)[*nkeys] = key;
419 *nkeys = *nkeys + 1;
420 debug("have %d keys", *nkeys);
421 } else {
422 RSA_free(rsa);
423 }
424 }
425 for (i = 0; i < 3; i++)
426 xfree(attribs[i].pValue);
427 }
428 if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
429 error("C_FindObjectsFinal failed: %lu", rv);
430 return (0);
431}
432
433/* register a new provider, fails if provider already exists */
434int
435pkcs11_add_provider(char *provider_id, char *pin, Key ***keyp)
436{
437 int nkeys, need_finalize = 0;
438 struct pkcs11_provider *p = NULL;
439 void *handle = NULL;
440 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
441 CK_RV rv;
442 CK_FUNCTION_LIST *f = NULL;
443 CK_TOKEN_INFO *token;
444 CK_ULONG i;
445
446 *keyp = NULL;
447 if (pkcs11_provider_lookup(provider_id) != NULL) {
448 error("provider already registered: %s", provider_id);
449 goto fail;
450 }
451 /* open shared pkcs11-libarary */
452 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
453 error("dlopen %s failed: %s", provider_id, dlerror());
454 goto fail;
455 }
456 if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
457 error("dlsym(C_GetFunctionList) failed: %s", dlerror());
458 goto fail;
459 }
460 p = xcalloc(1, sizeof(*p));
461 p->name = xstrdup(provider_id);
462 p->handle = handle;
463 /* setup the pkcs11 callbacks */
464 if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
465 error("C_GetFunctionList failed: %lu", rv);
466 goto fail;
467 }
468 p->function_list = f;
469 if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
470 error("C_Initialize failed: %lu", rv);
471 goto fail;
472 }
473 need_finalize = 1;
474 if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
475 error("C_GetInfo failed: %lu", rv);
476 goto fail;
477 }
478 rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
479 rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
480 debug("manufacturerID <%s> cryptokiVersion %d.%d"
481 " libraryDescription <%s> libraryVersion %d.%d",
482 p->info.manufacturerID,
483 p->info.cryptokiVersion.major,
484 p->info.cryptokiVersion.minor,
485 p->info.libraryDescription,
486 p->info.libraryVersion.major,
487 p->info.libraryVersion.minor);
488 if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
489 error("C_GetSlotList failed: %lu", rv);
490 goto fail;
491 }
492 if (p->nslots == 0) {
493 error("no slots");
494 goto fail;
495 }
496 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
497 if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
498 != CKR_OK) {
499 error("C_GetSlotList failed: %lu", rv);
500 goto fail;
501 }
502 p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
503 p->valid = 1;
504 nkeys = 0;
505 for (i = 0; i < p->nslots; i++) {
506 token = &p->slotinfo[i].token;
507 if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
508 != CKR_OK) {
509 error("C_GetTokenInfo failed: %lu", rv);
510 continue;
511 }
512 rmspace(token->label, sizeof(token->label));
513 rmspace(token->manufacturerID, sizeof(token->manufacturerID));
514 rmspace(token->model, sizeof(token->model));
515 rmspace(token->serialNumber, sizeof(token->serialNumber));
516 debug("label <%s> manufacturerID <%s> model <%s> serial <%s>"
517 " flags 0x%lx",
518 token->label, token->manufacturerID, token->model,
519 token->serialNumber, token->flags);
520 /* open session, login with pin and retrieve public keys */
521 if (pkcs11_open_session(p, i, pin) == 0)
522 pkcs11_fetch_keys(p, i, keyp, &nkeys);
523 }
524 if (nkeys > 0) {
525 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
526 p->refcount++; /* add to provider list */
527 return (nkeys);
528 }
529 error("no keys");
530 /* don't add the provider, since it does not have any keys */
531fail:
532 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
533 error("C_Finalize failed: %lu", rv);
534 if (p) {
535 if (p->slotlist)
536 xfree(p->slotlist);
537 if (p->slotinfo)
538 xfree(p->slotinfo);
539 xfree(p);
540 }
541 if (handle)
542 dlclose(handle);
543 return (-1);
544}
diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h
new file mode 100644
index 000000000..fae41a7b5
--- /dev/null
+++ b/ssh-pkcs11.h
@@ -0,0 +1,19 @@
1/*
2 * Copyright (c) 2010 Markus Friedl. All rights reserved.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16int pkcs11_init(int);
17void pkcs11_terminate(void);
18int pkcs11_add_provider(char *, char *, Key ***);
19int pkcs11_del_provider(char *);
diff --git a/ssh.1 b/ssh.1
index 1ff2cce4d..97a2455ab 100644
--- a/ssh.1
+++ b/ssh.1
@@ -34,8 +34,8 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: ssh.1,v 1.290 2010/01/11 01:39:46 dtucker Exp $ 37.\" $OpenBSD: ssh.1,v 1.291 2010/02/08 10:50:20 markus Exp $
38.Dd $Mdocdate: January 11 2010 $ 38.Dd $Mdocdate: February 8 2010 $
39.Dt SSH 1 39.Dt SSH 1
40.Os 40.Os
41.Sh NAME 41.Sh NAME
@@ -284,12 +284,12 @@ will wait for all remote port forwards to be successfully established
284before placing itself in the background. 284before placing itself in the background.
285.It Fl g 285.It Fl g
286Allows remote hosts to connect to local forwarded ports. 286Allows remote hosts to connect to local forwarded ports.
287.It Fl I Ar smartcard_device 287.It Fl I Ar pkcs11
288Specify the device 288Specify the PKCS#11 shared libarary
289.Nm 289.Nm
290should use to communicate with a smartcard used for storing the user's 290should use to communicate with a PKCS#11 token used for storing the user's
291private RSA key. 291private RSA key.
292This option is only available if support for smartcard devices 292This option is only available if support for PKCS#11
293is compiled in (default is no support). 293is compiled in (default is no support).
294.It Fl i Ar identity_file 294.It Fl i Ar identity_file
295Selects a file from which the identity (private key) for 295Selects a file from which the identity (private key) for
@@ -469,6 +469,7 @@ For full details of the options listed below, and their possible values, see
469.It NumberOfPasswordPrompts 469.It NumberOfPasswordPrompts
470.It PasswordAuthentication 470.It PasswordAuthentication
471.It PermitLocalCommand 471.It PermitLocalCommand
472.It PKCS11Provider
472.It Port 473.It Port
473.It PreferredAuthentications 474.It PreferredAuthentications
474.It Protocol 475.It Protocol
@@ -481,7 +482,6 @@ For full details of the options listed below, and their possible values, see
481.It SendEnv 482.It SendEnv
482.It ServerAliveInterval 483.It ServerAliveInterval
483.It ServerAliveCountMax 484.It ServerAliveCountMax
484.It SmartcardDevice
485.It StrictHostKeyChecking 485.It StrictHostKeyChecking
486.It TCPKeepAlive 486.It TCPKeepAlive
487.It Tunnel 487.It Tunnel
diff --git a/ssh.c b/ssh.c
index 97afdcfee..63523b42a 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.332 2010/01/26 01:28:35 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.333 2010/02/08 10:50:20 markus Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -103,8 +103,8 @@
103#include "roaming.h" 103#include "roaming.h"
104#include "version.h" 104#include "version.h"
105 105
106#ifdef SMARTCARD 106#ifdef ENABLE_PKCS11
107#include "scard.h" 107#include "ssh-pkcs11.h"
108#endif 108#endif
109 109
110extern char *__progname; 110extern char *__progname;
@@ -362,10 +362,10 @@ main(int ac, char **av)
362 xstrdup(optarg); 362 xstrdup(optarg);
363 break; 363 break;
364 case 'I': 364 case 'I':
365#ifdef SMARTCARD 365#ifdef ENABLE_PKCS11
366 options.smartcard_device = xstrdup(optarg); 366 options.pkcs11_provider = xstrdup(optarg);
367#else 367#else
368 fprintf(stderr, "no support for smartcards.\n"); 368 fprintf(stderr, "no support for PKCS#11.\n");
369#endif 369#endif
370 break; 370 break;
371 case 't': 371 case 't':
@@ -1305,14 +1305,17 @@ load_public_identity_files(void)
1305 int i = 0; 1305 int i = 0;
1306 Key *public; 1306 Key *public;
1307 struct passwd *pw; 1307 struct passwd *pw;
1308#ifdef SMARTCARD 1308#ifdef ENABLE_PKCS11
1309 Key **keys; 1309 Key **keys;
1310 int nkeys;
1310 1311
1311 if (options.smartcard_device != NULL && 1312 if (options.pkcs11_provider != NULL &&
1312 options.num_identity_files < SSH_MAX_IDENTITY_FILES && 1313 options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
1313 (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) { 1314 (pkcs11_init(!options.batch_mode) == 0) &&
1315 (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL,
1316 &keys)) > 0) {
1314 int count = 0; 1317 int count = 0;
1315 for (i = 0; keys[i] != NULL; i++) { 1318 for (i = 0; i < nkeys; i++) {
1316 count++; 1319 count++;
1317 memmove(&options.identity_files[1], 1320 memmove(&options.identity_files[1],
1318 &options.identity_files[0], 1321 &options.identity_files[0],
@@ -1322,14 +1325,16 @@ load_public_identity_files(void)
1322 sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); 1325 sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));
1323 options.num_identity_files++; 1326 options.num_identity_files++;
1324 options.identity_keys[0] = keys[i]; 1327 options.identity_keys[0] = keys[i];
1325 options.identity_files[0] = sc_get_key_label(keys[i]); 1328 options.identity_files[0] =
1329 xstrdup(options.pkcs11_provider); /* XXX */
1326 } 1330 }
1327 if (options.num_identity_files > SSH_MAX_IDENTITY_FILES) 1331 if (options.num_identity_files > SSH_MAX_IDENTITY_FILES)
1328 options.num_identity_files = SSH_MAX_IDENTITY_FILES; 1332 options.num_identity_files = SSH_MAX_IDENTITY_FILES;
1329 i = count; 1333 i = count;
1330 xfree(keys); 1334 xfree(keys);
1335 /* XXX leaks some keys */
1331 } 1336 }
1332#endif /* SMARTCARD */ 1337#endif /* ENABLE_PKCS11 */
1333 if ((pw = getpwuid(original_real_uid)) == NULL) 1338 if ((pw = getpwuid(original_real_uid)) == NULL)
1334 fatal("load_public_identity_files: getpwuid failed"); 1339 fatal("load_public_identity_files: getpwuid failed");
1335 pwname = xstrdup(pw->pw_name); 1340 pwname = xstrdup(pw->pw_name);
diff --git a/ssh_config.5 b/ssh_config.5
index 01f5f4304..350a8eacd 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -34,8 +34,8 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: ssh_config.5,v 1.126 2010/01/09 23:04:13 dtucker Exp $ 37.\" $OpenBSD: ssh_config.5,v 1.127 2010/02/08 10:50:20 markus Exp $
38.Dd $Mdocdate: January 9 2010 $ 38.Dd $Mdocdate: February 8 2010 $
39.Dt SSH_CONFIG 5 39.Dt SSH_CONFIG 5
40.Os 40.Os
41.Sh NAME 41.Sh NAME
@@ -711,6 +711,13 @@ or
711.Dq no . 711.Dq no .
712The default is 712The default is
713.Dq no . 713.Dq no .
714.It Cm PKCS11Provider
715Specifies which PKCS#11 provider to use.
716The argument to this keyword is the PKCS#11 shared libary
717.Xr ssh 1
718should use to communicate with a PKCS#11 token used for storing the user's
719private RSA key.
720By default, no device is specified and PKCS#11 support is not activated.
714.It Cm Port 721.It Cm Port
715Specifies the port number to connect on the remote host. 722Specifies the port number to connect on the remote host.
716The default is 22. 723The default is 22.
@@ -927,13 +934,6 @@ channel to request a response from the server.
927The default 934The default
928is 0, indicating that these messages will not be sent to the server. 935is 0, indicating that these messages will not be sent to the server.
929This option applies to protocol version 2 only. 936This option applies to protocol version 2 only.
930.It Cm SmartcardDevice
931Specifies which smartcard device to use.
932The argument to this keyword is the device
933.Xr ssh 1
934should use to communicate with a smartcard used for storing the user's
935private RSA key.
936By default, no device is specified and smartcard support is not activated.
937.It Cm StrictHostKeyChecking 937.It Cm StrictHostKeyChecking
938If this flag is set to 938If this flag is set to
939.Dq yes , 939.Dq yes ,