add DSA pubkey auth and other SSH2 fixes. use ssh-keygen -[xX]
authormarkus <markus@openbsd.org>
Wed, 26 Apr 2000 20:56:29 +0000 (20:56 +0000)
committermarkus <markus@openbsd.org>
Wed, 26 Apr 2000 20:56:29 +0000 (20:56 +0000)
for trading keys with the real and the original SSH, directly from the
people who invented the SSH protocol.

21 files changed:
usr.bin/ssh/auth.c
usr.bin/ssh/authfile.c
usr.bin/ssh/authfile.h [new file with mode: 0644]
usr.bin/ssh/compat.c
usr.bin/ssh/dsa.c
usr.bin/ssh/dsa.h
usr.bin/ssh/hostfile.c
usr.bin/ssh/key.c
usr.bin/ssh/key.h
usr.bin/ssh/lib/Makefile
usr.bin/ssh/radix.c
usr.bin/ssh/readconf.c
usr.bin/ssh/readconf.h
usr.bin/ssh/ssh-add.c
usr.bin/ssh/ssh-keygen.c
usr.bin/ssh/ssh.c
usr.bin/ssh/ssh.h
usr.bin/ssh/sshconnect.c
usr.bin/ssh/sshd.c
usr.bin/ssh/uuencode.c [new file with mode: 0644]
usr.bin/ssh/uuencode.h [new file with mode: 0644]

index d20a4e3..7c88017 100644 (file)
@@ -5,7 +5,11 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth.c,v 1.4 2000/04/14 10:30:29 markus Exp $");
+RCSID("$OpenBSD: auth.c,v 1.5 2000/04/26 20:56:29 markus Exp $");
+
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -19,13 +23,17 @@ RCSID("$OpenBSD: auth.c,v 1.4 2000/04/14 10:30:29 markus Exp $");
 #include "compat.h"
 #include "channels.h"
 #include "match.h"
-
 #include "bufaux.h"
 #include "ssh2.h"
 #include "auth.h"
 #include "session.h"
 #include "dispatch.h"
 
+#include "key.h"
+#include "kex.h"
+#include "dsa.h"
+#include "uidswap.h"
+#include "channels.h"
 
 /* import */
 extern ServerOptions options;
@@ -40,7 +48,7 @@ extern char *forced_command;
  * If the user's shell is not executable, false will be returned.
  * Otherwise true is returned.
  */
-static int
+int
 allowed_user(struct passwd * pw)
 {
        struct stat st;
@@ -110,6 +118,10 @@ allowed_user(struct passwd * pw)
        return 1;
 }
 
+/* import */
+extern ServerOptions options;
+extern char *forced_command;
+
 /*
  * convert ssh auth msg type into description
  */
@@ -559,10 +571,25 @@ do_authentication()
        do_authenticated(pw);
 }
 
+/* import */
+extern ServerOptions options;
+extern unsigned char *session_id2;
+extern int session_id2_len;
+
+/* protocol */
 
-void input_service_request(int type, int plen);
-void input_userauth_request(int type, int plen);
-void ssh2_pty_cleanup(void);
+void   input_service_request(int type, int plen);
+void   input_userauth_request(int type, int plen);
+void   protocol_error(int type, int plen);
+
+/* auth */
+int    ssh2_auth_none(struct passwd *pw);
+int    ssh2_auth_password(struct passwd *pw);
+int    ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
+
+/* helper */
+struct passwd*  auth_set_user(char *u, char *s);
+int    user_dsa_key_allowed(struct passwd *pw, Key *key);
 
 typedef struct Authctxt Authctxt;
 struct Authctxt {
@@ -574,11 +601,14 @@ struct Authctxt {
 static Authctxt        *authctxt = NULL;
 static int userauth_success = 0;
 
+/* set and get current user */
+
 struct passwd*
 auth_get_user(void)
 {
        return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
 }
+
 struct passwd*
 auth_set_user(char *u, char *s)
 {
@@ -615,7 +645,20 @@ auth_set_user(char *u, char *s)
        return auth_get_user();
 }
 
-static void
+/*
+ * loop until userauth_success == TRUE
+ */
+
+void
+do_authentication2()
+{
+       dispatch_init(&protocol_error);
+       dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
+       dispatch_run(DISPATCH_BLOCK, &userauth_success);
+       do_authenticated2();
+}
+
+void
 protocol_error(int type, int plen)
 {
        log("auth: protocol error: type %d plen %d", type, plen);
@@ -624,6 +667,7 @@ protocol_error(int type, int plen)
        packet_send();
        packet_write_wait();
 }
+
 void
 input_service_request(int type, int plen)
 {
@@ -652,18 +696,22 @@ input_service_request(int type, int plen)
        }
        xfree(service);
 }
+
 void
 input_userauth_request(int type, int plen)
 {
        static int try = 0;
-       unsigned int len;
-       int c, authenticated = 0;
-       char *user, *service, *method;
+       unsigned int len, rlen;
+       int authenticated = 0;
+       char *raw, *user, *service, *method;
        struct passwd *pw;
 
        if (++try == AUTH_FAIL_MAX)
                packet_disconnect("too many failed userauth_requests");
 
+       raw = packet_get_raw(&rlen);
+       if (plen != rlen)
+               fatal("plen != rlen");
        user = packet_get_string(&len);
        service = packet_get_string(&len);
        method = packet_get_string(&len);
@@ -672,64 +720,216 @@ input_userauth_request(int type, int plen)
        /* 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 && try == 1) {
-                       packet_done();
-                       authenticated = auth_password(pw, "");
+               if (strcmp(method, "none") == 0) {
+                       authenticated = ssh2_auth_none(pw);
                } else if (strcmp(method, "password") == 0) {
-                       char *password;
-                       c = packet_get_char();
-                       if (c)
-                               debug("password change not supported");
-                       password = packet_get_string(&len);
-                       packet_done();
-                       authenticated = auth_password(pw, password);
-                       memset(password, 0, len);
-                       xfree(password);
+                       authenticated = ssh2_auth_password(pw);
                } else if (strcmp(method, "publickey") == 0) {
-                       /* XXX TODO */
-                       char *pkalg, *pkblob, *sig;
-                       int have_sig = packet_get_char();
-                       pkalg = packet_get_string(&len);
-                       pkblob = packet_get_string(&len);
-                       if (have_sig) {
-                               sig = packet_get_string(&len);
-                               /* test for correct signature */
-                               packet_done();
-                               xfree(sig);
-                       } else {
-                               packet_done();
-                               /* test whether pkalg/pkblob are acceptable */
-                       }
-                       xfree(pkalg);
-                       xfree(pkblob);
+                       authenticated = ssh2_auth_pubkey(pw, raw, rlen);
                }
        }
        /* XXX check if other auth methods are needed */
-       if (authenticated) {
+       if (authenticated == 1) {
+               log("userauth success for %s method %s", user, method);
                /* turn off userauth */
                dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
                packet_start(SSH2_MSG_USERAUTH_SUCCESS);
                packet_send();
                packet_write_wait();
-               log("userauth success for %s", user);
                /* now we can break out */
                userauth_success = 1;
-       } else {
+       } else if (authenticated == 0) {
+               log("userauth failure for %s method %s", user, method);
                packet_start(SSH2_MSG_USERAUTH_FAILURE);
-               packet_put_cstring("password");
-               packet_put_char(0);             /* partial success */
+               packet_put_cstring("publickey,password");       /* XXX dynamic */
+               packet_put_char(0);                             /* XXX partial success, unused */
                packet_send();
                packet_write_wait();
+       } else {
+               log("userauth postponed for %s method %s", user, method);
        }
        xfree(service);
        xfree(user);
        xfree(method);
 }
-void
-do_authentication2()
+
+int
+ssh2_auth_none(struct passwd *pw)
 {
-       dispatch_init(&protocol_error);
-       dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
-       dispatch_run(DISPATCH_BLOCK, &userauth_success);
-       do_authenticated2();
+       packet_done();
+       return auth_password(pw, "");
+}
+int
+ssh2_auth_password(struct passwd *pw)
+{
+       char *password;
+       int authenticated = 0;
+       int change;
+       unsigned int len;
+       change = packet_get_char();
+       if (change)
+               log("password change not supported");
+       password = packet_get_string(&len);
+       packet_done();
+       if (auth_password(pw, password))
+               authenticated = 1;
+       memset(password, 0, len);
+       xfree(password);
+       return authenticated;
+}
+
+int
+ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
+{
+       Buffer b;
+       Key *key;
+       char *pkalg, *pkblob, *sig;
+       unsigned int alen, blen, slen;
+       int have_sig;
+       int authenticated = 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*/
+               return 0;
+       }
+       pkblob = packet_get_string(&blen);
+       key = dsa_key_from_blob(pkblob, blen);
+       
+       if (have_sig && key != NULL) {
+               sig = packet_get_string(&slen);
+               packet_done();
+               buffer_init(&b);
+               buffer_append(&b, session_id2, session_id2_len);
+               buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+               if (slen + 4 > rlen)
+                       fatal("bad rlen/slen");
+               buffer_append(&b, raw, rlen - slen - 4);
+#ifdef DEBUG_DSS
+               buffer_dump(&b);
+#endif
+               /* test for correct signature */
+               if (user_dsa_key_allowed(pw, key) &&
+                   dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+                       authenticated = 1;
+               buffer_clear(&b);
+               xfree(sig);
+       } else if (!have_sig && key != NULL) {
+               packet_done();
+               debug("test key...");
+               /* test whether pkalg/pkblob are acceptable */
+               /* XXX fake reply and always send PK_OK ? */
+               if (user_dsa_key_allowed(pw, key)) {
+                       packet_start(SSH2_MSG_USERAUTH_PK_OK);
+                       packet_put_string(pkalg, alen);
+                       packet_put_string(pkblob, blen);
+                       packet_send();
+                       packet_write_wait();
+                       authenticated = -1;
+               }
+       }
+       xfree(pkalg);
+       xfree(pkblob);
+       return authenticated;
+}
+
+/* return 1 if user allows given key */
+int
+user_dsa_key_allowed(struct passwd *pw, Key *key)
+{
+       char line[8192], file[1024];
+       int found_key = 0;
+       unsigned int bits = -1;
+       FILE *f;
+       unsigned long linenum = 0;
+       struct stat st;
+       Key *found;
+
+       /* Temporarily use the user's uid. */
+       temporarily_use_uid(pw->pw_uid);
+
+       /* The authorized keys. */
+       snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
+           SSH_USER_PERMITTED_KEYS2);
+
+       /* Fail quietly if file does not exist */
+       if (stat(file, &st) < 0) {
+               /* Restore the privileged uid. */
+               restore_uid();
+               return 0;
+       }
+       /* Open the file containing the authorized keys. */
+       f = fopen(file, "r");
+       if (!f) {
+               /* Restore the privileged uid. */
+               restore_uid();
+               packet_send_debug("Could not open %.900s for reading.", file);
+               packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
+               return 0;
+       }
+       if (options.strict_modes) {
+               int fail = 0;
+               char buf[1024];
+               /* Check open file in order to avoid open/stat races */
+               if (fstat(fileno(f), &st) < 0 ||
+                   (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+                   (st.st_mode & 022) != 0) {
+                       snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
+                           "bad ownership or modes for '%s'.", pw->pw_name, file);
+                       fail = 1;
+               } else {
+                       /* Check path to SSH_USER_PERMITTED_KEYS */
+                       int i;
+                       static const char *check[] = {
+                               "", SSH_USER_DIR, NULL
+                       };
+                       for (i = 0; check[i]; i++) {
+                               snprintf(line, sizeof line, "%.500s/%.100s",
+                                   pw->pw_dir, check[i]);
+                               if (stat(line, &st) < 0 ||
+                                   (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+                                   (st.st_mode & 022) != 0) {
+                                       snprintf(buf, sizeof buf,
+                                           "DSA authentication refused for %.100s: "
+                                           "bad ownership or modes for '%s'.",
+                                           pw->pw_name, line);
+                                       fail = 1;
+                                       break;
+                               }
+                       }
+               }
+               if (fail) {
+                       log(buf);
+                       fclose(f);
+                       restore_uid();
+                       return 0;
+               }
+       }
+       found_key = 0;
+       found = key_new(KEY_DSA);
+
+       while (fgets(line, sizeof(line), f)) {
+               char *cp;
+               linenum++;
+               /* Skip leading whitespace, empty and comment lines. */
+               for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (!*cp || *cp == '\n' || *cp == '#')
+                       continue;
+               bits = key_read(found, &cp);
+               if (bits == 0)
+                       continue;
+               if (key_equal(found, key)) {
+                       found_key = 1;
+                       debug("matching key found: file %s, line %ld",
+                           file, linenum);
+                       break;
+               }
+       }
+       restore_uid();
+       fclose(f);
+       key_free(found);
+       return found_key;
 }
index 82a0990..b6c4de3 100644 (file)
  */
 
 #include "includes.h"
-RCSID("$Id: authfile.c,v 1.14 2000/04/14 10:30:30 markus Exp $");
+RCSID("$Id: authfile.c,v 1.15 2000/04/26 20:56:29 markus Exp $");
 
 #include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+
 #include "xmalloc.h"
 #include "buffer.h"
 #include "bufaux.h"
 #include "cipher.h"
 #include "ssh.h"
+#include "key.h"
 
 /* Version identification string for identity files. */
 #define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
@@ -35,8 +41,8 @@ RCSID("$Id: authfile.c,v 1.14 2000/04/14 10:30:30 markus Exp $");
  */
 
 int
-save_private_key(const char *filename, const char *passphrase,
-                RSA *key, const char *comment)
+save_private_key_rsa(const char *filename, const char *passphrase,
+    RSA *key, const char *comment)
 {
        Buffer buffer, encrypted;
        char buf[100], *cp;
@@ -128,6 +134,63 @@ save_private_key(const char *filename, const char *passphrase,
        return 1;
 }
 
+/* save DSA key in OpenSSL PEM format */
+
+int
+save_private_key_dsa(const char *filename, const char *passphrase,
+    DSA *dsa, const char *comment)
+{
+       FILE *fp;
+       int fd;
+       int success = 1;
+       int len = strlen(passphrase);
+
+       if (len > 0 && len <= 4) {
+               error("passphrase too short: %d bytes", len);
+               errno = 0;
+               return 0;
+       }
+       fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+       if (fd < 0) {
+               debug("open %s failed", filename);
+               return 0;
+       }
+       fp = fdopen(fd, "w");
+       if (fp == NULL ) {
+               debug("fdopen %s failed", filename);
+               close(fd);
+               return 0;
+       }
+       if (len > 0) {
+               if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
+                   (char *)passphrase, strlen(passphrase), NULL, NULL))
+                       success = 0;
+       } else {
+               if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
+                   NULL, 0, NULL, NULL))
+                       success = 0;
+       }
+       fclose(fp);
+       return success;
+}
+
+int
+save_private_key(const char *filename, const char *passphrase, Key *key,
+    const char *comment)
+{
+       switch (key->type) {
+       case KEY_RSA:
+               return save_private_key_rsa(filename, passphrase, key->rsa, comment);
+               break;
+       case KEY_DSA:
+               return save_private_key_dsa(filename, passphrase, key->dsa, comment);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
 /*
  * Loads the public part of the key file.  Returns 0 if an error was
  * encountered (the file does not exist or is not readable), and non-zero
@@ -135,8 +198,7 @@ save_private_key(const char *filename, const char *passphrase,
  */
 
 int
-load_public_key(const char *filename, RSA * pub,
-               char **comment_return)
+load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
 {
        int fd, i;
        off_t len;
@@ -154,7 +216,7 @@ load_public_key(const char *filename, RSA * pub,
 
        if (read(fd, cp, (size_t) len) != (size_t) len) {
                debug("Read from key file %.200s failed: %.100s", filename,
-                     strerror(errno));
+                   strerror(errno));
                buffer_free(&buffer);
                close(fd);
                return 0;
@@ -183,9 +245,13 @@ load_public_key(const char *filename, RSA * pub,
 
        /* Read the public key from the buffer. */
        buffer_get_int(&buffer);
-       pub->n = BN_new();
+       /* XXX alloc */
+       if (pub->n == NULL)
+               pub->n = BN_new();
        buffer_get_bignum(&buffer, pub->n);
-       pub->e = BN_new();
+       /* XXX alloc */
+       if (pub->e == NULL)
+               pub->e = BN_new();
        buffer_get_bignum(&buffer, pub->e);
        if (comment_return)
                *comment_return = buffer_get_string(&buffer, NULL);
@@ -196,6 +262,20 @@ load_public_key(const char *filename, RSA * pub,
        return 1;
 }
 
+int
+load_public_key(const char *filename, Key * key, char **comment_return)
+{
+       switch (key->type) {
+       case KEY_RSA:
+               return load_public_key_rsa(filename, key->rsa, comment_return);
+               break;
+       case KEY_DSA:
+       default:
+               break;
+       }
+       return 0;
+}
+
 /*
  * Loads the private key from the file.  Returns 0 if an error is encountered
  * (file does not exist or is not readable, or passphrase is bad). This
@@ -204,35 +284,17 @@ load_public_key(const char *filename, RSA * pub,
  */
 
 int
-load_private_key(const char *filename, const char *passphrase,
-                RSA * prv, char **comment_return)
+load_private_key_rsa(int fd, const char *filename,
+    const char *passphrase, RSA * prv, char **comment_return)
 {
-       int fd, i, check1, check2, cipher_type;
+       int i, check1, check2, cipher_type;
        off_t len;
        Buffer buffer, decrypted;
        char *cp;
        CipherContext cipher;
        BN_CTX *ctx;
        BIGNUM *aux;
-       struct stat st;
-
-       fd = open(filename, O_RDONLY);
-       if (fd < 0)
-               return 0;
 
-       /* check owner and modes */
-       if (fstat(fd, &st) < 0 ||
-           (st.st_uid != 0 && st.st_uid != getuid()) ||
-           (st.st_mode & 077) != 0) {
-               close(fd);
-               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
-               error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
-               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
-               error("Bad ownership or mode(0%3.3o) for '%s'.",
-                     st.st_mode & 0777, filename);
-               error("It is recommended that your private key files are NOT accessible by others.");
-               return 0;
-       }
        len = lseek(fd, (off_t) 0, SEEK_END);
        lseek(fd, (off_t) 0, SEEK_SET);
 
@@ -309,7 +371,9 @@ load_private_key(const char *filename, const char *passphrase,
                buffer_free(&decrypted);
 fail:
                BN_clear_free(prv->n);
+               prv->n = NULL;
                BN_clear_free(prv->e);
+               prv->e = NULL;
                if (comment_return)
                        xfree(*comment_return);
                return 0;
@@ -343,3 +407,87 @@ fail:
 
        return 1;
 }
+
+int
+load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
+{
+       DSA *dsa;
+       BIO *in;
+       FILE *fp;
+
+       in = BIO_new(BIO_s_file());
+       if (in == NULL) {
+               error("BIO_new failed");
+               return 0;
+       }
+       fp = fdopen(fd, "r");
+       if (fp == NULL) {
+               error("fdopen failed");
+               return 0;
+       }
+       BIO_set_fp(in, fp, BIO_NOCLOSE);
+       dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
+       if (dsa == NULL) {
+               debug("PEM_read_bio_DSAPrivateKey failed");
+       } else {
+               /* replace k->dsa with loaded key */
+               DSA_free(k->dsa);
+               k->dsa = dsa;
+       }
+       BIO_free(in);
+       fclose(fp);
+       if (comment_return)
+               *comment_return = xstrdup("dsa w/o comment");
+       debug("read DSA private key done");
+#ifdef DEBUG_DSS
+       DSA_print_fp(stderr, dsa, 8);
+#endif
+       return dsa != NULL ? 1 : 0;
+}
+
+int
+load_private_key(const char *filename, const char *passphrase, Key *key,
+    char **comment_return)
+{
+       int fd;
+       int ret = 0;
+       struct stat st;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0)
+               return 0;
+
+       /* check owner and modes */
+       if (fstat(fd, &st) < 0 ||
+           (st.st_uid != 0 && st.st_uid != getuid()) ||
+           (st.st_mode & 077) != 0) {
+               close(fd);
+               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+               error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
+               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+               error("Bad ownership or mode(0%3.3o) for '%s'.",
+                     st.st_mode & 0777, filename);
+               error("It is recommended that your private key files are NOT accessible by others.");
+               return 0;
+       }
+       switch (key->type) {
+       case KEY_RSA:
+               if (key->rsa->e != NULL) {
+                       BN_clear_free(key->rsa->e);
+                       key->rsa->e = NULL;
+               }
+               if (key->rsa->n != NULL) {
+                       BN_clear_free(key->rsa->n);
+                       key->rsa->n = NULL;
+               }
+               ret = load_private_key_rsa(fd, filename, passphrase,
+                    key->rsa, comment_return);
+               break;
+       case KEY_DSA:
+               ret = load_private_key_dsa(fd, passphrase, key, comment_return);
+       default:
+               break;
+       }
+       close(fd);
+       return ret;
+}
diff --git a/usr.bin/ssh/authfile.h b/usr.bin/ssh/authfile.h
new file mode 100644 (file)
index 0000000..afec27d
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef AUTHFILE_H
+#define AUTHFILE_H
+
+/*
+ * Saves the authentication (private) key in a file, encrypting it with
+ * passphrase.
+ * For RSA keys: The identification of the file (lowest 64 bits of n)
+ * will precede the key to provide identification of the key without
+ * needing a passphrase.
+ */
+int
+save_private_key(const char *filename, const char *passphrase,
+    Key * private_key, const char *comment);
+
+/*
+ * Loads the public part of the key file (public key and comment). Returns 0
+ * if an error occurred; zero if the public key was successfully read.  The
+ * comment of the key is returned in comment_return if it is non-NULL; the
+ * caller must free the value with xfree.
+ */
+int
+load_public_key(const char *filename, Key * pub,
+    char **comment_return);
+
+/*
+ * Loads the private key from the file.  Returns 0 if an error is encountered
+ * (file does not exist or is not readable, or passphrase is bad). This
+ * initializes the private key.  The comment of the key is returned in
+ * comment_return if it is non-NULL; the caller must free the value with
+ * xfree.
+ */
+int
+load_private_key(const char *filename, const char *passphrase,
+    Key * private_key, char **comment_return);
+
+#endif
index bcd1ff2..d7bb118 100644 (file)
@@ -28,7 +28,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: compat.c,v 1.11 2000/04/14 10:30:31 markus Exp $");
+RCSID("$Id: compat.c,v 1.12 2000/04/26 20:56:29 markus Exp $");
 
 #include "ssh.h"
 #include "packet.h"
@@ -44,7 +44,6 @@ enable_compat20(void)
 {
        verbose("Enabling compatibility mode for protocol 2.0");
        compat20 = 1;
-       packet_set_ssh2_format();
 }
 void
 enable_compat13(void)
index 1594c14..a4f6d3e 100644 (file)
@@ -28,7 +28,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: dsa.c,v 1.4 2000/04/14 10:30:31 markus Exp $");
+RCSID("$Id: dsa.c,v 1.5 2000/04/26 20:56:29 markus Exp $");
 
 #include "ssh.h"
 #include "xmalloc.h"
@@ -47,13 +47,14 @@ RCSID("$Id: dsa.c,v 1.4 2000/04/14 10:30:31 markus Exp $");
 #include <openssl/hmac.h>
 #include "kex.h"
 #include "key.h"
+#include "uuencode.h"
 
 #define INTBLOB_LEN    20
 #define SIGBLOB_LEN    (2*INTBLOB_LEN)
 
 Key *
-dsa_serverkey_from_blob(
-    char *serverhostkey, int serverhostkeylen)
+dsa_key_from_blob(
+    char *blob, int blen)
 {
        Buffer b;
        char *ktype;
@@ -61,14 +62,17 @@ dsa_serverkey_from_blob(
        DSA *dsa;
        Key *key;
 
+#ifdef DEBUG_DSS
+       dump_base64(blob, blen);
+#endif
        /* fetch & parse DSA/DSS pubkey */
        key = key_new(KEY_DSA);
        dsa = key->dsa;
        buffer_init(&b);
-       buffer_append(&b, serverhostkey, serverhostkeylen);
+       buffer_append(&b, blob, blen);
        ktype = buffer_get_string(&b, NULL);
        if (strcmp(KEX_DSS, ktype) != 0) {
-               error("dsa_serverkey_from_blob: cannot handle type  %s", ktype);
+               error("dsa_key_from_blob: cannot handle type  %s", ktype);
                key_free(key);
                return NULL;
        }
@@ -78,7 +82,7 @@ dsa_serverkey_from_blob(
        buffer_get_bignum2(&b, dsa->pub_key);
        rlen = buffer_len(&b);
        if(rlen != 0)
-               error("dsa_serverkey_from_blob: remaining bytes in serverhostkey %d", rlen);
+               error("dsa_key_from_blob: remaining bytes in key blob %d", rlen);
        buffer_free(&b);
 
        debug("keytype %s", ktype);
@@ -87,37 +91,8 @@ dsa_serverkey_from_blob(
 #endif
        return key;
 }
-DSA *
-dsa_load_private(char *filename)
-{
-       DSA *dsa;
-       BIO *in;
-
-       in = BIO_new(BIO_s_file());
-       if (in == NULL)
-               fatal("BIO_new failed");
-       if (BIO_read_filename(in, filename) <= 0)
-               fatal("BIO_read failed %s: %s", filename, strerror(errno));
-       fprintf(stderr, "read DSA private key\n");
-       dsa = PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL);
-       if (dsa == NULL)
-               fatal("PEM_read_bio_DSAPrivateKey failed %s", filename);
-       BIO_free(in);
-       return dsa;
-}
-Key *
-dsa_get_serverkey(char *filename)
-{
-       Key *k = key_new(KEY_EMPTY);
-       k->type = KEY_DSA;
-       k->dsa = dsa_load_private(filename);
-#ifdef DEBUG_DSS
-       DSA_print_fp(stderr, dsa, 8);
-#endif
-       return k;
-}
 int
-dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
+dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
 {
        Buffer b;
        int len;
@@ -146,7 +121,7 @@ int
 dsa_sign(
     Key *key,
     unsigned char **sigp, int *lenp,
-    unsigned char *hash, int hlen)
+    unsigned char *data, int datalen)
 {
        unsigned char *digest;
        unsigned char *ret;
@@ -165,10 +140,13 @@ dsa_sign(
        }
        digest = xmalloc(evp_md->md_size);
        EVP_DigestInit(&md, evp_md);
-       EVP_DigestUpdate(&md, hash, hlen);
+       EVP_DigestUpdate(&md, data, datalen);
        EVP_DigestFinal(&md, digest, NULL);
 
        sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
+       if (sig == NULL) {
+               fatal("dsa_sign: cannot sign");
+       }
 
        rlen = BN_num_bytes(sig->r);
        slen = BN_num_bytes(sig->s);
@@ -212,7 +190,7 @@ int
 dsa_verify(
     Key *key,
     unsigned char *signature, int signaturelen,
-    unsigned char *hash, int hlen)
+    unsigned char *data, int datalen)
 {
        Buffer b;
        unsigned char *digest;
@@ -269,10 +247,10 @@ dsa_verify(
                xfree(sigblob);
        }
        
-       /* sha1 the signed data (== session_id == hash) */
+       /* sha1 the data */
        digest = xmalloc(evp_md->md_size);
        EVP_DigestInit(&md, evp_md);
-       EVP_DigestUpdate(&md, hash, hlen);
+       EVP_DigestUpdate(&md, data, datalen);
        EVP_DigestFinal(&md, digest, NULL);
 
        ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
@@ -296,3 +274,21 @@ dsa_verify(
        debug("dsa_verify: signature %s", txt);
        return ret;
 }
+
+Key *
+dsa_generate_key(unsigned int bits)
+{
+       DSA *dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
+       Key *k;
+       if (dsa == NULL) {
+               fatal("DSA_generate_parameters failed");
+       }
+       if (!DSA_generate_key(dsa)) {
+               fatal("DSA_generate_keys failed");
+       }
+
+       k = key_new(KEY_EMPTY);
+       k->type = KEY_DSA;
+       k->dsa = dsa;
+       return k;
+}
index 65e651d..3cece7c 100644 (file)
@@ -1,20 +1,22 @@
 #ifndef DSA_H
 #define DSA_H
 
-Key    *dsa_serverkey_from_blob(char *serverhostkey, int serverhostkeylen);
-Key    *dsa_get_serverkey(char *filename);
-int    dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
+Key    *dsa_key_from_blob(char *blob, int blen);
+int    dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
 
 int
 dsa_sign(
     Key *key,
     unsigned char **sigp, int *lenp,
-    unsigned char *hash, int hlen);
+    unsigned char *data, int datalen);
 
 int
 dsa_verify(
     Key *key,
     unsigned char *signature, int signaturelen,
-    unsigned char *hash, int hlen);
+    unsigned char *data, int datalen);
+
+Key *
+dsa_generate_key(unsigned int bits);
 
 #endif
index 29efe56..e1c2429 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: hostfile.c,v 1.16 2000/04/14 10:30:31 markus Exp $");
+RCSID("$OpenBSD: hostfile.c,v 1.17 2000/04/26 20:56:29 markus Exp $");
 
 #include "packet.h"
 #include "match.h"
@@ -39,13 +39,8 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
        for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
                ;
 
-       /* Get number of bits. */
-       if (*cp < '0' || *cp > '9')
-               return 0;       /* Bad bit count... */
-       for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
-               bits = 10 * bits + *cp - '0';
-
-       if (!key_read(ret, bits, &cp))
+       bits = key_read(ret, &cp);
+       if (bits == 0)
                return 0;
 
        /* Skip trailing whitespace. */
@@ -182,24 +177,18 @@ add_host_to_hostfile(const char *filename, const char *host, Key *key)
 {
        FILE *f;
        int success = 0;
-
        if (key == NULL)
-               return 1;
-
-       /* Open the file for appending. */
+               return 1;       /* XXX ? */
        f = fopen(filename, "a");
        if (!f)
                return 0;
-
        fprintf(f, "%s ", host);
        if (key_write(key, f)) {
-               fprintf(f, "\n");
                success = 1;
        } else {
-               error("add_host_to_hostfile: saving key failed");
+               error("add_host_to_hostfile: saving key in %s failed", filename);
        }
-
-       /* Close the file. */
+       fprintf(f, "\n");
        fclose(f);
        return success;
 }
index 872313a..583c529 100644 (file)
 #include <openssl/evp.h>
 #include "xmalloc.h"
 #include "key.h"
+#include "dsa.h"
+#include "uuencode.h"
+
+#define SSH_DSS "ssh-dss"
 
 Key *
 key_new(int type)
@@ -47,6 +51,8 @@ key_new(int type)
        DSA *dsa;
        k = xmalloc(sizeof(*k));
        k->type = type;
+       k->dsa = NULL;
+       k->rsa = NULL;
        switch (k->type) {
        case KEY_RSA:
                rsa = RSA_new();
@@ -63,8 +69,6 @@ key_new(int type)
                k->dsa = dsa;
                break;
        case KEY_EMPTY:
-               k->dsa = NULL;
-               k->rsa = NULL;
                break;
        default:
                fatal("key_new: bad key type %d", k->type);
@@ -111,7 +115,7 @@ key_equal(Key *a, Key *b)
                    BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
                break;
        default:
-               fatal("key_free: bad key type %d", a->type);
+               fatal("key_equal: bad key type %d", a->type);
                break;
        }
        return 0;
@@ -127,46 +131,37 @@ char *
 key_fingerprint(Key *k)
 {
        static char retval[80];
-       unsigned char *buf = NULL;
+       unsigned char *blob = NULL;
        int len = 0;
-       int nlen, elen, plen, qlen, glen, publen;
+       int nlen, elen;
 
        switch (k->type) {
        case KEY_RSA:
                nlen = BN_num_bytes(k->rsa->n);
                elen = BN_num_bytes(k->rsa->e);
                len = nlen + elen;
-               buf = xmalloc(len);
-               BN_bn2bin(k->rsa->n, buf);
-               BN_bn2bin(k->rsa->e, buf + nlen);
+               blob = xmalloc(len);
+               BN_bn2bin(k->rsa->n, blob);
+               BN_bn2bin(k->rsa->e, blob + nlen);
                break;
        case KEY_DSA:
-               plen = BN_num_bytes(k->dsa->p);
-               qlen = BN_num_bytes(k->dsa->q);
-               glen = BN_num_bytes(k->dsa->g);
-               publen = BN_num_bytes(k->dsa->pub_key);
-               len = qlen + qlen + glen + publen;
-               buf = xmalloc(len);
-               BN_bn2bin(k->dsa->p, buf);
-               BN_bn2bin(k->dsa->q, buf + plen);
-               BN_bn2bin(k->dsa->g, buf + plen + qlen);
-               BN_bn2bin(k->dsa->pub_key , buf + plen + qlen + glen);
+               dsa_make_key_blob(k, &blob, &len);
                break;
        default:
                fatal("key_fingerprint: bad key type %d", k->type);
                break;
        }
-       if (buf != NULL) {
+       if (blob != NULL) {
                unsigned char d[16];
                EVP_MD_CTX md;
                EVP_DigestInit(&md, EVP_md5());
-               EVP_DigestUpdate(&md, buf, len);
+               EVP_DigestUpdate(&md, blob, len);
                EVP_DigestFinal(&md, d, NULL);
                snprintf(retval, sizeof(retval), FPRINT,
                    d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
                    d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
-               memset(buf, 0, len);
-               xfree(buf);
+               memset(blob, 0, len);
+               xfree(blob);
        }
        return retval;
 }
@@ -226,13 +221,27 @@ write_bignum(FILE *f, BIGNUM *num)
        free(buf);
        return 1;
 }
-int
-key_read(Key *ret, unsigned int bits, char **cpp)
+unsigned int
+key_read(Key *ret, char **cpp)
 {
+       Key *k;
+       unsigned int bits = 0;
+       char *cp;
+       int len, n;
+       unsigned char *blob;
+
+       cp = *cpp;
+
        switch(ret->type) {
        case KEY_RSA:
+               /* Get number of bits. */
+               if (*cp < '0' || *cp > '9')
+                       return 0;       /* Bad bit count... */
+               for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
+                       bits = 10 * bits + *cp - '0';
                if (bits == 0)
                        return 0;
+               *cpp = cp;
                /* Get public exponent, public modulus. */
                if (!read_bignum(cpp, ret->rsa->e))
                        return 0;
@@ -240,22 +249,32 @@ key_read(Key *ret, unsigned int bits, char **cpp)
                        return 0;
                break;
        case KEY_DSA:
-               if (bits != 0)
-                       return 0;
-               if (!read_bignum(cpp, ret->dsa->p))
+               if (strncmp(cp, SSH_DSS " ", 7) != 0)
                        return 0;
-               if (!read_bignum(cpp, ret->dsa->q))
-                       return 0;
-               if (!read_bignum(cpp, ret->dsa->g))
-                       return 0;
-               if (!read_bignum(cpp, ret->dsa->pub_key))
+               cp += 7;
+               len = 2*strlen(cp);
+               blob = xmalloc(len);
+               n = uudecode(cp, blob, len);
+               k = dsa_key_from_blob(blob, n);
+               if (k == NULL)
+                        return 0;
+               xfree(blob);
+               if (ret->dsa != NULL)
+                       DSA_free(ret->dsa);
+               ret->dsa = k->dsa;
+               k->dsa = NULL;
+               key_free(k);
+               bits = BN_num_bits(ret->dsa->p);
+               cp = strchr(cp, '=');
+               if (cp == NULL)
                        return 0;
+               *cpp = cp + 1;
                break;
        default:
-               fatal("bad key type: %d", ret->type);
+               fatal("key_read: bad key type: %d", ret->type);
                break;
        }
-       return 1;
+       return bits;
 }
 int
 key_write(Key *key, FILE *f)
@@ -274,17 +293,15 @@ key_write(Key *key, FILE *f)
                        error("key_write: failed for RSA key");
                }
        } else if (key->type == KEY_DSA && key->dsa != NULL) {
-               /* bits == 0 means DSA key */
-               bits = 0;
-               fprintf(f, "%u", bits);
-               if (write_bignum(f, key->dsa->p) &&
-                   write_bignum(f, key->dsa->q) &&
-                   write_bignum(f, key->dsa->g) &&
-                   write_bignum(f, key->dsa->pub_key)) {
-                       success = 1;
-               } else {
-                       error("key_write: failed for DSA key");
-               }
+               int len, n;
+               unsigned char *blob, *uu;
+               dsa_make_key_blob(key, &blob, &len);
+               uu = xmalloc(2*len);
+               n = uuencode(blob, len, uu);
+               fprintf(f, "%s %s", SSH_DSS, uu);
+               xfree(blob);
+               xfree(uu);
+               success = 1;
        }
        return success;
 }
index 70f0c51..d1bcf3b 100644 (file)
@@ -18,6 +18,7 @@ void  key_free(Key *k);
 int    key_equal(Key *a, Key *b);
 char   *key_fingerprint(Key *k);
 int    key_write(Key *key, FILE *f);
-int    key_read(Key *key, unsigned int bits, char **cpp);
+unsigned int
+key_read(Key *key, char **cpp);
 
 #endif
index 4c695af..35de105 100644 (file)
@@ -5,7 +5,7 @@ SRCS=   authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
        cipher.c compat.c compress.c crc32.c deattack.c fingerprint.c \
        hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \
        rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
-       key.c dispatch.c dsa.c kex.c hmac.c
+       key.c dispatch.c dsa.c kex.c hmac.c uuencode.c
 
 NOPROFILE= yes
 NOPIC= yes
index 84e390f..9d1c999 100644 (file)
 /*
  *   radix.c
  *
- *   base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
- *   Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
- *   and placed in the public domain.
- *
  *   Dug Song <dugsong@UMICH.EDU>
  */
 
 #include "includes.h"
+#include "uuencode.h"
 
 #ifdef AFS
 #include <krb.h>
 
-char six2pr[64] = {
-       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-       'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-       'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
-       'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
-       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
-};
-
-unsigned char pr2six[256];
-
-int
-uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
-{
-       /* ENC is the basic 1 character encoding function to make a char printing */
-#define ENC(c) six2pr[c]
-
-       register char *outptr = bufcoded;
-       unsigned int i;
-
-       for (i = 0; i < nbytes; i += 3) {
-               *(outptr++) = ENC(*bufin >> 2);                                         /* c1 */
-               *(outptr++) = ENC(((*bufin << 4) & 060)   | ((bufin[1] >> 4) & 017));   /* c2 */
-               *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));    /* c3 */
-               *(outptr++) = ENC(bufin[2] & 077);                                      /* c4 */
-               bufin += 3;
-       }
-       if (i == nbytes + 1) {
-               outptr[-1] = '=';
-       } else if (i == nbytes + 2) {
-               outptr[-1] = '=';
-               outptr[-2] = '=';
-       }
-       *outptr = '\0';
-       return (outptr - bufcoded);
-}
-
-int
-uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
-{
-       /* single character decode */
-#define DEC(c) pr2six[(unsigned char)c]
-#define MAXVAL 63
-
-       static int first = 1;
-       int nbytesdecoded, j;
-       const char *bufin = bufcoded;
-       register unsigned char *bufout = bufplain;
-       register int nprbytes;
-
-       /* If this is the first call, initialize the mapping table. */
-       if (first) {
-               first = 0;
-               for (j = 0; j < 256; j++)
-                       pr2six[j] = MAXVAL + 1;
-               for (j = 0; j < 64; j++)
-                       pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
-       }
-       /* Strip leading whitespace. */
-       while (*bufcoded == ' ' || *bufcoded == '\t')
-               bufcoded++;
-
-       /*
-        * Figure out how many characters are in the input buffer. If this
-        * would decode into more bytes than would fit into the output
-        * buffer, adjust the number of input bytes downwards.
-        */
-       bufin = bufcoded;
-       while (DEC(*(bufin++)) <= MAXVAL);
-       nprbytes = bufin - bufcoded - 1;
-       nbytesdecoded = ((nprbytes + 3) / 4) * 3;
-       if (nbytesdecoded > outbufsize)
-               nprbytes = (outbufsize * 4) / 3;
-
-       bufin = bufcoded;
-
-       while (nprbytes > 0) {
-               *(bufout++) = (unsigned char) (DEC(*bufin)   << 2 | DEC(bufin[1]) >> 4);
-               *(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
-               *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
-               bufin += 4;
-               nprbytes -= 4;
-       }
-       if (nprbytes & 03) {
-               if (DEC(bufin[-2]) > MAXVAL)
-                       nbytesdecoded -= 2;
-               else
-                       nbytesdecoded -= 1;
-       }
-       return (nbytesdecoded);
-}
-
 typedef unsigned char my_u_char;
 typedef unsigned int my_u_int32_t;
 typedef unsigned short my_u_short;
index f7f00dd..eac514e 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: readconf.c,v 1.26 2000/04/14 10:30:32 markus Exp $");
+RCSID("$Id: readconf.c,v 1.27 2000/04/26 20:56:29 markus Exp $");
 
 #include "ssh.h"
 #include "cipher.h"
@@ -104,7 +104,8 @@ typedef enum {
        oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
        oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
        oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
-       oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol
+       oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
+       oGlobalKnownHostsFile2, oUserKnownHostsFile2
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -131,6 +132,7 @@ static struct {
        { "fallbacktorsh", oFallBackToRsh },
        { "usersh", oUseRsh },
        { "identityfile", oIdentityFile },
+       { "identityfile2", oIdentityFile2 },
        { "hostname", oHostName },
        { "proxycommand", oProxyCommand },
        { "port", oPort },
@@ -145,6 +147,8 @@ static struct {
        { "rhostsrsaauthentication", oRhostsRSAAuthentication },
        { "globalknownhostsfile", oGlobalKnownHostsFile },
        { "userknownhostsfile", oUserKnownHostsFile },
+       { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
+       { "userknownhostsfile2", oUserKnownHostsFile2 },
        { "connectionattempts", oConnectionAttempts },
        { "batchmode", oBatchMode },
        { "checkhostip", oCheckHostIP },
@@ -368,14 +372,22 @@ parse_flag:
                goto parse_int;
 
        case oIdentityFile:
+       case oIdentityFile2:
                cp = strtok(NULL, WHITESPACE);
                if (!cp)
                        fatal("%.200s line %d: Missing argument.", filename, linenum);
                if (*activep) {
-                       if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
+                       intptr = (opcode == oIdentityFile) ?
+                           &options->num_identity_files :
+                           &options->num_identity_files2;
+                       if (*intptr >= SSH_MAX_IDENTITY_FILES)
                                fatal("%.200s line %d: Too many identity files specified (max %d).",
                                      filename, linenum, SSH_MAX_IDENTITY_FILES);
-                       options->identity_files[options->num_identity_files++] = xstrdup(cp);
+                       charptr = (opcode == oIdentityFile) ?
+                           &options->identity_files[*intptr] :
+                           &options->identity_files2[*intptr];
+                       *charptr = xstrdup(cp);
+                       *intptr = *intptr + 1;
                }
                break;
 
@@ -397,6 +409,14 @@ parse_string:
                charptr = &options->user_hostfile;
                goto parse_string;
 
+       case oGlobalKnownHostsFile2:
+               charptr = &options->system_hostfile2;
+               goto parse_string;
+
+       case oUserKnownHostsFile2:
+               charptr = &options->user_hostfile2;
+               goto parse_string;
+
        case oHostName:
                charptr = &options->hostname;
                goto parse_string;
@@ -642,12 +662,15 @@ initialize_options(Options * options)
        options->ciphers = NULL;
        options->protocol = SSH_PROTO_UNKNOWN;
        options->num_identity_files = 0;
+       options->num_identity_files2 = 0;
        options->hostname = NULL;
        options->proxy_command = NULL;
        options->user = NULL;
        options->escape_char = -1;
        options->system_hostfile = NULL;
        options->user_hostfile = NULL;
+       options->system_hostfile2 = NULL;
+       options->user_hostfile2 = NULL;
        options->num_local_forwards = 0;
        options->num_remote_forwards = 0;
        options->log_level = (LogLevel) - 1;
@@ -722,12 +745,24 @@ fill_default_options(Options * options)
                sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
                options->num_identity_files = 1;
        }
+#if 0
+       if (options->num_identity_files2 == 0) {
+               options->identity_files2[0] =
+                       xmalloc(2 + strlen(SSH2_CLIENT_IDENTITY) + 1);
+               sprintf(options->identity_files2[0], "~/%.100s", SSH2_CLIENT_IDENTITY);
+               options->num_identity_files2 = 1;
+       }
+#endif
        if (options->escape_char == -1)
                options->escape_char = '~';
        if (options->system_hostfile == NULL)
                options->system_hostfile = SSH_SYSTEM_HOSTFILE;
        if (options->user_hostfile == NULL)
                options->user_hostfile = SSH_USER_HOSTFILE;
+       if (options->system_hostfile2 == NULL)
+               options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
+       if (options->user_hostfile2 == NULL)
+               options->user_hostfile2 = SSH_USER_HOSTFILE2;
        if (options->log_level == (LogLevel) - 1)
                options->log_level = SYSLOG_LEVEL_INFO;
        /* options->proxy_command should not be set by default */
index 3391e0e..ca685f3 100644 (file)
@@ -13,7 +13,7 @@
  *
  */
 
-/* RCSID("$Id: readconf.h,v 1.15 2000/04/14 10:30:32 markus Exp $"); */
+/* RCSID("$Id: readconf.h,v 1.16 2000/04/26 20:56:29 markus Exp $"); */
 
 #ifndef READCONF_H
 #define READCONF_H
@@ -73,9 +73,13 @@ typedef struct {
 
        char   *system_hostfile;/* Path for /etc/ssh_known_hosts. */
        char   *user_hostfile;  /* Path for $HOME/.ssh/known_hosts. */
+       char   *system_hostfile2;
+       char   *user_hostfile2;
 
        int     num_identity_files;     /* Number of files for RSA identities. */
+       int     num_identity_files2;    /* DSA identities. */
        char   *identity_files[SSH_MAX_IDENTITY_FILES];
+       char   *identity_files2[SSH_MAX_IDENTITY_FILES];
 
        /* Local TCP/IP forward requests. */
        int     num_local_forwards;
index 78e1520..b7a385c 100644 (file)
@@ -7,30 +7,35 @@
  */
 
 #include "includes.h"
-RCSID("$Id: ssh-add.c,v 1.15 1999/12/02 20:05:40 markus Exp $");
+RCSID("$Id: ssh-add.c,v 1.16 2000/04/26 20:56:29 markus Exp $");
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
 
 #include "rsa.h"
 #include "ssh.h"
 #include "xmalloc.h"
 #include "authfd.h"
 #include "fingerprint.h"
+#include "key.h"
+#include "authfile.h"
 
 void
 delete_file(AuthenticationConnection *ac, const char *filename)
 {
-       RSA *key;
+       Key *public;
        char *comment;
 
-       key = RSA_new();
-       if (!load_public_key(filename, key, &comment)) {
+       public = key_new(KEY_RSA);
+       if (!load_public_key(filename, public, &comment)) {
                printf("Bad key file %s: %s\n", filename, strerror(errno));
                return;
        }
-       if (ssh_remove_identity(ac, key))
+       if (ssh_remove_identity(ac, public->rsa))
                fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
        else
                fprintf(stderr, "Could not remove identity: %s\n", filename);
-       RSA_free(key);
+       key_free(public);
        xfree(comment);
 }
 
@@ -85,20 +90,19 @@ ssh_askpass(char *askpass, char *msg)
 void
 add_file(AuthenticationConnection *ac, const char *filename)
 {
-       RSA *key;
-       RSA *public_key;
+       Key *public;
+       Key *private;
        char *saved_comment, *comment, *askpass = NULL;
        char buf[1024], msg[1024];
        int success;
        int interactive = isatty(STDIN_FILENO);
 
-       key = RSA_new();
-       public_key = RSA_new();
-       if (!load_public_key(filename, public_key, &saved_comment)) {
+       public = key_new(KEY_RSA);
+       if (!load_public_key(filename, public, &saved_comment)) {
                printf("Bad key file %s: %s\n", filename, strerror(errno));
                return;
        }
-       RSA_free(public_key);
+       key_free(public);
 
        if (!interactive && getenv("DISPLAY")) {
                if (getenv(SSH_ASKPASS_ENV))
@@ -108,7 +112,8 @@ add_file(AuthenticationConnection *ac, const char *filename)
        }
 
        /* At first, try empty passphrase */
-       success = load_private_key(filename, "", key, &comment);
+       private = key_new(KEY_RSA);
+       success = load_private_key(filename, "", private, &comment);
        if (!success) {
                printf("Need passphrase for %.200s\n", filename);
                if (!interactive && askpass == NULL) {
@@ -129,7 +134,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
                                xfree(saved_comment);
                                return;
                        }
-                       success = load_private_key(filename, pass, key, &comment);
+                       success = load_private_key(filename, pass, private, &comment);
                        memset(pass, 0, strlen(pass));
                        xfree(pass);
                        if (success)
@@ -139,11 +144,11 @@ add_file(AuthenticationConnection *ac, const char *filename)
        }
        xfree(saved_comment);
 
-       if (ssh_add_identity(ac, key, comment))
+       if (ssh_add_identity(ac, private->rsa, comment))
                fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
        else
                fprintf(stderr, "Could not add identity: %s\n", filename);
-       RSA_free(key);
+       key_free(private);
        xfree(comment);
 }
 
index a8516c9..5482839 100644 (file)
@@ -7,20 +7,23 @@
  */
 
 #include "includes.h"
-RCSID("$Id: ssh-keygen.c,v 1.18 2000/04/14 10:30:33 markus Exp $");
+RCSID("$Id: ssh-keygen.c,v 1.19 2000/04/26 20:56:29 markus Exp $");
+
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
 
-#include "rsa.h"
 #include "ssh.h"
 #include "xmalloc.h"
 #include "fingerprint.h"
+#include "key.h"
+#include "rsa.h"
+#include "dsa.h"
+#include "authfile.h"
+#include "uuencode.h"
 
-/* Generated private key. */
-RSA *private_key;
-
-/* Generated public key. */
-RSA *public_key;
-
-/* Number of bits in the RSA key.  This value can be changed on the command line. */
+/* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
 int bits = 1024;
 
 /*
@@ -53,9 +56,17 @@ char *identity_new_passphrase = NULL;
 /* This is set to the new comment if given on the command line. */
 char *identity_comment = NULL;
 
+/* Dump public key file in format used by real and the original SSH 2 */
+int convert_to_ssh2 = 0;
+int convert_from_ssh2 = 0;
+int print_public = 0;
+int dsa_mode = 0;
+
 /* argv0 */
 extern char *__progname;
 
+char hostname[MAXHOSTNAMELEN];
+
 void
 ask_filename(struct passwd *pw, const char *prompt)
 {
@@ -73,12 +84,138 @@ ask_filename(struct passwd *pw, const char *prompt)
        have_identity = 1;
 }
 
+int
+try_load_key(char *filename, Key *k)
+{
+       int success = 1;
+       if (!load_private_key(filename, "", k, NULL)) {
+               char *pass = read_passphrase("Enter passphrase: ", 1);
+               if (!load_private_key(filename, pass, k, NULL)) {
+                       success = 0;
+               }
+               memset(pass, 0, strlen(pass));
+               xfree(pass);
+       }
+       return success;
+}
+
+#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
+#define SSH_COM_MAGIC_END   "---- END SSH2 PUBLIC KEY ----"
+
+void
+do_convert_to_ssh2(struct passwd *pw)
+{
+       Key *k;
+       int len;
+       unsigned char *blob;
+       struct stat st;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       k = key_new(KEY_DSA);
+       if (!try_load_key(identity_file, k)) {
+               fprintf(stderr, "load failed\n");
+               exit(1);
+       }
+       dsa_make_key_blob(k, &blob, &len);
+       fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
+       fprintf(stdout,
+           "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
+           BN_num_bits(k->dsa->p),
+           pw->pw_name, hostname);
+       dump_base64(stdout, blob, len);
+       fprintf(stdout, SSH_COM_MAGIC_END "\n");
+       key_free(k);
+       exit(0);
+}
+
+void
+do_convert_from_ssh2(struct passwd *pw)
+{
+       Key *k;
+       int blen;
+       char line[1024], *p;
+       char blob[8096];
+       char encoded[8096];
+       struct stat st;
+       FILE *fp;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       fp = fopen(identity_file, "r");
+       if (fp == NULL) {
+               perror(identity_file);
+               exit(1);
+       }
+       encoded[0] = '\0';
+       while (fgets(line, sizeof(line), fp)) {
+               if (strncmp(line, "----", 4) == 0 ||
+                   strstr(line, ": ") != NULL) {
+                       fprintf(stderr, "ignore: %s", line);
+                       continue;
+               }
+               if (!(p = strchr(line, '\n'))) {
+                       fprintf(stderr, "input line too long.\n");
+                       exit(1);
+               }
+               *p = '\0';
+               strlcat(encoded, line, sizeof(encoded));
+       }
+       blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
+       if (blen < 0) {
+               fprintf(stderr, "uudecode failed.\n");
+               exit(1);
+       }
+       k = dsa_key_from_blob(blob, blen);
+       if (!key_write(k, stdout))
+               fprintf(stderr, "key_write failed");
+       key_free(k);
+       fprintf(stdout, "\n");
+       fclose(fp);
+       exit(0);
+}
+
+void
+do_print_public(struct passwd *pw)
+{
+       Key *k;
+       int len;
+       unsigned char *blob;
+       struct stat st;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       k = key_new(KEY_DSA);
+       if (!try_load_key(identity_file, k)) {
+               fprintf(stderr, "load failed\n");
+               exit(1);
+       }
+       dsa_make_key_blob(k, &blob, &len);
+       if (!key_write(k, stdout))
+               fprintf(stderr, "key_write failed");
+       key_free(k);
+       fprintf(stdout, "\n");
+       exit(0);
+}
+
 void
 do_fingerprint(struct passwd *pw)
 {
        FILE *f;
        BIGNUM *e, *n;
-       RSA *public_key;
+       Key *public;
        char *comment = NULL, *cp, *ep, line[16*1024];
        int i, skip = 0, num = 1, invalid = 1;
        unsigned int ignore;
@@ -90,17 +227,16 @@ do_fingerprint(struct passwd *pw)
                perror(identity_file);
                exit(1);
        }
-       
-       public_key = RSA_new();
-       if (load_public_key(identity_file, public_key, &comment)) {
-               printf("%d %s %s\n", BN_num_bits(public_key->n),
-                   fingerprint(public_key->e, public_key->n),
-                   comment);
-               RSA_free(public_key);
+       public = key_new(KEY_RSA);
+       if (load_public_key(identity_file, public, &comment)) {
+               printf("%d %s %s\n", BN_num_bits(public->rsa->n),
+                   key_fingerprint(public), comment);
+               key_free(public);
                exit(0);
        }
-       RSA_free(public_key);
+       key_free(public);
 
+       /* XXX */
        f = fopen(identity_file, "r");
        if (f != NULL) {
                n = BN_new();
@@ -168,7 +304,9 @@ do_change_passphrase(struct passwd *pw)
        char *comment;
        char *old_passphrase, *passphrase1, *passphrase2;
        struct stat st;
-       RSA *private_key;
+       Key *private;
+       Key *public;
+       int type = dsa_mode ? KEY_DSA : KEY_RSA;
 
        if (!have_identity)
                ask_filename(pw, "Enter file in which the key is");
@@ -176,22 +314,26 @@ do_change_passphrase(struct passwd *pw)
                perror(identity_file);
                exit(1);
        }
-       public_key = RSA_new();
-       if (!load_public_key(identity_file, public_key, NULL)) {
-               printf("%s is not a valid key file.\n", identity_file);
-               exit(1);
+
+       if (type == KEY_RSA) {
+               /* XXX this works currently only for RSA */
+               public = key_new(type);
+               if (!load_public_key(identity_file, public, NULL)) {
+                       printf("%s is not a valid key file.\n", identity_file);
+                       exit(1);
+               }
+               /* Clear the public key since we are just about to load the whole file. */
+               key_free(public);
        }
-       /* Clear the public key since we are just about to load the whole file. */
-       RSA_free(public_key);
 
        /* Try to load the file with empty passphrase. */
-       private_key = RSA_new();
-       if (!load_private_key(identity_file, "", private_key, &comment)) {
+       private = key_new(type);
+       if (!load_private_key(identity_file, "", private, &comment)) {
                if (identity_passphrase)
                        old_passphrase = xstrdup(identity_passphrase);
                else
                        old_passphrase = read_passphrase("Enter old passphrase: ", 1);
-               if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
+               if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
                        memset(old_passphrase, 0, strlen(old_passphrase));
                        xfree(old_passphrase);
                        printf("Bad passphrase.\n");
@@ -226,19 +368,19 @@ do_change_passphrase(struct passwd *pw)
        }
 
        /* Save the file using the new passphrase. */
-       if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
+       if (!save_private_key(identity_file, passphrase1, private, comment)) {
                printf("Saving the key failed: %s: %s.\n",
                       identity_file, strerror(errno));
                memset(passphrase1, 0, strlen(passphrase1));
                xfree(passphrase1);
-               RSA_free(private_key);
+               key_free(private);
                xfree(comment);
                exit(1);
        }
        /* Destroy the passphrase and the copy of the key in memory. */
        memset(passphrase1, 0, strlen(passphrase1));
        xfree(passphrase1);
-       RSA_free(private_key);  /* Destroys contents */
+       key_free(private);               /* Destroys contents */
        xfree(comment);
 
        printf("Your identification has been saved with the new passphrase.\n");
@@ -252,11 +394,11 @@ void
 do_change_comment(struct passwd *pw)
 {
        char new_comment[1024], *comment;
-       RSA *private_key;
+       Key *private;
+       Key *public;
        char *passphrase;
        struct stat st;
        FILE *f;
-       char *tmpbuf;
 
        if (!have_identity)
                ask_filename(pw, "Enter file in which the key is");
@@ -268,14 +410,14 @@ do_change_comment(struct passwd *pw)
         * Try to load the public key from the file the verify that it is
         * readable and of the proper format.
         */
-       public_key = RSA_new();
-       if (!load_public_key(identity_file, public_key, NULL)) {
+       public = key_new(KEY_RSA);
+       if (!load_public_key(identity_file, public, NULL)) {
                printf("%s is not a valid key file.\n", identity_file);
                exit(1);
        }
-       private_key = RSA_new();
 
-       if (load_private_key(identity_file, "", private_key, &comment))
+       private = key_new(KEY_RSA);
+       if (load_private_key(identity_file, "", private, &comment))
                passphrase = xstrdup("");
        else {
                if (identity_passphrase)
@@ -285,7 +427,7 @@ do_change_comment(struct passwd *pw)
                else
                        passphrase = read_passphrase("Enter passphrase: ", 1);
                /* Try to load using the passphrase. */
-               if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
+               if (!load_private_key(identity_file, passphrase, private, &comment)) {
                        memset(passphrase, 0, strlen(passphrase));
                        xfree(passphrase);
                        printf("Bad passphrase.\n");
@@ -301,7 +443,7 @@ do_change_comment(struct passwd *pw)
                fflush(stdout);
                if (!fgets(new_comment, sizeof(new_comment), stdin)) {
                        memset(passphrase, 0, strlen(passphrase));
-                       RSA_free(private_key);
+                       key_free(private);
                        exit(1);
                }
                if (strchr(new_comment, '\n'))
@@ -309,18 +451,18 @@ do_change_comment(struct passwd *pw)
        }
 
        /* Save the file using the new passphrase. */
-       if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
+       if (!save_private_key(identity_file, passphrase, private, new_comment)) {
                printf("Saving the key failed: %s: %s.\n",
                       identity_file, strerror(errno));
                memset(passphrase, 0, strlen(passphrase));
                xfree(passphrase);
-               RSA_free(private_key);
+               key_free(private);
                xfree(comment);
                exit(1);
        }
        memset(passphrase, 0, strlen(passphrase));
        xfree(passphrase);
-       RSA_free(private_key);
+       key_free(private);
 
        strlcat(identity_file, ".pub", sizeof(identity_file));
        f = fopen(identity_file, "w");
@@ -328,13 +470,10 @@ do_change_comment(struct passwd *pw)
                printf("Could not save your public key in %s\n", identity_file);
                exit(1);
        }
-       fprintf(f, "%d ", BN_num_bits(public_key->n));
-       tmpbuf = BN_bn2dec(public_key->e);
-       fprintf(f, "%s ", tmpbuf);
-       free(tmpbuf);
-       tmpbuf = BN_bn2dec(public_key->n);
-       fprintf(f, "%s %s\n", tmpbuf, new_comment);
-       free(tmpbuf);
+       if (!key_write(public, f))
+               fprintf(stderr, "write key failed");
+       key_free(public);
+       fprintf(f, " %s\n", new_comment);
        fclose(f);
 
        xfree(comment);
@@ -347,7 +486,7 @@ void
 usage(void)
 {
        printf("ssh-keygen version %s\n", SSH_VERSION);
-       printf("Usage: %s [-b bits] [-p] [-c] [-l] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
+       printf("Usage: %s [-b bits] [-p] [-c] [-l] [-x] [-X] [-y] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
        exit(1);
 }
 
@@ -359,29 +498,28 @@ main(int ac, char **av)
 {
        char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
        struct passwd *pw;
-       char *tmpbuf;
        int opt;
        struct stat st;
        FILE *f;
-       char hostname[MAXHOSTNAMELEN];
+       Key *private;
+       Key *public;
        extern int optind;
        extern char *optarg;
 
-       /* check if RSA support exists */
-       if (rsa_alive() == 0) {
-               fprintf(stderr,
-                       "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
-                       __progname);
-               exit(1);
-       }
+       OpenSSL_add_all_algorithms();
+
        /* we need this for the home * directory.  */
        pw = getpwuid(getuid());
        if (!pw) {
                printf("You don't exist, go away!\n");
                exit(1);
        }
+       if (gethostname(hostname, sizeof(hostname)) < 0) {
+               perror("gethostname");
+               exit(1);
+       }
 
-       while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
+       while ((opt = getopt(ac, av, "dqpclxXyb:f:P:N:C:")) != EOF) {
                switch (opt) {
                case 'b':
                        bits = atoi(optarg);
@@ -424,6 +562,22 @@ main(int ac, char **av)
                        quiet = 1;
                        break;
 
+               case 'x':
+                       convert_to_ssh2 = 1;
+                       break;
+
+               case 'X':
+                       convert_from_ssh2 = 1;
+                       break;
+
+               case 'y':
+                       print_public = 1;
+                       break;
+
+               case 'd':
+                       dsa_mode = 1;
+                       break;
+
                case '?':
                default:
                        usage();
@@ -437,22 +591,44 @@ main(int ac, char **av)
                printf("Can only have one of -p and -c.\n");
                usage();
        }
+       /* check if RSA support is needed and exists */
+       if (dsa_mode == 0 && rsa_alive() == 0) {
+               fprintf(stderr,
+                       "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
+                       __progname);
+               exit(1);
+       }
        if (print_fingerprint)
                do_fingerprint(pw);
        if (change_passphrase)
                do_change_passphrase(pw);
        if (change_comment)
                do_change_comment(pw);
+       if (convert_to_ssh2)
+               do_convert_to_ssh2(pw);
+       if (convert_from_ssh2)
+               do_convert_from_ssh2(pw);
+       if (print_public)
+               do_print_public(pw);
 
        arc4random_stir();
 
-       if (quiet)
-               rsa_set_verbose(0);
-
-       /* Generate the rsa key pair. */
-       private_key = RSA_new();
-       public_key = RSA_new();
-       rsa_generate_key(private_key, public_key, bits);
+       if (dsa_mode != 0) {
+               if (!quiet)
+                       printf("Generating DSA parameter and key.\n");
+               public = private = dsa_generate_key(bits);
+               if (private == NULL) {
+                       fprintf(stderr, "dsa_generate_keys failed");
+                       exit(1);
+               }
+       } else {
+               if (quiet)
+                       rsa_set_verbose(0);
+               /* Generate the rsa key pair. */
+               public = key_new(KEY_RSA);
+               private = key_new(KEY_RSA);
+               rsa_generate_key(private->rsa, public->rsa, bits);
+       }
 
        if (!have_identity)
                ask_filename(pw, "Enter file in which to save the key");
@@ -505,17 +681,13 @@ passphrase_again:
                strlcpy(comment, identity_comment, sizeof(comment));
        } else {
                /* Create default commend field for the passphrase. */
-               if (gethostname(hostname, sizeof(hostname)) < 0) {
-                       perror("gethostname");
-                       exit(1);
-               }
                snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
        }
 
        /* Save the key with the given passphrase and comment. */
-       if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
+       if (!save_private_key(identity_file, passphrase1, private, comment)) {
                printf("Saving the key failed: %s: %s.\n",
-                      identity_file, strerror(errno));
+                   identity_file, strerror(errno));
                memset(passphrase1, 0, strlen(passphrase1));
                xfree(passphrase1);
                exit(1);
@@ -525,7 +697,9 @@ passphrase_again:
        xfree(passphrase1);
 
        /* Clear the private key and the random number generator. */
-       RSA_free(private_key);
+       if (private != public) {
+               key_free(private);
+       }
        arc4random_stir();
 
        if (!quiet)
@@ -537,21 +711,18 @@ passphrase_again:
                printf("Could not save your public key in %s\n", identity_file);
                exit(1);
        }
-       fprintf(f, "%d ", BN_num_bits(public_key->n));
-       tmpbuf = BN_bn2dec(public_key->e);
-       fprintf(f, "%s ", tmpbuf);
-       free(tmpbuf);
-       tmpbuf = BN_bn2dec(public_key->n);
-       fprintf(f, "%s %s\n", tmpbuf, comment);
-       free(tmpbuf);
+       if (!key_write(public, f))
+               fprintf(stderr, "write key failed");
+       fprintf(f, " %s\n", comment);
        fclose(f);
 
        if (!quiet) {
-               printf("Your public key has been saved in %s.\n", identity_file);
+               printf("Your public key has been saved in %s.\n",
+                   identity_file);
                printf("The key fingerprint is:\n");
-               printf("%d %s %s\n", BN_num_bits(public_key->n),
-                      fingerprint(public_key->e, public_key->n),
-                      comment);
+               printf("%s %s\n", key_fingerprint(public), comment);
        }
+
+       key_free(public);
        exit(0);
 }
index 850e1e5..5d6079e 100644 (file)
  */
 
 #include "includes.h"
-RCSID("$Id: ssh.c,v 1.48 2000/04/14 10:30:33 markus Exp $");
+RCSID("$Id: ssh.c,v 1.49 2000/04/26 20:56:30 markus Exp $");
+
+#include <openssl/evp.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -24,6 +28,10 @@ RCSID("$Id: ssh.c,v 1.48 2000/04/14 10:30:33 markus Exp $");
 #include "ssh2.h"
 #include "compat.h"
 #include "channels.h"
+#include "key.h"
+#include "authfile.h"
+
+extern char *__progname;
 
 /* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
    Default value is AF_UNSPEC means both IPv4 and IPv6. */
@@ -348,10 +356,16 @@ main(int ac, char **av)
                        }
                        break;
                case 'c':
-                       options.cipher = cipher_number(optarg);
-                       if (options.cipher == -1) {
-                               fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
-                               exit(1);
+                       if (ciphers_valid(optarg)) {
+                               /* SSH2 only */
+                               options.ciphers = xstrdup(optarg);
+                       } else {
+                               /* SSH1 only */
+                               options.cipher = cipher_number(optarg);
+                               if (options.cipher == -1) {
+                                       fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
+                                       exit(1);
+                               }
                        }
                        break;
                case 'p':
@@ -407,15 +421,8 @@ main(int ac, char **av)
        if (!host)
                usage();
 
-       /* check if RSA support exists */
-       if (rsa_alive() == 0) {
-               extern char *__progname;
+        OpenSSL_add_all_algorithms();
 
-               fprintf(stderr,
-                       "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
-                       __progname);
-               exit(1);
-       }
        /* Initialize the command to execute on remote host. */
        buffer_init(&command);
 
@@ -488,6 +495,20 @@ main(int ac, char **av)
        /* reinit */
        log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
 
+       /* check if RSA support exists */
+       if ((options.protocol & SSH_PROTO_1) &&
+           rsa_alive() == 0) {
+               log("%s: no RSA support in libssl and libcrypto.  See ssl(8).",
+                   __progname);
+               log("Disabling protocol version 1");
+               options.protocol &= ~ (SSH_PROTO_1|SSH_PROTO_1_PREFERRED);
+       }
+       if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
+               fprintf(stderr, "%s: No protocol version available.\n",
+                   __progname);
+               exit(1);
+       }
+
        if (options.user == NULL)
                options.user = xstrdup(pw->pw_name);
 
@@ -554,9 +575,12 @@ main(int ac, char **av)
         * authentication. This must be done before releasing extra
         * privileges, because the file is only readable by root.
         */
-       if (ok) {
+       if (ok && (options.protocol & SSH_PROTO_1)) {
+               Key k;
                host_private_key = RSA_new();
-               if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
+               k.type = KEY_RSA;
+               k.rsa = host_private_key;
+               if (load_private_key(HOST_KEY_FILE, "", &k, NULL))
                        host_private_key_loaded = 1;
        }
        /*
@@ -602,15 +626,22 @@ main(int ac, char **av)
                exit(1);
        }
        /* Expand ~ in options.identity_files. */
+       /* XXX mem-leaks */
        for (i = 0; i < options.num_identity_files; i++)
                options.identity_files[i] =
                        tilde_expand_filename(options.identity_files[i], original_real_uid);
-
+       for (i = 0; i < options.num_identity_files2; i++)
+               options.identity_files2[i] =
+                       tilde_expand_filename(options.identity_files2[i], original_real_uid);
        /* Expand ~ in known host file names. */
        options.system_hostfile = tilde_expand_filename(options.system_hostfile,
-                                                       original_real_uid);
+           original_real_uid);
        options.user_hostfile = tilde_expand_filename(options.user_hostfile,
-                                                     original_real_uid);
+           original_real_uid);
+       options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2,
+           original_real_uid);
+       options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2,
+           original_real_uid);
 
        /* Log into the remote system.  This never returns if the login fails. */
        ssh_login(host_private_key_loaded, host_private_key,
index 5e53b34..425b0b3 100644 (file)
@@ -13,7 +13,7 @@
  *
  */
 
-/* RCSID("$Id: ssh.h,v 1.39 2000/04/19 07:05:49 deraadt Exp $"); */
+/* RCSID("$Id: ssh.h,v 1.40 2000/04/26 20:56:30 markus Exp $"); */
 
 #ifndef SSH_H
 #define SSH_H
@@ -71,6 +71,7 @@
  * world-readable.
  */
 #define SSH_SYSTEM_HOSTFILE    ETCDIR "/ssh_known_hosts"
+#define SSH_SYSTEM_HOSTFILE2   ETCDIR "/ssh_known_hosts2"
 
 /*
  * Of these, ssh_host_key must be readable only by root, whereas ssh_config
  * contain anything particularly secret.
  */
 #define SSH_USER_HOSTFILE      "~/.ssh/known_hosts"
+#define SSH_USER_HOSTFILE2     "~/.ssh/known_hosts2"
 
 /*
  * Name of the default file containing client-side authentication key. This
  * running as root.)
  */
 #define SSH_USER_PERMITTED_KEYS        ".ssh/authorized_keys"
+#define SSH_USER_PERMITTED_KEYS2       ".ssh/authorized_keys2"
 
 /*
  * Per-user and system-wide ssh "rc" files.  These files are executed with
@@ -378,36 +381,6 @@ int     auth_rsa_challenge_dialog(RSA *pk);
  */
 char   *read_passphrase(const char *prompt, int from_stdin);
 
-/*
- * Saves the authentication (private) key in a file, encrypting it with
- * passphrase.  The identification of the file (lowest 64 bits of n) will
- * precede the key to provide identification of the key without needing a
- * passphrase.
- */
-int
-save_private_key(const char *filename, const char *passphrase,
-    RSA * private_key, const char *comment);
-
-/*
- * Loads the public part of the key file (public key and comment). Returns 0
- * if an error occurred; zero if the public key was successfully read.  The
- * comment of the key is returned in comment_return if it is non-NULL; the
- * caller must free the value with xfree.
- */
-int
-load_public_key(const char *filename, RSA * pub,
-    char **comment_return);
-
-/*
- * Loads the private key from the file.  Returns 0 if an error is encountered
- * (file does not exist or is not readable, or passphrase is bad). This
- * initializes the private key.  The comment of the key is returned in
- * comment_return if it is non-NULL; the caller must free the value with
- * xfree.
- */
-int
-load_private_key(const char *filename, const char *passphrase,
-    RSA * private_key, char **comment_return);
 
 /*------------ Definitions for logging. -----------------------*/
 
index 82c8b5c..9c551d4 100644 (file)
@@ -5,12 +5,10 @@
  * Created: Sat Mar 18 22:15:47 1995 ylo
  * Code to connect to a remote host, and to perform the client side of the
  * login (authentication) dialog.
- *
- * SSH2 support added by Markus Friedl.
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.69 2000/04/19 07:05:50 deraadt Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.70 2000/04/26 20:56:30 markus Exp $");
 
 #include <openssl/bn.h>
 #include "xmalloc.h"
@@ -38,15 +36,17 @@ RCSID("$OpenBSD: sshconnect.c,v 1.69 2000/04/19 07:05:50 deraadt Exp $");
 #include "key.h"
 #include "dsa.h"
 #include "hostfile.h"
+#include "authfile.h"
 
 /* Session id for the current session. */
 unsigned char session_id[16];
+unsigned int supported_authentications = 0;
 
-/* authentications supported by server */
-unsigned int supported_authentications;
+unsigned char *session_id2 = NULL;
+int session_id2_len = 0;
 
-static char *client_version_string = NULL;
-static char *server_version_string = NULL;
+char *client_version_string = NULL;
+char *server_version_string = NULL;
 
 extern Options options;
 extern char *__progname;
@@ -316,6 +316,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
        return 1;
 }
 
+
 /*
  * Checks if the user has an authentication agent, and if so, tries to
  * authenticate using the agent.
@@ -467,16 +468,16 @@ int
 try_rsa_authentication(const char *authfile)
 {
        BIGNUM *challenge;
-       RSA *private_key;
-       RSA *public_key;
+       Key *public;
+       Key *private;
        char *passphrase, *comment;
        int type, i;
        int plen, clen;
 
        /* Try to load identification for the authentication key. */
-       public_key = RSA_new();
-       if (!load_public_key(authfile, public_key, &comment)) {
-               RSA_free(public_key);
+       public = key_new(KEY_RSA);
+       if (!load_public_key(authfile, public, &comment)) {
+               key_free(public);
                /* Could not load it.  Fail. */
                return 0;
        }
@@ -484,12 +485,12 @@ try_rsa_authentication(const char *authfile)
 
        /* Tell the server that we are willing to authenticate using this key. */
        packet_start(SSH_CMSG_AUTH_RSA);
-       packet_put_bignum(public_key->n);
+       packet_put_bignum(public->rsa->n);
        packet_send();
        packet_write_wait();
 
        /* We no longer need the public key. */
-       RSA_free(public_key);
+       key_free(public);
 
        /* Wait for server's response. */
        type = packet_read(&plen);
@@ -515,12 +516,12 @@ try_rsa_authentication(const char *authfile)
 
        debug("Received RSA challenge from server.");
 
-       private_key = RSA_new();
+       private = key_new(KEY_RSA);
        /*
         * Load the private key.  Try first with empty passphrase; if it
         * fails, ask for a passphrase.
         */
-       if (!load_private_key(authfile, "", private_key, NULL)) {
+       if (!load_private_key(authfile, "", private, NULL)) {
                char buf[300];
                snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
                    comment);
@@ -533,7 +534,7 @@ try_rsa_authentication(const char *authfile)
                }
 
                /* Load the authentication file using the pasphrase. */
-               if (!load_private_key(authfile, passphrase, private_key, NULL)) {
+               if (!load_private_key(authfile, passphrase, private, NULL)) {
                        memset(passphrase, 0, strlen(passphrase));
                        xfree(passphrase);
                        error("Bad passphrase.");
@@ -558,10 +559,10 @@ try_rsa_authentication(const char *authfile)
        xfree(comment);
 
        /* Compute and send a response to the challenge. */
-       respond_to_rsa_challenge(challenge, private_key);
+       respond_to_rsa_challenge(challenge, private->rsa);
 
        /* Destroy the private key. */
-       RSA_free(private_key);
+       key_free(private);
 
        /* We no longer need the challenge. */
        BN_clear_free(challenge);
@@ -963,6 +964,7 @@ try_password_authentication(char *prompt)
        return 0;
 }
 
+
 char *
 chop(char *s)
 {
@@ -1060,7 +1062,8 @@ ssh_exchange_identification()
                fatal("Protocol major versions differ: %d vs. %d",
                    (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
                    remote_major);
-
+       if (compat20)
+               packet_set_ssh2_format();
        /* Send our own protocol version identification. */
        snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
            compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
@@ -1122,7 +1125,8 @@ read_yes_or_no(const char *prompt, int defval)
  */
 
 void
-check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
+check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
+       const char *user_hostfile, const char *system_hostfile)
 {
        Key *file_key;
        char *ip = NULL;
@@ -1140,6 +1144,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
         * essentially disables host authentication for localhost; however,
         * this is probably not a real problem.
         */
+       /**  hostaddr == 0! */
        switch (hostaddr->sa_family) {
        case AF_INET:
                local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
@@ -1180,19 +1185,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
         * Check if the host key is present in the user\'s list of known
         * hosts or in the systemwide list.
         */
-       host_status = check_host_in_hostfile(options.user_hostfile, host, host_key, file_key);
+       host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key);
        if (host_status == HOST_NEW)
-               host_status = check_host_in_hostfile(options.system_hostfile, host, host_key, file_key);
+               host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key);
        /*
         * Also perform check for the ip address, skip the check if we are
         * localhost or the hostname was an ip address to begin with
         */
        if (options.check_host_ip && !local && strcmp(host, ip)) {
                Key *ip_key = key_new(host_key->type);
-               ip_status = check_host_in_hostfile(options.user_hostfile, ip, host_key, ip_key);
+               ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key);
 
                if (ip_status == HOST_NEW)
-                       ip_status = check_host_in_hostfile(options.system_hostfile, ip, host_key, ip_key);
+                       ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key);
                if (host_status == HOST_CHANGED &&
                    (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
                        host_ip_differ = 1;
@@ -1209,9 +1214,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
                debug("Host '%.200s' is known and matches the host key.", host);
                if (options.check_host_ip) {
                        if (ip_status == HOST_NEW) {
-                               if (!add_host_to_hostfile(options.user_hostfile, ip, host_key))
+                               if (!add_host_to_hostfile(user_hostfile, ip, host_key))
                                        log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).",
-                                           ip, options.user_hostfile);
+                                           ip, user_hostfile);
                                else
                                        log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.",
                                            ip);
@@ -1245,9 +1250,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
                        hostp = host;
 
                /* If not in strict mode, add the key automatically to the local known_hosts file. */
-               if (!add_host_to_hostfile(options.user_hostfile, hostp, host_key))
+               if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
                        log("Failed to add the host to the list of known hosts (%.500s).",
-                           options.user_hostfile);
+                           user_hostfile);
                else
                        log("Warning: Permanently added '%.200s' to the list of known hosts.",
                            hostp);
@@ -1279,7 +1284,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
                error("It is also possible that the host key has just been changed.");
                error("Please contact your system administrator.");
                error("Add correct host key in %.100s to get rid of this message.",
-                     options.user_hostfile);
+                     user_hostfile);
 
                /*
                 * If strict host key checking is in use, the user will have
@@ -1313,18 +1318,11 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
        if (options.check_host_ip)
                xfree(ip);
 }
-void
-check_rsa_host_key(char *host, struct sockaddr *hostaddr, RSA *host_key)
-{
-       Key k;
-       k.type = KEY_RSA;
-       k.rsa = host_key;
-       check_host_key(host, hostaddr, &k);
-}
 
 /*
  * SSH2 key exchange
  */
+
 void
 ssh_kex2(char *host, struct sockaddr *hostaddr)
 {
@@ -1435,11 +1433,12 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
 
        /* key, cert */
        server_host_key_blob = packet_get_string(&sbloblen);
-       server_host_key = dsa_serverkey_from_blob(server_host_key_blob, 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);
+       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();
@@ -1498,7 +1497,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
                fprintf(stderr, "%02x", (hash[i])&0xff);
        fprintf(stderr, "\n");
 #endif
-       dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20);
+       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);
@@ -1507,6 +1507,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        /* have keys, free DH */
        DH_free(dh);
 
+       /* save session id */
+       session_id2_len = 20;
+       session_id2 = xmalloc(session_id2_len);
+       memcpy(session_id2, hash, session_id2_len);
+
        debug("Wait SSH2_MSG_NEWKEYS.");
        packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
        packet_done();
@@ -1530,19 +1535,103 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
 /*
  * Authenticate user
  */
+int
+ssh2_try_passwd(const char *server_user, const char *host, const char *service)
+{
+       char prompt[80];
+       char *password;
+
+       snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
+           server_user, host);
+       password = read_passphrase(prompt, 0);
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_cstring(server_user);
+       packet_put_cstring(service);
+       packet_put_cstring("password");
+       packet_put_char(0);
+       packet_put_cstring(password);
+       memset(password, 0, strlen(password));
+       xfree(password);
+       packet_send();
+       packet_write_wait();
+       return 1;
+}
+
+int
+ssh2_try_pubkey(char *filename,
+    const char *server_user, const char *host, const char *service)
+{
+       Buffer b;
+       Key *k;
+       unsigned char *blob, *signature;
+       int bloblen, slen;
+
+       debug("try pubkey: %s", filename);
+
+       k = key_new(KEY_DSA);
+       if (!load_private_key(filename, "", k, NULL)) {
+               int success = 0;
+               char *passphrase;
+               char prompt[300];
+                snprintf(prompt, sizeof prompt,
+                    "Enter passphrase for DSA key '%.100s': ",
+                     filename);
+               passphrase = read_passphrase(prompt, 0);
+               success = load_private_key(filename, passphrase, k, NULL);
+               memset(passphrase, 0, strlen(passphrase));
+               xfree(passphrase);
+               if (!success)
+                       return 0;
+       }
+       dsa_make_key_blob(k, &blob, &bloblen);
+
+       /* data to be signed */
+       buffer_init(&b);
+       buffer_append(&b, session_id2, session_id2_len);
+       buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+       buffer_put_cstring(&b, server_user);
+       buffer_put_cstring(&b, service);
+       buffer_put_cstring(&b, "publickey");
+       buffer_put_char(&b, 1);
+       buffer_put_cstring(&b, KEX_DSS); 
+       buffer_put_string(&b, blob, bloblen);
+
+       /* generate signature */
+       dsa_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
+       key_free(k);
+#ifdef DEBUG_DSS
+       buffer_dump(&b);
+#endif
+       /* append signature */
+       buffer_put_string(&b, signature, slen);
+       xfree(signature);
+
+       /* skip session id and packet type */
+       if (buffer_len(&b) < session_id2_len + 1)
+               fatal("ssh2_try_pubkey: internal error");
+       buffer_consume(&b, session_id2_len + 1);
+
+       /* put remaining data from buffer into packet */
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_raw(buffer_ptr(&b), buffer_len(&b));
+       buffer_free(&b);
+
+       /* send */
+       packet_send();
+       packet_write_wait();
+       return 1;
+}
+
 void
-ssh_userauth2(int host_key_valid, RSA *own_host_key,
-    uid_t original_real_uid, char *host)
+ssh_userauth2(const char *server_user, char *host)
 {
        int type;
        int plen;
+       int sent;
        unsigned int dlen;
        int partial;
-       struct passwd *pw;
-       char prompt[80];
-       char *server_user, *local_user;
+       int i = 0;
        char *auths;
-       char *password;
        char *service = "ssh-connection";               /* service name */
 
        debug("send SSH2_MSG_SERVICE_REQUEST");
@@ -1566,14 +1655,6 @@ ssh_userauth2(int host_key_valid, RSA *own_host_key,
        packet_done();
        debug("got SSH2_MSG_SERVICE_ACCEPT");
 
-       /*XX COMMONCODE: */
-       /* Get local user name.  Use it as server user if no user name was given. */
-       pw = getpwuid(original_real_uid);
-       if (!pw)
-               fatal("User id %d not found from user database.", original_real_uid);
-       local_user = xstrdup(pw->pw_name);
-       server_user = options.user ? options.user : local_user;
-
        /* INITIAL request for auth */
        packet_start(SSH2_MSG_USERAUTH_REQUEST);
        packet_put_cstring(server_user);
@@ -1583,6 +1664,7 @@ ssh_userauth2(int host_key_valid, RSA *own_host_key,
        packet_write_wait();
 
        for (;;) {
+               sent = 0;
                type = packet_read(&plen);
                if (type == SSH2_MSG_USERAUTH_SUCCESS)
                        break;
@@ -1595,23 +1677,25 @@ ssh_userauth2(int host_key_valid, RSA *own_host_key,
                packet_done();
                if (partial)
                        debug("partial success");
-               if (strstr(auths, "password") == NULL)
-                       fatal("passwd auth not supported: %s", auths);
+               if (strstr(auths, "publickey") != NULL) {
+                       while (i < options.num_identity_files2) {
+                               sent = ssh2_try_pubkey(
+                                   options.identity_files2[i++],
+                                   server_user, host, service);
+                               if (sent)
+                                       break;
+                       }
+               }
+               if (!sent) {
+                       if (strstr(auths, "password") != NULL) {
+                               sent = ssh2_try_passwd(server_user, host, service);
+                       } else {
+                               fatal("passwd auth not supported: %s", auths);
+                       }
+                       if (!sent)
+                               fatal("no more auths: %s", auths);
+               }
                xfree(auths);
-               /* try passwd */
-               snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
-                   server_user, host);
-               password = read_passphrase(prompt, 0);
-               packet_start(SSH2_MSG_USERAUTH_REQUEST);
-               packet_put_cstring(server_user);
-               packet_put_cstring(service);
-               packet_put_cstring("password");
-               packet_put_char(0);
-               packet_put_cstring(password);
-               memset(password, 0, strlen(password));
-               xfree(password);
-               packet_send();
-               packet_write_wait();
        }
        packet_done();
        debug("ssh-userauth2 successfull");
@@ -1627,6 +1711,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
        BIGNUM *key;
        RSA *host_key;
        RSA *public_key;
+       Key k;
        int bits, rbits;
        int ssh_cipher_default = SSH_CIPHER_3DES;
        unsigned char session_key[SSH_SESSION_KEY_LENGTH];
@@ -1691,8 +1776,10 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
        packet_integrity_check(payload_len,
                               8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
                               SSH_SMSG_PUBLIC_KEY);
-
-       check_rsa_host_key(host, hostaddr, host_key);
+       k.type = KEY_RSA;
+       k.rsa = host_key;
+       check_host_key(host, hostaddr, &k,
+           options.user_hostfile, options.system_hostfile);
 
        client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
 
@@ -1819,20 +1906,17 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
  * Authenticate user
  */
 void
-ssh_userauth(int host_key_valid, RSA *own_host_key,
-    uid_t original_real_uid, char *host)
+ssh_userauth(
+    const char* local_user,
+    const char* server_user,
+    char *host,
+    int host_key_valid, RSA *own_host_key)
 {
        int i, type;
        int payload_len;
-       struct passwd *pw;
-       const char *server_user, *local_user;
 
-       /* Get local user name.  Use it as server user if no user name was given. */
-       pw = getpwuid(original_real_uid);
-       if (!pw)
-               fatal("User id %d not found from user database.", original_real_uid);
-       local_user = xstrdup(pw->pw_name);
-       server_user = options.user ? options.user : local_user;
+       if (supported_authentications == 0)
+               fatal("ssh_userauth: server supports no auth methods");
 
        /* Send the name of the user to log in as on the server. */
        packet_start(SSH_CMSG_USER);
@@ -1951,6 +2035,7 @@ ssh_userauth(int host_key_valid, RSA *own_host_key,
        fatal("Permission denied.");
        /* NOTREACHED */
 }
+
 /*
  * Starts a dialog with the server, and authenticates the current user on the
  * server.  This does not need any extra privileges.  The basic connection
@@ -1962,7 +2047,16 @@ void
 ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
     struct sockaddr *hostaddr, uid_t original_real_uid)
 {
+       struct passwd *pw;
        char *host, *cp;
+       char *server_user, *local_user;
+
+       /* Get local user name.  Use it as server user if no user name was given. */
+       pw = getpwuid(original_real_uid);
+       if (!pw)
+               fatal("User id %d not found from user database.", original_real_uid);
+       local_user = xstrdup(pw->pw_name);
+       server_user = options.user ? options.user : local_user;
 
        /* Convert the user-supplied hostname into all lowercase. */
        host = xstrdup(orighost);
@@ -1980,12 +2074,9 @@ ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
        /* authenticate user */
        if (compat20) {
                ssh_kex2(host, hostaddr);
-               ssh_userauth2(host_key_valid, own_host_key, original_real_uid, host);
+               ssh_userauth2(server_user, host);
        } else {
-               supported_authentications = 0;
                ssh_kex(host, hostaddr);
-               if (supported_authentications == 0)
-                       fatal("supported_authentications == 0.");
-               ssh_userauth(host_key_valid, own_host_key, original_real_uid, host);
+               ssh_userauth(local_user, server_user, host, host_key_valid, own_host_key);
        }
 }
index b13347d..3bd1b32 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.107 2000/04/19 07:05:50 deraadt Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.108 2000/04/26 20:56:30 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -40,6 +40,7 @@ RCSID("$OpenBSD: sshd.c,v 1.107 2000/04/19 07:05:50 deraadt Exp $");
 
 #include "auth.h"
 #include "myproposal.h"
+#include "authfile.h"
 
 #ifdef LIBWRAP
 #include <tcpd.h>
@@ -108,8 +109,9 @@ char *server_version_string = NULL;
  * not very useful.  Currently, memory locking is not implemented.
  */
 struct {
-       RSA *private_key;        /* Private part of server key. */
+       RSA *private_key;        /* Private part of empheral server key. */
        RSA *host_key;           /* Private part of host key. */
+       Key *dsa_host_key;       /* Private DSA host key. */
 } sensitive_data;
 
 /*
@@ -128,6 +130,10 @@ RSA *public_key;
 /* session identifier, used by RSA-auth */
 unsigned char session_id[16];
 
+/* same for ssh2 */
+unsigned char *session_id2 = NULL;
+int session_id2_len = 0;
+
 /* Prototypes for various functions defined later in this file. */
 void do_ssh1_kex();
 void do_ssh2_kex();
@@ -220,6 +226,7 @@ grace_alarm_handler(int sig)
  * Thus there should be no concurrency control/asynchronous execution
  * problems.
  */
+/* XXX do we really want this work to be done in a signal handler ? -m */
 void
 key_regeneration_alarm(int sig)
 {
@@ -340,6 +347,13 @@ sshd_exchange_identification(int sock_in, int sock_out)
        mismatch = 0;
        switch(remote_major) {
        case 1:
+               if (remote_minor == 99) {
+                       if (options.protocol & SSH_PROTO_2)
+                               enable_compat20();
+                       else
+                               mismatch = 1;
+                       break;
+               }
                if (!(options.protocol & SSH_PROTO_1)) {
                        mismatch = 1;
                        break;
@@ -351,12 +365,6 @@ sshd_exchange_identification(int sock_in, int sock_out)
                        /* note that this disables agent-forwarding */
                        enable_compat13();
                }
-               if (remote_minor == 99) {
-                       if (options.protocol & SSH_PROTO_2)
-                               enable_compat20();
-                       else
-                               mismatch = 1;
-               }
                break;
        case 2:
                if (options.protocol & SSH_PROTO_2) {
@@ -382,6 +390,20 @@ sshd_exchange_identification(int sock_in, int sock_out)
                    server_version_string, client_version_string);
                fatal_cleanup();
        }
+       if (compat20)
+               packet_set_ssh2_format();
+}
+
+
+void
+destroy_sensitive_data(void)
+{
+       /* Destroy the private and public keys.  They will no longer be needed. */
+       RSA_free(public_key);
+       RSA_free(sensitive_data.private_key);
+       RSA_free(sensitive_data.host_key);
+       if (sensitive_data.dsa_host_key != NULL)
+               key_free(sensitive_data.dsa_host_key);
 }
 
 /*
@@ -495,25 +517,12 @@ main(int ac, char **av)
            options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
            !inetd_flag);
 
-       /* check if RSA support exists */
-       if (rsa_alive() == 0) {
-               if (silentrsa == 0)
-                       printf("sshd: no RSA support in libssl and libcrypto -- exiting.  See ssl(8)\n");
-               log("no RSA support in libssl and libcrypto -- exiting.  See ssl(8)");
-               exit(1);
-       }
        /* Read server configuration options from the configuration file. */
        read_server_config(&options, config_file_name);
 
        /* Fill in default values for those options not explicitly set. */
        fill_default_server_options(&options);
 
-       /* Check certain values for sanity. */
-       if (options.server_key_bits < 512 ||
-           options.server_key_bits > 32768) {
-               fprintf(stderr, "Bad server key size.\n");
-               exit(1);
-       }
        /* Check that there are no remaining arguments. */
        if (optind < ac) {
                fprintf(stderr, "Extra argument %s.\n", av[optind]);
@@ -522,26 +531,81 @@ main(int ac, char **av)
 
        debug("sshd version %.100s", SSH_VERSION);
 
-       sensitive_data.host_key = RSA_new();
-       errno = 0;
-       /* Load the host key.  It must have empty passphrase. */
-       if (!load_private_key(options.host_key_file, "",
-                             sensitive_data.host_key, &comment)) {
-               error("Could not load host key: %.200s: %.100s",
-                     options.host_key_file, strerror(errno));
+       sensitive_data.dsa_host_key = NULL;
+       sensitive_data.host_key = NULL;
+
+       /* check if RSA support exists */
+       if ((options.protocol & SSH_PROTO_1) &&
+           rsa_alive() == 0) {
+               if (silentrsa == 0)
+                       fprintf(stderr, "sshd: no RSA support in libssl and libcrypto.  See ssl(8)\n");
+               log("no RSA support in libssl and libcrypto.  See ssl(8)");
+               log("Disabling protocol version 1");
+               options.protocol &= ~SSH_PROTO_1;
+       }
+       /* Load the RSA/DSA host key.  It must have empty passphrase. */
+       if (options.protocol & SSH_PROTO_1) {
+               Key k;
+               sensitive_data.host_key = RSA_new();
+               k.type = KEY_RSA;
+               k.rsa = sensitive_data.host_key;
+               errno = 0;
+               if (!load_private_key(options.host_key_file, "", &k, &comment)) {
+                       error("Could not load host key: %.200s: %.100s",
+                           options.host_key_file, strerror(errno));
+                       log("Disabling protocol version 1");
+                       options.protocol &= ~SSH_PROTO_1;
+               }
+               k.rsa = NULL;
+               xfree(comment);
+       }
+       if (options.protocol & SSH_PROTO_2) {
+               sensitive_data.dsa_host_key = key_new(KEY_DSA);
+               if (!load_private_key(options.dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) {
+                       error("Could not load DSA host key: %.200s", options.dsa_key_file);
+                       log("Disabling protocol version 2");
+                       options.protocol &= ~SSH_PROTO_2;
+               }
+       }
+       if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
+               fprintf(stderr, "sshd: no hostkeys available -- exiting.\n");
+               log("sshd: no hostkeys available -- exiting.\n");
                exit(1);
        }
-       xfree(comment);
 
-       /* Initialize the log (it is reinitialized below in case we
-          forked). */
+       /* Check certain values for sanity. */
+       if (options.protocol & SSH_PROTO_1) {
+               if (options.server_key_bits < 512 ||
+                   options.server_key_bits > 32768) {
+                       fprintf(stderr, "Bad server key size.\n");
+                       exit(1);
+               }
+               /*
+                * Check that server and host key lengths differ sufficiently. This
+                * is necessary to make double encryption work with rsaref. Oh, I
+                * hate software patents. I dont know if this can go? Niels
+                */
+               if (options.server_key_bits >
+                   BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
+                   options.server_key_bits <
+                   BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
+                       options.server_key_bits =
+                           BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
+                       debug("Forcing server key to %d bits to make it differ from host key.",
+                           options.server_key_bits);
+               }
+       }
+
+       /* Initialize the log (it is reinitialized below in case we forked). */
        if (debug_flag && !inetd_flag)
                log_stderr = 1;
        log_init(av0, options.log_level, options.log_facility, log_stderr);
 
-       /* If not in debugging mode, and not started from inetd,
-          disconnect from the controlling terminal, and fork.  The
-          original process exits. */
+       /*
+        * If not in debugging mode, and not started from inetd, disconnect
+        * from the controlling terminal, and fork.  The original process
+        * exits.
+        */
        if (!debug_flag && !inetd_flag) {
 #ifdef TIOCNOTTY
                int fd;
@@ -561,18 +625,6 @@ main(int ac, char **av)
        /* Reinitialize the log (because of the fork above). */
        log_init(av0, options.log_level, options.log_facility, log_stderr);
 
-       /* Check that server and host key lengths differ sufficiently.
-          This is necessary to make double encryption work with rsaref.
-          Oh, I hate software patents. I dont know if this can go? Niels */
-       if (options.server_key_bits >
-       BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
-           options.server_key_bits <
-       BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
-               options.server_key_bits =
-                       BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
-               debug("Forcing server key to %d bits to make it differ from host key.",
-                     options.server_key_bits);
-       }
        /* Do not display messages to stdout in RSA code. */
        rsa_set_verbose(0);
 
@@ -590,20 +642,22 @@ main(int ac, char **av)
                s2 = dup(s1);
                sock_in = dup(0);
                sock_out = dup(1);
-               /* We intentionally do not close the descriptors 0, 1, and 2
-                  as our code for setting the descriptors won\'t work
-                  if ttyfd happens to be one of those. */
+               /*
+                * We intentionally do not close the descriptors 0, 1, and 2
+                * as our code for setting the descriptors won\'t work if
+                * ttyfd happens to be one of those.
+                */
                debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
 
-               public_key = RSA_new();
-               sensitive_data.private_key = RSA_new();
-
-               /* XXX check options.protocol */
-               log("Generating %d bit RSA key.", options.server_key_bits);
-               rsa_generate_key(sensitive_data.private_key, public_key,
-                                options.server_key_bits);
-               arc4random_stir();
-               log("RSA key generation complete.");
+               if (options.protocol & SSH_PROTO_1) {
+                       public_key = RSA_new();
+                       sensitive_data.private_key = RSA_new();
+                       log("Generating %d bit RSA key.", options.server_key_bits);
+                       rsa_generate_key(sensitive_data.private_key, public_key,
+                           options.server_key_bits);
+                       arc4random_stir();
+                       log("RSA key generation complete.");
+               }
        } else {
                for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
                        if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
@@ -679,19 +733,20 @@ main(int ac, char **av)
                                fclose(f);
                        }
                }
+               if (options.protocol & SSH_PROTO_1) {
+                       public_key = RSA_new();
+                       sensitive_data.private_key = RSA_new();
 
-               public_key = RSA_new();
-               sensitive_data.private_key = RSA_new();
-
-               log("Generating %d bit RSA key.", options.server_key_bits);
-               rsa_generate_key(sensitive_data.private_key, public_key,
-                                options.server_key_bits);
-               arc4random_stir();
-               log("RSA key generation complete.");
+                       log("Generating %d bit RSA key.", options.server_key_bits);
+                       rsa_generate_key(sensitive_data.private_key, public_key,
+                           options.server_key_bits);
+                       arc4random_stir();
+                       log("RSA key generation complete.");
 
-               /* Schedule server key regeneration alarm. */
-               signal(SIGALRM, key_regeneration_alarm);
-               alarm(options.key_regeneration_time);
+                       /* Schedule server key regeneration alarm. */
+                       signal(SIGALRM, key_regeneration_alarm);
+                       alarm(options.key_regeneration_time);
+               }
 
                /* Arrange to restart on SIGHUP.  The handler needs listen_sock. */
                signal(SIGHUP, sighup_handler);
@@ -1059,9 +1114,7 @@ do_ssh1_kex()
                           sensitive_data.private_key->n);
 
        /* Destroy the private and public keys.  They will no longer be needed. */
-       RSA_free(public_key);
-       RSA_free(sensitive_data.private_key);
-       RSA_free(sensitive_data.host_key);
+       destroy_sensitive_data();
 
        /*
         * Extract session key from the decrypted integer.  The key is in the
@@ -1120,7 +1173,6 @@ do_ssh2_kex()
        unsigned char *kbuf;
        unsigned char *hash;
        Kex *kex;
-       Key *server_host_key;
        char *cprop[PROPOSAL_MAX];
        char *sprop[PROPOSAL_MAX];
 
@@ -1221,8 +1273,7 @@ do_ssh2_kex()
        memset(kbuf, 0, klen);
        xfree(kbuf);
 
-       server_host_key = dsa_get_serverkey(options.dsa_key_file);
-       dsa_make_serverkey_blob(server_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(
@@ -1245,10 +1296,17 @@ do_ssh2_kex()
                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 */
-       dsa_sign(server_host_key, &signature, &slen, hash, 20);
-               /* hashlen depends on KEX */
-       key_free(server_host_key);
+       /* 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_KEXDH_REPLY);
diff --git a/usr.bin/ssh/uuencode.c b/usr.bin/ssh/uuencode.c
new file mode 100644 (file)
index 0000000..22cad30
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ *   base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
+ *   Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
+ *   and placed in the public domain.
+ *
+ *   Dug Song <dugsong@UMICH.EDU>
+ */
+
+#include "includes.h"
+#include "xmalloc.h"
+
+char six2pr[64] = {
+       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+       'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+       'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+       'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+unsigned char pr2six[256];
+
+int
+uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
+{
+       /* ENC is the basic 1 character encoding function to make a char printing */
+#define ENC(c) six2pr[c]
+
+       register char *outptr = bufcoded;
+       unsigned int i;
+
+       for (i = 0; i < nbytes; i += 3) {
+               *(outptr++) = ENC(*bufin >> 2);                                         /* c1 */
+               *(outptr++) = ENC(((*bufin << 4) & 060)   | ((bufin[1] >> 4) & 017));   /* c2 */
+               *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));    /* c3 */
+               *(outptr++) = ENC(bufin[2] & 077);                                      /* c4 */
+               bufin += 3;
+       }
+       if (i == nbytes + 1) {
+               outptr[-1] = '=';
+       } else if (i == nbytes + 2) {
+               outptr[-1] = '=';
+               outptr[-2] = '=';
+       }
+       *outptr = '\0';
+       return (outptr - bufcoded);
+}
+
+int
+uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
+{
+       /* single character decode */
+#define DEC(c) pr2six[(unsigned char)c]
+#define MAXVAL 63
+
+       static int first = 1;
+       int nbytesdecoded, j;
+       const char *bufin = bufcoded;
+       register unsigned char *bufout = bufplain;
+       register int nprbytes;
+
+       /* If this is the first call, initialize the mapping table. */
+       if (first) {
+               first = 0;
+               for (j = 0; j < 256; j++)
+                       pr2six[j] = MAXVAL + 1;
+               for (j = 0; j < 64; j++)
+                       pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
+       }
+       /* Strip leading whitespace. */
+       while (*bufcoded == ' ' || *bufcoded == '\t')
+               bufcoded++;
+
+       /*
+        * Figure out how many characters are in the input buffer. If this
+        * would decode into more bytes than would fit into the output
+        * buffer, adjust the number of input bytes downwards.
+        */
+       bufin = bufcoded;
+       while (DEC(*(bufin++)) <= MAXVAL);
+       nprbytes = bufin - bufcoded - 1;
+       nbytesdecoded = ((nprbytes + 3) / 4) * 3;
+       if (nbytesdecoded > outbufsize)
+               nprbytes = (outbufsize * 4) / 3;
+
+       bufin = bufcoded;
+
+       while (nprbytes > 0) {
+               *(bufout++) = (unsigned char) (DEC(*bufin)   << 2 | DEC(bufin[1]) >> 4);
+               *(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
+               *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
+               bufin += 4;
+               nprbytes -= 4;
+       }
+       if (nprbytes & 03) {
+               if (DEC(bufin[-2]) > MAXVAL)
+                       nbytesdecoded -= 2;
+               else
+                       nbytesdecoded -= 1;
+       }
+       return (nbytesdecoded);
+}
+
+void
+dump_base64(FILE *fp, unsigned char *data, int len)
+{
+       unsigned char *buf = xmalloc(2*len);
+       int i, n;
+       n = uuencode(data, len, buf);
+       for (i = 0; i < n; i++) {
+               fprintf(fp, "%c", buf[i]);
+               if (i % 70 == 69)
+                       fprintf(fp, "\n");
+       }
+       if (i % 70 != 69)
+               fprintf(fp, "\n");
+       xfree(buf);
+}
diff --git a/usr.bin/ssh/uuencode.h b/usr.bin/ssh/uuencode.h
new file mode 100644 (file)
index 0000000..d3f4462
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef UUENCODE_H
+#define UUENCODE_H
+int    uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded);
+int    uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize);
+void   dump_base64(FILE *fp, unsigned char *data, int len);
+#endif