From 7ea845e48df6d34a333ebbe79380cba0938d02a5 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 12 Feb 2010 09:21:02 +1100 Subject: - 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 ` --- ssh-pkcs11-helper.c | 349 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 ssh-pkcs11-helper.c (limited to 'ssh-pkcs11-helper.c') 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 @@ +/* + * Copyright (c) 2010 Markus Friedl. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "xmalloc.h" +#include "buffer.h" +#include "log.h" +#include "misc.h" +#include "key.h" +#include "authfd.h" +#include "ssh-pkcs11.h" + +/* borrows code from sftp-server and ssh-agent */ + +struct pkcs11_keyinfo { + Key *key; + char *providername; + TAILQ_ENTRY(pkcs11_keyinfo) next; +}; + +TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist; + +#define MAX_MSG_LENGTH 10240 /*XXX*/ + +/* helper */ +#define get_int() buffer_get_int(&iqueue); +#define get_string(lenp) buffer_get_string(&iqueue, lenp); + +/* input and output queue */ +Buffer iqueue; +Buffer oqueue; + +static void +add_key(Key *k, char *name) +{ + struct pkcs11_keyinfo *ki; + + ki = xcalloc(1, sizeof(*ki)); + ki->providername = xstrdup(name); + ki->key = k; + TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next); +} + +static void +del_keys_by_name(char *name) +{ + struct pkcs11_keyinfo *ki, *nxt; + + for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) { + nxt = TAILQ_NEXT(ki, next); + if (!strcmp(ki->providername, name)) { + TAILQ_REMOVE(&pkcs11_keylist, ki, next); + xfree(ki->providername); + key_free(ki->key); + free(ki); + } + } +} + +/* lookup matching 'private' key */ +static Key * +lookup_key(Key *k) +{ + struct pkcs11_keyinfo *ki; + + TAILQ_FOREACH(ki, &pkcs11_keylist, next) { + debug("check %p %s", ki, ki->providername); + if (key_equal(k, ki->key)) + return (ki->key); + } + return (NULL); +} + +static void +send_msg(Buffer *m) +{ + int mlen = buffer_len(m); + + buffer_put_int(&oqueue, mlen); + buffer_append(&oqueue, buffer_ptr(m), mlen); + buffer_consume(m, mlen); +} + +static void +process_add(void) +{ + char *name, *pin; + Key **keys; + int i, nkeys; + u_char *blob; + u_int blen; + Buffer msg; + + buffer_init(&msg); + name = get_string(NULL); + pin = get_string(NULL); + if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) { + buffer_put_char(&msg, SSH2_AGENT_IDENTITIES_ANSWER); + buffer_put_int(&msg, nkeys); + for (i = 0; i < nkeys; i++) { + key_to_blob(keys[i], &blob, &blen); + buffer_put_string(&msg, blob, blen); + buffer_put_cstring(&msg, name); + xfree(blob); + add_key(keys[i], name); + } + xfree(keys); + } else { + buffer_put_char(&msg, SSH_AGENT_FAILURE); + } + xfree(pin); + xfree(name); + send_msg(&msg); + buffer_free(&msg); +} + +static void +process_del(void) +{ + char *name, *pin; + Buffer msg; + + buffer_init(&msg); + name = get_string(NULL); + pin = get_string(NULL); + del_keys_by_name(name); + if (pkcs11_del_provider(name) == 0) + buffer_put_char(&msg, SSH_AGENT_SUCCESS); + else + buffer_put_char(&msg, SSH_AGENT_FAILURE); + xfree(pin); + xfree(name); + send_msg(&msg); + buffer_free(&msg); +} + +static void +process_sign(void) +{ + u_char *blob, *data, *signature = NULL; + u_int blen, dlen, slen = 0; + int ok = -1, flags, ret; + Key *key, *found; + Buffer msg; + + blob = get_string(&blen); + data = get_string(&dlen); + flags = get_int(); /* XXX ignore */ + + if ((key = key_from_blob(blob, blen)) != NULL) { + if ((found = lookup_key(key)) != NULL) { + slen = RSA_size(key->rsa); + signature = xmalloc(slen); + if ((ret = RSA_private_encrypt(dlen, data, signature, + found->rsa, RSA_PKCS1_PADDING)) != -1) { + slen = ret; + ok = 0; + } + } + key_free(key); + } + buffer_init(&msg); + if (ok == 0) { + buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE); + buffer_put_string(&msg, signature, slen); + } else { + buffer_put_char(&msg, SSH_AGENT_FAILURE); + } + xfree(data); + xfree(blob); + if (signature != NULL) + xfree(signature); + send_msg(&msg); + buffer_free(&msg); +} + +static void +process(void) +{ + u_int msg_len; + u_int buf_len; + u_int consumed; + u_int type; + u_char *cp; + + buf_len = buffer_len(&iqueue); + if (buf_len < 5) + return; /* Incomplete message. */ + cp = buffer_ptr(&iqueue); + msg_len = get_u32(cp); + if (msg_len > MAX_MSG_LENGTH) { + error("bad message len %d", msg_len); + cleanup_exit(11); + } + if (buf_len < msg_len + 4) + return; + buffer_consume(&iqueue, 4); + buf_len -= 4; + type = buffer_get_char(&iqueue); + switch (type) { + case SSH_AGENTC_ADD_SMARTCARD_KEY: + debug("process_add"); + process_add(); + break; + case SSH_AGENTC_REMOVE_SMARTCARD_KEY: + debug("process_del"); + process_del(); + break; + case SSH2_AGENTC_SIGN_REQUEST: + debug("process_sign"); + process_sign(); + break; + default: + error("Unknown message %d", type); + break; + } + /* discard the remaining bytes from the current packet */ + if (buf_len < buffer_len(&iqueue)) { + error("iqueue grew unexpectedly"); + cleanup_exit(255); + } + consumed = buf_len - buffer_len(&iqueue); + if (msg_len < consumed) { + error("msg_len %d < consumed %d", msg_len, consumed); + cleanup_exit(255); + } + if (msg_len > consumed) + buffer_consume(&iqueue, msg_len - consumed); +} + +void +cleanup_exit(int i) +{ + /* XXX */ + _exit(i); +} + +int +main(int argc, char **argv) +{ + fd_set *rset, *wset; + int in, out, max, log_stderr = 0; + ssize_t len, olen, set_size; + SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; + LogLevel log_level = SYSLOG_LEVEL_ERROR; + char buf[4*4096]; + + TAILQ_INIT(&pkcs11_keylist); + pkcs11_init(0); + + extern char *optarg; + extern char *__progname; + + log_init(__progname, log_level, log_facility, log_stderr); + + in = STDIN_FILENO; + out = STDOUT_FILENO; + + max = 0; + if (in > max) + max = in; + if (out > max) + max = out; + + buffer_init(&iqueue); + buffer_init(&oqueue); + + set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); + rset = (fd_set *)xmalloc(set_size); + wset = (fd_set *)xmalloc(set_size); + + for (;;) { + memset(rset, 0, set_size); + memset(wset, 0, set_size); + + /* + * Ensure that we can read a full buffer and handle + * the worst-case length packet it can generate, + * otherwise apply backpressure by stopping reads. + */ + if (buffer_check_alloc(&iqueue, sizeof(buf)) && + buffer_check_alloc(&oqueue, MAX_MSG_LENGTH)) + FD_SET(in, rset); + + olen = buffer_len(&oqueue); + if (olen > 0) + FD_SET(out, wset); + + if (select(max+1, rset, wset, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + error("select: %s", strerror(errno)); + cleanup_exit(2); + } + + /* copy stdin to iqueue */ + if (FD_ISSET(in, rset)) { + len = read(in, buf, sizeof buf); + if (len == 0) { + debug("read eof"); + cleanup_exit(0); + } else if (len < 0) { + error("read: %s", strerror(errno)); + cleanup_exit(1); + } else { + buffer_append(&iqueue, buf, len); + } + } + /* send oqueue to stdout */ + if (FD_ISSET(out, wset)) { + len = write(out, buffer_ptr(&oqueue), olen); + if (len < 0) { + error("write: %s", strerror(errno)); + cleanup_exit(1); + } else { + buffer_consume(&oqueue, len); + } + } + + /* + * Process requests from client if we can fit the results + * into the output buffer, otherwise stop processing input + * and let the output queue drain. + */ + if (buffer_check_alloc(&oqueue, MAX_MSG_LENGTH)) + process(); + } +} -- cgit v1.2.3 From 8ad0fbd98e5ffd98c25f88881981336508ae90d7 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 12 Feb 2010 09:49:06 +1100 Subject: - (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] Make it compile on OSX --- ChangeLog | 2 ++ ssh-pkcs11-client.c | 6 +++++- ssh-pkcs11-helper.c | 9 +++++++-- ssh-pkcs11.c | 12 +++++++++--- 4 files changed, 23 insertions(+), 6 deletions(-) (limited to 'ssh-pkcs11-helper.c') diff --git a/ChangeLog b/ChangeLog index ce4ef1343..f56dad3ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -40,6 +40,8 @@ - (djm) [INSTALL Makefile.in README.smartcard configure.ac scard-opensc.c] [scard.c scard.h pkcs11.h scard/Makefile.in scard/Ssh.bin.uu scard/Ssh.java] Remove obsolete smartcard support + - (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] + Make it compile on OSX 20100210 - (djm) add -lselinux to LIBS before calling AC_CHECK_FUNCS for diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 6ffdd9364..d376153fa 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -14,8 +14,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include -#include +#ifdef HAVE_SYS_TIME_H +# include +#endif #include #include diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index f9962709b..464209641 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c @@ -14,9 +14,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include "includes.h" + #include -#include +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#include "openbsd-compat/sys-queue.h" #include #include diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index f82454329..2f6c9cec8 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -14,14 +14,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include -#include +#ifdef HAVE_SYS_TIME_H +# include +#endif #include #include #include #include +#include "openbsd-compat/sys-queue.h" + #define CRYPTOKI_COMPAT #include "pkcs11.h" @@ -190,14 +196,14 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, CK_ULONG tlen = 0, nfound = 0; CK_RV rv; CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY; - CK_BBOOL true = CK_TRUE; + CK_BBOOL true_val = CK_TRUE; CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 }; CK_ATTRIBUTE key_filter[] = { {CKA_CLASS, &private_key_class, sizeof(private_key_class) }, {CKA_ID, NULL, 0}, - {CKA_SIGN, &true, sizeof(true) } + {CKA_SIGN, &true_val, sizeof(true_val) } }; char *pin, prompt[1024]; int rval = -1; -- cgit v1.2.3 From dfa4156dbd4aa45464b2ea6b867bcaa483bed134 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 12 Feb 2010 10:06:28 +1100 Subject: - (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] Use ssh_get_progname to fill __progname --- ChangeLog | 2 ++ ssh-pkcs11-client.c | 4 ++++ ssh-pkcs11-helper.c | 15 +++++++++++++++ ssh-pkcs11.c | 4 ++++ 4 files changed, 25 insertions(+) (limited to 'ssh-pkcs11-helper.c') diff --git a/ChangeLog b/ChangeLog index f56dad3ca..c5dc75262 100644 --- a/ChangeLog +++ b/ChangeLog @@ -42,6 +42,8 @@ Remove obsolete smartcard support - (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] Make it compile on OSX + - (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] + Use ssh_get_progname to fill __progname 20100210 - (djm) add -lselinux to LIBS before calling AC_CHECK_FUNCS for diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index d376153fa..37050e04d 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -16,6 +16,8 @@ #include "includes.h" +#ifdef ENABLE_PKCS11 + #include #ifdef HAVE_SYS_TIME_H # include @@ -231,3 +233,5 @@ pkcs11_del_provider(char *name) buffer_free(&msg); return (ret); } + +#endif /* ENABLE_PKCS11 */ diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index 464209641..3b44f7c30 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c @@ -16,6 +16,8 @@ #include "includes.h" +#ifdef ENABLE_PKCS11 + #include #ifdef HAVE_SYS_TIME_H # include @@ -277,6 +279,8 @@ main(int argc, char **argv) extern char *optarg; extern char *__progname; + __progname = ssh_get_progname(argv[0]); + log_init(__progname, log_level, log_facility, log_stderr); in = STDIN_FILENO; @@ -352,3 +356,14 @@ main(int argc, char **argv) process(); } } +#else /* ENABLE_PKCS11 */ +int +main(int argc, char **argv) +{ + extern char *__progname; + + __progname = ssh_get_progname(argv[0]); + log_init(__progname, SYSLOG_LEVEL_ERROR, SYSLOG_FACILITY_AUTH, 0); + fatal("PKCS#11 support disabled at compile time"); +} +#endif /* ENABLE_PKCS11 */ diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 2f6c9cec8..821e9f840 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -16,6 +16,8 @@ #include "includes.h" +#ifdef ENABLE_PKCS11 + #include #ifdef HAVE_SYS_TIME_H # include @@ -548,3 +550,5 @@ fail: dlclose(handle); return (-1); } + +#endif /* ENABLE_PKCS11 */ -- cgit v1.2.3 From 05abd2c96876b959f4a2f71671652064fcedda0d Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 24 Feb 2010 17:16:08 +1100 Subject: - (djm) [pkcs11.h ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] [ssh-pkcs11.h] Add $OpenBSD$ RCS idents so we can sync portable --- ChangeLog | 4 ++++ pkcs11.h | 1 + ssh-pkcs11-client.c | 1 + ssh-pkcs11-helper.c | 1 + ssh-pkcs11.c | 1 + ssh-pkcs11.h | 1 + 6 files changed, 9 insertions(+) (limited to 'ssh-pkcs11-helper.c') diff --git a/ChangeLog b/ChangeLog index 83259b5fd..ac08efa4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +20100224 + - (djm) [pkcs11.h ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] + [ssh-pkcs11.h] Add $OpenBSD$ RCS idents so we can sync portable + 20100212 - (djm) OpenBSD CVS Sync - djm@cvs.openbsd.org 2010/02/02 22:49:34 diff --git a/pkcs11.h b/pkcs11.h index 223f20ff3..2cde5b3f4 100644 --- a/pkcs11.h +++ b/pkcs11.h @@ -1,3 +1,4 @@ +/* $OpenBSD: pkcs11.h,v 1.2 2010/02/24 06:12:53 djm Exp $ */ /* pkcs11.h Copyright 2006, 2007 g10 Code GmbH Copyright 2006 Andreas Jellinghaus diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 37050e04d..650c37342 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -1,3 +1,4 @@ +/* $OpenBSD: ssh-pkcs11-client.c,v 1.2 2010/02/24 06:12:53 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index 3b44f7c30..1684ab0c2 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c @@ -1,3 +1,4 @@ +/* $OpenBSD: ssh-pkcs11-helper.c,v 1.3 2010/02/24 06:12:53 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 821e9f840..7536f92a6 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1,3 +1,4 @@ +/* $OpenBSD: ssh-pkcs11.c,v 1.4 2010/02/24 06:12:53 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h index fae41a7b5..59f456adf 100644 --- a/ssh-pkcs11.h +++ b/ssh-pkcs11.h @@ -1,3 +1,4 @@ +/* $OpenBSD: ssh-pkcs11.h,v 1.2 2010/02/24 06:12:53 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * -- cgit v1.2.3 From 09a24db2d7e89c2fe72c1754181b6cc6e62949d7 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sun, 28 Feb 2010 03:28:05 +1100 Subject: - (djm) [ssh-pkcs11-helper.c ] Ensure RNG is initialised and seeded --- ChangeLog | 3 +++ ssh-pkcs11-helper.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'ssh-pkcs11-helper.c') diff --git a/ChangeLog b/ChangeLog index 703c347fb..931683219 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +20100227 +- (djm) [ssh-pkcs11-helper.c ] Ensure RNG is initialised and seeded + 20100226 - OpenBSD CVS Sync - djm@cvs.openbsd.org 2010/02/26 20:29:54 diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index 1684ab0c2..54786c62a 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c @@ -280,6 +280,8 @@ main(int argc, char **argv) extern char *optarg; extern char *__progname; + init_rng(); + seed_rng(); __progname = ssh_get_progname(argv[0]); log_init(__progname, log_level, log_facility, log_stderr); -- cgit v1.2.3 From bff24b8ad29f4b5427ffbe017acafdb3efc1b951 Mon Sep 17 00:00:00 2001 From: Tim Rice Date: Sun, 28 Feb 2010 14:51:56 -0800 Subject: - (tim) [ssh-pkcs11-helper.c] Move declarations before calling functions to make older compilers (gcc 2.95) happy. --- ChangeLog | 2 ++ ssh-pkcs11-helper.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'ssh-pkcs11-helper.c') diff --git a/ChangeLog b/ChangeLog index 06f519868..74bfc0469 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ platform, passwords are stored case-insensitively, but sshd requires exact case matching for Match blocks in sshd_config(5). Based on a patch from vinschen AT redhat.com. + - (tim) [ssh-pkcs11-helper.c] Move declarations before calling functions + to make older compilers (gcc 2.95) happy. 20100227 - (djm) [ssh-pkcs11-helper.c ] Ensure RNG is initialised and seeded diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index 54786c62a..d3bfb9838 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c @@ -274,12 +274,12 @@ main(int argc, char **argv) LogLevel log_level = SYSLOG_LEVEL_ERROR; char buf[4*4096]; - TAILQ_INIT(&pkcs11_keylist); - pkcs11_init(0); - extern char *optarg; extern char *__progname; + TAILQ_INIT(&pkcs11_keylist); + pkcs11_init(0); + init_rng(); seed_rng(); __progname = ssh_get_progname(argv[0]); -- cgit v1.2.3