version 1.36, 2001/06/25 08:25:37 |
version 1.36.2.2, 2002/05/17 00:03:23 |
|
|
#include "mac.h" |
#include "mac.h" |
#include "match.h" |
#include "match.h" |
#include "dispatch.h" |
#include "dispatch.h" |
|
#include "monitor.h" |
|
|
#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 *); |
|
|
static void |
static void |
kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) |
kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) |
{ |
{ |
u_int32_t rand = 0; |
|
int i; |
int i; |
|
|
buffer_clear(b); |
buffer_clear(b); |
for (i = 0; i < KEX_COOKIE_LEN; i++) { |
/* |
if (i % 4 == 0) |
* add a dummy cookie, the cookie will be overwritten by |
rand = arc4random(); |
* kex_send_kexinit(), each time a kexinit is set |
buffer_put_char(b, rand & 0xff); |
*/ |
rand >>= 8; |
for (i = 0; i < KEX_COOKIE_LEN; i++) |
} |
buffer_put_char(b, 0); |
for (i = 0; i < PROPOSAL_MAX; i++) |
for (i = 0; i < PROPOSAL_MAX; i++) |
buffer_put_cstring(b, proposal[i]); |
buffer_put_cstring(b, proposal[i]); |
buffer_put_char(b, 0); /* first_kex_packet_follows */ |
buffer_put_char(b, 0); /* first_kex_packet_follows */ |
|
|
} |
} |
|
|
static void |
static void |
kex_protocol_error(int type, int plen, void *ctxt) |
kex_protocol_error(int type, u_int32_t seq, void *ctxt) |
{ |
{ |
error("Hm, kex protocol error: type %d plen %d", type, plen); |
error("Hm, kex protocol error: type %d seq %u", type, seq); |
} |
} |
|
|
static void |
static void |
kex_clear_dispatch(void) |
kex_reset_dispatch(void) |
{ |
{ |
int i; |
dispatch_range(SSH2_MSG_TRANSPORT_MIN, |
|
SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); |
/* Numbers 30-49 are used for kex packets */ |
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); |
for (i = 30; i <= 49; i++) |
|
dispatch_set(i, &kex_protocol_error); |
|
} |
} |
|
|
void |
void |
kex_finish(Kex *kex) |
kex_finish(Kex *kex) |
{ |
{ |
int plen; |
kex_reset_dispatch(); |
|
|
kex_clear_dispatch(); |
|
|
|
packet_start(SSH2_MSG_NEWKEYS); |
packet_start(SSH2_MSG_NEWKEYS); |
packet_send(); |
packet_send(); |
/* packet_write_wait(); */ |
/* packet_write_wait(); */ |
debug("SSH2_MSG_NEWKEYS sent"); |
debug("SSH2_MSG_NEWKEYS sent"); |
|
|
debug("waiting for SSH2_MSG_NEWKEYS"); |
debug("waiting for SSH2_MSG_NEWKEYS"); |
packet_read_expect(&plen, SSH2_MSG_NEWKEYS); |
packet_read_expect(SSH2_MSG_NEWKEYS); |
|
packet_check_eom(); |
debug("SSH2_MSG_NEWKEYS received"); |
debug("SSH2_MSG_NEWKEYS received"); |
|
|
kex->done = 1; |
kex->done = 1; |
|
|
void |
void |
kex_send_kexinit(Kex *kex) |
kex_send_kexinit(Kex *kex) |
{ |
{ |
|
u_int32_t rand = 0; |
|
u_char *cookie; |
|
int i; |
|
|
if (kex == NULL) { |
if (kex == NULL) { |
error("kex_send_kexinit: no kex, cannot rekey"); |
error("kex_send_kexinit: no kex, cannot rekey"); |
return; |
return; |
|
|
return; |
return; |
} |
} |
kex->done = 0; |
kex->done = 0; |
|
|
|
/* generate a random cookie */ |
|
if (buffer_len(&kex->my) < KEX_COOKIE_LEN) |
|
fatal("kex_send_kexinit: kex proposal too short"); |
|
cookie = buffer_ptr(&kex->my); |
|
for (i = 0; i < KEX_COOKIE_LEN; i++) { |
|
if (i % 4 == 0) |
|
rand = arc4random(); |
|
cookie[i] = rand; |
|
rand >>= 8; |
|
} |
packet_start(SSH2_MSG_KEXINIT); |
packet_start(SSH2_MSG_KEXINIT); |
packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); |
packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); |
packet_send(); |
packet_send(); |
|
|
} |
} |
|
|
void |
void |
kex_input_kexinit(int type, int plen, void *ctxt) |
kex_input_kexinit(int type, u_int32_t seq, void *ctxt) |
{ |
{ |
char *ptr; |
char *ptr; |
int dlen; |
int dlen; |
|
|
xfree(packet_get_string(NULL)); |
xfree(packet_get_string(NULL)); |
packet_get_char(); |
packet_get_char(); |
packet_get_int(); |
packet_get_int(); |
packet_done(); |
packet_check_eom(); |
|
|
kex_kexinit_finish(kex); |
kex_kexinit_finish(kex); |
} |
} |
|
|
kex->done = 0; |
kex->done = 0; |
|
|
kex_send_kexinit(kex); /* we start */ |
kex_send_kexinit(kex); /* we start */ |
kex_clear_dispatch(); |
kex_reset_dispatch(); |
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); |
|
|
|
return kex; |
return kex; |
} |
} |
|
|
|
|
kex_choose_conf(kex); |
kex_choose_conf(kex); |
|
|
switch(kex->kex_type) { |
switch (kex->kex_type) { |
case DH_GRP1_SHA1: |
case DH_GRP1_SHA1: |
kexdh(kex); |
kexdh(kex); |
break; |
break; |
|
|
char *name = match_list(client, server, NULL); |
char *name = match_list(client, server, NULL); |
if (name == NULL) |
if (name == NULL) |
fatal("no matching cipher found: client %s server %s", client, server); |
fatal("no matching cipher found: client %s server %s", client, server); |
enc->cipher = cipher_by_name(name); |
if ((enc->cipher = cipher_by_name(name)) == NULL) |
if (enc->cipher == NULL) |
|
fatal("matching cipher is not supported: %s", name); |
fatal("matching cipher is not supported: %s", name); |
enc->name = name; |
enc->name = name; |
enc->enabled = 0; |
enc->enabled = 0; |
enc->iv = NULL; |
enc->iv = NULL; |
enc->key = NULL; |
enc->key = NULL; |
|
enc->key_len = cipher_keylen(enc->cipher); |
|
enc->block_size = cipher_blocksize(enc->cipher); |
} |
} |
static void |
static void |
choose_mac(Mac *mac, char *client, char *server) |
choose_mac(Mac *mac, char *client, char *server) |
|
|
need = 0; |
need = 0; |
for (mode = 0; mode < MODE_MAX; mode++) { |
for (mode = 0; mode < MODE_MAX; mode++) { |
newkeys = kex->newkeys[mode]; |
newkeys = kex->newkeys[mode]; |
if (need < newkeys->enc.cipher->key_len) |
if (need < newkeys->enc.key_len) |
need = newkeys->enc.cipher->key_len; |
need = newkeys->enc.key_len; |
if (need < newkeys->enc.cipher->block_size) |
if (need < newkeys->enc.block_size) |
need = newkeys->enc.cipher->block_size; |
need = newkeys->enc.block_size; |
if (need < newkeys->mac.key_len) |
if (need < newkeys->mac.key_len) |
need = newkeys->mac.key_len; |
need = newkeys->mac.key_len; |
} |
} |
|
|
derive_key(Kex *kex, 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; |
Buffer b; |
EVP_MD *evp_md = EVP_sha1(); |
const EVP_MD *evp_md = EVP_sha1(); |
EVP_MD_CTX md; |
EVP_MD_CTX md; |
char c = id; |
char c = id; |
int have; |
int have; |
int mdsz = evp_md->md_size; |
int mdsz = EVP_MD_size(evp_md); |
u_char *digest = xmalloc(roundup(need, mdsz)); |
u_char *digest = xmalloc(roundup(need, mdsz)); |
|
|
buffer_init(&b); |
buffer_init(&b); |
|
|
int i; |
int i; |
|
|
fprintf(stderr, "%s\n", msg); |
fprintf(stderr, "%s\n", msg); |
for (i = 0; i< len; i++){ |
for (i = 0; i< len; i++) { |
fprintf(stderr, "%02x", digest[i]); |
fprintf(stderr, "%02x", digest[i]); |
if (i%32 == 31) |
if (i%32 == 31) |
fprintf(stderr, "\n"); |
fprintf(stderr, "\n"); |