From 98a58edad29e2c355de1a79d40801036a6bde5e8 Mon Sep 17 00:00:00 2001 From: djm Date: Mon, 24 Feb 2003 01:03:03 +0000 Subject: [PATCH] - markus@cvs.openbsd.org 2003/02/16 17:09:57 [kex.c kexdh.c kexgex.c kex.h sshconnect2.c sshd.c ssh-keyscan.c] split kex into client and server code, no need to link server code into the client; ok provos@ --- ChangeLog | 4 + kex.c | 23 ++-- kex.h | 23 +++- kexdh.c | 234 +---------------------------------- kexdhc.c | 137 +++++++++++++++++++++ kexdhs.c | 138 +++++++++++++++++++++ kexgex.c | 328 +------------------------------------------------- kexgexc.c | 189 +++++++++++++++++++++++++++++ kexgexs.c | 186 ++++++++++++++++++++++++++++ ssh-keyscan.c | 4 +- sshconnect2.c | 4 +- sshd.c | 8 +- 12 files changed, 696 insertions(+), 582 deletions(-) create mode 100644 kexdhc.c create mode 100644 kexdhs.c create mode 100644 kexgexc.c create mode 100644 kexgexs.c diff --git a/ChangeLog b/ChangeLog index 1507ad96..d8374253 100644 --- a/ChangeLog +++ b/ChangeLog @@ -63,6 +63,10 @@ - markus@cvs.openbsd.org 2003/02/12 21:39:50 [crc32.c crc32.h] replace crc32.c with a BSD licensed version; noted by David Turner + - markus@cvs.openbsd.org 2003/02/16 17:09:57 + [kex.c kexdh.c kexgex.c kex.h sshconnect2.c sshd.c ssh-keyscan.c] + split kex into client and server code, no need to link + server code into the client; ok provos@ 20030211 - (djm) Cygwin needs libcrypt too. Patch from vinschen@redhat.com diff --git a/kex.c b/kex.c index 0a861fb9..2c1cacfe 100644 --- a/kex.c +++ b/kex.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.53 2003/02/02 10:56:08 markus Exp $"); +RCSID("$OpenBSD: kex.c,v 1.54 2003/02/16 17:09:57 markus Exp $"); #include @@ -44,11 +44,6 @@ RCSID("$OpenBSD: kex.c,v 1.53 2003/02/02 10:56:08 markus Exp $"); #define KEX_COOKIE_LEN 16 -/* Use privilege separation for sshd */ -int use_privsep; -struct monitor *pmonitor; - - /* prototype */ static void kex_kexinit_finish(Kex *); static void kex_choose_conf(Kex *); @@ -237,14 +232,10 @@ kex_kexinit_finish(Kex *kex) kex_choose_conf(kex); - switch (kex->kex_type) { - case DH_GRP1_SHA1: - kexdh(kex); - break; - case DH_GEX_SHA1: - kexgex(kex); - break; - default: + if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && + kex->kex[kex->kex_type] != NULL) { + (kex->kex[kex->kex_type])(kex); + } else { fatal("Unsupported key exchange %d", kex->kex_type); } } @@ -301,9 +292,9 @@ choose_kex(Kex *k, char *client, char *server) if (k->name == NULL) fatal("no kex alg"); if (strcmp(k->name, KEX_DH1) == 0) { - k->kex_type = DH_GRP1_SHA1; + k->kex_type = KEX_DH_GRP1_SHA1; } else if (strcmp(k->name, KEX_DHGEX) == 0) { - k->kex_type = DH_GEX_SHA1; + k->kex_type = KEX_DH_GEX_SHA1; } else fatal("bad kex alg %s", k->name); } diff --git a/kex.h b/kex.h index 93a529e1..52d442e9 100644 --- a/kex.h +++ b/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.32 2002/09/09 14:54:14 markus Exp $ */ +/* $OpenBSD: kex.h,v 1.33 2003/02/16 17:09:57 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -55,8 +55,9 @@ enum kex_modes { }; enum kex_exchange { - DH_GRP1_SHA1, - DH_GEX_SHA1 + KEX_DH_GRP1_SHA1, + KEX_DH_GEX_SHA1, + KEX_MAX }; #define KEX_INIT_SENT 0x0001 @@ -112,6 +113,7 @@ struct Kex { int (*verify_host_key)(Key *); Key *(*load_host_key)(int); int (*host_key_index)(Key *); + void (*kex[KEX_MAX])(Kex *); }; Kex *kex_setup(char *[PROPOSAL_MAX]); @@ -121,11 +123,20 @@ void kex_send_kexinit(Kex *); void kex_input_kexinit(int, u_int32_t, void *); void kex_derive_keys(Kex *, u_char *, BIGNUM *); -void kexdh(Kex *); -void kexgex(Kex *); - Newkeys *kex_get_newkeys(int); +void kexdh_client(Kex *); +void kexdh_server(Kex *); +void kexgex_client(Kex *); +void kexgex_server(Kex *); + +u_char * +kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, + BIGNUM *, BIGNUM *, BIGNUM *); +u_char * +kexgex_hash(char *, char *, char *, int, char *, int, u_char *, int, + int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *); + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) void dump_digest(char *, u_char *, int); #endif diff --git a/kexdh.c b/kexdh.c index 1e91e255..4bbb7d1d 100644 --- a/kexdh.c +++ b/kexdh.c @@ -23,23 +23,16 @@ */ #include "includes.h" -RCSID("$OpenBSD: kexdh.c,v 1.18 2002/03/18 17:50:31 provos Exp $"); +RCSID("$OpenBSD: kexdh.c,v 1.19 2003/02/16 17:09:57 markus Exp $"); -#include -#include +#include -#include "xmalloc.h" #include "buffer.h" #include "bufaux.h" -#include "key.h" -#include "kex.h" -#include "log.h" -#include "packet.h" -#include "dh.h" #include "ssh2.h" -#include "monitor_wrap.h" +#include "kex.h" -static u_char * +u_char * kex_dh_hash( char *client_version_string, char *server_version_string, @@ -86,222 +79,3 @@ kex_dh_hash( #endif return digest; } - -/* client */ - -static void -kexdh_client(Kex *kex) -{ - BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; - DH *dh; - Key *server_host_key; - u_char *server_host_key_blob = NULL, *signature = NULL; - u_char *kbuf, *hash; - u_int klen, kout, slen, sbloblen; - - /* generate and send 'e', client DH public key */ - dh = dh_new_group1(); - dh_gen_key(dh, kex->we_need * 8); - packet_start(SSH2_MSG_KEXDH_INIT); - packet_put_bignum2(dh->pub_key); - packet_send(); - - debug("sending SSH2_MSG_KEXDH_INIT"); -#ifdef DEBUG_KEXDH - DHparams_print_fp(stderr, dh); - fprintf(stderr, "pub= "); - BN_print_fp(stderr, dh->pub_key); - fprintf(stderr, "\n"); -#endif - - debug("expecting SSH2_MSG_KEXDH_REPLY"); - packet_read_expect(SSH2_MSG_KEXDH_REPLY); - - /* key, cert */ - server_host_key_blob = packet_get_string(&sbloblen); - server_host_key = key_from_blob(server_host_key_blob, sbloblen); - if (server_host_key == NULL) - fatal("cannot decode server_host_key_blob"); - if (server_host_key->type != kex->hostkey_type) - fatal("type mismatch for decoded server_host_key_blob"); - if (kex->verify_host_key == NULL) - fatal("cannot verify server_host_key"); - if (kex->verify_host_key(server_host_key) == -1) - fatal("server_host_key verification failed"); - - /* DH paramter f, server public DH key */ - if ((dh_server_pub = BN_new()) == NULL) - fatal("dh_server_pub == NULL"); - packet_get_bignum2(dh_server_pub); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "dh_server_pub= "); - BN_print_fp(stderr, dh_server_pub); - fprintf(stderr, "\n"); - debug("bits %d", BN_num_bits(dh_server_pub)); -#endif - - /* signed H */ - signature = packet_get_string(&slen); - packet_check_eom(); - - if (!dh_pub_is_valid(dh, dh_server_pub)) - packet_disconnect("bad server public DH value"); - - klen = DH_size(dh); - kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_server_pub, dh); -#ifdef DEBUG_KEXDH - dump_digest("shared secret", kbuf, kout); -#endif - if ((shared_secret = BN_new()) == NULL) - fatal("kexdh_client: BN_new failed"); - BN_bin2bn(kbuf, kout, shared_secret); - memset(kbuf, 0, klen); - xfree(kbuf); - - /* calc and verify H */ - hash = kex_dh_hash( - kex->client_version_string, - kex->server_version_string, - buffer_ptr(&kex->my), buffer_len(&kex->my), - buffer_ptr(&kex->peer), buffer_len(&kex->peer), - server_host_key_blob, sbloblen, - dh->pub_key, - dh_server_pub, - shared_secret - ); - xfree(server_host_key_blob); - BN_clear_free(dh_server_pub); - DH_free(dh); - - if (key_verify(server_host_key, signature, slen, hash, 20) != 1) - fatal("key_verify failed for server_host_key"); - key_free(server_host_key); - xfree(signature); - - /* save session id */ - if (kex->session_id == NULL) { - kex->session_id_len = 20; - kex->session_id = xmalloc(kex->session_id_len); - memcpy(kex->session_id, hash, kex->session_id_len); - } - - kex_derive_keys(kex, hash, shared_secret); - BN_clear_free(shared_secret); - kex_finish(kex); -} - -/* server */ - -static void -kexdh_server(Kex *kex) -{ - BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; - DH *dh; - Key *server_host_key; - u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; - u_int sbloblen, klen, kout; - u_int slen; - - /* generate server DH public key */ - dh = dh_new_group1(); - dh_gen_key(dh, kex->we_need * 8); - - debug("expecting SSH2_MSG_KEXDH_INIT"); - packet_read_expect(SSH2_MSG_KEXDH_INIT); - - if (kex->load_host_key == NULL) - fatal("Cannot load hostkey"); - server_host_key = kex->load_host_key(kex->hostkey_type); - if (server_host_key == NULL) - fatal("Unsupported hostkey type %d", kex->hostkey_type); - - /* key, cert */ - if ((dh_client_pub = BN_new()) == NULL) - fatal("dh_client_pub == NULL"); - packet_get_bignum2(dh_client_pub); - packet_check_eom(); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "dh_client_pub= "); - BN_print_fp(stderr, dh_client_pub); - fprintf(stderr, "\n"); - debug("bits %d", BN_num_bits(dh_client_pub)); -#endif - -#ifdef DEBUG_KEXDH - DHparams_print_fp(stderr, dh); - fprintf(stderr, "pub= "); - BN_print_fp(stderr, dh->pub_key); - fprintf(stderr, "\n"); -#endif - if (!dh_pub_is_valid(dh, dh_client_pub)) - packet_disconnect("bad client public DH value"); - - klen = DH_size(dh); - kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_client_pub, dh); -#ifdef DEBUG_KEXDH - dump_digest("shared secret", kbuf, kout); -#endif - if ((shared_secret = BN_new()) == NULL) - fatal("kexdh_server: BN_new failed"); - BN_bin2bn(kbuf, kout, shared_secret); - memset(kbuf, 0, klen); - xfree(kbuf); - - key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); - - /* calc H */ - hash = kex_dh_hash( - kex->client_version_string, - kex->server_version_string, - buffer_ptr(&kex->peer), buffer_len(&kex->peer), - buffer_ptr(&kex->my), buffer_len(&kex->my), - server_host_key_blob, sbloblen, - dh_client_pub, - dh->pub_key, - shared_secret - ); - BN_clear_free(dh_client_pub); - - /* save session id := H */ - /* XXX hashlen depends on KEX */ - if (kex->session_id == NULL) { - kex->session_id_len = 20; - kex->session_id = xmalloc(kex->session_id_len); - memcpy(kex->session_id, hash, kex->session_id_len); - } - - /* sign H */ - /* XXX hashlen depends on KEX */ - PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20)); - - /* destroy_sensitive_data(); */ - - /* send server hostkey, DH pubkey 'f' and singed H */ - packet_start(SSH2_MSG_KEXDH_REPLY); - packet_put_string(server_host_key_blob, sbloblen); - packet_put_bignum2(dh->pub_key); /* f */ - packet_put_string(signature, slen); - packet_send(); - - xfree(signature); - xfree(server_host_key_blob); - /* have keys, free DH */ - DH_free(dh); - - kex_derive_keys(kex, hash, shared_secret); - BN_clear_free(shared_secret); - kex_finish(kex); -} - -void -kexdh(Kex *kex) -{ - if (kex->server) - kexdh_server(kex); - else - kexdh_client(kex); -} diff --git a/kexdhc.c b/kexdhc.c new file mode 100644 index 00000000..fe6dc53f --- /dev/null +++ b/kexdhc.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2001 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: kexdhc.c,v 1.1 2003/02/16 17:09:57 markus Exp $"); + +#include "xmalloc.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" + +void +kexdh_client(Kex *kex) +{ + BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; + DH *dh; + Key *server_host_key; + u_char *server_host_key_blob = NULL, *signature = NULL; + u_char *kbuf, *hash; + u_int klen, kout, slen, sbloblen; + + /* generate and send 'e', client DH public key */ + dh = dh_new_group1(); + dh_gen_key(dh, kex->we_need * 8); + packet_start(SSH2_MSG_KEXDH_INIT); + packet_put_bignum2(dh->pub_key); + packet_send(); + + debug("sending SSH2_MSG_KEXDH_INIT"); +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + + debug("expecting SSH2_MSG_KEXDH_REPLY"); + packet_read_expect(SSH2_MSG_KEXDH_REPLY); + + /* key, cert */ + server_host_key_blob = packet_get_string(&sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); + if (server_host_key == NULL) + fatal("cannot decode server_host_key_blob"); + if (server_host_key->type != kex->hostkey_type) + fatal("type mismatch for decoded server_host_key_blob"); + if (kex->verify_host_key == NULL) + fatal("cannot verify server_host_key"); + if (kex->verify_host_key(server_host_key) == -1) + fatal("server_host_key verification failed"); + + /* DH paramter f, server public DH key */ + if ((dh_server_pub = BN_new()) == NULL) + fatal("dh_server_pub == NULL"); + packet_get_bignum2(dh_server_pub); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_server_pub= "); + BN_print_fp(stderr, dh_server_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_server_pub)); +#endif + + /* signed H */ + signature = packet_get_string(&slen); + packet_check_eom(); + + if (!dh_pub_is_valid(dh, dh_server_pub)) + packet_disconnect("bad server public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + if ((shared_secret = BN_new()) == NULL) + fatal("kexdh_client: BN_new failed"); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + /* calc and verify H */ + hash = kex_dh_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->my), buffer_len(&kex->my), + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + server_host_key_blob, sbloblen, + dh->pub_key, + dh_server_pub, + shared_secret + ); + xfree(server_host_key_blob); + BN_clear_free(dh_server_pub); + DH_free(dh); + + if (key_verify(server_host_key, signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); + key_free(server_host_key); + xfree(signature); + + /* save session id */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); +} diff --git a/kexdhs.c b/kexdhs.c new file mode 100644 index 00000000..f04bce82 --- /dev/null +++ b/kexdhs.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2001 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: kexdhs.c,v 1.1 2003/02/16 17:09:57 markus Exp $"); + +#include "xmalloc.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" +#include "monitor_wrap.h" + +void +kexdh_server(Kex *kex) +{ + BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; + DH *dh; + Key *server_host_key; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int sbloblen, klen, kout; + u_int slen; + + /* generate server DH public key */ + dh = dh_new_group1(); + dh_gen_key(dh, kex->we_need * 8); + + debug("expecting SSH2_MSG_KEXDH_INIT"); + packet_read_expect(SSH2_MSG_KEXDH_INIT); + + if (kex->load_host_key == NULL) + fatal("Cannot load hostkey"); + server_host_key = kex->load_host_key(kex->hostkey_type); + if (server_host_key == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); + + /* key, cert */ + if ((dh_client_pub = BN_new()) == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub); + packet_check_eom(); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_client_pub= "); + BN_print_fp(stderr, dh_client_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_client_pub)); +#endif + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + if ((shared_secret = BN_new()) == NULL) + fatal("kexdh_server: BN_new failed"); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + + /* calc H */ + hash = kex_dh_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + server_host_key_blob, sbloblen, + dh_client_pub, + dh->pub_key, + shared_secret + ); + BN_clear_free(dh_client_pub); + + /* save session id := H */ + /* XXX hashlen depends on KEX */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + /* sign H */ + /* XXX hashlen depends on KEX */ + PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20)); + + /* destroy_sensitive_data(); */ + + /* send server hostkey, DH pubkey 'f' and singed H */ + packet_start(SSH2_MSG_KEXDH_REPLY); + packet_put_string(server_host_key_blob, sbloblen); + packet_put_bignum2(dh->pub_key); /* f */ + packet_put_string(signature, slen); + packet_send(); + + xfree(signature); + xfree(server_host_key_blob); + /* have keys, free DH */ + DH_free(dh); + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); +} diff --git a/kexgex.c b/kexgex.c index 2d4a5815..b0c39c8c 100644 --- a/kexgex.c +++ b/kexgex.c @@ -24,23 +24,16 @@ */ #include "includes.h" -RCSID("$OpenBSD: kexgex.c,v 1.22 2002/03/24 17:27:03 stevesk Exp $"); +RCSID("$OpenBSD: kexgex.c,v 1.23 2003/02/16 17:09:57 markus Exp $"); -#include +#include -#include "xmalloc.h" #include "buffer.h" #include "bufaux.h" -#include "key.h" #include "kex.h" -#include "log.h" -#include "packet.h" -#include "dh.h" #include "ssh2.h" -#include "compat.h" -#include "monitor_wrap.h" -static u_char * +u_char * kexgex_hash( char *client_version_string, char *server_version_string, @@ -97,318 +90,3 @@ kexgex_hash( #endif return digest; } - -/* client */ - -static void -kexgex_client(Kex *kex) -{ - BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; - BIGNUM *p = NULL, *g = NULL; - Key *server_host_key; - u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; - u_int klen, kout, slen, sbloblen; - int min, max, nbits; - DH *dh; - - nbits = dh_estimate(kex->we_need * 8); - - if (datafellows & SSH_OLD_DHGEX) { - debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent"); - - /* Old GEX request */ - packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); - packet_put_int(nbits); - min = DH_GRP_MIN; - max = DH_GRP_MAX; - } else { - debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent"); - - /* New GEX request */ - min = DH_GRP_MIN; - max = DH_GRP_MAX; - packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); - packet_put_int(min); - packet_put_int(nbits); - packet_put_int(max); - } -#ifdef DEBUG_KEXDH - fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", - min, nbits, max); -#endif - packet_send(); - - debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); - packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP); - - if ((p = BN_new()) == NULL) - fatal("BN_new"); - packet_get_bignum2(p); - if ((g = BN_new()) == NULL) - fatal("BN_new"); - packet_get_bignum2(g); - packet_check_eom(); - - if (BN_num_bits(p) < min || BN_num_bits(p) > max) - fatal("DH_GEX group out of range: %d !< %d !< %d", - min, BN_num_bits(p), max); - - dh = dh_new_group(g, p); - dh_gen_key(dh, kex->we_need * 8); - -#ifdef DEBUG_KEXDH - DHparams_print_fp(stderr, dh); - fprintf(stderr, "pub= "); - BN_print_fp(stderr, dh->pub_key); - fprintf(stderr, "\n"); -#endif - - debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); - /* generate and send 'e', client DH public key */ - packet_start(SSH2_MSG_KEX_DH_GEX_INIT); - packet_put_bignum2(dh->pub_key); - packet_send(); - - debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); - packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY); - - /* key, cert */ - server_host_key_blob = packet_get_string(&sbloblen); - server_host_key = key_from_blob(server_host_key_blob, sbloblen); - if (server_host_key == NULL) - fatal("cannot decode server_host_key_blob"); - if (server_host_key->type != kex->hostkey_type) - fatal("type mismatch for decoded server_host_key_blob"); - if (kex->verify_host_key == NULL) - fatal("cannot verify server_host_key"); - if (kex->verify_host_key(server_host_key) == -1) - fatal("server_host_key verification failed"); - - /* DH paramter f, server public DH key */ - if ((dh_server_pub = BN_new()) == NULL) - fatal("dh_server_pub == NULL"); - packet_get_bignum2(dh_server_pub); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "dh_server_pub= "); - BN_print_fp(stderr, dh_server_pub); - fprintf(stderr, "\n"); - debug("bits %d", BN_num_bits(dh_server_pub)); -#endif - - /* signed H */ - signature = packet_get_string(&slen); - packet_check_eom(); - - if (!dh_pub_is_valid(dh, dh_server_pub)) - packet_disconnect("bad server public DH value"); - - klen = DH_size(dh); - kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_server_pub, dh); -#ifdef DEBUG_KEXDH - dump_digest("shared secret", kbuf, kout); -#endif - if ((shared_secret = BN_new()) == NULL) - fatal("kexgex_client: BN_new failed"); - BN_bin2bn(kbuf, kout, shared_secret); - memset(kbuf, 0, klen); - xfree(kbuf); - - if (datafellows & SSH_OLD_DHGEX) - min = max = -1; - - /* calc and verify H */ - hash = kexgex_hash( - kex->client_version_string, - kex->server_version_string, - buffer_ptr(&kex->my), buffer_len(&kex->my), - buffer_ptr(&kex->peer), buffer_len(&kex->peer), - server_host_key_blob, sbloblen, - min, nbits, max, - dh->p, dh->g, - dh->pub_key, - dh_server_pub, - shared_secret - ); - /* have keys, free DH */ - DH_free(dh); - xfree(server_host_key_blob); - BN_clear_free(dh_server_pub); - - if (key_verify(server_host_key, signature, slen, hash, 20) != 1) - fatal("key_verify failed for server_host_key"); - key_free(server_host_key); - xfree(signature); - - /* save session id */ - if (kex->session_id == NULL) { - kex->session_id_len = 20; - kex->session_id = xmalloc(kex->session_id_len); - memcpy(kex->session_id, hash, kex->session_id_len); - } - kex_derive_keys(kex, hash, shared_secret); - BN_clear_free(shared_secret); - - kex_finish(kex); -} - -/* server */ - -static void -kexgex_server(Kex *kex) -{ - BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; - Key *server_host_key; - DH *dh; - u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; - u_int sbloblen, klen, kout, slen; - int min = -1, max = -1, nbits = -1, type; - - if (kex->load_host_key == NULL) - fatal("Cannot load hostkey"); - server_host_key = kex->load_host_key(kex->hostkey_type); - if (server_host_key == NULL) - fatal("Unsupported hostkey type %d", kex->hostkey_type); - - type = packet_read(); - switch (type) { - case SSH2_MSG_KEX_DH_GEX_REQUEST: - debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); - min = packet_get_int(); - nbits = packet_get_int(); - max = packet_get_int(); - min = MAX(DH_GRP_MIN, min); - max = MIN(DH_GRP_MAX, max); - break; - case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: - debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); - nbits = packet_get_int(); - min = DH_GRP_MIN; - max = DH_GRP_MAX; - /* unused for old GEX */ - break; - default: - fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); - } - packet_check_eom(); - - if (max < min || nbits < min || max < nbits) - fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", - min, nbits, max); - - /* Contact privileged parent */ - dh = PRIVSEP(choose_dh(min, nbits, max)); - if (dh == NULL) - packet_disconnect("Protocol error: no matching DH grp found"); - - debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); - packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); - packet_put_bignum2(dh->p); - packet_put_bignum2(dh->g); - packet_send(); - - /* flush */ - packet_write_wait(); - - /* Compute our exchange value in parallel with the client */ - dh_gen_key(dh, kex->we_need * 8); - - debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); - packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); - - /* key, cert */ - if ((dh_client_pub = BN_new()) == NULL) - fatal("dh_client_pub == NULL"); - packet_get_bignum2(dh_client_pub); - packet_check_eom(); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "dh_client_pub= "); - BN_print_fp(stderr, dh_client_pub); - fprintf(stderr, "\n"); - debug("bits %d", BN_num_bits(dh_client_pub)); -#endif - -#ifdef DEBUG_KEXDH - DHparams_print_fp(stderr, dh); - fprintf(stderr, "pub= "); - BN_print_fp(stderr, dh->pub_key); - fprintf(stderr, "\n"); -#endif - if (!dh_pub_is_valid(dh, dh_client_pub)) - packet_disconnect("bad client public DH value"); - - klen = DH_size(dh); - kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_client_pub, dh); -#ifdef DEBUG_KEXDH - dump_digest("shared secret", kbuf, kout); -#endif - if ((shared_secret = BN_new()) == NULL) - fatal("kexgex_server: BN_new failed"); - BN_bin2bn(kbuf, kout, shared_secret); - memset(kbuf, 0, klen); - xfree(kbuf); - - key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); - - if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) - min = max = -1; - - /* calc H */ /* XXX depends on 'kex' */ - hash = kexgex_hash( - kex->client_version_string, - kex->server_version_string, - buffer_ptr(&kex->peer), buffer_len(&kex->peer), - buffer_ptr(&kex->my), buffer_len(&kex->my), - server_host_key_blob, sbloblen, - min, nbits, max, - dh->p, dh->g, - dh_client_pub, - dh->pub_key, - shared_secret - ); - BN_clear_free(dh_client_pub); - - /* save session id := H */ - /* XXX hashlen depends on KEX */ - if (kex->session_id == NULL) { - kex->session_id_len = 20; - kex->session_id = xmalloc(kex->session_id_len); - memcpy(kex->session_id, hash, kex->session_id_len); - } - - /* sign H */ - /* XXX hashlen depends on KEX */ - PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20)); - - /* destroy_sensitive_data(); */ - - /* send server hostkey, DH pubkey 'f' and singed H */ - debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); - packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); - packet_put_string(server_host_key_blob, sbloblen); - packet_put_bignum2(dh->pub_key); /* f */ - packet_put_string(signature, slen); - packet_send(); - - xfree(signature); - xfree(server_host_key_blob); - /* have keys, free DH */ - DH_free(dh); - - kex_derive_keys(kex, hash, shared_secret); - BN_clear_free(shared_secret); - - kex_finish(kex); -} - -void -kexgex(Kex *kex) -{ - if (kex->server) - kexgex_server(kex); - else - kexgex_client(kex); -} diff --git a/kexgexc.c b/kexgexc.c new file mode 100644 index 00000000..f14ac44c --- /dev/null +++ b/kexgexc.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * Copyright (c) 2001 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: kexgexc.c,v 1.1 2003/02/16 17:09:57 markus Exp $"); + +#include "xmalloc.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" +#include "compat.h" + +void +kexgex_client(Kex *kex) +{ + BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; + BIGNUM *p = NULL, *g = NULL; + Key *server_host_key; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int klen, kout, slen, sbloblen; + int min, max, nbits; + DH *dh; + + nbits = dh_estimate(kex->we_need * 8); + + if (datafellows & SSH_OLD_DHGEX) { + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent"); + + /* Old GEX request */ + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); + packet_put_int(nbits); + min = DH_GRP_MIN; + max = DH_GRP_MAX; + } else { + debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent"); + + /* New GEX request */ + min = DH_GRP_MIN; + max = DH_GRP_MAX; + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); + packet_put_int(min); + packet_put_int(nbits); + packet_put_int(max); + } +#ifdef DEBUG_KEXDH + fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", + min, nbits, max); +#endif + packet_send(); + + debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); + packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP); + + if ((p = BN_new()) == NULL) + fatal("BN_new"); + packet_get_bignum2(p); + if ((g = BN_new()) == NULL) + fatal("BN_new"); + packet_get_bignum2(g); + packet_check_eom(); + + if (BN_num_bits(p) < min || BN_num_bits(p) > max) + fatal("DH_GEX group out of range: %d !< %d !< %d", + min, BN_num_bits(p), max); + + dh = dh_new_group(g, p); + dh_gen_key(dh, kex->we_need * 8); + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + + debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); + /* generate and send 'e', client DH public key */ + packet_start(SSH2_MSG_KEX_DH_GEX_INIT); + packet_put_bignum2(dh->pub_key); + packet_send(); + + debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); + packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY); + + /* key, cert */ + server_host_key_blob = packet_get_string(&sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); + if (server_host_key == NULL) + fatal("cannot decode server_host_key_blob"); + if (server_host_key->type != kex->hostkey_type) + fatal("type mismatch for decoded server_host_key_blob"); + if (kex->verify_host_key == NULL) + fatal("cannot verify server_host_key"); + if (kex->verify_host_key(server_host_key) == -1) + fatal("server_host_key verification failed"); + + /* DH paramter f, server public DH key */ + if ((dh_server_pub = BN_new()) == NULL) + fatal("dh_server_pub == NULL"); + packet_get_bignum2(dh_server_pub); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_server_pub= "); + BN_print_fp(stderr, dh_server_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_server_pub)); +#endif + + /* signed H */ + signature = packet_get_string(&slen); + packet_check_eom(); + + if (!dh_pub_is_valid(dh, dh_server_pub)) + packet_disconnect("bad server public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + if ((shared_secret = BN_new()) == NULL) + fatal("kexgex_client: BN_new failed"); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + if (datafellows & SSH_OLD_DHGEX) + min = max = -1; + + /* calc and verify H */ + hash = kexgex_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->my), buffer_len(&kex->my), + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + server_host_key_blob, sbloblen, + min, nbits, max, + dh->p, dh->g, + dh->pub_key, + dh_server_pub, + shared_secret + ); + /* have keys, free DH */ + DH_free(dh); + xfree(server_host_key_blob); + BN_clear_free(dh_server_pub); + + if (key_verify(server_host_key, signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); + key_free(server_host_key); + xfree(signature); + + /* save session id */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + + kex_finish(kex); +} diff --git a/kexgexs.c b/kexgexs.c new file mode 100644 index 00000000..baebfcfb --- /dev/null +++ b/kexgexs.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * Copyright (c) 2001 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: kexgexs.c,v 1.1 2003/02/16 17:09:57 markus Exp $"); + +#include "xmalloc.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" +#include "compat.h" +#include "monitor_wrap.h" + +void +kexgex_server(Kex *kex) +{ + BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; + Key *server_host_key; + DH *dh; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int sbloblen, klen, kout, slen; + int min = -1, max = -1, nbits = -1, type; + + if (kex->load_host_key == NULL) + fatal("Cannot load hostkey"); + server_host_key = kex->load_host_key(kex->hostkey_type); + if (server_host_key == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); + + type = packet_read(); + switch (type) { + case SSH2_MSG_KEX_DH_GEX_REQUEST: + debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); + min = packet_get_int(); + nbits = packet_get_int(); + max = packet_get_int(); + min = MAX(DH_GRP_MIN, min); + max = MIN(DH_GRP_MAX, max); + break; + case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); + nbits = packet_get_int(); + min = DH_GRP_MIN; + max = DH_GRP_MAX; + /* unused for old GEX */ + break; + default: + fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); + } + packet_check_eom(); + + if (max < min || nbits < min || max < nbits) + fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", + min, nbits, max); + + /* Contact privileged parent */ + dh = PRIVSEP(choose_dh(min, nbits, max)); + if (dh == NULL) + packet_disconnect("Protocol error: no matching DH grp found"); + + debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); + packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); + packet_put_bignum2(dh->p); + packet_put_bignum2(dh->g); + packet_send(); + + /* flush */ + packet_write_wait(); + + /* Compute our exchange value in parallel with the client */ + dh_gen_key(dh, kex->we_need * 8); + + debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); + packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); + + /* key, cert */ + if ((dh_client_pub = BN_new()) == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub); + packet_check_eom(); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_client_pub= "); + BN_print_fp(stderr, dh_client_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_client_pub)); +#endif + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + if ((shared_secret = BN_new()) == NULL) + fatal("kexgex_server: BN_new failed"); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + + if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) + min = max = -1; + + /* calc H */ /* XXX depends on 'kex' */ + hash = kexgex_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + server_host_key_blob, sbloblen, + min, nbits, max, + dh->p, dh->g, + dh_client_pub, + dh->pub_key, + shared_secret + ); + BN_clear_free(dh_client_pub); + + /* save session id := H */ + /* XXX hashlen depends on KEX */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + /* sign H */ + /* XXX hashlen depends on KEX */ + PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20)); + + /* destroy_sensitive_data(); */ + + /* send server hostkey, DH pubkey 'f' and singed H */ + debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); + packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); + packet_put_string(server_host_key_blob, sbloblen); + packet_put_bignum2(dh->pub_key); /* f */ + packet_put_string(signature, slen); + packet_send(); + + xfree(signature); + xfree(server_host_key_blob); + /* have keys, free DH */ + DH_free(dh); + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + + kex_finish(kex); +} diff --git a/ssh-keyscan.c b/ssh-keyscan.c index 8c14d6d2..5b4eb82d 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -7,7 +7,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-keyscan.c,v 1.40 2002/07/06 17:47:58 stevesk Exp $"); +RCSID("$OpenBSD: ssh-keyscan.c,v 1.41 2003/02/16 17:09:57 markus Exp $"); #include "openbsd-compat/sys-queue.h" @@ -354,6 +354,8 @@ keygrab_ssh2(con *c) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA? "ssh-dss": "ssh-rsa"; c->c_kex = kex_setup(myproposal); + c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; + c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; c->c_kex->verify_host_key = hostjump; if (!(j = setjmp(kexjmp))) { diff --git a/sshconnect2.c b/sshconnect2.c index de33e142..81d1b91c 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.110 2002/12/19 00:07:02 djm Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.111 2003/02/16 17:09:57 markus Exp $"); #include "ssh.h" #include "ssh2.h" @@ -110,6 +110,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) /* start key exchange */ kex = kex_setup(myproposal); + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->verify_host_key=&verify_host_key_callback; diff --git a/sshd.c b/sshd.c index ca2d4d1b..86441cff 100644 --- a/sshd.c +++ b/sshd.c @@ -42,7 +42,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.262 2003/01/27 17:06:31 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.263 2003/02/16 17:09:57 markus Exp $"); #include #include @@ -202,8 +202,8 @@ int *startup_pipes = NULL; int startup_pipe; /* in child */ /* variables used for privilege separation */ -extern struct monitor *pmonitor; -extern int use_privsep; +int use_privsep; +struct monitor *pmonitor; /* Prototypes for various functions defined later in this file. */ void destroy_sensitive_data(void); @@ -1814,6 +1814,8 @@ do_ssh2_kex(void) /* start key exchange */ kex = kex_setup(myproposal); + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->server = 1; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; -- 2.45.1