diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2001-04-03 23:32:13 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2001-04-03 23:32:13 +0000 |
commit | 2523ebe5de401adafe2f226ed9a1b34f65e93181 (patch) | |
tree | 5b705da89bc1350b32d15cc2d5ffe605fe8460b2 /usr.bin | |
parent | c985060f0f8d96088c0b97e28aed2cc2c2fd6b07 (diff) |
undo parts of recent my changes: main part of keyexchange does not
need dispatch-callbacks, since application data is delayed until
the keyexchange completes (if i understand the drafts correctly).
add some infrastructure for re-keying.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/ssh/kex.c | 85 | ||||
-rw-r--r-- | usr.bin/ssh/kex.h | 75 | ||||
-rw-r--r-- | usr.bin/ssh/kexdh.c | 122 | ||||
-rw-r--r-- | usr.bin/ssh/kexgex.c | 205 | ||||
-rw-r--r-- | usr.bin/ssh/packet.c | 108 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect2.c | 5 | ||||
-rw-r--r-- | usr.bin/ssh/sshd.c | 5 |
7 files changed, 258 insertions, 347 deletions
diff --git a/usr.bin/ssh/kex.c b/usr.bin/ssh/kex.c index a0a5b46fef8..3b42d324017 100644 --- a/usr.bin/ssh/kex.c +++ b/usr.bin/ssh/kex.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.26 2001/04/03 19:53:29 markus Exp $"); +RCSID("$OpenBSD: kex.c,v 1.27 2001/04/03 23:32:11 markus Exp $"); #include <openssl/crypto.h> @@ -131,7 +131,7 @@ kex_input_newkeys(int type, int plen, void *ctxt) for (i = 30; i <= 49; i++) dispatch_set(i, &kex_protocol_error); buffer_clear(&kex->peer); - buffer_clear(&kex->my); + /* buffer_clear(&kex->my); */ kex->flags &= ~KEX_INIT_SENT; } @@ -152,7 +152,6 @@ kex_input_kexinit(int type, int plen, void *ctxt) int dlen; Kex *kex = (Kex *)ctxt; - dispatch_set(SSH2_MSG_KEXINIT, &kex_protocol_error); debug("SSH2_MSG_KEXINIT received"); ptr = packet_get_raw(&dlen); @@ -274,18 +273,20 @@ choose_hostkeyalg(Kex *k, char *client, char *server) } void -kex_choose_conf(Kex *k) +kex_choose_conf(Kex *kex) { + Newkeys *newkeys; char **my, **peer; char **cprop, **sprop; + int nenc, nmac, ncomp; int mode; int ctos; /* direction: if true client-to-server */ int need; - my = kex_buf2prop(&k->my); - peer = kex_buf2prop(&k->peer); + my = kex_buf2prop(&kex->my); + peer = kex_buf2prop(&kex->peer); - if (k->server) { + if (kex->server) { cprop=peer; sprop=my; } else { @@ -294,42 +295,44 @@ kex_choose_conf(Kex *k) } for (mode = 0; mode < MODE_MAX; mode++) { - int nenc, nmac, ncomp; - ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); + newkeys = xmalloc(sizeof(*newkeys)); + memset(newkeys, 0, sizeof(*newkeys)); + kex->keys[mode] = newkeys; + ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; - choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]); - choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]); - choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]); + choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); + choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); + choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", - k->enc[mode].name, - k->mac[mode].name, - k->comp[mode].name); + newkeys->enc.name, + newkeys->mac.name, + newkeys->comp.name); } - choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); - choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], + choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); + choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); need = 0; for (mode = 0; mode < MODE_MAX; mode++) { - if (need < k->enc[mode].cipher->key_len) - need = k->enc[mode].cipher->key_len; - if (need < k->enc[mode].cipher->block_size) - need = k->enc[mode].cipher->block_size; - if (need < k->mac[mode].key_len) - need = k->mac[mode].key_len; + newkeys = kex->keys[mode]; + if (need < newkeys->enc.cipher->key_len) + need = newkeys->enc.cipher->key_len; + if (need < newkeys->enc.cipher->block_size) + need = newkeys->enc.cipher->block_size; + if (need < newkeys->mac.key_len) + need = newkeys->mac.key_len; } /* XXX need runden? */ - k->we_need = need; + kex->we_need = need; kex_prop_free(my); kex_prop_free(peer); - } u_char * -derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret) +derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) { Buffer b; EVP_MD *evp_md = EVP_sha1(); @@ -346,7 +349,7 @@ derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret) EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */ EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */ EVP_DigestUpdate(&md, &c, 1); /* key id */ - EVP_DigestUpdate(&md, hash, mdsz); /* session id */ + EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); EVP_DigestFinal(&md, digest, NULL); /* expand */ @@ -365,26 +368,36 @@ derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret) return digest; } +Newkeys *x_newkeys[MODE_MAX]; + #define NKEYS 6 void -kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret) +kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) { - int i; - int mode; - int ctos; + Newkeys *newkeys; u_char *keys[NKEYS]; + int i, mode, ctos; for (i = 0; i < NKEYS; i++) - keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret); + keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); + debug("kex_derive_keys"); for (mode = 0; mode < MODE_MAX; mode++) { - ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); - k->enc[mode].iv = keys[ctos ? 0 : 1]; - k->enc[mode].key = keys[ctos ? 2 : 3]; - k->mac[mode].key = keys[ctos ? 4 : 5]; + newkeys = kex->keys[mode]; + ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); + newkeys->enc.iv = keys[ctos ? 0 : 1]; + newkeys->enc.key = keys[ctos ? 2 : 3]; + newkeys->mac.key = keys[ctos ? 4 : 5]; + x_newkeys[mode] = newkeys; } } +Newkeys * +kex_get_newkeys(int mode) +{ + return x_newkeys[mode]; +} + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) void dump_digest(char *msg, u_char *digest, int len) diff --git a/usr.bin/ssh/kex.h b/usr.bin/ssh/kex.h index 58f6d82c0b2..83f54fd968a 100644 --- a/usr.bin/ssh/kex.h +++ b/usr.bin/ssh/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.18 2001/04/03 19:53:29 markus Exp $ */ +/* $OpenBSD: kex.h,v 1.19 2001/04/03 23:32:12 markus Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -59,64 +59,69 @@ enum kex_exchange { DH_GEX_SHA1 }; +#define KEX_INIT_SENT 0x0001 + typedef struct Kex Kex; typedef struct Mac Mac; typedef struct Comp Comp; typedef struct Enc Enc; +typedef struct Newkeys Newkeys; struct Enc { - char *name; - Cipher *cipher; - int enabled; + char *name; + Cipher *cipher; + int enabled; u_char *key; u_char *iv; }; struct Mac { - char *name; - int enabled; - EVP_MD *md; - int mac_len; + char *name; + int enabled; + EVP_MD *md; + int mac_len; u_char *key; - int key_len; + int key_len; }; struct Comp { - int type; - int enabled; - char *name; + int type; + int enabled; + char *name; +}; +struct Newkeys { + Enc enc; + Mac mac; + Comp comp; }; -#define KEX_INIT_SENT 0x0001 struct Kex { - Enc enc [MODE_MAX]; - Mac mac [MODE_MAX]; - Comp comp[MODE_MAX]; - int we_need; - int server; - char *name; - int hostkey_type; - int kex_type; - - /* used during kex */ - Buffer my; - Buffer peer; - int newkeys; - int flags; - void *state; - char *client_version_string; - char *server_version_string; - - int (*check_host_key)(Key *hostkey); - Key *(*load_host_key)(int type); + u_char *session_id; + int session_id_len; + Newkeys *keys[MODE_MAX]; + int we_need; + int server; + char *name; + int hostkey_type; + int kex_type; + Buffer my; + Buffer peer; + int newkeys; + int flags; + char *client_version_string; + char *server_version_string; + int (*check_host_key)(Key *hostkey); + Key *(*load_host_key)(int type); }; -void kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret); -void packet_set_kex(Kex *k); Kex *kex_start(char *proposal[PROPOSAL_MAX]); void kex_send_newkeys(void); +void kex_send_kexinit(Kex *kex); void kex_protocol_error(int type, int plen, void *ctxt); +void kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret); void kexdh(Kex *); void kexgex(Kex *); +Newkeys *kex_get_newkeys(int mode); + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) void dump_digest(char *msg, u_char *digest, int len); #endif diff --git a/usr.bin/ssh/kexdh.c b/usr.bin/ssh/kexdh.c index dcf4f123e1e..8449ec06ae8 100644 --- a/usr.bin/ssh/kexdh.c +++ b/usr.bin/ssh/kexdh.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kexdh.c,v 1.1 2001/04/03 19:53:29 markus Exp $"); +RCSID("$OpenBSD: kexdh.c,v 1.2 2001/04/03 23:32:12 markus Exp $"); #include <openssl/crypto.h> #include <openssl/bn.h> @@ -34,22 +34,10 @@ RCSID("$OpenBSD: kexdh.c,v 1.1 2001/04/03 19:53:29 markus Exp $"); #include "key.h" #include "kex.h" #include "log.h" -#include "dispatch.h" #include "packet.h" #include "dh.h" #include "ssh2.h" -extern u_char *session_id2; -extern int session_id2_len; - -dispatch_fn kexdh_input_init; /* C -> S */ -dispatch_fn kexdh_input_reply; /* S -> C */ - -typedef struct State State; -struct State { - DH *dh; -}; - u_char * kex_dh_hash( char *client_version_string, @@ -103,43 +91,31 @@ kex_dh_hash( void kexdh_client(Kex *kex) { - State *state; - - dispatch_set(SSH2_MSG_KEXDH_REPLY, &kexdh_input_reply); - - state = xmalloc(sizeof(State)); - kex->state = state; + BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; + DH *dh; + Key *server_host_key; + char *server_host_key_blob = NULL, *signature = NULL; + u_char *kbuf, *hash; + u_int klen, kout, slen, sbloblen; + int dlen, plen; /* generate and send 'e', client DH public key */ - state->dh = dh_new_group1(); - dh_gen_key(state->dh, kex->we_need * 8); + dh = dh_new_group1(); + dh_gen_key(dh, kex->we_need * 8); packet_start(SSH2_MSG_KEXDH_INIT); - packet_put_bignum2(state->dh->pub_key); + packet_put_bignum2(dh->pub_key); packet_send(); - debug("SSH2_MSG_KEXDH_INIT sent"); + debug("sending SSH2_MSG_KEXDH_INIT"); #ifdef DEBUG_KEXDH - DHparams_print_fp(stderr, state->dh); + DHparams_print_fp(stderr, dh); fprintf(stderr, "pub= "); - BN_print_fp(stderr, state->dh->pub_key); + BN_print_fp(stderr, dh->pub_key); fprintf(stderr, "\n"); #endif -} - -void -kexdh_input_reply(int type, int plen, void *ctxt) -{ - BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; - Key *server_host_key; - char *server_host_key_blob = NULL, *signature = NULL; - u_char *kbuf, *hash; - u_int klen, kout, slen, sbloblen; - int dlen; - Kex *kex = (Kex *)ctxt; - State *state = (State *)kex->state; - debug("SSH2_MSG_KEXDH_REPLY received"); - dispatch_set(SSH2_MSG_KEXDH_REPLY, &kex_protocol_error); + debug("expecting SSH2_MSG_KEXDH_REPLY"); + packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY); /* key, cert */ server_host_key_blob = packet_get_string(&sbloblen); @@ -168,12 +144,12 @@ kexdh_input_reply(int type, int plen, void *ctxt) signature = packet_get_string(&slen); packet_done(); - if (!dh_pub_is_valid(state->dh, dh_server_pub)) + if (!dh_pub_is_valid(dh, dh_server_pub)) packet_disconnect("bad server public DH value"); - klen = DH_size(state->dh); + klen = DH_size(dh); kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_server_pub, state->dh); + kout = DH_compute_key(kbuf, dh_server_pub, dh); #ifdef DEBUG_KEXDH dump_digest("shared secret", kbuf, kout); #endif @@ -189,12 +165,12 @@ kexdh_input_reply(int type, int plen, void *ctxt) buffer_ptr(&kex->my), buffer_len(&kex->my), buffer_ptr(&kex->peer), buffer_len(&kex->peer), server_host_key_blob, sbloblen, - state->dh->pub_key, + dh->pub_key, dh_server_pub, shared_secret ); xfree(server_host_key_blob); - DH_free(state->dh); + DH_free(dh); BN_free(dh_server_pub); if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) @@ -202,18 +178,16 @@ kexdh_input_reply(int type, int plen, void *ctxt) 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); - packet_set_kex(kex); kex_send_newkeys(); - - /* save session id */ - session_id2_len = 20; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, hash, session_id2_len); - - xfree(state); - kex->state = NULL; } /* server */ @@ -221,32 +195,19 @@ kexdh_input_reply(int type, int plen, void *ctxt) void kexdh_server(Kex *kex) { - State *state; - - dispatch_set(SSH2_MSG_KEXDH_INIT, &kexdh_input_init); - - state = xmalloc(sizeof(*state)); - kex->state = state; - - /* generate server DH public key */ - state->dh = dh_new_group1(); - dh_gen_key(state->dh, kex->we_need * 8); -} - -void -kexdh_input_init(int type, int plen, void *ctxt) -{ 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; - int dlen, slen; - Kex *kex = (Kex*) ctxt; - State *state = (State*) kex->state; - DH *dh = state->dh; + int dlen, slen, plen; + + /* generate server DH public key */ + dh = dh_new_group1(); + dh_gen_key(dh, kex->we_need * 8); - debug("SSH2_MSG_KEXDH_INIT received"); - dispatch_set(SSH2_MSG_KEXDH_INIT, &kex_protocol_error); + debug("expecting SSH2_MSG_KEXDH_INIT"); + packet_read_expect(&plen, SSH2_MSG_KEXDH_INIT); if (kex->load_host_key == NULL) fatal("Cannot load hostkey"); @@ -304,9 +265,11 @@ kexdh_input_init(int type, int plen, void *ctxt) /* save session id := H */ /* XXX hashlen depends on KEX */ - session_id2_len = 20; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, hash, session_id2_len); + 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 */ @@ -325,13 +288,10 @@ kexdh_input_init(int type, int plen, void *ctxt) kex_derive_keys(kex, hash, shared_secret); BN_clear_free(shared_secret); - packet_set_kex(kex); kex_send_newkeys(); /* have keys, free DH */ DH_free(dh); - xfree(state); - kex->state = NULL; } void diff --git a/usr.bin/ssh/kexgex.c b/usr.bin/ssh/kexgex.c index 43fa8b9b7e2..6e8be78b552 100644 --- a/usr.bin/ssh/kexgex.c +++ b/usr.bin/ssh/kexgex.c @@ -24,7 +24,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kexgex.c,v 1.1 2001/04/03 19:53:29 markus Exp $"); +RCSID("$OpenBSD: kexgex.c,v 1.2 2001/04/03 23:32:12 markus Exp $"); #include <openssl/bn.h> @@ -34,26 +34,11 @@ RCSID("$OpenBSD: kexgex.c,v 1.1 2001/04/03 19:53:29 markus Exp $"); #include "key.h" #include "kex.h" #include "log.h" -#include "dispatch.h" #include "packet.h" #include "dh.h" #include "ssh2.h" #include "compat.h" -extern u_char *session_id2; -extern int session_id2_len; - -typedef struct State State; -struct State { - DH *dh; - int min, nbits, max; -}; - -dispatch_fn kexgex_input_request; /* C -> S */ -dispatch_fn kexgex_input_group; /* S -> C */ -dispatch_fn kexgex_input_init; /* C -> S */ -dispatch_fn kexgex_input_reply; /* S -> C */ - u_char * kexgex_hash( char *client_version_string, @@ -117,52 +102,43 @@ kexgex_hash( void kexgex_client(Kex *kex) { - State *state; - - dispatch_set(SSH2_MSG_KEX_DH_GEX_GROUP, &kexgex_input_group); + 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 dlen, plen, min, max, nbits; + DH *dh; - state = xmalloc(sizeof(*state)); - state->nbits = dh_estimate(kex->we_need * 8); - kex->state = state; + 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(state->nbits); - state->min = DH_GRP_MIN; - state->max = DH_GRP_MAX; + packet_put_int(nbits); + min = DH_GRP_MIN; + max = DH_GRP_MAX; } else { debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent"); /* New GEX request */ - state->min = DH_GRP_MIN; - state->max = DH_GRP_MAX; + min = DH_GRP_MIN; + max = DH_GRP_MAX; packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); - packet_put_int(state->min); - packet_put_int(state->nbits); - packet_put_int(state->max); + packet_put_int(min); + packet_put_int(nbits); + packet_put_int(max); } #ifdef DEBUG_KEXDH fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", - state->min, state->nbits, state->max); + min, nbits, max); #endif packet_send(); -} - -void -kexgex_input_group(int type, int plen, void *ctxt) -{ - DH *dh; - int dlen; - BIGNUM *p = 0, *g = 0; - Kex *kex = (Kex*) ctxt; - State *state = (State *) kex->state; - debug("SSH2_MSG_KEX_DH_GEX_GROUP receivied"); - dispatch_set(SSH2_MSG_KEX_DH_GEX_GROUP, &kex_protocol_error); - dispatch_set(SSH2_MSG_KEX_DH_GEX_REPLY, &kexgex_input_reply); + debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); + packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP); if ((p = BN_new()) == NULL) fatal("BN_new"); @@ -170,16 +146,15 @@ kexgex_input_group(int type, int plen, void *ctxt) if ((g = BN_new()) == NULL) fatal("BN_new"); packet_get_bignum2(g, &dlen); + packet_done(); - if (BN_num_bits(p) < state->min || BN_num_bits(p) > state->max) + if (BN_num_bits(p) < min || BN_num_bits(p) > max) fatal("DH_GEX group out of range: %d !< %d !< %d", - state->min, BN_num_bits(p), state->max); + min, BN_num_bits(p), max); dh = dh_new_group(g, p); dh_gen_key(dh, kex->we_need * 8); - state->dh = dh; - #ifdef DEBUG_KEXDH DHparams_print_fp(stderr, dh); fprintf(stderr, "pub= "); @@ -192,22 +167,9 @@ kexgex_input_group(int type, int plen, void *ctxt) packet_start(SSH2_MSG_KEX_DH_GEX_INIT); packet_put_bignum2(dh->pub_key); packet_send(); -} -void -kexgex_input_reply(int type, int plen, void *ctxt) -{ - BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; - Key *server_host_key; - Kex *kex = (Kex*) ctxt; - State *state = (State *) kex->state; - DH *dh = state->dh; - u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; - u_int klen, kout, slen, sbloblen; - int dlen, min, max; - - debug("SSH2_MSG_KEX_DH_GEX_REPLY received"); - dispatch_set(SSH2_MSG_KEX_DH_GEX_REPLY, &kex_protocol_error); + debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); + packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY); /* key, cert */ server_host_key_blob = packet_get_string(&sbloblen); @@ -250,12 +212,8 @@ kexgex_input_reply(int type, int plen, void *ctxt) memset(kbuf, 0, klen); xfree(kbuf); - if (datafellows & SSH_OLD_DHGEX) { + if (datafellows & SSH_OLD_DHGEX) min = max = -1; - } else { - min = state->min; - max = state->max; - } /* calc and verify H */ hash = kexgex_hash( @@ -264,7 +222,7 @@ kexgex_input_reply(int type, int plen, void *ctxt) buffer_ptr(&kex->my), buffer_len(&kex->my), buffer_ptr(&kex->peer), buffer_len(&kex->peer), server_host_key_blob, sbloblen, - min, state->nbits, max, + min, nbits, max, dh->p, dh->g, dh->pub_key, dh_server_pub, @@ -278,21 +236,20 @@ kexgex_input_reply(int type, int plen, void *ctxt) 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); - packet_set_kex(kex); - - /* save session id */ - session_id2_len = 20; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, hash, session_id2_len); kex_send_newkeys(); /* have keys, free DH */ DH_free(dh); - xfree(state); - kex->state = NULL; } /* server */ @@ -300,90 +257,63 @@ kexgex_input_reply(int type, int plen, void *ctxt) void kexgex_server(Kex *kex) { - State *state; - - state = xmalloc(sizeof(*state)); - kex->state = state; - - dispatch_set(SSH2_MSG_KEX_DH_GEX_REQUEST, &kexgex_input_request); - dispatch_set(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, &kexgex_input_request); -} - -void -kexgex_input_request(int type, int plen, void *ctxt) -{ - Kex *kex = (Kex*) ctxt; - State *state = (State *) kex->state; - int min = -1, max = -1; + BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; + Key *server_host_key; + DH *dh = dh; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int sbloblen, klen, kout; + int min = -1, max = -1, nbits = -1, type, plen, dlen, slen; - dispatch_set(SSH2_MSG_KEX_DH_GEX_REQUEST, &kex_protocol_error); - dispatch_set(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, &kex_protocol_error); - dispatch_set(SSH2_MSG_KEX_DH_GEX_INIT, &kexgex_input_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); + type = packet_read(&plen); switch(type){ case SSH2_MSG_KEX_DH_GEX_REQUEST: debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); min = packet_get_int(); - state->nbits = packet_get_int(); + nbits = packet_get_int(); max = packet_get_int(); min = MAX(DH_GRP_MIN, min); max = MIN(DH_GRP_MAX, max); - state->min = min; - state->max = max; break; case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); - state->nbits = packet_get_int(); + nbits = packet_get_int(); min = DH_GRP_MIN; max = DH_GRP_MAX; /* unused for old GEX */ - state->min = -1; - state->max = -1; break; + default: + fatal("protocol error during kex, no DH_GEX_REQUEST"); } packet_done(); - if (max < min || state->nbits < min || max < state->nbits) + if (max < min || nbits < min || max < nbits) fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", - min, state->nbits, max); + min, nbits, max); - state->dh = choose_dh(min, state->nbits, max); - if (state->dh == NULL) + dh = 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(state->dh->p); - packet_put_bignum2(state->dh->g); + 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(state->dh, kex->we_need * 8); -} - -void -kexgex_input_init(int type, int plen, void *ctxt) -{ - BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; - Key *server_host_key; - Kex *kex = (Kex*) ctxt; - State *state = (State *) kex->state; - DH *dh = state->dh; - u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; - u_int sbloblen, klen, kout; - int dlen, slen; - - 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); + dh_gen_key(dh, kex->we_need * 8); - dispatch_set(SSH2_MSG_KEX_DH_GEX_INIT, &kex_protocol_error); - debug("SSH2_MSG_KEX_DH_GEX_INIT received"); + debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); + packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_INIT); /* key, cert */ dh_client_pub = BN_new(); @@ -420,6 +350,9 @@ kexgex_input_init(int type, int plen, void *ctxt) 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, @@ -427,7 +360,7 @@ kexgex_input_init(int type, int plen, void *ctxt) buffer_ptr(&kex->peer), buffer_len(&kex->peer), buffer_ptr(&kex->my), buffer_len(&kex->my), (char *)server_host_key_blob, sbloblen, - state->min, state->nbits, state->max, + min, nbits, max, dh->p, dh->g, dh_client_pub, dh->pub_key, @@ -437,9 +370,11 @@ kexgex_input_init(int type, int plen, void *ctxt) /* save session id := H */ /* XXX hashlen depends on KEX */ - session_id2_len = 20; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, hash, session_id2_len); + 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 */ @@ -456,18 +391,14 @@ kexgex_input_init(int type, int plen, void *ctxt) packet_send(); xfree(signature); xfree(server_host_key_blob); - /* packet_write_wait(); */ kex_derive_keys(kex, hash, shared_secret); BN_clear_free(shared_secret); - packet_set_kex(kex); kex_send_newkeys(); /* have keys, free DH */ DH_free(dh); - xfree(state); - kex->state = NULL; } void diff --git a/usr.bin/ssh/packet.c b/usr.bin/ssh/packet.c index 362ee50ad66..5bf1d8fb146 100644 --- a/usr.bin/ssh/packet.c +++ b/usr.bin/ssh/packet.c @@ -37,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: packet.c,v 1.56 2001/03/03 21:41:07 millert Exp $"); +RCSID("$OpenBSD: packet.c,v 1.57 2001/04/03 23:32:12 markus Exp $"); #include "xmalloc.h" #include "buffer.h" @@ -121,21 +121,9 @@ static int interactive_mode = 0; int use_ssh2_packet_format = 0; /* Session key information for Encryption and MAC */ -Kex *kex = NULL; +Newkeys *newkeys[MODE_MAX]; void -packet_set_kex(Kex *k) -{ - if( k->mac[MODE_IN ].key == NULL || - k->enc[MODE_IN ].key == NULL || - k->enc[MODE_IN ].iv == NULL || - k->mac[MODE_OUT].key == NULL || - k->enc[MODE_OUT].key == NULL || - k->enc[MODE_OUT].iv == NULL) - fatal("bad KEX"); - kex = k; -} -void clear_enc_keys(Enc *enc, int len) { memset(enc->iv, 0, len); @@ -150,6 +138,7 @@ packet_set_ssh2_format(void) { DBG(debug("use_ssh2_packet_format")); use_ssh2_packet_format = 1; + newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; } /* @@ -522,6 +511,41 @@ packet_send1(void) */ } +void +set_newkeys(int mode) +{ + Enc *enc; + Mac *mac; + Comp *comp; + CipherContext *cc; + + debug("newkeys: mode %d", mode); + + cc = (mode == MODE_OUT) ? &send_context : &receive_context; + if (newkeys[mode] != NULL) { + debug("newkeys: rekeying"); + memset(cc, 0, sizeof(*cc)); + // free old keys, reset compression cipher-contexts; + } + newkeys[mode] = kex_get_newkeys(mode); + if (newkeys[mode] == NULL) + fatal("newkeys: no keys for mode %d", mode); + enc = &newkeys[mode]->enc; + mac = &newkeys[mode]->mac; + comp = &newkeys[mode]->comp; + if (mac->md != NULL) + mac->enabled = 1; + DBG(debug("cipher_init_context: %d", mode)); + cipher_init(cc, enc->cipher, enc->key, enc->cipher->key_len, + enc->iv, enc->cipher->block_size); + clear_enc_keys(enc, enc->cipher->key_len); + if (comp->type != 0 && comp->enabled == 0) { + comp->enabled = 1; + if (! packet_compression) + packet_start_compression(6); + } +} + /* * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) */ @@ -540,10 +564,10 @@ packet_send2(void) Comp *comp = NULL; int block_size; - if (kex != NULL) { - enc = &kex->enc[MODE_OUT]; - mac = &kex->mac[MODE_OUT]; - comp = &kex->comp[MODE_OUT]; + if (newkeys[MODE_OUT] != NULL) { + enc = &newkeys[MODE_OUT]->enc; + mac = &newkeys[MODE_OUT]->mac; + comp = &newkeys[MODE_OUT]->comp; } block_size = enc ? enc->cipher->block_size : 8; @@ -622,22 +646,8 @@ packet_send2(void) log("outgoing seqnr wraps around"); buffer_clear(&outgoing_packet); - if (type == SSH2_MSG_NEWKEYS) { - if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) - fatal("packet_send2: no KEX"); - if (mac->md != NULL) - mac->enabled = 1; - DBG(debug("cipher_init send_context")); - cipher_init(&send_context, enc->cipher, - enc->key, enc->cipher->key_len, - enc->iv, enc->cipher->block_size); - clear_enc_keys(enc, kex->we_need); - if (comp->type != 0 && comp->enabled == 0) { - comp->enabled = 1; - if (! packet_compression) - packet_start_compression(6); - } - } + if (type == SSH2_MSG_NEWKEYS) + set_newkeys(MODE_OUT); } void @@ -833,10 +843,10 @@ packet_read_poll2(int *payload_len_ptr) Mac *mac = NULL; Comp *comp = NULL; - if (kex != NULL) { - enc = &kex->enc[MODE_IN]; - mac = &kex->mac[MODE_IN]; - comp = &kex->comp[MODE_IN]; + if (newkeys[MODE_IN] != NULL) { + enc = &newkeys[MODE_IN]->enc; + mac = &newkeys[MODE_IN]->mac; + comp = &newkeys[MODE_IN]->comp; } maclen = mac && mac->enabled ? mac->mac_len : 0; block_size = enc ? enc->cipher->block_size : 8; @@ -930,22 +940,8 @@ packet_read_poll2(int *payload_len_ptr) /* extract packet type */ type = (u_char)buf[0]; - if (type == SSH2_MSG_NEWKEYS) { - if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) - fatal("packet_read_poll2: no KEX"); - if (mac->md != NULL) - mac->enabled = 1; - DBG(debug("cipher_init receive_context")); - cipher_init(&receive_context, enc->cipher, - enc->key, enc->cipher->key_len, - enc->iv, enc->cipher->block_size); - clear_enc_keys(enc, kex->we_need); - if (comp->type != 0 && comp->enabled == 0) { - comp->enabled = 1; - if (! packet_compression) - packet_start_compression(6); - } - } + if (type == SSH2_MSG_NEWKEYS) + set_newkeys(MODE_IN); #ifdef PACKET_DEBUG fprintf(stderr, "read/plain[%d]:\r\n", type); @@ -1333,8 +1329,8 @@ packet_inject_ignore(int sumlen) have = buffer_len(&outgoing_packet); debug2("packet_inject_ignore: current %d", have); - if (kex != NULL) - enc = &kex->enc[MODE_OUT]; + if (newkeys[MODE_OUT] != NULL) + enc = &newkeys[MODE_OUT]->enc; blocksize = enc ? enc->cipher->block_size : 8; padlen = blocksize - (have % blocksize); if (padlen < 4) diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c index 4ed39a23ee6..dd3f36b5773 100644 --- a/usr.bin/ssh/sshconnect2.c +++ b/usr.bin/ssh/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.61 2001/04/03 19:53:29 markus Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.62 2001/04/03 23:32:12 markus Exp $"); #include <openssl/bn.h> #include <openssl/md5.h> @@ -117,6 +117,9 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) /* start key exchange */ dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex); + session_id2 = kex->session_id; + session_id2_len = kex->session_id_len; + #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ packet_start(SSH2_MSG_IGNORE); diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index e7a5755fdf0..9aa662eef74 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.186 2001/04/03 19:53:29 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.187 2001/04/03 23:32:12 markus Exp $"); #include <openssl/dh.h> #include <openssl/bn.h> @@ -1408,6 +1408,9 @@ do_ssh2_kex(void) /* start key exchange */ dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex); + session_id2 = kex->session_id; + session_id2_len = kex->session_id_len; + #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ packet_start(SSH2_MSG_IGNORE); |