summaryrefslogtreecommitdiff
path: root/usr.bin/ssh
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2001-04-03 23:32:13 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2001-04-03 23:32:13 +0000
commit2523ebe5de401adafe2f226ed9a1b34f65e93181 (patch)
tree5b705da89bc1350b32d15cc2d5ffe605fe8460b2 /usr.bin/ssh
parentc985060f0f8d96088c0b97e28aed2cc2c2fd6b07 (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/ssh')
-rw-r--r--usr.bin/ssh/kex.c85
-rw-r--r--usr.bin/ssh/kex.h75
-rw-r--r--usr.bin/ssh/kexdh.c122
-rw-r--r--usr.bin/ssh/kexgex.c205
-rw-r--r--usr.bin/ssh/packet.c108
-rw-r--r--usr.bin/ssh/sshconnect2.c5
-rw-r--r--usr.bin/ssh/sshd.c5
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);