version 1.51.2.3, 2003/09/16 21:20:25 |
version 1.52, 2002/11/21 22:45:31 |
|
|
|
|
#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, int *first_kex_follows) |
kex_buf2prop(Buffer *raw) |
{ |
{ |
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); |
|
|
|
|
kex_choose_conf(kex); |
kex_choose_conf(kex); |
|
|
if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && |
switch (kex->kex_type) { |
kex->kex[kex->kex_type] != NULL) { |
case DH_GRP1_SHA1: |
(kex->kex[kex->kex_type])(kex); |
kexdh(kex); |
} else { |
break; |
|
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 = KEX_DH_GRP1_SHA1; |
k->kex_type = DH_GRP1_SHA1; |
} else if (strcmp(k->name, KEX_DHGEX) == 0) { |
} else if (strcmp(k->name, KEX_DHGEX) == 0) { |
k->kex_type = KEX_DH_GEX_SHA1; |
k->kex_type = 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, NULL); |
my = kex_buf2prop(&kex->my); |
peer = kex_buf2prop(&kex->peer, &first_kex_follows); |
peer = kex_buf2prop(&kex->peer); |
|
|
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); |