From fa08c86b0da2449181b5e9e64cd62eb0344e88bf Mon Sep 17 00:00:00 2001 From: djm Date: Mon, 13 Nov 2000 11:57:25 +0000 Subject: [PATCH] - (djm) Merge OpenBSD changes: - markus@cvs.openbsd.org 2000/11/06 16:04:56 [channels.c channels.h clientloop.c nchan.c serverloop.c] [session.c ssh.c] agent forwarding and -R for ssh2, based on work from jhuuskon@messi.uku.fi - markus@cvs.openbsd.org 2000/11/06 16:13:27 [ssh.c sshconnect.c sshd.c] do not disabled rhosts(rsa) if server port > 1024; from pekkas@netcore.fi - markus@cvs.openbsd.org 2000/11/06 16:16:35 [sshconnect.c] downgrade client to 1.3 if server is 1.4; help from mdb@juniper.net - markus@cvs.openbsd.org 2000/11/09 18:04:40 [auth1.c] typo; from mouring@pconline.com - markus@cvs.openbsd.org 2000/11/12 12:03:28 [ssh-agent.c] off-by-one when removing a key from the agent - markus@cvs.openbsd.org 2000/11/12 12:50:39 [auth-rh-rsa.c auth2.c authfd.c authfd.h] [authfile.c hostfile.c kex.c kex.h key.c key.h myproposal.h] [readconf.c readconf.h rsa.c rsa.h servconf.c servconf.h ssh-add.c] [ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config] [sshconnect1.c sshconnect2.c sshd.8 sshd.c sshd_config ssh-dss.c] [ssh-dss.h ssh-rsa.c ssh-rsa.h dsa.c dsa.h] add support for RSA to SSH2. please test. there are now 3 types of keys: RSA1 is used by ssh-1 only, RSA and DSA are used by SSH2. you can use 'ssh-keygen -t rsa -f ssh2_rsa_file' to generate RSA keys for SSH2 and use the RSA keys for hostkeys or for user keys. SSH2 RSA or DSA keys are added to .ssh/authorised_keys2 as before. - (djm) Fix up Makefile and Redhat init script to create RSA host keys - (djm) Change to interim version --- ChangeLog | 33 ++++ Makefile.in | 16 +- auth-rh-rsa.c | 6 +- auth1.c | 2 +- auth2.c | 38 ++-- authfd.c | 76 +++++--- authfd.h | 7 +- authfile.c | 136 ++++++++------ channels.c | 159 ++++++++++++---- channels.h | 18 +- clientloop.c | 122 +++++++++--- contrib/redhat/sshd.init | 27 ++- hostfile.c | 12 +- kex.c | 12 +- kex.h | 2 +- key.c | 388 +++++++++++++++++++++++++++++++++++---- key.h | 28 ++- myproposal.h | 2 +- nchan.c | 6 +- readconf.c | 55 +++--- readconf.h | 9 +- rsa.c | 79 +------- rsa.h | 13 +- servconf.c | 57 +++--- servconf.h | 9 +- serverloop.c | 128 +++++++++---- session.c | 17 +- sftp-server.8 | 4 +- ssh-add.1 | 2 +- ssh-add.c | 26 +-- ssh-agent.1 | 4 +- ssh-agent.c | 143 +++++++-------- dsa.c => ssh-dss.c | 118 ++---------- dsa.h => ssh-dss.h | 10 +- ssh-keygen.1 | 24 ++- ssh-keygen.c | 115 ++++++------ ssh-rsa.c | 163 ++++++++++++++++ ssh-rsa.h | 39 ++++ ssh.1 | 53 +++--- ssh.c | 193 ++++++++++--------- ssh_config | 13 +- sshconnect.c | 12 +- sshconnect1.c | 13 +- sshconnect2.c | 77 ++++---- sshd.8 | 30 +-- sshd.c | 316 ++++++++++++++++++------------- sshd_config | 2 + 47 files changed, 1817 insertions(+), 997 deletions(-) rename dsa.c => ssh-dss.c (67%) rename dsa.h => ssh-dss.h (89%) create mode 100644 ssh-rsa.c create mode 100644 ssh-rsa.h diff --git a/ChangeLog b/ChangeLog index ff3924a4..38f81b2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,39 @@ 20001113 - (djm) Add pointer to http://www.imasy.or.jp/~gotoh/connect.c to contrib/README + - (djm) Merge OpenBSD changes: + - markus@cvs.openbsd.org 2000/11/06 16:04:56 + [channels.c channels.h clientloop.c nchan.c serverloop.c] + [session.c ssh.c] + agent forwarding and -R for ssh2, based on work from + jhuuskon@messi.uku.fi + - markus@cvs.openbsd.org 2000/11/06 16:13:27 + [ssh.c sshconnect.c sshd.c] + do not disabled rhosts(rsa) if server port > 1024; from + pekkas@netcore.fi + - markus@cvs.openbsd.org 2000/11/06 16:16:35 + [sshconnect.c] + downgrade client to 1.3 if server is 1.4; help from mdb@juniper.net + - markus@cvs.openbsd.org 2000/11/09 18:04:40 + [auth1.c] + typo; from mouring@pconline.com + - markus@cvs.openbsd.org 2000/11/12 12:03:28 + [ssh-agent.c] + off-by-one when removing a key from the agent + - markus@cvs.openbsd.org 2000/11/12 12:50:39 + [auth-rh-rsa.c auth2.c authfd.c authfd.h] + [authfile.c hostfile.c kex.c kex.h key.c key.h myproposal.h] + [readconf.c readconf.h rsa.c rsa.h servconf.c servconf.h ssh-add.c] + [ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config] + [sshconnect1.c sshconnect2.c sshd.8 sshd.c sshd_config ssh-dss.c] + [ssh-dss.h ssh-rsa.c ssh-rsa.h dsa.c dsa.h] + add support for RSA to SSH2. please test. + there are now 3 types of keys: RSA1 is used by ssh-1 only, + RSA and DSA are used by SSH2. + you can use 'ssh-keygen -t rsa -f ssh2_rsa_file' to generate RSA + keys for SSH2 and use the RSA keys for hostkeys or for user keys. + SSH2 RSA or DSA keys are added to .ssh/authorised_keys2 as before. + - (djm) Fix up Makefile and Redhat init script to create RSA host keys 20001112 - (bal) SCO Patch to add needed libraries for configure.in. Patch by diff --git a/Makefile.in b/Makefile.in index cc49517b..c93e7eab 100644 --- a/Makefile.in +++ b/Makefile.in @@ -35,7 +35,7 @@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) $(EXTRA_TARGETS) -LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o cli.o compat.o compress.o crc32.o cygwin_util.o deattack.o dispatch.o dsa.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o +LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o cli.o compat.o compress.o crc32.o cygwin_util.o deattack.o dispatch.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o LIBOPENBSD_COMPAT_OBJS=bsd-arc4random.o bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-getcwd.o bsd-inet_aton.o bsd-inet_ntoa.o bsd-misc.o bsd-mktemp.o bsd-realpath.o bsd-rresvport.o bsd-setenv.o bsd-sigaction.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bsd-strsep.o bsd-strtok.o bsd-vis.o bsd-setproctitle.o bsd-waitpid.o fake-getaddrinfo.o fake-getnameinfo.o next-posix.o @@ -179,18 +179,24 @@ host-key: ssh-keygen$(EXEEXT) if [ -f "$(DESTDIR)$(sysconfdir)/ssh_host_key" ] ; then \ echo "$(DESTDIR)$(sysconfdir)/ssh_host_key already exists, skipping." ; \ else \ - $(srcdir)/ssh-keygen -b 1024 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N "" ; \ + $(srcdir)/ssh-keygen -t rsa1 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N "" ; \ fi ; \ if [ -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key ] ; then \ echo "$(DESTDIR)$(sysconfdir)/ssh_host_dsa_key already exists, skipping." ; \ else \ - $(srcdir)/ssh-keygen -d -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N "" ; \ + $(srcdir)/ssh-keygen -t dsa -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N "" ; \ + fi ; \ + if [ -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key ] ; then \ + echo "$(DESTDIR)$(sysconfdir)/ssh_host_rsa_key already exists, skipping." ; \ + else \ + $(srcdir)/ssh-keygen -t rsa -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key -N "" ; \ fi ; \ fi ; host-key-force: ssh-keygen$(EXEEXT) - $(srcdir)/ssh-keygen -b 1024 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N "" - $(srcdir)/ssh-keygen -d -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N "" + $(srcdir)/ssh-keygen -t rsa1 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N "" + $(srcdir)/ssh-keygen -t dsa -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N "" + $(srcdir)/ssh-keygen -t rsa -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key -N "" uninstallall: uninstall -rm -f $(DESTDIR)$(sysconfdir)/ssh_config diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c index 3070c9d4..a9f17ef8 100644 --- a/auth-rh-rsa.c +++ b/auth-rh-rsa.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rh-rsa.c,v 1.17 2000/10/03 18:03:03 markus Exp $"); +RCSID("$OpenBSD: auth-rh-rsa.c,v 1.18 2000/11/12 19:50:37 markus Exp $"); #include "packet.h" #include "ssh.h" @@ -53,10 +53,10 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname); /* wrap the RSA key into a 'generic' key */ - client_key = key_new(KEY_RSA); + client_key = key_new(KEY_RSA1); BN_copy(client_key->rsa->e, client_host_key->e); BN_copy(client_key->rsa->n, client_host_key->n); - found = key_new(KEY_RSA); + found = key_new(KEY_RSA1); /* Check if we know the host and its host key. */ host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, diff --git a/auth1.c b/auth1.c index ca0495d3..fec73e3a 100644 --- a/auth1.c +++ b/auth1.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth1.c,v 1.6 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: auth1.c,v 1.7 2000/11/10 01:04:40 markus Exp $"); #ifdef HAVE_OSF_SIA # include diff --git a/auth2.c b/auth2.c index d51a1a76..46bf07c8 100644 --- a/auth2.c +++ b/auth2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); +RCSID("$OpenBSD: auth2.c,v 1.21 2000/11/12 19:50:37 markus Exp $"); #ifdef HAVE_OSF_SIA # include @@ -52,7 +52,6 @@ RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); #include "key.h" #include "kex.h" -#include "dsa.h" #include "uidswap.h" #include "auth-options.h" @@ -89,7 +88,7 @@ void protocol_error(int type, int plen, void *ctxt); /* helper */ Authmethod *authmethod_lookup(const char *name); struct passwd *pwcopy(struct passwd *pw); -int user_dsa_key_allowed(struct passwd *pw, Key *key); +int user_key_allowed(struct passwd *pw, Key *key); char *authmethods_get(void); /* auth */ @@ -104,7 +103,7 @@ Authmethod authmethods[] = { &one}, {"publickey", userauth_pubkey, - &options.dsa_authentication}, + &options.pubkey_authentication}, {"keyboard-interactive", userauth_kbdint, &options.kbd_interactive_authentication}, @@ -422,7 +421,7 @@ userauth_pubkey(Authctxt *authctxt) Key *key; char *pkalg, *pkblob, *sig; unsigned int alen, blen, slen; - int have_sig; + int have_sig, pktype; int authenticated = 0; if (!authctxt->valid) { @@ -431,13 +430,14 @@ userauth_pubkey(Authctxt *authctxt) } have_sig = packet_get_char(); pkalg = packet_get_string(&alen); - if (strcmp(pkalg, KEX_DSS) != 0) { - log("bad pkalg %s", pkalg); /*XXX*/ + pktype = key_type_from_name(pkalg); + if (pktype == KEY_UNSPEC) { + log("bad pkalg %s", pkalg); xfree(pkalg); return 0; } pkblob = packet_get_string(&blen); - key = dsa_key_from_blob(pkblob, blen); + key = key_from_blob(pkblob, blen); if (key != NULL) { if (have_sig) { sig = packet_get_string(&slen); @@ -457,14 +457,14 @@ userauth_pubkey(Authctxt *authctxt) authctxt->service); buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, KEX_DSS); + buffer_put_cstring(&b, key_ssh_name(key)); buffer_put_string(&b, pkblob, blen); -#ifdef DEBUG_DSS +#ifdef DEBUG_PK buffer_dump(&b); #endif /* test for correct signature */ - if (user_dsa_key_allowed(authctxt->pw, key) && - dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) + if (user_key_allowed(authctxt->pw, key) && + key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) authenticated = 1; buffer_clear(&b); xfree(sig); @@ -480,7 +480,7 @@ userauth_pubkey(Authctxt *authctxt) * if a user is not allowed to login. is this an * issue? -markus */ - if (user_dsa_key_allowed(authctxt->pw, key)) { + if (user_key_allowed(authctxt->pw, key)) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); @@ -493,6 +493,7 @@ userauth_pubkey(Authctxt *authctxt) auth_clear_options(); key_free(key); } + debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); xfree(pkalg); xfree(pkblob); #ifdef HAVE_CYGWIN @@ -560,11 +561,10 @@ authmethod_lookup(const char *name) /* return 1 if user allows given key */ int -user_dsa_key_allowed(struct passwd *pw, Key *key) +user_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; @@ -645,10 +645,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) if (!*cp || *cp == '\n' || *cp == '#') continue; - bits = key_read(found, &cp); - if (bits == 0) { + if (key_read(found, &cp) == -1) { /* no key? check if there are options for this key */ int quoted = 0; + debug2("user_key_allowed: check options: '%s'", cp); options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') @@ -659,8 +659,8 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; - bits = key_read(found, &cp); - if (bits == 0) { + if (key_read(found, &cp) == -1) { + debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } diff --git a/authfd.c b/authfd.c index d06cc536..9036a8d8 100644 --- a/authfd.c +++ b/authfd.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $"); +RCSID("$OpenBSD: authfd.c,v 1.30 2000/11/12 19:50:37 markus Exp $"); #include "ssh.h" #include "rsa.h" @@ -50,7 +50,6 @@ RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $"); #include "key.h" #include "authfd.h" #include "kex.h" -#include "dsa.h" #include "compat.h" /* helper */ @@ -211,8 +210,8 @@ ssh_close_authentication_connection(AuthenticationConnection *auth) * Returns the first authentication identity held by the agent. */ -Key * -ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) +int +ssh_get_num_identities(AuthenticationConnection *auth, int version) { int type, code1 = 0, code2 = 0; Buffer request; @@ -227,7 +226,7 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi code2 = SSH2_AGENT_IDENTITIES_ANSWER; break; default: - return NULL; + return 0; } /* @@ -240,14 +239,14 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi buffer_clear(&auth->identities); if (ssh_request_reply(auth, &request, &auth->identities) == 0) { buffer_free(&request); - return NULL; + return 0; } buffer_free(&request); /* Get message type, and verify that we got a proper answer. */ type = buffer_get_char(&auth->identities); if (agent_failed(type)) { - return NULL; + return 0; } else if (type != code2) { fatal("Bad authentication reply message type: %d", type); } @@ -258,8 +257,16 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi fatal("Too many identities in authentication reply: %d\n", auth->howmany); - /* Return the first entry (if any). */ - return ssh_get_next_identity(auth, comment, version); + return auth->howmany; +} + +Key * +ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) +{ + /* get number of identities and return the first entry (if any). */ + if (ssh_get_num_identities(auth, version) > 0) + return ssh_get_next_identity(auth, comment, version); + return NULL; } Key * @@ -280,7 +287,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio */ switch(version){ case 1: - key = key_new(KEY_RSA); + key = key_new(KEY_RSA1); bits = buffer_get_int(&auth->identities); buffer_get_bignum(&auth->identities, key->rsa->e); buffer_get_bignum(&auth->identities, key->rsa->n); @@ -292,7 +299,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio case 2: blob = buffer_get_string(&auth->identities, &blen); *comment = buffer_get_string(&auth->identities, NULL); - key = dsa_key_from_blob(blob, blen); + key = key_from_blob(blob, blen); xfree(blob); break; default: @@ -324,7 +331,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth, int i; int type; - if (key->type != KEY_RSA) + if (key->type != KEY_RSA1) return 0; if (response_type == 0) { log("Compatibility with ssh protocol version 1.0 no longer supported."); @@ -376,7 +383,7 @@ ssh_agent_sign(AuthenticationConnection *auth, int type, flags = 0; int ret = -1; - if (dsa_make_key_blob(key, &blob, &blen) == 0) + if (key_to_blob(key, &blob, &blen) == 0) return -1; if (datafellows & SSH_BUG_SIGBLOB) @@ -409,7 +416,7 @@ ssh_agent_sign(AuthenticationConnection *auth, /* Encode key for a message to the agent. */ void -ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment) +ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) { buffer_clear(b); buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY); @@ -425,17 +432,29 @@ ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment) } void -ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment) +ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) { buffer_clear(b); buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY); - buffer_put_cstring(b, KEX_DSS); - buffer_put_bignum2(b, key->p); - buffer_put_bignum2(b, key->q); - buffer_put_bignum2(b, key->g); - buffer_put_bignum2(b, key->pub_key); - buffer_put_bignum2(b, key->priv_key); - buffer_put_string(b, comment, strlen(comment)); + buffer_put_cstring(b, key_ssh_name(key)); + switch(key->type){ + case KEY_RSA: + buffer_put_bignum2(b, key->rsa->n); + buffer_put_bignum2(b, key->rsa->e); + buffer_put_bignum2(b, key->rsa->d); + buffer_put_bignum2(b, key->rsa->iqmp); + buffer_put_bignum2(b, key->rsa->p); + buffer_put_bignum2(b, key->rsa->q); + break; + case KEY_DSA: + buffer_put_bignum2(b, key->dsa->p); + buffer_put_bignum2(b, key->dsa->q); + buffer_put_bignum2(b, key->dsa->g); + buffer_put_bignum2(b, key->dsa->pub_key); + buffer_put_bignum2(b, key->dsa->priv_key); + break; + } + buffer_put_cstring(b, comment); } /* @@ -452,11 +471,12 @@ ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment) buffer_init(&msg); switch (key->type) { - case KEY_RSA: - ssh_encode_identity_rsa(&msg, key->rsa, comment); + case KEY_RSA1: + ssh_encode_identity_rsa1(&msg, key->rsa, comment); break; + case KEY_RSA: case KEY_DSA: - ssh_encode_identity_dsa(&msg, key->dsa, comment); + ssh_encode_identity_ssh2(&msg, key, comment); break; default: buffer_free(&msg); @@ -487,13 +507,13 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key) buffer_init(&msg); - if (key->type == KEY_RSA) { + if (key->type == KEY_RSA1) { buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); buffer_put_int(&msg, BN_num_bits(key->rsa->n)); buffer_put_bignum(&msg, key->rsa->e); buffer_put_bignum(&msg, key->rsa->n); - } else if (key->type == KEY_DSA) { - dsa_make_key_blob(key, &blob, &blen); + } else if (key->type == KEY_DSA || key->type == KEY_RSA) { + key_to_blob(key, &blob, &blen); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_string(&msg, blob, blen); xfree(blob); diff --git a/authfd.h b/authfd.h index 2d246520..65471ad7 100644 --- a/authfd.h +++ b/authfd.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: authfd.h,v 1.13 2000/10/09 21:51:00 markus Exp $"); */ +/* RCSID("$OpenBSD: authfd.h,v 1.14 2000/11/12 19:50:37 markus Exp $"); */ #ifndef AUTHFD_H #define AUTHFD_H @@ -74,6 +74,11 @@ AuthenticationConnection *ssh_get_authentication_connection(); */ void ssh_close_authentication_connection(AuthenticationConnection *auth); +/* + * Returns the number authentication identity held by the agent. + */ +int ssh_get_num_identities(AuthenticationConnection *auth, int version); + /* * Returns the first authentication identity held by the agent or NULL if * no identies are available. Caller must free comment and key. diff --git a/authfile.c b/authfile.c index d1a97d77..986b10f6 100644 --- a/authfile.c +++ b/authfile.c @@ -36,11 +36,12 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: authfile.c,v 1.21 2000/11/12 19:50:37 markus Exp $"); #include #include #include +#include #include #include @@ -61,7 +62,7 @@ RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $"); */ int -save_private_key_rsa(const char *filename, const char *passphrase, +save_private_key_rsa1(const char *filename, const char *passphrase, RSA *key, const char *comment) { Buffer buffer, encrypted; @@ -155,16 +156,17 @@ save_private_key_rsa(const char *filename, const char *passphrase, return 1; } -/* save DSA key in OpenSSL PEM format */ - +/* save SSH2 key in OpenSSL PEM format */ int -save_private_key_dsa(const char *filename, const char *passphrase, - DSA *dsa, const char *comment) +save_private_key_ssh2(const char *filename, const char *_passphrase, + Key *key, const char *comment) { FILE *fp; int fd; - int success = 1; - int len = strlen(passphrase); + int success = 0; + int len = strlen(_passphrase); + char *passphrase = (len > 0) ? (char *)_passphrase : NULL; + EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; if (len > 0 && len <= 4) { error("passphrase too short: %d bytes", len); @@ -182,14 +184,15 @@ save_private_key_dsa(const char *filename, const char *passphrase, 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; + switch (key->type) { + case KEY_DSA: + success = PEM_write_DSAPrivateKey(fp, key->dsa, + cipher, passphrase, len, NULL, NULL); + break; + case KEY_RSA: + success = PEM_write_RSAPrivateKey(fp, key->rsa, + cipher, passphrase, len, NULL, NULL); + break; } fclose(fp); return success; @@ -200,11 +203,12 @@ 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); + case KEY_RSA1: + return save_private_key_rsa1(filename, passphrase, key->rsa, comment); break; case KEY_DSA: - return save_private_key_dsa(filename, passphrase, key->dsa, comment); + case KEY_RSA: + return save_private_key_ssh2(filename, passphrase, key, comment); break; default: break; @@ -246,7 +250,7 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) /* Check that it is at least big enought to contain the ID string. */ if (len < strlen(AUTHFILE_ID_STRING) + 1) { - debug("Bad key file %.200s.", filename); + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -256,7 +260,7 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) */ for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) { - debug("Bad key file %.200s.", filename); + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -288,10 +292,11 @@ int load_public_key(const char *filename, Key * key, char **comment_return) { switch (key->type) { - case KEY_RSA: + case KEY_RSA1: return load_public_key_rsa(filename, key->rsa, comment_return); break; case KEY_DSA: + case KEY_RSA: default: break; } @@ -306,7 +311,7 @@ load_public_key(const char *filename, Key * key, char **comment_return) */ int -load_private_key_rsa(int fd, const char *filename, +load_private_key_rsa1(int fd, const char *filename, const char *passphrase, RSA * prv, char **comment_return) { int i, check1, check2, cipher_type; @@ -326,7 +331,7 @@ load_private_key_rsa(int fd, const char *filename, 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; @@ -335,7 +340,7 @@ load_private_key_rsa(int fd, const char *filename, /* Check that it is at least big enought to contain the ID string. */ if (len < strlen(AUTHFILE_ID_STRING) + 1) { - debug("Bad key file %.200s.", filename); + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -344,8 +349,8 @@ load_private_key_rsa(int fd, const char *filename, * from the buffer. */ for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) - if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) { - debug("Bad key file %.200s.", filename); + if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) { + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -431,40 +436,59 @@ fail: } int -load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return) +load_private_key_ssh2(int fd, const char *passphrase, Key *k, char **comment_return) { - DSA *dsa; - BIO *in; FILE *fp; + int success = 0; + EVP_PKEY *pk = NULL; + char *name = ""; - 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 { + pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); + if (pk == NULL) { + debug("PEM_read_PrivateKey failed"); + (void)ERR_get_error(); + } else if (pk->type == EVP_PKEY_RSA) { + /* replace k->rsa with loaded key */ + if (k->type == KEY_RSA || k->type == KEY_UNSPEC) { + if (k->rsa != NULL) + RSA_free(k->rsa); + k->rsa = EVP_PKEY_get1_RSA(pk); + k->type = KEY_RSA; + name = "rsa w/o comment"; + success = 1; +#ifdef DEBUG_PK + RSA_print_fp(stderr, k->rsa, 8); +#endif + } + } else if (pk->type == EVP_PKEY_DSA) { /* replace k->dsa with loaded key */ - DSA_free(k->dsa); - k->dsa = dsa; + if (k->type == KEY_DSA || k->type == KEY_UNSPEC) { + if (k->dsa != NULL) + DSA_free(k->dsa); + k->dsa = EVP_PKEY_get1_DSA(pk); + k->type = KEY_DSA; + name = "dsa w/o comment"; +#ifdef DEBUG_PK + DSA_print_fp(stderr, k->dsa, 8); +#endif + success = 1; + } + } else { + error("PEM_read_PrivateKey: mismatch or " + "unknown EVP_PKEY save_type %d", pk->save_type); } - 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; + if (pk != NULL) + EVP_PKEY_free(pk); + if (success && comment_return) + *comment_return = xstrdup(name); + debug("read SSH2 private key done: name %s success %d", name, success); + return success; } int @@ -496,7 +520,7 @@ load_private_key(const char *filename, const char *passphrase, Key *key, return 0; } switch (key->type) { - case KEY_RSA: + case KEY_RSA1: if (key->rsa->e != NULL) { BN_clear_free(key->rsa->e); key->rsa->e = NULL; @@ -505,11 +529,13 @@ load_private_key(const char *filename, const char *passphrase, Key *key, BN_clear_free(key->rsa->n); key->rsa->n = NULL; } - ret = load_private_key_rsa(fd, filename, passphrase, + ret = load_private_key_rsa1(fd, filename, passphrase, key->rsa, comment_return); break; case KEY_DSA: - ret = load_private_key_dsa(fd, passphrase, key, comment_return); + case KEY_RSA: + case KEY_UNSPEC: + ret = load_private_key_ssh2(fd, passphrase, key, comment_return); default: break; } @@ -521,7 +547,6 @@ int do_load_public_key(const char *filename, Key *k, char **commentp) { FILE *f; - unsigned int bits; char line[1024]; char *cp; @@ -540,8 +565,7 @@ do_load_public_key(const char *filename, Key *k, char **commentp) for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) ; if (*cp) { - bits = key_read(k, &cp); - if (bits != 0) { + if (key_read(k, &cp) == 1) { if (commentp) *commentp=xstrdup(filename); fclose(f); diff --git a/channels.c b/channels.c index 028c09e6..0886a91e 100644 --- a/channels.c +++ b/channels.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.72 2000/10/27 07:48:22 markus Exp $"); +RCSID("$OpenBSD: channels.c,v 1.73 2000/11/06 23:04:55 markus Exp $"); #include "ssh.h" #include "packet.h" @@ -588,9 +588,12 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) struct sockaddr addr; int newsock, newch; socklen_t addrlen; - char buf[1024], *remote_hostname; + char buf[1024], *remote_hostname, *rtype; int remote_port; + rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ? + "forwarded-tcpip" : "direct-tcpip"; + if (FD_ISSET(c->sock, readset)) { debug("Connection to port %d forwarding " "to %.100s port %d requested.", @@ -608,19 +611,26 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) "connect from %.200s port %d", c->listening_port, c->path, c->host_port, remote_hostname, remote_port); - newch = channel_new("direct-tcpip", + + newch = channel_new(rtype, SSH_CHANNEL_OPENING, newsock, newsock, -1, c->local_window_max, c->local_maxpacket, 0, xstrdup(buf), 1); if (compat20) { packet_start(SSH2_MSG_CHANNEL_OPEN); - packet_put_cstring("direct-tcpip"); + packet_put_cstring(rtype); packet_put_int(newch); packet_put_int(c->local_window_max); packet_put_int(c->local_maxpacket); - /* target host and port */ - packet_put_string(c->path, strlen(c->path)); - packet_put_int(c->host_port); + if (c->type == SSH_CHANNEL_RPORT_LISTENER) { + /* listen address, port */ + packet_put_string(c->path, strlen(c->path)); + packet_put_int(c->listening_port); + } else { + /* target host, port */ + packet_put_string(c->path, strlen(c->path)); + packet_put_int(c->host_port); + } /* originator host and port */ packet_put_cstring(remote_hostname); packet_put_int(remote_port); @@ -657,10 +667,20 @@ channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) error("accept from auth socket: %.100s", strerror(errno)); return; } - newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, - xstrdup("accepted auth socket")); - packet_start(SSH_SMSG_AGENT_OPEN); - packet_put_int(newch); + newch = channel_new("accepted auth socket", + SSH_CHANNEL_OPENING, newsock, newsock, -1, + c->local_window_max, c->local_maxpacket, + 0, xstrdup("accepted auth socket"), 1); + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring("auth-agent@openssh.com"); + packet_put_int(newch); + packet_put_int(c->local_window_max); + packet_put_int(c->local_maxpacket); + } else { + packet_start(SSH_SMSG_AGENT_OPEN); + packet_put_int(newch); + } packet_send(); } } @@ -820,11 +840,15 @@ channel_handler_init_20(void) channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2; channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; + channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; + channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; } void @@ -1326,6 +1350,7 @@ channel_stop_listening() channel_free(i); break; case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_X11_LISTENER: close(channels[i].sock); channel_free(i); @@ -1369,6 +1394,7 @@ channel_still_open() case SSH_CHANNEL_FREE: case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: continue; @@ -1414,6 +1440,7 @@ channel_open_message() case SSH_CHANNEL_FREE: case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: continue; @@ -1446,19 +1473,44 @@ channel_open_message() * Initiate forwarding of connections to local port "port" through the secure * channel to host:port from remote side. */ +void +channel_request_local_forwarding(u_short listen_port, const char *host_to_connect, + u_short port_to_connect, int gateway_ports) +{ + channel_request_forwarding( + NULL, listen_port, + host_to_connect, port_to_connect, + gateway_ports, /*remote_fwd*/ 0); +} +/* + * If 'remote_fwd' is true we have a '-R style' listener for protocol 2 + * (SSH_CHANNEL_RPORT_LISTENER). + */ void -channel_request_local_forwarding(u_short port, const char *host, - u_short host_port, int gateway_ports) +channel_request_forwarding( + const char *listen_address, u_short listen_port, + const char *host_to_connect, u_short port_to_connect, + int gateway_ports, int remote_fwd) { - int success, ch, sock, on = 1; + int success, ch, sock, on = 1, ctype; struct addrinfo hints, *ai, *aitop; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + const char *host; struct linger linger; + if (remote_fwd) { + host = listen_address; + ctype = SSH_CHANNEL_RPORT_LISTENER; + } else { + host = host_to_connect; + ctype =SSH_CHANNEL_PORT_LISTENER; + } + if (strlen(host) > sizeof(channels[0].path) - 1) packet_disconnect("Forward host name too long."); + /* XXX listen_address is currently ignored */ /* * getaddrinfo returns a loopback address if the hostname is * set to NULL and hints.ai_flags is not AI_PASSIVE @@ -1467,7 +1519,7 @@ channel_request_local_forwarding(u_short port, const char *host, hints.ai_family = IPv4or6; hints.ai_flags = gateway_ports ? AI_PASSIVE : 0; hints.ai_socktype = SOCK_STREAM; - snprintf(strport, sizeof strport, "%d", port); + snprintf(strport, sizeof strport, "%d", listen_port); if (getaddrinfo(NULL, strport, &hints, &aitop) != 0) packet_disconnect("getaddrinfo: fatal error"); @@ -1477,7 +1529,7 @@ channel_request_local_forwarding(u_short port, const char *host, continue; if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { - error("channel_request_local_forwarding: getnameinfo failed"); + error("channel_request_forwarding: getnameinfo failed"); continue; } /* Create a port to listen for the host. */ @@ -1515,18 +1567,16 @@ channel_request_local_forwarding(u_short port, const char *host, continue; } /* Allocate a channel number for the socket. */ - ch = channel_new( - "port listener", SSH_CHANNEL_PORT_LISTENER, - sock, sock, -1, + ch = channel_new("port listener", ctype, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("port listener"), 1); strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); - channels[ch].host_port = host_port; - channels[ch].listening_port = port; + channels[ch].host_port = port_to_connect; + channels[ch].listening_port = listen_port; success = 1; } if (success == 0) - packet_disconnect("cannot listen port: %d", port); + packet_disconnect("cannot listen port: %d", listen_port); /*XXX ?disconnect? */ freeaddrinfo(aitop); } @@ -1536,19 +1586,15 @@ channel_request_local_forwarding(u_short port, const char *host, */ void -channel_request_remote_forwarding(u_short listen_port, const char *host_to_connect, - u_short port_to_connect) +channel_request_remote_forwarding(u_short listen_port, + const char *host_to_connect, u_short port_to_connect) { - int payload_len; + int payload_len, type, success = 0; + /* Record locally that connection to this host/port is permitted. */ if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) fatal("channel_request_remote_forwarding: too many forwards"); - permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); - permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; - permitted_opens[num_permitted_opens].listen_port = listen_port; - num_permitted_opens++; - /* Send the forward request to the remote side. */ if (compat20) { const char *address_to_bind = "0.0.0.0"; @@ -1557,6 +1603,10 @@ channel_request_remote_forwarding(u_short listen_port, const char *host_to_conne packet_put_char(0); /* boolean: want reply */ packet_put_cstring(address_to_bind); packet_put_int(listen_port); + packet_send(); + packet_write_wait(); + /* Assume that server accepts the request */ + success = 1; } else { packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); packet_put_int(listen_port); @@ -1564,11 +1614,27 @@ channel_request_remote_forwarding(u_short listen_port, const char *host_to_conne packet_put_int(port_to_connect); packet_send(); packet_write_wait(); - /* - * Wait for response from the remote side. It will send a disconnect - * message on failure, and we will never see it here. - */ - packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); + + /* Wait for response from the remote side. */ + type = packet_read(&payload_len); + switch (type) { + case SSH_SMSG_SUCCESS: + success = 1; + break; + case SSH_SMSG_FAILURE: + log("Warning: Server denied remote port forwarding."); + break; + default: + /* Unknown packet */ + packet_disconnect("Protocol error for port forward request:" + "received packet type %d.", type); + } + } + if (success) { + permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); + permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; + permitted_opens[num_permitted_opens].listen_port = listen_port; + num_permitted_opens++; } } @@ -1598,9 +1664,7 @@ channel_input_port_forward_request(int is_root, int gateway_ports) packet_disconnect("Requested forwarding of port %d but user is not root.", port); #endif - /* - * Initiate forwarding, - */ + /* Initiate forwarding */ channel_request_local_forwarding(port, hostname, host_port, gateway_ports); /* Free the argument string. */ @@ -1656,6 +1720,18 @@ channel_connect_to(const char *host, u_short host_port) /* success */ return sock; } +int +channel_connect_by_listen_adress(u_short listen_port) +{ + int i; + for (i = 0; i < num_permitted_opens; i++) + if (permitted_opens[i].listen_port == listen_port) + return channel_connect_to( + permitted_opens[i].host_to_connect, + permitted_opens[i].port_to_connect); + debug("channel_connect_by_listen_adress: unknown listen_port %d", listen_port); + return -1; +} /* * This is called after receiving PORT_OPEN message. This attempts to @@ -2233,8 +2309,11 @@ auth_input_request_forwarding(struct passwd * pw) packet_disconnect("listen: %.100s", strerror(errno)); /* Allocate a channel for the authentication agent socket. */ - newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock, - xstrdup("auth socket")); + newch = channel_new("auth socket", + SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, + 0, xstrdup("auth socket"), 1); + strlcpy(channels[newch].path, channel_forwarded_auth_socket_name, sizeof(channels[newch].path)); return 1; diff --git a/channels.h b/channels.h index 00526860..8f5e987f 100644 --- a/channels.h +++ b/channels.h @@ -32,7 +32,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("$OpenBSD: channels.h,v 1.22 2000/10/27 07:48:22 markus Exp $"); */ +/* RCSID("$OpenBSD: channels.h,v 1.23 2000/11/06 23:04:56 markus Exp $"); */ #ifndef CHANNELS_H #define CHANNELS_H @@ -49,7 +49,8 @@ #define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */ #define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */ #define SSH_CHANNEL_LARVAL 10 /* larval session */ -#define SSH_CHANNEL_MAX_TYPE 11 +#define SSH_CHANNEL_RPORT_LISTENER 11 /* Listening to a R-style port */ +#define SSH_CHANNEL_MAX_TYPE 12 /* * Data structure for channel data. This is iniailized in channel_allocate @@ -147,7 +148,6 @@ void channel_input_open_confirmation(int type, int plen, void *ctxt); void channel_input_open_failure(int type, int plen, void *ctxt); void channel_input_port_open(int type, int plen, void *ctxt); void channel_input_window_adjust(int type, int plen, void *ctxt); -void channel_input_open(int type, int plen, void *ctxt); /* Sets specific protocol options. */ void channel_set_options(int hostname_in_open); @@ -202,12 +202,15 @@ char *channel_open_message(void); /* * Initiate forwarding of connections to local port "port" through the secure - * channel to host:port from remote side. This never returns if there was an - * error. + * channel to host:port from remote side. */ void -channel_request_local_forwarding(u_short port, const char *host, - u_short remote_port, int gateway_ports); +channel_request_local_forwarding(u_short listen_port, + const char *host_to_connect, u_short port_to_connect, int gateway_ports); +void +channel_request_forwarding(const char *listen_address, u_short listen_port, + const char *host_to_connect, u_short port_to_connect, int gateway_ports, + int remote_fwd); /* * Initiate forwarding of connections to port "port" on remote host through @@ -288,6 +291,7 @@ void auth_input_open_request(int type, int plen, void *ctxt); /* XXX */ int channel_connect_to(const char *host, u_short host_port); +int channel_connect_by_listen_adress(u_short listen_port); int x11_connect_display(void); #endif diff --git a/clientloop.c b/clientloop.c index bccb9be2..8f16d2fb 100644 --- a/clientloop.c +++ b/clientloop.c @@ -59,7 +59,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: clientloop.c,v 1.39 2000/10/27 07:48:22 markus Exp $"); +RCSID("$OpenBSD: clientloop.c,v 1.40 2000/11/06 23:04:56 markus Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -75,6 +75,10 @@ RCSID("$OpenBSD: clientloop.c,v 1.39 2000/10/27 07:48:22 markus Exp $"); #include "buffer.h" #include "bufaux.h" +#include +#include +#include "key.h" +#include "authfd.h" /* import options */ extern Options options; @@ -1016,13 +1020,99 @@ client_input_exit_status(int type, int plen, void *ctxt) quit_pending = 1; } +Channel * +client_request_forwarded_tcpip(const char *request_type, int rchan) +{ + Channel* c = NULL; + char *listen_address, *originator_address; + int listen_port, originator_port; + int sock, newch; + + /* Get rest of the packet */ + listen_address = packet_get_string(NULL); + listen_port = packet_get_int(); + originator_address = packet_get_string(NULL); + originator_port = packet_get_int(); + packet_done(); + + debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", + listen_address, listen_port, originator_address, originator_port); + + sock = channel_connect_by_listen_adress(listen_port); + if (sock >= 0) { + newch = channel_new("forwarded-tcpip", + SSH_CHANNEL_OPEN, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, + xstrdup(originator_address), 1); + c = channel_lookup(newch); + } + xfree(originator_address); + xfree(listen_address); + return c; +} + +Channel* +client_request_x11(const char *request_type, int rchan) +{ + Channel *c = NULL; + char *originator; + int originator_port; + int sock, newch; + + if (!options.forward_x11) { + error("Warning: ssh server tried X11 forwarding."); + error("Warning: this is probably a break in attempt by a malicious server."); + return NULL; + } + originator = packet_get_string(NULL); + if (datafellows & SSH_BUG_X11FWD) { + debug2("buggy server: x11 request w/o originator_port"); + originator_port = 0; + } else { + originator_port = packet_get_int(); + } + packet_done(); + /* XXX check permission */ + sock = x11_connect_display(); + if (sock >= 0) { + newch = channel_new("x11", + SSH_CHANNEL_X11_OPEN, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, + xstrdup("x11"), 1); + c = channel_lookup(newch); + } + xfree(originator); + return c; +} + +Channel* +client_request_agent(const char *request_type, int rchan) +{ + Channel *c = NULL; + int sock, newch; + + if (!options.forward_agent) { + error("Warning: ssh server tried agent forwarding."); + error("Warning: this is probably a break in attempt by a malicious server."); + return NULL; + } + sock = ssh_get_authentication_socket(); + if (sock >= 0) { + newch = channel_new("authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, + xstrdup("authentication agent connection"), 1); + c = channel_lookup(newch); + } + return c; +} + /* XXXX move to generic input handler */ void client_input_channel_open(int type, int plen, void *ctxt) { Channel *c = NULL; char *ctype; - int id; unsigned int len; int rchan; int rmaxpack; @@ -1036,28 +1126,12 @@ client_input_channel_open(int type, int plen, void *ctxt) debug("client_input_channel_open: ctype %s rchan %d win %d max %d", ctype, rchan, rwindow, rmaxpack); - if (strcmp(ctype, "x11") == 0 && options.forward_x11) { - int sock; - char *originator; - int originator_port; - originator = packet_get_string(NULL); - if (datafellows & SSH_BUG_X11FWD) { - debug2("buggy server: x11 request w/o originator_port"); - originator_port = 0; - } else { - originator_port = packet_get_int(); - } - packet_done(); - /* XXX check permission */ - xfree(originator); - /* XXX move to channels.c */ - sock = x11_connect_display(); - if (sock >= 0) { - id = channel_new("x11", SSH_CHANNEL_X11_OPEN, - sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, - CHAN_X11_PACKET_DEFAULT, 0, xstrdup("x11"), 1); - c = channel_lookup(id); - } + if (strcmp(ctype, "forwarded-tcpip") == 0) { + c = client_request_forwarded_tcpip(ctype, rchan); + } else if (strcmp(ctype, "x11") == 0) { + c = client_request_x11(ctype, rchan); + } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { + c = client_request_agent(ctype, rchan); } /* XXX duplicate : */ if (c != NULL) { diff --git a/contrib/redhat/sshd.init b/contrib/redhat/sshd.init index 41f98ad8..a4df6427 100755 --- a/contrib/redhat/sshd.init +++ b/contrib/redhat/sshd.init @@ -19,13 +19,27 @@ RETVAL=0 # Some functions to make the below more readable KEYGEN=/usr/bin/ssh-keygen -RSA_KEY=/etc/ssh/ssh_host_key +RSA1_KEY=/etc/ssh/ssh_host_key +RSA_KEY=/etc/ssh/ssh_host_rsa_key DSA_KEY=/etc/ssh/ssh_host_dsa_key PID_FILE=/var/run/sshd.pid +do_rsa1_keygen() { + if ! test -f $RSA1_KEY ; then + echo -n "Generating SSH1 RSA host key: " + if $KEYGEN -q -t rsa1 -f $RSA1_KEY -C '' -N '' >&/dev/null; then + success "RSA1 key generation" + echo + else + failure "RSA1 key generation" + echo + exit 1 + fi + fi +} do_rsa_keygen() { - if $KEYGEN -R && ! test -f $RSA_KEY ; then - echo -n "Generating SSH RSA host key: " - if $KEYGEN -q -b 1024 -f $RSA_KEY -C '' -N '' >&/dev/null; then + if ! test -f $RSA_KEY ; then + echo -n "Generating SSH2 RSA host key: " + if $KEYGEN -q -t rsa -f $RSA_KEY -C '' -N '' >&/dev/null; then success "RSA key generation" echo else @@ -37,8 +51,8 @@ do_rsa_keygen() { } do_dsa_keygen() { if ! test -f $DSA_KEY ; then - echo -n "Generating SSH DSA host key: " - if $KEYGEN -q -d -b 1024 -f $DSA_KEY -C '' -N '' >&/dev/null; then + echo -n "Generating SSH2 DSA host key: " + if $KEYGEN -q -t dsa -f $DSA_KEY -C '' -N '' >&/dev/null; then success "DSA key generation" echo else @@ -52,6 +66,7 @@ do_dsa_keygen() { case "$1" in start) # Create keys if necessary + do_rsa1_keygen; do_rsa_keygen; do_dsa_keygen; diff --git a/hostfile.c b/hostfile.c index 9c03a468..3b0f286f 100644 --- a/hostfile.c +++ b/hostfile.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp $"); +RCSID("$OpenBSD: hostfile.c,v 1.21 2000/11/12 19:50:37 markus Exp $"); #include "packet.h" #include "match.h" @@ -54,15 +54,13 @@ RCSID("$OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp $"); int hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret) { - unsigned int bits; char *cp; /* Skip leading whitespace. */ for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) ; - bits = key_read(ret, &cp); - if (bits == 0) + if (key_read(ret, &cp) != 1) return 0; /* Skip trailing whitespace. */ @@ -71,14 +69,14 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret) /* Return results. */ *cpp = cp; - *bitsp = bits; + *bitsp = key_size(ret); return 1; } int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) { - Key *k = key_new(KEY_RSA); + Key *k = key_new(KEY_RSA1); int ret = hostfile_read_key(cpp, bitsp, k); BN_copy(e, k->rsa->e); BN_copy(n, k->rsa->n); @@ -89,7 +87,7 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) int hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum) { - if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) + if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) return 1; if (bits != BN_num_bits(key->rsa->n)) { log("Warning: %s, line %d: keysize mismatch for host %s: " diff --git a/kex.c b/kex.c index 68b9e522..2dbac9b1 100644 --- a/kex.c +++ b/kex.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: kex.c,v 1.13 2000/11/12 19:50:37 markus Exp $"); #include "ssh.h" #include "ssh2.h" @@ -43,6 +43,7 @@ RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $"); #include #include "kex.h" +#include "key.h" #define KEX_COOKIE_LEN 16 @@ -454,11 +455,12 @@ choose_kex(Kex *k, char *client, char *server) void choose_hostkeyalg(Kex *k, char *client, char *server) { - k->hostkeyalg = get_match(client, server); - if (k->hostkeyalg == NULL) + char *hostkeyalg = get_match(client, server); + if (hostkeyalg == NULL) fatal("no hostkey alg"); - if (strcmp(k->hostkeyalg, KEX_DSS) != 0) - fatal("bad hostkey alg %s", k->hostkeyalg); + k->hostkey_type = key_type_from_name(hostkeyalg); + if (k->hostkey_type == KEY_UNSPEC) + fatal("bad hostkey alg '%s'", hostkeyalg); } Kex * diff --git a/kex.h b/kex.h index 21295813..1890fc02 100644 --- a/kex.h +++ b/kex.h @@ -85,7 +85,7 @@ struct Kex { int we_need; int server; char *name; - char *hostkeyalg; + int hostkey_type; int kex_type; }; diff --git a/key.c b/key.c index f7df0bb1..a6b25b7a 100644 --- a/key.c +++ b/key.c @@ -39,12 +39,14 @@ #include #include "xmalloc.h" #include "key.h" -#include "dsa.h" +#include "rsa.h" +#include "ssh-dss.h" +#include "ssh-rsa.h" #include "uuencode.h" +#include "buffer.h" +#include "bufaux.h" -RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $"); - -#define SSH_DSS "ssh-dss" +RCSID("$OpenBSD: key.c,v 1.12 2000/11/12 19:50:37 markus Exp $"); Key * key_new(int type) @@ -57,6 +59,7 @@ key_new(int type) k->dsa = NULL; k->rsa = NULL; switch (k->type) { + case KEY_RSA1: case KEY_RSA: rsa = RSA_new(); rsa->n = BN_new(); @@ -71,7 +74,7 @@ key_new(int type) dsa->pub_key = BN_new(); k->dsa = dsa; break; - case KEY_EMPTY: + case KEY_UNSPEC: break; default: fatal("key_new: bad key type %d", k->type); @@ -79,10 +82,35 @@ key_new(int type) } return k; } +Key * +key_new_private(int type) +{ + Key *k = key_new(type); + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + k->rsa->d = BN_new(); + k->rsa->iqmp = BN_new(); + k->rsa->q = BN_new(); + k->rsa->p = BN_new(); + k->rsa->dmq1 = BN_new(); + k->rsa->dmp1 = BN_new(); + break; + case KEY_DSA: + k->dsa->priv_key = BN_new(); + break; + case KEY_UNSPEC: + break; + default: + break; + } + return k; +} void key_free(Key *k) { switch (k->type) { + case KEY_RSA1: case KEY_RSA: if (k->rsa != NULL) RSA_free(k->rsa); @@ -93,6 +121,8 @@ key_free(Key *k) DSA_free(k->dsa); k->dsa = NULL; break; + case KEY_UNSPEC: + break; default: fatal("key_free: bad key type %d", k->type); break; @@ -105,6 +135,7 @@ key_equal(Key *a, Key *b) if (a == NULL || b == NULL || a->type != b->type) return 0; switch (a->type) { + case KEY_RSA1: case KEY_RSA: return a->rsa != NULL && b->rsa != NULL && BN_cmp(a->rsa->e, b->rsa->e) == 0 && @@ -136,8 +167,9 @@ key_fingerprint(Key *k) int len = 0; int nlen, elen; + retval[0] = '\0'; switch (k->type) { - case KEY_RSA: + case KEY_RSA1: nlen = BN_num_bytes(k->rsa->n); elen = BN_num_bytes(k->rsa->e); len = nlen + elen; @@ -146,14 +178,16 @@ key_fingerprint(Key *k) BN_bn2bin(k->rsa->e, blob + nlen); break; case KEY_DSA: - dsa_make_key_blob(k, &blob, &len); + case KEY_RSA: + key_to_blob(k, &blob, &len); + break; + case KEY_UNSPEC: + return retval; break; default: fatal("key_fingerprint: bad key type %d", k->type); break; } - retval[0] = '\0'; - if (blob != NULL) { int i; unsigned char digest[EVP_MAX_MD_SIZE]; @@ -229,56 +263,106 @@ write_bignum(FILE *f, BIGNUM *num) free(buf); return 1; } -unsigned int + +/* returns 1 ok, -1 error, 0 type mismatch */ +int key_read(Key *ret, char **cpp) { Key *k; - unsigned int bits = 0; - char *cp; - int len, n; + int success = -1; + char *cp, *space; + int len, n, type; + u_int bits; unsigned char *blob; cp = *cpp; switch(ret->type) { - case KEY_RSA: + case KEY_RSA1: /* Get number of bits. */ if (*cp < '0' || *cp > '9') - return 0; /* Bad bit count... */ + return -1; /* Bad bit count... */ for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) bits = 10 * bits + *cp - '0'; if (bits == 0) - return 0; + return -1; *cpp = cp; /* Get public exponent, public modulus. */ if (!read_bignum(cpp, ret->rsa->e)) - return 0; + return -1; if (!read_bignum(cpp, ret->rsa->n)) - return 0; + return -1; + success = 1; break; + case KEY_UNSPEC: + case KEY_RSA: case KEY_DSA: - if (strncmp(cp, SSH_DSS " ", 7) != 0) + space = strchr(cp, ' '); + if (space == NULL) { + debug3("key_read: no space"); + return -1; + } + *space = '\0'; + type = key_type_from_name(cp); + *space = ' '; + if (type == KEY_UNSPEC) { + debug3("key_read: no key found"); + return -1; + } + cp = space+1; + if (*cp == '\0') { + debug3("key_read: short string"); + return -1; + } + if (ret->type == KEY_UNSPEC) { + ret->type = type; + } else if (ret->type != type) { + /* is a key, but different type */ + debug3("key_read: type mismatch"); return 0; - cp += 7; + } len = 2*strlen(cp); blob = xmalloc(len); n = uudecode(cp, blob, len); if (n < 0) { error("key_read: uudecode %s failed", cp); - return 0; + return -1; } - k = dsa_key_from_blob(blob, n); + k = key_from_blob(blob, n); if (k == NULL) { - error("key_read: dsa_key_from_blob %s failed", cp); - return 0; + error("key_read: key_from_blob %s failed", cp); + return -1; } xfree(blob); - if (ret->dsa != NULL) - DSA_free(ret->dsa); - ret->dsa = k->dsa; - k->dsa = NULL; + if (k->type != type) { + error("key_read: type mismatch: encoding error"); + key_free(k); + return -1; + } +/*XXXX*/ + if (ret->type == KEY_RSA) { + if (ret->rsa != NULL) + RSA_free(ret->rsa); + ret->rsa = k->rsa; + k->rsa = NULL; + success = 1; +#ifdef DEBUG_PK + RSA_print_fp(stderr, ret->rsa, 8); +#endif + } else { + if (ret->dsa != NULL) + DSA_free(ret->dsa); + ret->dsa = k->dsa; + k->dsa = NULL; + success = 1; +#ifdef DEBUG_PK + DSA_print_fp(stderr, ret->dsa, 8); +#endif + } +/*XXXX*/ + if (success != 1) + break; key_free(k); - bits = BN_num_bits(ret->dsa->p); /* advance cp: skip whitespace and data */ while (*cp == ' ' || *cp == '\t') cp++; @@ -290,7 +374,7 @@ key_read(Key *ret, char **cpp) fatal("key_read: bad key type: %d", ret->type); break; } - return bits; + return success; } int key_write(Key *key, FILE *f) @@ -298,7 +382,7 @@ key_write(Key *key, FILE *f) int success = 0; unsigned int bits = 0; - if (key->type == KEY_RSA && key->rsa != NULL) { + if (key->type == KEY_RSA1 && key->rsa != NULL) { /* size of modulus 'n' */ bits = BN_num_bits(key->rsa->n); fprintf(f, "%u", bits); @@ -308,14 +392,15 @@ key_write(Key *key, FILE *f) } else { error("key_write: failed for RSA key"); } - } else if (key->type == KEY_DSA && key->dsa != NULL) { + } else if ((key->type == KEY_DSA && key->dsa != NULL) || + (key->type == KEY_RSA && key->rsa != NULL)) { int len, n; unsigned char *blob, *uu; - dsa_make_key_blob(key, &blob, &len); + key_to_blob(key, &blob, &len); uu = xmalloc(2*len); n = uuencode(blob, len, uu, 2*len); if (n > 0) { - fprintf(f, "%s %s", SSH_DSS, uu); + fprintf(f, "%s %s", key_ssh_name(key), uu); success = 1; } xfree(blob); @@ -327,6 +412,9 @@ char * key_type(Key *k) { switch (k->type) { + case KEY_RSA1: + return "RSA1"; + break; case KEY_RSA: return "RSA"; break; @@ -336,9 +424,23 @@ key_type(Key *k) } return "unknown"; } -unsigned int +char * +key_ssh_name(Key *k) +{ + switch (k->type) { + case KEY_RSA: + return "ssh-rsa"; + break; + case KEY_DSA: + return "ssh-dss"; + break; + } + return "ssh-unknown"; +} +u_int key_size(Key *k){ switch (k->type) { + case KEY_RSA1: case KEY_RSA: return BN_num_bits(k->rsa->n); break; @@ -348,3 +450,219 @@ key_size(Key *k){ } return 0; } + +RSA * +rsa_generate_private_key(unsigned int bits) +{ + RSA *private; + private = RSA_generate_key(bits, 35, NULL, NULL); + if (private == NULL) + fatal("rsa_generate_private_key: key generation failed."); + return private; +} + +DSA* +dsa_generate_private_key(unsigned int bits) +{ + DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL); + if (private == NULL) + fatal("dsa_generate_private_key: DSA_generate_parameters failed"); + if (!DSA_generate_key(private)) + fatal("dsa_generate_private_key: DSA_generate_key failed."); + if (private == NULL) + fatal("dsa_generate_private_key: NULL."); + return private; +} + +Key * +key_generate(int type, unsigned int bits) +{ + Key *k = key_new(KEY_UNSPEC); + switch (type) { + case KEY_DSA: + k->dsa = dsa_generate_private_key(bits); + break; + case KEY_RSA: + case KEY_RSA1: + k->rsa = rsa_generate_private_key(bits); + break; + default: + fatal("key_generate: unknown type %d", type); + } + k->type = type; + return k; +} + +Key * +key_from_private(Key *k) +{ + Key *n = NULL; + switch (k->type) { + case KEY_DSA: + n = key_new(k->type); + BN_copy(n->dsa->p, k->dsa->p); + BN_copy(n->dsa->q, k->dsa->q); + BN_copy(n->dsa->g, k->dsa->g); + BN_copy(n->dsa->pub_key, k->dsa->pub_key); + break; + case KEY_RSA: + case KEY_RSA1: + n = key_new(k->type); + BN_copy(n->rsa->n, k->rsa->n); + BN_copy(n->rsa->e, k->rsa->e); + break; + default: + fatal("key_from_private: unknown type %d", k->type); + break; + } + return n; +} + +int +key_type_from_name(char *name) +{ + if (strcmp(name, "rsa1") == 0){ + return KEY_RSA1; + } else if (strcmp(name, "rsa") == 0){ + return KEY_RSA; + } else if (strcmp(name, "dsa") == 0){ + return KEY_DSA; + } else if (strcmp(name, "ssh-rsa") == 0){ + return KEY_RSA; + } else if (strcmp(name, "ssh-dss") == 0){ + return KEY_DSA; + } + debug("key_type_from_name: unknown key type '%s'", name); + return KEY_UNSPEC; +} + +Key * +key_from_blob(char *blob, int blen) +{ + Buffer b; + char *ktype; + int rlen, type; + Key *key = NULL; + +#ifdef DEBUG_PK + dump_base64(stderr, blob, blen); +#endif + buffer_init(&b); + buffer_append(&b, blob, blen); + ktype = buffer_get_string(&b, NULL); + type = key_type_from_name(ktype); + + switch(type){ + case KEY_RSA: + key = key_new(type); + buffer_get_bignum2(&b, key->rsa->n); + buffer_get_bignum2(&b, key->rsa->e); +#ifdef DEBUG_PK + RSA_print_fp(stderr, key->rsa, 8); +#endif + break; + case KEY_DSA: + key = key_new(type); + buffer_get_bignum2(&b, key->dsa->p); + buffer_get_bignum2(&b, key->dsa->q); + buffer_get_bignum2(&b, key->dsa->g); + buffer_get_bignum2(&b, key->dsa->pub_key); +#ifdef DEBUG_PK + DSA_print_fp(stderr, key->dsa, 8); +#endif + break; + case KEY_UNSPEC: + key = key_new(type); + break; + default: + error("key_from_blob: cannot handle type %s", ktype); + break; + } + rlen = buffer_len(&b); + if (key != NULL && rlen != 0) + error("key_from_blob: remaining bytes in key blob %d", rlen); + xfree(ktype); + buffer_free(&b); + return key; +} + +int +key_to_blob(Key *key, unsigned char **blobp, unsigned int *lenp) +{ + Buffer b; + int len; + unsigned char *buf; + + if (key == NULL) { + error("key_to_blob: key == NULL"); + return 0; + } + buffer_init(&b); + switch(key->type){ + case KEY_DSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->dsa->p); + buffer_put_bignum2(&b, key->dsa->q); + buffer_put_bignum2(&b, key->dsa->g); + buffer_put_bignum2(&b, key->dsa->pub_key); + break; + case KEY_RSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->rsa->n); + buffer_put_bignum2(&b, key->rsa->e); + break; + default: + error("key_to_blob: illegal key type %d", key->type); + break; + } + len = buffer_len(&b); + buf = xmalloc(len); + memcpy(buf, buffer_ptr(&b), len); + memset(buffer_ptr(&b), 0, len); + buffer_free(&b); + if (lenp != NULL) + *lenp = len; + if (blobp != NULL) + *blobp = buf; + return len; +} + +int +key_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen) +{ + switch(key->type){ + case KEY_DSA: + return ssh_dss_sign(key, sigp, lenp, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_sign(key, sigp, lenp, data, datalen); + break; + default: + error("key_sign: illegal key type %d", key->type); + return -1; + break; + } +} + +int +key_verify( + Key *key, + unsigned char *signature, int signaturelen, + unsigned char *data, int datalen) +{ + switch(key->type){ + case KEY_DSA: + return ssh_dss_verify(key, signature, signaturelen, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_verify(key, signature, signaturelen, data, datalen); + break; + default: + error("key_verify: illegal key type %d", key->type); + return -1; + break; + } +} diff --git a/key.h b/key.h index 8e1e0a98..b6c3eb01 100644 --- a/key.h +++ b/key.h @@ -26,9 +26,10 @@ typedef struct Key Key; enum types { + KEY_RSA1, KEY_RSA, KEY_DSA, - KEY_EMPTY + KEY_UNSPEC }; struct Key { int type; @@ -37,12 +38,33 @@ struct Key { }; Key *key_new(int type); +Key *key_new_private(int type); void key_free(Key *k); int key_equal(Key *a, Key *b); char *key_fingerprint(Key *k); char *key_type(Key *k); int key_write(Key *key, FILE *f); -unsigned int key_read(Key *key, char **cpp); -unsigned int key_size(Key *k); +int key_read(Key *key, char **cpp); +u_int key_size(Key *k); + +Key *key_generate(int type, unsigned int bits); +Key *key_from_private(Key *k); +int key_type_from_name(char *name); + +Key *key_from_blob(char *blob, int blen); +int key_to_blob(Key *key, unsigned char **blobp, unsigned int *lenp); +char *key_ssh_name(Key *k); + +int +key_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen); + +int +key_verify( + Key *key, + unsigned char *signature, int signaturelen, + unsigned char *data, int datalen); #endif diff --git a/myproposal.h b/myproposal.h index 98060dc3..5abb0e5a 100644 --- a/myproposal.h +++ b/myproposal.h @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define KEX_DEFAULT_KEX "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1" -#define KEX_DEFAULT_PK_ALG "ssh-dss" +#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" #define KEX_DEFAULT_ENCRYPT \ "3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \ "aes128-cbc,aes192-cbc,aes256-cbc," \ diff --git a/nchan.c b/nchan.c index 55d391e0..02c213c2 100644 --- a/nchan.c +++ b/nchan.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: nchan.c,v 1.19 2000/09/07 20:27:52 deraadt Exp $"); +RCSID("$OpenBSD: nchan.c,v 1.20 2000/11/06 23:04:56 markus Exp $"); #include "ssh.h" @@ -253,6 +253,8 @@ chan_send_oclose1(Channel *c) static void chan_delete_if_full_closed1(Channel *c) { + debug3("channel %d: chan_delete_if_full_closed1: istate %d ostate %d", + c->self, c->istate, c->ostate); if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { debug("channel %d: full closed", c->self); channel_free(c->self); @@ -403,6 +405,8 @@ chan_send_close2(Channel *c) static void chan_delete_if_full_closed2(Channel *c) { + debug3("channel %d: chan_delete_if_full_closed2: istate %d ostate %d", + c->self, c->istate, c->ostate); if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { if (!(c->flags & CHAN_CLOSE_SENT)) { chan_send_close2(c); diff --git a/readconf.c b/readconf.c index c6fdd530..c821d840 100644 --- a/readconf.c +++ b/readconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.50 2000/11/12 19:50:37 markus Exp $"); #include "ssh.h" #include "readconf.h" @@ -68,7 +68,7 @@ RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $"); # Defaults for various options Host * ForwardAgent no - ForwardX11 yes + ForwardX11 no RhostsAuthentication yes PasswordAuthentication yes RSAAuthentication yes @@ -101,8 +101,8 @@ typedef enum { oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication, - oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2, - oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication, + oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, + oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, oKbdInteractiveAuthentication, oKbdInteractiveDevices } OpCodes; @@ -122,7 +122,8 @@ static struct { { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, { "kbdinteractivedevices", oKbdInteractiveDevices }, { "rsaauthentication", oRSAAuthentication }, - { "dsaauthentication", oDSAAuthentication }, + { "pubkeyauthentication", oPubkeyAuthentication }, + { "dsaauthentication", oPubkeyAuthentication }, /* alias */ { "skeyauthentication", oSkeyAuthentication }, #ifdef KRB4 { "kerberosauthentication", oKerberosAuthentication }, @@ -134,7 +135,7 @@ static struct { { "fallbacktorsh", oFallBackToRsh }, { "usersh", oUseRsh }, { "identityfile", oIdentityFile }, - { "identityfile2", oIdentityFile2 }, + { "identityfile2", oIdentityFile }, /* alias */ { "hostname", oHostName }, { "proxycommand", oProxyCommand }, { "port", oPort }, @@ -300,8 +301,8 @@ parse_flag: charptr = &options->kbd_interactive_devices; goto parse_string; - case oDSAAuthentication: - intptr = &options->dsa_authentication; + case oPubkeyAuthentication: + intptr = &options->pubkey_authentication; goto parse_flag; case oRSAAuthentication: @@ -386,20 +387,15 @@ parse_flag: goto parse_int; case oIdentityFile: - case oIdentityFile2: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep) { - intptr = (opcode == oIdentityFile) ? - &options->num_identity_files : - &options->num_identity_files2; + intptr = &options->num_identity_files; if (*intptr >= SSH_MAX_IDENTITY_FILES) fatal("%.200s line %d: Too many identity files specified (max %d).", filename, linenum, SSH_MAX_IDENTITY_FILES); - charptr = (opcode == oIdentityFile) ? - &options->identity_files[*intptr] : - &options->identity_files2[*intptr]; + charptr = &options->identity_files[*intptr]; *charptr = xstrdup(arg); *intptr = *intptr + 1; } @@ -664,7 +660,7 @@ initialize_options(Options * options) options->use_privileged_port = -1; options->rhosts_authentication = -1; options->rsa_authentication = -1; - options->dsa_authentication = -1; + options->pubkey_authentication = -1; options->skey_authentication = -1; #ifdef KRB4 options->kerberos_authentication = -1; @@ -692,7 +688,6 @@ 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; @@ -730,8 +725,8 @@ fill_default_options(Options * options) options->rhosts_authentication = 1; if (options->rsa_authentication == -1) options->rsa_authentication = 1; - if (options->dsa_authentication == -1) - options->dsa_authentication = 1; + if (options->pubkey_authentication == -1) + options->pubkey_authentication = 1; if (options->skey_authentication == -1) options->skey_authentication = 0; #ifdef KRB4 @@ -779,16 +774,18 @@ fill_default_options(Options * options) if (options->protocol == SSH_PROTO_UNKNOWN) options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED; if (options->num_identity_files == 0) { - options->identity_files[0] = - xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); - sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY); - options->num_identity_files = 1; - } - if (options->num_identity_files2 == 0) { - options->identity_files2[0] = - xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1); - sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA); - options->num_identity_files2 = 1; + if (options->protocol & SSH_PROTO_1) { + options->identity_files[options->num_identity_files] = + xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); + sprintf(options->identity_files[options->num_identity_files++], + "~/%.100s", SSH_CLIENT_IDENTITY); + } + if (options->protocol & SSH_PROTO_2) { + options->identity_files[options->num_identity_files] = + xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1); + sprintf(options->identity_files[options->num_identity_files++], + "~/%.100s", SSH_CLIENT_ID_DSA); + } } if (options->escape_char == -1) options->escape_char = '~'; diff --git a/readconf.h b/readconf.h index e94213fa..85d937d8 100644 --- a/readconf.h +++ b/readconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: readconf.h,v 1.22 2000/10/11 20:14:39 markus Exp $"); */ +/* RCSID("$OpenBSD: readconf.h,v 1.23 2000/11/12 19:50:37 markus Exp $"); */ #ifndef READCONF_H #define READCONF_H @@ -35,7 +35,7 @@ typedef struct { int rhosts_rsa_authentication; /* Try rhosts with RSA * authentication. */ int rsa_authentication; /* Try RSA authentication. */ - int dsa_authentication; /* Try DSA authentication. */ + int pubkey_authentication; /* Try ssh2 pubkey authentication. */ int skey_authentication; /* Try S/Key or TIS authentication. */ #ifdef KRB4 int kerberos_authentication; /* Try Kerberos @@ -78,10 +78,9 @@ typedef struct { char *system_hostfile2; char *user_hostfile2; - int num_identity_files; /* Number of files for RSA identities. */ - int num_identity_files2; /* DSA identities. */ + int num_identity_files; /* Number of files for RSA/DSA identities. */ char *identity_files[SSH_MAX_IDENTITY_FILES]; - char *identity_files2[SSH_MAX_IDENTITY_FILES]; + int identity_files_type[SSH_MAX_IDENTITY_FILES]; /* Local TCP/IP forward requests. */ int num_local_forwards; diff --git a/rsa.c b/rsa.c index 0c9aef79..7cfcc80d 100644 --- a/rsa.c +++ b/rsa.c @@ -60,82 +60,13 @@ */ #include "includes.h" -RCSID("$OpenBSD: rsa.c,v 1.16 2000/09/07 20:27:53 deraadt Exp $"); +RCSID("$OpenBSD: rsa.c,v 1.17 2000/11/12 19:50:37 markus Exp $"); #include "rsa.h" #include "ssh.h" #include "xmalloc.h" #include "entropy.h" -int rsa_verbose = 1; - -int -rsa_alive() -{ - RSA *key; - - seed_rng(); - key = RSA_generate_key(32, 3, NULL, NULL); - if (key == NULL) - return (0); - RSA_free(key); - return (1); -} - -/* - * Generates RSA public and private keys. This initializes the data - * structures; they should be freed with rsa_clear_private_key and - * rsa_clear_public_key. - */ - -void -rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits) -{ - RSA *key; - - seed_rng(); - - if (rsa_verbose) { - printf("Generating RSA keys: "); - fflush(stdout); - } - key = RSA_generate_key(bits, 35, NULL, NULL); - if (key == NULL) - fatal("rsa_generate_key: key generation failed."); - - /* Copy public key parameters */ - pub->n = BN_new(); - BN_copy(pub->n, key->n); - pub->e = BN_new(); - BN_copy(pub->e, key->e); - - /* Copy private key parameters */ - prv->n = BN_new(); - BN_copy(prv->n, key->n); - prv->e = BN_new(); - BN_copy(prv->e, key->e); - prv->d = BN_new(); - BN_copy(prv->d, key->d); - prv->p = BN_new(); - BN_copy(prv->p, key->p); - prv->q = BN_new(); - BN_copy(prv->q, key->q); - - prv->dmp1 = BN_new(); - BN_copy(prv->dmp1, key->dmp1); - - prv->dmq1 = BN_new(); - BN_copy(prv->dmq1, key->dmq1); - - prv->iqmp = BN_new(); - BN_copy(prv->iqmp, key->iqmp); - - RSA_free(key); - - if (rsa_verbose) - printf("Key generation complete.\n"); -} - void rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key) { @@ -188,11 +119,3 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) xfree(outbuf); xfree(inbuf); } - -/* Set whether to output verbose messages during key generation. */ - -void -rsa_set_verbose(int verbose) -{ - rsa_verbose = verbose; -} diff --git a/rsa.h b/rsa.h index 93a2dac8..57d72cc7 100644 --- a/rsa.h +++ b/rsa.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: rsa.h,v 1.8 2000/09/07 20:27:53 deraadt Exp $"); */ +/* RCSID("$OpenBSD: rsa.h,v 1.9 2000/11/12 19:50:38 markus Exp $"); */ #ifndef RSA_H #define RSA_H @@ -19,17 +19,6 @@ #include #include -/* Calls SSL RSA_generate_key, only copies to prv and pub */ -void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits); - -/* - * Indicates whether the rsa module is permitted to show messages on the - * terminal. - */ -void rsa_set_verbose __P((int verbose)); - -int rsa_alive __P((void)); - void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); void rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); diff --git a/servconf.c b/servconf.c index 76702a83..5da55de0 100644 --- a/servconf.c +++ b/servconf.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: servconf.c,v 1.53 2000/10/14 12:12:09 markus Exp $"); +RCSID("$OpenBSD: servconf.c,v 1.54 2000/11/12 19:50:38 markus Exp $"); #include "ssh.h" #include "servconf.h" @@ -29,8 +29,7 @@ initialize_server_options(ServerOptions *options) options->num_ports = 0; options->ports_from_cmdline = 0; options->listen_addrs = NULL; - options->host_key_file = NULL; - options->host_dsa_key_file = NULL; + options->num_host_key_files = 0; options->pid_file = NULL; options->server_key_bits = -1; options->login_grace_time = -1; @@ -50,7 +49,7 @@ initialize_server_options(ServerOptions *options) options->rhosts_authentication = -1; options->rhosts_rsa_authentication = -1; options->rsa_authentication = -1; - options->dsa_authentication = -1; + options->pubkey_authentication = -1; #ifdef KRB4 options->kerberos_authentication = -1; options->kerberos_or_local_passwd = -1; @@ -84,14 +83,19 @@ initialize_server_options(ServerOptions *options) void fill_default_server_options(ServerOptions *options) { + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_1|SSH_PROTO_2; + if (options->num_host_key_files == 0) { + /* fill default hostkeys for protocols */ + if (options->protocol & SSH_PROTO_1) + options->host_key_files[options->num_host_key_files++] = HOST_KEY_FILE; + if (options->protocol & SSH_PROTO_2) + options->host_key_files[options->num_host_key_files++] = HOST_DSA_KEY_FILE; + } if (options->num_ports == 0) options->ports[options->num_ports++] = SSH_DEFAULT_PORT; if (options->listen_addrs == NULL) add_listen_addr(options, NULL); - if (options->host_key_file == NULL) - options->host_key_file = HOST_KEY_FILE; - if (options->host_dsa_key_file == NULL) - options->host_dsa_key_file = HOST_DSA_KEY_FILE; if (options->pid_file == NULL) options->pid_file = SSH_DAEMON_PID_FILE; if (options->server_key_bits == -1) @@ -132,8 +136,8 @@ fill_default_server_options(ServerOptions *options) options->rhosts_rsa_authentication = 0; if (options->rsa_authentication == -1) options->rsa_authentication = 1; - if (options->dsa_authentication == -1) - options->dsa_authentication = 1; + if (options->pubkey_authentication == -1) + options->pubkey_authentication = 1; #ifdef KRB4 if (options->kerberos_authentication == -1) options->kerberos_authentication = (access(KEYFILE, R_OK) == 0); @@ -162,8 +166,6 @@ fill_default_server_options(ServerOptions *options) options->use_login = 0; if (options->allow_tcp_forwarding == -1) options->allow_tcp_forwarding = 1; - if (options->protocol == SSH_PROTO_UNKNOWN) - options->protocol = SSH_PROTO_1|SSH_PROTO_2; if (options->gateway_ports == -1) options->gateway_ports = 0; if (options->max_startups == -1) @@ -194,8 +196,8 @@ typedef enum { sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, sUseLogin, sAllowTcpForwarding, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, - sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, - sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups + sIgnoreUserKnownHosts, sCiphers, sProtocol, sPidFile, + sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, } ServerOpCodes; /* Textual representation of the tokens. */ @@ -205,7 +207,7 @@ static struct { } keywords[] = { { "port", sPort }, { "hostkey", sHostKeyFile }, - { "hostdsakey", sHostDSAKeyFile }, + { "hostdsakey", sHostKeyFile }, /* alias */ { "pidfile", sPidFile }, { "serverkeybits", sServerKeyBits }, { "logingracetime", sLoginGraceTime }, @@ -216,7 +218,8 @@ static struct { { "rhostsauthentication", sRhostsAuthentication }, { "rhostsrsaauthentication", sRhostsRSAAuthentication }, { "rsaauthentication", sRSAAuthentication }, - { "dsaauthentication", sDSAAuthentication }, + { "pubkeyauthentication", sPubkeyAuthentication }, + { "dsaauthentication", sPubkeyAuthentication }, /* alias */ #ifdef KRB4 { "kerberosauthentication", sKerberosAuthentication }, { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, @@ -336,6 +339,8 @@ read_server_config(ServerOptions *options, const char *filename) arg = strdelim(&cp); if (!*arg || *arg == '#') continue; + intptr = NULL; + charptr = NULL; opcode = parse_token(arg, filename, linenum); switch (opcode) { case sBadOption: @@ -389,9 +394,13 @@ parse_int: break; case sHostKeyFile: - case sHostDSAKeyFile: - charptr = (opcode == sHostKeyFile ) ? - &options->host_key_file : &options->host_dsa_key_file; + intptr = &options->num_host_key_files; + if (*intptr >= MAX_HOSTKEYS) { + fprintf(stderr, "%s line %d: to many host keys specified (max %d).\n", + filename, linenum, MAX_HOSTKEYS); + exit(1); + } + charptr = &options->host_key_files[*intptr]; parse_filename: arg = strdelim(&cp); if (!arg || *arg == '\0') { @@ -399,8 +408,12 @@ parse_filename: filename, linenum); exit(1); } - if (*charptr == NULL) + if (*charptr == NULL) { *charptr = tilde_expand_filename(arg, getuid()); + /* increase optional counter */ + if (intptr != NULL) + *intptr = *intptr + 1; + } break; case sPidFile: @@ -474,8 +487,8 @@ parse_flag: intptr = &options->rsa_authentication; goto parse_flag; - case sDSAAuthentication: - intptr = &options->dsa_authentication; + case sPubkeyAuthentication: + intptr = &options->pubkey_authentication; goto parse_flag; #ifdef KRB4 diff --git a/servconf.h b/servconf.h index 0188b9b8..3ecf6a00 100644 --- a/servconf.h +++ b/servconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: servconf.h,v 1.30 2000/10/14 12:12:09 markus Exp $"); */ +/* RCSID("$OpenBSD: servconf.h,v 1.31 2000/11/12 19:50:38 markus Exp $"); */ #ifndef SERVCONF_H #define SERVCONF_H @@ -23,6 +23,7 @@ #define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ #define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ +#define MAX_HOSTKEYS 256 /* Max # hostkeys. */ typedef struct { unsigned int num_ports; @@ -30,8 +31,8 @@ typedef struct { u_short ports[MAX_PORTS]; /* Port number to listen on. */ char *listen_addr; /* Address on which the server listens. */ struct addrinfo *listen_addrs; /* Addresses on which the server listens. */ - char *host_key_file; /* File containing host key. */ - char *host_dsa_key_file; /* File containing dsa host key. */ + char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */ + int num_host_key_files; /* Number of files for host keys. */ char *pid_file; /* Where to put our pid */ int server_key_bits;/* Size of the server key. */ int login_grace_time; /* Disconnect if no auth in this time @@ -59,7 +60,7 @@ typedef struct { int rhosts_rsa_authentication; /* If true, permit rhosts RSA * authentication. */ int rsa_authentication; /* If true, permit RSA authentication. */ - int dsa_authentication; /* If true, permit DSA authentication. */ + int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ #ifdef KRB4 int kerberos_authentication; /* If true, permit Kerberos * authentication. */ diff --git a/serverloop.c b/serverloop.c index 6a81806b..dfef6f33 100644 --- a/serverloop.c +++ b/serverloop.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: serverloop.c,v 1.34 2000/10/27 07:32:18 markus Exp $"); +RCSID("$OpenBSD: serverloop.c,v 1.35 2000/11/06 23:04:56 markus Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -50,6 +50,7 @@ RCSID("$OpenBSD: serverloop.c,v 1.34 2000/10/27 07:32:18 markus Exp $"); #include "session.h" #include "dispatch.h" #include "auth-options.h" +#include "auth.h" extern ServerOptions options; @@ -739,10 +740,10 @@ server_input_window_size(int type, int plen, void *ctxt) pty_change_window_size(fdin, row, col, xpixel, ypixel); } -int -input_direct_tcpip(void) +Channel * +server_request_direct_tcpip(char *ctype) { - int sock; + int sock, newch; char *target, *originator; int target_port, originator_port; @@ -752,23 +753,52 @@ input_direct_tcpip(void) originator_port = packet_get_int(); packet_done(); - debug("open direct-tcpip: from %s port %d to %s port %d", + debug("server_request_direct_tcpip: originator %s port %d, target %s port %d", originator, originator_port, target, target_port); /* XXX check permission */ if (no_port_forwarding_flag || !options.allow_tcp_forwarding) { xfree(target); xfree(originator); - return -1; + return NULL; } sock = channel_connect_to(target, target_port); xfree(target); xfree(originator); if (sock < 0) - return -1; - return channel_new("direct-tcpip", SSH_CHANNEL_OPEN, + return NULL; + newch = channel_new(ctype, SSH_CHANNEL_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1); + return (newch >= 0) ? channel_lookup(newch) : NULL; +} + +Channel * +server_request_session(char *ctype) +{ + int newch; + + debug("input_session_request"); + packet_done(); + /* + * A server session has no fd to read or write until a + * CHANNEL_REQUEST for a shell is made, so we set the type to + * SSH_CHANNEL_LARVAL. Additionally, a callback for handling all + * CHANNEL_REQUEST messages is registered. + */ + newch = channel_new(ctype, SSH_CHANNEL_LARVAL, + -1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT, + 0, xstrdup("server-session"), 1); + if (session_open(newch) == 1) { + channel_register_callback(newch, SSH2_MSG_CHANNEL_REQUEST, + session_input_channel_req, (void *)0); + channel_register_cleanup(newch, session_close_by_channel); + return channel_lookup(newch); + } else { + debug("session open failed, free channel %d", newch); + channel_free(newch); + } + return NULL; } void @@ -776,7 +806,6 @@ server_input_channel_open(int type, int plen, void *ctxt) { Channel *c = NULL; char *ctype; - int id; unsigned int len; int rchan; int rmaxpack; @@ -791,34 +820,12 @@ server_input_channel_open(int type, int plen, void *ctxt) ctype, rchan, rwindow, rmaxpack); if (strcmp(ctype, "session") == 0) { - debug("open session"); - packet_done(); - /* - * A server session has no fd to read or write - * until a CHANNEL_REQUEST for a shell is made, - * so we set the type to SSH_CHANNEL_LARVAL. - * Additionally, a callback for handling all - * CHANNEL_REQUEST messages is registered. - */ - id = channel_new(ctype, SSH_CHANNEL_LARVAL, - -1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT, - 0, xstrdup("server-session"), 1); - if (session_open(id) == 1) { - channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST, - session_input_channel_req, (void *)0); - channel_register_cleanup(id, session_close_by_channel); - c = channel_lookup(id); - } else { - debug("session open failed, free channel %d", id); - channel_free(id); - } + c = server_request_session(ctype); } else if (strcmp(ctype, "direct-tcpip") == 0) { - id = input_direct_tcpip(); - if (id >= 0) - c = channel_lookup(id); + c = server_request_direct_tcpip(ctype); } if (c != NULL) { - debug("confirm %s", ctype); + debug("server_input_channel_open: confirm %s", ctype); c->remote_id = rchan; c->remote_window = rwindow; c->remote_maxpacket = rmaxpack; @@ -830,7 +837,7 @@ server_input_channel_open(int type, int plen, void *ctxt) packet_put_int(c->local_maxpacket); packet_send(); } else { - debug("failure %s", ctype); + debug("server_input_channel_open: failure %s", ctype); packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); packet_put_int(rchan); packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); @@ -841,6 +848,56 @@ server_input_channel_open(int type, int plen, void *ctxt) xfree(ctype); } +void +server_input_global_request(int type, int plen, void *ctxt) +{ + char *rtype; + int want_reply; + int success = 0; + + rtype = packet_get_string(NULL); + want_reply = packet_get_char(); + debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply); + + if (strcmp(rtype, "tcpip-forward") == 0) { + struct passwd *pw; + char *listen_address; + u_short listen_port; + + pw = auth_get_user(); + if (pw == NULL) + fatal("server_input_global_request: no user"); + listen_address = packet_get_string(NULL); /* XXX currently ignored */ + listen_port = (u_short)packet_get_int(); + debug("server_input_global_request: tcpip-forward listen %s port %d", + listen_address, listen_port); + + /* check permissions */ + if (!options.allow_tcp_forwarding || + no_port_forwarding_flag || + (listen_port < IPPORT_RESERVED && pw->pw_uid != 0)) { + success = 0; + packet_send_debug("Server has disabled port forwarding."); + } else { + /* Start listening on the port */ + channel_request_forwarding( + listen_address, listen_port, + /*unspec host_to_connect*/ "", + /*unspec port_to_connect*/ 0, + options.gateway_ports, /*remote*/ 1); + success = 1; + } + xfree(listen_address); + } + if (want_reply) { + packet_start(success ? + SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); + packet_send(); + packet_write_wait(); + } + xfree(rtype); +} + void server_init_dispatch_20() { @@ -855,6 +912,7 @@ server_init_dispatch_20() dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request); dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); + dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); } void server_init_dispatch_13() diff --git a/session.c b/session.c index 6794d3d6..b94c8e84 100644 --- a/session.c +++ b/session.c @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.42 2000/10/27 07:32:18 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.43 2000/11/06 23:04:56 markus Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -1735,6 +1735,19 @@ session_exec_req(Session *s) return 1; } +int +session_auth_agent_req(Session *s) +{ + static int called = 0; + packet_done(); + if (called) { + return 0; + } else { + called = 1; + return auth_input_request_forwarding(s->pw); + } +} + void session_input_channel_req(int id, void *arg) { @@ -1771,6 +1784,8 @@ session_input_channel_req(int id, void *arg) success = session_pty_req(s); } else if (strcmp(rtype, "x11-req") == 0) { success = session_x11_req(s); + } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { + success = session_auth_agent_req(s); } else if (strcmp(rtype, "subsystem") == 0) { success = session_subsystem_req(s); } diff --git a/sftp-server.8 b/sftp-server.8 index fb4706c4..b8d579a9 100644 --- a/sftp-server.8 +++ b/sftp-server.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp-server.8,v 1.3 2000/10/13 17:20:44 aaron Exp $ +.\" $OpenBSD: sftp-server.8,v 1.4 2000/11/10 05:10:40 aaron Exp $ .\" .\" Copyright (c) 2000 Markus Friedl. All rights reserved. .\" @@ -48,7 +48,7 @@ for more information. .Xr ssh-add 1 , .Xr ssh-keygen 1 , .Xr sshd 8 -.Sh AUTHOR +.Sh AUTHORS Markus Friedl .Sh HISTORY .Nm diff --git a/ssh-add.1 b/ssh-add.1 index aa12ef34..7d641c02 100644 --- a/ssh-add.1 +++ b/ssh-add.1 @@ -116,7 +116,7 @@ may be necessary to redirect the input from .Pa /dev/null to make this work.) .El -.Sh AUTHOR +.Sh AUTHORS Tatu Ylonen .Pp OpenSSH diff --git a/ssh-add.c b/ssh-add.c index 3adc2509..f49d13fb 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-add.c,v 1.22 2000/09/07 20:27:54 deraadt Exp $"); +RCSID("$OpenBSD: ssh-add.c,v 1.23 2000/11/12 19:50:38 markus Exp $"); #include #include @@ -60,10 +60,10 @@ delete_file(AuthenticationConnection *ac, const char *filename) Key *public; char *comment; - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (!load_public_key(filename, public, &comment)) { key_free(public); - public = key_new(KEY_DSA); + public = key_new(KEY_UNSPEC); if (!try_load_public_key(filename, public, &comment)) { printf("Bad key file %s\n", filename); return; @@ -144,7 +144,7 @@ add_file(AuthenticationConnection *ac, const char *filename) char buf[1024], msg[1024]; int success; int interactive = isatty(STDIN_FILENO); - int type = KEY_RSA; + int type = KEY_RSA1; if (stat(filename, &st) < 0) { perror(filename); @@ -154,10 +154,10 @@ add_file(AuthenticationConnection *ac, const char *filename) * try to load the public key. right now this only works for RSA, * since DSA keys are fully encrypted */ - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (!load_public_key(filename, public, &saved_comment)) { - /* ok, so we will asume this is a DSA key */ - type = KEY_DSA; + /* ok, so we will assume this is 'some' key */ + type = KEY_UNSPEC; saved_comment = xstrdup(filename); } key_free(public); @@ -223,8 +223,9 @@ list_identities(AuthenticationConnection *ac, int fp) key = ssh_get_next_identity(ac, &comment, version)) { had_identities = 1; if (fp) { - printf("%d %s %s\n", - key_size(key), key_fingerprint(key), comment); + printf("%d %s %s (%s)\n", + key_size(key), key_fingerprint(key), + comment, key_type(key)); } else { if (!key_write(key, stdout)) fprintf(stderr, "key_write failed"); @@ -250,13 +251,6 @@ main(int argc, char **argv) init_rng(); - /* 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); - } SSLeay_add_all_algorithms(); /* At first, get a connection to the authentication agent. */ diff --git a/ssh-agent.1 b/ssh-agent.1 index 064d9d4c..31ea2b31 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.16 2000/09/07 20:27:54 deraadt Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.17 2000/11/10 05:10:40 aaron Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -160,7 +160,7 @@ authentication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the agent exits. .El -.Sh AUTHOR +.Sh AUTHORS Tatu Ylonen .Pp OpenSSH diff --git a/ssh-agent.c b/ssh-agent.c index 479388fa..9f61aec3 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.37 2000/09/21 11:07:51 markus Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.39 2000/11/12 19:50:38 markus Exp $ */ /* * Author: Tatu Ylonen @@ -37,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-agent.c,v 1.37 2000/09/21 11:07:51 markus Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.39 2000/11/12 19:50:38 markus Exp $"); #include "ssh.h" #include "rsa.h" @@ -54,7 +54,6 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.37 2000/09/21 11:07:51 markus Exp $"); #include #include "key.h" #include "authfd.h" -#include "dsa.h" #include "kex.h" #include "compat.h" @@ -147,14 +146,14 @@ process_request_identities(SocketEntry *e, int version) buffer_put_int(&msg, tab->nentries); for (i = 0; i < tab->nentries; i++) { Identity *id = &tab->identities[i]; - if (id->key->type == KEY_RSA) { + if (id->key->type == KEY_RSA1) { buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); buffer_put_bignum(&msg, id->key->rsa->e); buffer_put_bignum(&msg, id->key->rsa->n); } else { unsigned char *blob; unsigned int blen; - dsa_make_key_blob(id->key, &blob, &blen); + key_to_blob(id->key, &blob, &blen); buffer_put_string(&msg, blob, blen); xfree(blob); } @@ -178,7 +177,7 @@ process_authentication_challenge1(SocketEntry *e) unsigned int response_type; buffer_init(&msg); - key = key_new(KEY_RSA); + key = key_new(KEY_RSA1); challenge = BN_new(); buffer_get_int(&e->input); /* ignored */ @@ -251,11 +250,11 @@ process_sign_request2(SocketEntry *e) if (flags & SSH_AGENT_OLD_SIGNATURE) datafellows = SSH_BUG_SIGBLOB; - key = dsa_key_from_blob(blob, blen); + key = key_from_blob(blob, blen); if (key != NULL) { private = lookup_private_key(key, NULL, 2); if (private != NULL) - ok = dsa_sign(private, &signature, &slen, data, dlen); + ok = key_sign(private, &signature, &slen, data, dlen); } key_free(key); buffer_init(&msg); @@ -287,7 +286,7 @@ process_remove_identity(SocketEntry *e, int version) switch(version){ case 1: - key = key_new(KEY_RSA); + key = key_new(KEY_RSA1); bits = buffer_get_int(&e->input); buffer_get_bignum(&e->input, key->rsa->e); buffer_get_bignum(&e->input, key->rsa->n); @@ -298,7 +297,7 @@ process_remove_identity(SocketEntry *e, int version) break; case 2: blob = buffer_get_string(&e->input, &blen); - key = dsa_key_from_blob(blob, blen); + key = key_from_blob(blob, blen); xfree(blob); break; } @@ -315,8 +314,12 @@ process_remove_identity(SocketEntry *e, int version) Idtab *tab = idtab_lookup(version); key_free(tab->identities[idx].key); xfree(tab->identities[idx].comment); - if (idx != tab->nentries) - tab->identities[idx] = tab->identities[tab->nentries]; + if (tab->nentries < 1) + fatal("process_remove_identity: " + "internal error: tab->nentries %d", + tab->nentries); + if (idx != tab->nentries - 1) + tab->identities[idx] = tab->identities[tab->nentries - 1]; tab->nentries--; success = 1; } @@ -349,79 +352,80 @@ process_remove_all_identities(SocketEntry *e, int version) } void -process_add_identity(SocketEntry *e, int version) +generate_additional_parameters(RSA *rsa) { - Key *k = NULL; - RSA *rsa; BIGNUM *aux; BN_CTX *ctx; - char *type; + /* Generate additional parameters */ + aux = BN_new(); + ctx = BN_CTX_new(); + + BN_sub(aux, rsa->q, BN_value_one()); + BN_mod(rsa->dmq1, rsa->d, aux, ctx); + + BN_sub(aux, rsa->p, BN_value_one()); + BN_mod(rsa->dmp1, rsa->d, aux, ctx); + + BN_clear_free(aux); + BN_CTX_free(ctx); +} + +void +process_add_identity(SocketEntry *e, int version) +{ + Key *k = NULL; + char *type_name; char *comment; - int success = 0; + int type, success = 0; Idtab *tab = idtab_lookup(version); switch (version) { case 1: - k = key_new(KEY_RSA); - rsa = k->rsa; - - /* allocate mem for private key */ - /* XXX rsa->n and rsa->e are already allocated */ - rsa->d = BN_new(); - rsa->iqmp = BN_new(); - rsa->q = BN_new(); - rsa->p = BN_new(); - rsa->dmq1 = BN_new(); - rsa->dmp1 = BN_new(); - - buffer_get_int(&e->input); /* ignored */ - - buffer_get_bignum(&e->input, rsa->n); - buffer_get_bignum(&e->input, rsa->e); - buffer_get_bignum(&e->input, rsa->d); - buffer_get_bignum(&e->input, rsa->iqmp); + k = key_new_private(KEY_RSA1); + buffer_get_int(&e->input); /* ignored */ + buffer_get_bignum(&e->input, k->rsa->n); + buffer_get_bignum(&e->input, k->rsa->e); + buffer_get_bignum(&e->input, k->rsa->d); + buffer_get_bignum(&e->input, k->rsa->iqmp); /* SSH and SSL have p and q swapped */ - buffer_get_bignum(&e->input, rsa->q); /* p */ - buffer_get_bignum(&e->input, rsa->p); /* q */ + buffer_get_bignum(&e->input, k->rsa->q); /* p */ + buffer_get_bignum(&e->input, k->rsa->p); /* q */ /* Generate additional parameters */ - aux = BN_new(); - ctx = BN_CTX_new(); - - BN_sub(aux, rsa->q, BN_value_one()); - BN_mod(rsa->dmq1, rsa->d, aux, ctx); - - BN_sub(aux, rsa->p, BN_value_one()); - BN_mod(rsa->dmp1, rsa->d, aux, ctx); - - BN_clear_free(aux); - BN_CTX_free(ctx); - + generate_additional_parameters(k->rsa); break; case 2: - type = buffer_get_string(&e->input, NULL); - if (strcmp(type, KEX_DSS)) { + type_name = buffer_get_string(&e->input, NULL); + type = key_type_from_name(type_name); + xfree(type_name); + switch(type) { + case KEY_DSA: + k = key_new_private(type); + buffer_get_bignum2(&e->input, k->dsa->p); + buffer_get_bignum2(&e->input, k->dsa->q); + buffer_get_bignum2(&e->input, k->dsa->g); + buffer_get_bignum2(&e->input, k->dsa->pub_key); + buffer_get_bignum2(&e->input, k->dsa->priv_key); + break; + case KEY_RSA: + k = key_new_private(type); + buffer_get_bignum2(&e->input, k->rsa->n); + buffer_get_bignum2(&e->input, k->rsa->e); + buffer_get_bignum2(&e->input, k->rsa->d); + buffer_get_bignum2(&e->input, k->rsa->iqmp); + buffer_get_bignum2(&e->input, k->rsa->p); + buffer_get_bignum2(&e->input, k->rsa->q); + + /* Generate additional parameters */ + generate_additional_parameters(k->rsa); + break; + default: buffer_clear(&e->input); - xfree(type); goto send; } - xfree(type); - - k = key_new(KEY_DSA); - - /* allocate mem for private key */ - k->dsa->priv_key = BN_new(); - - buffer_get_bignum2(&e->input, k->dsa->p); - buffer_get_bignum2(&e->input, k->dsa->q); - buffer_get_bignum2(&e->input, k->dsa->g); - buffer_get_bignum2(&e->input, k->dsa->pub_key); - buffer_get_bignum2(&e->input, k->dsa->priv_key); - break; } - comment = buffer_get_string(&e->input, NULL); if (k == NULL) { xfree(comment); @@ -670,13 +674,6 @@ main(int ac, char **av) init_rng(); - /* 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); - } #ifdef __GNU_LIBRARY__ while ((ch = getopt(ac, av, "+cks")) != -1) { #else /* __GNU_LIBRARY__ */ diff --git a/dsa.c b/ssh-dss.c similarity index 67% rename from dsa.c rename to ssh-dss.c index 4ff4b58f..fea1fe2d 100644 --- a/dsa.c +++ b/ssh-dss.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: dsa.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $"); +RCSID("$OpenBSD: ssh-dss.c,v 1.1 2000/11/12 19:50:38 markus Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -32,88 +32,17 @@ RCSID("$OpenBSD: dsa.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $"); #include "compat.h" #include -#include #include #include #include -#include -#include -#include -#include "kex.h" #include "key.h" -#include "uuencode.h" #define INTBLOB_LEN 20 #define SIGBLOB_LEN (2*INTBLOB_LEN) -Key * -dsa_key_from_blob(char *blob, int blen) -{ - Buffer b; - char *ktype; - int rlen; - DSA *dsa; - Key *key; - -#ifdef DEBUG_DSS - dump_base64(stderr, blob, blen); -#endif - /* fetch & parse DSA/DSS pubkey */ - buffer_init(&b); - buffer_append(&b, blob, blen); - ktype = buffer_get_string(&b, NULL); - if (strcmp(KEX_DSS, ktype) != 0) { - error("dsa_key_from_blob: cannot handle type %s", ktype); - buffer_free(&b); - xfree(ktype); - return NULL; - } - key = key_new(KEY_DSA); - dsa = key->dsa; - buffer_get_bignum2(&b, dsa->p); - buffer_get_bignum2(&b, dsa->q); - buffer_get_bignum2(&b, dsa->g); - buffer_get_bignum2(&b, dsa->pub_key); - rlen = buffer_len(&b); - if(rlen != 0) - error("dsa_key_from_blob: remaining bytes in key blob %d", rlen); - buffer_free(&b); - xfree(ktype); - -#ifdef DEBUG_DSS - DSA_print_fp(stderr, dsa, 8); -#endif - return key; -} -int -dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp) -{ - Buffer b; - int len; - unsigned char *buf; - - if (key == NULL || key->type != KEY_DSA) - return 0; - buffer_init(&b); - buffer_put_cstring(&b, KEX_DSS); - buffer_put_bignum2(&b, key->dsa->p); - buffer_put_bignum2(&b, key->dsa->q); - buffer_put_bignum2(&b, key->dsa->g); - buffer_put_bignum2(&b, key->dsa->pub_key); - len = buffer_len(&b); - buf = xmalloc(len); - memcpy(buf, buffer_ptr(&b), len); - memset(buffer_ptr(&b), 0, len); - buffer_free(&b); - if (lenp != NULL) - *lenp = len; - if (blobp != NULL) - *blobp = buf; - return len; -} int -dsa_sign( +ssh_dss_sign( Key *key, unsigned char **sigp, int *lenp, unsigned char *data, int datalen) @@ -130,7 +59,7 @@ dsa_sign( Buffer b; if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { - error("dsa_sign: no DSA key"); + error("ssh_dss_sign: no DSA key"); return -1; } digest = xmalloc(evp_md->md_size); @@ -140,7 +69,7 @@ dsa_sign( sig = DSA_do_sign(digest, evp_md->md_size, key->dsa); if (sig == NULL) { - fatal("dsa_sign: cannot sign"); + fatal("ssh_dss_sign: cannot sign"); } rlen = BN_num_bytes(sig->r); @@ -168,7 +97,7 @@ dsa_sign( } else { /* ietf-drafts */ buffer_init(&b); - buffer_put_cstring(&b, KEX_DSS); + buffer_put_cstring(&b, "ssh-dss"); buffer_put_string(&b, sigblob, SIGBLOB_LEN); len = buffer_len(&b); ret = xmalloc(len); @@ -182,7 +111,7 @@ dsa_sign( return 0; } int -dsa_verify( +ssh_dss_verify( Key *key, unsigned char *signature, int signaturelen, unsigned char *data, int datalen) @@ -194,12 +123,12 @@ dsa_verify( EVP_MD_CTX md; unsigned char *sigblob; char *txt; - unsigned int len; + unsigned int len, dlen; int rlen; int ret; if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { - error("dsa_verify: no DSA key"); + error("ssh_dss_verify: no DSA key"); return -1; } @@ -225,8 +154,8 @@ dsa_verify( buffer_init(&b); buffer_append(&b, (char *) signature, signaturelen); ktype = buffer_get_string(&b, NULL); - if (strcmp(KEX_DSS, ktype) != 0) { - error("dsa_verify: cannot handle type %s", ktype); + if (strcmp("ssh-dss", ktype) != 0) { + error("ssh_dss_verify: cannot handle type %s", ktype); buffer_free(&b); return -1; } @@ -258,14 +187,15 @@ dsa_verify( } /* sha1 the data */ - digest = xmalloc(evp_md->md_size); + dlen = evp_md->md_size; + digest = xmalloc(dlen); EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, data, datalen); EVP_DigestFinal(&md, digest, NULL); - ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa); + ret = DSA_do_verify(digest, dlen, sig, key->dsa); - memset(digest, 0, evp_md->md_size); + memset(digest, 0, dlen); xfree(digest); DSA_SIG_free(sig); @@ -281,24 +211,6 @@ dsa_verify( txt = "error"; break; } - debug("dsa_verify: signature %s", txt); + debug("ssh_dss_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/dsa.h b/ssh-dss.h similarity index 89% rename from dsa.h rename to ssh-dss.h index 252e7880..7b376e82 100644 --- a/dsa.h +++ b/ssh-dss.h @@ -24,22 +24,16 @@ #ifndef DSA_H #define DSA_H -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( +ssh_dss_sign( Key *key, unsigned char **sigp, int *lenp, unsigned char *data, int datalen); int -dsa_verify( +ssh_dss_verify( Key *key, unsigned char *signature, int signaturelen, unsigned char *data, int datalen); -Key * -dsa_generate_key(unsigned int bits); - #endif diff --git a/ssh-keygen.1 b/ssh-keygen.1 index b91a0982..b1430f14 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 @@ -43,8 +43,9 @@ .Nd authentication key generation .Sh SYNOPSIS .Nm ssh-keygen -.Op Fl dq +.Op Fl q .Op Fl b Ar bits +.Op Fl t Ar type .Op Fl N Ar new_passphrase .Op Fl C Ar comment .Op Fl f Ar output_keyfile @@ -79,8 +80,8 @@ generates and manages authentication keys for .Nm defaults to generating an RSA key for use by protocols 1.3 and 1.5; specifying the -.Fl d -flag will create a DSA key instead for use by protocol 2.0. +.Fl t +allows you to create a key for use by protocol 2.0. .Pp Normally each user wishing to use SSH with RSA or DSA authentication runs this once to create the authentication @@ -154,6 +155,17 @@ Silence Used by .Pa /etc/rc when creating a new key. +.It Fl t Ar type +Specifies the type of the key to create. +The possible values are +.Dq rsa1 +for protocol version 1 and +.Dq rsa +or +.Dq dsa +for protocol version 2. +The default is +.Dq rsa . .It Fl C Ar comment Provides the new comment. .It Fl N Ar new_passphrase @@ -173,7 +185,7 @@ SSH2-compatible private (or public) key file and print an OpenSSH compatible private (or public) key to stdout. .It Fl y This option will read a private -OpenSSH DSA format file and print an OpenSSH DSA public key to stdout. +OpenSSH format file and print an OpenSSH public key to stdout. .El .Sh FILES .Bl -tag -width Ds @@ -211,10 +223,10 @@ Contains the public key for authentication. The contents of this file should be added to .Pa $HOME/.ssh/authorized_keys2 on all machines -where you wish to log in using DSA authentication. +where you wish to log in using public key authentication. There is no need to keep the contents of this file secret. .El -.Sh AUTHOR +.Sh AUTHORS Tatu Ylonen .Pp OpenSSH diff --git a/ssh-keygen.c b/ssh-keygen.c index e050f405..76edc530 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-keygen.c,v 1.32 2000/10/09 21:30:44 markus Exp $"); +RCSID("$OpenBSD: ssh-keygen.c,v 1.33 2000/11/12 19:50:38 markus Exp $"); #include #include @@ -23,7 +23,6 @@ RCSID("$OpenBSD: ssh-keygen.c,v 1.32 2000/10/09 21:30:44 markus Exp $"); #include "xmalloc.h" #include "key.h" #include "rsa.h" -#include "dsa.h" #include "authfile.h" #include "uuencode.h" @@ -67,7 +66,10 @@ char *identity_comment = NULL; int convert_to_ssh2 = 0; int convert_from_ssh2 = 0; int print_public = 0; -int dsa_mode = 0; + +/* key type */ +int dsa_mode = 0; /* compat */ +char *key_type_name = NULL; /* argv0 */ #ifdef HAVE___PROGNAME @@ -130,12 +132,12 @@ do_convert_to_ssh2(struct passwd *pw) perror(identity_file); exit(1); } - k = key_new(KEY_DSA); + k = key_new(KEY_UNSPEC); if (!try_load_key(identity_file, k)) { fprintf(stderr, "load failed\n"); exit(1); } - dsa_make_key_blob(k, &blob, &len); + key_to_blob(k, &blob, &len); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); fprintf(stdout, "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n", @@ -266,7 +268,7 @@ do_convert_from_ssh2(struct passwd *pw) } k = private ? do_convert_private_ssh2_from_blob(blob, blen) : - dsa_key_from_blob(blob, blen); + key_from_blob(blob, blen); if (k == NULL) { fprintf(stderr, "decode blob failed.\n"); exit(1); @@ -288,8 +290,6 @@ void do_print_public(struct passwd *pw) { Key *k; - int len; - unsigned char *blob; struct stat st; if (!have_identity) @@ -298,16 +298,14 @@ do_print_public(struct passwd *pw) perror(identity_file); exit(1); } - k = key_new(KEY_DSA); + k = key_new(KEY_UNSPEC); 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); - xfree(blob); fprintf(stdout, "\n"); exit(0); } @@ -315,12 +313,11 @@ do_print_public(struct passwd *pw) void do_fingerprint(struct passwd *pw) { - /* XXX RSA1 only */ FILE *f; Key *public; char *comment = NULL, *cp, *ep, line[16*1024]; - int i, skip = 0, num = 1, invalid = 1; + int i, skip = 0, num = 1, invalid = 1, success = 0; unsigned int ignore; struct stat st; @@ -330,14 +327,27 @@ do_fingerprint(struct passwd *pw) perror(identity_file); exit(1); } - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (load_public_key(identity_file, public, &comment)) { - printf("%d %s %s\n", BN_num_bits(public->rsa->n), - key_fingerprint(public), comment); + success = 1; + } else { + key_free(public); + public = key_new(KEY_UNSPEC); + if (try_load_public_key(identity_file, public, &comment)) + success = 1; + else + error("try_load_public_key KEY_UNSPEC failed"); + } + if (success) { + printf("%d %s %s\n", key_size(public), key_fingerprint(public), comment); key_free(public); + xfree(comment); exit(0); } + /* XXX RSA1 only */ + + public = key_new(KEY_RSA1); f = fopen(identity_file, "r"); if (f != NULL) { while (fgets(line, sizeof(line), f)) { @@ -404,7 +414,7 @@ do_change_passphrase(struct passwd *pw) struct stat st; Key *private; Key *public; - int type = dsa_mode ? KEY_DSA : KEY_RSA; + int type = KEY_RSA1; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); @@ -412,18 +422,13 @@ do_change_passphrase(struct passwd *pw) perror(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); - } + public = key_new(type); + if (!load_public_key(identity_file, public, NULL)) { + type = KEY_UNSPEC; + } else { /* Clear the public key since we are just about to load the whole file. */ key_free(public); } - /* Try to load the file with empty passphrase. */ private = key_new(type); if (!load_private_key(identity_file, "", private, &comment)) { @@ -508,13 +513,13 @@ 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_new(KEY_RSA); + public = key_new(KEY_RSA1); if (!load_public_key(identity_file, public, NULL)) { printf("%s is not a valid key file.\n", identity_file); exit(1); } - private = key_new(KEY_RSA); + private = key_new(KEY_RSA1); if (load_private_key(identity_file, "", private, &comment)) passphrase = xstrdup(""); else { @@ -583,7 +588,7 @@ do_change_comment(struct passwd *pw) void usage(void) { - printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname); + printf("Usage: %s [-lpqxXyc] [-t type] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname); exit(1); } @@ -598,8 +603,10 @@ main(int ac, char **av) int opt; struct stat st; FILE *f; + int type = KEY_RSA1; Key *private; Key *public; + extern int optind; extern char *optarg; @@ -618,7 +625,7 @@ main(int ac, char **av) exit(1); } - while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) { + while ((opt = getopt(ac, av, "dqpclRxXyb:f:t:P:N:C:")) != EOF) { switch (opt) { case 'b': bits = atoi(optarg); @@ -662,10 +669,8 @@ main(int ac, char **av) break; case 'R': - if (rsa_alive() == 0) - exit(1); - else - exit(0); + /* unused */ + exit(0); break; case 'x': @@ -681,9 +686,15 @@ main(int ac, char **av) break; case 'd': + key_type_name = "dsa"; dsa_mode = 1; break; + case 't': + key_type_name = optarg; + dsa_mode = (strcmp(optarg, "dsa") == 0); + break; + case '?': default: usage(); @@ -697,13 +708,6 @@ 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) @@ -719,22 +723,21 @@ main(int ac, char **av) arc4random_stir(); - 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"); + if (key_type_name != NULL) { + type = key_type_from_name(key_type_name); + if (type == KEY_UNSPEC) { + fprintf(stderr, "unknown key type %s", key_type_name); 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 (!quiet) + printf("Generating public/private key pair.\n"); + private = key_generate(type, bits); + if (private == NULL) { + fprintf(stderr, "key_generate failed"); + exit(1); + } + public = key_from_private(private); if (!have_identity) ask_filename(pw, "Enter file in which to save the key"); @@ -803,9 +806,7 @@ passphrase_again: xfree(passphrase1); /* Clear the private key and the random number generator. */ - if (private != public) { - key_free(private); - } + key_free(private); arc4random_stir(); if (!quiet) diff --git a/ssh-rsa.c b/ssh-rsa.c new file mode 100644 index 00000000..cc31154d --- /dev/null +++ b/ssh-rsa.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-rsa.c,v 1.1 2000/11/12 19:50:38 markus Exp $"); + +#include "ssh.h" +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" + +#include +#include +#include +#include + +#include "key.h" + +#define INTBLOB_LEN 20 +#define SIGBLOB_LEN (2*INTBLOB_LEN) + +/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ +int +ssh_rsa_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen) +{ + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + unsigned char *digest, *sig, *ret; + unsigned int slen, dlen, len; + int ok; + Buffer b; + + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + error("ssh_rsa_sign: no RSA key"); + return -1; + } + slen = RSA_size(key->rsa); + sig = xmalloc(slen); + + dlen = evp_md->md_size; + digest = xmalloc(dlen); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, NULL); + + ok = RSA_sign(NID_sha1, digest, dlen, sig, &len, key->rsa); + memset(digest, 'd', dlen); + xfree(digest); + + if (ok != 1) { + int ecode = ERR_get_error(); + error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL)); + xfree(sig); + return -1; + } + if (len < slen) { + int diff = slen - len; + debug("slen %d > len %d", slen, len); + memmove(sig + diff, sig, len); + memset(sig, 0, diff); + } else if (len > slen) { + error("ssh_rsa_sign: slen %d slen2 %d", slen, len); + xfree(sig); + return -1; + } + /* encode signature */ + buffer_init(&b); + buffer_put_cstring(&b, "ssh-rsa"); + buffer_put_string(&b, sig, slen); + len = buffer_len(&b); + ret = xmalloc(len); + memcpy(ret, buffer_ptr(&b), len); + buffer_free(&b); + memset(sig, 's', slen); + xfree(sig); + + if (lenp != NULL) + *lenp = len; + if (sigp != NULL) + *sigp = ret; + debug2("ssh_rsa_sign: done"); + return 0; +} + +int +ssh_rsa_verify( + Key *key, + unsigned char *signature, int signaturelen, + unsigned char *data, int datalen) +{ + Buffer b; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + char *ktype; + unsigned char *sigblob, *digest; + unsigned int len, dlen; + int rlen; + int ret; + + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + error("ssh_rsa_verify: no RSA key"); + return -1; + } + buffer_init(&b); + buffer_append(&b, (char *) signature, signaturelen); + ktype = buffer_get_string(&b, NULL); + if (strcmp("ssh-rsa", ktype) != 0) { + error("ssh_rsa_verify: cannot handle type %s", ktype); + buffer_free(&b); + xfree(ktype); + return -1; + } + xfree(ktype); + sigblob = (unsigned char *)buffer_get_string(&b, &len); + rlen = buffer_len(&b); + buffer_free(&b); + if(rlen != 0) { + error("ssh_rsa_verify: remaining bytes in signature %d", rlen); + return -1; + } + + dlen = evp_md->md_size; + digest = xmalloc(dlen); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, NULL); + + ret = RSA_verify(NID_sha1, digest, dlen, sigblob, len, key->rsa); + memset(digest, 'd', dlen); + xfree(digest); + memset(sigblob, 's', len); + xfree(sigblob); + if (ret == 0) { + int ecode = ERR_get_error(); + error("ssh_rsa_verify: RSA_verify failed: %s", ERR_error_string(ecode, NULL)); + } + debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); + return ret; +} diff --git a/ssh-rsa.h b/ssh-rsa.h new file mode 100644 index 00000000..29a0c029 --- /dev/null +++ b/ssh-rsa.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SSH_RSA_H +#define SSH_RSA_H + +int +ssh_rsa_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen); + +int +ssh_rsa_verify( + Key *key, + unsigned char *signature, int signaturelen, + unsigned char *data, int datalen); + +#endif diff --git a/ssh.1 b/ssh.1 index 786df184..4bbfe34c 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.64 2000/10/16 21:46:31 markus Exp $ +.\" $OpenBSD: ssh.1,v 1.68 2000/11/12 19:50:38 markus Exp $ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -209,9 +209,9 @@ At first, the client attempts to authenticate using the public key method. If this method fails password authentication is tried. .Pp The public key method is similar to RSA authentication described -in the previous section except that the DSA algorithm is used -instead of the patented RSA algorithm. -The client uses his private DSA key +in the previous section except that the DSA or RSA algorithm is used +instead. +The client uses his private key .Pa $HOME/.ssh/id_dsa to sign the session identifier and sends the result to the server. The server checks whether the matching public key is listed in @@ -331,7 +331,7 @@ identifications for all hosts it has ever been used with. RSA host keys are stored in .Pa $HOME/.ssh/known_hosts and -DSA host keys are stored in +host keys used in the protocol version 2 are stored in .Pa $HOME/.ssh/known_hosts2 in the user's home directory. Additionally, the files @@ -352,7 +352,8 @@ The .Cm StrictHostKeyChecking option (see below) can be used to prevent logins to machines whose host key is not known or has changed. -.Sh OPTIONS +.Pp +The options are as follows: .Bl -tag -width Ds .It Fl a Disables forwarding of the authentication agent connection. @@ -407,7 +408,7 @@ something like Allows remote hosts to connect to local forwarded ports. .It Fl i Ar identity_file Selects the file from which the identity (private key) for -RSA authentication is read. +RSA or DSA authentication is read. Default is .Pa $HOME/.ssh/identity in the user's home directory. @@ -552,6 +553,22 @@ Forces .Nm to use IPv6 addresses only. .El +.Pp +If +.Nm +is not invoked with one of the standard program names +.Pf ( Dq ssh , +.Dq slogin , +.Dq rsh , +.Dq rlogin , +or +.Dq remsh ) , +it uses this name as its +.Ar hostname +argument. +This is consistent with traditional +.Xr rsh 1 +behavior. .Sh CONFIGURATION FILES .Nm obtains configuration data from the following sources (in this order): @@ -660,14 +677,12 @@ Specifies the number of tries (one per second) to make before falling back to rsh or exiting. The argument must be an integer. This may be useful in scripts if the connection sometimes fails. -.It Cm DSAAuthentication -Specifies whether to try DSA authentication. +.It Cm PubkeyAuthentication +Specifies whether to try public key authentication. The argument to this keyword must be .Dq yes or .Dq no . -DSA authentication will only be -attempted if a DSA identity file exists. Note that this option applies to protocol version 2 only. .It Cm EscapeChar Sets the escape character (default: @@ -745,16 +760,6 @@ syntax to refer to a user's home directory. It is possible to have multiple identity files specified in configuration files; all these identities will be tried in sequence. -.It Cm IdentityFile2 -Specifies the file from which the user's DSA authentication identity -is read (default -.Pa $HOME/.ssh/id_dsa -in the user's home directory). -The file name may use the tilde -syntax to refer to a user's home directory. -It is possible to have -multiple identity files specified in configuration files; all these -identities will be tried in sequence. .It Cm KeepAlive Specifies whether the system should send keepalive messages to the other side. @@ -1096,7 +1101,7 @@ spaces). This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. .It Pa $HOME/.ssh/authorized_keys2 -Lists the DSA keys that can be used for logging in as this user. +Lists the public keys (DSA/RSA) that can be used for logging in as this user. This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. .It Pa /etc/ssh_known_hosts, /etc/ssh_known_hosts2 @@ -1104,7 +1109,7 @@ Systemwide list of known host keys. .Pa /etc/ssh_known_hosts contains RSA and .Pa /etc/ssh_known_hosts2 -contains DSA keys. +contains DSA or RSA keys for protocol version 2. These files should be prepared by the system administrator to contain the public host keys of all machines in the organization. @@ -1219,7 +1224,7 @@ above. A version of this library which includes support for the RSA algorithm is required for proper operation. .El -.Sh AUTHOR +.Sh AUTHORS OpenSSH is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen, but with bugs removed and newer features re-added. diff --git a/ssh.c b/ssh.c index 429d571b..ab32e3b8 100644 --- a/ssh.c +++ b/ssh.c @@ -39,11 +39,12 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh.c,v 1.69 2000/10/27 07:32:19 markus Exp $"); +RCSID("$OpenBSD: ssh.c,v 1.72 2000/11/12 19:50:38 markus Exp $"); #include #include #include +#include #include "xmalloc.h" #include "ssh.h" @@ -218,8 +219,9 @@ rsh_connect(char *host, char *user, Buffer * command) exit(1); } -int ssh_session(void); -int ssh_session2(void); +int ssh_session(void); +int ssh_session2(void); +int guess_identity_file_type(const char *filename); /* * Main program for the ssh client. @@ -370,14 +372,13 @@ main(int ac, char **av) case 'i': if (stat(optarg, &st) < 0) { fprintf(stderr, "Warning: Identity file %s does not exist.\n", - optarg); + optarg); break; } if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES) fatal("Too many identity files specified (max %d)", - SSH_MAX_IDENTITY_FILES); - options.identity_files[options.num_identity_files++] = - xstrdup(optarg); + SSH_MAX_IDENTITY_FILES); + options.identity_files[options.num_identity_files++] = xstrdup(optarg); break; case 't': tty_flag = 1; @@ -487,6 +488,7 @@ main(int ac, char **av) usage(); SSLeay_add_all_algorithms(); + ERR_load_crypto_strings(); /* Initialize the command to execute on remote host. */ buffer_init(&command); @@ -563,20 +565,6 @@ 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); @@ -589,6 +577,8 @@ main(int ac, char **av) if (!options.use_privileged_port) { #else if (original_effective_uid != 0 || !options.use_privileged_port) { + debug("Rhosts Authentication methods disabled, " + "originating port will not be trusted."); #endif options.rhosts_authentication = 0; options.rhosts_rsa_authentication = 0; @@ -635,7 +625,7 @@ main(int ac, char **av) if (ok && (options.protocol & SSH_PROTO_1)) { Key k; host_private_key = RSA_new(); - k.type = KEY_RSA; + k.type = KEY_RSA1; k.rsa = host_private_key; if (load_private_key(HOST_KEY_FILE, "", &k, NULL)) host_private_key_loaded = 1; @@ -682,23 +672,23 @@ main(int ac, char **av) } exit(1); } - /* Expand ~ in options.identity_files. */ + /* Expand ~ in options.identity_files, known host file names. */ /* XXX mem-leaks */ - for (i = 0; i < options.num_identity_files; i++) + 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); - options.user_hostfile = tilde_expand_filename(options.user_hostfile, - 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); + tilde_expand_filename(options.identity_files[i], original_real_uid); + options.identity_files_type[i] = guess_identity_file_type(options.identity_files[i]); + debug("identity file %s type %d", options.identity_files[i], + options.identity_files_type[i]); + } + options.system_hostfile = + tilde_expand_filename(options.system_hostfile, original_real_uid); + options.user_hostfile = + tilde_expand_filename(options.user_hostfile, 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, @@ -752,16 +742,57 @@ x11_get_proto(char *proto, int proto_len, char *data, int data_len) } } +void +ssh_init_forwarding(void) +{ + int i; + /* Initiate local TCP/IP port forwardings. */ + for (i = 0; i < options.num_local_forwards; i++) { + debug("Connections to local port %d forwarded to remote address %.200s:%d", + options.local_forwards[i].port, + options.local_forwards[i].host, + options.local_forwards[i].host_port); + channel_request_local_forwarding( + options.local_forwards[i].port, + options.local_forwards[i].host, + options.local_forwards[i].host_port, + options.gateway_ports); + } + + /* Initiate remote TCP/IP port forwardings. */ + for (i = 0; i < options.num_remote_forwards; i++) { + debug("Connections to remote port %d forwarded to local address %.200s:%d", + options.remote_forwards[i].port, + options.remote_forwards[i].host, + options.remote_forwards[i].host_port); + channel_request_remote_forwarding( + options.remote_forwards[i].port, + options.remote_forwards[i].host, + options.remote_forwards[i].host_port); + } +} + +void +check_agent_present(void) +{ + if (options.forward_agent) { + /* Clear agent forwarding if we don\'t have an agent. */ + int authfd = ssh_get_authentication_socket(); + if (authfd < 0) + options.forward_agent = 0; + else + ssh_close_authentication_socket(authfd); + } +} + int ssh_session(void) { int type; - int i; int plen; int interactive = 0; int have_tty = 0; struct winsize ws; - int authfd; char *cp; /* Enable compression if requested. */ @@ -845,14 +876,10 @@ ssh_session(void) /* Tell the packet module whether this is an interactive session. */ packet_set_interactive(interactive, options.keepalives); - /* Clear agent forwarding if we don\'t have an agent. */ - authfd = ssh_get_authentication_socket(); - if (authfd < 0) - options.forward_agent = 0; - else - ssh_close_authentication_socket(authfd); /* Request authentication agent forwarding if appropriate. */ + check_agent_present(); + if (options.forward_agent) { debug("Requesting authentication agent forwarding."); auth_request_forwarding(); @@ -863,28 +890,9 @@ ssh_session(void) if (type != SSH_SMSG_SUCCESS) log("Warning: Remote host denied authentication agent forwarding."); } - /* Initiate local TCP/IP port forwardings. */ - for (i = 0; i < options.num_local_forwards; i++) { - debug("Connections to local port %d forwarded to remote address %.200s:%d", - options.local_forwards[i].port, - options.local_forwards[i].host, - options.local_forwards[i].host_port); - channel_request_local_forwarding(options.local_forwards[i].port, - options.local_forwards[i].host, - options.local_forwards[i].host_port, - options.gateway_ports); - } - /* Initiate remote TCP/IP port forwardings. */ - for (i = 0; i < options.num_remote_forwards; i++) { - debug("Connections to remote port %d forwarded to local address %.200s:%d", - options.remote_forwards[i].port, - options.remote_forwards[i].host, - options.remote_forwards[i].host_port); - channel_request_remote_forwarding(options.remote_forwards[i].port, - options.remote_forwards[i].host, - options.remote_forwards[i].host_port); - } + /* Initiate port forwardings. */ + ssh_init_forwarding(); /* If requested, let ssh continue in the background. */ if (fork_after_authentication_flag) @@ -915,27 +923,10 @@ ssh_session(void) return client_loop(have_tty, tty_flag ? options.escape_char : -1, 0); } -void -init_local_fwd(void) -{ - int i; - /* Initiate local TCP/IP port forwardings. */ - for (i = 0; i < options.num_local_forwards; i++) { - debug("Connections to local port %d forwarded to remote address %.200s:%d", - options.local_forwards[i].port, - options.local_forwards[i].host, - options.local_forwards[i].host_port); - channel_request_local_forwarding(options.local_forwards[i].port, - options.local_forwards[i].host, - options.local_forwards[i].host_port, - options.gateway_ports); - } -} - extern void client_set_session_ident(int id); void -client_init(int id, void *arg) +ssh_session2_callback(int id, void *arg) { int len; debug("client_init id %d arg %d", id, (int)arg); @@ -974,6 +965,13 @@ client_init(int id, void *arg) /* XXX wait for reply */ } + check_agent_present(); + if (options.forward_agent) { + debug("Requesting authentication agent forwarding."); + channel_request_start(id, "auth-agent-req@openssh.com", 0); + packet_send(); + } + len = buffer_len(&command); if (len > 0) { if (len > 900) @@ -1016,8 +1014,8 @@ ssh_session2(void) if (!isatty(err)) set_nonblock(err); - /* should be pre-session */ - init_local_fwd(); + /* XXX should be pre-session */ + ssh_init_forwarding(); /* If requested, let ssh continue in the background. */ if (fork_after_authentication_flag) @@ -1036,7 +1034,28 @@ ssh_session2(void) xstrdup("client-session"), /*nonblock*/0); channel_open(id); - channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0); + channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, + ssh_session2_callback, (void *)0); return client_loop(tty_flag, tty_flag ? options.escape_char : -1, id); } + +int +guess_identity_file_type(const char *filename) +{ + struct stat st; + Key *public; + int type = KEY_RSA1; /* default */ + + if (stat(filename, &st) < 0) { + perror(filename); + return KEY_UNSPEC; + } + public = key_new(type); + if (!load_public_key(filename, public, NULL)) { + /* ok, so we will assume this is 'some' key */ + type = KEY_UNSPEC; + } + key_free(public); + return type; +} diff --git a/ssh_config b/ssh_config index cb360d04..fdac1313 100644 --- a/ssh_config +++ b/ssh_config @@ -13,9 +13,9 @@ # Site-wide defaults for various options # Host * -# ForwardAgent yes -# ForwardX11 yes -# RhostsAuthentication yes +# ForwardAgent no +# ForwardX11 no +# RhostsAuthentication no # RhostsRSAAuthentication yes # RSAAuthentication yes # PasswordAuthentication yes @@ -23,9 +23,12 @@ # UseRsh no # BatchMode no # CheckHostIP yes -# StrictHostKeyChecking no +# StrictHostKeyChecking yes # IdentityFile ~/.ssh/identity +# IdentityFile ~/.ssh/id_dsa +# IdentityFile ~/.ssh/id_rsa1 +# IdentityFile ~/.ssh/id_rsa2 # Port 22 -# Protocol 2,1 +# Protocol 1,2 # Cipher blowfish # EscapeChar ~ diff --git a/sshconnect.c b/sshconnect.c index d6072b36..12ca69fd 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.79 2000/09/17 15:52:51 markus Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.81 2000/11/06 23:16:35 markus Exp $"); #include #include @@ -249,9 +249,9 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, /* Create a socket for connecting. */ sock = ssh_create_socket(original_real_uid, #ifdef HAVE_CYGWIN - !anonymous && port < IPPORT_RESERVED, + !anonymous, #else - !anonymous && geteuid() == 0 && port < IPPORT_RESERVED, + !anonymous && geteuid() == 0, #endif ai->ai_family); if (sock < 0) @@ -321,6 +321,7 @@ ssh_exchange_identification() int remote_major, remote_minor, i, mismatch; int connection_in = packet_get_connection_in(); int connection_out = packet_get_connection_out(); + int minor1 = PROTOCOL_MINOR_1; /* Read other side\'s version identification. */ for (;;) { @@ -374,9 +375,10 @@ ssh_exchange_identification() } if (remote_minor < 3) { fatal("Remote machine has too old SSH software version."); - } else if (remote_minor == 3) { + } else if (remote_minor == 3 || remote_minor == 4) { /* We speak 1.3, too. */ enable_compat13(); + minor1 = 3; if (options.forward_agent) { log("Agent forwarding disabled for protocol 1.3"); options.forward_agent = 0; @@ -402,7 +404,7 @@ ssh_exchange_identification() /* Send our own protocol version identification. */ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, - compat20 ? PROTOCOL_MINOR_2 : PROTOCOL_MINOR_1, + compat20 ? PROTOCOL_MINOR_2 : minor1, SSH_VERSION); if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf)) fatal("write: %.100s", strerror(errno)); diff --git a/sshconnect1.c b/sshconnect1.c index ce560791..227e10b4 100644 --- a/sshconnect1.c +++ b/sshconnect1.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.8 2000/10/12 09:59:19 markus Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.9 2000/11/12 19:50:38 markus Exp $"); #include #include @@ -62,7 +62,7 @@ try_agent_authentication() return 0; challenge = BN_new(); - key = key_new(KEY_RSA); + key = key_new(KEY_RSA1); /* Loop through identities served by the agent. */ for (key = ssh_get_first_identity(auth, &comment, 1); @@ -196,7 +196,7 @@ try_rsa_authentication(const char *authfile) int plen, clen; /* Try to load identification for the authentication key. */ - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (!load_public_key(authfile, public, &comment)) { key_free(public); /* Could not load it. Fail. */ @@ -237,7 +237,7 @@ try_rsa_authentication(const char *authfile) debug("Received RSA challenge from server."); - private = key_new(KEY_RSA); + private = key_new(KEY_RSA1); /* * Load the private key. Try first with empty passphrase; if it * fails, ask for a passphrase. @@ -760,7 +760,7 @@ 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); - k.type = KEY_RSA; + k.type = KEY_RSA1; k.rsa = host_key; check_host_key(host, hostaddr, &k, options.user_hostfile, options.system_hostfile); @@ -994,7 +994,8 @@ ssh_userauth( /* Try RSA authentication for each identity. */ for (i = 0; i < options.num_identity_files; i++) - if (try_rsa_authentication(options.identity_files[i])) + if (options.identity_files_type[i] == KEY_RSA1 && + try_rsa_authentication(options.identity_files[i])) return; } /* Try skey authentication if the server supports it. */ diff --git a/sshconnect2.c b/sshconnect2.c index 6ba23d44..bb4774aa 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.27 2000/10/19 16:45:16 provos Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.28 2000/11/12 19:50:38 markus Exp $"); #include #include @@ -45,7 +45,6 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.27 2000/10/19 16:45:16 provos Exp $"); #include "kex.h" #include "myproposal.h" #include "key.h" -#include "dsa.h" #include "sshconnect.h" #include "authfile.h" #include "cli.h" @@ -196,7 +195,7 @@ ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, /* key, cert */ server_host_key_blob = packet_get_string(&sbloblen); - server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); if (server_host_key == NULL) fatal("cannot decode server_host_key_blob"); @@ -258,8 +257,8 @@ ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, fprintf(stderr, "%02x", (hash[i])&0xff); fprintf(stderr, "\n"); #endif - if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) - fatal("dsa_verify failed for server_host_key"); + if (key_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); key_free(server_host_key); kex_derive_keys(kex, hash, shared_secret); @@ -366,7 +365,7 @@ ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, /* key, cert */ server_host_key_blob = packet_get_string(&sbloblen); - server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); if (server_host_key == NULL) fatal("cannot decode server_host_key_blob"); @@ -429,8 +428,8 @@ ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, fprintf(stderr, "%02x", (hash[i])&0xff); fprintf(stderr, "\n"); #endif - if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) - fatal("dsa_verify failed for server_host_key"); + if (key_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); key_free(server_host_key); kex_derive_keys(kex, hash, shared_secret); @@ -485,7 +484,7 @@ Authmethod *authmethod_lookup(const char *name); Authmethod authmethods[] = { {"publickey", userauth_pubkey, - &options.dsa_authentication, + &options.pubkey_authentication, NULL}, {"password", userauth_passwd, @@ -653,8 +652,10 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) int ret = -1; int have_sig = 1; - dsa_make_key_blob(k, &blob, &bloblen); - + if (key_to_blob(k, &blob, &bloblen) == 0) { + /* we cannot handle this key */ + return 0; + } /* data to be signed */ buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { @@ -672,7 +673,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) authctxt->service); buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, KEX_DSS); + buffer_put_cstring(&b, key_ssh_name(k)); buffer_put_string(&b, blob, bloblen); /* generate signature */ @@ -682,7 +683,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) buffer_free(&b); return 0; } -#ifdef DEBUG_DSS +#ifdef DEBUG_PK buffer_dump(&b); #endif if (datafellows & SSH_BUG_PUBKEYAUTH) { @@ -693,7 +694,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) buffer_put_cstring(&b, authctxt->service); buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, KEX_DSS); + buffer_put_cstring(&b, key_ssh_name(k)); buffer_put_string(&b, blob, bloblen); } xfree(blob); @@ -719,10 +720,10 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) } /* sign callback */ -int dsa_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, +int key_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, unsigned char *data, int datalen) { - return dsa_sign(key, sigp, lenp, data, datalen); + return key_sign(key, sigp, lenp, data, datalen); } int @@ -738,14 +739,13 @@ userauth_pubkey_identity(Authctxt *authctxt, char *filename) } debug("try pubkey: %s", filename); - k = key_new(KEY_DSA); + k = key_new(KEY_UNSPEC); if (!load_private_key(filename, "", k, NULL)) { int success = 0; char *passphrase; char prompt[300]; snprintf(prompt, sizeof prompt, - "Enter passphrase for %s key '%.100s': ", - key_type(k), filename); + "Enter passphrase for key '%.100s': ", filename); for (i = 0; i < options.number_of_password_prompts; i++) { passphrase = read_passphrase(prompt, 0); if (strcmp(passphrase, "") != 0) { @@ -766,7 +766,7 @@ userauth_pubkey_identity(Authctxt *authctxt, char *filename) return 0; } } - ret = sign_and_send_pubkey(authctxt, k, dsa_sign_cb); + ret = sign_and_send_pubkey(authctxt, k, key_sign_cb); key_free(k); return ret; } @@ -782,24 +782,26 @@ int userauth_pubkey_agent(Authctxt *authctxt) { static int called = 0; + int ret = 0; char *comment; Key *k; - int ret; if (called == 0) { - k = ssh_get_first_identity(authctxt->agent, &comment, 2); + if (ssh_get_num_identities(authctxt->agent, 2) == 0) + debug2("userauth_pubkey_agent: no keys at all"); called = 1; - } else { - k = ssh_get_next_identity(authctxt->agent, &comment, 2); } + k = ssh_get_next_identity(authctxt->agent, &comment, 2); if (k == NULL) { - debug2("no more DSA keys from agent"); - return 0; + debug2("userauth_pubkey_agent: no more keys"); + } else { + debug("userauth_pubkey_agent: trying agent key %s", comment); + xfree(comment); + ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb); + key_free(k); } - debug("trying DSA agent key %s", comment); - xfree(comment); - ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb); - key_free(k); + if (ret == 0) + debug2("userauth_pubkey_agent: no message sent"); return ret; } @@ -809,10 +811,17 @@ userauth_pubkey(Authctxt *authctxt) static int idx = 0; int sent = 0; - if (authctxt->agent != NULL) - sent = userauth_pubkey_agent(authctxt); - while (sent == 0 && idx < options.num_identity_files2) - sent = userauth_pubkey_identity(authctxt, options.identity_files2[idx++]); + if (authctxt->agent != NULL) { + do { + sent = userauth_pubkey_agent(authctxt); + } while(!sent && authctxt->agent->howmany > 0); + } + while (!sent && idx < options.num_identity_files) { + if (options.identity_files_type[idx] != KEY_RSA1) + sent = userauth_pubkey_identity(authctxt, + options.identity_files[idx]); + idx++; + } return sent; } diff --git a/sshd.8 b/sshd.8 index e53eebe8..82328201 100644 --- a/sshd.8 +++ b/sshd.8 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.70 2000/10/16 09:38:44 djm Exp $ +.\" $OpenBSD: sshd.8,v 1.72 2000/11/12 19:50:38 markus Exp $ .Dd September 25, 1999 .Dt SSHD 8 .Os @@ -144,7 +144,7 @@ through a cryptographic message authentication code (hmac-sha1 or hmac-md5). .Pp Protocol version 2 provides a public key based -user authentication method (DSAAuthentication) +user authentication method (PubkeyAuthentication) and conventional password authentication. .Pp .Ss Command execution and data forwarding @@ -359,8 +359,8 @@ and can be used as wildcards in the patterns. Only user names are valid; a numerical user ID isn't recognized. By default login is allowed regardless of the user name. -.It Cm DSAAuthentication -Specifies whether DSA authentication is allowed. +.It Cm PubkeyAuthentication +Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. @@ -373,20 +373,20 @@ or .Dq no . The default is .Dq no . -.It Cm HostDSAKey -Specifies the file containing the private DSA host key (default -.Pa /etc/ssh_host_dsa_key ) -used by SSH protocol 2.0. -Note that -.Nm -disables protocol 2.0 if this file is group/world-accessible. .It Cm HostKey -Specifies the file containing the private RSA host key (default +Specifies the file containing the private host keys (default .Pa /etc/ssh_host_key ) -used by SSH protocols 1.3 and 1.5. +used by SSH protocol versions 1 and 2. Note that .Nm -disables protocols 1.3 and 1.5 if this file is group/world-accessible. +if this file is group/world-accessible. +It is possible to have multiple host key files. +.Dq rsa1 +keys are used for version 1 and +.Dq dsa +or +.Dq rsa +are used for version 2 of the SSH protocol. .It Cm IgnoreRhosts Specifies that .Pa .rhosts @@ -1039,7 +1039,7 @@ This can be used to specify machine-specific login-time initializations globally. This file should be writable only by root, and should be world-readable. .El -.Sh AUTHOR +.Sh AUTHORS OpenSSH is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen, but with bugs removed and newer features re-added. diff --git a/sshd.c b/sshd.c index e5c2508a..56a39bd0 100644 --- a/sshd.c +++ b/sshd.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.132 2000/10/13 18:34:46 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.134 2000/11/12 19:50:38 markus Exp $"); #include "xmalloc.h" #include "rsa.h" @@ -61,7 +61,6 @@ RCSID("$OpenBSD: sshd.c,v 1.132 2000/10/13 18:34:46 markus Exp $"); #include #include #include "key.h" -#include "dsa.h" #include "dh.h" #include "auth.h" @@ -140,9 +139,11 @@ char *server_version_string = NULL; * not very useful. Currently, memory locking is not implemented. */ struct { - 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. */ + Key *server_key; /* empheral server key */ + Key *ssh1_host_key; /* ssh1 host key */ + Key **host_keys; /* all private host keys */ + int have_ssh1_key; + int have_ssh2_key; } sensitive_data; /* @@ -154,10 +155,6 @@ int key_used = 0; /* This is set to true when SIGHUP is received. */ int received_sighup = 0; -/* Public side of the server key. This value is regenerated regularly with - the private key. */ -RSA *public_key; - /* session identifier, used by RSA-auth */ unsigned char session_id[16]; @@ -266,6 +263,17 @@ grace_alarm_handler(int sig) */ /* XXX do we really want this work to be done in a signal handler ? -m */ void +generate_empheral_server_key(void) +{ + log("Generating %s%d bit RSA key.", sensitive_data.server_key ? "new " : "", + options.server_key_bits); + if (sensitive_data.server_key != NULL) + key_free(sensitive_data.server_key); + sensitive_data.server_key = key_generate(KEY_RSA1, options.server_key_bits); + arc4random_stir(); + log("RSA key generation complete."); +} +void key_regeneration_alarm(int sig) { int save_errno = errno; @@ -273,21 +281,8 @@ key_regeneration_alarm(int sig) /* Check if we should generate a new key. */ if (key_used) { /* This should really be done in the background. */ - log("Generating new %d bit RSA key.", options.server_key_bits); - - if (sensitive_data.private_key != NULL) - RSA_free(sensitive_data.private_key); - sensitive_data.private_key = RSA_new(); - - if (public_key != NULL) - RSA_free(public_key); - public_key = RSA_new(); - - rsa_generate_key(sensitive_data.private_key, public_key, - options.server_key_bits); - arc4random_stir(); + generate_empheral_server_key(); key_used = 0; - log("RSA key generation complete."); } /* Reschedule the alarm. */ signal(SIGALRM, key_regeneration_alarm); @@ -422,18 +417,93 @@ sshd_exchange_identification(int sock_in, int sock_out) } +/* Destroy the host and server keys. They will no longer be needed. */ void destroy_sensitive_data(void) { - /* Destroy the private and public keys. They will no longer be needed. */ - if (public_key) - RSA_free(public_key); - if (sensitive_data.private_key) - RSA_free(sensitive_data.private_key); - if (sensitive_data.host_key) - RSA_free(sensitive_data.host_key); - if (sensitive_data.dsa_host_key != NULL) - key_free(sensitive_data.dsa_host_key); + int i; + + if (sensitive_data.server_key) { + key_free(sensitive_data.server_key); + sensitive_data.server_key = NULL; + } + for(i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = NULL; + } + } + sensitive_data.ssh1_host_key = NULL; +} +Key * +load_private_key_autodetect(const char *filename) +{ + struct stat st; + int type; + Key *public, *private; + + if (stat(filename, &st) < 0) { + perror(filename); + return NULL; + } + /* + * try to load the public key. right now this only works for RSA1, + * since SSH2 keys are fully encrypted + */ + type = KEY_RSA1; + public = key_new(type); + if (!load_public_key(filename, public, NULL)) { + /* ok, so we will assume this is 'some' key */ + type = KEY_UNSPEC; + } + key_free(public); + + /* Ok, try key with empty passphrase */ + private = key_new(type); + if (load_private_key(filename, "", private, NULL)) { + debug("load_private_key_autodetect: type %d %s", + private->type, key_type(private)); + return private; + } + key_free(private); + return NULL; +} + +char * +list_hostkey_types(void) +{ + static char buf[1024]; + int i; + buf[0] = '\0'; + for(i = 0; i < options.num_host_key_files; i++) { + Key *key = sensitive_data.host_keys[i]; + if (key == NULL) + continue; + switch(key->type) { + case KEY_RSA: + case KEY_DSA: + strlcat(buf, key_ssh_name(key), sizeof buf); + strlcat(buf, ",", sizeof buf); + break; + } + } + i = strlen(buf); + if (i > 0 && buf[i-1] == ',') + buf[i-1] = '\0'; + debug("list_hostkey_types: %s", buf); + return buf; +} + +Key * +get_hostkey_by_type(int type) +{ + int i; + for(i = 0; i < options.num_host_key_files; i++) { + Key *key = sensitive_data.host_keys[i]; + if (key != NULL && key->type == type) + return key; + } + return NULL; } /* @@ -555,7 +625,11 @@ main(int ac, char **av) options.key_regeneration_time = atoi(optarg); break; case 'h': - options.host_key_file = optarg; + if (options.num_host_key_files >= MAX_HOSTKEYS) { + fprintf(stderr, "too many host keys.\n"); + exit(1); + } + options.host_key_files[options.num_host_key_files++] = optarg; break; case 'V': client_version_string = optarg; @@ -610,39 +684,39 @@ main(int ac, char **av) debug("sshd version %.100s", SSH_VERSION); - sensitive_data.dsa_host_key = NULL; - sensitive_data.host_key = NULL; + /* load private host keys */ + sensitive_data.host_keys = xmalloc(options.num_host_key_files*sizeof(Key*)); + sensitive_data.server_key = NULL; + sensitive_data.ssh1_host_key = NULL; + sensitive_data.have_ssh1_key = 0; + sensitive_data.have_ssh2_key = 0; - /* check if RSA support exists */ - if ((options.protocol & SSH_PROTO_1) && - rsa_alive() == 0) { - 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, NULL)) { + for(i = 0; i < options.num_host_key_files; i++) { + Key *key = load_private_key_autodetect(options.host_key_files[i]); + if (key == NULL) { error("Could not load host key: %.200s: %.100s", - options.host_key_file, strerror(errno)); - log("Disabling protocol version 1"); - options.protocol &= ~SSH_PROTO_1; + options.host_key_files[i], strerror(errno)); + continue; } - k.rsa = NULL; - } - if (options.protocol & SSH_PROTO_2) { - sensitive_data.dsa_host_key = key_new(KEY_DSA); - if (!load_private_key(options.host_dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) { - - error("Could not load DSA host key: %.200s", options.host_dsa_key_file); - log("Disabling protocol version 2"); - options.protocol &= ~SSH_PROTO_2; + switch(key->type){ + case KEY_RSA1: + sensitive_data.ssh1_host_key = key; + sensitive_data.have_ssh1_key = 1; + break; + case KEY_RSA: + case KEY_DSA: + sensitive_data.have_ssh2_key = 1; + break; } + sensitive_data.host_keys[i] = key; + } + if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { + log("Disabling protocol version 1. Could not load host key"); + options.protocol &= ~SSH_PROTO_1; + } + if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { + log("Disabling protocol version 2. Could not load host key"); + options.protocol &= ~SSH_PROTO_2; } if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) { if (silent == 0) @@ -664,11 +738,11 @@ main(int ac, char **av) * 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 && + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - SSH_KEY_BITS_RESERVED && options.server_key_bits < - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { options.server_key_bits = - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED; + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED; debug("Forcing server key to %d bits to make it differ from host key.", options.server_key_bits); } @@ -707,9 +781,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); - /* Do not display messages to stdout in RSA code. */ - rsa_set_verbose(0); - /* Initialize the random number generator. */ arc4random_stir(); @@ -731,16 +802,8 @@ main(int ac, char **av) * ttyfd happens to be one of those. */ debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); - - 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."); - } + if (options.protocol & SSH_PROTO_1) + generate_empheral_server_key(); } else { for (ai = options.listen_addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) @@ -818,14 +881,7 @@ main(int ac, char **av) } } 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."); + generate_empheral_server_key(); /* Schedule server key regeneration alarm. */ signal(SIGALRM, key_regeneration_alarm); @@ -1065,6 +1121,8 @@ main(int ac, char **av) */ if (remote_port >= IPPORT_RESERVED || remote_port < IPPORT_RESERVED / 2) { + debug("Rhosts Authentication methods disabled, " + "originating port not trusted."); options.rhosts_authentication = 0; options.rhosts_rsa_authentication = 0; } @@ -1145,14 +1203,14 @@ do_ssh1_kex() packet_put_char(cookie[i]); /* Store our public server RSA key. */ - packet_put_int(BN_num_bits(public_key->n)); - packet_put_bignum(public_key->e); - packet_put_bignum(public_key->n); + packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n)); + packet_put_bignum(sensitive_data.server_key->rsa->e); + packet_put_bignum(sensitive_data.server_key->rsa->n); /* Store our public host RSA key. */ - packet_put_int(BN_num_bits(sensitive_data.host_key->n)); - packet_put_bignum(sensitive_data.host_key->e); - packet_put_bignum(sensitive_data.host_key->n); + packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); + packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e); + packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n); /* Put protocol flags. */ packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); @@ -1190,8 +1248,9 @@ do_ssh1_kex() packet_send(); packet_write_wait(); - debug("Sent %d bit public key and %d bit host key.", - BN_num_bits(public_key->n), BN_num_bits(sensitive_data.host_key->n)); + debug("Sent %d bit server key and %d bit host key.", + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); /* Read clients reply (cipher type and session key). */ packet_read_expect(&plen, SSH_CMSG_SESSION_KEY); @@ -1223,39 +1282,39 @@ do_ssh1_kex() * Decrypt it using our private server key and private host key (key * with larger modulus first). */ - if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) { + if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { /* Private key has bigger modulus. */ - if (BN_num_bits(sensitive_data.private_key->n) < - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), - BN_num_bits(sensitive_data.private_key->n), - BN_num_bits(sensitive_data.host_key->n), - SSH_KEY_BITS_RESERVED); + if (BN_num_bits(sensitive_data.server_key->rsa->n) < + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + SSH_KEY_BITS_RESERVED); } rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.private_key); + sensitive_data.server_key->rsa); rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.host_key); + sensitive_data.ssh1_host_key->rsa); } else { /* Host key has bigger modulus (or they are equal). */ - if (BN_num_bits(sensitive_data.host_key->n) < - BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), - BN_num_bits(sensitive_data.host_key->n), - BN_num_bits(sensitive_data.private_key->n), - SSH_KEY_BITS_RESERVED); + if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < + BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + BN_num_bits(sensitive_data.server_key->rsa->n), + SSH_KEY_BITS_RESERVED); } rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.host_key); + sensitive_data.ssh1_host_key->rsa); rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.private_key); + sensitive_data.server_key->rsa); } compute_session_id(session_id, cookie, - sensitive_data.host_key->n, - sensitive_data.private_key->n); + sensitive_data.ssh1_host_key->rsa->n, + sensitive_data.server_key->rsa->n); /* Destroy the private and public keys. They will no longer be needed. */ destroy_sensitive_data(); @@ -1269,8 +1328,8 @@ do_ssh1_kex() len = BN_num_bytes(session_key_int); if (len < 0 || len > sizeof(session_key)) fatal("do_connection: bad len from %s: session_key_int %d > sizeof(session_key) %d", - get_remote_ipaddr(), - len, (int) sizeof(session_key)); + get_remote_ipaddr(), + len, sizeof(session_key)); memset(session_key, 0, sizeof(session_key)); BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len); @@ -1314,6 +1373,8 @@ do_ssh2_kex() myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); + server_kexinit = kex_init(myproposal); client_kexinit = xmalloc(sizeof(*client_kexinit)); buffer_init(client_kexinit); @@ -1379,6 +1440,11 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) BIGNUM *shared_secret = 0; DH *dh; BIGNUM *dh_client_pub = 0; + Key *hostkey; + + hostkey = get_hostkey_by_type(kex->hostkey_type); + if (hostkey == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); /* KEXDH */ debug("Wait SSH2_MSG_KEXDH_INIT."); @@ -1431,8 +1497,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) xfree(kbuf); /* XXX precompute? */ - dsa_make_key_blob(sensitive_data.dsa_host_key, - &server_host_key_blob, &sbloblen); + key_to_blob(hostkey, &server_host_key_blob, &sbloblen); /* calc H */ /* XXX depends on 'kex' */ hash = kex_hash( @@ -1463,7 +1528,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) /* sign H */ /* XXX hashlen depends on KEX */ - dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20); + key_sign(hostkey, &signature, &slen, hash, 20); destroy_sensitive_data(); @@ -1503,6 +1568,11 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) BIGNUM *shared_secret = 0; DH *dh; BIGNUM *dh_client_pub = 0; + Key *hostkey; + + hostkey = get_hostkey_by_type(kex->hostkey_type); + if (hostkey == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); /* KEXDHGEX */ debug("Wait SSH2_MSG_KEX_DH_GEX_REQUEST."); @@ -1564,8 +1634,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) xfree(kbuf); /* XXX precompute? */ - dsa_make_key_blob(sensitive_data.dsa_host_key, - &server_host_key_blob, &sbloblen); + key_to_blob(hostkey, &server_host_key_blob, &sbloblen); /* calc H */ /* XXX depends on 'kex' */ hash = kex_hash_gex( @@ -1597,7 +1666,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) /* sign H */ /* XXX hashlen depends on KEX */ - dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20); + key_sign(hostkey, &signature, &slen, hash, 20); destroy_sensitive_data(); @@ -1617,4 +1686,3 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) /* have keys, free DH */ DH_free(dh); } - diff --git a/sshd_config b/sshd_config index 3b88062f..f368b97a 100644 --- a/sshd_config +++ b/sshd_config @@ -5,6 +5,8 @@ Port 22 ListenAddress 0.0.0.0 #ListenAddress :: HostKey /etc/ssh_host_key +HostKey /etc/ssh_host_rsa_key +HostKey /etc/ssh_host_dsa_key ServerKeyBits 768 LoginGraceTime 600 KeyRegenerationInterval 3600 -- 2.45.1