version 1.1, 2001/04/03 19:53:29 |
version 1.2, 2001/04/03 23:32:12 |
|
|
#include "key.h" |
#include "key.h" |
#include "kex.h" |
#include "kex.h" |
#include "log.h" |
#include "log.h" |
#include "dispatch.h" |
|
#include "packet.h" |
#include "packet.h" |
#include "dh.h" |
#include "dh.h" |
#include "ssh2.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 * |
u_char * |
kex_dh_hash( |
kex_dh_hash( |
char *client_version_string, |
char *client_version_string, |
|
|
void |
void |
kexdh_client(Kex *kex) |
kexdh_client(Kex *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; |
|
|
dispatch_set(SSH2_MSG_KEXDH_REPLY, &kexdh_input_reply); |
|
|
|
state = xmalloc(sizeof(State)); |
|
kex->state = state; |
|
|
|
/* generate and send 'e', client DH public key */ |
/* generate and send 'e', client DH public key */ |
state->dh = dh_new_group1(); |
dh = dh_new_group1(); |
dh_gen_key(state->dh, kex->we_need * 8); |
dh_gen_key(dh, kex->we_need * 8); |
packet_start(SSH2_MSG_KEXDH_INIT); |
packet_start(SSH2_MSG_KEXDH_INIT); |
packet_put_bignum2(state->dh->pub_key); |
packet_put_bignum2(dh->pub_key); |
packet_send(); |
packet_send(); |
|
|
debug("SSH2_MSG_KEXDH_INIT sent"); |
debug("sending SSH2_MSG_KEXDH_INIT"); |
#ifdef DEBUG_KEXDH |
#ifdef DEBUG_KEXDH |
DHparams_print_fp(stderr, state->dh); |
DHparams_print_fp(stderr, dh); |
fprintf(stderr, "pub= "); |
fprintf(stderr, "pub= "); |
BN_print_fp(stderr, state->dh->pub_key); |
BN_print_fp(stderr, dh->pub_key); |
fprintf(stderr, "\n"); |
fprintf(stderr, "\n"); |
#endif |
#endif |
} |
|
|
|
void |
debug("expecting SSH2_MSG_KEXDH_REPLY"); |
kexdh_input_reply(int type, int plen, void *ctxt) |
packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY); |
{ |
|
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); |
|
|
|
/* key, cert */ |
/* key, cert */ |
server_host_key_blob = packet_get_string(&sbloblen); |
server_host_key_blob = packet_get_string(&sbloblen); |
server_host_key = key_from_blob(server_host_key_blob, sbloblen); |
server_host_key = key_from_blob(server_host_key_blob, sbloblen); |
|
|
signature = packet_get_string(&slen); |
signature = packet_get_string(&slen); |
packet_done(); |
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"); |
packet_disconnect("bad server public DH value"); |
|
|
klen = DH_size(state->dh); |
klen = DH_size(dh); |
kbuf = xmalloc(klen); |
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 |
#ifdef DEBUG_KEXDH |
dump_digest("shared secret", kbuf, kout); |
dump_digest("shared secret", kbuf, kout); |
#endif |
#endif |
|
|
buffer_ptr(&kex->my), buffer_len(&kex->my), |
buffer_ptr(&kex->my), buffer_len(&kex->my), |
buffer_ptr(&kex->peer), buffer_len(&kex->peer), |
buffer_ptr(&kex->peer), buffer_len(&kex->peer), |
server_host_key_blob, sbloblen, |
server_host_key_blob, sbloblen, |
state->dh->pub_key, |
dh->pub_key, |
dh_server_pub, |
dh_server_pub, |
shared_secret |
shared_secret |
); |
); |
xfree(server_host_key_blob); |
xfree(server_host_key_blob); |
DH_free(state->dh); |
DH_free(dh); |
BN_free(dh_server_pub); |
BN_free(dh_server_pub); |
|
|
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) |
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) |
|
|
key_free(server_host_key); |
key_free(server_host_key); |
xfree(signature); |
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); |
kex_derive_keys(kex, hash, shared_secret); |
BN_clear_free(shared_secret); |
BN_clear_free(shared_secret); |
packet_set_kex(kex); |
|
kex_send_newkeys(); |
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 */ |
/* server */ |
|
|
void |
void |
kexdh_server(Kex *kex) |
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; |
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; |
|
DH *dh; |
Key *server_host_key; |
Key *server_host_key; |
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; |
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; |
u_int sbloblen, klen, kout; |
u_int sbloblen, klen, kout; |
int dlen, slen; |
int dlen, slen, plen; |
Kex *kex = (Kex*) ctxt; |
|
State *state = (State*) kex->state; |
|
DH *dh = state->dh; |
|
|
|
debug("SSH2_MSG_KEXDH_INIT received"); |
/* generate server DH public key */ |
dispatch_set(SSH2_MSG_KEXDH_INIT, &kex_protocol_error); |
dh = dh_new_group1(); |
|
dh_gen_key(dh, kex->we_need * 8); |
|
|
|
debug("expecting SSH2_MSG_KEXDH_INIT"); |
|
packet_read_expect(&plen, SSH2_MSG_KEXDH_INIT); |
|
|
if (kex->load_host_key == NULL) |
if (kex->load_host_key == NULL) |
fatal("Cannot load hostkey"); |
fatal("Cannot load hostkey"); |
server_host_key = kex->load_host_key(kex->hostkey_type); |
server_host_key = kex->load_host_key(kex->hostkey_type); |
|
|
|
|
/* save session id := H */ |
/* save session id := H */ |
/* XXX hashlen depends on KEX */ |
/* XXX hashlen depends on KEX */ |
session_id2_len = 20; |
if (kex->session_id == NULL) { |
session_id2 = xmalloc(session_id2_len); |
kex->session_id_len = 20; |
memcpy(session_id2, hash, session_id2_len); |
kex->session_id = xmalloc(kex->session_id_len); |
|
memcpy(kex->session_id, hash, kex->session_id_len); |
|
} |
|
|
/* sign H */ |
/* sign H */ |
/* XXX hashlen depends on KEX */ |
/* XXX hashlen depends on KEX */ |
|
|
|
|
kex_derive_keys(kex, hash, shared_secret); |
kex_derive_keys(kex, hash, shared_secret); |
BN_clear_free(shared_secret); |
BN_clear_free(shared_secret); |
packet_set_kex(kex); |
|
kex_send_newkeys(); |
kex_send_newkeys(); |
|
|
/* have keys, free DH */ |
/* have keys, free DH */ |
DH_free(dh); |
DH_free(dh); |
xfree(state); |
|
kex->state = NULL; |
|
} |
} |
|
|
void |
void |