]> andersk Git - openssh.git/commitdiff
- (djm) Big OpenBSD sync:
authordjm <djm>
Sat, 14 Oct 2000 05:23:11 +0000 (05:23 +0000)
committerdjm <djm>
Sat, 14 Oct 2000 05:23:11 +0000 (05:23 +0000)
   - markus@cvs.openbsd.org  2000/09/30 10:27:44
     [log.c]
     allow loglevel debug
   - markus@cvs.openbsd.org  2000/10/03 11:59:57
     [packet.c]
     hmac->mac
   - markus@cvs.openbsd.org  2000/10/03 12:03:03
     [auth-krb4.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth1.c]
     move fake-auth from auth1.c to individual auth methods, disables s/key in
     debug-msg
   - markus@cvs.openbsd.org  2000/10/03 12:16:48
     ssh.c
     do not resolve canonname, i have no idea why this was added oin ossh
   - markus@cvs.openbsd.org  2000/10/09 15:30:44
     ssh-keygen.1 ssh-keygen.c
     -X now reads private ssh.com DSA keys, too.
   - markus@cvs.openbsd.org  2000/10/09 15:32:34
     auth-options.c
     clear options on every call.
   - markus@cvs.openbsd.org  2000/10/09 15:51:00
     authfd.c authfd.h
     interop with ssh-agent2, from <res@shore.net>
   - markus@cvs.openbsd.org  2000/10/10 14:20:45
     compat.c
     use rexexp for version string matching
   - provos@cvs.openbsd.org  2000/10/10 22:02:18
     [kex.c kex.h myproposal.h ssh.h ssh2.h sshconnect2.c sshd.c dh.c dh.h]
     First rough implementation of the diffie-hellman group exchange.  The
     client can ask the server for bigger groups to perform the diffie-hellman
     in, thus increasing the attack complexity when using ciphers with longer
     keys.  University of Windsor provided network, T the company.
   - markus@cvs.openbsd.org  2000/10/11 13:59:52
     [auth-rsa.c auth2.c]
     clear auth options unless auth sucessfull
   - markus@cvs.openbsd.org  2000/10/11 14:00:27
     [auth-options.h]
     clear auth options unless auth sucessfull
   - markus@cvs.openbsd.org  2000/10/11 14:03:27
     [scp.1 scp.c]
     support 'scp -o' with help from mouring@pconline.com
   - markus@cvs.openbsd.org  2000/10/11 14:11:35
     [dh.c]
     Wall
   - markus@cvs.openbsd.org  2000/10/11 14:14:40
     [auth.h auth2.c readconf.c readconf.h readpass.c servconf.c servconf.h]
     [ssh.h sshconnect2.c sshd_config auth2-skey.c cli.c cli.h]
     add support for s/key (kbd-interactive) to ssh2, based on work by
     mkiernan@avantgo.com and me
   - markus@cvs.openbsd.org  2000/10/11 14:27:24
     [auth.c auth1.c auth2.c authfile.c cipher.c cipher.h kex.c kex.h]
     [myproposal.h packet.c readconf.c session.c ssh.c ssh.h sshconnect1.c]
     [sshconnect2.c sshd.c]
     new cipher framework
   - markus@cvs.openbsd.org  2000/10/11 14:45:21
     [cipher.c]
     remove DES
   - markus@cvs.openbsd.org  2000/10/12 03:59:20
     [cipher.c cipher.h sshconnect1.c sshconnect2.c sshd.c]
     enable DES in SSH-1 clients only
   - markus@cvs.openbsd.org  2000/10/12 08:21:13
     [kex.h packet.c]
     remove unused
   - markus@cvs.openbsd.org  2000/10/13 12:34:46
     [sshd.c]
     Kludge for F-Secure Macintosh < 1.0.2; appro@fy.chalmers.se
   - markus@cvs.openbsd.org  2000/10/13 12:59:15
     [cipher.c cipher.h myproposal.h  rijndael.c rijndael.h]
     rijndael/aes support
   - markus@cvs.openbsd.org  2000/10/13 13:10:54
     [sshd.8]
     more info about -V
   - markus@cvs.openbsd.org  2000/10/13 13:12:02
     [myproposal.h]
     prefer no compression

56 files changed:
ChangeLog
Makefile.in
auth-krb4.c
auth-options.c
auth-options.h
auth-pam.c
auth-passwd.c
auth-rh-rsa.c
auth-rhosts.c
auth-rsa.c
auth.c
auth.h
auth1.c
auth2.c
authfd.c
authfd.h
authfile.c
bsd-vis.c [new file with mode: 0644]
bsd-vis.h [new file with mode: 0644]
cipher.c
cipher.h
cli.c [new file with mode: 0644]
cli.h [new file with mode: 0644]
compat.c
configure.in
dh.c [new file with mode: 0644]
dh.h [new file with mode: 0644]
includes.h
kex.c
kex.h
log.c
myproposal.h
openbsd-compat.h
packet.c
readconf.c
readconf.h
readpass.c
rijndael.c [new file with mode: 0644]
rijndael.h [new file with mode: 0644]
scp.1
scp.c
servconf.c
servconf.h
session.c
sftp-server.8
ssh-keygen.1
ssh-keygen.c
ssh.1
ssh.c
ssh.h
ssh2.h
sshconnect1.c
sshconnect2.c
sshd.8
sshd.c
sshd_config

index 86e7cea9608e37cece3122192fb2448e7615b351..61c08bc357b9d911983377286cff8787a86bd2a5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,81 @@
  - (djm) Revert SSH2 serverloop hack, will find a better way.
  - (djm) Add workaround for Linux 2.4's gratuitious errno change. Patch
    from Martin Johansson <fatbob@acc.umu.se>
+ - (djm) Big OpenBSD sync:
+   - markus@cvs.openbsd.org  2000/09/30 10:27:44
+     [log.c]
+     allow loglevel debug
+   - markus@cvs.openbsd.org  2000/10/03 11:59:57
+     [packet.c]
+     hmac->mac
+   - markus@cvs.openbsd.org  2000/10/03 12:03:03
+     [auth-krb4.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth1.c]
+     move fake-auth from auth1.c to individual auth methods, disables s/key in
+     debug-msg
+   - markus@cvs.openbsd.org  2000/10/03 12:16:48
+     ssh.c
+     do not resolve canonname, i have no idea why this was added oin ossh
+   - markus@cvs.openbsd.org  2000/10/09 15:30:44
+     ssh-keygen.1 ssh-keygen.c
+     -X now reads private ssh.com DSA keys, too.
+   - markus@cvs.openbsd.org  2000/10/09 15:32:34
+     auth-options.c
+     clear options on every call.
+   - markus@cvs.openbsd.org  2000/10/09 15:51:00
+     authfd.c authfd.h
+     interop with ssh-agent2, from <res@shore.net>
+   - markus@cvs.openbsd.org  2000/10/10 14:20:45
+     compat.c
+     use rexexp for version string matching
+   - provos@cvs.openbsd.org  2000/10/10 22:02:18
+     [kex.c kex.h myproposal.h ssh.h ssh2.h sshconnect2.c sshd.c dh.c dh.h]
+     First rough implementation of the diffie-hellman group exchange.  The
+     client can ask the server for bigger groups to perform the diffie-hellman
+     in, thus increasing the attack complexity when using ciphers with longer
+     keys.  University of Windsor provided network, T the company.
+   - markus@cvs.openbsd.org  2000/10/11 13:59:52
+     [auth-rsa.c auth2.c]
+     clear auth options unless auth sucessfull
+   - markus@cvs.openbsd.org  2000/10/11 14:00:27
+     [auth-options.h]
+     clear auth options unless auth sucessfull
+   - markus@cvs.openbsd.org  2000/10/11 14:03:27
+     [scp.1 scp.c]
+     support 'scp -o' with help from mouring@pconline.com
+   - markus@cvs.openbsd.org  2000/10/11 14:11:35
+     [dh.c]
+     Wall
+   - markus@cvs.openbsd.org  2000/10/11 14:14:40
+     [auth.h auth2.c readconf.c readconf.h readpass.c servconf.c servconf.h]
+     [ssh.h sshconnect2.c sshd_config auth2-skey.c cli.c cli.h]
+     add support for s/key (kbd-interactive) to ssh2, based on work by
+     mkiernan@avantgo.com and me
+   - markus@cvs.openbsd.org  2000/10/11 14:27:24
+     [auth.c auth1.c auth2.c authfile.c cipher.c cipher.h kex.c kex.h]
+     [myproposal.h packet.c readconf.c session.c ssh.c ssh.h sshconnect1.c]
+     [sshconnect2.c sshd.c]
+     new cipher framework
+   - markus@cvs.openbsd.org  2000/10/11 14:45:21
+     [cipher.c]
+     remove DES
+   - markus@cvs.openbsd.org  2000/10/12 03:59:20
+     [cipher.c cipher.h sshconnect1.c sshconnect2.c sshd.c]
+     enable DES in SSH-1 clients only
+   - markus@cvs.openbsd.org  2000/10/12 08:21:13
+     [kex.h packet.c]
+     remove unused
+   - markus@cvs.openbsd.org  2000/10/13 12:34:46
+     [sshd.c]
+     Kludge for F-Secure Macintosh < 1.0.2; appro@fy.chalmers.se
+   - markus@cvs.openbsd.org  2000/10/13 12:59:15
+     [cipher.c cipher.h myproposal.h  rijndael.c rijndael.h]
+     rijndael/aes support
+   - markus@cvs.openbsd.org  2000/10/13 13:10:54
+     [sshd.8]
+     more info about -V
+   - markus@cvs.openbsd.org  2000/10/13 13:12:02
+     [myproposal.h]
+     prefer no compression
 
 20001007
  - (stevesk) Print PAM return value in PAM log messages to aid
index 2d47f637cb5812c8ae08b58c697ed6e8330f9d9f..af0886cdede0f895c8a93d9d58611514736d045e 100644 (file)
@@ -35,13 +35,13 @@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
 
 TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) $(EXTRA_TARGETS)
 
-LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o cygwin_util.o deattack.o dispatch.o dsa.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o 
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o cli.o compat.o compress.o crc32.o cygwin_util.o deattack.o dispatch.o dsa.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o 
 
-LIBOPENBSD_COMPAT_OBJS=bsd-arc4random.o bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-inet_aton.o bsd-inet_ntoa.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-sigaction.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bsd-strsep.o bsd-strtok.o fake-getaddrinfo.o fake-getnameinfo.o next-posix.o
+LIBOPENBSD_COMPAT_OBJS=bsd-arc4random.o bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-inet_aton.o bsd-inet_ntoa.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-sigaction.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bsd-strsep.o bsd-strtok.o bsd-vis.o fake-getaddrinfo.o fake-getnameinfo.o next-posix.o
 
 SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o
 
-SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o
+SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o dh.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o
 
 TROFFMAN       = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 sftp-server.8
 CATMAN         = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 sftp-server.0
index 799cf261a70eba780d14fb06c6e678a6cc5f1e9a..21a9625e3569e4fa3bf1057dbea60dea15f0dc85 100644 (file)
@@ -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,
index da6965266af350674dfe264ab2c29eff82c3cd01..c9c149d69b74721cfce199c6481a5cc631020ea8 100644 (file)
@@ -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;
                        }
index 9044d98bea875a0916673958a05321024f8fd1e6..02ac5df1d1e89a21d43dfc78ddb743f025a8b285 100644 (file)
@@ -22,4 +22,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
index d6bcbabeae4b860f6c9fd667a7b6f2c73ae3c3c1..99eab1e396520a0ad2216ec4099e61ea7b75f93f 100644 (file)
@@ -257,7 +257,7 @@ void do_pam_setcred()
        pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
        if (pam_retval != PAM_SUCCESS) {
                fatal("PAM setcred failed[%d]: %.200s", 
-                       pam_setcred, PAM_STRERROR(pamh, pam_retval));
+                       pam_retval, PAM_STRERROR(pamh, pam_retval));
        }
 }
 
index 8dd6034d877337804477d0103a7a41876ef81e33..184ce154cffc2a6a43aab58da06af7cfe1ebdf68 100644 (file)
@@ -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 $");
 
 #if !defined(USE_PAM) && !defined(HAVE_OSF_SIA)
 
@@ -156,7 +156,7 @@ auth_password(struct passwd * pw, const char *password)
        }
 #endif
 
-#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)
index 072e385ab29ef17a82f9f606b3870bf97eb8928e..3070c9d4138885743f64da1dad2efefc512bd674 100644 (file)
@@ -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. */
index 901c8d1390e70f024a357c070e9e189f39b1dc48..8314e23a100cf911267484c2ae89835352179bb6 100644 (file)
@@ -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);
        /*
index 8aefc8fadadd7507201194d6d6ac97ac4f3f7724..522f01f84cb982d9267be7263ac088d68e573341 100644 (file)
@@ -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.31 2000/10/11 19:59:52 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);
 
@@ -277,6 +284,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/auth.c b/auth.c
index 883f08ab03cfd9c007af0cb40d9319b630d0027b..bc42c96cb7607fb44d4e072852a7eeb8d90f9748 100644 (file)
--- a/auth.c
+++ b/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/auth.h b/auth.h
index 65bf7ae1012b9bc4b3bec71f1110dbc27102fbb0..c4a8ac54407a67811efd5712a8d4a6bc3c813613 100644 (file)
--- a/auth.h
+++ b/auth.h
 #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    auth2_skey(Authctxt *authctxt);
 
-int allowed_user(struct passwd * pw);
+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/auth1.c b/auth1.c
index 99639b59f433993fbf57bd64b49a9d6b8977fb37..520da640c6bd3c4b340b72e9595cb29dd89bbeb4 100644 (file)
--- a/auth1.c
+++ b/auth1.c
  */
 
 #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 $");
+
+#ifdef HAVE_OSF_SIA
+# include <sia.h>
+# include <siad.h>
+#endif
 
 #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"
 #include "auth.h"
 #include "session.h"
 
-#ifdef HAVE_OSF_SIA
-# include <sia.h>
-# include <siad.h>
-#endif
-
 /* import */
 extern ServerOptions options;
 extern char *forced_command;
+
+#ifdef WITH_AIXAUTHENTICATE
+extern char *aixloginmsg;
+#endif /* WITH_AIXAUTHENTICATE */
 #ifdef HAVE_OSF_SIA
 extern int saved_argc;
 extern char **saved_argv;
@@ -67,89 +70,21 @@ 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());
-
-#ifdef WITH_AIXAUTHENTICATE 
-       loginfailed(user,get_canonical_hostname(),"ssh");
-#endif /* WITH_AIXAUTHENTICATE */
-
-       /* 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;
-#ifndef SKEY
-               (void)packet_read(&plen);
-#else /* SKEY */
-               int type = packet_read(&plen);
-               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;
        BIGNUM *n;
-       char *client_user = NULL, *password = NULL;
+       char *client_user, *password;
        char user[1024];
        unsigned int dlen;
        int plen, nlen, elen;
@@ -162,8 +97,12 @@ do_authloop(struct passwd * pw)
        packet_send();
        packet_write_wait();
 
+       client_user = NULL;
+
        for (attempt = 1;; attempt++) {
-               int authenticated = 0;
+               /* default to fail */
+               authenticated = 0;
+
                strlcpy(user, "", sizeof user);
 
                /* Get a packet from the client. */
@@ -174,7 +113,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 {
@@ -182,14 +120,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 {
@@ -197,7 +134,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;
@@ -219,11 +156,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;
@@ -243,8 +181,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);
@@ -275,7 +212,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);
 
@@ -322,7 +259,7 @@ do_authloop(struct passwd * pw)
                                authenticated = 1;
                        }
 #else /* !USE_PAM && !HAVE_OSF_SIA */
-                       /* Try authentication with the password. */
+                       /* Try authentication with the password. */
                        authenticated = auth_password(pw, password);
 #endif /* USE_PAM */
 
@@ -334,16 +271,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;
@@ -356,8 +295,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;
@@ -376,12 +316,14 @@ 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");
 
 #ifdef HAVE_CYGWIN
-               if (authenticated &&
+               if (authenticated && 
                    !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD,pw->pw_uid)) {
                        packet_disconnect("Authentication rejected for uid %d.",
-                                         (int) pw->pw_uid);
+                       (int)pw->pw_uid);
                        authenticated = 0;
                }
 #endif
@@ -391,7 +333,7 @@ do_authloop(struct passwd * pw)
                 * 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 {
@@ -407,41 +349,33 @@ 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);
 
 #ifdef USE_PAM
-               if (authenticated) {
-                       if (!do_pam_account(pw->pw_name, client_user)) {
-                               if (client_user != NULL) {
-                                       xfree(client_user);
-                                       client_user = NULL;
-                               }
-                               do_fake_authloop1(pw->pw_name);
-                       }
-                       return;
-               }
-#else /* USE_PAM */
-               if (authenticated) {
-                       return;
-               }
-#endif /* USE_PAM */
+               if (authenticated && !do_pam_account(pw->pw_name, client_user))
+                       authenticated = 0;
+#endif
 
                if (client_user != NULL) {
                        xfree(client_user);
                        client_user = NULL;
                }
 
+               if (authenticated)
+                       return;
+
                if (attempt > AUTH_FAIL_MAX) {
 #ifdef WITH_AIXAUTHENTICATE 
-                       loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
+                       loginfailed(user,get_canonical_hostname(),"ssh");
 #endif /* WITH_AIXAUTHENTICATE */
-                       packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
+                       packet_disconnect(AUTH_FAIL_MSG, luser);
                }
 
                /* Send a message indicating that the authentication attempt failed. */
@@ -462,9 +396,6 @@ do_authentication()
        int plen;
        unsigned int ulen;
        char *user;
-#ifdef WITH_AIXAUTHENTICATE
-       extern char *aixloginmsg;
-#endif /* WITH_AIXAUTHENTICATE */
 
        /* Get the name of the user that we wish to log in as. */
        packet_read_expect(&plen, SSH_CMSG_USER);
@@ -485,38 +416,38 @@ 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;
+       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;
 #ifdef HAVE_PW_CLASS_IN_PASSWD
-       pwcopy.pw_class = xstrdup(pw->pw_class);
+               pwcopy.pw_class = xstrdup(pw->pw_class);
 #endif
-       pwcopy.pw_dir = xstrdup(pw->pw_dir);
-       pwcopy.pw_shell = xstrdup(pw->pw_shell);
-       pw = &pwcopy;
+               pwcopy.pw_dir = xstrdup(pw->pw_dir);
+               pwcopy.pw_shell = xstrdup(pw->pw_shell);
+               pw = &pwcopy;
+       } else {
+               pw = NULL;
+       }
 
 #ifdef USE_PAM
-       start_pam(pw);
+       if (pw)
+               start_pam(pw);
 #endif
 
-#ifndef HAVE_CYGWIN
        /*
         * If we are not running as root, the user must have the same uid as
-        * the server.
-        * Rule not valid on Windows systems.
+        * the server. (Unless you are running Windows)
         */
-       if (getuid() != 0 && pw->pw_uid != getuid())
+#ifndef HAVE_CYGWIN
+       if (getuid() != 0 && pw && pw->pw_uid != getuid())
                packet_disconnect("Cannot change user when server not running as root.");
 #endif
 
-       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 &&
@@ -527,30 +458,33 @@ do_authentication()
            auth_pam_password(pw, "")) {
 #elif defined(HAVE_OSF_SIA)
            (sia_validate_user(NULL, saved_argc, saved_argv, 
-           get_canonical_hostname(), pw->pw_name, NULL, 0, NULL, 
-           "") == SIASUCCESS)) {
+           get_canonical_hostname(), pw->pw_name, NULL, 0, 
+                NULL, "") == SIASUCCESS)) {
 #else /* !HAVE_OSF_SIA && !USE_PAM */
-           auth_password(pw, "")) {
+           auth_password(pw, "")) {
 #endif /* USE_PAM */
                /* 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);
+       packet_send();
+       packet_write_wait();
+
 #ifdef WITH_AIXAUTHENTICATE
        /* We don't have a pty yet, so just label the line as "ssh" */
        if (loginsuccess(user,get_canonical_hostname(),"ssh",&aixloginmsg) < 0)
                aixloginmsg = NULL;
 #endif /* WITH_AIXAUTHENTICATE */
-       packet_start(SSH_SMSG_SUCCESS);
-       packet_send();
-       packet_write_wait();
 
        /* Perform session preparation. */
        do_authenticated(pw);
diff --git a/auth2.c b/auth2.c
index 2c8c0bfdd123fd053654bb827ee3e91584e2af9c..f34b586d4c5f1048a78d6ebe3ea3f0d732d5cf6e 100644 (file)
--- a/auth2.c
+++ b/auth2.c
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.19 2000/10/11 20:27:23 markus Exp $");
+
+#ifdef HAVE_OSF_SIA
+# include <sia.h>
+# include <siad.h>
+#endif
 
 #include <openssl/dsa.h>
 #include <openssl/rsa.h>
@@ -35,7 +40,6 @@ RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $");
 #include "pty.h"
 #include "packet.h"
 #include "buffer.h"
-#include "cipher.h"
 #include "servconf.h"
 #include "compat.h"
 #include "channels.h"
@@ -52,59 +56,85 @@ RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $");
 #include "uidswap.h"
 #include "auth-options.h"
 
-#ifdef HAVE_OSF_SIA
-# include <sia.h>
-# include <siad.h>
-#endif
-
 /* import */
 extern ServerOptions options;
 extern unsigned char *session_id2;
 extern int session_id2_len;
 
+#ifdef WITH_AIXAUTHENTICATE
+extern char *aixloginmsg;
+#endif
+#ifdef HAVE_OSF_SIA
+extern int saved_argc;
+extern char **saved_argv;
+#endif
+
+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 *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, NULL);
+       dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
        do_authenticated2();
 }
 
@@ -121,13 +151,17 @@ protocol_error(int type, int plen, void *ctxt)
 void
 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);
@@ -150,65 +184,99 @@ input_service_request(int type, int plen, void *ctxt)
 void
 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;
-#ifdef WITH_AIXAUTHENTICATE
-       extern char *aixloginmsg;
-#endif /* WITH_AIXAUTHENTICATE */
 
-       user = packet_get_string(&len);
-       service = packet_get_string(&len);
-       method = packet_get_string(&len);
-       if (++attempt == AUTH_FAIL_MAX) {
+       if (authctxt == NULL)
+               fatal("input_userauth_request: no authctxt");
+       if (authctxt->attempt++ >= AUTH_FAIL_MAX) {
 #ifdef WITH_AIXAUTHENTICATE 
                loginfailed(user,get_canonical_hostname(),"ssh");
 #endif /* WITH_AIXAUTHENTICATE */
                packet_disconnect("too many failed userauth_requests");
        }
-       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);
+       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);
+       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);
+#ifdef USE_PAM
+                       start_pam(pw);
+#endif
+               } 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;
                }
        }
 
-#ifdef HAVE_CYGWIN
-       if (authenticated && !check_nt_auth(strcmp(method, "password") == 0, pw->pw_uid)) {
-               packet_disconnect("Authentication rejected for uid %d.",
-                                 (int) pw->pw_uid);
+       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 (!authctxt->valid && authenticated == 1) {
+               log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
                authenticated = 0;
        }
-#endif
 
-       if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
+       /* 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());
        }
 
 #ifdef USE_PAM
-       if (authenticated && !do_pam_account(pw->pw_name, NULL))
+       if (authenticated && !do_pam_account(authctxt->pw->pw_name, NULL))
                authenticated = 0;
 #endif /* USE_PAM */
 
+       /* 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) {
@@ -216,18 +284,29 @@ input_userauth_request(int type, int plen, void *ctxt)
        } 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) {
 #ifdef WITH_AIXAUTHENTICATE
                /* We don't have a pty yet, so just label the line as "ssh" */
-               if (loginsuccess(user,get_canonical_hostname(),"ssh",
+               if (loginsuccess(user, get_canonical_hostname(), "ssh",
                                &aixloginmsg) < 0)
                        aixloginmsg = NULL;
 #endif /* WITH_AIXAUTHENTICATE */
@@ -237,73 +316,106 @@ input_userauth_request(int type, int plen, void *ctxt)
                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)
 {
-#ifdef HAVE_OSF_SIA
-       extern int saved_argc;
-       extern char **saved_argv;
-#endif
-
+       /* disable method "none", only allowed one time */
+       Authmethod *m = authmethod_lookup("none");
+       if (m != NULL)
+               m->enabled = NULL;
        packet_done();
 
+       if (authctxt->valid == 0)
+               return(0);
+               
+#ifdef HAVE_CYGWIN
+       if (check_nt_auth(1, authctxt->pw->pw_uid) == 0)
+               return(0);
+#endif
 #ifdef USE_PAM
-       return auth_pam_password(pw, "");
+       return auth_pam_password(authctxt->pw, "");
 #elif defined(HAVE_OSF_SIA)
-       return(sia_validate_user(NULL, saved_argc, saved_argv, 
-               get_canonical_hostname(), pw->pw_name, NULL, 0, NULL, 
-               "") == SIASUCCESS);
+       return (sia_validate_user(NULL, saved_argc, saved_argv, 
+               get_canonical_hostname(), authctxt->pw->pw_name, NULL, 
+               0, NULL, "") == SIASUCCESS);
 #else /* !HAVE_OSF_SIA && !USE_PAM */
-       return auth_password(pw, "");
+       return auth_password(authctxt->pw, "");
 #endif /* USE_PAM */
 }
+
 int
-ssh2_auth_password(struct passwd *pw)
+userauth_passwd(Authctxt *authctxt)
 {
        char *password;
        int authenticated = 0;
        int change;
        unsigned int len;
-#ifdef HAVE_OSF_SIA
-       extern int saved_argc;
-       extern char **saved_argv;
-#endif
        change = packet_get_char();
        if (change)
                log("password change not supported");
        password = packet_get_string(&len);
        packet_done();
-       if (options.password_authentication &&
+       if (authctxt->valid &&
+#ifdef HAVE_CYGWIN
+               check_nt_auth(1, authctxt->pw->pw_uid) &&
+#endif
 #ifdef USE_PAM
-           auth_pam_password(pw, password) == 1)
+           auth_pam_password(authctxt->pw, password) == 1)
 #elif defined(HAVE_OSF_SIA)
            sia_validate_user(NULL, saved_argc, saved_argv, 
-                       get_canonical_hostname(), pw->pw_name, NULL, 0, 
+                       get_canonical_hostname(), authctxt->pw->pw_name, NULL, 0, 
                        NULL, password) == SIASUCCESS)
 #else /* !USE_PAM && !HAVE_OSF_SIA */
-           auth_password(pw, password) == 1)
+           auth_password(authctxt->pw, password) == 1)
 #endif /* USE_PAM */
                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);
+#ifdef HAVE_CYGWIN
+       if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
+               return(0);
+#endif
+       return authenticated;
+}
+
 int
-ssh2_auth_pubkey(struct passwd *pw, char *service)
+userauth_pubkey(Authctxt *authctxt)
 {
        Buffer b;
        Key *key;
@@ -312,15 +424,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);
@@ -337,11 +449,11 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
                        }
                        /* 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);
@@ -350,15 +462,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
@@ -367,7 +479,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);
@@ -376,61 +488,73 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
                                authenticated = -1;
                        }
                }
+               if (authenticated != 1)
+                       auth_clear_options();
                key_free(key);
        }
        xfree(pkalg);
        xfree(pkblob);
+#ifdef HAVE_CYGWIN
+       if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
+               return(0);
+#endif
        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);
                }
-#ifdef USE_PAM
-               start_pam(pw);
-#endif
-               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;
-#ifdef HAVE_PW_CLASS_IN_PASSWD
-               copy->pw_class = xstrdup(pw->pw_class);
-#endif
-               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 */
@@ -445,6 +569,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);
 
@@ -550,3 +677,20 @@ 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;
+#ifdef HAVE_PW_CLASS_IN_PASSWD
+       copy->pw_class = xstrdup(pw->pw_class);
+#endif
+       copy->pw_dir = xstrdup(pw->pw_dir);
+       copy->pw_shell = xstrdup(pw->pw_shell);
+       return copy;
+}
index 433623ef71991a5f2f2ecf6019701edd53d83834..d06cc536c9dd593e611e84d5bf2095d0aebc7994 100644 (file)
--- a/authfd.c
+++ b/authfd.c
@@ -35,7 +35,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: authfd.c,v 1.28 2000/09/21 11:07:50 markus Exp $");
+RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $");
 
 #include "ssh.h"
 #include "rsa.h"
@@ -56,6 +56,10 @@ RCSID("$OpenBSD: authfd.c,v 1.28 2000/09/21 11:07:50 markus Exp $");
 /* 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
@@ -242,7 +246,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);
@@ -341,7 +345,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);
@@ -390,7 +394,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);
@@ -537,6 +541,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:
index 808575cd8b26845247fa1952b2325cda3e17f44b..2d2465206b49706442857ea9293eb816a7e37957 100644 (file)
--- a/authfd.h
+++ b/authfd.h
@@ -11,7 +11,7 @@
  * called by a name other than "ssh" or "Secure Shell".
  */
 
-/* RCSID("$OpenBSD: authfd.h,v 1.12 2000/09/21 11:07:51 markus 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,9 @@
 #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
 
 
index afedd7bbbe957bedaaae2c3e23864ed6e5f11cee..d1a97d7734da27e2e427afe28612c31f26b963ae 100644 (file)
@@ -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/bsd-vis.c b/bsd-vis.c
new file mode 100644 (file)
index 0000000..94283a0
--- /dev/null
+++ b/bsd-vis.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: vis.c,v 1.5 2000/07/19 15:25:13 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef HAVE_VIS
+
+#include "includes.h"
+
+#define        isoctal(c)      (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+
+/*
+ * vis - visually encode characters
+ */
+char *vis(char *dst, int c, int flag, int nextc)
+{
+       if (((u_int)c <= UCHAR_MAX && isascii((u_char)c) &&
+           isgraph((u_char)c)) ||
+          ((flag & VIS_SP) == 0 && c == ' ') ||
+          ((flag & VIS_TAB) == 0 && c == '\t') ||
+          ((flag & VIS_NL) == 0 && c == '\n') ||
+          ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
+               *dst++ = c;
+               if (c == '\\' && (flag & VIS_NOSLASH) == 0)
+                       *dst++ = '\\';
+               *dst = '\0';
+               return (dst);
+       }
+
+       if (flag & VIS_CSTYLE) {
+               switch(c) {
+               case '\n':
+                       *dst++ = '\\';
+                       *dst++ = 'n';
+                       goto done;
+               case '\r':
+                       *dst++ = '\\';
+                       *dst++ = 'r';
+                       goto done;
+               case '\b':
+                       *dst++ = '\\';
+                       *dst++ = 'b';
+                       goto done;
+#ifdef __STDC__
+               case '\a':
+#else
+               case '\007':
+#endif
+                       *dst++ = '\\';
+                       *dst++ = 'a';
+                       goto done;
+               case '\v':
+                       *dst++ = '\\';
+                       *dst++ = 'v';
+                       goto done;
+               case '\t':
+                       *dst++ = '\\';
+                       *dst++ = 't';
+                       goto done;
+               case '\f':
+                       *dst++ = '\\';
+                       *dst++ = 'f';
+                       goto done;
+               case ' ':
+                       *dst++ = '\\';
+                       *dst++ = 's';
+                       goto done;
+               case '\0':
+                       *dst++ = '\\';
+                       *dst++ = '0';
+                       if (isoctal(nextc)) {
+                               *dst++ = '0';
+                               *dst++ = '0';
+                       }
+                       goto done;
+               }
+       }
+       if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) {        
+               *dst++ = '\\';
+               *dst++ = ((u_char)c >> 6 & 07) + '0';
+               *dst++ = ((u_char)c >> 3 & 07) + '0';
+               *dst++ = ((u_char)c & 07) + '0';
+               goto done;
+       }
+       if ((flag & VIS_NOSLASH) == 0)
+               *dst++ = '\\';
+       if (c & 0200) {
+               c &= 0177;
+               *dst++ = 'M';
+       }
+       if (iscntrl(c)) {
+               *dst++ = '^';
+               if (c == 0177)
+                       *dst++ = '?';
+               else
+                       *dst++ = c + '@';
+       } else {
+               *dst++ = '-';
+               *dst++ = c;
+       }
+done:
+       *dst = '\0';
+       return (dst);
+}
+#endif /* HAVE_VIS */
diff --git a/bsd-vis.h b/bsd-vis.h
new file mode 100644 (file)
index 0000000..52e867b
--- /dev/null
+++ b/bsd-vis.h
@@ -0,0 +1,32 @@
+#ifndef _BSD_VIS_H
+#define        _BSD_VIS_H
+
+#include "config.h"
+
+#ifndef HAVE_VIS
+
+/*
+ * to select alternate encoding format
+ */
+#define        VIS_OCTAL       0x01    /* use octal \ddd format */
+#define        VIS_CSTYLE      0x02    /* use \[nrft0..] where appropriate */
+
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define        VIS_SP          0x04    /* also encode space */
+#define        VIS_TAB         0x08    /* also encode tab */
+#define        VIS_NL          0x10    /* also encode newline */
+#define        VIS_WHITE       (VIS_SP | VIS_TAB | VIS_NL)
+#define        VIS_SAFE        0x20    /* only encode "unsafe" characters */
+
+/*
+ * other
+ */
+#define        VIS_NOSLASH     0x40    /* inhibit printing '\' */
+
+char   *vis (char *, int, int, int);
+#endif /* HAVE_VIS */
+
+#endif /* _BSD_VIS_H */
index c7985a79c0c41552923a330f2018e823facf91b0..226e4256a7a817f0612066fd6d8e079375adf808 100644 (file)
--- a/cipher.c
+++ b/cipher.c
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: cipher.c,v 1.31 2000/09/12 00:38:32 deraadt Exp $");
+RCSID("$OpenBSD: cipher.c,v 1.35 2000/10/13 18:59:13 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,48 +135,84 @@ RCSID("$OpenBSD: cipher.c,v 1.31 2000/09/12 00:38:32 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).
@@ -130,88 +243,255 @@ swap_bytes(const unsigned char *src, unsigned char *dst_, int n)
        }
 }
 
-/*
- * Names of all encryption algorithms.
- * These must match the numbers defined in cipher.h.
- */
-static char *cipher_names[] =
-{
-       "none",
-       "idea",
-       "des",
-       "3des",
-       "tss",
-       "rc4",          /* Alleged 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 {
+                       debug("cipher ok: %s [%s]", p, names);
                }
        }
+       debug("ciphers ok: [%s]", names);
        xfree(ciphers);
        return 1;
 }
@@ -224,14 +504,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 +555,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));
-       }
-}
index bc7a5e2243120032cc10842dc184993e3e0054af..97bc8891fbc1e91a4a5dde0b9d38691134d55fc3 100644 (file)
--- a/cipher.h
+++ b/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
 #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 */
 #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;
@@ -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/cli.c b/cli.c
new file mode 100644 (file)
index 0000000..abe3f7c
--- /dev/null
+++ b/cli.c
@@ -0,0 +1,195 @@
+#include "includes.h"
+RCSID("$Id$");
+
+#include "xmalloc.h"
+#include "ssh.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/cli.h b/cli.h
new file mode 100644 (file)
index 0000000..e33ce4a
--- /dev/null
+++ b/cli.h
@@ -0,0 +1,14 @@
+#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 */
index eeb6e2ef1268446ccf8fd22d1fac176249cc868c..19dc76d961667934c2bd2ce7a9f8f6875a03fea1 100644 (file)
--- a/compat.c
+++ b/compat.c
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: compat.c,v 1.23 2000/09/07 21:13:37 markus Exp $");
+RCSID("$OpenBSD: compat.c,v 1.24 2000/10/10 20:20:45 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,39 @@ 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}
+               {"^.*MindTerm",         0},
+               {"^2\\.1\\.0 ",         SSH_BUG_SIGBLOB|SSH_BUG_HMAC},
+               {"^2\\.0\\.",           SSH_BUG_SIGBLOB|SSH_BUG_HMAC|SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD},
+               {"^2\\.[23]\\.0 ",      SSH_BUG_HMAC|SSH_COMPAT_SESSIONID_ENCODING},
+               {"^2\\.[2-9]\\.",       SSH_COMPAT_SESSIONID_ENCODING},
+               {"^2\\.",               SSH_BUG_HMAC|SSH_COMPAT_SESSIONID_ENCODING},
+               {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(&reg, check[i].pat, REG_EXTENDED|REG_NOSUB);
+               if (ret != 0) {
+                       regerror(ret, &reg, ebuf, sizeof(ebuf));
+                       ebuf[sizeof(ebuf)-1] = '\0';
+                       error("regerror: %s", ebuf);
+                       continue;
+               }
+               ret = regexec(&reg, version, 0, NULL, 0);
+               regfree(&reg);
+               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     ","
index c342d14fa96a669dc031361743be9a5490e8af20..b3ab2fdb84c595d225f0e6a8c35a9b292c8e51ae 100644 (file)
@@ -265,10 +265,10 @@ if test -z "$no_libnsl" ; then
 fi
 
 # Checks for header files.
-AC_CHECK_HEADERS(bstring.h endian.h floatingpoint.h getopt.h lastlog.h limits.h login.h login_cap.h maillock.h netdb.h netgroup.h netinet/in_systm.h paths.h poll.h pty.h shadow.h security/pam_appl.h sys/bitypes.h sys/bsdtty.h sys/cdefs.h sys/poll.h sys/select.h sys/stat.h sys/stropts.h sys/sysmacros.h sys/time.h sys/ttcompat.h sys/un.h stddef.h time.h ttyent.h usersec.h util.h utmp.h utmpx.h)
+AC_CHECK_HEADERS(bstring.h endian.h floatingpoint.h getopt.h lastlog.h limits.h login.h login_cap.h maillock.h netdb.h netgroup.h netinet/in_systm.h paths.h poll.h pty.h shadow.h security/pam_appl.h sys/bitypes.h sys/bsdtty.h sys/cdefs.h sys/poll.h sys/select.h sys/stat.h sys/stropts.h sys/sysmacros.h sys/time.h sys/ttcompat.h sys/un.h stddef.h time.h ttyent.h usersec.h util.h utmp.h utmpx.h vis.h)
 
 dnl    Checks for library functions.
-AC_CHECK_FUNCS(arc4random atexit b64_ntop bcopy bindresvport_af clock fchmod freeaddrinfo futimes gai_strerror getaddrinfo getnameinfo getrusage getttyent inet_aton inet_ntoa innetgr login_getcapbool md5_crypt memmove mkdtemp on_exit openpty rresvport_af setenv seteuid setlogin setproctitle setreuid setrlimit sigaction sigvec snprintf strerror strlcat strlcpy strsep strtok_r vsnprintf vhangup _getpty __b64_ntop)
+AC_CHECK_FUNCS(arc4random atexit b64_ntop bcopy bindresvport_af clock fchmod freeaddrinfo futimes gai_strerror getaddrinfo getnameinfo getrusage getttyent inet_aton inet_ntoa innetgr login_getcapbool md5_crypt memmove mkdtemp on_exit openpty rresvport_af setenv seteuid setlogin setproctitle setreuid setrlimit sigaction sigvec snprintf strerror strlcat strlcpy strsep strtok_r vsnprintf vhangup vis _getpty __b64_ntop)
 dnl    Checks for time functions
 AC_CHECK_FUNCS(gettimeofday time)
 dnl    Checks for libutil functions
diff --git a/dh.c b/dh.c
new file mode 100644 (file)
index 0000000..ff84619
--- /dev/null
+++ b/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/dh.h b/dh.h
new file mode 100644 (file)
index 0000000..09b11fd
--- /dev/null
+++ b/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
index 37881f6b00f85d7461fd753d91ad6495ab5271d4..797c5e851e163b3d4505bbf1262907489d434c5b 100644 (file)
@@ -87,7 +87,9 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
 #ifdef HAVE_SYS_SYSMACROS_H
 # include <sys/sysmacros.h>
 #endif
-
+#ifdef HAVE_VIS_H
+# include <vis.h>
+#endif
 #include "version.h"
 #include "openbsd-compat.h"
 #include "cygwin_util.h"
diff --git a/kex.c b/kex.c
index 8a83db47e8067761e8ed37dfb34aeff65efecfd6..68b9e522e73d96bfdc9b8c502ccb700ef7427888 100644 (file)
--- a/kex.c
+++ b/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)
 {
@@ -236,6 +259,59 @@ kex_hash(
        return digest;
 }
 
+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)
 {
@@ -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/kex.h b/kex.h
index 8c89687b6068f23c166161ca44c9e7f01b0bf8f9..212958131272e1c827d3724ea1e261dc68470e6f 100644 (file)
--- a/kex.h
+++ b/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/log.c b/log.c
index 13033ab4260e96e2de93b7c396be1e1031aef977..ce89c59ba82157de408df663eba94346534e15ce 100644 (file)
--- a/log.c
+++ b/log.c
@@ -36,7 +36,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: log.c,v 1.10 2000/09/12 20:53:10 markus Exp $");
+RCSID("$OpenBSD: log.c,v 1.11 2000/09/30 16:27:43 markus Exp $");
 
 #include "ssh.h"
 #include "xmalloc.h"
@@ -208,6 +208,7 @@ static struct {
        { "ERROR",      SYSLOG_LEVEL_ERROR },
        { "INFO",       SYSLOG_LEVEL_INFO },
        { "VERBOSE",    SYSLOG_LEVEL_VERBOSE },
+       { "DEBUG",      SYSLOG_LEVEL_DEBUG1 },
        { "DEBUG1",     SYSLOG_LEVEL_DEBUG1 },
        { "DEBUG2",     SYSLOG_LEVEL_DEBUG2 },
        { "DEBUG3",     SYSLOG_LEVEL_DEBUG3 },
index 18db954c588ba6251c4ca6ee7f1988c9ba26d6b7..98060dc3528e968c486cc1d359897228f8ebad38 100644 (file)
  * (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        ""
 
 
index 671728fbce402e7b734997b9fe13bad2dc8c55e2..f3ae2f3ffa3580e22320f6ea8922fbba0067bc15 100644 (file)
@@ -19,6 +19,7 @@
 #include "bsd-inet_ntoa.h"
 #include "bsd-strsep.h"
 #include "bsd-strtok.h"
+#include "bsd-vis.h"
 
 /* rfc2553 socket API replacements */
 #include "fake-getaddrinfo.h"
index 62239eb7d6541c90e4eb4d4230a382e7252d5864..8c9374fca3b81c683486c448adf456af75f22450 100644 (file)
--- a/packet.c
+++ b/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;
index 4f4a16de8f18775bd8340d837c269feb9289a6c3..c6fdd5308445aa1f595d090e4eac008bf2610f07 100644 (file)
  */
 
 #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 },
@@ -290,6 +292,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;
@@ -664,6 +674,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;
@@ -734,6 +746,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)
index 23df57b4271fae4726390a73e5e7ae39b5be2816..e94213fa1770c4ce9214f10082a69e17250ff930 100644 (file)
@@ -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. */
index c38292f15716f801cbd12417c970488bbd6ce0f5..f3a7dcbed274da056fcb0810973218949a7bc969 100644 (file)
  */
 
 #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/rijndael.c b/rijndael.c
new file mode 100644 (file)
index 0000000..bb592bc
--- /dev/null
@@ -0,0 +1,493 @@
+/*     $OpenBSD: rijndael.c,v 1.1 2000/10/13 18:59:14 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/rijndael.h b/rijndael.h
new file mode 100644 (file)
index 0000000..c13f18c
--- /dev/null
@@ -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/scp.1 b/scp.1
index 9ae2ab64cbed5a4b0df3bf7189a8b13a71410d07..eb02837de78c1fa47bf259e151953f47da3a6f22 100644 (file)
--- a/scp.1
+++ b/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/scp.c b/scp.c
index 356d97e6370643d51c72bb9cd85efa3cb3f93c3d..40cf72963b0911cb2c62fc21d5cae3ad243396ac 100644 (file)
--- a/scp.c
+++ b/scp.c
@@ -75,7 +75,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: scp.c,v 1.40 2000/09/21 11:11:42 markus Exp $");
+RCSID("$OpenBSD: scp.c,v 1.41 2000/10/11 20:03:27 markus Exp $");
 
 #include "ssh.h"
 #include "xmalloc.h"
@@ -102,6 +102,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;
 
@@ -114,12 +117,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;
 
@@ -129,23 +126,16 @@ int compress_flag = 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
@@ -158,8 +148,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
@@ -178,10 +168,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]);
@@ -190,41 +177,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_flag)
-                       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);
        }
@@ -290,27 +249,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("-o Batchmode 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. */
@@ -325,24 +302,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_flag = 1;
-                       break;
-               case 'q':
-                       showprogress = 0;
-                       break;
                case '?':
                default:
                        usage();
@@ -1287,3 +1246,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;
+}
index 81551081432a21f438541ffcdca8a703bba03a25..e90defe61e598d291cf08879b78f8e59400261fc 100644 (file)
@@ -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.52 2000/10/11 20:14:39 markus Exp $");
 
 #include "ssh.h"
 #include "servconf.h"
@@ -61,6 +61,7 @@ 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
@@ -148,6 +149,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;
@@ -183,7 +186,7 @@ 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,
@@ -220,6 +223,7 @@ static struct {
        { "afstokenpassing", sAFSTokenPassing },
 #endif
        { "passwordauthentication", sPasswordAuthentication },
+       { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
 #ifdef SKEY
        { "skeyauthentication", sSkeyAuthentication },
 #endif
@@ -497,6 +501,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;
index f00a1284f55140c6d3ea93636d46bbe70d6d0eb6..ef0790c7bebd89512ae282eb2fc0c32b11bb5c05 100644 (file)
@@ -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.29 2000/10/11 20:14:39 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. */
index 0b31d5f196ff4674f001564d149abdff45a51c5c..dacb6a099db4d278776feaad665ea5ab6f0c5501 100644 (file)
--- a/session.c
+++ b/session.c
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.37 2000/09/07 20:27:53 deraadt Exp $");
+RCSID("$OpenBSD: session.c,v 1.38 2000/10/11 20:27:23 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"
index 59c997c3ff82b03c0ffd1fe03d55233e186b8845..2a7ba258ba441ba8493eb65f76f965023386354f 100644 (file)
@@ -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.
 .\"
index 33713446522ae6d1527348ed51aa8ef43b2ce61a..b91a09827975a80f146aa2d0943cc6df13d92421 100644 (file)
@@ -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.
index 216a8b6ef0f764751d96edefe9e5ca6d2e621944..e050f405193feb1634e65cb565121f52f81cf7a3 100644 (file)
@@ -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;
 
@@ -108,8 +111,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)
@@ -131,18 +136,83 @@ 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)
 {
@@ -152,7 +222,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)
@@ -176,6 +246,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;
                }
@@ -192,9 +264,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/ssh.1 b/ssh.1
index 5786782204e4e77dd00e2f3ca200e9d6fc1686e1..a73a07c658dad5e46b12bcb8184e193c6f835a2a 100644 (file)
--- a/ssh.1
+++ b/ssh.1
@@ -374,8 +374,9 @@ 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,7 +484,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.
+Multiple -v options increases the verbosity.
+Maximum is 3.
 .It Fl x
 Disables X11 forwarding.
 .It Fl X
diff --git a/ssh.c b/ssh.c
index 5188545454272c2960d0e55e4c479b2e245d90ef..ed31007ad7374e170f995cccdaed5e41549e0817 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -39,7 +39,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.66 2000/09/12 20:53:10 markus Exp $");
+RCSID("$OpenBSD: ssh.c,v 1.68 2000/10/11 20:27:24 markus Exp $");
 
 #include <openssl/evp.h>
 #include <openssl/dsa.h>
@@ -425,11 +425,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':
@@ -582,22 +583,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. */
 #ifdef HAVE_CYGWIN
        /* Ignore uid if running under Windows */
diff --git a/ssh.h b/ssh.h
index cc612d0d4b69adc68b4654adf7472136fb9241de..78254e45a5a8306a6244c7281f96f67967424b6a 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -12,7 +12,7 @@
  * called by a name other than "ssh" or "Secure Shell".
  */
 
-/* RCSID("$OpenBSD: ssh.h,v 1.51 2000/09/12 20:53:10 markus Exp $"); */
+/* RCSID("$OpenBSD: ssh.h,v 1.54 2000/10/11 20:27:24 markus Exp $"); */
 
 #ifndef SSH_H
 #define SSH_H
 #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
 
@@ -98,6 +90,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"
 
 #ifndef SSH_PROGRAM
 #define SSH_PROGRAM                    "/usr/bin/ssh"
@@ -423,7 +416,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. -----------------------*/
diff --git a/ssh2.h b/ssh2.h
index 47628ddd4ba27bc19ecfb5dae7a0cf1735e01600..fe0146cbdb9fac0d3b0e767364d409cb6b5c4893 100644 (file)
--- a/ssh2.h
+++ b/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 */
 
 #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
index 2bb4d5387d10426a1159531fa32a4554e4475f10..ce560791ceae33eb4b8f32591d77a1dcd6c94c82 100644 (file)
@@ -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)))
index eee09a19ca8a1e7b433bff8f889817015e4912a0..ca459f62c35e6ccffbed0fb14fd4e62949ec4ecf 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus Exp $");
+RCSID("$OpenBSD: sshconnect2.c,v 1.25 2000/10/12 09:59:19 markus Exp $");
 
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
@@ -37,7 +37,6 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus Exp $");
 #include "rsa.h"
 #include "buffer.h"
 #include "packet.h"
-#include "cipher.h"
 #include "uidswap.h"
 #include "compat.h"
 #include "readconf.h"
@@ -49,9 +48,13 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus 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;
@@ -65,8 +68,90 @@ 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;
@@ -116,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();
@@ -186,72 +271,175 @@ 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);
 }
 
 /*
@@ -270,8 +458,8 @@ struct Authctxt {
        const char *host;
        const char *service;
        AuthenticationConnection *agent;
-       int success;
        Authmethod *method;
+       int success;
 };
 struct Authmethod {
        char    *name;          /* string to compare against server's list */
@@ -283,11 +471,16 @@ struct Authmethod {
 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 *auth_list);
+Authmethod *authmethod_get(char *authlist);
+Authmethod *authmethod_lookup(const char *name);
 
 Authmethod authmethods[] = {
        {"publickey",
@@ -298,6 +491,14 @@ Authmethod authmethods[] = {
                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}
 };
 
@@ -334,17 +535,13 @@ ssh_userauth2(const char *server_user, char *host)
        authctxt.host = host;
        authctxt.service = "ssh-connection";            /* service name */
        authctxt.success = 0;
-       authctxt.method = NULL;
+       authctxt.method = authmethod_lookup("none");
+       if (authctxt.method == NULL)
+               fatal("ssh_userauth2: internal error: cannot send userauth none request");
+       authmethod_clear();
 
        /* initial userauth request */
-       packet_start(SSH2_MSG_USERAUTH_REQUEST);
-       packet_put_cstring(authctxt.server_user);
-       packet_put_cstring(authctxt.service);
-       packet_put_cstring("none");
-       packet_send();
-       packet_write_wait();
-
-       authmethod_clear();
+       userauth_none(&authctxt);
 
        dispatch_init(&input_userauth_error);
        dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
@@ -354,7 +551,7 @@ ssh_userauth2(const char *server_user, char *host)
        if (authctxt.agent != NULL)
                ssh_close_authentication_connection(authctxt.agent);
 
-       debug("ssh-userauth2 successfull");
+       debug("ssh-userauth2 successfull: method %s", authctxt.method->name);
 }
 void
 input_userauth_error(int type, int plen, void *ctxt)
@@ -376,12 +573,11 @@ input_userauth_failure(int type, int plen, void *ctxt)
        Authctxt *authctxt = ctxt;
        char *authlist = NULL;
        int partial;
-       int dlen;
 
        if (authctxt == NULL)
                fatal("input_userauth_failure: no authentication context");
 
-       authlist = packet_get_string(&dlen);
+       authlist = packet_get_string(NULL);
        partial = packet_get_char();
        packet_done();
 
@@ -390,12 +586,12 @@ input_userauth_failure(int type, int plen, void *ctxt)
        debug("authentications that can continue: %s", authlist);
 
        for (;;) {
-               /* try old method or get next method */
                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 packet, wait for reply");
+                       debug2("we sent a %s packet, wait for reply", method->name);
                        break;
                } else {
                        debug2("we did not send a packet, disable method");
@@ -405,6 +601,19 @@ input_userauth_failure(int type, int plen, void *ctxt)
        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
 userauth_passwd(Authctxt *authctxt)
 {
@@ -424,7 +633,7 @@ userauth_passwd(Authctxt *authctxt)
        packet_start(SSH2_MSG_USERAUTH_REQUEST);
        packet_put_cstring(authctxt->server_user);
        packet_put_cstring(authctxt->service);
-       packet_put_cstring("password");
+       packet_put_cstring(authctxt->method->name);
        packet_put_char(0);
        packet_put_cstring(password);
        memset(password, 0, strlen(password));
@@ -442,6 +651,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
        int bloblen, slen;
        int skip = 0;
        int ret = -1;
+       int have_sig = 1;
 
        dsa_make_key_blob(k, &blob, &bloblen);
 
@@ -460,8 +670,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
            datafellows & SSH_BUG_PUBKEYAUTH ?
            "ssh-userauth" :
            authctxt->service);
-       buffer_put_cstring(&b, "publickey");
-       buffer_put_char(&b, 1);
+       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);
 
@@ -481,8 +691,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
                buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
                buffer_put_cstring(&b, authctxt->server_user);
                buffer_put_cstring(&b, authctxt->service);
-               buffer_put_cstring(&b, "publickey");
-               buffer_put_char(&b, 1);
+               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);
        }
@@ -606,6 +816,92 @@ userauth_pubkey(Authctxt *authctxt)
        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();
+
+       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(); /* done with parsing incoming message. */
+
+       packet_send();
+       packet_write_wait();
+}
 
 /* find auth method */
 
@@ -692,6 +988,7 @@ authmethod_get(char *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);
@@ -706,16 +1003,20 @@ authmethod_get(char *authlist)
        }
 
        while (name != NULL) {
+               debug3("authmethod_lookup %s", name);
                method = authmethod_lookup(name);
-               if (method != NULL && authmethod_is_enabled(method))
+               if (method != NULL && authmethod_is_enabled(method)) {
+                       debug3("authmethod_is_enabled %s", name);
                        break;
+               }
                name = strtok_r(NULL, DELIM, &authlist_state);
+               method = NULL;
        }
 
        if (authname_current != NULL)
                xfree(authname_current);
 
-       if (name != NULL) {
+       if (method != NULL) {
                debug("next auth method to try is %s", name);
                authname_current = xstrdup(name);
                return method;
diff --git a/sshd.8 b/sshd.8
index cd2a8e962cb004437571ee16653c4a60729291b5..29ad2144a0a37ef7d20db326fdd97907622338c9 100644 (file)
--- a/sshd.8
+++ b/sshd.8
@@ -186,7 +186,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.
+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
@@ -255,12 +256,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
@@ -424,7 +426,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 .
@@ -488,7 +491,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 +613,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/sshd.c b/sshd.c
index ae22cd9530caa18e02bdb4b203656d410d74b79a..e5c2508a10e47d86ea8c12b56950744892194bbb 100644 (file)
--- a/sshd.c
+++ b/sshd.c
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.128 2000/09/17 15:38:59 markus 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.128 2000/09/17 15:38:59 markus Exp $");
 #include <openssl/rsa.h>
 #include "key.h"
 #include "dsa.h"
+#include "dh.h"
 
 #include "auth.h"
 #include "myproposal.h"
@@ -172,6 +172,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
  */
@@ -333,6 +336,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') {
@@ -1151,7 +1158,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;
@@ -1192,7 +1199,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
@@ -1296,18 +1303,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];
 
@@ -1327,8 +1324,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);
 
@@ -1379,7 +1431,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(
@@ -1429,23 +1482,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);
 }
+
index 43d2e8ea6b49f9b8f2a0305079f9abf45b1d0cd3..3b88062fa3de9fb247271add62cd1e8bc2c4881a 100644 (file)
@@ -37,6 +37,7 @@ PasswordAuthentication yes
 PermitEmptyPasswords no
 # Uncomment to disable s/key passwords 
 #SkeyAuthentication no
+#KbdInteractiveAuthentication yes
 
 # To change Kerberos options
 #KerberosAuthentication no
This page took 0.408599 seconds and 5 git commands to generate.