summaryrefslogtreecommitdiff
path: root/usr.bin/ssh
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2000-04-26 20:56:31 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2000-04-26 20:56:31 +0000
commit37cb67acec9e6e06ee5741a04a6fc32a124506c7 (patch)
treedd607b413c9d9cf79da9058fe97f075d0cc7a20c /usr.bin/ssh
parent80bd16910dd37033c37a20a6606cac3416cb0795 (diff)
add DSA pubkey auth and other SSH2 fixes. use ssh-keygen -[xX]
for trading keys with the real and the original SSH, directly from the people who invented the SSH protocol.
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r--usr.bin/ssh/auth.c298
-rw-r--r--usr.bin/ssh/authfile.c206
-rw-r--r--usr.bin/ssh/authfile.h36
-rw-r--r--usr.bin/ssh/compat.c3
-rw-r--r--usr.bin/ssh/dsa.c78
-rw-r--r--usr.bin/ssh/dsa.h12
-rw-r--r--usr.bin/ssh/hostfile.c23
-rw-r--r--usr.bin/ssh/key.c107
-rw-r--r--usr.bin/ssh/key.h3
-rw-r--r--usr.bin/ssh/lib/Makefile2
-rw-r--r--usr.bin/ssh/radix.c96
-rw-r--r--usr.bin/ssh/readconf.c43
-rw-r--r--usr.bin/ssh/readconf.h6
-rw-r--r--usr.bin/ssh/ssh-add.c37
-rw-r--r--usr.bin/ssh/ssh-keygen.c341
-rw-r--r--usr.bin/ssh/ssh.c67
-rw-r--r--usr.bin/ssh/ssh.h35
-rw-r--r--usr.bin/ssh/sshconnect.c267
-rw-r--r--usr.bin/ssh/sshd.c214
-rw-r--r--usr.bin/ssh/uuencode.c117
-rw-r--r--usr.bin/ssh/uuencode.h6
21 files changed, 1391 insertions, 606 deletions
diff --git a/usr.bin/ssh/auth.c b/usr.bin/ssh/auth.c
index d20a4e3fe3e..7c88017e8d0 100644
--- a/usr.bin/ssh/auth.c
+++ b/usr.bin/ssh/auth.c
@@ -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;
}
diff --git a/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c
index 82a0990917d..b6c4de38b4f 100644
--- a/usr.bin/ssh/authfile.c
+++ b/usr.bin/ssh/authfile.c
@@ -15,14 +15,20 @@
*/
#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
index 00000000000..afec27d5433
--- /dev/null
+++ b/usr.bin/ssh/authfile.h
@@ -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
diff --git a/usr.bin/ssh/compat.c b/usr.bin/ssh/compat.c
index bcd1ff2ae56..d7bb1186695 100644
--- a/usr.bin/ssh/compat.c
+++ b/usr.bin/ssh/compat.c
@@ -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)
diff --git a/usr.bin/ssh/dsa.c b/usr.bin/ssh/dsa.c
index 1594c14f53a..a4f6d3e7857 100644
--- a/usr.bin/ssh/dsa.c
+++ b/usr.bin/ssh/dsa.c
@@ -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;
+}
diff --git a/usr.bin/ssh/dsa.h b/usr.bin/ssh/dsa.h
index 65e651d9b91..3cece7c1f22 100644
--- a/usr.bin/ssh/dsa.h
+++ b/usr.bin/ssh/dsa.h
@@ -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
diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c
index 29efe5656a1..e1c2429bd64 100644
--- a/usr.bin/ssh/hostfile.c
+++ b/usr.bin/ssh/hostfile.c
@@ -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;
}
diff --git a/usr.bin/ssh/key.c b/usr.bin/ssh/key.c
index 872313abc29..583c529010d 100644
--- a/usr.bin/ssh/key.c
+++ b/usr.bin/ssh/key.c
@@ -38,6 +38,10 @@
#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;
}
diff --git a/usr.bin/ssh/key.h b/usr.bin/ssh/key.h
index 70f0c518b8a..d1bcf3b1bed 100644
--- a/usr.bin/ssh/key.h
+++ b/usr.bin/ssh/key.h
@@ -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
diff --git a/usr.bin/ssh/lib/Makefile b/usr.bin/ssh/lib/Makefile
index 4c695afa741..35de105b496 100644
--- a/usr.bin/ssh/lib/Makefile
+++ b/usr.bin/ssh/lib/Makefile
@@ -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
diff --git a/usr.bin/ssh/radix.c b/usr.bin/ssh/radix.c
index 84e390fd1d6..9d1c999a12b 100644
--- a/usr.bin/ssh/radix.c
+++ b/usr.bin/ssh/radix.c
@@ -1,109 +1,15 @@
/*
* 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;
diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c
index f7f00dd9c2b..eac514ea530 100644
--- a/usr.bin/ssh/readconf.c
+++ b/usr.bin/ssh/readconf.c
@@ -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 */
diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h
index 3391e0ebaad..ca685f30957 100644
--- a/usr.bin/ssh/readconf.h
+++ b/usr.bin/ssh/readconf.h
@@ -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;
diff --git a/usr.bin/ssh/ssh-add.c b/usr.bin/ssh/ssh-add.c
index 78e15204304..b7a385c171d 100644
--- a/usr.bin/ssh/ssh-add.c
+++ b/usr.bin/ssh/ssh-add.c
@@ -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);
}
diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c
index a8516c9b1ff..5482839578d 100644
--- a/usr.bin/ssh/ssh-keygen.c
+++ b/usr.bin/ssh/ssh-keygen.c
@@ -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);
}
diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c
index 850e1e528f4..5d6079e9b6e 100644
--- a/usr.bin/ssh/ssh.c
+++ b/usr.bin/ssh/ssh.c
@@ -11,7 +11,11 @@
*/
#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,
diff --git a/usr.bin/ssh/ssh.h b/usr.bin/ssh/ssh.h
index 5e53b34b1e0..425b0b3e55a 100644
--- a/usr.bin/ssh/ssh.h
+++ b/usr.bin/ssh/ssh.h
@@ -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
@@ -101,6 +102,7 @@
* 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
@@ -125,6 +127,7 @@
* 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. -----------------------*/
diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c
index 82c8b5c2179..9c551d46a76 100644
--- a/usr.bin/ssh/sshconnect.c
+++ b/usr.bin/ssh/sshconnect.c
@@ -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);
}
}
diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c
index b13347d83c4..3bd1b3237ae 100644
--- a/usr.bin/ssh/sshd.c
+++ b/usr.bin/ssh/sshd.c
@@ -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
index 00000000000..22cad305884
--- /dev/null
+++ b/usr.bin/ssh/uuencode.c
@@ -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
index 00000000000..d3f4462845b
--- /dev/null
+++ b/usr.bin/ssh/uuencode.h
@@ -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