diff options
author | Damien Miller <djm@mindrot.org> | 2010-02-12 09:21:02 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2010-02-12 09:21:02 +1100 |
commit | 7ea845e48df6d34a333ebbe79380cba0938d02a5 (patch) | |
tree | 44ab0d3fdfe0560b7ca92f5747e9dd5d012aea18 | |
parent | 17751bcab25681d341442fdc2386a30a6bea345e (diff) |
- markus@cvs.openbsd.org 2010/02/08 10:50:20
[pathnames.h readconf.c readconf.h scp.1 sftp.1 ssh-add.1 ssh-add.c]
[ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config.5]
replace our obsolete smartcard code with PKCS#11.
ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-20/pkcs-11v2-20.pdf
ssh(1) and ssh-keygen(1) use dlopen(3) directly to talk to a PKCS#11
provider (shared library) while ssh-agent(1) delegates PKCS#11 to
a forked a ssh-pkcs11-helper process.
PKCS#11 is currently a compile time option.
feedback and ok djm@; inspired by patches from Alon Bar-Lev
`
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | Makefile.in | 20 | ||||
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | pathnames.h | 7 | ||||
-rw-r--r-- | readconf.c | 16 | ||||
-rw-r--r-- | readconf.h | 4 | ||||
-rw-r--r-- | scp.1 | 6 | ||||
-rw-r--r-- | sftp.1 | 6 | ||||
-rw-r--r-- | ssh-add.1 | 16 | ||||
-rw-r--r-- | ssh-add.c | 20 | ||||
-rw-r--r-- | ssh-agent.c | 101 | ||||
-rw-r--r-- | ssh-keygen.1 | 14 | ||||
-rw-r--r-- | ssh-keygen.c | 84 | ||||
-rw-r--r-- | ssh-pkcs11-client.c | 229 | ||||
-rw-r--r-- | ssh-pkcs11-helper.c | 349 | ||||
-rw-r--r-- | ssh-pkcs11.c | 544 | ||||
-rw-r--r-- | ssh-pkcs11.h | 19 | ||||
-rw-r--r-- | ssh.1 | 14 | ||||
-rw-r--r-- | ssh.c | 29 | ||||
-rw-r--r-- | ssh_config.5 | 18 |
20 files changed, 1326 insertions, 188 deletions
@@ -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 | ||
9 | 20100210 | 19 | 20100210 |
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 | |||
25 | ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass | 25 | ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass |
26 | SFTP_SERVER=$(libexecdir)/sftp-server | 26 | SFTP_SERVER=$(libexecdir)/sftp-server |
27 | SSH_KEYSIGN=$(libexecdir)/ssh-keysign | 27 | SSH_KEYSIGN=$(libexecdir)/ssh-keysign |
28 | SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper | ||
28 | RAND_HELPER=$(libexecdir)/ssh-rand-helper | 29 | RAND_HELPER=$(libexecdir)/ssh-rand-helper |
29 | PRIVSEP_PATH=@PRIVSEP_PATH@ | 30 | PRIVSEP_PATH=@PRIVSEP_PATH@ |
30 | SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ | 31 | SSH_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@ | |||
60 | INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ | 62 | INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ |
61 | INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ | 63 | INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ |
62 | 64 | ||
63 | TARGETS=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) | 65 | TARGETS=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 | ||
65 | LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ | 67 | LIBSSH_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 | ||
76 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ | 79 | SSHOBJS= 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 | |||
147 | ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o | 150 | ssh-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 | ||
150 | ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o | 153 | ssh-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 | ||
153 | ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o | 156 | ssh-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 | |||
156 | ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o | 159 | ssh-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 | ||
162 | ssh-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 | |||
159 | ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o | 165 | ssh-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 | ||
17 | AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org) | 17 | AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org) |
18 | AC_REVISION($Revision: 1.440 $) | 18 | AC_REVISION($Revision: 1.441 $) |
19 | AC_CONFIG_SRCDIR([ssh.c]) | 19 | AC_CONFIG_SRCDIR([ssh.c]) |
20 | 20 | ||
21 | AC_CONFIG_HEADER(config.h) | 21 | AC_CONFIG_HEADER(config.h) |
@@ -4197,6 +4197,10 @@ else | |||
4197 | AC_SUBST(TEST_SSH_IPV6, yes) | 4197 | AC_SUBST(TEST_SSH_IPV6, yes) |
4198 | fi | 4198 | fi |
4199 | 4199 | ||
4200 | if test "x$enable_pkcs11" != "xno" ; then | ||
4201 | AC_DEFINE([ENABLE_PKCS11], [], [Enable for PKCS#11 support]) | ||
4202 | fi | ||
4203 | |||
4200 | AC_EXEEXT | 4204 | AC_EXEEXT |
4201 | AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \ | 4205 | AC_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. */ |
@@ -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 |
@@ -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 |
@@ -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, | |||
101 | will append | 101 | will append |
102 | .Pa .pub | 102 | .Pa .pub |
103 | and retry. | 103 | and retry. |
104 | .It Fl e Ar reader | 104 | .It Fl e Ar pkcs11 |
105 | Remove key in smartcard | 105 | Remove key provided by |
106 | .Ar reader . | 106 | .Ar pkcs11 . |
107 | .It Fl L | 107 | .It Fl L |
108 | Lists public key parameters of all identities currently represented | 108 | Lists public key parameters of all identities currently represented |
109 | by the agent. | 109 | by the agent. |
110 | .It Fl l | 110 | .It Fl l |
111 | Lists fingerprints of all identities currently represented by the agent. | 111 | Lists fingerprints of all identities currently represented by the agent. |
112 | .It Fl s Ar reader | 112 | .It Fl s Ar pkcs11 |
113 | Add key in smartcard | 113 | Add key provider by |
114 | .Ar reader . | 114 | .Ar pkcs11 . |
115 | .It Fl t Ar life | 115 | .It Fl t Ar life |
116 | Set a maximum lifetime when adding identities to an agent. | 116 | Set a maximum lifetime when adding identities to an agent. |
117 | The lifetime may be specified in seconds or in a time format | 117 | The lifetime may be specified in seconds or in a time format |
@@ -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 | ||
326 | int | 324 | int |
@@ -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 | |||
171 | free_identity(Identity *id) | 172 | free_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 |
613 | static void | 615 | static void |
614 | process_add_smartcard_key(SocketEntry *e) | 616 | process_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); | ||
671 | send: | 664 | send: |
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: | |||
677 | static void | 676 | static void |
678 | process_remove_smartcard_key(SocketEntry *e) | 677 | process_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) |
710 | send: | 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 | |||
1009 | cleanup_handler(int sig) | 1003 | cleanup_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 | ||
1257 | skip: | 1254 | skip: |
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. | |||
201 | This operation is only supported for RSA1 keys. | 201 | This operation is only supported for RSA1 keys. |
202 | The program will prompt for the file containing the private keys, for | 202 | The program will prompt for the file containing the private keys, for |
203 | the passphrase if the key has one, and for the new comment. | 203 | the passphrase if the key has one, and for the new comment. |
204 | .It Fl D Ar reader | 204 | .It Fl D Ar pkcs11 |
205 | Download the RSA public key stored in the smartcard in | 205 | Download the RSA public keys stored in the |
206 | .Ar reader . | 206 | .Ar pkcs11 |
207 | provider. | ||
207 | .It Fl e | 208 | .It Fl e |
208 | This option will read a private or public OpenSSH key file and | 209 | This option will read a private or public OpenSSH key file and |
209 | print the key in | 210 | print the key in |
@@ -313,9 +314,6 @@ for protocol version 1 and | |||
313 | or | 314 | or |
314 | .Dq dsa | 315 | .Dq dsa |
315 | for protocol version 2. | 316 | for protocol version 2. |
316 | .It Fl U Ar reader | ||
317 | Upload an existing RSA private key into the smartcard in | ||
318 | .Ar reader . | ||
319 | .It Fl v | 317 | .It Fl v |
320 | Verbose mode. | 318 | Verbose mode. |
321 | Causes | 319 | Causes |
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 | ||
463 | static void | 462 | static void |
464 | do_upload(struct passwd *pw, const char *sc_reader_id) | 463 | do_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 | |||
489 | static void | ||
490 | do_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 | ||
508 | static void | 486 | static void |
509 | do_fingerprint(struct passwd *pw) | 487 | do_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 | |||
1082 | main(int argc, char **argv) | 1057 | main(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 | |||
38 | int fd = -1; | ||
39 | pid_t pid = -1; | ||
40 | |||
41 | static void | ||
42 | send_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 | |||
55 | static int | ||
56 | recv_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 | |||
84 | int | ||
85 | pkcs11_init(int interactive) | ||
86 | { | ||
87 | return (0); | ||
88 | } | ||
89 | |||
90 | void | ||
91 | pkcs11_terminate(void) | ||
92 | { | ||
93 | close(fd); | ||
94 | } | ||
95 | |||
96 | static int | ||
97 | pkcs11_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 */ | ||
132 | static int | ||
133 | wrap_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 | |||
144 | static int | ||
145 | pkcs11_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 | |||
175 | int | ||
176 | pkcs11_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 | |||
212 | int | ||
213 | pkcs11_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 | |||
36 | struct pkcs11_keyinfo { | ||
37 | Key *key; | ||
38 | char *providername; | ||
39 | TAILQ_ENTRY(pkcs11_keyinfo) next; | ||
40 | }; | ||
41 | |||
42 | TAILQ_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 */ | ||
51 | Buffer iqueue; | ||
52 | Buffer oqueue; | ||
53 | |||
54 | static void | ||
55 | add_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 | |||
65 | static void | ||
66 | del_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 */ | ||
82 | static Key * | ||
83 | lookup_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 | |||
95 | static void | ||
96 | send_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 | |||
105 | static void | ||
106 | process_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 | |||
138 | static void | ||
139 | process_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 | |||
158 | static void | ||
159 | process_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 | |||
198 | static void | ||
199 | process(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 | |||
252 | void | ||
253 | cleanup_exit(int i) | ||
254 | { | ||
255 | /* XXX */ | ||
256 | _exit(i); | ||
257 | } | ||
258 | |||
259 | int | ||
260 | main(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 | |||
34 | struct pkcs11_slotinfo { | ||
35 | CK_TOKEN_INFO token; | ||
36 | CK_SESSION_HANDLE session; | ||
37 | int logged_in; | ||
38 | }; | ||
39 | |||
40 | struct 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 | |||
53 | TAILQ_HEAD(, pkcs11_provider) pkcs11_providers; | ||
54 | |||
55 | struct 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 | |||
64 | int pkcs11_interactive = 0; | ||
65 | |||
66 | int | ||
67 | pkcs11_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 | */ | ||
80 | static void | ||
81 | pkcs11_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 | */ | ||
107 | static void | ||
108 | pkcs11_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 */ | ||
121 | void | ||
122 | pkcs11_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 */ | ||
134 | static struct pkcs11_provider * | ||
135 | pkcs11_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 */ | ||
148 | int | ||
149 | pkcs11_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 */ | ||
163 | static int | ||
164 | pkcs11_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 */ | ||
182 | static int | ||
183 | pkcs11_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 | |||
259 | static int | ||
260 | pkcs11_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 */ | ||
267 | static int | ||
268 | pkcs11_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 */ | ||
294 | static void | ||
295 | rmspace(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 | */ | ||
312 | static int | ||
313 | pkcs11_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 | */ | ||
351 | static int | ||
352 | pkcs11_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 */ | ||
434 | int | ||
435 | pkcs11_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 */ | ||
531 | fail: | ||
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 | */ | ||
16 | int pkcs11_init(int); | ||
17 | void pkcs11_terminate(void); | ||
18 | int pkcs11_add_provider(char *, char *, Key ***); | ||
19 | int pkcs11_del_provider(char *); | ||
@@ -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 | |||
284 | before placing itself in the background. | 284 | before placing itself in the background. |
285 | .It Fl g | 285 | .It Fl g |
286 | Allows remote hosts to connect to local forwarded ports. | 286 | Allows remote hosts to connect to local forwarded ports. |
287 | .It Fl I Ar smartcard_device | 287 | .It Fl I Ar pkcs11 |
288 | Specify the device | 288 | Specify the PKCS#11 shared libarary |
289 | .Nm | 289 | .Nm |
290 | should use to communicate with a smartcard used for storing the user's | 290 | should use to communicate with a PKCS#11 token used for storing the user's |
291 | private RSA key. | 291 | private RSA key. |
292 | This option is only available if support for smartcard devices | 292 | This option is only available if support for PKCS#11 |
293 | is compiled in (default is no support). | 293 | is compiled in (default is no support). |
294 | .It Fl i Ar identity_file | 294 | .It Fl i Ar identity_file |
295 | Selects a file from which the identity (private key) for | 295 | Selects 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 |
@@ -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 | ||
110 | extern char *__progname; | 110 | extern 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 . |
712 | The default is | 712 | The default is |
713 | .Dq no . | 713 | .Dq no . |
714 | .It Cm PKCS11Provider | ||
715 | Specifies which PKCS#11 provider to use. | ||
716 | The argument to this keyword is the PKCS#11 shared libary | ||
717 | .Xr ssh 1 | ||
718 | should use to communicate with a PKCS#11 token used for storing the user's | ||
719 | private RSA key. | ||
720 | By default, no device is specified and PKCS#11 support is not activated. | ||
714 | .It Cm Port | 721 | .It Cm Port |
715 | Specifies the port number to connect on the remote host. | 722 | Specifies the port number to connect on the remote host. |
716 | The default is 22. | 723 | The default is 22. |
@@ -927,13 +934,6 @@ channel to request a response from the server. | |||
927 | The default | 934 | The default |
928 | is 0, indicating that these messages will not be sent to the server. | 935 | is 0, indicating that these messages will not be sent to the server. |
929 | This option applies to protocol version 2 only. | 936 | This option applies to protocol version 2 only. |
930 | .It Cm SmartcardDevice | ||
931 | Specifies which smartcard device to use. | ||
932 | The argument to this keyword is the device | ||
933 | .Xr ssh 1 | ||
934 | should use to communicate with a smartcard used for storing the user's | ||
935 | private RSA key. | ||
936 | By default, no device is specified and smartcard support is not activated. | ||
937 | .It Cm StrictHostKeyChecking | 937 | .It Cm StrictHostKeyChecking |
938 | If this flag is set to | 938 | If this flag is set to |
939 | .Dq yes , | 939 | .Dq yes , |