diff options
72 files changed, 3643 insertions, 1442 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-krb4.c b/crypto/openssh/auth-krb4.c index 799cf26..21a9625 100644 --- a/crypto/openssh/auth-krb4.c +++ b/crypto/openssh/auth-krb4.c @@ -28,7 +28,7 @@ #include "ssh.h" #include "servconf.h" -RCSID("$OpenBSD: auth-krb4.c,v 1.18 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: auth-krb4.c,v 1.19 2000/10/03 18:03:02 markus Exp $"); #ifdef KRB4 char *ticket = NULL; @@ -280,6 +280,8 @@ auth_kerberos_tgt(struct passwd *pw, const char *string) { CREDENTIALS creds; + if (pw == NULL) + goto auth_kerberos_tgt_failure; if (!radix_to_creds(string, &creds)) { log("Protocol error decoding Kerberos V4 tgt"); packet_send_debug("Protocol error decoding Kerberos V4 tgt"); @@ -334,8 +336,16 @@ int auth_afs_token(struct passwd *pw, const char *token_string) { CREDENTIALS creds; - uid_t uid = pw->pw_uid; + uid_t uid; + if (pw == NULL) { + /* XXX fake protocol error */ + packet_send_debug("Protocol error decoding AFS token"); + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + return 0; + } if (!radix_to_creds(token_string, &creds)) { log("Protocol error decoding AFS token"); packet_send_debug("Protocol error decoding AFS token"); @@ -349,6 +359,8 @@ auth_afs_token(struct passwd *pw, const char *token_string) if (strncmp(creds.pname, "AFS ID ", 7) == 0) uid = atoi(creds.pname + 7); + else + uid = pw->pw_uid; if (kafs_settoken(creds.realm, uid, &creds)) { log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm, 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-passwd.c b/crypto/openssh/auth-passwd.c index c67ead7..f3bcee5 100644 --- a/crypto/openssh/auth-passwd.c +++ b/crypto/openssh/auth-passwd.c @@ -59,7 +59,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-passwd.c,v 1.17 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: auth-passwd.c,v 1.18 2000/10/03 18:03:03 markus Exp $"); #include "packet.h" #include "ssh.h" @@ -84,7 +84,7 @@ auth_password(struct passwd * pw, const char *password) if (*password == '\0' && options.permit_empty_passwd == 0) return 0; -#ifdef SKEY +#ifdef SKEY_VIA_PASSWD_IS_DISABLED if (options.skey_authentication == 1) { int ret = auth_skey_password(pw, password); if (ret == 1 || ret == 0) diff --git a/crypto/openssh/auth-rh-rsa.c b/crypto/openssh/auth-rh-rsa.c index 072e385..3070c9d 100644 --- a/crypto/openssh/auth-rh-rsa.c +++ b/crypto/openssh/auth-rh-rsa.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rh-rsa.c,v 1.16 2000/09/07 21:13:36 markus Exp $"); +RCSID("$OpenBSD: auth-rh-rsa.c,v 1.17 2000/10/03 18:03:03 markus Exp $"); #include "packet.h" #include "ssh.h" @@ -39,9 +39,9 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key HostStatus host_status; Key *client_key, *found; - debug("Trying rhosts with RSA host authentication for %.100s", client_user); + debug("Trying rhosts with RSA host authentication for client user %.100s", client_user); - if (client_host_key == NULL) + if (pw == NULL || client_host_key == NULL) return 0; /* Check if we would accept it using rhosts authentication. */ 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-rsa.c b/crypto/openssh/auth-rsa.c index 8aefc8f..e8bfa16 100644 --- a/crypto/openssh/auth-rsa.c +++ b/crypto/openssh/auth-rsa.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rsa.c,v 1.29 2000/09/07 21:13:36 markus Exp $"); +RCSID("$OpenBSD: auth-rsa.c,v 1.32 2000/10/14 12:19:45 markus Exp $"); #include "rsa.h" #include "packet.h" @@ -29,6 +29,10 @@ RCSID("$OpenBSD: auth-rsa.c,v 1.29 2000/09/07 21:13:36 markus Exp $"); #include <openssl/rsa.h> #include <openssl/md5.h> + +/* import */ +extern ServerOptions options; + /* * Session identifier that is used to bind key exchange and authentication * responses to a particular session. @@ -116,7 +120,6 @@ auth_rsa_challenge_dialog(RSA *pk) int auth_rsa(struct passwd *pw, BIGNUM *client_n) { - extern ServerOptions options; char line[8192], file[1024]; int authenticated; unsigned int bits; @@ -125,6 +128,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) struct stat st; RSA *pk; + /* no user given */ + if (pw == NULL) + return 0; + /* Temporarily use the user's uid. */ temporarily_use_uid(pw->pw_uid); @@ -224,6 +231,12 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) } } else options = NULL; + /* + * If our options do not allow this key to be used, + * do not send challenge. + */ + if (!auth_parse_options(pw, options, linenum)) + continue; /* Parse the key from the line. */ if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) { @@ -262,9 +275,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) * Break out of the loop if authentication was successful; * otherwise continue searching. */ - authenticated = auth_parse_options(pw, options, linenum); - if (authenticated) - break; + authenticated = 1; + break; } /* Restore the privileged uid. */ @@ -277,6 +289,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) if (authenticated) packet_send_debug("RSA authentication accepted."); + else + auth_clear_options(); /* Return authentication result. */ return authenticated; diff --git a/crypto/openssh/auth-skey.c b/crypto/openssh/auth-skey.c index 81dd4c2..95ff6e4 100644 --- a/crypto/openssh/auth-skey.c +++ b/crypto/openssh/auth-skey.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-skey.c,v 1.8 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: auth-skey.c,v 1.9 2000/10/19 16:41:13 deraadt Exp $"); #include "ssh.h" #include "packet.h" @@ -45,7 +45,7 @@ auth_skey_password(struct passwd * pw, const char *password) skeyinfo = skey_fake_keyinfo(pw->pw_name); } if (skeyinfo != NULL) - packet_send_debug(skeyinfo); + packet_send_debug("%s", skeyinfo); /* Try again. */ return 0; } else if (skey_haskey(pw->pw_name) == 0 && diff --git a/crypto/openssh/auth.c b/crypto/openssh/auth.c index 2d4f6d0..182d646 100644 --- a/crypto/openssh/auth.c +++ b/crypto/openssh/auth.c @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth.c,v 1.10 2000/09/07 21:13:36 markus Exp $"); +RCSID("$OpenBSD: auth.c,v 1.11 2000/10/11 20:27:23 markus Exp $"); #include "xmalloc.h" #include "rsa.h" @@ -41,7 +41,6 @@ RCSID("$OpenBSD: auth.c,v 1.10 2000/09/07 21:13:36 markus Exp $"); #include "pty.h" #include "packet.h" #include "buffer.h" -#include "cipher.h" #include "mpaux.h" #include "servconf.h" #include "compat.h" 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/auth1.c b/crypto/openssh/auth1.c index 59df9e3..8d50d28 100644 --- a/crypto/openssh/auth1.c +++ b/crypto/openssh/auth1.c @@ -10,14 +10,13 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth1.c,v 1.4 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: auth1.c,v 1.6 2000/10/11 20:27:23 markus Exp $"); #include "xmalloc.h" #include "rsa.h" #include "ssh.h" #include "packet.h" #include "buffer.h" -#include "cipher.h" #include "mpaux.h" #include "servconf.h" #include "compat.h" @@ -58,78 +57,16 @@ get_authname(int type) } /* - * The user does not exist or access is denied, - * but fake indication that authentication is needed. + * read packets and try to authenticate local user 'luser'. + * return if authentication is successfull. not that pw == NULL + * if the user does not exists or is not allowed to login. + * each auth method has to 'fake' authentication for nonexisting + * users. */ void -do_fake_authloop1(char *user) -{ - int attempt = 0; - - log("Faking authloop for illegal user %.200s from %.200s port %d", - user, - get_remote_ipaddr(), - get_remote_port()); - - /* Indicate that authentication is needed. */ - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - - /* - * Keep reading packets, and always respond with a failure. This is - * to avoid disclosing whether such a user really exists. - */ - for (attempt = 1;; attempt++) { - /* Read a packet. This will not return if the client disconnects. */ - int plen; - int type = packet_read(&plen); -#ifdef SKEY - unsigned int dlen; - char *password, *skeyinfo; - password = NULL; - /* Try to send a fake s/key challenge. */ - if (options.skey_authentication == 1 && - (skeyinfo = skey_fake_keyinfo(user)) != NULL) { - if (type == SSH_CMSG_AUTH_TIS) { - packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); - packet_put_string(skeyinfo, strlen(skeyinfo)); - packet_send(); - packet_write_wait(); - continue; - } else if (type == SSH_CMSG_AUTH_PASSWORD && - options.password_authentication && - (password = packet_get_string(&dlen)) != NULL && - dlen == 5 && - strncasecmp(password, "s/key", 5) == 0 ) { - packet_send_debug(skeyinfo); - } - } - if (password != NULL) - xfree(password); -#endif - if (attempt > AUTH_FAIL_MAX) - packet_disconnect(AUTH_FAIL_MSG, user); - - /* - * Send failure. This should be indistinguishable from a - * failed authentication. - */ - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - } - /* NOTREACHED */ - abort(); -} - -/* - * read packets and try to authenticate local user *pw. - * return if authentication is successfull - */ -void -do_authloop(struct passwd * pw) +do_authloop(struct passwd * pw, char *luser) { + int authenticated = 0; int attempt = 0; unsigned int bits; RSA *client_host_key; @@ -148,7 +85,9 @@ do_authloop(struct passwd * pw) packet_write_wait(); for (attempt = 1;; attempt++) { - int authenticated = 0; + /* default to fail */ + authenticated = 0; + strlcpy(user, "", sizeof user); /* Get a packet from the client. */ @@ -159,7 +98,6 @@ do_authloop(struct passwd * pw) #ifdef AFS case SSH_CMSG_HAVE_KERBEROS_TGT: if (!options.kerberos_tgt_passing) { - /* packet_get_all(); */ verbose("Kerberos tgt passing disabled."); break; } else { @@ -167,14 +105,13 @@ do_authloop(struct passwd * pw) char *tgt = packet_get_string(&dlen); packet_integrity_check(plen, 4 + dlen, type); if (!auth_kerberos_tgt(pw, tgt)) - verbose("Kerberos tgt REFUSED for %s", pw->pw_name); + verbose("Kerberos tgt REFUSED for %.100s", luser); xfree(tgt); } continue; case SSH_CMSG_HAVE_AFS_TOKEN: if (!options.afs_token_passing || !k_hasafs()) { - /* packet_get_all(); */ verbose("AFS token passing disabled."); break; } else { @@ -182,7 +119,7 @@ do_authloop(struct passwd * pw) char *token_string = packet_get_string(&dlen); packet_integrity_check(plen, 4 + dlen, type); if (!auth_afs_token(pw, token_string)) - verbose("AFS token REFUSED for %s", pw->pw_name); + verbose("AFS token REFUSED for %.100s", luser); xfree(token_string); } continue; @@ -204,11 +141,12 @@ do_authloop(struct passwd * pw) memcpy(auth.dat, kdata, auth.length); xfree(kdata); - authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user); - - if (authenticated) { - snprintf(user, sizeof user, " tktuser %s", tkt_user); - xfree(tkt_user); + if (pw != NULL) { + authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user); + if (authenticated) { + snprintf(user, sizeof user, " tktuser %s", tkt_user); + xfree(tkt_user); + } } } break; @@ -228,8 +166,7 @@ do_authloop(struct passwd * pw) client_user = packet_get_string(&ulen); packet_integrity_check(plen, 4 + ulen, type); - /* Try to authenticate using /etc/hosts.equiv and - .rhosts. */ + /* Try to authenticate using /etc/hosts.equiv and .rhosts. */ authenticated = auth_rhosts(pw, client_user); snprintf(user, sizeof user, " ruser %s", client_user); @@ -261,7 +198,7 @@ do_authloop(struct passwd * pw) packet_get_bignum(client_host_key->n, &nlen); if (bits != BN_num_bits(client_host_key->n)) - log("Warning: keysize mismatch for client_host_key: " + verbose("Warning: keysize mismatch for client_host_key: " "actual %d, announced %d", BN_num_bits(client_host_key->n), bits); packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type); @@ -309,16 +246,18 @@ do_authloop(struct passwd * pw) case SSH_CMSG_AUTH_TIS: debug("rcvd SSH_CMSG_AUTH_TIS"); if (options.skey_authentication == 1) { - char *skeyinfo = skey_keyinfo(pw->pw_name); + char *skeyinfo = NULL; + if (pw != NULL) + skey_keyinfo(pw->pw_name); if (skeyinfo == NULL) { - debug("generating fake skeyinfo for %.100s.", pw->pw_name); - skeyinfo = skey_fake_keyinfo(pw->pw_name); + debug("generating fake skeyinfo for %.100s.", luser); + skeyinfo = skey_fake_keyinfo(luser); } if (skeyinfo != NULL) { /* we send our s/key- in tis-challenge messages */ debug("sending challenge '%s'", skeyinfo); packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); - packet_put_string(skeyinfo, strlen(skeyinfo)); + packet_put_cstring(skeyinfo); packet_send(); packet_write_wait(); continue; @@ -331,8 +270,9 @@ do_authloop(struct passwd * pw) char *response = packet_get_string(&dlen); debug("skey response == '%s'", response); packet_integrity_check(plen, 4 + dlen, type); - authenticated = (skey_haskey(pw->pw_name) == 0 && - skey_passcheck(pw->pw_name, response) != -1); + authenticated = (pw != NULL && + skey_haskey(pw->pw_name) == 0 && + skey_passcheck(pw->pw_name, response) != -1); xfree(response); } break; @@ -351,13 +291,15 @@ do_authloop(struct passwd * pw) log("Unknown message during authentication: type %d", type); break; } + if (authenticated && pw == NULL) + fatal("internal error: authenticated for pw == NULL"); /* * Check if the user is logging in as root and root logins * are disallowed. * Note that root login is allowed for forced commands. */ - if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) { + if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) { if (forced_command) { log("Root login accepted for forced command."); } else { @@ -373,10 +315,11 @@ do_authloop(struct passwd * pw) type == SSH_CMSG_AUTH_PASSWORD) authlog = log; - authlog("%s %s for %.200s from %.200s port %d%s", + authlog("%s %s for %s%.100s from %.200s port %d%s", authenticated ? "Accepted" : "Failed", get_authname(type), - pw->pw_uid == 0 ? "ROOT" : pw->pw_name, + pw ? "" : "illegal user ", + pw && pw->pw_uid == 0 ? "ROOT" : luser, get_remote_ipaddr(), get_remote_port(), user); @@ -385,7 +328,7 @@ do_authloop(struct passwd * pw) return; if (attempt > AUTH_FAIL_MAX) - packet_disconnect(AUTH_FAIL_MSG, pw->pw_name); + packet_disconnect(AUTH_FAIL_MSG, luser); /* Send a message indicating that the authentication attempt failed. */ packet_start(SSH_SMSG_FAILURE); @@ -425,29 +368,29 @@ do_authentication() /* Verify that the user is a valid user. */ pw = getpwnam(user); - if (!pw || !allowed_user(pw)) - do_fake_authloop1(user); - xfree(user); - - /* Take a copy of the returned structure. */ - memset(&pwcopy, 0, sizeof(pwcopy)); - pwcopy.pw_name = xstrdup(pw->pw_name); - pwcopy.pw_passwd = xstrdup(pw->pw_passwd); - pwcopy.pw_uid = pw->pw_uid; - pwcopy.pw_gid = pw->pw_gid; - pwcopy.pw_class = xstrdup(pw->pw_class); - pwcopy.pw_dir = xstrdup(pw->pw_dir); - pwcopy.pw_shell = xstrdup(pw->pw_shell); - pw = &pwcopy; + if (pw && allowed_user(pw)) { + /* Take a copy of the returned structure. */ + memset(&pwcopy, 0, sizeof(pwcopy)); + pwcopy.pw_name = xstrdup(pw->pw_name); + pwcopy.pw_passwd = xstrdup(pw->pw_passwd); + pwcopy.pw_uid = pw->pw_uid; + pwcopy.pw_gid = pw->pw_gid; + pwcopy.pw_class = xstrdup(pw->pw_class); + pwcopy.pw_dir = xstrdup(pw->pw_dir); + pwcopy.pw_shell = xstrdup(pw->pw_shell); + pw = &pwcopy; + } else { + pw = NULL; + } /* * If we are not running as root, the user must have the same uid as * the server. */ - if (getuid() != 0 && pw->pw_uid != getuid()) + if (getuid() != 0 && pw && pw->pw_uid != getuid()) packet_disconnect("Cannot change user when server not running as root."); - debug("Attempting authentication for %.100s.", pw->pw_name); + debug("Attempting authentication for %s%.100s.", pw ? "" : "illegal user ", user); /* If the user has no password, accept authentication immediately. */ if (options.password_authentication && @@ -457,13 +400,15 @@ do_authentication() auth_password(pw, "")) { /* Authentication with empty password succeeded. */ log("Login for user %s from %.100s, accepted without authentication.", - pw->pw_name, get_remote_ipaddr()); + user, get_remote_ipaddr()); } else { /* Loop until the user has been authenticated or the connection is closed, do_authloop() returns only if authentication is successfull */ - do_authloop(pw); + do_authloop(pw, user); } + if (pw == NULL) + fatal("internal error, authentication successfull for user '%.100s'", user); /* The user has been authenticated and accepted. */ packet_start(SSH_SMSG_SUCCESS); 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/auth2.c b/crypto/openssh/auth2.c index f2d7428..b20f712 100644 --- a/crypto/openssh/auth2.c +++ b/crypto/openssh/auth2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); #include <openssl/dsa.h> #include <openssl/rsa.h> @@ -35,7 +35,6 @@ RCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $"); #include "pty.h" #include "packet.h" #include "buffer.h" -#include "cipher.h" #include "servconf.h" #include "compat.h" #include "channels.h" @@ -57,54 +56,77 @@ extern ServerOptions options; extern unsigned char *session_id2; extern int session_id2_len; +static Authctxt *x_authctxt = NULL; +static int one = 1; + +typedef struct Authmethod Authmethod; +struct Authmethod { + char *name; + int (*userauth)(Authctxt *authctxt); + int *enabled; +}; + /* protocol */ -void input_service_request(int type, int plen); -void input_userauth_request(int type, int plen); -void protocol_error(int type, int plen); +void input_service_request(int type, int plen, void *ctxt); +void input_userauth_request(int type, int plen, void *ctxt); +void protocol_error(int type, int plen, void *ctxt); -/* auth */ -int ssh2_auth_none(struct passwd *pw); -int ssh2_auth_password(struct passwd *pw); -int ssh2_auth_pubkey(struct passwd *pw, char *service); /* helper */ -struct passwd* auth_set_user(char *u, char *s); +Authmethod *authmethod_lookup(const char *name); +struct passwd *pwcopy(struct passwd *pw); int user_dsa_key_allowed(struct passwd *pw, Key *key); +char *authmethods_get(void); -typedef struct Authctxt Authctxt; -struct Authctxt { - char *user; - char *service; - struct passwd pw; - int valid; +/* auth */ +int userauth_none(Authctxt *authctxt); +int userauth_passwd(Authctxt *authctxt); +int userauth_pubkey(Authctxt *authctxt); +int userauth_kbdint(Authctxt *authctxt); + +Authmethod authmethods[] = { + {"none", + userauth_none, + &one}, + {"publickey", + userauth_pubkey, + &options.dsa_authentication}, + {"keyboard-interactive", + userauth_kbdint, + &options.kbd_interactive_authentication}, + {"password", + userauth_passwd, + &options.password_authentication}, + {NULL, NULL, NULL} }; -static Authctxt *authctxt = NULL; -static int userauth_success = 0; /* - * loop until userauth_success == TRUE + * loop until authctxt->success == TRUE */ void do_authentication2() { - /* turn off skey/kerberos, not supported by SSH2 */ -#ifdef SKEY - options.skey_authentication = 0; -#endif + Authctxt *authctxt = xmalloc(sizeof(*authctxt)); + memset(authctxt, 'a', sizeof(*authctxt)); + authctxt->valid = 0; + authctxt->attempt = 0; + authctxt->success = 0; + x_authctxt = authctxt; /*XXX*/ + #ifdef KRB4 + /* turn off kerberos, not supported by SSH2 */ options.kerberos_authentication = 0; #endif - dispatch_init(&protocol_error); dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); - dispatch_run(DISPATCH_BLOCK, &userauth_success); + dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); do_authenticated2(); } void -protocol_error(int type, int plen) +protocol_error(int type, int plen, void *ctxt) { log("auth: protocol error: type %d plen %d", type, plen); packet_start(SSH2_MSG_UNIMPLEMENTED); @@ -114,15 +136,19 @@ protocol_error(int type, int plen) } void -input_service_request(int type, int plen) +input_service_request(int type, int plen, void *ctxt) { + Authctxt *authctxt = ctxt; unsigned int len; int accept = 0; char *service = packet_get_string(&len); packet_done(); + if (authctxt == NULL) + fatal("input_service_request: no authctxt"); + if (strcmp(service, "ssh-userauth") == 0) { - if (!userauth_success) { + if (!authctxt->success) { accept = 1; /* now we can handle user-auth requests */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); @@ -143,47 +169,89 @@ input_service_request(int type, int plen) } void -input_userauth_request(int type, int plen) +input_userauth_request(int type, int plen, void *ctxt) { - static void (*authlog) (const char *fmt,...) = verbose; - static int attempt = 0; - unsigned int len; + Authctxt *authctxt = ctxt; + Authmethod *m = NULL; + char *user, *service, *method; int authenticated = 0; - char *user, *service, *method, *authmsg = NULL; - struct passwd *pw; - if (++attempt == AUTH_FAIL_MAX) + if (authctxt == NULL) + fatal("input_userauth_request: no authctxt"); + if (authctxt->attempt++ >= AUTH_FAIL_MAX) packet_disconnect("too many failed userauth_requests"); - user = packet_get_string(&len); - service = packet_get_string(&len); - method = packet_get_string(&len); + user = packet_get_string(NULL); + service = packet_get_string(NULL); + method = packet_get_string(NULL); debug("userauth-request for user %s service %s method %s", user, service, method); - - /* XXX we only allow the ssh-connection service */ - pw = auth_set_user(user, service); - if (pw && strcmp(service, "ssh-connection")==0) { - if (strcmp(method, "none") == 0) { - authenticated = ssh2_auth_none(pw); - } else if (strcmp(method, "password") == 0) { - authenticated = ssh2_auth_password(pw); - } else if (strcmp(method, "publickey") == 0) { - authenticated = ssh2_auth_pubkey(pw, service); + debug("attempt #%d", authctxt->attempt); + + if (authctxt->attempt == 1) { + /* setup auth context */ + struct passwd *pw = NULL; + setproctitle("%s", user); + pw = getpwnam(user); + if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { + authctxt->pw = pwcopy(pw); + authctxt->valid = 1; + debug2("input_userauth_request: setting up authctxt for %s", user); + } else { + log("input_userauth_request: illegal user %s", user); } + authctxt->user = xstrdup(user); + authctxt->service = xstrdup(service); + } else if (authctxt->valid) { + if (strcmp(user, authctxt->user) != 0 || + strcmp(service, authctxt->service) != 0) { + log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)", + user, service, authctxt->user, authctxt->service); + authctxt->valid = 0; + } + } + + m = authmethod_lookup(method); + if (m != NULL) { + debug2("input_userauth_request: try method %s", method); + authenticated = m->userauth(authctxt); + } else { + debug2("input_userauth_request: unsupported method %s", method); } - if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) { + if (!authctxt->valid && authenticated == 1) { + log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method); + authenticated = 0; + } + + /* Special handling for root */ + if (authenticated == 1 && + authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) { authenticated = 0; - log("ROOT LOGIN REFUSED FROM %.200s", - get_canonical_hostname()); + log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname()); } + /* Log before sending the reply */ + userauth_log(authctxt, authenticated, method); + userauth_reply(authctxt, authenticated); + + xfree(service); + xfree(user); + xfree(method); +} + + +void +userauth_log(Authctxt *authctxt, int authenticated, char *method) +{ + void (*authlog) (const char *fmt,...) = verbose; + char *user = NULL, *authmsg = NULL; + /* Raise logging level */ if (authenticated == 1 || - attempt == AUTH_FAIL_LOG || + !authctxt->valid || + authctxt->attempt >= AUTH_FAIL_LOG || strcmp(method, "password") == 0) authlog = log; - /* Log before sending the reply */ if (authenticated == 1) { authmsg = "Accepted"; } else if (authenticated == 0) { @@ -191,13 +259,24 @@ input_userauth_request(int type, int plen) } else { authmsg = "Postponed"; } + + if (authctxt->valid) { + user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user; + } else { + user = "NOUSER"; + } + authlog("%s %s for %.200s from %.200s port %d ssh2", - authmsg, - method, - pw && pw->pw_uid == 0 ? "ROOT" : user, - get_remote_ipaddr(), - get_remote_port()); + authmsg, + method, + user, + get_remote_ipaddr(), + get_remote_port()); +} +void +userauth_reply(Authctxt *authctxt, int authenticated) +{ /* XXX todo: check if multiple auth methods are needed */ if (authenticated == 1) { /* turn off userauth */ @@ -206,28 +285,33 @@ input_userauth_request(int type, int plen) packet_send(); packet_write_wait(); /* now we can break out */ - userauth_success = 1; + authctxt->success = 1; } else if (authenticated == 0) { + char *methods = authmethods_get(); packet_start(SSH2_MSG_USERAUTH_FAILURE); - packet_put_cstring("publickey,password"); /* XXX dynamic */ - packet_put_char(0); /* XXX partial success, unused */ + packet_put_cstring(methods); + packet_put_char(0); /* XXX partial success, unused */ packet_send(); packet_write_wait(); + xfree(methods); + } else { + /* do nothing, we did already send a reply */ } - - xfree(service); - xfree(user); - xfree(method); } int -ssh2_auth_none(struct passwd *pw) +userauth_none(Authctxt *authctxt) { + /* disable method "none", only allowed one time */ + Authmethod *m = authmethod_lookup("none"); + if (m != NULL) + m->enabled = NULL; packet_done(); - return auth_password(pw, ""); + return authctxt->valid ? auth_password(authctxt->pw, "") : 0; } + int -ssh2_auth_password(struct passwd *pw) +userauth_passwd(Authctxt *authctxt) { char *password; int authenticated = 0; @@ -238,15 +322,38 @@ ssh2_auth_password(struct passwd *pw) log("password change not supported"); password = packet_get_string(&len); packet_done(); - if (options.password_authentication && - auth_password(pw, password) == 1) + if (authctxt->valid && + auth_password(authctxt->pw, password) == 1) authenticated = 1; memset(password, 0, len); xfree(password); return authenticated; } + +int +userauth_kbdint(Authctxt *authctxt) +{ + int authenticated = 0; + char *lang = NULL; + char *devs = NULL; + + lang = packet_get_string(NULL); + devs = packet_get_string(NULL); + packet_done(); + + debug("keyboard-interactive language %s devs %s", lang, devs); +#ifdef SKEY + /* XXX hardcoded, we should look at devs */ + if (options.skey_authentication != 0) + authenticated = auth2_skey(authctxt); +#endif + xfree(lang); + xfree(devs); + return authenticated; +} + int -ssh2_auth_pubkey(struct passwd *pw, char *service) +userauth_pubkey(Authctxt *authctxt) { Buffer b; Key *key; @@ -255,15 +362,15 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) int have_sig; int authenticated = 0; - if (options.dsa_authentication == 0) { - debug("pubkey auth disabled"); + if (!authctxt->valid) { + debug2("userauth_pubkey: disabled because of invalid user"); return 0; } have_sig = packet_get_char(); pkalg = packet_get_string(&alen); if (strcmp(pkalg, KEX_DSS) != 0) { - xfree(pkalg); log("bad pkalg %s", pkalg); /*XXX*/ + xfree(pkalg); return 0; } pkblob = packet_get_string(&blen); @@ -273,18 +380,18 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) sig = packet_get_string(&slen); packet_done(); buffer_init(&b); - if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) { - buffer_put_string(&b, session_id2, session_id2_len); - } else { + if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); + } else { + buffer_put_string(&b, session_id2, session_id2_len); } /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); - buffer_put_cstring(&b, pw->pw_name); + buffer_put_cstring(&b, authctxt->user); buffer_put_cstring(&b, datafellows & SSH_BUG_PUBKEYAUTH ? "ssh-userauth" : - service); + authctxt->service); buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, KEX_DSS); @@ -293,15 +400,15 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) buffer_dump(&b); #endif /* test for correct signature */ - if (user_dsa_key_allowed(pw, key) && + if (user_dsa_key_allowed(authctxt->pw, key) && dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) authenticated = 1; buffer_clear(&b); xfree(sig); } else { + debug("test whether pkalg/pkblob are acceptable"); packet_done(); - debug("test key..."); - /* test whether pkalg/pkblob are acceptable */ + /* XXX fake reply and always send PK_OK ? */ /* * XXX this allows testing whether a user is allowed @@ -310,7 +417,7 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) * if a user is not allowed to login. is this an * issue? -markus */ - if (user_dsa_key_allowed(pw, key)) { + if (user_dsa_key_allowed(authctxt->pw, key)) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); @@ -319,6 +426,8 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) authenticated = -1; } } + if (authenticated != 1) + auth_clear_options(); key_free(key); } xfree(pkalg); @@ -326,49 +435,60 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) return authenticated; } -/* set and get current user */ +/* get current user */ struct passwd* auth_get_user(void) { - return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL; + return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; } -struct passwd* -auth_set_user(char *u, char *s) +#define DELIM "," + +char * +authmethods_get(void) { - struct passwd *pw, *copy; - - if (authctxt == NULL) { - authctxt = xmalloc(sizeof(*authctxt)); - authctxt->valid = 0; - authctxt->user = xstrdup(u); - authctxt->service = xstrdup(s); - setproctitle("%s", u); - pw = getpwnam(u); - if (!pw || !allowed_user(pw)) { - log("auth_set_user: illegal user %s", u); - return NULL; + Authmethod *method = NULL; + unsigned int size = 0; + char *list; + + for (method = authmethods; method->name != NULL; method++) { + if (strcmp(method->name, "none") == 0) + continue; + if (method->enabled != NULL && *(method->enabled) != 0) { + if (size != 0) + size += strlen(DELIM); + size += strlen(method->name); } - copy = &authctxt->pw; - memset(copy, 0, sizeof(*copy)); - copy->pw_name = xstrdup(pw->pw_name); - copy->pw_passwd = xstrdup(pw->pw_passwd); - copy->pw_uid = pw->pw_uid; - copy->pw_gid = pw->pw_gid; - copy->pw_class = xstrdup(pw->pw_class); - copy->pw_dir = xstrdup(pw->pw_dir); - copy->pw_shell = xstrdup(pw->pw_shell); - authctxt->valid = 1; - } else { - if (strcmp(u, authctxt->user) != 0 || - strcmp(s, authctxt->service) != 0) { - log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)", - u, s, authctxt->user, authctxt->service); - return NULL; + } + size++; /* trailing '\0' */ + list = xmalloc(size); + list[0] = '\0'; + + for (method = authmethods; method->name != NULL; method++) { + if (strcmp(method->name, "none") == 0) + continue; + if (method->enabled != NULL && *(method->enabled) != 0) { + if (list[0] != '\0') + strlcat(list, DELIM, size); + strlcat(list, method->name, size); } } - return auth_get_user(); + return list; +} + +Authmethod * +authmethod_lookup(const char *name) +{ + Authmethod *method = NULL; + if (name != NULL) + for (method = authmethods; method->name != NULL; method++) + if (method->enabled != NULL && + *(method->enabled) != 0 && + strcmp(name, method->name) == 0) + return method; + debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); + return NULL; } /* return 1 if user allows given key */ @@ -383,6 +503,9 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) struct stat st; Key *found; + if (pw == NULL) + return 0; + /* Temporarily use the user's uid. */ temporarily_use_uid(pw->pw_uid); @@ -410,8 +533,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) if (fstat(fileno(f), &st) < 0 || (st.st_uid != 0 && st.st_uid != pw->pw_uid) || (st.st_mode & 022) != 0) { - snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: " - "bad ownership or modes for '%s'.", pw->pw_name, file); + snprintf(buf, sizeof buf, + "%s authentication refused for %.100s: " + "bad ownership or modes for '%s'.", + key_type(key), pw->pw_name, file); fail = 1; } else { /* Check path to SSH_USER_PERMITTED_KEYS */ @@ -426,9 +551,9 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) (st.st_uid != 0 && st.st_uid != pw->pw_uid) || (st.st_mode & 022) != 0) { snprintf(buf, sizeof buf, - "DSA authentication refused for %.100s: " + "%s authentication refused for %.100s: " "bad ownership or modes for '%s'.", - pw->pw_name, line); + key_type(key), pw->pw_name, line); fail = 1; break; } @@ -442,7 +567,7 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) } } found_key = 0; - found = key_new(KEY_DSA); + found = key_new(key->type); while (fgets(line, sizeof(line), f)) { char *cp, *options = NULL; @@ -486,3 +611,18 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) key_free(found); return found_key; } + +struct passwd * +pwcopy(struct passwd *pw) +{ + struct passwd *copy = xmalloc(sizeof(*copy)); + memset(copy, 0, sizeof(*copy)); + copy->pw_name = xstrdup(pw->pw_name); + copy->pw_passwd = xstrdup(pw->pw_passwd); + copy->pw_uid = pw->pw_uid; + copy->pw_gid = pw->pw_gid; + copy->pw_class = xstrdup(pw->pw_class); + copy->pw_dir = xstrdup(pw->pw_dir); + copy->pw_shell = xstrdup(pw->pw_shell); + return copy; +} diff --git a/crypto/openssh/authfd.c b/crypto/openssh/authfd.c index 9586385..d62b8d6 100644 --- a/crypto/openssh/authfd.c +++ b/crypto/openssh/authfd.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfd.c,v 1.27 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $"); #include "ssh.h" #include "rsa.h" @@ -51,10 +51,15 @@ RCSID("$OpenBSD: authfd.c,v 1.27 2000/09/07 20:27:49 deraadt Exp $"); #include "authfd.h" #include "kex.h" #include "dsa.h" +#include "compat.h" /* helper */ int decode_reply(int type); +/* macro to check for "agent failure" message */ +#define agent_failed(x) \ + ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE)) + /* Returns the number of the authentication fd, or -1 if there is none. */ int @@ -237,7 +242,7 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi /* Get message type, and verify that we got a proper answer. */ type = buffer_get_char(&auth->identities); - if (type == SSH_AGENT_FAILURE) { + if (agent_failed(type)) { return NULL; } else if (type != code2) { fatal("Bad authentication reply message type: %d", type); @@ -336,7 +341,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth, } type = buffer_get_char(&buffer); - if (type == SSH_AGENT_FAILURE) { + if (agent_failed(type)) { log("Agent admitted failure to authenticate using the key."); } else if (type != SSH_AGENT_RSA_RESPONSE) { fatal("Bad authentication response: %d", type); @@ -360,20 +365,24 @@ ssh_agent_sign(AuthenticationConnection *auth, unsigned char **sigp, int *lenp, unsigned char *data, int datalen) { + extern int datafellows; Buffer msg; unsigned char *blob; unsigned int blen; - int type; + int type, flags = 0; int ret = -1; if (dsa_make_key_blob(key, &blob, &blen) == 0) return -1; + if (datafellows & SSH_BUG_SIGBLOB) + flags = SSH_AGENT_OLD_SIGNATURE; + buffer_init(&msg); buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); buffer_put_string(&msg, blob, blen); buffer_put_string(&msg, data, datalen); - buffer_put_int(&msg, 0); /* flags, unused */ + buffer_put_int(&msg, flags); xfree(blob); if (ssh_request_reply(auth, &msg, &msg) == 0) { @@ -381,7 +390,7 @@ ssh_agent_sign(AuthenticationConnection *auth, return -1; } type = buffer_get_char(&msg); - if (type == SSH_AGENT_FAILURE) { + if (agent_failed(type)) { log("Agent admitted failure to sign using the key."); } else if (type != SSH2_AGENT_SIGN_RESPONSE) { fatal("Bad authentication response: %d", type); @@ -528,6 +537,7 @@ decode_reply(int type) { switch (type) { case SSH_AGENT_FAILURE: + case SSH_COM_AGENT2_FAILURE: log("SSH_AGENT_FAILURE"); return 0; case SSH_AGENT_SUCCESS: 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.c b/crypto/openssh/authfile.c index bd6fee0..fdeab80 100644 --- a/crypto/openssh/authfile.c +++ b/crypto/openssh/authfile.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfile.c,v 1.19 2000/09/07 20:27:49 deraadt Exp $"); +RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $"); #include <openssl/bn.h> #include <openssl/dsa.h> @@ -47,7 +47,6 @@ RCSID("$OpenBSD: authfile.c,v 1.19 2000/09/07 20:27:49 deraadt Exp $"); #include "xmalloc.h" #include "buffer.h" #include "bufaux.h" -#include "cipher.h" #include "ssh.h" #include "key.h" @@ -68,8 +67,8 @@ save_private_key_rsa(const char *filename, const char *passphrase, Buffer buffer, encrypted; char buf[100], *cp; int fd, i; - CipherContext cipher; - int cipher_type; + CipherContext ciphercontext; + Cipher *cipher; u_int32_t rand; /* @@ -77,9 +76,11 @@ save_private_key_rsa(const char *filename, const char *passphrase, * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. */ if (strcmp(passphrase, "") == 0) - cipher_type = SSH_CIPHER_NONE; + cipher = cipher_by_number(SSH_CIPHER_NONE); else - cipher_type = SSH_AUTHFILE_CIPHER; + cipher = cipher_by_number(SSH_AUTHFILE_CIPHER); + if (cipher == NULL) + fatal("save_private_key_rsa: bad cipher"); /* This buffer is used to built the secret part of the private key. */ buffer_init(&buffer); @@ -116,7 +117,7 @@ save_private_key_rsa(const char *filename, const char *passphrase, buffer_put_char(&encrypted, 0); /* Store cipher type. */ - buffer_put_char(&encrypted, cipher_type); + buffer_put_char(&encrypted, cipher->number); buffer_put_int(&encrypted, 0); /* For future extension */ /* Store public key. This will be in plain text. */ @@ -128,11 +129,10 @@ save_private_key_rsa(const char *filename, const char *passphrase, /* Allocate space for the private part of the key in the buffer. */ buffer_append_space(&encrypted, &cp, buffer_len(&buffer)); - cipher_set_key_string(&cipher, cipher_type, passphrase); - cipher_encrypt(&cipher, (unsigned char *) cp, - (unsigned char *) buffer_ptr(&buffer), - buffer_len(&buffer)); - memset(&cipher, 0, sizeof(cipher)); + cipher_set_key_string(&ciphercontext, cipher, passphrase); + cipher_encrypt(&ciphercontext, (unsigned char *) cp, + (unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer)); + memset(&ciphercontext, 0, sizeof(ciphercontext)); /* Destroy temporary data. */ memset(buf, 0, sizeof(buf)); @@ -313,7 +313,8 @@ load_private_key_rsa(int fd, const char *filename, off_t len; Buffer buffer, decrypted; char *cp; - CipherContext cipher; + CipherContext ciphercontext; + Cipher *cipher; BN_CTX *ctx; BIGNUM *aux; @@ -364,10 +365,10 @@ load_private_key_rsa(int fd, const char *filename, xfree(buffer_get_string(&buffer, NULL)); /* Check that it is a supported cipher. */ - if (((cipher_mask1() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) & - (1 << cipher_type)) == 0) { - debug("Unsupported cipher %.100s used in key file %.200s.", - cipher_name(cipher_type), filename); + cipher = cipher_by_number(cipher_type); + if (cipher == NULL) { + debug("Unsupported cipher %d used in key file %.200s.", + cipher_type, filename); buffer_free(&buffer); goto fail; } @@ -376,11 +377,10 @@ load_private_key_rsa(int fd, const char *filename, buffer_append_space(&decrypted, &cp, buffer_len(&buffer)); /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ - cipher_set_key_string(&cipher, cipher_type, passphrase); - cipher_decrypt(&cipher, (unsigned char *) cp, - (unsigned char *) buffer_ptr(&buffer), - buffer_len(&buffer)); - + cipher_set_key_string(&ciphercontext, cipher, passphrase); + cipher_decrypt(&ciphercontext, (unsigned char *) cp, + (unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer)); + memset(&ciphercontext, 0, sizeof(ciphercontext)); buffer_free(&buffer); check1 = buffer_get_char(&decrypted); 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/canohost.c b/crypto/openssh/canohost.c index ff8da0e..1f4e9ad 100644 --- a/crypto/openssh/canohost.c +++ b/crypto/openssh/canohost.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: canohost.c,v 1.15 2000/09/07 21:13:37 markus Exp $"); +RCSID("$OpenBSD: canohost.c,v 1.16 2000/10/21 17:04:22 markus Exp $"); #include "packet.h" #include "xmalloc.h" @@ -123,7 +123,7 @@ check_ip_options: else ipproto = IPPROTO_IP; option_size = sizeof(options); - if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options, + if (getsockopt(socket, ipproto, IP_OPTIONS, (char *) options, &option_size) >= 0 && option_size != 0) { cp = text; /* Note: "text" buffer must be at least 3x as big as options. */ 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/cipher.c b/crypto/openssh/cipher.c index 899f052..65cde47 100644 --- a/crypto/openssh/cipher.c +++ b/crypto/openssh/cipher.c @@ -35,14 +35,91 @@ */ #include "includes.h" -RCSID("$OpenBSD: cipher.c,v 1.30 2000/09/07 20:27:50 deraadt Exp $"); +RCSID("$OpenBSD: cipher.c,v 1.37 2000/10/23 19:31:54 markus Exp $"); #include "ssh.h" -#include "cipher.h" #include "xmalloc.h" #include <openssl/md5.h> + +/* no encryption */ +void +none_setkey(CipherContext *cc, const u_char *key, u_int keylen) +{ +} +void +none_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) +{ +} +void +none_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + memcpy(dest, src, len); +} + +/* DES */ +void +des_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen) +{ + static int dowarn = 1; + if (dowarn) { + error("Warning: use of DES is strongly discouraged " + "due to cryptographic weaknesses"); + dowarn = 0; + } + des_set_key((void *)key, cc->u.des.key); +} +void +des_ssh1_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) +{ + memset(cc->u.des.iv, 0, sizeof(cc->u.des.iv)); +} +void +des_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv, + DES_ENCRYPT); +} +void +des_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv, + DES_DECRYPT); +} + +/* 3DES */ +void +des3_setkey(CipherContext *cc, const u_char *key, u_int keylen) +{ + des_set_key((void *) key, cc->u.des3.key1); + des_set_key((void *) (key+8), cc->u.des3.key2); + des_set_key((void *) (key+16), cc->u.des3.key3); +} +void +des3_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) +{ + memset(cc->u.des3.iv2, 0, sizeof(cc->u.des3.iv2)); + memset(cc->u.des3.iv3, 0, sizeof(cc->u.des3.iv3)); + if (iv == NULL) + return; + memcpy(cc->u.des3.iv3, (char *)iv, 8); +} +void +des3_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + des_ede3_cbc_encrypt(src, dest, len, + cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3, + &cc->u.des3.iv3, DES_ENCRYPT); +} +void +des3_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + des_ede3_cbc_encrypt(src, dest, len, + cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3, + &cc->u.des3.iv3, DES_DECRYPT); +} + /* * This is used by SSH1: * @@ -58,160 +135,356 @@ RCSID("$OpenBSD: cipher.c,v 1.30 2000/09/07 20:27:50 deraadt Exp $"); * choosing the X block. */ void -SSH_3CBC_ENCRYPT(des_key_schedule ks1, - des_key_schedule ks2, des_cblock * iv2, - des_key_schedule ks3, des_cblock * iv3, - unsigned char *dest, unsigned char *src, - unsigned int len) +des3_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen) +{ + des_set_key((void *) key, cc->u.des3.key1); + des_set_key((void *) (key+8), cc->u.des3.key2); + if (keylen <= 16) + des_set_key((void *) key, cc->u.des3.key3); + else + des_set_key((void *) (key+16), cc->u.des3.key3); +} +void +des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, + u_int len) { des_cblock iv1; + des_cblock *iv2 = &cc->u.des3.iv2; + des_cblock *iv3 = &cc->u.des3.iv3; memcpy(&iv1, iv2, 8); - des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT); + des_cbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT); memcpy(&iv1, dest + len - 8, 8); - des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT); + des_cbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT); memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */ - des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT); + des_cbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT); memcpy(iv3, dest + len - 8, 8); } - void -SSH_3CBC_DECRYPT(des_key_schedule ks1, - des_key_schedule ks2, des_cblock * iv2, - des_key_schedule ks3, des_cblock * iv3, - unsigned char *dest, unsigned char *src, - unsigned int len) +des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, + u_int len) { des_cblock iv1; + des_cblock *iv2 = &cc->u.des3.iv2; + des_cblock *iv3 = &cc->u.des3.iv3; memcpy(&iv1, iv2, 8); - des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT); + des_cbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT); memcpy(iv3, src + len - 8, 8); - des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT); + des_cbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT); memcpy(iv2, dest + len - 8, 8); - des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT); + des_cbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT); /* memcpy(&iv1, iv2, 8); */ /* Note how iv1 == iv2 on entry and exit. */ } +/* Blowfish */ +void +blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen) +{ + BF_set_key(&cc->u.bf.key, keylen, (unsigned char *)key); +} +void +blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) +{ + if (iv == NULL) + memset(cc->u.bf.iv, 0, 8); + else + memcpy(cc->u.bf.iv, (char *)iv, 8); +} +void +blowfish_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, + u_int len) +{ + BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv, + BF_ENCRYPT); +} +void +blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, + u_int len) +{ + BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv, + BF_DECRYPT); +} + /* * SSH1 uses a variation on Blowfish, all bytes must be swapped before * and after encryption/decryption. Thus the swap_bytes stuff (yuk). */ static void -swap_bytes(const unsigned char *src, unsigned char *dst_, int n) -{ - /* dst must be properly aligned. */ - u_int32_t *dst = (u_int32_t *) dst_; - union { - u_int32_t i; - char c[4]; - } t; - - /* Process 8 bytes every lap. */ - for (n = n / 8; n > 0; n--) { - t.c[3] = *src++; - t.c[2] = *src++; - t.c[1] = *src++; - t.c[0] = *src++; - *dst++ = t.i; - - t.c[3] = *src++; - t.c[2] = *src++; - t.c[1] = *src++; - t.c[0] = *src++; - *dst++ = t.i; +swap_bytes(const unsigned char *src, unsigned char *dst, int n) +{ + char c[4]; + + /* Process 4 bytes every lap. */ + for (n = n / 4; n > 0; n--) { + c[3] = *src++; + c[2] = *src++; + c[1] = *src++; + c[0] = *src++; + + *dst++ = c[0]; + *dst++ = c[1]; + *dst++ = c[2]; + *dst++ = c[3]; } } -/* - * Names of all encryption algorithms. - * These must match the numbers defined in cipher.h. - */ -static char *cipher_names[] = -{ - "none", - "idea", - "des", - "3des", - "tss", - "rc4", - "blowfish", - "reserved", - "blowfish-cbc", - "3des-cbc", - "arcfour", - "cast128-cbc" -}; +void +blowfish_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, + u_int len) +{ + swap_bytes(src, dest, len); + BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv, + BF_ENCRYPT); + swap_bytes(dest, dest, len); +} +void +blowfish_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, + u_int len) +{ + swap_bytes(src, dest, len); + BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv, + BF_DECRYPT); + swap_bytes(dest, dest, len); +} -/* - * Returns a bit mask indicating which ciphers are supported by this - * implementation. The bit mask has the corresponding bit set of each - * supported cipher. - */ +/* alleged rc4 */ +void +arcfour_setkey(CipherContext *cc, const u_char *key, u_int keylen) +{ + RC4_set_key(&cc->u.rc4, keylen, (u_char *)key); +} +void +arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + RC4(&cc->u.rc4, len, (u_char *)src, dest); +} -unsigned int -cipher_mask1() +/* CAST */ +void +cast_setkey(CipherContext *cc, const u_char *key, u_int keylen) { - unsigned int mask = 0; - mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ - mask |= 1 << SSH_CIPHER_BLOWFISH; - return mask; + CAST_set_key(&cc->u.cast.key, keylen, (unsigned char *) key); +} +void +cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) +{ + if (iv == NULL) + fatal("no IV for %s.", cc->cipher->name); + memcpy(cc->u.cast.iv, (char *)iv, 8); +} +void +cast_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv, + CAST_ENCRYPT); +} +void +cast_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv, + CAST_DECRYPT); +} + +/* RIJNDAEL */ + +#define RIJNDAEL_BLOCKSIZE 16 +void +rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen) +{ + rijndael_set_key(&cc->u.rijndael.enc, (u4byte *)key, 8*keylen, 1); + rijndael_set_key(&cc->u.rijndael.dec, (u4byte *)key, 8*keylen, 0); +} +void +rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) +{ + if (iv == NULL) + fatal("no IV for %s.", cc->cipher->name); + memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE); } +void +rijndael_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, + u_int len) +{ + rijndael_ctx *ctx = &cc->u.rijndael.enc; + u4byte *iv = cc->u.rijndael.iv; + u4byte in[4]; + u4byte *cprev, *cnow, *plain; + int i, blocks = len / RIJNDAEL_BLOCKSIZE; + if (len == 0) + return; + if (len % RIJNDAEL_BLOCKSIZE) + fatal("rijndael_cbc_encrypt: bad len %d", len); + cnow = (u4byte*) dest; + plain = (u4byte*) src; + cprev = iv; + for(i = 0; i < blocks; i++, plain+=4, cnow+=4) { + in[0] = plain[0] ^ cprev[0]; + in[1] = plain[1] ^ cprev[1]; + in[2] = plain[2] ^ cprev[2]; + in[3] = plain[3] ^ cprev[3]; + rijndael_encrypt(ctx, in, cnow); + cprev = cnow; + } + memcpy(iv, cprev, RIJNDAEL_BLOCKSIZE); +} + +void +rijndael_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, + u_int len) +{ + rijndael_ctx *ctx = &cc->u.rijndael.dec; + u4byte *iv = cc->u.rijndael.iv; + u4byte ivsaved[4]; + u4byte *cnow = (u4byte*) (src+len-RIJNDAEL_BLOCKSIZE); + u4byte *plain = (u4byte*) (dest+len-RIJNDAEL_BLOCKSIZE); + u4byte *ivp; + int i, blocks = len / RIJNDAEL_BLOCKSIZE; + if (len == 0) + return; + if (len % RIJNDAEL_BLOCKSIZE) + fatal("rijndael_cbc_decrypt: bad len %d", len); + memcpy(ivsaved, cnow, RIJNDAEL_BLOCKSIZE); + for(i = blocks; i > 0; i--, cnow-=4, plain-=4) { + rijndael_decrypt(ctx, cnow, plain); + ivp = (i == 1) ? iv : cnow-4; + plain[0] ^= ivp[0]; + plain[1] ^= ivp[1]; + plain[2] ^= ivp[2]; + plain[3] ^= ivp[3]; + } + memcpy(iv, ivsaved, RIJNDAEL_BLOCKSIZE); +} + +Cipher ciphers[] = { + { "none", + SSH_CIPHER_NONE, 8, 0, + none_setkey, none_setiv, + none_crypt, none_crypt }, + { "des", + SSH_CIPHER_DES, 8, 8, + des_ssh1_setkey, des_ssh1_setiv, + des_ssh1_encrypt, des_ssh1_decrypt }, + { "3des", + SSH_CIPHER_3DES, 8, 16, + des3_ssh1_setkey, des3_setiv, + des3_ssh1_encrypt, des3_ssh1_decrypt }, + { "blowfish", + SSH_CIPHER_BLOWFISH, 8, 16, + blowfish_setkey, blowfish_setiv, + blowfish_ssh1_encrypt, blowfish_ssh1_decrypt }, + + { "3des-cbc", + SSH_CIPHER_SSH2, 8, 24, + des3_setkey, des3_setiv, + des3_cbc_encrypt, des3_cbc_decrypt }, + { "blowfish-cbc", + SSH_CIPHER_SSH2, 8, 16, + blowfish_setkey, blowfish_setiv, + blowfish_cbc_encrypt, blowfish_cbc_decrypt }, + { "cast128-cbc", + SSH_CIPHER_SSH2, 8, 16, + cast_setkey, cast_setiv, + cast_cbc_encrypt, cast_cbc_decrypt }, + { "arcfour", + SSH_CIPHER_SSH2, 8, 16, + arcfour_setkey, none_setiv, + arcfour_crypt, arcfour_crypt }, + { "aes128-cbc", + SSH_CIPHER_SSH2, 16, 16, + rijndael_setkey, rijndael_setiv, + rijndael_cbc_encrypt, rijndael_cbc_decrypt }, + { "aes192-cbc", + SSH_CIPHER_SSH2, 16, 24, + rijndael_setkey, rijndael_setiv, + rijndael_cbc_encrypt, rijndael_cbc_decrypt }, + { "aes256-cbc", + SSH_CIPHER_SSH2, 16, 32, + rijndael_setkey, rijndael_setiv, + rijndael_cbc_encrypt, rijndael_cbc_decrypt }, + { "rijndael128-cbc", + SSH_CIPHER_SSH2, 16, 16, + rijndael_setkey, rijndael_setiv, + rijndael_cbc_encrypt, rijndael_cbc_decrypt }, + { "rijndael192-cbc", + SSH_CIPHER_SSH2, 16, 24, + rijndael_setkey, rijndael_setiv, + rijndael_cbc_encrypt, rijndael_cbc_decrypt }, + { "rijndael256-cbc", + SSH_CIPHER_SSH2, 16, 32, + rijndael_setkey, rijndael_setiv, + rijndael_cbc_encrypt, rijndael_cbc_decrypt }, + { "rijndael-cbc@lysator.liu.se", + SSH_CIPHER_SSH2, 16, 32, + rijndael_setkey, rijndael_setiv, + rijndael_cbc_encrypt, rijndael_cbc_decrypt }, + { NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL } +}; + +/*--*/ + unsigned int -cipher_mask2() +cipher_mask_ssh1(int client) { unsigned int mask = 0; - mask |= 1 << SSH_CIPHER_BLOWFISH_CBC; - mask |= 1 << SSH_CIPHER_3DES_CBC; - mask |= 1 << SSH_CIPHER_ARCFOUR; - mask |= 1 << SSH_CIPHER_CAST128_CBC; + mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ + mask |= 1 << SSH_CIPHER_BLOWFISH; + if (client) { + mask |= 1 << SSH_CIPHER_DES; + } return mask; } -unsigned int -cipher_mask() + +Cipher * +cipher_by_name(const char *name) { - return cipher_mask1() | cipher_mask2(); + Cipher *c; + for (c = ciphers; c->name != NULL; c++) + if (strcasecmp(c->name, name) == 0) + return c; + return NULL; } -/* Returns the name of the cipher. */ - -const char * -cipher_name(int cipher) +Cipher * +cipher_by_number(int id) { - if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) || - cipher_names[cipher] == NULL) - fatal("cipher_name: bad cipher name: %d", cipher); - return cipher_names[cipher]; + Cipher *c; + for (c = ciphers; c->name != NULL; c++) + if (c->number == id) + return c; + return NULL; } -/* Returns 1 if the name of the ciphers are valid. */ - #define CIPHER_SEP "," int ciphers_valid(const char *names) { + Cipher *c; char *ciphers, *cp; char *p; - int i; if (names == NULL || strcmp(names, "") == 0) return 0; ciphers = cp = xstrdup(names); - for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; + for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; (p = strsep(&cp, CIPHER_SEP))) { - i = cipher_number(p); - if (i == -1 || !(cipher_mask2() & (1 << i))) { + c = cipher_by_name(p); + if (c == NULL || c->number != SSH_CIPHER_SSH2) { + debug("bad cipher %s [%s]", p, names); xfree(ciphers); return 0; + } else { + debug3("cipher ok: %s [%s]", p, names); } } + debug3("ciphers ok: [%s]", names); xfree(ciphers); return 1; } @@ -224,14 +497,49 @@ ciphers_valid(const char *names) int cipher_number(const char *name) { - int i; + Cipher *c; if (name == NULL) return -1; - for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++) - if (strcmp(cipher_names[i], name) == 0 && - (cipher_mask() & (1 << i))) - return i; - return -1; + c = cipher_by_name(name); + return (c==NULL) ? -1 : c->number; +} + +char * +cipher_name(int id) +{ + Cipher *c = cipher_by_number(id); + return (c==NULL) ? "<unknown>" : c->name; +} + +void +cipher_init(CipherContext *cc, Cipher *cipher, + const u_char *key, u_int keylen, const u_char *iv, u_int ivlen) +{ + if (keylen < cipher->key_len) + fatal("cipher_init: key length %d is insufficient for %s.", + keylen, cipher->name); + if (iv != NULL && ivlen < cipher->block_size) + fatal("cipher_init: iv length %d is insufficient for %s.", + ivlen, cipher->name); + cc->cipher = cipher; + cipher->setkey(cc, key, keylen); + cipher->setiv(cc, iv, ivlen); +} + +void +cipher_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + if (len % cc->cipher->block_size) + fatal("cipher_encrypt: bad plaintext length %d", len); + cc->cipher->encrypt(cc, dest, src, len); +} + +void +cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + if (len % cc->cipher->block_size) + fatal("cipher_decrypt: bad ciphertext length %d", len); + cc->cipher->decrypt(cc, dest, src, len); } /* @@ -240,248 +548,18 @@ cipher_number(const char *name) */ void -cipher_set_key_string(CipherContext *context, int cipher, const char *passphrase) +cipher_set_key_string(CipherContext *cc, Cipher *cipher, + const char *passphrase) { MD5_CTX md; unsigned char digest[16]; MD5_Init(&md); - MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase)); + MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase)); MD5_Final(digest, &md); - cipher_set_key(context, cipher, digest, 16); + cipher_init(cc, cipher, digest, 16, NULL, 0); memset(digest, 0, sizeof(digest)); memset(&md, 0, sizeof(md)); } - -/* Selects the cipher to use and sets the key. */ - -void -cipher_set_key(CipherContext *context, int cipher, const unsigned char *key, - int keylen) -{ - unsigned char padded[32]; - - /* Set cipher type. */ - context->type = cipher; - - /* Get 32 bytes of key data. Pad if necessary. (So that code - below does not need to worry about key size). */ - memset(padded, 0, sizeof(padded)); - memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded)); - - /* Initialize the initialization vector. */ - switch (cipher) { - case SSH_CIPHER_NONE: - /* - * Has to stay for authfile saving of private key with no - * passphrase - */ - break; - - case SSH_CIPHER_3DES: - /* - * Note: the least significant bit of each byte of key is - * parity, and must be ignored by the implementation. 16 - * bytes of key are used (first and last keys are the same). - */ - if (keylen < 16) - error("Key length %d is insufficient for 3DES.", keylen); - des_set_key((void *) padded, context->u.des3.key1); - des_set_key((void *) (padded + 8), context->u.des3.key2); - if (keylen <= 16) - des_set_key((void *) padded, context->u.des3.key3); - else - des_set_key((void *) (padded + 16), context->u.des3.key3); - memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2)); - memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3)); - break; - - case SSH_CIPHER_BLOWFISH: - if (keylen < 16) - error("Key length %d is insufficient for blowfish.", keylen); - BF_set_key(&context->u.bf.key, keylen, padded); - memset(context->u.bf.iv, 0, 8); - break; - - case SSH_CIPHER_3DES_CBC: - case SSH_CIPHER_BLOWFISH_CBC: - case SSH_CIPHER_ARCFOUR: - case SSH_CIPHER_CAST128_CBC: - fatal("cipher_set_key: illegal cipher: %s", cipher_name(cipher)); - break; - - default: - fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher)); - } - memset(padded, 0, sizeof(padded)); -} - -void -cipher_set_key_iv(CipherContext * context, int cipher, - const unsigned char *key, int keylen, - const unsigned char *iv, int ivlen) -{ - /* Set cipher type. */ - context->type = cipher; - - /* Initialize the initialization vector. */ - switch (cipher) { - case SSH_CIPHER_NONE: - break; - - case SSH_CIPHER_3DES: - case SSH_CIPHER_BLOWFISH: - fatal("cipher_set_key_iv: illegal cipher: %s", cipher_name(cipher)); - break; - - case SSH_CIPHER_3DES_CBC: - if (keylen < 24) - error("Key length %d is insufficient for 3des-cbc.", keylen); - des_set_key((void *) key, context->u.des3.key1); - des_set_key((void *) (key+8), context->u.des3.key2); - des_set_key((void *) (key+16), context->u.des3.key3); - if (ivlen < 8) - error("IV length %d is insufficient for 3des-cbc.", ivlen); - memcpy(context->u.des3.iv3, (char *)iv, 8); - break; - - case SSH_CIPHER_BLOWFISH_CBC: - if (keylen < 16) - error("Key length %d is insufficient for blowfish.", keylen); - if (ivlen < 8) - error("IV length %d is insufficient for blowfish.", ivlen); - BF_set_key(&context->u.bf.key, keylen, (unsigned char *)key); - memcpy(context->u.bf.iv, (char *)iv, 8); - break; - - case SSH_CIPHER_ARCFOUR: - if (keylen < 16) - error("Key length %d is insufficient for arcfour.", keylen); - RC4_set_key(&context->u.rc4, keylen, (unsigned char *)key); - break; - - case SSH_CIPHER_CAST128_CBC: - if (keylen < 16) - error("Key length %d is insufficient for cast128.", keylen); - if (ivlen < 8) - error("IV length %d is insufficient for cast128.", ivlen); - CAST_set_key(&context->u.cast.key, keylen, (unsigned char *) key); - memcpy(context->u.cast.iv, (char *)iv, 8); - break; - - default: - fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher)); - } -} - -/* Encrypts data using the cipher. */ - -void -cipher_encrypt(CipherContext *context, unsigned char *dest, - const unsigned char *src, unsigned int len) -{ - if ((len & 7) != 0) - fatal("cipher_encrypt: bad plaintext length %d", len); - - switch (context->type) { - case SSH_CIPHER_NONE: - memcpy(dest, src, len); - break; - - case SSH_CIPHER_3DES: - SSH_3CBC_ENCRYPT(context->u.des3.key1, - context->u.des3.key2, &context->u.des3.iv2, - context->u.des3.key3, &context->u.des3.iv3, - dest, (unsigned char *) src, len); - break; - - case SSH_CIPHER_BLOWFISH: - swap_bytes(src, dest, len); - BF_cbc_encrypt(dest, dest, len, - &context->u.bf.key, context->u.bf.iv, - BF_ENCRYPT); - swap_bytes(dest, dest, len); - break; - - case SSH_CIPHER_BLOWFISH_CBC: - BF_cbc_encrypt((void *)src, dest, len, - &context->u.bf.key, context->u.bf.iv, - BF_ENCRYPT); - break; - - case SSH_CIPHER_3DES_CBC: - des_ede3_cbc_encrypt(src, dest, len, - context->u.des3.key1, context->u.des3.key2, - context->u.des3.key3, &context->u.des3.iv3, DES_ENCRYPT); - break; - - case SSH_CIPHER_ARCFOUR: - RC4(&context->u.rc4, len, (unsigned char *)src, dest); - break; - - case SSH_CIPHER_CAST128_CBC: - CAST_cbc_encrypt(src, dest, len, - &context->u.cast.key, context->u.cast.iv, CAST_ENCRYPT); - break; - - default: - fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type)); - } -} - -/* Decrypts data using the cipher. */ - -void -cipher_decrypt(CipherContext *context, unsigned char *dest, - const unsigned char *src, unsigned int len) -{ - if ((len & 7) != 0) - fatal("cipher_decrypt: bad ciphertext length %d", len); - - switch (context->type) { - case SSH_CIPHER_NONE: - memcpy(dest, src, len); - break; - - case SSH_CIPHER_3DES: - SSH_3CBC_DECRYPT(context->u.des3.key1, - context->u.des3.key2, &context->u.des3.iv2, - context->u.des3.key3, &context->u.des3.iv3, - dest, (unsigned char *) src, len); - break; - - case SSH_CIPHER_BLOWFISH: - swap_bytes(src, dest, len); - BF_cbc_encrypt((void *) dest, dest, len, - &context->u.bf.key, context->u.bf.iv, - BF_DECRYPT); - swap_bytes(dest, dest, len); - break; - - case SSH_CIPHER_BLOWFISH_CBC: - BF_cbc_encrypt((void *) src, dest, len, - &context->u.bf.key, context->u.bf.iv, - BF_DECRYPT); - break; - - case SSH_CIPHER_3DES_CBC: - des_ede3_cbc_encrypt(src, dest, len, - context->u.des3.key1, context->u.des3.key2, - context->u.des3.key3, &context->u.des3.iv3, DES_DECRYPT); - break; - - case SSH_CIPHER_ARCFOUR: - RC4(&context->u.rc4, len, (unsigned char *)src, dest); - break; - - case SSH_CIPHER_CAST128_CBC: - CAST_cbc_encrypt(src, dest, len, - &context->u.cast.key, context->u.cast.iv, CAST_DECRYPT); - break; - - default: - fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type)); - } -} diff --git a/crypto/openssh/cipher.h b/crypto/openssh/cipher.h index bc7a5e2..97bc889 100644 --- a/crypto/openssh/cipher.h +++ b/crypto/openssh/cipher.h @@ -8,9 +8,31 @@ * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". + * + * Copyright (c) 2000 Markus Friedl. 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. */ -/* RCSID("$OpenBSD: cipher.h,v 1.19 2000/09/07 20:27:50 deraadt Exp $"); */ +/* RCSID("$OpenBSD: cipher.h,v 1.22 2000/10/13 18:59:14 markus Exp $"); */ #ifndef CIPHER_H #define CIPHER_H @@ -19,9 +41,12 @@ #include <openssl/blowfish.h> #include <openssl/rc4.h> #include <openssl/cast.h> - -/* Cipher types. New types can be added, but old types should not be removed - for compatibility. The maximum allowed value is 31. */ +#include "rijndael.h" +/* + * Cipher types for SSH-1. New types can be added, but old types should not + * be removed for compatibility. The maximum allowed value is 31. + */ +#define SSH_CIPHER_SSH2 -3 #define SSH_CIPHER_ILLEGAL -2 /* No valid cipher selected. */ #define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */ #define SSH_CIPHER_NONE 0 /* no encryption */ @@ -32,17 +57,18 @@ #define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */ #define SSH_CIPHER_BLOWFISH 6 #define SSH_CIPHER_RESERVED 7 +#define SSH_CIPHER_MAX 31 -/* these ciphers are used in SSH2: */ -#define SSH_CIPHER_BLOWFISH_CBC 8 -#define SSH_CIPHER_3DES_CBC 9 -#define SSH_CIPHER_ARCFOUR 10 /* Alleged RC4 */ -#define SSH_CIPHER_CAST128_CBC 11 +typedef struct Cipher Cipher; +typedef struct CipherContext CipherContext; -typedef struct { - unsigned int type; +struct CipherContext { union { struct { + des_key_schedule key; + des_cblock iv; + } des; + struct { des_key_schedule key1; des_key_schedule key2; des_cblock iv2; @@ -51,64 +77,41 @@ typedef struct { } des3; struct { struct bf_key_st key; - unsigned char iv[8]; + u_char iv[8]; } bf; struct { CAST_KEY key; - unsigned char iv[8]; + u_char iv[8]; } cast; + struct { + u4byte iv[4]; + rijndael_ctx enc; + rijndael_ctx dec; + } rijndael; RC4_KEY rc4; } u; -} CipherContext; -/* - * Returns a bit mask indicating which ciphers are supported by this - * implementation. The bit mask has the corresponding bit set of each - * supported cipher. - */ -unsigned int cipher_mask(); -unsigned int cipher_mask1(); -unsigned int cipher_mask2(); - -/* Returns the name of the cipher. */ -const char *cipher_name(int cipher); - -/* - * Parses the name of the cipher. Returns the number of the corresponding - * cipher, or -1 on error. - */ -int cipher_number(const char *name); - -/* returns 1 if all ciphers are supported (ssh2 only) */ -int ciphers_valid(const char *names); - -/* - * Selects the cipher to use and sets the key. If for_encryption is true, - * the key is setup for encryption; otherwise it is setup for decryption. - */ -void -cipher_set_key(CipherContext * context, int cipher, - const unsigned char *key, int keylen); -void -cipher_set_key_iv(CipherContext * context, int cipher, - const unsigned char *key, int keylen, - const unsigned char *iv, int ivlen); - -/* - * Sets key for the cipher by computing the MD5 checksum of the passphrase, - * and using the resulting 16 bytes as the key. - */ -void -cipher_set_key_string(CipherContext * context, int cipher, - const char *passphrase); - -/* Encrypts data using the cipher. */ -void -cipher_encrypt(CipherContext * context, unsigned char *dest, - const unsigned char *src, unsigned int len); + Cipher *cipher; +}; +struct Cipher { + char *name; + int number; /* for ssh1 only */ + u_int block_size; + u_int key_len; + void (*setkey)(CipherContext *, const u_char *, u_int); + void (*setiv)(CipherContext *, const u_char *, u_int); + void (*encrypt)(CipherContext *, u_char *, const u_char *, u_int); + void (*decrypt)(CipherContext *, u_char *, const u_char *, u_int); +}; -/* Decrypts data using the cipher. */ -void -cipher_decrypt(CipherContext * context, unsigned char *dest, - const unsigned char *src, unsigned int len); +unsigned int cipher_mask_ssh1(int client); +Cipher *cipher_by_name(const char *name); +Cipher *cipher_by_number(int id); +int cipher_number(const char *name); +char *cipher_name(int id); +int ciphers_valid(const char *names); +void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, const u_char *, u_int); +void cipher_encrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len); +void cipher_decrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len); +void cipher_set_key_string(CipherContext *context, Cipher *cipher, const char *passphrase); #endif /* CIPHER_H */ 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/readconf.c b/crypto/openssh/readconf.c index 2ddf3ed..bcdbc4c 100644 --- a/crypto/openssh/readconf.c +++ b/crypto/openssh/readconf.c @@ -12,10 +12,9 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.47 2000/09/07 21:13:37 markus Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $"); #include "ssh.h" -#include "cipher.h" #include "readconf.h" #include "match.h" #include "xmalloc.h" @@ -103,7 +102,8 @@ typedef enum { oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication, oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2, - oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication + oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication, + oKbdInteractiveAuthentication, oKbdInteractiveDevices } OpCodes; /* Textual representations of the tokens. */ @@ -119,6 +119,8 @@ static struct { { "useprivilegedport", oUsePrivilegedPort }, { "rhostsauthentication", oRhostsAuthentication }, { "passwordauthentication", oPasswordAuthentication }, + { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, + { "kbdinteractivedevices", oKbdInteractiveDevices }, { "rsaauthentication", oRSAAuthentication }, { "dsaauthentication", oDSAAuthentication }, { "skeyauthentication", oSkeyAuthentication }, @@ -288,6 +290,14 @@ parse_flag: intptr = &options->password_authentication; goto parse_flag; + case oKbdInteractiveAuthentication: + intptr = &options->kbd_interactive_authentication; + goto parse_flag; + + case oKbdInteractiveDevices: + charptr = &options->kbd_interactive_devices; + goto parse_string; + case oDSAAuthentication: intptr = &options->dsa_authentication; goto parse_flag; @@ -662,6 +672,8 @@ initialize_options(Options * options) options->afs_token_passing = -1; #endif options->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->kbd_interactive_devices = NULL; options->rhosts_rsa_authentication = -1; options->fallback_to_rsh = -1; options->use_rsh = -1; @@ -732,6 +744,8 @@ fill_default_options(Options * options) #endif /* AFS */ if (options->password_authentication == -1) options->password_authentication = 1; + if (options->kbd_interactive_authentication == -1) + options->kbd_interactive_authentication = 0; if (options->rhosts_rsa_authentication == -1) options->rhosts_rsa_authentication = 1; if (options->fallback_to_rsh == -1) diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h index 23df57b..e94213f 100644 --- a/crypto/openssh/readconf.h +++ b/crypto/openssh/readconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: readconf.h,v 1.21 2000/09/07 20:27:53 deraadt Exp $"); */ +/* RCSID("$OpenBSD: readconf.h,v 1.22 2000/10/11 20:14:39 markus Exp $"); */ #ifndef READCONF_H #define READCONF_H @@ -47,6 +47,8 @@ typedef struct { #endif int password_authentication; /* Try password * authentication. */ + int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ + char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */ int fallback_to_rsh;/* Use rsh if cannot connect with ssh. */ int use_rsh; /* Always use rsh (don\'t try ssh). */ int batch_mode; /* Batch mode: do not ask for passwords. */ 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/servconf.c b/crypto/openssh/servconf.c index 8155108..76702a8 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: servconf.c,v 1.51 2000/09/07 20:27:53 deraadt Exp $"); +RCSID("$OpenBSD: servconf.c,v 1.53 2000/10/14 12:12:09 markus Exp $"); #include "ssh.h" #include "servconf.h" @@ -61,11 +61,13 @@ initialize_server_options(ServerOptions *options) options->afs_token_passing = -1; #endif options->password_authentication = -1; + options->kbd_interactive_authentication = -1; #ifdef SKEY options->skey_authentication = -1; #endif options->permit_empty_passwd = -1; options->use_login = -1; + options->allow_tcp_forwarding = -1; options->num_allow_users = 0; options->num_deny_users = 0; options->num_allow_groups = 0; @@ -148,6 +150,8 @@ fill_default_server_options(ServerOptions *options) #endif /* AFS */ if (options->password_authentication == -1) options->password_authentication = 1; + if (options->kbd_interactive_authentication == -1) + options->kbd_interactive_authentication = 0; #ifdef SKEY if (options->skey_authentication == -1) options->skey_authentication = 1; @@ -156,6 +160,8 @@ fill_default_server_options(ServerOptions *options) options->permit_empty_passwd = 0; if (options->use_login == -1) options->use_login = 0; + if (options->allow_tcp_forwarding == -1) + options->allow_tcp_forwarding = 1; if (options->protocol == SSH_PROTO_UNKNOWN) options->protocol = SSH_PROTO_1|SSH_PROTO_2; if (options->gateway_ports == -1) @@ -183,10 +189,11 @@ typedef enum { #ifdef SKEY sSkeyAuthentication, #endif - sPasswordAuthentication, sListenAddress, + sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, - sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, + sUseLogin, sAllowTcpForwarding, + sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups } ServerOpCodes; @@ -220,6 +227,7 @@ static struct { { "afstokenpassing", sAFSTokenPassing }, #endif { "passwordauthentication", sPasswordAuthentication }, + { "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, #ifdef SKEY { "skeyauthentication", sSkeyAuthentication }, #endif @@ -236,6 +244,7 @@ static struct { { "uselogin", sUseLogin }, { "randomseed", sRandomSeedFile }, { "keepalive", sKeepAlives }, + { "allowtcpforwarding", sAllowTcpForwarding }, { "allowusers", sAllowUsers }, { "denyusers", sDenyUsers }, { "allowgroups", sAllowGroups }, @@ -497,6 +506,10 @@ parse_flag: intptr = &options->password_authentication; goto parse_flag; + case sKbdInteractiveAuthentication: + intptr = &options->kbd_interactive_authentication; + goto parse_flag; + case sCheckMail: intptr = &options->check_mail; goto parse_flag; @@ -565,6 +578,10 @@ parse_flag: *intptr = (LogLevel) value; break; + case sAllowTcpForwarding: + intptr = &options->allow_tcp_forwarding; + goto parse_flag; + case sAllowUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_users >= MAX_ALLOW_USERS) diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h index f00a128..0188b9b 100644 --- a/crypto/openssh/servconf.h +++ b/crypto/openssh/servconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: servconf.h,v 1.28 2000/09/07 20:27:53 deraadt Exp $"); */ +/* RCSID("$OpenBSD: servconf.h,v 1.30 2000/10/14 12:12:09 markus Exp $"); */ #ifndef SERVCONF_H #define SERVCONF_H @@ -78,6 +78,7 @@ typedef struct { #endif int password_authentication; /* If true, permit password * authentication. */ + int kbd_interactive_authentication; /* If true, permit */ #ifdef SKEY int skey_authentication; /* If true, permit s/key * authentication. */ @@ -85,6 +86,7 @@ typedef struct { int permit_empty_passwd; /* If false, do not permit empty * passwords. */ int use_login; /* If true, login(1) is used */ + int allow_tcp_forwarding; unsigned int num_allow_users; char *allow_users[MAX_ALLOW_USERS]; unsigned int num_deny_users; 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/session.c b/crypto/openssh/session.c index 4321535..13525f8 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -33,14 +33,13 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.37 2000/09/07 20:27:53 deraadt Exp $"); +RCSID("$OpenBSD: session.c,v 1.42 2000/10/27 07:32:18 markus Exp $"); #include "xmalloc.h" #include "ssh.h" #include "pty.h" #include "packet.h" #include "buffer.h" -#include "cipher.h" #include "mpaux.h" #include "servconf.h" #include "uidswap.h" @@ -90,7 +89,7 @@ void session_pty_cleanup(Session *s); void session_proctitle(Session *s); void do_exec_pty(Session *s, const char *command, struct passwd * pw); void do_exec_no_pty(Session *s, const char *command, struct passwd * pw); -void do_login(Session *s); +void do_login(Session *s, const char *command); void do_child(const char *command, struct passwd * pw, const char *term, @@ -197,7 +196,7 @@ do_authenticated(struct passwd * pw) * by the client telling us, so we can equally well trust the client * not to request anything bogus.) */ - if (!no_port_forwarding_flag) + if (!no_port_forwarding_flag && options.allow_tcp_forwarding) channel_permit_all_opens(); s = session_new(); @@ -349,6 +348,10 @@ do_authenticated(struct passwd * pw) debug("Port forwarding not permitted for this authentication."); break; } + if (!options.allow_tcp_forwarding) { + debug("Port forwarding not permitted."); + break; + } debug("Received TCP/IP port forwarding request."); channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports); success = 1; @@ -569,8 +572,8 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) close(ttyfd); /* record login, etc. similar to login(1) */ - if (command == NULL && !options.use_login) - do_login(s); + if (!(options.use_login && command == NULL)) + do_login(s, command); /* Do common processing for the child, such as execing the command. */ do_child(command, pw, s->term, s->display, s->auth_proto, @@ -622,7 +625,7 @@ get_remote_name_or_ip(void) /* administrative, login(1)-like work */ void -do_login(Session *s) +do_login(Session *s, const char *command) { FILE *f; char *time_string; @@ -658,7 +661,9 @@ do_login(Session *s) record_login(pid, s->tty, pw->pw_name, pw->pw_uid, get_remote_name_or_ip(), (struct sockaddr *)&from); - /* Done if .hushlogin exists. */ + /* Done if .hushlogin exists or a command given. */ + if (command != NULL) + return; snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); #ifdef HAVE_LOGIN_CAP if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) @@ -670,7 +675,7 @@ do_login(Session *s) time_string = ctime(&last_login_time); if (strchr(time_string, '\n')) *strchr(time_string, '\n') = 0; - if (strcmp(buf, "") == 0) + if (strcmp(hostname, "") == 0) printf("Last login: %s\r\n", time_string); else printf("Last login: %s from %s\r\n", time_string, hostname); @@ -1477,7 +1482,8 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) fatal("no channel for session %d", s->self); channel_set_fds(s->chanid, fdout, fdin, fderr, - fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ); + fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, + 1); } void 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-agent.c b/crypto/openssh/ssh-agent.c index 5b17868..ad58a55 100644 --- a/crypto/openssh/ssh-agent.c +++ b/crypto/openssh/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.35 2000/09/07 20:27:54 deraadt Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.37 2000/09/21 11:07:51 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -37,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-agent.c,v 1.35 2000/09/07 20:27:54 deraadt Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.37 2000/09/21 11:07:51 markus Exp $"); #include "ssh.h" #include "rsa.h" @@ -56,6 +56,7 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.35 2000/09/07 20:27:54 deraadt Exp $"); #include "authfd.h" #include "dsa.h" #include "kex.h" +#include "compat.h" typedef struct { int fd; @@ -233,6 +234,7 @@ process_sign_request2(SocketEntry *e) Key *key, *private; unsigned char *blob, *data, *signature = NULL; unsigned int blen, dlen, slen = 0; + int flags; Buffer msg; int ok = -1; @@ -240,7 +242,10 @@ process_sign_request2(SocketEntry *e) blob = buffer_get_string(&e->input, &blen); data = buffer_get_string(&e->input, &dlen); - buffer_get_int(&e->input); /* flags, unused */ + + flags = buffer_get_int(&e->input); + if (flags & SSH_AGENT_OLD_SIGNATURE) + datafellows = SSH_BUG_SIGBLOB; key = dsa_key_from_blob(blob, blen); if (key != NULL) { @@ -771,8 +776,11 @@ main(int ac, char **av) printf("echo Agent pid %d;\n", pid); exit(0); } - setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1); - setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1); + if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 || + setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) { + perror("setenv"); + exit(1); + } execvp(av[0], av); perror(av[0]); exit(1); 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/ssh.1 b/crypto/openssh/ssh.1 index 78a1bd7..318f450 100644 --- a/crypto/openssh/ssh.1 +++ b/crypto/openssh/ssh.1 @@ -34,6 +34,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. .\" +.\" $OpenBSD: ssh.1,v 1.64 2000/10/16 21:46:31 markus Exp $ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -367,15 +368,16 @@ It is believed to be secure. (triple-des) is an encrypt-decrypt-encrypt triple with three different keys. It is presumably more secure than the .Ar des -cipher which is no longer supported in +cipher which is no longer fully supported in .Nm ssh . .Ar blowfish is a fast block cipher, it appears very secure and is much faster than .Ar 3des . .It Fl c Ar "3des-cbc,blowfish-cbc,arcfour,cast128-cbc" Additionally, for protocol version 2 a comma-separated list of ciphers can -be specified in order of preference. Protocol version 2 supports -3DES, Blowfish and CAST128 in CBC mode and Arcfour. +be specified in order of preference. +Protocol version 2 supports 3DES, Blowfish, and CAST128 in CBC mode +and Arcfour. .It Fl e Ar ch|^ch|none Sets the escape character for sessions with a pty (default: .Ql ~ ) . @@ -483,6 +485,8 @@ debugging connection, authentication, and configuration problems. The verbose mode is also used to display .Xr skey 1 challenges, if the user entered "s/key" as password. +Multiple -v options increases the verbosity. +Maximum is 3. .It Fl x Disables X11 forwarding. .It Fl X @@ -624,9 +628,10 @@ If the option is set to .Dq no , the check will not be executed. .It Cm Cipher -Specifies the cipher to use for encrypting the session. +Specifies the cipher to use for encrypting the session +in protocol version 1. Currently, -.Dq blowfish , +.Dq blowfish and .Dq 3des are supported. @@ -637,7 +642,7 @@ Specifies the ciphers allowed for protocol version 2 in order of preference. Multiple ciphers must be comma-separated. The default is -.Dq 3des-cbc,blowfish-cbc,arcfour,cast128-cbc . +.Dq 3des-cbc,blowfish-cbc,cast128-cbc,arcfour . .It Cm Compression Specifies whether to use compression. The argument must be diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index 4c4b836..f671726 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -39,7 +39,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh.c,v 1.65 2000/09/07 20:40:30 markus Exp $"); +RCSID("$OpenBSD: ssh.c,v 1.69 2000/10/27 07:32:19 markus Exp $"); #include <openssl/evp.h> #include <openssl/dsa.h> @@ -147,6 +147,7 @@ usage() fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n"); fprintf(stderr, " -T Do not allocate a tty.\n"); fprintf(stderr, " -v Verbose; display verbose debugging messages.\n"); + fprintf(stderr, " Multiple -v increases verbosity.\n"); fprintf(stderr, " -V Display version number only.\n"); fprintf(stderr, " -P Don't allocate a privileged port.\n"); fprintf(stderr, " -q Quiet; don't display any warning messages.\n"); @@ -361,6 +362,16 @@ main(int ac, char **av) tty_flag = 1; break; case 'v': + if (0 == debug_flag) { + debug_flag = 1; + options.log_level = SYSLOG_LEVEL_DEBUG1; + } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) { + options.log_level++; + break; + } else { + fatal("Too high debugging level.\n"); + } + /* fallthrough */ case 'V': fprintf(stderr, "SSH Version %s, protocol versions %d.%d/%d.%d.\n", SSH_VERSION, @@ -369,8 +380,6 @@ main(int ac, char **av) fprintf(stderr, "Compiled with SSL (0x%8.8lx).\n", SSLeay()); if (opt == 'V') exit(0); - debug_flag = 1; - options.log_level = SYSLOG_LEVEL_DEBUG; break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; @@ -395,11 +404,12 @@ main(int ac, char **av) options.cipher = SSH_CIPHER_ILLEGAL; } else { /* SSH1 only */ - options.cipher = cipher_number(optarg); - if (options.cipher == -1) { + Cipher *c = cipher_by_name(optarg); + if (c == NULL || c->number < 0) { fprintf(stderr, "Unknown cipher type '%s'\n", optarg); exit(1); } + options.cipher = c->number; } break; case 'p': @@ -550,22 +560,6 @@ main(int ac, char **av) if (options.hostname != NULL) host = options.hostname; - /* Find canonic host name. */ - if (strchr(host, '.') == 0) { - struct addrinfo hints; - struct addrinfo *ai = NULL; - int errgai; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = IPv4or6; - hints.ai_flags = AI_CANONNAME; - hints.ai_socktype = SOCK_STREAM; - errgai = getaddrinfo(host, NULL, &hints, &ai); - if (errgai == 0) { - if (ai->ai_canonname != NULL) - host = xstrdup(ai->ai_canonname); - freeaddrinfo(ai); - } - } /* Disable rhosts authentication if not running as root. */ if (original_effective_uid != 0 || !options.use_privileged_port) { options.rhosts_authentication = 0; @@ -986,6 +980,14 @@ ssh_session2(void) if (in < 0 || out < 0 || err < 0) fatal("dup() in/out/err failed"); + /* enable nonblocking unless tty */ + if (!isatty(in)) + set_nonblock(in); + if (!isatty(out)) + set_nonblock(out); + if (!isatty(err)) + set_nonblock(err); + /* should be pre-session */ init_local_fwd(); @@ -1003,7 +1005,7 @@ ssh_session2(void) id = channel_new( "session", SSH_CHANNEL_OPENING, in, out, err, window, packetmax, CHAN_EXTENDED_WRITE, - xstrdup("client-session")); + xstrdup("client-session"), /*nonblock*/0); channel_open(id); channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0); diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h index f48012f..f8c58e6 100644 --- a/crypto/openssh/ssh.h +++ b/crypto/openssh/ssh.h @@ -12,7 +12,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: ssh.h,v 1.50 2000/09/07 20:27:54 deraadt Exp $"); */ +/* RCSID("$OpenBSD: ssh.h,v 1.54 2000/10/11 20:27:24 markus Exp $"); */ #ifndef SSH_H #define SSH_H @@ -20,14 +20,6 @@ #include "rsa.h" #include "cipher.h" -/* - * XXX - * The default cipher used if IDEA is not supported by the remote host. It is - * recommended that this be one of the mandatory ciphers (DES, 3DES), though - * that is not required. - */ -#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES - /* Cipher used for encrypting authentication files. */ #define SSH_AUTHFILE_CIPHER SSH_CIPHER_3DES @@ -81,6 +73,7 @@ #define SERVER_CONFIG_FILE ETCDIR "/sshd_config" #define HOST_CONFIG_FILE ETCDIR "/ssh_config" #define HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key" +#define DH_PRIMES ETCDIR "/primes" #define SSH_PROGRAM "/usr/bin/ssh" @@ -380,7 +373,7 @@ int auth_rsa_challenge_dialog(RSA *pk); * passphrase (allocated with xmalloc). Exits if EOF is encountered. If * from_stdin is true, the passphrase will be read from stdin instead. */ -char *read_passphrase(const char *prompt, int from_stdin); +char *read_passphrase(char *prompt, int from_stdin); /*------------ Definitions for logging. -----------------------*/ @@ -406,7 +399,9 @@ typedef enum { SYSLOG_LEVEL_ERROR, SYSLOG_LEVEL_INFO, SYSLOG_LEVEL_VERBOSE, - SYSLOG_LEVEL_DEBUG + SYSLOG_LEVEL_DEBUG1, + SYSLOG_LEVEL_DEBUG2, + SYSLOG_LEVEL_DEBUG3 } LogLevel; /* Initializes logging. */ void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr); @@ -424,6 +419,8 @@ void error(const char *fmt,...) __attribute__((format(printf, 1, 2))); void log(const char *fmt,...) __attribute__((format(printf, 1, 2))); void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2))); void debug(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void debug2(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void debug3(const char *fmt,...) __attribute__((format(printf, 1, 2))); /* same as fatal() but w/o logging */ void fatal_cleanup(void); 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/sshconnect.c b/crypto/openssh/sshconnect.c index 22fa9dc..f7b62d8 100644 --- a/crypto/openssh/sshconnect.c +++ b/crypto/openssh/sshconnect.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.78 2000/09/07 20:27:54 deraadt Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.79 2000/09/17 15:52:51 markus Exp $"); #include <openssl/bn.h> #include <openssl/dsa.h> @@ -436,8 +436,10 @@ read_yes_or_no(const char *prompt, int defval) retval = defval; if (strcmp(buf, "yes") == 0) retval = 1; - if (strcmp(buf, "no") == 0) + else if (strcmp(buf, "no") == 0) retval = 0; + else + fprintf(stderr, "Please type 'yes' or 'no'.\n"); if (retval != -1) { if (f != stdin) diff --git a/crypto/openssh/sshconnect1.c b/crypto/openssh/sshconnect1.c index 2bb4d53..ce56079 100644 --- a/crypto/openssh/sshconnect1.c +++ b/crypto/openssh/sshconnect1.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.6 2000/09/07 20:27:54 deraadt Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.8 2000/10/12 09:59:19 markus Exp $"); #include <openssl/bn.h> #include <openssl/dsa.h> @@ -25,7 +25,6 @@ RCSID("$OpenBSD: sshconnect1.c,v 1.6 2000/09/07 20:27:54 deraadt Exp $"); #include "ssh.h" #include "buffer.h" #include "packet.h" -#include "cipher.h" #include "mpaux.h" #include "uidswap.h" #include "readconf.h" @@ -836,17 +835,11 @@ ssh_kex(char *host, struct sockaddr *hostaddr) if (options.cipher == SSH_CIPHER_ILLEGAL) { log("No valid SSH1 cipher, using %.100s instead.", - cipher_name(SSH_FALLBACK_CIPHER)); - options.cipher = SSH_FALLBACK_CIPHER; + cipher_name(ssh_cipher_default)); + options.cipher = ssh_cipher_default; } else if (options.cipher == SSH_CIPHER_NOT_SET) { - if (cipher_mask1() & supported_ciphers & (1 << ssh_cipher_default)) + if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default)) options.cipher = ssh_cipher_default; - else { - debug("Cipher %s not supported, using %.100s instead.", - cipher_name(ssh_cipher_default), - cipher_name(SSH_FALLBACK_CIPHER)); - options.cipher = SSH_FALLBACK_CIPHER; - } } /* Check that the selected cipher is supported. */ if (!(supported_ciphers & (1 << options.cipher))) 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.8 b/crypto/openssh/sshd.8 index 21caf8d..cd1771a 100644 --- a/crypto/openssh/sshd.8 +++ b/crypto/openssh/sshd.8 @@ -34,6 +34,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. .\" +.\" $OpenBSD: sshd.8,v 1.70 2000/10/16 09:38:44 djm Exp $ .Dd September 25, 1999 .Dt SSHD 8 .Os @@ -186,6 +187,8 @@ The server sends verbose debug output to the system log, and does not put itself in the background. The server also will not fork and will only process one connection. This option is only intended for debugging for the server. +Multiple -d options increases the debugging level. +Maximum is 3. .It Fl f Ar configuration_file Specifies the name of the configuration file. The default is @@ -254,12 +257,13 @@ file. .It Fl Q Do not print an error message if RSA support is missing. .It Fl V Ar client_protocol_id -SSH2 compatibility mode. +SSH-2 compatibility mode. When this option is specified .Nm assumes the client has sent the supplied version string and skips the Protocol Version Identification Exchange. +This option is not intended to be called directly. .It Fl 4 Forces .Nm @@ -300,6 +304,14 @@ wildcards in the patterns. Only group names are valid; a numerical group ID isn't recognized. By default login is allowed regardless of the primary group. .Pp +.It Cm AllowTcpForwarding +Specifies whether TCP forwarding is permitted. +The default is +.Dq yes . +Note that disabling TCP forwarding does not improve security unless +users are also denied shell access, as they can always install their +own forwarders. +.Pp .It Cm AllowUsers This keyword can be followed by a number of user names, separated by spaces. @@ -423,7 +435,8 @@ Specifies whether Kerberos authentication is allowed. This can be in the form of a Kerberos ticket, or if .Cm PasswordAuthentication is yes, the password provided by the user will be validated through -the Kerberos KDC. To use this option, the server needs a +the Kerberos KDC. +To use this option, the server needs a Kerberos servtab which allows the verification of the KDC's identity. Default is .Dq yes . @@ -431,8 +444,7 @@ Default is If set then if password authentication through Kerberos fails then the password will be validated via any additional local mechanism such as -.Pa /etc/passwd -or SecurID. +.Pa /etc/passwd . Default is .Dq yes . .It Cm KerberosTgtPassing @@ -488,7 +500,7 @@ The default is 10. Alternatively, random early drop can be enabled by specifying the three colon separated values .Dq start:rate:full -(e.g. "10:30:60"). +(e.g., "10:30:60"). .Nm will refuse connection attempts with a probabillity of .Dq rate/100 @@ -610,8 +622,9 @@ directory or files world-writable. The default is .Dq yes . .It Cm Subsystem -Configures an external subsystem (e.g. file transfer daemon). -Arguments should be a subsystem name and a command to execute upon subsystem request. +Configures an external subsystem (e.g., file transfer daemon). +Arguments should be a subsystem name and a command to execute upon subsystem +request. The command .Xr sftp-server 8 implements the diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index e4cfe02..f0110b2 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -40,14 +40,13 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.126 2000/09/07 20:27:55 deraadt Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.132 2000/10/13 18:34:46 markus Exp $"); #include "xmalloc.h" #include "rsa.h" #include "ssh.h" #include "pty.h" #include "packet.h" -#include "cipher.h" #include "mpaux.h" #include "servconf.h" #include "uidswap.h" @@ -63,6 +62,7 @@ RCSID("$OpenBSD: sshd.c,v 1.126 2000/09/07 20:27:55 deraadt Exp $"); #include <openssl/rsa.h> #include "key.h" #include "dsa.h" +#include "dh.h" #include "auth.h" #include "myproposal.h" @@ -167,6 +167,9 @@ unsigned int utmp_len = MAXHOSTNAMELEN; void do_ssh1_kex(); void do_ssh2_kex(); +void ssh_dh1_server(Kex *, Buffer *_kexinit, Buffer *); +void ssh_dhgex_server(Kex *, Buffer *_kexinit, Buffer *); + /* * Close all listening sockets */ @@ -328,6 +331,10 @@ sshd_exchange_identification(int sock_in, int sock_out) if (buf[i] == '\r') { buf[i] = '\n'; buf[i + 1] = 0; + /* Kludge for F-Secure Macintosh < 1.0.2 */ + if (i == 12 && + strncmp(buf, "SSH-1.5-W1.0", 12) == 0) + break; continue; } if (buf[i] == '\n') { @@ -503,8 +510,15 @@ main(int ac, char **av) config_file_name = optarg; break; case 'd': - debug_flag = 1; - options.log_level = SYSLOG_LEVEL_DEBUG; + if (0 == debug_flag) { + debug_flag = 1; + options.log_level = SYSLOG_LEVEL_DEBUG1; + } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) { + options.log_level++; + } else { + fprintf(stderr, "Too high debugging level.\n"); + exit(1); + } break; case 'i': inetd_flag = 1; @@ -520,8 +534,10 @@ main(int ac, char **av) break; case 'p': options.ports_from_cmdline = 1; - if (options.num_ports >= MAX_PORTS) - fatal("too many ports.\n"); + if (options.num_ports >= MAX_PORTS) { + fprintf(stderr, "too many ports.\n"); + exit(1); + } options.ports[options.num_ports++] = atoi(optarg); break; case 'g': @@ -547,7 +563,7 @@ main(int ac, char **av) fprintf(stderr, "Usage: %s [options]\n", av0); fprintf(stderr, "Options:\n"); fprintf(stderr, " -f file Configuration file (default %s)\n", SERVER_CONFIG_FILE); - fprintf(stderr, " -d Debugging mode\n"); + fprintf(stderr, " -d Debugging mode (multiple -d means more debugging)\n"); fprintf(stderr, " -i Started from inetd\n"); fprintf(stderr, " -q Quiet (no logging)\n"); fprintf(stderr, " -p port Listen on the specified port (default: 22)\n"); @@ -1123,7 +1139,7 @@ do_ssh1_kex() packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); /* Declare which ciphers we support. */ - packet_put_int(cipher_mask1()); + packet_put_int(cipher_mask_ssh1(0)); /* Declare supported authentication types. */ auth_mask = 0; @@ -1164,7 +1180,7 @@ do_ssh1_kex() /* Get cipher type and check whether we accept this. */ cipher_type = packet_get_char(); - if (!(cipher_mask() & (1 << cipher_type))) + if (!(cipher_mask_ssh1(0) & (1 << cipher_type))) packet_disconnect("Warning: client selects unsupported cipher."); /* Get check bytes from the packet. These must match those we @@ -1268,18 +1284,8 @@ do_ssh2_kex() { Buffer *server_kexinit; Buffer *client_kexinit; - int payload_len, dlen; - int slen; - unsigned int klen, kout; - unsigned char *signature = NULL; - unsigned char *server_host_key_blob = NULL; - unsigned int sbloblen; - DH *dh; - BIGNUM *dh_client_pub = 0; - BIGNUM *shared_secret = 0; + int payload_len; int i; - unsigned char *kbuf; - unsigned char *hash; Kex *kex; char *cprop[PROPOSAL_MAX]; @@ -1299,8 +1305,63 @@ do_ssh2_kex() for (i = 0; i < PROPOSAL_MAX; i++) xfree(cprop[i]); -/* KEXDH */ + switch (kex->kex_type) { + case DH_GRP1_SHA1: + ssh_dh1_server(kex, client_kexinit, server_kexinit); + break; + case DH_GEX_SHA1: + ssh_dhgex_server(kex, client_kexinit, server_kexinit); + break; + default: + fatal("Unsupported key exchange %d", kex->kex_type); + } + + debug("send SSH2_MSG_NEWKEYS."); + packet_start(SSH2_MSG_NEWKEYS); + packet_send(); + packet_write_wait(); + debug("done: send SSH2_MSG_NEWKEYS."); + + debug("Wait SSH2_MSG_NEWKEYS."); + packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); + debug("GOT 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."); +} + +/* + * SSH2 key exchange + */ + +/* diffie-hellman-group1-sha1 */ +void +ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) +{ +#ifdef DEBUG_KEXDH + int i; +#endif + int payload_len, dlen; + int slen; + unsigned char *signature = NULL; + unsigned char *server_host_key_blob = NULL; + unsigned int sbloblen; + unsigned int klen, kout; + unsigned char *kbuf; + unsigned char *hash; + BIGNUM *shared_secret = 0; + DH *dh; + BIGNUM *dh_client_pub = 0; + +/* KEXDH */ debug("Wait SSH2_MSG_KEXDH_INIT."); packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT); @@ -1312,7 +1373,7 @@ do_ssh2_kex() #ifdef DEBUG_KEXDH fprintf(stderr, "\ndh_client_pub= "); - bignum_print(dh_client_pub); + BN_print_fp(stderr, dh_client_pub); fprintf(stderr, "\n"); debug("bits %d", BN_num_bits(dh_client_pub)); #endif @@ -1322,12 +1383,13 @@ do_ssh2_kex() #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(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 if (!dh_pub_is_valid(dh, dh_client_pub)) packet_disconnect("bad client public DH value"); @@ -1350,7 +1412,8 @@ do_ssh2_kex() xfree(kbuf); /* XXX precompute? */ - dsa_make_key_blob(sensitive_data.dsa_host_key, &server_host_key_blob, &sbloblen); + dsa_make_key_blob(sensitive_data.dsa_host_key, + &server_host_key_blob, &sbloblen); /* calc H */ /* XXX depends on 'kex' */ hash = kex_hash( @@ -1400,23 +1463,139 @@ do_ssh2_kex() /* have keys, free DH */ DH_free(dh); +} - debug("send SSH2_MSG_NEWKEYS."); - packet_start(SSH2_MSG_NEWKEYS); +/* diffie-hellman-group-exchange-sha1 */ + +void +ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) +{ +#ifdef DEBUG_KEXDH + int i; +#endif + int payload_len, dlen; + int slen, nbits; + unsigned char *signature = NULL; + unsigned char *server_host_key_blob = NULL; + unsigned int sbloblen; + unsigned int klen, kout; + unsigned char *kbuf; + unsigned char *hash; + BIGNUM *shared_secret = 0; + DH *dh; + BIGNUM *dh_client_pub = 0; + +/* KEXDHGEX */ + debug("Wait SSH2_MSG_KEX_DH_GEX_REQUEST."); + packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_REQUEST); + nbits = packet_get_int(); + dh = choose_dh(nbits); + + debug("Sending SSH2_MSG_KEX_DH_GEX_GROUP."); + packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); + packet_put_bignum2(dh->p); + packet_put_bignum2(dh->g); packet_send(); packet_write_wait(); - debug("done: send SSH2_MSG_NEWKEYS."); - debug("Wait SSH2_MSG_NEWKEYS."); - packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); - debug("GOT SSH2_MSG_NEWKEYS."); + debug("Wait SSH2_MSG_KEX_DH_GEX_INIT."); + packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_INIT); + + /* key, cert */ + dh_client_pub = BN_new(); + if (dh_client_pub == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub, &dlen); #ifdef DEBUG_KEXDH - /* send 1st encrypted/maced/compressed message */ - packet_start(SSH2_MSG_IGNORE); - packet_put_cstring("markus"); + fprintf(stderr, "\ndh_client_pub= "); + BN_print_fp(stderr, dh_client_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_client_pub)); +#endif + +#ifdef DEBUG_KEXDH + fprintf(stderr, "\np= "); + BN_print_fp(stderr, dh->p); + fprintf(stderr, "\ng= "); + bn_print(dh->g); + fprintf(stderr, "\npub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); + DHparams_print_fp(stderr, dh); +#endif + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_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); + + /* XXX precompute? */ + dsa_make_key_blob(sensitive_data.dsa_host_key, + &server_host_key_blob, &sbloblen); + + /* calc H */ /* XXX depends on 'kex' */ + 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), + (char *)server_host_key_blob, sbloblen, + nbits, dh->p, dh->g, + dh_client_pub, + dh->pub_key, + shared_secret + ); + buffer_free(client_kexinit); + buffer_free(server_kexinit); + xfree(client_kexinit); + xfree(server_kexinit); +#ifdef DEBUG_KEXDH + fprintf(stderr, "hash == "); + for (i = 0; i< 20; i++) + fprintf(stderr, "%02x", (hash[i])&0xff); + fprintf(stderr, "\n"); +#endif + /* save session id := H */ + /* XXX hashlen depends on KEX */ + session_id2_len = 20; + session_id2 = xmalloc(session_id2_len); + memcpy(session_id2, hash, session_id2_len); + + /* sign H */ + /* XXX hashlen depends on KEX */ + dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20); + + destroy_sensitive_data(); + + /* send server hostkey, DH pubkey 'f' and singed H */ + packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); + packet_put_string((char *)server_host_key_blob, sbloblen); + packet_put_bignum2(dh->pub_key); /* f */ + packet_put_string((char *)signature, slen); packet_send(); + xfree(signature); + xfree(server_host_key_blob); packet_write_wait(); -#endif - debug("done: KEX2."); + + kex_derive_keys(kex, hash, shared_secret); + packet_set_kex(kex); + + /* have keys, free DH */ + DH_free(dh); } + 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/sshd_config b/crypto/openssh/sshd_config index 71e73ba..0ef2fa8 100644 --- a/crypto/openssh/sshd_config +++ b/crypto/openssh/sshd_config @@ -37,6 +37,7 @@ PasswordAuthentication yes PermitEmptyPasswords no # Uncomment to disable s/key passwords #SkeyAuthentication no +#KbdInteractiveAuthentication yes # To change Kerberos options #KerberosAuthentication no 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" |