diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2000-04-06 08:55:23 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2000-04-06 08:55:23 +0000 |
commit | ba6fecc544a89dfac29a8954067ccf27c8132874 (patch) | |
tree | ee38218d1be673638e554409ddab61613f16efa8 /usr.bin/ssh/sshd.c | |
parent | 8aad4726dfbb92d8746782ea75c5d45dd6c396d3 (diff) |
ssh2 server side, see README.openssh2; enable with 'sshd -2'
Diffstat (limited to 'usr.bin/ssh/sshd.c')
-rw-r--r-- | usr.bin/ssh/sshd.c | 235 |
1 files changed, 229 insertions, 6 deletions
diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index e6a7327cfaf..40d2aa6d4ac 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -8,10 +8,13 @@ * information to/from the application to the user client over an encrypted * connection. This can also handle forwarding of X11, TCP/IP, and authentication * agent connections. + * + * SSH2 implementation, + * Copyright (c) 2000 Markus Friedl. All rights reserved. */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.98 2000/04/06 08:55:22 markus Exp $"); #include "xmalloc.h" #include "rsa.h" @@ -25,14 +28,18 @@ RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $"); #include "compat.h" #include "buffer.h" +#include "ssh2.h" #include <ssl/dh.h> #include <ssl/bn.h> #include <ssl/hmac.h> +#include "kex.h" #include <ssl/dsa.h> #include <ssl/rsa.h> #include "key.h" +#include "dsa.h" #include "auth.h" +#include "myproposal.h" #ifdef LIBWRAP #include <tcpd.h> @@ -57,6 +64,9 @@ char *config_file_name = SERVER_CONFIG_FILE; */ int IPv4or6 = AF_UNSPEC; +/* Flag indicating whether SSH2 is enabled */ +int allow_ssh2 = 0; + /* * Debug mode flag. This can be set on the command line. If debug * mode is enabled, extra debugging output will be sent to the system @@ -123,6 +133,7 @@ unsigned char session_id[16]; /* Prototypes for various functions defined later in this file. */ void do_ssh1_kex(); +void do_ssh2_kex(); /* * Close all listening sockets @@ -242,6 +253,21 @@ key_regeneration_alarm(int sig) errno = save_errno; } +char * +chop(char *s) +{ + char *t = s; + while (*t) { + if(*t == '\n' || *t == '\r') { + *t = '\0'; + return s; + } + t++; + } + return s; + +} + void sshd_exchange_identification(int sock_in, int sock_out) { @@ -252,7 +278,9 @@ sshd_exchange_identification(int sock_in, int sock_out) char remote_version[256]; /* Must be at least as big as buf. */ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", - PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); + allow_ssh2 ? 1 : PROTOCOL_MAJOR, + allow_ssh2 ? 99 : PROTOCOL_MINOR, + SSH_VERSION); server_version_string = xstrdup(buf); if (client_version_string == NULL) { @@ -273,7 +301,7 @@ sshd_exchange_identification(int sock_in, int sock_out) buf[i] = '\n'; buf[i + 1] = 0; continue; - /*break; XXX eat \r */ + //break; } if (buf[i] == '\n') { /* buf[i] == '\n' */ @@ -302,6 +330,8 @@ sshd_exchange_identification(int sock_in, int sock_out) debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); + compat_datafellows(remote_version); + switch(remote_major) { case 1: if (remote_minor < 3) { @@ -312,6 +342,11 @@ sshd_exchange_identification(int sock_in, int sock_out) enable_compat13(); } break; + case 2: + if (allow_ssh2) { + enable_compat20(); + break; + } default: s = "Protocol major versions differ.\n"; (void) atomicio(write, sock_out, s, strlen(s)); @@ -322,6 +357,8 @@ sshd_exchange_identification(int sock_in, int sock_out) fatal_cleanup(); break; } + chop(server_version_string); + chop(client_version_string); } /* @@ -357,8 +394,11 @@ main(int ac, char **av) initialize_server_options(&options); /* Parse command-line arguments. */ - while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) { + while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ246")) != EOF) { switch (opt) { + case '2': + allow_ssh2 = 1; + break; case '4': IPv4or6 = AF_INET; break; @@ -823,9 +863,14 @@ main(int ac, char **av) packet_set_nonblocking(); /* perform the key exchange */ - do_ssh1_kex(); /* authenticate user and start session */ - do_authentication(); + if (compat20) { + do_ssh2_kex(); + do_authentication2(); + } else { + do_ssh1_kex(); + do_authentication(); + } #ifdef KRB4 /* Cleanup user's ticket cache file. */ @@ -1030,3 +1075,181 @@ do_ssh1_kex() packet_send(); packet_write_wait(); } + +/* + * SSH2 key exchange: diffie-hellman-group1-sha1 + */ +void +do_ssh2_kex() +{ + Buffer *server_kexinit; + Buffer *client_kexinit; + int payload_len, dlen; + int slen; + unsigned int klen, kout; + char *ptr; + unsigned char *signature = NULL; + unsigned char *server_host_key_blob = NULL; + unsigned int sbloblen; + DH *dh; + BIGNUM *dh_client_pub = 0; + BIGNUM *shared_secret = 0; + int i; + unsigned char *kbuf; + unsigned char *hash; + Kex *kex; + Key *server_host_key; + char *cprop[PROPOSAL_MAX]; + char *sprop[PROPOSAL_MAX]; + +/* KEXINIT */ + + debug("Sending KEX init."); + + for (i = 0; i < PROPOSAL_MAX; i++) + sprop[i] = xstrdup(myproposal[i]); + server_kexinit = kex_init(sprop); + packet_start(SSH2_MSG_KEXINIT); + packet_put_raw(buffer_ptr(server_kexinit), buffer_len(server_kexinit)); + packet_send(); + packet_write_wait(); + + debug("done"); + + packet_read_expect(&payload_len, SSH2_MSG_KEXINIT); + + /* + * save raw KEXINIT payload in buffer. this is used during + * computation of the session_id and the session keys. + */ + client_kexinit = xmalloc(sizeof(*client_kexinit)); + buffer_init(client_kexinit); + ptr = packet_get_raw(&payload_len); + buffer_append(client_kexinit, ptr, payload_len); + + /* skip cookie */ + for (i = 0; i < 16; i++) + (void) packet_get_char(); + /* save kex init proposal strings */ + for (i = 0; i < PROPOSAL_MAX; i++) { + cprop[i] = packet_get_string(NULL); + debug("got kexinit string: %s", cprop[i]); + } + + i = (int) packet_get_char(); + debug("first kex follow == %d", i); + i = packet_get_int(); + debug("reserved == %d", i); + + debug("done read kexinit"); + kex = kex_choose_conf(cprop, sprop, 1); + +/* KEXDH */ + + debug("Wait SSH2_MSG_KEXDH_INIT."); + packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT); + + /* key, cert */ + dh_client_pub = BN_new(); + if (dh_client_pub == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub, &dlen); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "\ndh_client_pub= "); + bignum_print(dh_client_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_client_pub)); +#endif + + /* generate DH key */ + dh = new_dh_group1(); /* XXX depends on 'kex' */ + +#ifdef DEBUG_KEXDH + fprintf(stderr, "\np= "); + bignum_print(dh->p); + fprintf(stderr, "\ng= "); + bignum_print(dh->g); + fprintf(stderr, "\npub= "); + bignum_print(dh->pub_key); + fprintf(stderr, "\n"); +#endif + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); + +#ifdef DEBUG_KEXDH + debug("shared secret: len %d/%d", klen, kout); + fprintf(stderr, "shared secret == "); + for (i = 0; i< kout; i++) + fprintf(stderr, "%02x", (kbuf[i])&0xff); + fprintf(stderr, "\n"); +#endif + shared_secret = BN_new(); + + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + server_host_key = dsa_get_serverkey(options.dsa_key_file); + dsa_make_serverkey_blob(server_host_key, &server_host_key_blob, &sbloblen); + + /* calc H */ /* XXX depends on 'kex' */ + hash = kex_hash( + client_version_string, + server_version_string, + buffer_ptr(client_kexinit), buffer_len(client_kexinit), + buffer_ptr(server_kexinit), buffer_len(server_kexinit), + (char *)server_host_key_blob, sbloblen, + dh_client_pub, + dh->pub_key, + shared_secret + ); + buffer_free(client_kexinit); + buffer_free(server_kexinit); + xfree(client_kexinit); + xfree(server_kexinit); +#ifdef DEBUG_KEXDH + fprintf(stderr, "hash == "); + for (i = 0; i< 20; i++) + fprintf(stderr, "%02x", (hash[i])&0xff); + fprintf(stderr, "\n"); +#endif + /* sign H */ + dsa_sign(server_host_key, &signature, &slen, hash, 20); + /* hashlen depends on KEX */ + key_free(server_host_key); + + /* send server hostkey, DH pubkey 'f' and singed H */ + packet_start(SSH2_MSG_KEXDH_REPLY); + packet_put_string((char *)server_host_key_blob, sbloblen); + packet_put_bignum2(dh->pub_key); // f + packet_put_string((char *)signature, slen); + packet_send(); + packet_write_wait(); + + kex_derive_keys(kex, hash, shared_secret); + packet_set_kex(kex); + + /* have keys, free DH */ + DH_free(dh); + + debug("send SSH2_MSG_NEWKEYS."); + packet_start(SSH2_MSG_NEWKEYS); + packet_send(); + packet_write_wait(); + debug("done: send SSH2_MSG_NEWKEYS."); + + debug("Wait SSH2_MSG_NEWKEYS."); + packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); + debug("GOT SSH2_MSG_NEWKEYS."); + + /* send 1st encrypted/maced/compressed message */ + packet_start(SSH2_MSG_IGNORE); + packet_put_cstring("markus"); + packet_send(); + packet_write_wait(); + + debug("done: KEX2."); +} |