version 1.51, 2002/06/24 14:55:38 |
version 1.51.2.2, 2003/04/03 23:27:12 |
|
|
|
|
#define KEX_COOKIE_LEN 16 |
#define KEX_COOKIE_LEN 16 |
|
|
/* Use privilege separation for sshd */ |
|
int use_privsep; |
|
struct monitor *pmonitor; |
|
|
|
|
|
/* prototype */ |
/* prototype */ |
static void kex_kexinit_finish(Kex *); |
static void kex_kexinit_finish(Kex *); |
static void kex_choose_conf(Kex *); |
static void kex_choose_conf(Kex *); |
|
|
|
|
/* parse buffer and return algorithm proposal */ |
/* parse buffer and return algorithm proposal */ |
static char ** |
static char ** |
kex_buf2prop(Buffer *raw) |
kex_buf2prop(Buffer *raw, int *first_kex_follows) |
{ |
{ |
Buffer b; |
Buffer b; |
int i; |
int i; |
|
|
} |
} |
/* first kex follows / reserved */ |
/* first kex follows / reserved */ |
i = buffer_get_char(&b); |
i = buffer_get_char(&b); |
|
if (first_kex_follows != NULL) |
|
*first_kex_follows = i; |
debug2("kex_parse_kexinit: first_kex_follows %d ", i); |
debug2("kex_parse_kexinit: first_kex_follows %d ", i); |
i = buffer_get_int(&b); |
i = buffer_get_int(&b); |
debug2("kex_parse_kexinit: reserved %d ", i); |
debug2("kex_parse_kexinit: reserved %d ", i); |
|
|
/* packet_write_wait(); */ |
/* packet_write_wait(); */ |
debug("SSH2_MSG_NEWKEYS sent"); |
debug("SSH2_MSG_NEWKEYS sent"); |
|
|
debug("waiting for SSH2_MSG_NEWKEYS"); |
debug("expecting SSH2_MSG_NEWKEYS"); |
packet_read_expect(SSH2_MSG_NEWKEYS); |
packet_read_expect(SSH2_MSG_NEWKEYS); |
packet_check_eom(); |
packet_check_eom(); |
debug("SSH2_MSG_NEWKEYS received"); |
debug("SSH2_MSG_NEWKEYS received"); |
|
|
|
|
kex_choose_conf(kex); |
kex_choose_conf(kex); |
|
|
switch (kex->kex_type) { |
if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && |
case DH_GRP1_SHA1: |
kex->kex[kex->kex_type] != NULL) { |
kexdh(kex); |
(kex->kex[kex->kex_type])(kex); |
break; |
} else { |
case DH_GEX_SHA1: |
|
kexgex(kex); |
|
break; |
|
default: |
|
fatal("Unsupported key exchange %d", kex->kex_type); |
fatal("Unsupported key exchange %d", kex->kex_type); |
} |
} |
} |
} |
|
|
if (k->name == NULL) |
if (k->name == NULL) |
fatal("no kex alg"); |
fatal("no kex alg"); |
if (strcmp(k->name, KEX_DH1) == 0) { |
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) { |
} else if (strcmp(k->name, KEX_DHGEX) == 0) { |
k->kex_type = DH_GEX_SHA1; |
k->kex_type = KEX_DH_GEX_SHA1; |
} else |
} else |
fatal("bad kex alg %s", k->name); |
fatal("bad kex alg %s", k->name); |
} |
} |
|
|
xfree(hostkeyalg); |
xfree(hostkeyalg); |
} |
} |
|
|
|
static int |
|
proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) |
|
{ |
|
static int check[] = { |
|
PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 |
|
}; |
|
int *idx; |
|
char *p; |
|
|
|
for (idx = &check[0]; *idx != -1; idx++) { |
|
if ((p = strchr(my[*idx], ',')) != NULL) |
|
*p = '\0'; |
|
if ((p = strchr(peer[*idx], ',')) != NULL) |
|
*p = '\0'; |
|
if (strcmp(my[*idx], peer[*idx]) != 0) { |
|
debug2("proposal mismatch: my %s peer %s", |
|
my[*idx], peer[*idx]); |
|
return (0); |
|
} |
|
} |
|
debug2("proposals match"); |
|
return (1); |
|
} |
|
|
static void |
static void |
kex_choose_conf(Kex *kex) |
kex_choose_conf(Kex *kex) |
{ |
{ |
|
|
int mode; |
int mode; |
int ctos; /* direction: if true client-to-server */ |
int ctos; /* direction: if true client-to-server */ |
int need; |
int need; |
|
int first_kex_follows, type; |
|
|
my = kex_buf2prop(&kex->my); |
my = kex_buf2prop(&kex->my, NULL); |
peer = kex_buf2prop(&kex->peer); |
peer = kex_buf2prop(&kex->peer, &first_kex_follows); |
|
|
if (kex->server) { |
if (kex->server) { |
cprop=peer; |
cprop=peer; |
|
|
/* XXX need runden? */ |
/* XXX need runden? */ |
kex->we_need = need; |
kex->we_need = need; |
|
|
|
/* ignore the next message if the proposals do not match */ |
|
if (first_kex_follows && !proposals_match(my, peer) && |
|
!(datafellows & SSH_BUG_FIRSTKEX)) { |
|
type = packet_read(); |
|
debug2("skipping next packet (type %u)", type); |
|
} |
|
|
kex_prop_free(my); |
kex_prop_free(my); |
kex_prop_free(peer); |
kex_prop_free(peer); |
} |
} |
|
|
for (i = 0; i < NKEYS; i++) |
for (i = 0; i < NKEYS; i++) |
keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); |
keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); |
|
|
debug("kex_derive_keys"); |
debug2("kex_derive_keys"); |
for (mode = 0; mode < MODE_MAX; mode++) { |
for (mode = 0; mode < MODE_MAX; mode++) { |
current_keys[mode] = kex->newkeys[mode]; |
current_keys[mode] = kex->newkeys[mode]; |
kex->newkeys[mode] = NULL; |
kex->newkeys[mode] = NULL; |