diff options
author | green <green@FreeBSD.org> | 2000-12-05 02:20:19 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2000-12-05 02:20:19 +0000 |
commit | 1c5144a169aecf147a657c0e0e0a6460e92b5b83 (patch) | |
tree | db590dc709e61e16f11313599d2edbc3d7990745 /crypto | |
parent | c972e7aad1a6bdf921bbf261f2f93198504e35cf (diff) | |
parent | 2aecee364f2b1fa8b38c4d29600f05f33075cddf (diff) | |
download | FreeBSD-src-1c5144a169aecf147a657c0e0e0a6460e92b5b83.zip FreeBSD-src-1c5144a169aecf147a657c0e0e0a6460e92b5b83.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r69587,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'crypto')
45 files changed, 2407 insertions, 648 deletions
diff --git a/crypto/openssh/LICENCE b/crypto/openssh/LICENCE index e8ab01b..7c2346a 100644 --- a/crypto/openssh/LICENCE +++ b/crypto/openssh/LICENCE @@ -36,7 +36,7 @@ OpenSSH contains no GPL code. - The make-ssh-known-hosts script is no longer included - TSS has been removed - MD5 is now external, in the OpenSSL library - - RC4 support has been removed + - RC4 support has been replaced with ARC4 support from OpenSSL - Blowfish is now external, in the OpenSSL library [The licence continues] diff --git a/crypto/openssh/Makefile.inc b/crypto/openssh/Makefile.inc index fddf3da..85e1454 100644 --- a/crypto/openssh/Makefile.inc +++ b/crypto/openssh/Makefile.inc @@ -1,5 +1,7 @@ CFLAGS+= -I${.CURDIR}/.. +CFLAGS+= -Wall + .include <bsd.obj.mk> .if exists(${.CURDIR}/../lib/${__objdir}) diff --git a/crypto/openssh/RFC.nroff b/crypto/openssh/RFC.nroff index dccc954..bf7146a 100644 --- a/crypto/openssh/RFC.nroff +++ b/crypto/openssh/RFC.nroff @@ -1,6 +1,6 @@ .\" -*- nroff -*- .\" -.\" $Id: RFC.nroff,v 1.1 1999/09/26 20:53:32 deraadt Exp $ +.\" $OpenBSD: RFC.nroff,v 1.2 2000/10/16 09:38:44 djm Exp $ .\" .pl 10.0i .po 0 diff --git a/crypto/openssh/atomicio.c b/crypto/openssh/atomicio.c index 019eda8..744ccc7 100644 --- a/crypto/openssh/atomicio.c +++ b/crypto/openssh/atomicio.c @@ -24,7 +24,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: atomicio.c,v 1.5 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: atomicio.c,v 1.7 2000/10/18 18:04:02 markus Exp $"); #include "xmalloc.h" #include "ssh.h" diff --git a/crypto/openssh/auth-options.c b/crypto/openssh/auth-options.c index da69652..c9c149d 100644 --- a/crypto/openssh/auth-options.c +++ b/crypto/openssh/auth-options.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-options.c,v 1.4 2000/09/07 21:13:36 markus Exp $"); +RCSID("$OpenBSD: auth-options.c,v 1.5 2000/10/09 21:32:34 markus Exp $"); #include "ssh.h" #include "packet.h" @@ -33,6 +33,25 @@ char *forced_command = NULL; /* "environment=" options. */ struct envstring *custom_environment = NULL; +void +auth_clear_options(void) +{ + no_agent_forwarding_flag = 0; + no_port_forwarding_flag = 0; + no_pty_flag = 0; + no_x11_forwarding_flag = 0; + while (custom_environment) { + struct envstring *ce = custom_environment; + custom_environment = ce->next; + xfree(ce->s); + xfree(ce); + } + if (forced_command) { + xfree(forced_command); + forced_command = NULL; + } +} + /* return 1 if access is granted, 0 if not. side effect: sets key option flags */ int auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) @@ -40,6 +59,10 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) const char *cp; if (!options) return 1; + + /* reset options */ + auth_clear_options(); + while (*options && *options != ' ' && *options != '\t') { cp = "no-port-forwarding"; if (strncmp(options, cp, strlen(cp)) == 0) { @@ -87,9 +110,9 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) } if (!*options) { debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); + SSH_USER_PERMITTED_KEYS, linenum); packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); + SSH_USER_PERMITTED_KEYS, linenum); continue; } forced_command[i] = 0; @@ -117,9 +140,9 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) } if (!*options) { debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); + SSH_USER_PERMITTED_KEYS, linenum); packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); + SSH_USER_PERMITTED_KEYS, linenum); continue; } s[i] = 0; @@ -175,21 +198,6 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) get_remote_ipaddr()); packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", get_canonical_hostname()); - /* key invalid for this host, reset flags */ - no_agent_forwarding_flag = 0; - no_port_forwarding_flag = 0; - no_pty_flag = 0; - no_x11_forwarding_flag = 0; - while (custom_environment) { - struct envstring *ce = custom_environment; - custom_environment = ce->next; - xfree(ce->s); - xfree(ce); - } - if (forced_command) { - xfree(forced_command); - forced_command = NULL; - } /* deny access */ return 0; } diff --git a/crypto/openssh/auth-options.h b/crypto/openssh/auth-options.h index 9044d98..00fae22 100644 --- a/crypto/openssh/auth-options.h +++ b/crypto/openssh/auth-options.h @@ -10,6 +10,9 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ + +/* $OpenBSD: auth-options.h,v 1.5 2000/10/16 09:38:44 djm Exp $ */ + #ifndef AUTH_OPTIONS_H #define AUTH_OPTIONS_H /* Flags that may be set in authorized_keys options. */ @@ -22,4 +25,7 @@ extern struct envstring *custom_environment; /* return 1 if access is granted, 0 if not. side effect: sets key option flags */ int auth_parse_options(struct passwd *pw, char *options, unsigned long linenum); +/* reset options flags */ +void auth_clear_options(void); + #endif diff --git a/crypto/openssh/auth-rhosts.c b/crypto/openssh/auth-rhosts.c index 901c8d1..8314e23 100644 --- a/crypto/openssh/auth-rhosts.c +++ b/crypto/openssh/auth-rhosts.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rhosts.c,v 1.15 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: auth-rhosts.c,v 1.16 2000/10/03 18:03:03 markus Exp $"); #include "packet.h" #include "ssh.h" @@ -154,6 +154,9 @@ auth_rhosts(struct passwd *pw, const char *client_user) static const char *rhosts_files[] = {".shosts", ".rhosts", NULL}; unsigned int rhosts_file_index; + /* no user given */ + if (pw == NULL) + return 0; /* Switch to the user's uid. */ temporarily_use_uid(pw->pw_uid); /* diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h index 65bf7ae..721d763 100644 --- a/crypto/openssh/auth.h +++ b/crypto/openssh/auth.h @@ -20,21 +20,35 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $OpenBSD: auth.h,v 1.7 2000/10/16 09:38:44 djm Exp $ */ #ifndef AUTH_H #define AUTH_H +typedef struct Authctxt Authctxt; +struct Authctxt { + int success; + int valid; + int attempt; + char *user; + char *service; + struct passwd *pw; +}; + void do_authentication(void); void do_authentication2(void); -struct passwd * -auth_get_user(void); +void userauth_log(Authctxt *authctxt, int authenticated, char *method); +void userauth_reply(Authctxt *authctxt, int authenticated); -int allowed_user(struct passwd * pw); +int auth2_skey(Authctxt *authctxt); + +int allowed_user(struct passwd * pw); +struct passwd * auth_get_user(void); #define AUTH_FAIL_MAX 6 #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) #define AUTH_FAIL_MSG "Too many authentication failures for %.100s" #endif - diff --git a/crypto/openssh/auth2-skey.c b/crypto/openssh/auth2-skey.c new file mode 100644 index 0000000..9de08fc --- /dev/null +++ b/crypto/openssh/auth2-skey.c @@ -0,0 +1,104 @@ +#include "includes.h" +RCSID("$OpenBSD: auth2-skey.c,v 1.1 2000/10/11 20:14:38 markus Exp $"); + +#include "ssh.h" +#include "ssh2.h" +#include "auth.h" +#include "packet.h" +#include "xmalloc.h" +#include "dispatch.h" + +void send_userauth_into_request(Authctxt *authctxt, int echo); +void input_userauth_info_response(int type, int plen, void *ctxt); + +/* + * try skey authentication, always return -1 (= postponed) since we have to + * wait for the s/key response. + */ +int +auth2_skey(Authctxt *authctxt) +{ + send_userauth_into_request(authctxt, 0); + dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &input_userauth_info_response); + return -1; +} + +void +send_userauth_into_request(Authctxt *authctxt, int echo) +{ + int retval = -1; + struct skey skey; + char challenge[SKEY_MAX_CHALLENGE]; + char *fake; + + if (authctxt->user == NULL) + fatal("send_userauth_into_request: internal error: no user"); + + /* get skey challenge */ + if (authctxt->valid) + retval = skeychallenge(&skey, authctxt->user, challenge); + + if (retval == -1) { + fake = skey_fake_keyinfo(authctxt->user); + strlcpy(challenge, fake, sizeof challenge); + } + /* send our info request */ + packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); + packet_put_cstring("S/Key Authentication"); /* Name */ + packet_put_cstring(challenge); /* Instruction */ + packet_put_cstring(""); /* Language */ + packet_put_int(1); /* Number of prompts */ + packet_put_cstring(echo ? + "Response [Echo]: ": "Response: "); /* Prompt */ + packet_put_char(echo); /* Echo */ + packet_send(); + packet_write_wait(); + memset(challenge, 'c', sizeof challenge); +} + +void +input_userauth_info_response(int type, int plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + int authenticated = 0; + unsigned int nresp, rlen; + char *resp, *method; + + if (authctxt == NULL) + fatal("input_userauth_info_response: no authentication context"); + + if (authctxt->attempt++ >= AUTH_FAIL_MAX) + packet_disconnect("too many failed userauth_requests"); + + nresp = packet_get_int(); + if (nresp == 1) { + /* we only support s/key and assume s/key for nresp == 1 */ + method = "s/key"; + resp = packet_get_string(&rlen); + packet_done(); + if (strlen(resp) == 0) { + /* + * if we received a null response, resend prompt with + * echo enabled + */ + authenticated = -1; + userauth_log(authctxt, authenticated, method); + send_userauth_into_request(authctxt, 1); + } else { + /* verify skey response */ + if (authctxt->valid && + skey_haskey(authctxt->pw->pw_name) == 0 && + skey_passcheck(authctxt->pw->pw_name, resp) != -1) { + authenticated = 1; + } else { + authenticated = 0; + } + memset(resp, 'r', rlen); + /* unregister callback */ + dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); + userauth_log(authctxt, authenticated, method); + userauth_reply(authctxt, authenticated); + } + xfree(resp); + } +} diff --git a/crypto/openssh/authfd.h b/crypto/openssh/authfd.h index b7a137d..2d24652 100644 --- a/crypto/openssh/authfd.h +++ b/crypto/openssh/authfd.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: authfd.h,v 1.11 2000/09/07 20:27:49 deraadt Exp $"); */ +/* RCSID("$OpenBSD: authfd.h,v 1.13 2000/10/09 21:51:00 markus Exp $"); */ #ifndef AUTHFD_H #define AUTHFD_H @@ -29,6 +29,7 @@ #define SSH_AGENTC_REMOVE_RSA_IDENTITY 8 #define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9 +/* private OpenSSH extensions for SSH2 */ #define SSH2_AGENTC_REQUEST_IDENTITIES 11 #define SSH2_AGENT_IDENTITIES_ANSWER 12 #define SSH2_AGENTC_SIGN_REQUEST 13 @@ -37,6 +38,12 @@ #define SSH2_AGENTC_REMOVE_IDENTITY 18 #define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 +/* additional error code for ssh.com's ssh-agent2 */ +#define SSH_COM_AGENT2_FAILURE 102 + +#define SSH_AGENT_OLD_SIGNATURE 0x01 + + typedef struct { int fd; Buffer identities; diff --git a/crypto/openssh/authfile.h b/crypto/openssh/authfile.h index 4283d93..525b4aa 100644 --- a/crypto/openssh/authfile.h +++ b/crypto/openssh/authfile.h @@ -10,9 +10,13 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ + +/* $OpenBSD: authfile.h,v 1.5 2000/10/16 09:38:44 djm Exp $ */ + #ifndef AUTHFILE_H #define AUTHFILE_H + /* * Saves the authentication (private) key in a file, encrypting it with * passphrase. diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c index e9a64d9..81bd715 100644 --- a/crypto/openssh/channels.c +++ b/crypto/openssh/channels.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.68 2000/09/07 20:40:29 markus Exp $"); +RCSID("$OpenBSD: channels.c,v 1.72 2000/10/27 07:48:22 markus Exp $"); #include "ssh.h" #include "packet.h" @@ -174,7 +174,8 @@ channel_lookup(int id) */ void -channel_register_fds(Channel *c, int rfd, int wfd, int efd, int extusage) +channel_register_fds(Channel *c, int rfd, int wfd, int efd, + int extusage, int nonblock) { /* Update the maximum file descriptor value. */ if (rfd > channel_max_fd_value) @@ -190,12 +191,16 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, int extusage) c->sock = (rfd == wfd) ? rfd : -1; c->efd = efd; c->extended_usage = extusage; - if (rfd != -1) - set_nonblock(rfd); - if (wfd != -1) - set_nonblock(wfd); - if (efd != -1) - set_nonblock(efd); + + /* enable nonblocking mode */ + if (nonblock) { + if (rfd != -1) + set_nonblock(rfd); + if (wfd != -1) + set_nonblock(wfd); + if (efd != -1) + set_nonblock(efd); + } } /* @@ -205,7 +210,7 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, int extusage) int channel_new(char *ctype, int type, int rfd, int wfd, int efd, - int window, int maxpack, int extusage, char *remote_name) + int window, int maxpack, int extusage, char *remote_name, int nonblock) { int i, found; Channel *c; @@ -234,7 +239,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, /* There are no free slots. Take last+1 slot and expand the array. */ found = channels_alloc; channels_alloc += 10; - debug("channel: expanding %d", channels_alloc); + debug2("channel: expanding %d", channels_alloc); channels = xrealloc(channels, channels_alloc * sizeof(Channel)); for (i = found; i < channels_alloc; i++) channels[i].type = SSH_CHANNEL_FREE; @@ -245,7 +250,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, buffer_init(&c->output); buffer_init(&c->extended); chan_init_iostates(c); - channel_register_fds(c, rfd, wfd, efd, extusage); + channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); c->self = found; c->type = type; c->ctype = ctype; @@ -269,7 +274,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, int channel_allocate(int type, int sock, char *remote_name) { - return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name); + return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name, 1); } @@ -548,7 +553,7 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) newch = channel_new("x11", SSH_CHANNEL_OPENING, newsock, newsock, -1, c->local_window_max, c->local_maxpacket, - 0, xstrdup(buf)); + 0, xstrdup(buf), 1); if (compat20) { packet_start(SSH2_MSG_CHANNEL_OPEN); packet_put_cstring("x11"); @@ -606,7 +611,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) newch = channel_new("direct-tcpip", SSH_CHANNEL_OPENING, newsock, newsock, -1, c->local_window_max, c->local_maxpacket, - 0, xstrdup(buf)); + 0, xstrdup(buf), 1); if (compat20) { packet_start(SSH2_MSG_CHANNEL_OPEN); packet_put_cstring("direct-tcpip"); @@ -737,7 +742,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) buffer_len(&c->extended) > 0) { len = write(c->efd, buffer_ptr(&c->extended), buffer_len(&c->extended)); - debug("channel %d: written %d to efd %d", + debug2("channel %d: written %d to efd %d", c->self, len, c->efd); if (len > 0) { buffer_consume(&c->extended, len); @@ -746,7 +751,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) } else if (c->extended_usage == CHAN_EXTENDED_READ && FD_ISSET(c->efd, readset)) { len = read(c->efd, buf, sizeof(buf)); - debug("channel %d: read %d from efd %d", + debug2("channel %d: read %d from efd %d", c->self, len, c->efd); if (len == 0) { debug("channel %d: closing efd %d", @@ -769,7 +774,7 @@ channel_check_window(Channel *c, fd_set * readset, fd_set * writeset) packet_put_int(c->remote_id); packet_put_int(c->local_consumed); packet_send(); - debug("channel %d: window %d sent adjust %d", + debug2("channel %d: window %d sent adjust %d", c->self, c->local_window, c->local_consumed); c->local_window += c->local_consumed; @@ -998,7 +1003,7 @@ channel_output_poll() */ void -channel_input_data(int type, int plen) +channel_input_data(int type, int plen, void *ctxt) { int id; char *data; @@ -1043,7 +1048,7 @@ channel_input_data(int type, int plen) xfree(data); } void -channel_input_extended_data(int type, int plen) +channel_input_extended_data(int type, int plen, void *ctxt) { int id; int tcode; @@ -1076,7 +1081,7 @@ channel_input_extended_data(int type, int plen) xfree(data); return; } - debug("channel %d: rcvd ext data %d", c->self, data_len); + debug2("channel %d: rcvd ext data %d", c->self, data_len); c->local_window -= data_len; buffer_append(&c->extended, data, data_len); xfree(data); @@ -1113,7 +1118,7 @@ channel_not_very_much_buffered_data() } void -channel_input_ieof(int type, int plen) +channel_input_ieof(int type, int plen, void *ctxt) { int id; Channel *c; @@ -1128,7 +1133,7 @@ channel_input_ieof(int type, int plen) } void -channel_input_close(int type, int plen) +channel_input_close(int type, int plen, void *ctxt) { int id; Channel *c; @@ -1167,7 +1172,7 @@ channel_input_close(int type, int plen) /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ void -channel_input_oclose(int type, int plen) +channel_input_oclose(int type, int plen, void *ctxt) { int id = packet_get_int(); Channel *c = channel_lookup(id); @@ -1178,7 +1183,7 @@ channel_input_oclose(int type, int plen) } void -channel_input_close_confirmation(int type, int plen) +channel_input_close_confirmation(int type, int plen, void *ctxt) { int id = packet_get_int(); Channel *c = channel_lookup(id); @@ -1194,7 +1199,7 @@ channel_input_close_confirmation(int type, int plen) } void -channel_input_open_confirmation(int type, int plen) +channel_input_open_confirmation(int type, int plen, void *ctxt) { int id, remote_id; Channel *c; @@ -1218,9 +1223,9 @@ channel_input_open_confirmation(int type, int plen) c->remote_maxpacket = packet_get_int(); packet_done(); if (c->cb_fn != NULL && c->cb_event == type) { - debug("callback start"); + debug2("callback start"); c->cb_fn(c->self, c->cb_arg); - debug("callback done"); + debug2("callback done"); } debug("channel %d: open confirm rwindow %d rmax %d", c->self, c->remote_window, c->remote_maxpacket); @@ -1228,7 +1233,7 @@ channel_input_open_confirmation(int type, int plen) } void -channel_input_open_failure(int type, int plen) +channel_input_open_failure(int type, int plen, void *ctxt) { int id; Channel *c; @@ -1256,7 +1261,7 @@ channel_input_open_failure(int type, int plen) } void -channel_input_channel_request(int type, int plen) +channel_input_channel_request(int type, int plen, void *ctxt) { int id; Channel *c; @@ -1269,19 +1274,19 @@ channel_input_channel_request(int type, int plen) packet_disconnect("Received request for " "non-open channel %d.", id); if (c->cb_fn != NULL && c->cb_event == type) { - debug("callback start"); + debug2("callback start"); c->cb_fn(c->self, c->cb_arg); - debug("callback done"); + debug2("callback done"); } else { char *service = packet_get_string(NULL); debug("channel: %d rcvd request for %s", c->self, service); -debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event); + debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event); xfree(service); } } void -channel_input_window_adjust(int type, int plen) +channel_input_window_adjust(int type, int plen, void *ctxt) { Channel *c; int id, adjust; @@ -1300,7 +1305,7 @@ channel_input_window_adjust(int type, int plen) } adjust = packet_get_int(); packet_done(); - debug("channel %d: rcvd adjust %d", id, adjust); + debug2("channel %d: rcvd adjust %d", id, adjust); c->remote_window += adjust; } @@ -1510,7 +1515,7 @@ channel_request_local_forwarding(u_short port, const char *host, "port listener", SSH_CHANNEL_PORT_LISTENER, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, - 0, xstrdup("port listener")); + 0, xstrdup("port listener"), 1); strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); channels[ch].host_port = host_port; channels[ch].listening_port = port; @@ -1652,7 +1657,7 @@ channel_connect_to(const char *host, u_short host_port) */ void -channel_input_port_open(int type, int plen) +channel_input_port_open(int type, int plen, void *ctxt) { u_short host_port; char *host, *originator_string; @@ -1800,7 +1805,7 @@ x11_create_display_inet(int screen_number, int x11_display_offset) (void) channel_new("x11 listener", SSH_CHANNEL_X11_LISTENER, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, - 0, xstrdup("X11 inet listener")); + 0, xstrdup("X11 inet listener"), 1); } /* Return a suitable value for the DISPLAY environment variable. */ @@ -1942,7 +1947,7 @@ x11_connect_display(void) */ void -x11_input_open(int type, int plen) +x11_input_open(int type, int plen, void *ctxt) { int remote_channel, sock = 0, newch; char *remote_host; @@ -1986,6 +1991,28 @@ x11_input_open(int type, int plen) } } +/* dummy protocol handler that denies SSH-1 requests (agent/x11) */ +void +deny_input_open(int type, int plen, void *ctxt) +{ + int rchan = packet_get_int(); + switch(type){ + case SSH_SMSG_AGENT_OPEN: + error("Warning: ssh server tried agent forwarding."); + break; + case SSH_SMSG_X11_OPEN: + error("Warning: ssh server tried X11 forwarding."); + break; + default: + error("deny_input_open: type %d plen %d", type, plen); + break; + } + error("Warning: this is probably a break in attempt by a malicious server."); + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(rchan); + packet_send(); +} + /* * Requests forwarding of X11 connections, generates fake authentication * data, and enables authentication spoofing. @@ -2157,7 +2184,7 @@ auth_input_request_forwarding(struct passwd * pw) /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ void -auth_input_open_request(int type, int plen) +auth_input_open_request(int type, int plen, void *ctxt) { int remch, sock, newch; char *dummyname; @@ -2290,13 +2317,13 @@ channel_register_filter(int id, channel_filter_fn *fn) } void -channel_set_fds(int id, int rfd, int wfd, int efd, int extusage) +channel_set_fds(int id, int rfd, int wfd, int efd, + int extusage, int nonblock) { Channel *c = channel_lookup(id); if (c == NULL || c->type != SSH_CHANNEL_LARVAL) fatal("channel_activate for non-larval channel %d.", id); - - channel_register_fds(c, rfd, wfd, efd, extusage); + channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); c->type = SSH_CHANNEL_OPEN; /* XXX window size? */ c->local_window = c->local_window_max = c->local_maxpacket * 2; diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h index c0d6019..0052686 100644 --- a/crypto/openssh/channels.h +++ b/crypto/openssh/channels.h @@ -32,7 +32,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("$OpenBSD: channels.h,v 1.19 2000/09/07 21:13:37 markus Exp $"); */ +/* RCSID("$OpenBSD: channels.h,v 1.22 2000/10/27 07:48:22 markus Exp $"); */ #ifndef CHANNELS_H #define CHANNELS_H @@ -117,7 +117,6 @@ struct Channel { #define CHAN_X11_PACKET_DEFAULT (CHAN_X11_WINDOW_DEFAULT/2) -void channel_set_fds(int id, int rfd, int wfd, int efd, int extusage); void channel_open(int id); void channel_request(int id, char *service, int wantconfirm); void channel_request_start(int id, char *service, int wantconfirm); @@ -129,20 +128,26 @@ Channel *channel_lookup(int id); int channel_new(char *ctype, int type, int rfd, int wfd, int efd, - int window, int maxpack, int extended_usage, char *remote_name); - -void channel_input_channel_request(int type, int plen); -void channel_input_close(int type, int plen); -void channel_input_close_confirmation(int type, int plen); -void channel_input_data(int type, int plen); -void channel_input_extended_data(int type, int plen); -void channel_input_ieof(int type, int plen); -void channel_input_oclose(int type, int plen); -void channel_input_open_confirmation(int type, int plen); -void channel_input_open_failure(int type, int plen); -void channel_input_port_open(int type, int plen); -void channel_input_window_adjust(int type, int plen); -void channel_input_open(int type, int plen); + int window, int maxpack, int extended_usage, char *remote_name, + int nonblock); +void +channel_set_fds(int id, int rfd, int wfd, int efd, + int extusage, int nonblock); + +void deny_input_open(int type, int plen, void *ctxt); + +void channel_input_channel_request(int type, int plen, void *ctxt); +void channel_input_close(int type, int plen, void *ctxt); +void channel_input_close_confirmation(int type, int plen, void *ctxt); +void channel_input_data(int type, int plen, void *ctxt); +void channel_input_extended_data(int type, int plen, void *ctxt); +void channel_input_ieof(int type, int plen, void *ctxt); +void channel_input_oclose(int type, int plen, void *ctxt); +void channel_input_open_confirmation(int type, int plen, void *ctxt); +void channel_input_open_failure(int type, int plen, void *ctxt); +void channel_input_port_open(int type, int plen, void *ctxt); +void channel_input_window_adjust(int type, int plen, void *ctxt); +void channel_input_open(int type, int plen, void *ctxt); /* Sets specific protocol options. */ void channel_set_options(int hostname_in_open); @@ -246,7 +251,7 @@ char *x11_create_display_inet(int screen, int x11_display_offset); * the remote channel number. We should do whatever we want, and respond * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */ -void x11_input_open(int type, int plen); +void x11_input_open(int type, int plen, void *ctxt); /* * Requests forwarding of X11 connections. This should be called on the @@ -279,7 +284,7 @@ char *auth_get_socket_name(void); int auth_input_request_forwarding(struct passwd * pw); /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ -void auth_input_open_request(int type, int plen); +void auth_input_open_request(int type, int plen, void *ctxt); /* XXX */ int channel_connect_to(const char *host, u_short host_port); diff --git a/crypto/openssh/cli.c b/crypto/openssh/cli.c new file mode 100644 index 0000000..ab9a7dc --- /dev/null +++ b/crypto/openssh/cli.c @@ -0,0 +1,196 @@ +#include "includes.h" +RCSID("$OpenBSD: cli.c,v 1.2 2000/10/16 09:38:44 djm Exp $"); + +#include "xmalloc.h" +#include "ssh.h" +#include <vis.h> + +static int cli_input = -1; +static int cli_output = -1; +static int cli_from_stdin = 0; + +sigset_t oset; +sigset_t nset; +struct sigaction nsa; +struct sigaction osa; +struct termios ntio; +struct termios otio; +int echo_modified; + +volatile int intr; + +static int +cli_open(int from_stdin) +{ + if (cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin) + return 1; + + if (from_stdin) { + if (!cli_from_stdin && cli_input >= 0) { + (void)close(cli_input); + } + cli_input = STDIN_FILENO; + cli_output = STDERR_FILENO; + } else { + cli_input = cli_output = open("/dev/tty", O_RDWR); + if (cli_input < 0) + fatal("You have no controlling tty. Cannot read passphrase."); + } + + cli_from_stdin = from_stdin; + + return cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin; +} + +static void +cli_close() +{ + if (!cli_from_stdin && cli_input >= 0) + close(cli_input); + cli_input = -1; + cli_output = -1; + cli_from_stdin = 0; + return; +} + +void +intrcatch() +{ + intr = 1; +} + +static void +cli_echo_disable() +{ + sigemptyset(&nset); + sigaddset(&nset, SIGTSTP); + (void) sigprocmask(SIG_BLOCK, &nset, &oset); + + intr = 0; + + memset(&nsa, 0, sizeof(nsa)); + nsa.sa_handler = intrcatch; + (void) sigaction(SIGINT, &nsa, &osa); + + echo_modified = 0; + if (tcgetattr(cli_input, &otio) == 0 && (otio.c_lflag & ECHO)) { + echo_modified = 1; + ntio = otio; + ntio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); + (void) tcsetattr(cli_input, TCSANOW, &ntio); + } + return; +} + +static void +cli_echo_restore() +{ + if (echo_modified != 0) { + tcsetattr(cli_input, TCSANOW, &otio); + echo_modified = 0; + } + + (void) sigprocmask(SIG_SETMASK, &oset, NULL); + (void) sigaction(SIGINT, &osa, NULL); + + if (intr != 0) { + kill(getpid(), SIGINT); + sigemptyset(&nset); + /* XXX tty has not neccessarily drained by now? */ + sigsuspend(&nset); + intr = 0; + } + return; +} + +static int +cli_read(char* buf, int size, int echo) +{ + char ch = 0; + int i = 0; + + if (!echo) + cli_echo_disable(); + + while (ch != '\n') { + if (read(cli_input, &ch, 1) != 1) + break; + if (ch == '\n' || intr != 0) + break; + if (i < size) + buf[i++] = ch; + } + buf[i] = '\0'; + + if (!echo) + cli_echo_restore(); + if (!intr && !echo) + (void) write(cli_output, "\n", 1); + return i; +} + +static int +cli_write(char* buf, int size) +{ + int i, len, pos, ret = 0; + char *output, *p; + + output = xmalloc(4*size); + for (p = output, i = 0; i < size; i++) { + if (buf[i] == '\n') + *p++ = buf[i]; + else + p = vis(p, buf[i], 0, 0); + } + len = p - output; + + for (pos = 0; pos < len; pos += ret) { + ret = write(cli_output, output + pos, len - pos); + if (ret == -1) + return -1; + } + return 0; +} + +/* + * Presents a prompt and returns the response allocated with xmalloc(). + * Uses /dev/tty or stdin/out depending on arg. Optionally disables echo + * of response depending on arg. Tries to ensure that no other userland + * buffer is storing the response. + */ +char* +cli_read_passphrase(char* prompt, int from_stdin, int echo_enable) +{ + char buf[BUFSIZ]; + char* p; + + if (!cli_open(from_stdin)) + fatal("Cannot read passphrase."); + + fflush(stdout); + + cli_write(prompt, strlen(prompt)); + cli_read(buf, sizeof buf, echo_enable); + + cli_close(); + + p = xstrdup(buf); + memset(buf, 0, sizeof(buf)); + return (p); +} + +char* +cli_prompt(char* prompt, int echo_enable) +{ + return cli_read_passphrase(prompt, 0, echo_enable); +} + +void +cli_mesg(char* mesg) +{ + cli_open(0); + cli_write(mesg, strlen(mesg)); + cli_write("\n", strlen("\n")); + cli_close(); + return; +} diff --git a/crypto/openssh/cli.h b/crypto/openssh/cli.h new file mode 100644 index 0000000..c419404 --- /dev/null +++ b/crypto/openssh/cli.h @@ -0,0 +1,16 @@ +/* $OpenBSD: cli.h,v 1.2 2000/10/16 09:38:44 djm Exp $ */ + +#ifndef CLI_H +#define CLI_H + +/* + * Presents a prompt and returns the response allocated with xmalloc(). + * Uses /dev/tty or stdin/out depending on arg. Optionally disables echo + * of response depending on arg. Tries to ensure that no other userland + * buffer is storing the response. + */ +char* cli_read_passphrase(char* prompt, int from_stdin, int echo_enable); +char* cli_prompt(char* prompt, int echo_enable); +void cli_mesg(char* mesg); + +#endif /* CLI_H */ diff --git a/crypto/openssh/clientloop.c b/crypto/openssh/clientloop.c index 4a10b98..bccb9be 100644 --- a/crypto/openssh/clientloop.c +++ b/crypto/openssh/clientloop.c @@ -59,7 +59,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: clientloop.c,v 1.34 2000/09/07 20:40:30 markus Exp $"); +RCSID("$OpenBSD: clientloop.c,v 1.39 2000/10/27 07:48:22 markus Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -75,6 +75,8 @@ RCSID("$OpenBSD: clientloop.c,v 1.34 2000/09/07 20:40:30 markus Exp $"); #include "buffer.h" #include "bufaux.h" + +/* import options */ extern Options options; /* Flag indicating that stdin should be redirected from /dev/null. */ @@ -335,7 +337,7 @@ client_check_window_change() if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) return; - debug("client_check_window_change: changed"); + debug2("client_check_window_change: changed"); if (compat20) { channel_request_start(session_ident, "window-change", 0); @@ -362,8 +364,6 @@ client_check_window_change() void client_wait_until_can_do_something(fd_set * readset, fd_set * writeset) { - /*debug("client_wait_until_can_do_something"); */ - /* Initialize select masks. */ FD_ZERO(readset); FD_ZERO(writeset); @@ -482,7 +482,6 @@ client_process_net_input(fd_set * readset) if (FD_ISSET(connection_in, readset)) { /* Read as much as possible. */ len = read(connection_in, buf, sizeof(buf)); -/*debug("read connection_in len %d", len); XXX */ if (len == 0) { /* Received EOF. The remote host has closed the connection. */ snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", @@ -773,7 +772,7 @@ client_process_output(fd_set * writeset) void client_process_buffered_input_packets() { - dispatch_run(DISPATCH_NONBLOCK, &quit_pending); + dispatch_run(DISPATCH_NONBLOCK, &quit_pending, NULL); } /* scan buf[] for '~' before sending data to the peer */ @@ -853,7 +852,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) client_process_buffered_input_packets(); if (compat20 && !channel_still_open()) { - debug("!channel_still_open."); + debug2("!channel_still_open."); break; } @@ -979,7 +978,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) /*********/ void -client_input_stdout_data(int type, int plen) +client_input_stdout_data(int type, int plen, void *ctxt) { unsigned int data_len; char *data = packet_get_string(&data_len); @@ -990,7 +989,7 @@ client_input_stdout_data(int type, int plen) xfree(data); } void -client_input_stderr_data(int type, int plen) +client_input_stderr_data(int type, int plen, void *ctxt) { unsigned int data_len; char *data = packet_get_string(&data_len); @@ -1001,7 +1000,7 @@ client_input_stderr_data(int type, int plen) xfree(data); } void -client_input_exit_status(int type, int plen) +client_input_exit_status(int type, int plen, void *ctxt) { packet_integrity_check(plen, 4, type); exit_status = packet_get_int(); @@ -1019,7 +1018,7 @@ client_input_exit_status(int type, int plen) /* XXXX move to generic input handler */ void -client_input_channel_open(int type, int plen) +client_input_channel_open(int type, int plen, void *ctxt) { Channel *c = NULL; char *ctype; @@ -1043,7 +1042,7 @@ client_input_channel_open(int type, int plen) int originator_port; originator = packet_get_string(NULL); if (datafellows & SSH_BUG_X11FWD) { - debug("buggy server: x11 request w/o originator_port"); + debug2("buggy server: x11 request w/o originator_port"); originator_port = 0; } else { originator_port = packet_get_int(); @@ -1056,7 +1055,7 @@ client_input_channel_open(int type, int plen) if (sock >= 0) { id = channel_new("x11", SSH_CHANNEL_X11_OPEN, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, - CHAN_X11_PACKET_DEFAULT, 0, xstrdup("x11")); + CHAN_X11_PACKET_DEFAULT, 0, xstrdup("x11"), 1); c = channel_lookup(id); } } @@ -1114,9 +1113,9 @@ client_init_dispatch_13() dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ? - &auth_input_open_request : NULL); + &auth_input_open_request : &deny_input_open); dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? - &x11_input_open : NULL); + &x11_input_open : &deny_input_open); } void client_init_dispatch_15() @@ -1152,7 +1151,7 @@ client_input_channel_req(int id, void *arg) c = channel_lookup(id); if (c == NULL) - fatal("session_input_channel_req: channel %d: bad channel", id); + fatal("client_input_channel_req: channel %d: bad channel", id); if (session_ident == -1) { error("client_input_channel_req: no channel %d", id); @@ -1176,7 +1175,7 @@ client_input_channel_req(int id, void *arg) void client_set_session_ident(int id) { - debug("client_set_session_ident: id %d", id); + debug2("client_set_session_ident: id %d", id); session_ident = id; channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST, client_input_channel_req, (void *)0); diff --git a/crypto/openssh/compat.c b/crypto/openssh/compat.c index eeb6e2e..a9daabc 100644 --- a/crypto/openssh/compat.c +++ b/crypto/openssh/compat.c @@ -23,12 +23,13 @@ */ #include "includes.h" -RCSID("$OpenBSD: compat.c,v 1.23 2000/09/07 21:13:37 markus Exp $"); +RCSID("$OpenBSD: compat.c,v 1.27 2000/10/31 09:31:58 markus Exp $"); #include "ssh.h" #include "packet.h" #include "xmalloc.h" #include "compat.h" +#include <regex.h> int compat13 = 0; int compat20 = 0; @@ -50,27 +51,46 @@ enable_compat13(void) void compat_datafellows(const char *version) { - int i; - size_t len; - struct { - char *version; + int i, ret; + char ebuf[1024]; + regex_t reg; + static struct { + char *pat; int bugs; } check[] = { - {"2.1.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC}, - {"2.0.1", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD}, - {"2.", SSH_BUG_HMAC|SSH_COMPAT_SESSIONID_ENCODING}, - {NULL, 0} + { "^OpenSSH[-_]2\\.[012]", SSH_OLD_SESSIONID }, + { "MindTerm", 0 }, + { "^2\\.1\\.0 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID }, + { "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID| + SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD }, + { "^2\\.[23]\\.0 ", SSH_BUG_HMAC}, + { "^2\\.[2-9]\\.", 0 }, + { "^2\\.4$", SSH_OLD_SESSIONID}, /* Van Dyke */ + { "^3\\.0 SecureCRT", SSH_OLD_SESSIONID}, + { "^1\\.7 SecureFX", SSH_OLD_SESSIONID}, + { "^2\\.", SSH_BUG_HMAC}, /* XXX fallback */ + { NULL, 0 } }; /* process table, return first match */ - for (i = 0; check[i].version; i++) { - len = strlen(check[i].version); - if (strlen(version) >= len && - (strncmp(version, check[i].version, len) == 0)) { - verbose("datafellows: %.200s", version); + for (i = 0; check[i].pat; i++) { + ret = regcomp(®, check[i].pat, REG_EXTENDED|REG_NOSUB); + if (ret != 0) { + regerror(ret, ®, ebuf, sizeof(ebuf)); + ebuf[sizeof(ebuf)-1] = '\0'; + error("regerror: %s", ebuf); + continue; + } + ret = regexec(®, version, 0, NULL, 0); + regfree(®); + if (ret == 0) { + debug("match: %s pat %s\n", version, check[i].pat); datafellows = check[i].bugs; return; } } + debug("no match: %s", version); } #define SEP "," diff --git a/crypto/openssh/compat.h b/crypto/openssh/compat.h index 5be188b..f14efaf 100644 --- a/crypto/openssh/compat.h +++ b/crypto/openssh/compat.h @@ -21,7 +21,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("$OpenBSD: compat.h,v 1.10 2000/09/07 20:27:50 deraadt Exp $"); */ +/* RCSID("$OpenBSD: compat.h,v 1.11 2000/10/14 12:16:56 markus Exp $"); */ #ifndef COMPAT_H #define COMPAT_H @@ -35,7 +35,7 @@ #define SSH_BUG_PUBKEYAUTH 0x02 #define SSH_BUG_HMAC 0x04 #define SSH_BUG_X11FWD 0x08 -#define SSH_COMPAT_SESSIONID_ENCODING 0x10 +#define SSH_OLD_SESSIONID 0x10 void enable_compat13(void); void enable_compat20(void); diff --git a/crypto/openssh/deattack.c b/crypto/openssh/deattack.c index 74a46c0..df1d224 100644 --- a/crypto/openssh/deattack.c +++ b/crypto/openssh/deattack.c @@ -1,4 +1,4 @@ -/* $OpenBSD: deattack.c,v 1.9 2000/09/07 20:27:51 deraadt Exp $ */ +/* $OpenBSD: deattack.c,v 1.10 2000/10/31 13:18:53 markus Exp $ */ /* * Cryptographic attack detector for ssh - source code @@ -85,7 +85,7 @@ int detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV) { static u_int16_t *h = (u_int16_t *) NULL; - static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE; + static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE; register u_int32_t i, j; u_int32_t l; register unsigned char *c; diff --git a/crypto/openssh/dh.c b/crypto/openssh/dh.c new file mode 100644 index 0000000..ff84619 --- /dev/null +++ b/crypto/openssh/dh.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $"); + +#include "xmalloc.h" + +#include <openssl/bn.h> +#include <openssl/dh.h> +#include <openssl/evp.h> + +#include "ssh.h" +#include "buffer.h" +#include "kex.h" +#include "dh.h" + +int +parse_prime(int linenum, char *line, struct dhgroup *dhg) +{ + char *cp, *arg; + char *strsize, *gen, *prime; + + cp = line; + arg = strdelim(&cp); + /* Ignore leading whitespace */ + if (*arg == '\0') + arg = strdelim(&cp); + if (!*arg || *arg == '#') + return 0; + + /* time */ + if (cp == NULL || *arg == '\0') + goto fail; + arg = strsep(&cp, " "); /* type */ + if (cp == NULL || *arg == '\0') + goto fail; + arg = strsep(&cp, " "); /* tests */ + if (cp == NULL || *arg == '\0') + goto fail; + arg = strsep(&cp, " "); /* tries */ + if (cp == NULL || *arg == '\0') + goto fail; + strsize = strsep(&cp, " "); /* size */ + if (cp == NULL || *strsize == '\0' || + (dhg->size = atoi(strsize)) == 0) + goto fail; + gen = strsep(&cp, " "); /* gen */ + if (cp == NULL || *gen == '\0') + goto fail; + prime = strsep(&cp, " "); /* prime */ + if (cp != NULL || *prime == '\0') + goto fail; + + dhg->g = BN_new(); + if (BN_hex2bn(&dhg->g, gen) < 0) { + BN_free(dhg->g); + goto fail; + } + dhg->p = BN_new(); + if (BN_hex2bn(&dhg->p, prime) < 0) { + BN_free(dhg->g); + BN_free(dhg->p); + goto fail; + } + + return (1); + fail: + fprintf(stderr, "Bad prime description in line %d\n", linenum); + return (0); +} + +DH * +choose_dh(int minbits) +{ + FILE *f; + char line[1024]; + int best, bestcount, which; + int linenum; + struct dhgroup dhg; + + f = fopen(DH_PRIMES, "r"); + if (!f) { + perror(DH_PRIMES); + log("WARNING: %s does not exist, using old prime", DH_PRIMES); + return (dh_new_group1()); + } + + linenum = 0; + best = bestcount = 0; + while (fgets(line, sizeof(line), f)) { + linenum++; + if (!parse_prime(linenum, line, &dhg)) + continue; + BN_free(dhg.g); + BN_free(dhg.p); + + if ((dhg.size > minbits && dhg.size < best) || + (dhg.size > best && best < minbits)) { + best = dhg.size; + bestcount = 0; + } + if (dhg.size == best) + bestcount++; + } + fclose (f); + + if (bestcount == 0) { + log("WARNING: no primes in %s, using old prime", DH_PRIMES); + return (dh_new_group1()); + } + + f = fopen(DH_PRIMES, "r"); + if (!f) { + perror(DH_PRIMES); + exit(1); + } + + linenum = 0; + which = arc4random() % bestcount; + while (fgets(line, sizeof(line), f)) { + if (!parse_prime(linenum, line, &dhg)) + continue; + if (dhg.size != best) + continue; + if (linenum++ != which) { + BN_free(dhg.g); + BN_free(dhg.p); + continue; + } + break; + } + fclose(f); + + return (dh_new_group(dhg.g, dhg.p)); +} diff --git a/crypto/openssh/dh.h b/crypto/openssh/dh.h new file mode 100644 index 0000000..09b11fd --- /dev/null +++ b/crypto/openssh/dh.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef DH_H +#define DH_H + +struct dhgroup { + int size; + BIGNUM *g; + BIGNUM *p; +}; + +DH *choose_dh(int minbits); + +#endif diff --git a/crypto/openssh/dispatch.c b/crypto/openssh/dispatch.c index 3daac20..db8951c 100644 --- a/crypto/openssh/dispatch.c +++ b/crypto/openssh/dispatch.c @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: dispatch.c,v 1.4 2000/09/07 20:27:51 deraadt Exp $"); +RCSID("$OpenBSD: dispatch.c,v 1.5 2000/09/21 11:25:34 markus Exp $"); #include "ssh.h" #include "dispatch.h" #include "packet.h" @@ -33,7 +33,7 @@ RCSID("$OpenBSD: dispatch.c,v 1.4 2000/09/07 20:27:51 deraadt Exp $"); dispatch_fn *dispatch[DISPATCH_MAX]; void -dispatch_protocol_error(int type, int plen) +dispatch_protocol_error(int type, int plen, void *ctxt) { error("Hm, dispatch protocol error: type %d plen %d", type, plen); } @@ -50,7 +50,7 @@ dispatch_set(int type, dispatch_fn *fn) dispatch[type] = fn; } void -dispatch_run(int mode, int *done) +dispatch_run(int mode, int *done, void *ctxt) { for (;;) { int plen; @@ -64,7 +64,7 @@ dispatch_run(int mode, int *done) return; } if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL) - (*dispatch[type])(type, plen); + (*dispatch[type])(type, plen, ctxt); else packet_disconnect("protocol error: rcvd type %d", type); if (done != NULL && *done) diff --git a/crypto/openssh/dispatch.h b/crypto/openssh/dispatch.h index dc9d3dd..e60174c 100644 --- a/crypto/openssh/dispatch.h +++ b/crypto/openssh/dispatch.h @@ -26,9 +26,9 @@ enum { DISPATCH_NONBLOCK }; -typedef void dispatch_fn(int type, int plen); +typedef void dispatch_fn(int type, int plen, void *ctxt); void dispatch_init(dispatch_fn *dflt); void dispatch_set(int type, dispatch_fn *fn); -void dispatch_run(int mode, int *done); -void dispatch_protocol_error(int type, int plen); +void dispatch_run(int mode, int *done, void *ctxt); +void dispatch_protocol_error(int type, int plen, void *ctxt); diff --git a/crypto/openssh/kex.c b/crypto/openssh/kex.c index 8a83db4..68b9e52 100644 --- a/crypto/openssh/kex.c +++ b/crypto/openssh/kex.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.10 2000/09/07 20:27:51 deraadt Exp $"); +RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $"); #include "ssh.h" #include "ssh2.h" @@ -31,7 +31,6 @@ RCSID("$OpenBSD: kex.c,v 1.10 2000/09/07 20:27:51 deraadt Exp $"); #include "buffer.h" #include "bufaux.h" #include "packet.h" -#include "cipher.h" #include "compat.h" #include <openssl/bn.h> @@ -123,11 +122,6 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) int n = BN_num_bits(dh_pub); int bits_set = 0; - /* we only accept g==2 */ - if (!BN_is_word(dh->g, 2)) { - log("invalid DH base != 2"); - return 0; - } if (dh_pub->neg) { log("invalid public DH value: negativ"); return 0; @@ -145,27 +139,10 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) } DH * -dh_new_group1() +dh_gen_key(DH *dh) { - static char *group1 = - "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" - "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" - "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" - "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" - "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" - "FFFFFFFF" "FFFFFFFF"; - DH *dh; - int ret, tries = 0; - dh = DH_new(); - if(dh == NULL) - fatal("DH_new"); - ret = BN_hex2bn(&dh->p, group1); - if(ret<0) - fatal("BN_hex2bn"); - dh->g = BN_new(); - if(dh->g == NULL) - fatal("DH_new g"); - BN_set_word(dh->g, 2); + int tries = 0; + do { if (DH_generate_key(dh) == 0) fatal("DH_generate_key"); @@ -175,6 +152,52 @@ dh_new_group1() return dh; } +DH * +dh_new_group_asc(const char *gen, const char *modulus) +{ + DH *dh; + int ret; + + dh = DH_new(); + if (dh == NULL) + fatal("DH_new"); + + if ((ret = BN_hex2bn(&dh->p, modulus)) < 0) + fatal("BN_hex2bn p"); + if ((ret = BN_hex2bn(&dh->g, gen)) < 0) + fatal("BN_hex2bn g"); + + return (dh_gen_key(dh)); +} + +DH * +dh_new_group(BIGNUM *gen, BIGNUM *modulus) +{ + DH *dh; + + dh = DH_new(); + if (dh == NULL) + fatal("DH_new"); + dh->p = modulus; + dh->g = gen; + + return (dh_gen_key(dh)); +} + +DH * +dh_new_group1() +{ + static char *gen = "2", *group1 = + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" + "FFFFFFFF" "FFFFFFFF"; + + return (dh_new_group_asc(gen, group1)); +} + void dump_digest(unsigned char *digest, int len) { @@ -237,6 +260,59 @@ kex_hash( } unsigned char * +kex_hash_gex( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + char *serverhostkeyblob, int sbloblen, + int minbits, BIGNUM *prime, BIGNUM *gen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret) +{ + Buffer b; + static unsigned char digest[EVP_MAX_MD_SIZE]; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + + buffer_init(&b); + buffer_put_string(&b, client_version_string, strlen(client_version_string)); + buffer_put_string(&b, server_version_string, strlen(server_version_string)); + + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); + + buffer_put_string(&b, serverhostkeyblob, sbloblen); + buffer_put_int(&b, minbits); + buffer_put_bignum2(&b, prime); + buffer_put_bignum2(&b, gen); + buffer_put_bignum2(&b, client_dh_pub); + buffer_put_bignum2(&b, server_dh_pub); + buffer_put_bignum2(&b, shared_secret); + +#ifdef DEBUG_KEX + buffer_dump(&b); +#endif + + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEX + dump_digest(digest, evp_md->md_size); +#endif + return digest; +} + +unsigned char * derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret) { Buffer b; @@ -318,28 +394,9 @@ choose_enc(Enc *enc, char *client, char *server) char *name = get_match(client, server); if (name == NULL) fatal("no matching cipher found: client %s server %s", client, server); - enc->type = cipher_number(name); - - switch (enc->type) { - case SSH_CIPHER_3DES_CBC: - enc->key_len = 24; - enc->iv_len = 8; - enc->block_size = 8; - break; - case SSH_CIPHER_BLOWFISH_CBC: - case SSH_CIPHER_CAST128_CBC: - enc->key_len = 16; - enc->iv_len = 8; - enc->block_size = 8; - break; - case SSH_CIPHER_ARCFOUR: - enc->key_len = 16; - enc->iv_len = 0; - enc->block_size = 8; - break; - default: - fatal("unsupported cipher %s", name); - } + enc->cipher = cipher_by_name(name); + if (enc->cipher == NULL) + fatal("matching cipher is not supported: %s", name); enc->name = name; enc->enabled = 0; enc->iv = NULL; @@ -387,7 +444,11 @@ choose_kex(Kex *k, char *client, char *server) k->name = get_match(client, server); if (k->name == NULL) fatal("no kex alg"); - if (strcmp(k->name, KEX_DH1) != 0) + if (strcmp(k->name, KEX_DH1) == 0) { + k->kex_type = DH_GRP1_SHA1; + } else if (strcmp(k->name, KEX_DHGEX) == 0) { + k->kex_type = DH_GEX_SHA1; + } else fatal("bad kex alg %s", k->name); } void @@ -432,10 +493,10 @@ kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); need = 0; for (mode = 0; mode < MODE_MAX; mode++) { - if (need < k->enc[mode].key_len) - need = k->enc[mode].key_len; - if (need < k->enc[mode].iv_len) - need = k->enc[mode].iv_len; + if (need < k->enc[mode].cipher->key_len) + need = k->enc[mode].cipher->key_len; + if (need < k->enc[mode].cipher->block_size) + need = k->enc[mode].cipher->block_size; if (need < k->mac[mode].key_len) need = k->mac[mode].key_len; } diff --git a/crypto/openssh/kex.h b/crypto/openssh/kex.h index 8c89687..2129581 100644 --- a/crypto/openssh/kex.h +++ b/crypto/openssh/kex.h @@ -24,8 +24,9 @@ #ifndef KEX_H #define KEX_H -#define KEX_DH1 "diffie-hellman-group1-sha1" -#define KEX_DSS "ssh-dss" +#define KEX_DH1 "diffie-hellman-group1-sha1" +#define KEX_DHGEX "diffie-hellman-group-exchange-sha1" +#define KEX_DSS "ssh-dss" enum kex_init_proposals { PROPOSAL_KEX_ALGS, @@ -47,28 +48,30 @@ enum kex_modes { MODE_MAX }; +enum kex_exchange { + DH_GRP1_SHA1, + DH_GEX_SHA1 +}; + typedef struct Kex Kex; typedef struct Mac Mac; typedef struct Comp Comp; typedef struct Enc Enc; struct Enc { - int type; + char *name; + Cipher *cipher; int enabled; - int block_size; unsigned char *key; unsigned char *iv; - int key_len; - int iv_len; - char *name; }; struct Mac { - EVP_MD *md; + char *name; int enabled; + EVP_MD *md; int mac_len; unsigned char *key; int key_len; - char *name; }; struct Comp { int type; @@ -83,6 +86,7 @@ struct Kex { int server; char *name; char *hostkeyalg; + int kex_type; }; Buffer *kex_init(char *myproposal[PROPOSAL_MAX]); @@ -96,6 +100,8 @@ kex_choose_conf(char *cprop[PROPOSAL_MAX], int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret); void packet_set_kex(Kex *k); int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub); +DH *dh_new_group_asc(const char *, const char *); +DH *dh_new_group(BIGNUM *, BIGNUM *); DH *dh_new_group1(); unsigned char * @@ -109,4 +115,15 @@ kex_hash( BIGNUM *server_dh_pub, BIGNUM *shared_secret); +unsigned char * +kex_hash_gex( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + char *serverhostkeyblob, int sbloblen, + int minbits, BIGNUM *prime, BIGNUM *gen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret); #endif diff --git a/crypto/openssh/lib/Makefile b/crypto/openssh/lib/Makefile index 4bbe222..396186b 100644 --- a/crypto/openssh/lib/Makefile +++ b/crypto/openssh/lib/Makefile @@ -5,7 +5,8 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \ cipher.c compat.c compress.c crc32.c deattack.c \ hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \ rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \ - key.c dispatch.c dsa.c kex.c hmac.c uuencode.c util.c + key.c dispatch.c dsa.c kex.c hmac.c uuencode.c util.c \ + cli.c rijndael.c NOPROFILE= yes NOPIC= yes diff --git a/crypto/openssh/log-client.c b/crypto/openssh/log-client.c index 616d3d0..505c8c3 100644 --- a/crypto/openssh/log-client.c +++ b/crypto/openssh/log-client.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: log-client.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $"); +RCSID("$OpenBSD: log-client.c,v 1.12 2000/09/12 20:53:10 markus Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -57,7 +57,9 @@ log_init(char *av0, LogLevel level, SyslogFacility ignored1, int ignored2) case SYSLOG_LEVEL_FATAL: case SYSLOG_LEVEL_INFO: case SYSLOG_LEVEL_VERBOSE: - case SYSLOG_LEVEL_DEBUG: + case SYSLOG_LEVEL_DEBUG1: + case SYSLOG_LEVEL_DEBUG2: + case SYSLOG_LEVEL_DEBUG3: log_level = level; break; default: @@ -75,7 +77,7 @@ do_log(LogLevel level, const char *fmt, va_list args) if (level > log_level) return; - if (level == SYSLOG_LEVEL_DEBUG) + if (level >= SYSLOG_LEVEL_DEBUG1) fprintf(stderr, "debug: "); vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); fprintf(stderr, "%s\r\n", msgbuf); diff --git a/crypto/openssh/log-server.c b/crypto/openssh/log-server.c index 11d650b..de3d5cf 100644 --- a/crypto/openssh/log-server.c +++ b/crypto/openssh/log-server.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: log-server.c,v 1.16 2000/09/07 20:27:52 deraadt Exp $"); +RCSID("$OpenBSD: log-server.c,v 1.17 2000/09/12 20:53:10 markus Exp $"); #include <syslog.h> #include "packet.h" @@ -62,7 +62,9 @@ log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) case SYSLOG_LEVEL_FATAL: case SYSLOG_LEVEL_INFO: case SYSLOG_LEVEL_VERBOSE: - case SYSLOG_LEVEL_DEBUG: + case SYSLOG_LEVEL_DEBUG1: + case SYSLOG_LEVEL_DEBUG2: + case SYSLOG_LEVEL_DEBUG3: log_level = level; break; default: @@ -138,8 +140,16 @@ do_log(LogLevel level, const char *fmt, va_list args) case SYSLOG_LEVEL_VERBOSE: pri = LOG_INFO; break; - case SYSLOG_LEVEL_DEBUG: - txt = "debug"; + case SYSLOG_LEVEL_DEBUG1: + txt = "debug1"; + pri = LOG_DEBUG; + break; + case SYSLOG_LEVEL_DEBUG2: + txt = "debug2"; + pri = LOG_DEBUG; + break; + case SYSLOG_LEVEL_DEBUG3: + txt = "debug3"; pri = LOG_DEBUG; break; default: diff --git a/crypto/openssh/log.c b/crypto/openssh/log.c index a6d9e05..ce89c59 100644 --- a/crypto/openssh/log.c +++ b/crypto/openssh/log.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: log.c,v 1.9 2000/09/07 21:13:37 markus Exp $"); +RCSID("$OpenBSD: log.c,v 1.11 2000/09/30 16:27:43 markus Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -93,7 +93,25 @@ debug(const char *fmt,...) { va_list args; va_start(args, fmt); - do_log(SYSLOG_LEVEL_DEBUG, fmt, args); + do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); + va_end(args); +} + +void +debug2(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); + va_end(args); +} + +void +debug3(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); va_end(args); } @@ -190,7 +208,10 @@ static struct { { "ERROR", SYSLOG_LEVEL_ERROR }, { "INFO", SYSLOG_LEVEL_INFO }, { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, - { "DEBUG", SYSLOG_LEVEL_DEBUG }, + { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, + { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, + { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, + { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, { NULL, 0 } }; diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h index 18db954..98060dc 100644 --- a/crypto/openssh/myproposal.h +++ b/crypto/openssh/myproposal.h @@ -21,11 +21,15 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define KEX_DEFAULT_KEX "diffie-hellman-group1-sha1" +#define KEX_DEFAULT_KEX "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1" #define KEX_DEFAULT_PK_ALG "ssh-dss" -#define KEX_DEFAULT_ENCRYPT "3des-cbc,blowfish-cbc,arcfour,cast128-cbc" +#define KEX_DEFAULT_ENCRYPT \ + "3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \ + "aes128-cbc,aes192-cbc,aes256-cbc," \ + "rijndael128-cbc,rijndael192-cbc,rijndael256-cbc," \ + "rijndael-cbc@lysator.liu.se" #define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com" -#define KEX_DEFAULT_COMP "zlib,none" +#define KEX_DEFAULT_COMP "none,zlib" #define KEX_DEFAULT_LANG "" diff --git a/crypto/openssh/packet.c b/crypto/openssh/packet.c index 670c0ed..3216fda 100644 --- a/crypto/openssh/packet.c +++ b/crypto/openssh/packet.c @@ -37,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: packet.c,v 1.35 2000/09/07 20:27:52 deraadt Exp $"); +RCSID("$OpenBSD: packet.c,v 1.38 2000/10/12 14:21:12 markus Exp $"); #include "xmalloc.h" #include "buffer.h" @@ -45,7 +45,6 @@ RCSID("$OpenBSD: packet.c,v 1.35 2000/09/07 20:27:52 deraadt Exp $"); #include "bufaux.h" #include "ssh.h" #include "crc32.h" -#include "cipher.h" #include "getput.h" #include "compress.h" @@ -59,6 +58,7 @@ RCSID("$OpenBSD: packet.c,v 1.35 2000/09/07 20:27:52 deraadt Exp $"); #include <openssl/dh.h> #include <openssl/hmac.h> #include "buffer.h" +#include "cipher.h" #include "kex.h" #include "hmac.h" @@ -161,11 +161,14 @@ packet_set_ssh2_format(void) void packet_set_connection(int fd_in, int fd_out) { + Cipher *none = cipher_by_name("none"); + if (none == NULL) + fatal("packet_set_connection: cannot load cipher 'none'"); connection_in = fd_in; connection_out = fd_out; cipher_type = SSH_CIPHER_NONE; - cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0); - cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0); + cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0); + cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0); if (!initialized) { initialized = 1; buffer_init(&input); @@ -326,28 +329,18 @@ packet_encrypt(CipherContext * cc, void *dest, void *src, */ void -packet_decrypt(CipherContext * cc, void *dest, void *src, - unsigned int bytes) +packet_decrypt(CipherContext *context, void *dest, void *src, unsigned int bytes) { - int i; - - if ((bytes % 8) != 0) - fatal("packet_decrypt: bad ciphertext length %d", bytes); - /* * Cryptographic attack detector for ssh - Modifications for packet.c * (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com) */ - - if (cc->type == SSH_CIPHER_NONE || compat20) { - i = DEATTACK_OK; - } else { - i = detect_attack(src, bytes, NULL); - } - if (i == DEATTACK_DETECTED) + if (!compat20 && + context->cipher->number != SSH_CIPHER_NONE && + detect_attack(src, bytes, NULL) == DEATTACK_DETECTED) packet_disconnect("crc32 compensation attack: network attack detected"); - cipher_decrypt(cc, dest, src, bytes); + cipher_decrypt(context, dest, src, bytes); } /* @@ -358,14 +351,15 @@ packet_decrypt(CipherContext * cc, void *dest, void *src, void packet_set_encryption_key(const unsigned char *key, unsigned int keylen, - int cipher) + int number) { + Cipher *cipher = cipher_by_number(number); + if (cipher == NULL) + fatal("packet_set_encryption_key: unknown cipher number %d", number); if (keylen < 20) - fatal("keylen too small: %d", keylen); - - /* All other ciphers use the same key in both directions for now. */ - cipher_set_key(&receive_context, cipher, key, keylen); - cipher_set_key(&send_context, cipher, key, keylen); + fatal("packet_set_encryption_key: keylen too small: %d", keylen); + cipher_init(&receive_context, cipher, key, keylen, NULL, 0); + cipher_init(&send_context, cipher, key, keylen, NULL, 0); } /* Starts constructing a packet to send. */ @@ -553,7 +547,7 @@ packet_send2() mac = &kex->mac[MODE_OUT]; comp = &kex->comp[MODE_OUT]; } - block_size = enc ? enc->block_size : 8; + block_size = enc ? enc->cipher->block_size : 8; cp = buffer_ptr(&outgoing_packet); type = cp[5] & 0xff; @@ -588,7 +582,7 @@ packet_send2() if (padlen < 4) padlen += block_size; buffer_append_space(&outgoing_packet, &cp, padlen); - if (enc && enc->type != SSH_CIPHER_NONE) { + if (enc && enc->cipher->number != SSH_CIPHER_NONE) { /* random padding */ for (i = 0; i < padlen; i++) { if (i % 4 == 0) @@ -614,7 +608,7 @@ packet_send2() buffer_len(&outgoing_packet), mac->key, mac->key_len ); - DBG(debug("done calc HMAC out #%d", seqnr)); + DBG(debug("done calc MAC out #%d", seqnr)); } /* encrypt packet and append to output buffer. */ buffer_append_space(&output, &cp, buffer_len(&outgoing_packet)); @@ -637,10 +631,10 @@ packet_send2() fatal("packet_send2: no KEX"); if (mac->md != NULL) mac->enabled = 1; - DBG(debug("cipher_set_key_iv send_context")); - cipher_set_key_iv(&send_context, enc->type, - enc->key, enc->key_len, - enc->iv, enc->iv_len); + DBG(debug("cipher_init send_context")); + cipher_init(&send_context, enc->cipher, + enc->key, enc->cipher->key_len, + enc->iv, enc->cipher->block_size); clear_enc_keys(enc, kex->we_need); if (comp->type != 0 && comp->enabled == 0) { comp->enabled = 1; @@ -841,7 +835,7 @@ packet_read_poll2(int *payload_len_ptr) comp = &kex->comp[MODE_IN]; } maclen = mac && mac->enabled ? mac->mac_len : 0; - block_size = enc ? enc->block_size : 8; + block_size = enc ? enc->cipher->block_size : 8; if (packet_length == 0) { /* @@ -894,8 +888,8 @@ packet_read_poll2(int *payload_len_ptr) mac->key, mac->key_len ); if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) - packet_disconnect("Corrupted HMAC on input."); - DBG(debug("HMAC #%d ok", seqnr)); + packet_disconnect("Corrupted MAC on input."); + DBG(debug("MAC #%d ok", seqnr)); buffer_consume(&input, mac->mac_len); } if (++seqnr == 0) @@ -939,10 +933,10 @@ packet_read_poll2(int *payload_len_ptr) fatal("packet_read_poll2: no KEX"); if (mac->md != NULL) mac->enabled = 1; - DBG(debug("cipher_set_key_iv receive_context")); - cipher_set_key_iv(&receive_context, enc->type, - enc->key, enc->key_len, - enc->iv, enc->iv_len); + DBG(debug("cipher_init receive_context")); + cipher_init(&receive_context, enc->cipher, + enc->key, enc->cipher->key_len, + enc->iv, enc->cipher->block_size); clear_enc_keys(enc, kex->we_need); if (comp->type != 0 && comp->enabled == 0) { comp->enabled = 1; diff --git a/crypto/openssh/readpass.c b/crypto/openssh/readpass.c index c38292f..f3a7dcb 100644 --- a/crypto/openssh/readpass.c +++ b/crypto/openssh/readpass.c @@ -32,88 +32,24 @@ */ #include "includes.h" -RCSID("$OpenBSD: readpass.c,v 1.11 2000/06/20 01:39:44 markus Exp $"); +RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $"); #include "xmalloc.h" #include "ssh.h" - -volatile int intr; - -void -intcatch() -{ - intr = 1; -} +#include "cli.h" /* * Reads a passphrase from /dev/tty with echo turned off. Returns the * passphrase (allocated with xmalloc), being very careful to ensure that * no other userland buffer is storing the password. */ +/* + * Note: the funcationallity of this routing has been moved to + * cli_read_passphrase(). This routing remains to maintain + * compatibility with existing code. + */ char * -read_passphrase(const char *prompt, int from_stdin) +read_passphrase(char *prompt, int from_stdin) { - char buf[1024], *p, ch; - struct termios tio, saved_tio; - sigset_t oset, nset; - struct sigaction sa, osa; - int input, output, echo = 0; - - if (from_stdin) { - input = STDIN_FILENO; - output = STDERR_FILENO; - } else - input = output = open("/dev/tty", O_RDWR); - - if (input == -1) - fatal("You have no controlling tty. Cannot read passphrase.\n"); - - /* block signals, get terminal modes and turn off echo */ - sigemptyset(&nset); - sigaddset(&nset, SIGTSTP); - (void) sigprocmask(SIG_BLOCK, &nset, &oset); - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = intcatch; - (void) sigaction(SIGINT, &sa, &osa); - - intr = 0; - - if (tcgetattr(input, &saved_tio) == 0 && (saved_tio.c_lflag & ECHO)) { - echo = 1; - tio = saved_tio; - tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); - (void) tcsetattr(input, TCSANOW, &tio); - } - - fflush(stdout); - - (void)write(output, prompt, strlen(prompt)); - for (p = buf; read(input, &ch, 1) == 1 && ch != '\n';) { - if (intr) - break; - if (p < buf + sizeof(buf) - 1) - *p++ = ch; - } - *p = '\0'; - if (!intr) - (void)write(output, "\n", 1); - - /* restore terminal modes and allow signals */ - if (echo) - tcsetattr(input, TCSANOW, &saved_tio); - (void) sigprocmask(SIG_SETMASK, &oset, NULL); - (void) sigaction(SIGINT, &osa, NULL); - - if (intr) { - kill(getpid(), SIGINT); - sigemptyset(&nset); - /* XXX tty has not neccessarily drained by now? */ - sigsuspend(&nset); - } - - if (!from_stdin) - (void)close(input); - p = xstrdup(buf); - memset(buf, 0, sizeof(buf)); - return (p); + return cli_read_passphrase(prompt, from_stdin, 0); } diff --git a/crypto/openssh/rijndael.c b/crypto/openssh/rijndael.c new file mode 100644 index 0000000..0eb313d --- /dev/null +++ b/crypto/openssh/rijndael.c @@ -0,0 +1,493 @@ +/* $OpenBSD: rijndael.c,v 1.2 2000/10/15 14:14:01 markus Exp $ */ + +/* This is an independent implementation of the encryption algorithm: */ +/* */ +/* RIJNDAEL by Joan Daemen and Vincent Rijmen */ +/* */ +/* which is a candidate algorithm in the Advanced Encryption Standard */ +/* programme of the US National Institute of Standards and Technology. */ +/* */ +/* Copyright in this implementation is held by Dr B R Gladman but I */ +/* hereby give permission for its free direct or derivative use subject */ +/* to acknowledgment of its origin and compliance with any conditions */ +/* that the originators of the algorithm place on its exploitation. */ +/* */ +/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */ + +/* Timing data for Rijndael (rijndael.c) + +Algorithm: rijndael (rijndael.c) + +128 bit key: +Key Setup: 305/1389 cycles (encrypt/decrypt) +Encrypt: 374 cycles = 68.4 mbits/sec +Decrypt: 352 cycles = 72.7 mbits/sec +Mean: 363 cycles = 70.5 mbits/sec + +192 bit key: +Key Setup: 277/1595 cycles (encrypt/decrypt) +Encrypt: 439 cycles = 58.3 mbits/sec +Decrypt: 425 cycles = 60.2 mbits/sec +Mean: 432 cycles = 59.3 mbits/sec + +256 bit key: +Key Setup: 374/1960 cycles (encrypt/decrypt) +Encrypt: 502 cycles = 51.0 mbits/sec +Decrypt: 498 cycles = 51.4 mbits/sec +Mean: 500 cycles = 51.2 mbits/sec + +*/ + +#include <sys/types.h> +#include "rijndael.h" + +void gen_tabs __P((void)); + +/* 3. Basic macros for speeding up generic operations */ + +/* Circular rotate of 32 bit values */ + +#define rotr(x,n) (((x) >> ((int)(n))) | ((x) << (32 - (int)(n)))) +#define rotl(x,n) (((x) << ((int)(n))) | ((x) >> (32 - (int)(n)))) + +/* Invert byte order in a 32 bit variable */ + +#define bswap(x) (rotl(x, 8) & 0x00ff00ff | rotr(x, 8) & 0xff00ff00) + +/* Extract byte from a 32 bit quantity (little endian notation) */ + +#define byte(x,n) ((u1byte)((x) >> (8 * n))) + +#if BYTE_ORDER != LITTLE_ENDIAN +#define BLOCK_SWAP +#endif + +/* For inverting byte order in input/output 32 bit words if needed */ + +#ifdef BLOCK_SWAP +#define BYTE_SWAP +#define WORD_SWAP +#endif + +#ifdef BYTE_SWAP +#define io_swap(x) bswap(x) +#else +#define io_swap(x) (x) +#endif + +/* For inverting the byte order of input/output blocks if needed */ + +#ifdef WORD_SWAP + +#define get_block(x) \ + ((u4byte*)(x))[0] = io_swap(in_blk[3]); \ + ((u4byte*)(x))[1] = io_swap(in_blk[2]); \ + ((u4byte*)(x))[2] = io_swap(in_blk[1]); \ + ((u4byte*)(x))[3] = io_swap(in_blk[0]) + +#define put_block(x) \ + out_blk[3] = io_swap(((u4byte*)(x))[0]); \ + out_blk[2] = io_swap(((u4byte*)(x))[1]); \ + out_blk[1] = io_swap(((u4byte*)(x))[2]); \ + out_blk[0] = io_swap(((u4byte*)(x))[3]) + +#define get_key(x,len) \ + ((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \ + ((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \ + switch((((len) + 63) / 64)) { \ + case 2: \ + ((u4byte*)(x))[0] = io_swap(in_key[3]); \ + ((u4byte*)(x))[1] = io_swap(in_key[2]); \ + ((u4byte*)(x))[2] = io_swap(in_key[1]); \ + ((u4byte*)(x))[3] = io_swap(in_key[0]); \ + break; \ + case 3: \ + ((u4byte*)(x))[0] = io_swap(in_key[5]); \ + ((u4byte*)(x))[1] = io_swap(in_key[4]); \ + ((u4byte*)(x))[2] = io_swap(in_key[3]); \ + ((u4byte*)(x))[3] = io_swap(in_key[2]); \ + ((u4byte*)(x))[4] = io_swap(in_key[1]); \ + ((u4byte*)(x))[5] = io_swap(in_key[0]); \ + break; \ + case 4: \ + ((u4byte*)(x))[0] = io_swap(in_key[7]); \ + ((u4byte*)(x))[1] = io_swap(in_key[6]); \ + ((u4byte*)(x))[2] = io_swap(in_key[5]); \ + ((u4byte*)(x))[3] = io_swap(in_key[4]); \ + ((u4byte*)(x))[4] = io_swap(in_key[3]); \ + ((u4byte*)(x))[5] = io_swap(in_key[2]); \ + ((u4byte*)(x))[6] = io_swap(in_key[1]); \ + ((u4byte*)(x))[7] = io_swap(in_key[0]); \ + } + +#else + +#define get_block(x) \ + ((u4byte*)(x))[0] = io_swap(in_blk[0]); \ + ((u4byte*)(x))[1] = io_swap(in_blk[1]); \ + ((u4byte*)(x))[2] = io_swap(in_blk[2]); \ + ((u4byte*)(x))[3] = io_swap(in_blk[3]) + +#define put_block(x) \ + out_blk[0] = io_swap(((u4byte*)(x))[0]); \ + out_blk[1] = io_swap(((u4byte*)(x))[1]); \ + out_blk[2] = io_swap(((u4byte*)(x))[2]); \ + out_blk[3] = io_swap(((u4byte*)(x))[3]) + +#define get_key(x,len) \ + ((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \ + ((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \ + switch((((len) + 63) / 64)) { \ + case 4: \ + ((u4byte*)(x))[6] = io_swap(in_key[6]); \ + ((u4byte*)(x))[7] = io_swap(in_key[7]); \ + case 3: \ + ((u4byte*)(x))[4] = io_swap(in_key[4]); \ + ((u4byte*)(x))[5] = io_swap(in_key[5]); \ + case 2: \ + ((u4byte*)(x))[0] = io_swap(in_key[0]); \ + ((u4byte*)(x))[1] = io_swap(in_key[1]); \ + ((u4byte*)(x))[2] = io_swap(in_key[2]); \ + ((u4byte*)(x))[3] = io_swap(in_key[3]); \ + } + +#endif + +#define LARGE_TABLES + +u1byte pow_tab[256]; +u1byte log_tab[256]; +u1byte sbx_tab[256]; +u1byte isb_tab[256]; +u4byte rco_tab[ 10]; +u4byte ft_tab[4][256]; +u4byte it_tab[4][256]; + +#ifdef LARGE_TABLES + u4byte fl_tab[4][256]; + u4byte il_tab[4][256]; +#endif + +u4byte tab_gen = 0; + +#define ff_mult(a,b) (a && b ? pow_tab[(log_tab[a] + log_tab[b]) % 255] : 0) + +#define f_rn(bo, bi, n, k) \ + bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ + ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rn(bo, bi, n, k) \ + bo[n] = it_tab[0][byte(bi[n],0)] ^ \ + it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#ifdef LARGE_TABLES + +#define ls_box(x) \ + ( fl_tab[0][byte(x, 0)] ^ \ + fl_tab[1][byte(x, 1)] ^ \ + fl_tab[2][byte(x, 2)] ^ \ + fl_tab[3][byte(x, 3)] ) + +#define f_rl(bo, bi, n, k) \ + bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ + fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rl(bo, bi, n, k) \ + bo[n] = il_tab[0][byte(bi[n],0)] ^ \ + il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#else + +#define ls_box(x) \ + ((u4byte)sbx_tab[byte(x, 0)] << 0) ^ \ + ((u4byte)sbx_tab[byte(x, 1)] << 8) ^ \ + ((u4byte)sbx_tab[byte(x, 2)] << 16) ^ \ + ((u4byte)sbx_tab[byte(x, 3)] << 24) + +#define f_rl(bo, bi, n, k) \ + bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \ + rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \ + rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \ + rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n) + +#define i_rl(bo, bi, n, k) \ + bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^ \ + rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \ + rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \ + rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n) + +#endif + +void +gen_tabs(void) +{ + u4byte i, t; + u1byte p, q; + + /* log and power tables for GF(2**8) finite field with */ + /* 0x11b as modular polynomial - the simplest prmitive */ + /* root is 0x11, used here to generate the tables */ + + for(i = 0,p = 1; i < 256; ++i) { + pow_tab[i] = (u1byte)p; log_tab[p] = (u1byte)i; + + p = p ^ (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + log_tab[1] = 0; p = 1; + + for(i = 0; i < 10; ++i) { + rco_tab[i] = p; + + p = (p << 1) ^ (p & 0x80 ? 0x1b : 0); + } + + /* note that the affine byte transformation matrix in */ + /* rijndael specification is in big endian format with */ + /* bit 0 as the most significant bit. In the remainder */ + /* of the specification the bits are numbered from the */ + /* least significant end of a byte. */ + + for(i = 0; i < 256; ++i) { + p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p; + q = (q >> 7) | (q << 1); p ^= q; + q = (q >> 7) | (q << 1); p ^= q; + q = (q >> 7) | (q << 1); p ^= q; + q = (q >> 7) | (q << 1); p ^= q ^ 0x63; + sbx_tab[i] = (u1byte)p; isb_tab[p] = (u1byte)i; + } + + for(i = 0; i < 256; ++i) { + p = sbx_tab[i]; + +#ifdef LARGE_TABLES + + t = p; fl_tab[0][i] = t; + fl_tab[1][i] = rotl(t, 8); + fl_tab[2][i] = rotl(t, 16); + fl_tab[3][i] = rotl(t, 24); +#endif + t = ((u4byte)ff_mult(2, p)) | + ((u4byte)p << 8) | + ((u4byte)p << 16) | + ((u4byte)ff_mult(3, p) << 24); + + ft_tab[0][i] = t; + ft_tab[1][i] = rotl(t, 8); + ft_tab[2][i] = rotl(t, 16); + ft_tab[3][i] = rotl(t, 24); + + p = isb_tab[i]; + +#ifdef LARGE_TABLES + + t = p; il_tab[0][i] = t; + il_tab[1][i] = rotl(t, 8); + il_tab[2][i] = rotl(t, 16); + il_tab[3][i] = rotl(t, 24); +#endif + t = ((u4byte)ff_mult(14, p)) | + ((u4byte)ff_mult( 9, p) << 8) | + ((u4byte)ff_mult(13, p) << 16) | + ((u4byte)ff_mult(11, p) << 24); + + it_tab[0][i] = t; + it_tab[1][i] = rotl(t, 8); + it_tab[2][i] = rotl(t, 16); + it_tab[3][i] = rotl(t, 24); + } + + tab_gen = 1; +} + +#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) + +#define imix_col(y,x) \ + u = star_x(x); \ + v = star_x(u); \ + w = star_x(v); \ + t = w ^ (x); \ + (y) = u ^ v ^ w; \ + (y) ^= rotr(u ^ t, 8) ^ \ + rotr(v ^ t, 16) ^ \ + rotr(t,24) + +/* initialise the key schedule from the user supplied key */ + +#define loop4(i) \ +{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \ + t ^= e_key[4 * i]; e_key[4 * i + 4] = t; \ + t ^= e_key[4 * i + 1]; e_key[4 * i + 5] = t; \ + t ^= e_key[4 * i + 2]; e_key[4 * i + 6] = t; \ + t ^= e_key[4 * i + 3]; e_key[4 * i + 7] = t; \ +} + +#define loop6(i) \ +{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \ + t ^= e_key[6 * i]; e_key[6 * i + 6] = t; \ + t ^= e_key[6 * i + 1]; e_key[6 * i + 7] = t; \ + t ^= e_key[6 * i + 2]; e_key[6 * i + 8] = t; \ + t ^= e_key[6 * i + 3]; e_key[6 * i + 9] = t; \ + t ^= e_key[6 * i + 4]; e_key[6 * i + 10] = t; \ + t ^= e_key[6 * i + 5]; e_key[6 * i + 11] = t; \ +} + +#define loop8(i) \ +{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \ + t ^= e_key[8 * i]; e_key[8 * i + 8] = t; \ + t ^= e_key[8 * i + 1]; e_key[8 * i + 9] = t; \ + t ^= e_key[8 * i + 2]; e_key[8 * i + 10] = t; \ + t ^= e_key[8 * i + 3]; e_key[8 * i + 11] = t; \ + t = e_key[8 * i + 4] ^ ls_box(t); \ + e_key[8 * i + 12] = t; \ + t ^= e_key[8 * i + 5]; e_key[8 * i + 13] = t; \ + t ^= e_key[8 * i + 6]; e_key[8 * i + 14] = t; \ + t ^= e_key[8 * i + 7]; e_key[8 * i + 15] = t; \ +} + +rijndael_ctx * +rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len, + int encrypt) +{ + u4byte i, t, u, v, w; + u4byte *e_key = ctx->e_key; + u4byte *d_key = ctx->d_key; + + ctx->decrypt = !encrypt; + + if(!tab_gen) + gen_tabs(); + + ctx->k_len = (key_len + 31) / 32; + + e_key[0] = in_key[0]; e_key[1] = in_key[1]; + e_key[2] = in_key[2]; e_key[3] = in_key[3]; + + switch(ctx->k_len) { + case 4: t = e_key[3]; + for(i = 0; i < 10; ++i) + loop4(i); + break; + + case 6: e_key[4] = in_key[4]; t = e_key[5] = in_key[5]; + for(i = 0; i < 8; ++i) + loop6(i); + break; + + case 8: e_key[4] = in_key[4]; e_key[5] = in_key[5]; + e_key[6] = in_key[6]; t = e_key[7] = in_key[7]; + for(i = 0; i < 7; ++i) + loop8(i); + break; + } + + if (!encrypt) { + d_key[0] = e_key[0]; d_key[1] = e_key[1]; + d_key[2] = e_key[2]; d_key[3] = e_key[3]; + + for(i = 4; i < 4 * ctx->k_len + 24; ++i) { + imix_col(d_key[i], e_key[i]); + } + } + + return ctx; +} + +/* encrypt a block of text */ + +#define f_nround(bo, bi, k) \ + f_rn(bo, bi, 0, k); \ + f_rn(bo, bi, 1, k); \ + f_rn(bo, bi, 2, k); \ + f_rn(bo, bi, 3, k); \ + k += 4 + +#define f_lround(bo, bi, k) \ + f_rl(bo, bi, 0, k); \ + f_rl(bo, bi, 1, k); \ + f_rl(bo, bi, 2, k); \ + f_rl(bo, bi, 3, k) + +void +rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk) +{ + u4byte k_len = ctx->k_len; + u4byte *e_key = ctx->e_key; + u4byte b0[4], b1[4], *kp; + + b0[0] = in_blk[0] ^ e_key[0]; b0[1] = in_blk[1] ^ e_key[1]; + b0[2] = in_blk[2] ^ e_key[2]; b0[3] = in_blk[3] ^ e_key[3]; + + kp = e_key + 4; + + if(k_len > 6) { + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + } + + if(k_len > 4) { + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + } + + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + f_nround(b1, b0, kp); f_lround(b0, b1, kp); + + out_blk[0] = b0[0]; out_blk[1] = b0[1]; + out_blk[2] = b0[2]; out_blk[3] = b0[3]; +} + +/* decrypt a block of text */ + +#define i_nround(bo, bi, k) \ + i_rn(bo, bi, 0, k); \ + i_rn(bo, bi, 1, k); \ + i_rn(bo, bi, 2, k); \ + i_rn(bo, bi, 3, k); \ + k -= 4 + +#define i_lround(bo, bi, k) \ + i_rl(bo, bi, 0, k); \ + i_rl(bo, bi, 1, k); \ + i_rl(bo, bi, 2, k); \ + i_rl(bo, bi, 3, k) + +void +rijndael_decrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk) +{ + u4byte b0[4], b1[4], *kp; + u4byte k_len = ctx->k_len; + u4byte *e_key = ctx->e_key; + u4byte *d_key = ctx->d_key; + + b0[0] = in_blk[0] ^ e_key[4 * k_len + 24]; b0[1] = in_blk[1] ^ e_key[4 * k_len + 25]; + b0[2] = in_blk[2] ^ e_key[4 * k_len + 26]; b0[3] = in_blk[3] ^ e_key[4 * k_len + 27]; + + kp = d_key + 4 * (k_len + 5); + + if(k_len > 6) { + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + } + + if(k_len > 4) { + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + } + + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + i_nround(b1, b0, kp); i_lround(b0, b1, kp); + + out_blk[0] = b0[0]; out_blk[1] = b0[1]; + out_blk[2] = b0[2]; out_blk[3] = b0[3]; +} diff --git a/crypto/openssh/rijndael.h b/crypto/openssh/rijndael.h new file mode 100644 index 0000000..c13f18c --- /dev/null +++ b/crypto/openssh/rijndael.h @@ -0,0 +1,31 @@ +#ifndef _RIJNDAEL_H_ +#define _RIJNDAEL_H_ + +/* 1. Standard types for AES cryptography source code */ + +typedef u_int8_t u1byte; /* an 8 bit unsigned character type */ +typedef u_int16_t u2byte; /* a 16 bit unsigned integer type */ +typedef u_int32_t u4byte; /* a 32 bit unsigned integer type */ + +typedef int8_t s1byte; /* an 8 bit signed character type */ +typedef int16_t s2byte; /* a 16 bit signed integer type */ +typedef int32_t s4byte; /* a 32 bit signed integer type */ + +typedef struct _rijndael_ctx { + u4byte k_len; + int decrypt; + u4byte e_key[64]; + u4byte d_key[64]; +} rijndael_ctx; + + +/* 2. Standard interface for AES cryptographic routines */ + +/* These are all based on 32 bit unsigned values and will therefore */ +/* require endian conversions for big-endian architectures */ + +rijndael_ctx *rijndael_set_key __P((rijndael_ctx *, const u4byte *, u4byte, int)); +void rijndael_encrypt __P((rijndael_ctx *, const u4byte *, u4byte *)); +void rijndael_decrypt __P((rijndael_ctx *, const u4byte *, u4byte *)); + +#endif /* _RIJNDAEL_H_ */ diff --git a/crypto/openssh/scp.1 b/crypto/openssh/scp.1 index 4ef3fe5..0a2ca1a 100644 --- a/crypto/openssh/scp.1 +++ b/crypto/openssh/scp.1 @@ -9,7 +9,7 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $Id: scp.1,v 1.10 2000/09/01 15:25:13 deraadt Exp $ +.\" $OpenBSD: scp.1,v 1.13 2000/10/16 09:38:44 djm Exp $ .\" .Dd September 25, 1999 .Dt SCP 1 @@ -24,6 +24,7 @@ .Op Fl P Ar port .Op Fl c Ar cipher .Op Fl i Ar identity_file +.Op Fl o Ar option .Sm off .Oo .Op Ar user@ @@ -102,9 +103,13 @@ is already reserved for preserving the times and modes of the file in .It Fl S Ar program Name of .Ar program -to use for the encrypted connection. The program must understand +to use for the encrypted connection. +The program must understand .Xr ssh 1 options. +.It Fl o Ar option +The given option is directly passed to +.Xr ssh 1 . .It Fl 4 Forces .Nm diff --git a/crypto/openssh/scp.c b/crypto/openssh/scp.c index ec1f3d1..a412b8d 100644 --- a/crypto/openssh/scp.c +++ b/crypto/openssh/scp.c @@ -75,11 +75,10 @@ */ #include "includes.h" -RCSID("$OpenBSD: scp.c,v 1.39 2000/09/07 20:53:00 markus Exp $"); +RCSID("$OpenBSD: scp.c,v 1.43 2000/10/18 18:23:02 markus Exp $"); #include "ssh.h" #include "xmalloc.h" -#include <utime.h> #define _PATH_CP "cp" @@ -93,6 +92,9 @@ void progressmeter(int); int getttywidth(void); int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc); +/* setup arguments for the call to ssh */ +void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2))); + /* Time a transfer started. */ static struct timeval start; @@ -105,12 +107,6 @@ off_t totalbytes = 0; /* Name of current file being transferred. */ char *curfile; -/* This is set to non-zero if IPv4 is desired. */ -int IPv4 = 0; - -/* This is set to non-zero if IPv6 is desired. */ -int IPv6 = 0; - /* This is set to non-zero to enable verbose mode. */ int verbose_mode = 0; @@ -120,23 +116,16 @@ int compress = 0; /* This is set to zero if the progressmeter is not desired. */ int showprogress = 1; -/* This is set to non-zero if running in batch mode (that is, password - and passphrase queries are not allowed). */ -int batchmode = 0; - -/* This is set to the cipher type string if given on the command line. */ -char *cipher = NULL; - -/* This is set to the RSA authentication identity file name if given on - the command line. */ -char *identity = NULL; - -/* This is the port to use in contacting the remote site (is non-NULL). */ -char *port = NULL; - /* This is the program to execute for the secured connection. ("ssh" or -S) */ char *ssh_program = SSH_PROGRAM; +/* This is the list of arguments that scp passes to ssh */ +struct { + char **list; + int num; + int nalloc; +} args; + /* * This function executes the given command as the specified user on the * given host. This returns < 0 if execution fails, and >= 0 otherwise. This @@ -149,8 +138,8 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) int pin[2], pout[2], reserved[2]; if (verbose_mode) - fprintf(stderr, "Executing: host %s, user %s, command %s\n", - host, remuser ? remuser : "(unspecified)", cmd); + fprintf(stderr, "Executing: program %s host %s, user %s, command %s\n", + ssh_program, host, remuser ? remuser : "(unspecified)", cmd); /* * Reserve two descriptors so that the real pipes won't get @@ -169,10 +158,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) close(reserved[1]); /* For a child to execute the command on the remote host using ssh. */ - if (fork() == 0) { - char *args[100]; /* XXX careful */ - unsigned int i; - + if (fork() == 0) { /* Child. */ close(pin[1]); close(pout[0]); @@ -181,41 +167,13 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) close(pin[0]); close(pout[1]); - i = 0; - args[i++] = ssh_program; - args[i++] = "-x"; - args[i++] = "-oFallBackToRsh no"; - if (IPv4) - args[i++] = "-4"; - if (IPv6) - args[i++] = "-6"; - if (verbose_mode) - args[i++] = "-v"; - if (compress) - args[i++] = "-C"; - if (batchmode) - args[i++] = "-oBatchMode yes"; - if (cipher != NULL) { - args[i++] = "-c"; - args[i++] = cipher; - } - if (identity != NULL) { - args[i++] = "-i"; - args[i++] = identity; - } - if (port != NULL) { - args[i++] = "-p"; - args[i++] = port; - } - if (remuser != NULL) { - args[i++] = "-l"; - args[i++] = remuser; - } - args[i++] = host; - args[i++] = cmd; - args[i++] = NULL; + args.list[0] = ssh_program; + if (remuser != NULL) + addargs("-l%s", remuser); + addargs("%s", host); + addargs("%s", cmd); - execvp(ssh_program, args); + execvp(ssh_program, args.list); perror(ssh_program); exit(1); } @@ -281,27 +239,45 @@ main(argc, argv) extern char *optarg; extern int optind; + args.list = NULL; + addargs("ssh"); /* overwritten with ssh_program */ + addargs("-x"); + addargs("-oFallBackToRsh no"); + fflag = tflag = 0; - while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:")) != EOF) + while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != EOF) switch (ch) { /* User-visible flags. */ case '4': - IPv4 = 1; - break; case '6': - IPv6 = 1; + case 'C': + addargs("-%c", ch); break; - case 'p': - pflag = 1; + case 'o': + case 'c': + case 'i': + addargs("-%c%s", ch, optarg); break; case 'P': - port = optarg; + addargs("-p%s", optarg); + break; + case 'B': + addargs("-oBatchmode yes"); + break; + case 'p': + pflag = 1; break; case 'r': iamrecursive = 1; break; case 'S': - ssh_program = optarg; + ssh_program = xstrdup(optarg); + break; + case 'v': + verbose_mode = 1; + break; + case 'q': + showprogress = 0; break; /* Server options. */ @@ -316,24 +292,6 @@ main(argc, argv) iamremote = 1; tflag = 1; break; - case 'c': - cipher = optarg; - break; - case 'i': - identity = optarg; - break; - case 'v': - verbose_mode = 1; - break; - case 'B': - batchmode = 1; - break; - case 'C': - compress = 1; - break; - case 'q': - showprogress = 0; - break; case '?': default: usage(); @@ -703,8 +661,8 @@ sink(argc, argv) off_t size; int setimes, targisdir, wrerrno = 0; char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; - struct utimbuf ut; int dummy_usec; + struct timeval tv[2]; #define SCREWUP(str) { why = str; goto screwup; } @@ -758,16 +716,18 @@ sink(argc, argv) if (*cp == 'T') { setimes++; cp++; - getnum(ut.modtime); + getnum(tv[1].tv_sec); if (*cp++ != ' ') SCREWUP("mtime.sec not delimited"); getnum(dummy_usec); + tv[1].tv_usec = 0; if (*cp++ != ' ') SCREWUP("mtime.usec not delimited"); - getnum(ut.actime); + getnum(tv[0].tv_sec); if (*cp++ != ' ') SCREWUP("atime.sec not delimited"); getnum(dummy_usec); + tv[0].tv_usec = 0; if (*cp++ != '\0') SCREWUP("atime.usec not delimited"); (void) atomicio(write, remout, "", 1); @@ -835,7 +795,7 @@ sink(argc, argv) sink(1, vect); if (setimes) { setimes = 0; - if (utime(np, &ut) < 0) + if (utimes(np, tv) < 0) run_err("%s: set times: %s", np, strerror(errno)); } @@ -868,8 +828,10 @@ bad: run_err("%s: %s", np, strerror(errno)); amt = size - i; count += amt; do { - j = atomicio(read, remin, cp, amt); - if (j <= 0) { + j = read(remin, cp, amt); + if (j == -1 && (errno == EINTR || errno == EAGAIN)) { + continue; + } else if (j <= 0) { run_err("%s", j ? strerror(errno) : "dropped connection"); exit(1); @@ -922,7 +884,7 @@ bad: run_err("%s: %s", np, strerror(errno)); (void) response(); if (setimes && wrerr == NO) { setimes = 0; - if (utime(np, &ut) < 0) { + if (utimes(np, tv) < 0) { run_err("%s: set times: %s", np, strerror(errno)); wrerr = DISPLAYED; @@ -1249,3 +1211,25 @@ getttywidth(void) else return (80); } + +void +addargs(char *fmt, ...) +{ + va_list ap; + char buf[1024]; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + if (args.list == NULL) { + args.nalloc = 32; + args.num = 0; + args.list = xmalloc(args.nalloc * sizeof(char *)); + } else if (args.num+2 >= args.nalloc) { + args.nalloc *= 2; + args.list = xrealloc(args.list, args.nalloc * sizeof(char *)); + } + args.list[args.num++] = xstrdup(buf); + args.list[args.num] = NULL; +} diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c index ed2886a..f63131d 100644 --- a/crypto/openssh/serverloop.c +++ b/crypto/openssh/serverloop.c @@ -35,6 +35,8 @@ */ #include "includes.h" +RCSID("$OpenBSD: serverloop.c,v 1.34 2000/10/27 07:32:18 markus Exp $"); + #include "xmalloc.h" #include "ssh.h" #include "packet.h" @@ -49,6 +51,8 @@ #include "dispatch.h" #include "auth-options.h" +extern ServerOptions options; + static Buffer stdin_buffer; /* Buffer for stdin data. */ static Buffer stdout_buffer; /* Buffer for stdout data. */ static Buffer stderr_buffer; /* Buffer for stderr data. */ @@ -380,7 +384,7 @@ drain_output() void process_buffered_input_packets() { - dispatch_run(DISPATCH_NONBLOCK, NULL); + dispatch_run(DISPATCH_NONBLOCK, NULL, NULL); } /* @@ -673,7 +677,7 @@ server_loop2(void) } void -server_input_stdin_data(int type, int plen) +server_input_stdin_data(int type, int plen, void *ctxt) { char *data; unsigned int data_len; @@ -690,7 +694,7 @@ server_input_stdin_data(int type, int plen) } void -server_input_eof(int type, int plen) +server_input_eof(int type, int plen, void *ctxt) { /* * Eof from the client. The stdin descriptor to the @@ -703,7 +707,7 @@ server_input_eof(int type, int plen) } void -server_input_window_size(int type, int plen) +server_input_window_size(int type, int plen, void *ctxt) { int row = packet_get_int(); int col = packet_get_int(); @@ -733,7 +737,7 @@ input_direct_tcpip(void) originator, originator_port, target, target_port); /* XXX check permission */ - if (no_port_forwarding_flag) { + if (no_port_forwarding_flag || !options.allow_tcp_forwarding) { xfree(target); xfree(originator); return -1; @@ -745,11 +749,11 @@ input_direct_tcpip(void) return -1; return channel_new("direct-tcpip", SSH_CHANNEL_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, - CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip")); + CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1); } void -server_input_channel_open(int type, int plen) +server_input_channel_open(int type, int plen, void *ctxt) { Channel *c = NULL; char *ctype; @@ -764,7 +768,7 @@ server_input_channel_open(int type, int plen) rwindow = packet_get_int(); rmaxpack = packet_get_int(); - debug("channel_input_open: ctype %s rchan %d win %d max %d", + debug("server_input_channel_open: ctype %s rchan %d win %d max %d", ctype, rchan, rwindow, rmaxpack); if (strcmp(ctype, "session") == 0) { @@ -779,7 +783,7 @@ server_input_channel_open(int type, int plen) */ id = channel_new(ctype, SSH_CHANNEL_LARVAL, -1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT, - 0, xstrdup("server-session")); + 0, xstrdup("server-session"), 1); if (session_open(id) == 1) { channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST, session_input_channel_req, (void *)0); diff --git a/crypto/openssh/sftp-server.8 b/crypto/openssh/sftp-server.8 index 9811a3b..41a698e 100644 --- a/crypto/openssh/sftp-server.8 +++ b/crypto/openssh/sftp-server.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp-server.8,v 1.2 2000/09/07 20:27:53 deraadt Exp $ +.\" $OpenBSD: sftp-server.8,v 1.3 2000/10/13 17:20:44 aaron Exp $ .\" .\" Copyright (c) 2000 Markus Friedl. All rights reserved. .\" @@ -36,21 +36,21 @@ is a program that speaks the server side of SFTP protocol to stdout and expects client requests from stdin. .Nm is not intended to be called directly, but from -.Xr sshd 8 +.Xr sshd 8 using the .Cm Subsystem option. See -.Xr sshd 8 +.Xr sshd 8 for more information. -.Sh HISTORY -.Nm -first appeared in -.Ox 2.8 . -.Sh AUTHOR -Markus Friedl <markus@openbsd.org> .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-keygen 1 , -.Xr sshd 8 , +.Xr sshd 8 +.Sh AUTHOR +Markus Friedl <markus@openbsd.org> +.Sh HISTORY +.Nm +first appeared in +.Ox 2.8 . diff --git a/crypto/openssh/ssh-keygen.1 b/crypto/openssh/ssh-keygen.1 index b328ce0..e1b1525 100644 --- a/crypto/openssh/ssh-keygen.1 +++ b/crypto/openssh/ssh-keygen.1 @@ -168,8 +168,9 @@ removed once the RSA patent expires. This option will read a private OpenSSH DSA format file and print a SSH2-compatible public key to stdout. .It Fl X -This option will read a -SSH2-compatible public key file and print an OpenSSH DSA compatible public key to stdout. +This option will read a unencrypted +SSH2-compatible private (or public) key file and +print an OpenSSH compatible private (or public) key to stdout. .It Fl y This option will read a private OpenSSH DSA format file and print an OpenSSH DSA public key to stdout. diff --git a/crypto/openssh/ssh-keygen.c b/crypto/openssh/ssh-keygen.c index 29ee62d..e7b057f 100644 --- a/crypto/openssh/ssh-keygen.c +++ b/crypto/openssh/ssh-keygen.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-keygen.c,v 1.31 2000/09/07 20:27:54 deraadt Exp $"); +RCSID("$OpenBSD: ssh-keygen.c,v 1.32 2000/10/09 21:30:44 markus Exp $"); #include <openssl/evp.h> #include <openssl/pem.h> @@ -27,6 +27,9 @@ RCSID("$OpenBSD: ssh-keygen.c,v 1.31 2000/09/07 20:27:54 deraadt Exp $"); #include "authfile.h" #include "uuencode.h" +#include "buffer.h" +#include "bufaux.h" + /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */ int bits = 1024; @@ -104,8 +107,10 @@ try_load_key(char *filename, Key *k) return success; } -#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" -#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----" +#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" +#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" +#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" +#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb void do_convert_to_ssh2(struct passwd *pw) @@ -127,19 +132,84 @@ do_convert_to_ssh2(struct passwd *pw) exit(1); } dsa_make_key_blob(k, &blob, &len); - fprintf(stdout, "%s\n", SSH_COM_MAGIC_BEGIN); + fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); fprintf(stdout, - "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n", - BN_num_bits(k->dsa->p), + "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n", + key_size(k), key_type(k), pw->pw_name, hostname); dump_base64(stdout, blob, len); - fprintf(stdout, "%s\n", SSH_COM_MAGIC_END); + fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); key_free(k); xfree(blob); exit(0); } void +buffer_get_bignum_bits(Buffer *b, BIGNUM *value) +{ + int bits = buffer_get_int(b); + int bytes = (bits + 7) / 8; + if (buffer_len(b) < bytes) + fatal("buffer_get_bignum_bits: input buffer too small"); + BN_bin2bn((unsigned char *)buffer_ptr(b), bytes, value); + buffer_consume(b, bytes); +} + +Key * +do_convert_private_ssh2_from_blob(char *blob, int blen) +{ + Buffer b; + DSA *dsa; + Key *key = NULL; + int ignore, magic, rlen; + char *type, *cipher; + + buffer_init(&b); + buffer_append(&b, blob, blen); + + magic = buffer_get_int(&b); + if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { + error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); + buffer_free(&b); + return NULL; + } + ignore = buffer_get_int(&b); + type = buffer_get_string(&b, NULL); + cipher = buffer_get_string(&b, NULL); + ignore = buffer_get_int(&b); + ignore = buffer_get_int(&b); + ignore = buffer_get_int(&b); + xfree(type); + + if (strcmp(cipher, "none") != 0) { + error("unsupported cipher %s", cipher); + xfree(cipher); + buffer_free(&b); + return NULL; + } + xfree(cipher); + + key = key_new(KEY_DSA); + dsa = key->dsa; + dsa->priv_key = BN_new(); + if (dsa->priv_key == NULL) { + error("alloc priv_key failed"); + key_free(key); + return NULL; + } + buffer_get_bignum_bits(&b, dsa->p); + buffer_get_bignum_bits(&b, dsa->g); + buffer_get_bignum_bits(&b, dsa->q); + buffer_get_bignum_bits(&b, dsa->pub_key); + buffer_get_bignum_bits(&b, dsa->priv_key); + rlen = buffer_len(&b); + if(rlen != 0) + error("do_convert_private_ssh2_from_blob: remaining bytes in key blob %d", rlen); + buffer_free(&b); + return key; +} + +void do_convert_from_ssh2(struct passwd *pw) { Key *k; @@ -148,7 +218,7 @@ do_convert_from_ssh2(struct passwd *pw) char blob[8096]; char encoded[8096]; struct stat st; - int escaped = 0; + int escaped = 0, private = 0, ok; FILE *fp; if (!have_identity) @@ -172,6 +242,8 @@ do_convert_from_ssh2(struct passwd *pw) escaped++; if (strncmp(line, "----", 4) == 0 || strstr(line, ": ") != NULL) { + if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) + private = 1; fprintf(stderr, "ignore: %s", line); continue; } @@ -188,9 +260,20 @@ do_convert_from_ssh2(struct passwd *pw) fprintf(stderr, "uudecode failed.\n"); exit(1); } - k = dsa_key_from_blob(blob, blen); - if (!key_write(k, stdout)) - fprintf(stderr, "key_write failed"); + k = private ? + do_convert_private_ssh2_from_blob(blob, blen) : + dsa_key_from_blob(blob, blen); + if (k == NULL) { + fprintf(stderr, "decode blob failed.\n"); + exit(1); + } + ok = private ? + PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : + key_write(k, stdout); + if (!ok) { + fprintf(stderr, "key write failed"); + exit(1); + } key_free(k); fprintf(stdout, "\n"); fclose(fp); diff --git a/crypto/openssh/ssh2.h b/crypto/openssh/ssh2.h index 47628dd..fe0146c 100644 --- a/crypto/openssh/ssh2.h +++ b/crypto/openssh/ssh2.h @@ -52,7 +52,7 @@ * * 192-255 Local extensions */ -/* RCSID("$OpenBSD: ssh2.h,v 1.4 2000/09/07 20:27:54 deraadt Exp $"); */ +/* RCSID("$OpenBSD: ssh2.h,v 1.5 2000/10/11 04:02:17 provos Exp $"); */ /* transport layer: generic */ @@ -73,6 +73,12 @@ #define SSH2_MSG_KEXDH_INIT 30 #define SSH2_MSG_KEXDH_REPLY 31 +/* dh-group-exchange */ +#define SSH2_MSG_KEX_DH_GEX_REQUEST 30 +#define SSH2_MSG_KEX_DH_GEX_GROUP 31 +#define SSH2_MSG_KEX_DH_GEX_INIT 32 +#define SSH2_MSG_KEX_DH_GEX_REPLY 33 + /* user authentication: generic */ #define SSH2_MSG_USERAUTH_REQUEST 50 diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c index d225359..6ba23d4 100644 --- a/crypto/openssh/sshconnect2.c +++ b/crypto/openssh/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.18 2000/09/07 20:27:55 deraadt Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.27 2000/10/19 16:45:16 provos Exp $"); #include <openssl/bn.h> #include <openssl/rsa.h> @@ -37,7 +37,6 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.18 2000/09/07 20:27:55 deraadt Exp $"); #include "rsa.h" #include "buffer.h" #include "packet.h" -#include "cipher.h" #include "uidswap.h" #include "compat.h" #include "readconf.h" @@ -49,8 +48,13 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.18 2000/09/07 20:27:55 deraadt Exp $"); #include "dsa.h" #include "sshconnect.h" #include "authfile.h" +#include "cli.h" +#include "dispatch.h" #include "authfd.h" +void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); +void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); + /* import */ extern char *client_version_string; extern char *server_version_string; @@ -64,9 +68,94 @@ unsigned char *session_id2 = NULL; int session_id2_len = 0; void -ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, - Buffer *client_kexinit, Buffer *server_kexinit) +ssh_kex2(char *host, struct sockaddr *hostaddr) +{ + int i, plen; + Kex *kex; + Buffer *client_kexinit, *server_kexinit; + char *sprop[PROPOSAL_MAX]; + + if (options.ciphers == NULL) { + if (options.cipher == SSH_CIPHER_3DES) { + options.ciphers = "3des-cbc"; + } else if (options.cipher == SSH_CIPHER_BLOWFISH) { + options.ciphers = "blowfish-cbc"; + } else if (options.cipher == SSH_CIPHER_DES) { + fatal("cipher DES not supported for protocol version 2"); + } + } + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; + } + if (options.compression) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib"; + myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib"; + } else { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none"; + myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; + } + + /* buffers with raw kexinit messages */ + server_kexinit = xmalloc(sizeof(*server_kexinit)); + buffer_init(server_kexinit); + client_kexinit = kex_init(myproposal); + + /* algorithm negotiation */ + kex_exchange_kexinit(client_kexinit, server_kexinit, sprop); + kex = kex_choose_conf(myproposal, sprop, 0); + for (i = 0; i < PROPOSAL_MAX; i++) + xfree(sprop[i]); + + /* server authentication and session key agreement */ + switch(kex->kex_type) { + case DH_GRP1_SHA1: + ssh_dh1_client(kex, host, hostaddr, + client_kexinit, server_kexinit); + break; + case DH_GEX_SHA1: + ssh_dhgex_client(kex, host, hostaddr, client_kexinit, + server_kexinit); + break; + default: + fatal("Unsupported key exchange %d", kex->kex_type); + } + + buffer_free(client_kexinit); + buffer_free(server_kexinit); + xfree(client_kexinit); + xfree(server_kexinit); + + debug("Wait SSH2_MSG_NEWKEYS."); + packet_read_expect(&plen, SSH2_MSG_NEWKEYS); + packet_done(); + debug("GOT SSH2_MSG_NEWKEYS."); + + debug("send SSH2_MSG_NEWKEYS."); + packet_start(SSH2_MSG_NEWKEYS); + packet_send(); + packet_write_wait(); + debug("done: send SSH2_MSG_NEWKEYS."); + +#ifdef DEBUG_KEXDH + /* send 1st encrypted/maced/compressed message */ + packet_start(SSH2_MSG_IGNORE); + packet_put_cstring("markus"); + packet_send(); + packet_write_wait(); +#endif + debug("done: KEX2."); +} + +/* diffie-hellman-group1-sha1 */ + +void +ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, + Buffer *client_kexinit, Buffer *server_kexinit) { +#ifdef DEBUG_KEXDH + int i; +#endif int plen, dlen; unsigned int klen, kout; char *signature = NULL; @@ -90,11 +179,11 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, #ifdef DEBUG_KEXDH fprintf(stderr, "\np= "); - bignum_print(dh->p); + BN_print_fp(stderr, dh->p); fprintf(stderr, "\ng= "); - bignum_print(dh->g); + BN_print_fp(stderr, dh->g); fprintf(stderr, "\npub= "); - bignum_print(dh->pub_key); + BN_print_fp(stderr, dh->pub_key); fprintf(stderr, "\n"); DHparams_print_fp(stderr, dh); #endif @@ -112,7 +201,7 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, fatal("cannot decode server_host_key_blob"); check_host_key(host, hostaddr, server_host_key, - options.user_hostfile2, options.system_hostfile2); + options.user_hostfile2, options.system_hostfile2); /* DH paramter f, server public DH key */ dh_server_pub = BN_new(); @@ -122,7 +211,7 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, #ifdef DEBUG_KEXDH fprintf(stderr, "\ndh_server_pub= "); - bignum_print(dh_server_pub); + BN_print_fp(stderr, dh_server_pub); fprintf(stderr, "\n"); debug("bits %d", BN_num_bits(dh_server_pub)); #endif @@ -182,79 +271,351 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, memcpy(session_id2, hash, session_id2_len); } +/* diffie-hellman-group-exchange-sha1 */ + +/* + * Estimates the group order for a Diffie-Hellman group that has an + * attack complexity approximately the same as O(2**bits). Estimate + * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) + */ + +int +dh_estimate(int bits) +{ + + if (bits < 64) + return (512); /* O(2**63) */ + if (bits < 128) + return (1024); /* O(2**86) */ + if (bits < 192) + return (2048); /* O(2**116) */ + return (4096); /* O(2**156) */ +} + void -ssh_kex2(char *host, struct sockaddr *hostaddr) +ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, + Buffer *client_kexinit, Buffer *server_kexinit) { - int i, plen; - Kex *kex; - Buffer *client_kexinit, *server_kexinit; - char *sprop[PROPOSAL_MAX]; +#ifdef DEBUG_KEXDH + int i; +#endif + int plen, dlen; + unsigned int klen, kout; + char *signature = NULL; + unsigned int slen, nbits; + char *server_host_key_blob = NULL; + Key *server_host_key; + unsigned int sbloblen; + DH *dh; + BIGNUM *dh_server_pub = 0; + BIGNUM *shared_secret = 0; + BIGNUM *p = 0, *g = 0; + unsigned char *kbuf; + unsigned char *hash; - if (options.ciphers != NULL) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; - } else if (options.cipher == SSH_CIPHER_3DES) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = - (char *) cipher_name(SSH_CIPHER_3DES_CBC); - } else if (options.cipher == SSH_CIPHER_BLOWFISH) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = - (char *) cipher_name(SSH_CIPHER_BLOWFISH_CBC); - } - if (options.compression) { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib"; - myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib"; - } else { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none"; - myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; - } + nbits = dh_estimate(kex->enc[MODE_OUT].cipher->key_len * 8); - /* buffers with raw kexinit messages */ - server_kexinit = xmalloc(sizeof(*server_kexinit)); - buffer_init(server_kexinit); - client_kexinit = kex_init(myproposal); + debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST."); + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); + packet_put_int(nbits); + packet_send(); + packet_write_wait(); - /* algorithm negotiation */ - kex_exchange_kexinit(client_kexinit, server_kexinit, sprop); - kex = kex_choose_conf(myproposal, sprop, 0); - for (i = 0; i < PROPOSAL_MAX; i++) - xfree(sprop[i]); +#ifdef DEBUG_KEXDH + fprintf(stderr, "\nnbits = %d", nbits); +#endif - /* server authentication and session key agreement */ - ssh_kex_dh(kex, host, hostaddr, client_kexinit, server_kexinit); + debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP."); - buffer_free(client_kexinit); - buffer_free(server_kexinit); - xfree(client_kexinit); - xfree(server_kexinit); + packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP); - debug("Wait SSH2_MSG_NEWKEYS."); - packet_read_expect(&plen, SSH2_MSG_NEWKEYS); - packet_done(); - debug("GOT SSH2_MSG_NEWKEYS."); + debug("Got SSH2_MSG_KEX_DH_GEX_GROUP."); - debug("send SSH2_MSG_NEWKEYS."); - packet_start(SSH2_MSG_NEWKEYS); - packet_send(); - packet_write_wait(); - debug("done: send SSH2_MSG_NEWKEYS."); + if ((p = BN_new()) == NULL) + fatal("BN_new"); + packet_get_bignum2(p, &dlen); + if ((g = BN_new()) == NULL) + fatal("BN_new"); + packet_get_bignum2(g, &dlen); + if ((dh = dh_new_group(g, p)) == NULL) + fatal("dh_new_group"); #ifdef DEBUG_KEXDH - /* send 1st encrypted/maced/compressed message */ - packet_start(SSH2_MSG_IGNORE); - packet_put_cstring("markus"); + fprintf(stderr, "\np= "); + BN_print_fp(stderr, dh->p); + fprintf(stderr, "\ng= "); + BN_print_fp(stderr, dh->g); + fprintf(stderr, "\npub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); + DHparams_print_fp(stderr, dh); +#endif + + debug("Sending SSH2_MSG_KEX_DH_GEX_INIT."); + /* generate and send 'e', client DH public key */ + packet_start(SSH2_MSG_KEX_DH_GEX_INIT); + packet_put_bignum2(dh->pub_key); packet_send(); packet_write_wait(); + + debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY."); + + packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY); + + debug("Got SSH2_MSG_KEXDH_REPLY."); + + /* key, cert */ + server_host_key_blob = packet_get_string(&sbloblen); + server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen); + if (server_host_key == NULL) + fatal("cannot decode server_host_key_blob"); + + check_host_key(host, hostaddr, server_host_key, + options.user_hostfile2, options.system_hostfile2); + + /* DH paramter f, server public DH key */ + dh_server_pub = BN_new(); + if (dh_server_pub == NULL) + fatal("dh_server_pub == NULL"); + packet_get_bignum2(dh_server_pub, &dlen); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "\ndh_server_pub= "); + BN_print_fp(stderr, dh_server_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_server_pub)); #endif - debug("done: KEX2."); + + /* signed H */ + signature = packet_get_string(&slen); + packet_done(); + + if (!dh_pub_is_valid(dh, dh_server_pub)) + packet_disconnect("bad server public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); +#ifdef DEBUG_KEXDH + debug("shared secret: len %d/%d", klen, kout); + fprintf(stderr, "shared secret == "); + for (i = 0; i< kout; i++) + fprintf(stderr, "%02x", (kbuf[i])&0xff); + fprintf(stderr, "\n"); +#endif + shared_secret = BN_new(); + + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + /* calc and verify H */ + hash = kex_hash_gex( + client_version_string, + server_version_string, + buffer_ptr(client_kexinit), buffer_len(client_kexinit), + buffer_ptr(server_kexinit), buffer_len(server_kexinit), + server_host_key_blob, sbloblen, + nbits, dh->p, dh->g, + dh->pub_key, + dh_server_pub, + shared_secret + ); + xfree(server_host_key_blob); + DH_free(dh); +#ifdef DEBUG_KEXDH + fprintf(stderr, "hash == "); + for (i = 0; i< 20; i++) + fprintf(stderr, "%02x", (hash[i])&0xff); + fprintf(stderr, "\n"); +#endif + if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) + fatal("dsa_verify failed for server_host_key"); + key_free(server_host_key); + + kex_derive_keys(kex, hash, shared_secret); + packet_set_kex(kex); + + /* save session id */ + session_id2_len = 20; + session_id2 = xmalloc(session_id2_len); + memcpy(session_id2, hash, session_id2_len); } /* * Authenticate user */ + +typedef struct Authctxt Authctxt; +typedef struct Authmethod Authmethod; + +typedef int sign_cb_fn( + Authctxt *authctxt, Key *key, + unsigned char **sigp, int *lenp, unsigned char *data, int datalen); + +struct Authctxt { + const char *server_user; + const char *host; + const char *service; + AuthenticationConnection *agent; + Authmethod *method; + int success; +}; +struct Authmethod { + char *name; /* string to compare against server's list */ + int (*userauth)(Authctxt *authctxt); + int *enabled; /* flag in option struct that enables method */ + int *batch_flag; /* flag in option struct that disables method */ +}; + +void input_userauth_success(int type, int plen, void *ctxt); +void input_userauth_failure(int type, int plen, void *ctxt); +void input_userauth_error(int type, int plen, void *ctxt); +void input_userauth_info_req(int type, int plen, void *ctxt); + +int userauth_none(Authctxt *authctxt); +int userauth_pubkey(Authctxt *authctxt); +int userauth_passwd(Authctxt *authctxt); +int userauth_kbdint(Authctxt *authctxt); + +void authmethod_clear(); +Authmethod *authmethod_get(char *authlist); +Authmethod *authmethod_lookup(const char *name); + +Authmethod authmethods[] = { + {"publickey", + userauth_pubkey, + &options.dsa_authentication, + NULL}, + {"password", + userauth_passwd, + &options.password_authentication, + &options.batch_mode}, + {"keyboard-interactive", + userauth_kbdint, + &options.kbd_interactive_authentication, + &options.batch_mode}, + {"none", + userauth_none, + NULL, + NULL}, + {NULL, NULL, NULL, NULL} +}; + +void +ssh_userauth2(const char *server_user, char *host) +{ + Authctxt authctxt; + int type; + int plen; + + debug("send SSH2_MSG_SERVICE_REQUEST"); + packet_start(SSH2_MSG_SERVICE_REQUEST); + packet_put_cstring("ssh-userauth"); + packet_send(); + packet_write_wait(); + type = packet_read(&plen); + if (type != SSH2_MSG_SERVICE_ACCEPT) { + fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type); + } + if (packet_remaining() > 0) { + char *reply = packet_get_string(&plen); + debug("service_accept: %s", reply); + xfree(reply); + packet_done(); + } else { + debug("buggy server: service_accept w/o service"); + } + packet_done(); + debug("got SSH2_MSG_SERVICE_ACCEPT"); + + /* setup authentication context */ + authctxt.agent = ssh_get_authentication_connection(); + authctxt.server_user = server_user; + authctxt.host = host; + authctxt.service = "ssh-connection"; /* service name */ + authctxt.success = 0; + authctxt.method = authmethod_lookup("none"); + if (authctxt.method == NULL) + fatal("ssh_userauth2: internal error: cannot send userauth none request"); + authmethod_clear(); + + /* initial userauth request */ + userauth_none(&authctxt); + + dispatch_init(&input_userauth_error); + dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); + dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); + dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ + + if (authctxt.agent != NULL) + ssh_close_authentication_connection(authctxt.agent); + + debug("ssh-userauth2 successfull: method %s", authctxt.method->name); +} +void +input_userauth_error(int type, int plen, void *ctxt) +{ + fatal("input_userauth_error: bad message during authentication"); +} +void +input_userauth_success(int type, int plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + if (authctxt == NULL) + fatal("input_userauth_success: no authentication context"); + authctxt->success = 1; /* break out */ +} +void +input_userauth_failure(int type, int plen, void *ctxt) +{ + Authmethod *method = NULL; + Authctxt *authctxt = ctxt; + char *authlist = NULL; + int partial; + + if (authctxt == NULL) + fatal("input_userauth_failure: no authentication context"); + + authlist = packet_get_string(NULL); + partial = packet_get_char(); + packet_done(); + + if (partial != 0) + debug("partial success"); + debug("authentications that can continue: %s", authlist); + + for (;;) { + method = authmethod_get(authlist); + if (method == NULL) + fatal("Unable to find an authentication method"); + authctxt->method = method; + if (method->userauth(authctxt) != 0) { + debug2("we sent a %s packet, wait for reply", method->name); + break; + } else { + debug2("we did not send a packet, disable method"); + method->enabled = NULL; + } + } + xfree(authlist); +} + +int +userauth_none(Authctxt *authctxt) +{ + /* initial userauth request */ + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_send(); + packet_write_wait(); + return 1; +} + int -ssh2_try_passwd(const char *server_user, const char *host, const char *service) +userauth_passwd(Authctxt *authctxt) { static int attempt = 0; char prompt[80]; @@ -267,12 +628,12 @@ ssh2_try_passwd(const char *server_user, const char *host, const char *service) error("Permission denied, please try again."); snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", - server_user, host); + authctxt->server_user, authctxt->host); password = read_passphrase(prompt, 0); packet_start(SSH2_MSG_USERAUTH_REQUEST); - packet_put_cstring(server_user); - packet_put_cstring(service); - packet_put_cstring("password"); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); packet_put_char(0); packet_put_cstring(password); memset(password, 0, strlen(password)); @@ -282,45 +643,40 @@ ssh2_try_passwd(const char *server_user, const char *host, const char *service) return 1; } -typedef int sign_fn( - Key *key, - unsigned char **sigp, int *lenp, - unsigned char *data, int datalen); - int -ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, - const char *server_user, const char *host, const char *service) +sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) { Buffer b; unsigned char *blob, *signature; int bloblen, slen; int skip = 0; int ret = -1; + int have_sig = 1; dsa_make_key_blob(k, &blob, &bloblen); /* data to be signed */ buffer_init(&b); - if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) { - buffer_put_string(&b, session_id2, session_id2_len); - skip = buffer_len(&b); - } else { + if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); skip = session_id2_len; + } else { + buffer_put_string(&b, session_id2, session_id2_len); + skip = buffer_len(&b); } buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); - buffer_put_cstring(&b, server_user); + buffer_put_cstring(&b, authctxt->server_user); buffer_put_cstring(&b, datafellows & SSH_BUG_PUBKEYAUTH ? "ssh-userauth" : - service); - buffer_put_cstring(&b, "publickey"); - buffer_put_char(&b, 1); + authctxt->service); + buffer_put_cstring(&b, authctxt->method->name); + buffer_put_char(&b, have_sig); buffer_put_cstring(&b, KEX_DSS); buffer_put_string(&b, blob, bloblen); /* generate signature */ - ret = do_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); + ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); if (ret == -1) { xfree(blob); buffer_free(&b); @@ -333,10 +689,10 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, buffer_clear(&b); buffer_append(&b, session_id2, session_id2_len); buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); - buffer_put_cstring(&b, server_user); - buffer_put_cstring(&b, service); - buffer_put_cstring(&b, "publickey"); - buffer_put_char(&b, 1); + buffer_put_cstring(&b, authctxt->server_user); + buffer_put_cstring(&b, authctxt->service); + buffer_put_cstring(&b, authctxt->method->name); + buffer_put_char(&b, have_sig); buffer_put_cstring(&b, KEX_DSS); buffer_put_string(&b, blob, bloblen); } @@ -347,7 +703,7 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, /* skip session id and packet type */ if (buffer_len(&b) < skip + 1) - fatal("ssh2_try_pubkey: internal error"); + fatal("userauth_pubkey: internal error"); buffer_consume(&b, skip + 1); /* put remaining data from buffer into packet */ @@ -362,12 +718,18 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, return 1; } +/* sign callback */ +int dsa_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, + unsigned char *data, int datalen) +{ + return dsa_sign(key, sigp, lenp, data, datalen); +} + int -ssh2_try_pubkey(char *filename, - const char *server_user, const char *host, const char *service) +userauth_pubkey_identity(Authctxt *authctxt, char *filename) { Key *k; - int ret = 0; + int i, ret, try_next; struct stat st; if (stat(filename, &st) != 0) { @@ -382,39 +744,42 @@ ssh2_try_pubkey(char *filename, char *passphrase; char prompt[300]; snprintf(prompt, sizeof prompt, - "Enter passphrase for DSA key '%.100s': ", - filename); - passphrase = read_passphrase(prompt, 0); - success = load_private_key(filename, passphrase, k, NULL); - memset(passphrase, 0, strlen(passphrase)); - xfree(passphrase); + "Enter passphrase for %s key '%.100s': ", + key_type(k), filename); + for (i = 0; i < options.number_of_password_prompts; i++) { + passphrase = read_passphrase(prompt, 0); + if (strcmp(passphrase, "") != 0) { + success = load_private_key(filename, passphrase, k, NULL); + try_next = 0; + } else { + debug2("no passphrase given, try next key"); + try_next = 1; + } + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + if (success || try_next) + break; + debug2("bad passphrase given, try again..."); + } if (!success) { key_free(k); return 0; } } - ret = ssh2_sign_and_send_pubkey(k, dsa_sign, server_user, host, service); + ret = sign_and_send_pubkey(authctxt, k, dsa_sign_cb); key_free(k); return ret; } -int agent_sign( - Key *key, - unsigned char **sigp, int *lenp, +/* sign callback */ +int agent_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, unsigned char *data, int datalen) { - int ret = -1; - AuthenticationConnection *ac = ssh_get_authentication_connection(); - if (ac != NULL) { - ret = ssh_agent_sign(ac, key, sigp, lenp, data, datalen); - ssh_close_authentication_connection(ac); - } - return ret; + return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen); } int -ssh2_try_agent(AuthenticationConnection *ac, - const char *server_user, const char *host, const char *service) +userauth_pubkey_agent(Authctxt *authctxt) { static int called = 0; char *comment; @@ -422,104 +787,243 @@ ssh2_try_agent(AuthenticationConnection *ac, int ret; if (called == 0) { - k = ssh_get_first_identity(ac, &comment, 2); - called ++; + k = ssh_get_first_identity(authctxt->agent, &comment, 2); + called = 1; } else { - k = ssh_get_next_identity(ac, &comment, 2); + k = ssh_get_next_identity(authctxt->agent, &comment, 2); } - if (k == NULL) + if (k == NULL) { + debug2("no more DSA keys from agent"); return 0; + } debug("trying DSA agent key %s", comment); xfree(comment); - ret = ssh2_sign_and_send_pubkey(k, agent_sign, server_user, host, service); + ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb); key_free(k); return ret; } -void -ssh_userauth2(const char *server_user, char *host) +int +userauth_pubkey(Authctxt *authctxt) { - AuthenticationConnection *ac = ssh_get_authentication_connection(); - int type; - int plen; - int sent; - unsigned int dlen; - int partial; - int i = 0; - char *auths; - char *service = "ssh-connection"; /* service name */ + static int idx = 0; + int sent = 0; - debug("send SSH2_MSG_SERVICE_REQUEST"); - packet_start(SSH2_MSG_SERVICE_REQUEST); - packet_put_cstring("ssh-userauth"); + if (authctxt->agent != NULL) + sent = userauth_pubkey_agent(authctxt); + while (sent == 0 && idx < options.num_identity_files2) + sent = userauth_pubkey_identity(authctxt, options.identity_files2[idx++]); + return sent; +} + +/* + * Send userauth request message specifying keyboard-interactive method. + */ +int +userauth_kbdint(Authctxt *authctxt) +{ + static int attempt = 0; + + if (attempt++ >= options.number_of_password_prompts) + return 0; + + debug2("userauth_kbdint"); + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_cstring(""); /* lang */ + packet_put_cstring(options.kbd_interactive_devices ? + options.kbd_interactive_devices : ""); packet_send(); packet_write_wait(); - type = packet_read(&plen); - if (type != SSH2_MSG_SERVICE_ACCEPT) { - fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type); - } - if (packet_remaining() > 0) { - char *reply = packet_get_string(&plen); - debug("service_accept: %s", reply); - xfree(reply); - } else { - /* payload empty for ssh-2.0.13 ?? */ - debug("buggy server: service_accept w/o service"); + dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); + return 1; +} + +/* + * parse SSH2_MSG_USERAUTH_INFO_REQUEST, prompt user and send + * SSH2_MSG_USERAUTH_INFO_RESPONSE + */ +void +input_userauth_info_req(int type, int plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + char *name = NULL; + char *inst = NULL; + char *lang = NULL; + char *prompt = NULL; + char *response = NULL; + unsigned int num_prompts, i; + int echo = 0; + + debug2("input_userauth_info_req"); + + if (authctxt == NULL) + fatal("input_userauth_info_req: no authentication context"); + + name = packet_get_string(NULL); + inst = packet_get_string(NULL); + lang = packet_get_string(NULL); + + if (strlen(name) > 0) + cli_mesg(name); + xfree(name); + + if (strlen(inst) > 0) + cli_mesg(inst); + xfree(inst); + xfree(lang); /* unused */ + + num_prompts = packet_get_int(); + /* + * Begin to build info response packet based on prompts requested. + * We commit to providing the correct number of responses, so if + * further on we run into a problem that prevents this, we have to + * be sure and clean this up and send a correct error response. + */ + packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE); + packet_put_int(num_prompts); + + for (i = 0; i < num_prompts; i++) { + prompt = packet_get_string(NULL); + echo = packet_get_char(); + + response = cli_prompt(prompt, echo); + + packet_put_cstring(response); + memset(response, 0, strlen(response)); + xfree(response); + xfree(prompt); } - packet_done(); - debug("got SSH2_MSG_SERVICE_ACCEPT"); + packet_done(); /* done with parsing incoming message. */ - /* INITIAL request for auth */ - packet_start(SSH2_MSG_USERAUTH_REQUEST); - packet_put_cstring(server_user); - packet_put_cstring(service); - packet_put_cstring("none"); packet_send(); packet_write_wait(); +} - for (;;) { - sent = 0; - type = packet_read(&plen); - if (type == SSH2_MSG_USERAUTH_SUCCESS) +/* find auth method */ + +#define DELIM "," + +static char *def_authlist = "publickey,password"; +static char *authlist_current = NULL; /* clean copy used for comparison */ +static char *authname_current = NULL; /* last used auth method */ +static char *authlist_working = NULL; /* copy that gets modified by strtok_r() */ +static char *authlist_state = NULL; /* state variable for strtok_r() */ + +/* + * Before starting to use a new authentication method list sent by the + * server, reset internal variables. This should also be called when + * finished processing server list to free resources. + */ +void +authmethod_clear() +{ + if (authlist_current != NULL) { + xfree(authlist_current); + authlist_current = NULL; + } + if (authlist_working != NULL) { + xfree(authlist_working); + authlist_working = NULL; + } + if (authname_current != NULL) { + xfree(authname_current); + authlist_state = NULL; + } + if (authlist_state != NULL) + authlist_state = NULL; + return; +} + +/* + * given auth method name, if configurable options permit this method fill + * in auth_ident field and return true, otherwise return false. + */ +int +authmethod_is_enabled(Authmethod *method) +{ + if (method == NULL) + return 0; + /* return false if options indicate this method is disabled */ + if (method->enabled == NULL || *method->enabled == 0) + return 0; + /* return false if batch mode is enabled but method needs interactive mode */ + if (method->batch_flag != NULL && *method->batch_flag != 0) + return 0; + return 1; +} + +Authmethod * +authmethod_lookup(const char *name) +{ + Authmethod *method = NULL; + if (name != NULL) + for (method = authmethods; method->name != NULL; method++) + if (strcmp(name, method->name) == 0) + return method; + debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); + return NULL; +} + +/* + * Given the authentication method list sent by the server, return the + * next method we should try. If the server initially sends a nil list, + * use a built-in default list. If the server sends a nil list after + * previously sending a valid list, continue using the list originally + * sent. + */ + +Authmethod * +authmethod_get(char *authlist) +{ + char *name = NULL, *authname_old; + Authmethod *method = NULL; + + /* Use a suitable default if we're passed a nil list. */ + if (authlist == NULL || strlen(authlist) == 0) + authlist = def_authlist; + + if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) { + /* start over if passed a different list */ + debug3("start over, passed a different list"); + authmethod_clear(); + authlist_current = xstrdup(authlist); + authlist_working = xstrdup(authlist); + name = strtok_r(authlist_working, DELIM, &authlist_state); + } else { + /* + * try to use previously used authentication method + * or continue to use previously passed list + */ + name = (authname_current != NULL) ? + authname_current : strtok_r(NULL, DELIM, &authlist_state); + } + + while (name != NULL) { + debug3("authmethod_lookup %s", name); + method = authmethod_lookup(name); + if (method != NULL && authmethod_is_enabled(method)) { + debug3("authmethod_is_enabled %s", name); break; - if (type != SSH2_MSG_USERAUTH_FAILURE) - fatal("access denied: %d", type); - /* SSH2_MSG_USERAUTH_FAILURE means: try again */ - auths = packet_get_string(&dlen); - debug("authentications that can continue: %s", auths); - partial = packet_get_char(); - packet_done(); - if (partial) - debug("partial success"); - if (options.dsa_authentication && - strstr(auths, "publickey") != NULL) { - if (ac != NULL) - sent = ssh2_try_agent(ac, - server_user, host, service); - if (!sent) { - while (i < options.num_identity_files2) { - sent = ssh2_try_pubkey( - options.identity_files2[i++], - server_user, host, service); - if (sent) - break; - } - } - } - if (!sent) { - if (options.password_authentication && - !options.batch_mode && - strstr(auths, "password") != NULL) { - sent = ssh2_try_passwd(server_user, host, service); - } } - if (!sent) - fatal("Permission denied (%s).", auths); - xfree(auths); + name = strtok_r(NULL, DELIM, &authlist_state); + method = NULL; } - if (ac != NULL) - ssh_close_authentication_connection(ac); - packet_done(); - debug("ssh-userauth2 successfull"); + + authname_old = authname_current; + if (method != NULL) { + debug("next auth method to try is %s", name); + authname_current = xstrdup(name); + } else { + debug("no more auth methods to try"); + authname_current = NULL; + } + + if (authname_old != NULL) + xfree(authname_old); + + return (method); } diff --git a/crypto/openssh/sshd/Makefile b/crypto/openssh/sshd/Makefile index 0adfcd6..0a9fba8 100644 --- a/crypto/openssh/sshd/Makefile +++ b/crypto/openssh/sshd/Makefile @@ -9,7 +9,7 @@ CFLAGS+=-DHAVE_LOGIN_CAP SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c \ pty.c log-server.c login.c servconf.c serverloop.c \ - auth.c auth1.c auth2.c auth-options.c session.c + auth.c auth1.c auth2.c auth-options.c session.c dh.c .include <bsd.own.mk> # for KERBEROS and AFS @@ -26,7 +26,7 @@ DPADD+= ${LIBKRB} .endif # KERBEROS .if (${SKEY:L} == "yes") -SRCS+= auth-skey.c +SRCS+= auth-skey.c auth2-skey.c .endif .include <bsd.prog.mk> diff --git a/crypto/openssh/util.c b/crypto/openssh/util.c index 71808f1..1a591a6 100644 --- a/crypto/openssh/util.c +++ b/crypto/openssh/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.5 2000/09/07 20:27:55 deraadt Exp $ */ +/* $OpenBSD: util.c,v 1.6 2000/10/27 07:32:19 markus Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -25,7 +25,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: util.c,v 1.5 2000/09/07 20:27:55 deraadt Exp $"); +RCSID("$OpenBSD: util.c,v 1.6 2000/10/27 07:32:19 markus Exp $"); #include "ssh.h" @@ -48,18 +48,15 @@ void set_nonblock(int fd) { int val; - if (isatty(fd)) { - /* do not mess with tty's */ - debug("no set_nonblock for tty fd %d", fd); - return; - } val = fcntl(fd, F_GETFL, 0); if (val < 0) { error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); return; } - if (val & O_NONBLOCK) + if (val & O_NONBLOCK) { + debug("fd %d IS O_NONBLOCK", fd); return; + } debug("fd %d setting O_NONBLOCK", fd); val |= O_NONBLOCK; if (fcntl(fd, F_SETFL, val) == -1) diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h index bfd4327..ea78e8c 100644 --- a/crypto/openssh/version.h +++ b/crypto/openssh/version.h @@ -1 +1,3 @@ -#define SSH_VERSION "OpenSSH_2.2.0" +/* $OpenBSD: version.h,v 1.13 2000/10/16 09:38:45 djm Exp $ */ + +#define SSH_VERSION "OpenSSH_2.3.0" |