=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/kex.c,v retrieving revision 1.12.2.6 retrieving revision 1.13 diff -u -r1.12.2.6 -r1.13 --- src/usr.bin/ssh/kex.c 2002/03/08 17:04:42 1.12.2.6 +++ src/usr.bin/ssh/kex.c 2000/11/12 19:50:37 1.13 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2000 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,244 +23,411 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.12.2.6 2002/03/08 17:04:42 brad Exp $"); +RCSID("$OpenBSD: kex.c,v 1.13 2000/11/12 19:50:37 markus Exp $"); -#include - +#include "ssh.h" #include "ssh2.h" #include "xmalloc.h" #include "buffer.h" #include "bufaux.h" #include "packet.h" #include "compat.h" -#include "cipher.h" + +#include +#include + +#include +#include +#include +#include +#include + #include "kex.h" #include "key.h" -#include "log.h" -#include "mac.h" -#include "match.h" -#include "dispatch.h" #define KEX_COOKIE_LEN 16 -/* prototype */ -static void kex_kexinit_finish(Kex *); -static void kex_choose_conf(Kex *); - -/* put algorithm proposal into buffer */ -static void -kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) +Buffer * +kex_init(char *myproposal[PROPOSAL_MAX]) { + int first_kex_packet_follows = 0; + unsigned char cookie[KEX_COOKIE_LEN]; u_int32_t rand = 0; int i; - - buffer_clear(b); + Buffer *ki = xmalloc(sizeof(*ki)); for (i = 0; i < KEX_COOKIE_LEN; i++) { if (i % 4 == 0) rand = arc4random(); - buffer_put_char(b, rand & 0xff); + cookie[i] = rand & 0xff; rand >>= 8; } + buffer_init(ki); + buffer_append(ki, (char *)cookie, sizeof cookie); for (i = 0; i < PROPOSAL_MAX; i++) - buffer_put_cstring(b, proposal[i]); - buffer_put_char(b, 0); /* first_kex_packet_follows */ - buffer_put_int(b, 0); /* uint32 reserved */ + buffer_put_cstring(ki, myproposal[i]); + buffer_put_char(ki, first_kex_packet_follows); + buffer_put_int(ki, 0); /* uint32 reserved */ + return ki; } -/* parse buffer and return algorithm proposal */ -static char ** -kex_buf2prop(Buffer *raw) +/* send kexinit, parse and save reply */ +void +kex_exchange_kexinit( + Buffer *my_kexinit, Buffer *peer_kexint, + char *peer_proposal[PROPOSAL_MAX]) { - Buffer b; int i; - char **proposal; + char *ptr; + int plen; - proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); + debug("send KEXINIT"); + packet_start(SSH2_MSG_KEXINIT); + packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit)); + packet_send(); + packet_write_wait(); + debug("done"); - buffer_init(&b); - buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); + /* + * read and save raw KEXINIT payload in buffer. this is used during + * computation of the session_id and the session keys. + */ + debug("wait KEXINIT"); + packet_read_expect(&plen, SSH2_MSG_KEXINIT); + ptr = packet_get_raw(&plen); + buffer_append(peer_kexint, ptr, plen); + + /* parse packet and save algorithm proposal */ /* skip cookie */ for (i = 0; i < KEX_COOKIE_LEN; i++) - buffer_get_char(&b); + packet_get_char(); /* extract kex init proposal strings */ for (i = 0; i < PROPOSAL_MAX; i++) { - proposal[i] = buffer_get_string(&b,NULL); - debug2("kex_parse_kexinit: %s", proposal[i]); + peer_proposal[i] = packet_get_string(NULL); + debug("got kexinit: %s", peer_proposal[i]); } - /* first kex follows / reserved */ - i = buffer_get_char(&b); - debug2("kex_parse_kexinit: first_kex_follows %d ", i); - i = buffer_get_int(&b); - debug2("kex_parse_kexinit: reserved %d ", i); - buffer_free(&b); - return proposal; + /* first kex follow / reserved */ + i = packet_get_char(); + debug("first kex follow: %d ", i); + i = packet_get_int(); + debug("reserved: %d ", i); + packet_done(); + debug("done"); } -static void -kex_prop_free(char **proposal) +/* diffie-hellman-group1-sha1 */ + +int +dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) { int i; + int n = BN_num_bits(dh_pub); + int bits_set = 0; - for (i = 0; i < PROPOSAL_MAX; i++) - xfree(proposal[i]); - xfree(proposal); + if (dh_pub->neg) { + log("invalid public DH value: negativ"); + return 0; + } + for (i = 0; i <= n; i++) + if (BN_is_bit_set(dh_pub, i)) + bits_set++; + debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); + + /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ + if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) + return 1; + log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); + return 0; } -static void -kex_protocol_error(int type, u_int32_t seq, void *ctxt) +DH * +dh_gen_key(DH *dh) { - error("Hm, kex protocol error: type %d seq %u", type, seq); + int tries = 0; + + do { + if (DH_generate_key(dh) == 0) + fatal("DH_generate_key"); + if (tries++ > 10) + fatal("dh_new_group1: too many bad keys: giving up"); + } while (!dh_pub_is_valid(dh, dh->pub_key)); + return dh; } -static void -kex_reset_dispatch(void) +DH * +dh_new_group_asc(const char *gen, const char *modulus) { - dispatch_range(SSH2_MSG_TRANSPORT_MIN, - SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); - dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); + DH *dh; + int ret; + + dh = DH_new(); + if (dh == NULL) + fatal("DH_new"); + + if ((ret = BN_hex2bn(&dh->p, modulus)) < 0) + fatal("BN_hex2bn p"); + if ((ret = BN_hex2bn(&dh->g, gen)) < 0) + fatal("BN_hex2bn g"); + + return (dh_gen_key(dh)); } -void -kex_finish(Kex *kex) +DH * +dh_new_group(BIGNUM *gen, BIGNUM *modulus) { - kex_reset_dispatch(); + DH *dh; - packet_start(SSH2_MSG_NEWKEYS); - packet_send(); - /* packet_write_wait(); */ - debug("SSH2_MSG_NEWKEYS sent"); + dh = DH_new(); + if (dh == NULL) + fatal("DH_new"); + dh->p = modulus; + dh->g = gen; - debug("waiting for SSH2_MSG_NEWKEYS"); - packet_read_expect(SSH2_MSG_NEWKEYS); - packet_check_eom(); - debug("SSH2_MSG_NEWKEYS received"); + return (dh_gen_key(dh)); +} - kex->done = 1; - buffer_clear(&kex->peer); - /* buffer_clear(&kex->my); */ - kex->flags &= ~KEX_INIT_SENT; - xfree(kex->name); - kex->name = NULL; +DH * +dh_new_group1() +{ + static char *gen = "2", *group1 = + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" + "FFFFFFFF" "FFFFFFFF"; + + return (dh_new_group_asc(gen, group1)); } void -kex_send_kexinit(Kex *kex) +dump_digest(unsigned char *digest, int len) { - if (kex == NULL) { - error("kex_send_kexinit: no kex, cannot rekey"); - return; + int i; + for (i = 0; i< len; i++){ + fprintf(stderr, "%02x", digest[i]); + if(i%2!=0) + fprintf(stderr, " "); } - if (kex->flags & KEX_INIT_SENT) { - debug("KEX_INIT_SENT"); - return; - } - kex->done = 0; - packet_start(SSH2_MSG_KEXINIT); - packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); - packet_send(); - debug("SSH2_MSG_KEXINIT sent"); - kex->flags |= KEX_INIT_SENT; + fprintf(stderr, "\n"); } -void -kex_input_kexinit(int type, u_int32_t seq, void *ctxt) +unsigned char * +kex_hash( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + char *serverhostkeyblob, int sbloblen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret) { - char *ptr; - int dlen; - int i; - Kex *kex = (Kex *)ctxt; + Buffer b; + static unsigned char digest[EVP_MAX_MD_SIZE]; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; - debug("SSH2_MSG_KEXINIT received"); - if (kex == NULL) - fatal("kex_input_kexinit: no kex, cannot rekey"); + buffer_init(&b); + buffer_put_string(&b, client_version_string, strlen(client_version_string)); + buffer_put_string(&b, server_version_string, strlen(server_version_string)); - ptr = packet_get_raw(&dlen); - buffer_append(&kex->peer, ptr, dlen); + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); - /* discard packet */ - for (i = 0; i < KEX_COOKIE_LEN; i++) - packet_get_char(); - for (i = 0; i < PROPOSAL_MAX; i++) - xfree(packet_get_string(NULL)); - packet_get_char(); - packet_get_int(); - packet_check_eom(); + buffer_put_string(&b, serverhostkeyblob, sbloblen); + buffer_put_bignum2(&b, client_dh_pub); + buffer_put_bignum2(&b, server_dh_pub); + buffer_put_bignum2(&b, shared_secret); + +#ifdef DEBUG_KEX + buffer_dump(&b); +#endif - kex_kexinit_finish(kex); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEX + dump_digest(digest, evp_md->md_size); +#endif + return digest; } -Kex * -kex_setup(char *proposal[PROPOSAL_MAX]) +unsigned char * +kex_hash_gex( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + char *serverhostkeyblob, int sbloblen, + int minbits, BIGNUM *prime, BIGNUM *gen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret) { - Kex *kex; + Buffer b; + static unsigned char digest[EVP_MAX_MD_SIZE]; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; - kex = xmalloc(sizeof(*kex)); - memset(kex, 0, sizeof(*kex)); - buffer_init(&kex->peer); - buffer_init(&kex->my); - kex_prop2buf(&kex->my, proposal); - kex->done = 0; + buffer_init(&b); + buffer_put_string(&b, client_version_string, strlen(client_version_string)); + buffer_put_string(&b, server_version_string, strlen(server_version_string)); - kex_send_kexinit(kex); /* we start */ - kex_reset_dispatch(); + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); - return kex; + buffer_put_string(&b, serverhostkeyblob, sbloblen); + buffer_put_int(&b, minbits); + buffer_put_bignum2(&b, prime); + buffer_put_bignum2(&b, gen); + buffer_put_bignum2(&b, client_dh_pub); + buffer_put_bignum2(&b, server_dh_pub); + buffer_put_bignum2(&b, shared_secret); + +#ifdef DEBUG_KEX + buffer_dump(&b); +#endif + + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEX + dump_digest(digest, evp_md->md_size); +#endif + return digest; } -static void -kex_kexinit_finish(Kex *kex) +unsigned char * +derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret) { - if (!(kex->flags & KEX_INIT_SENT)) - kex_send_kexinit(kex); + Buffer b; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + char c = id; + int have; + int mdsz = evp_md->md_size; + unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); - kex_choose_conf(kex); + buffer_init(&b); + buffer_put_bignum2(&b, shared_secret); - switch (kex->kex_type) { - case DH_GRP1_SHA1: - kexdh(kex); - break; - case DH_GEX_SHA1: - kexgex(kex); - break; - default: - fatal("Unsupported key exchange %d", kex->kex_type); + EVP_DigestInit(&md, evp_md); + 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_DigestFinal(&md, digest, NULL); + + /* expand */ + for (have = mdsz; need > have; have += mdsz) { + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestUpdate(&md, hash, mdsz); + EVP_DigestUpdate(&md, digest, have); + EVP_DigestFinal(&md, digest + have, NULL); } + buffer_free(&b); +#ifdef DEBUG_KEX + fprintf(stderr, "Digest '%c'== ", c); + dump_digest(digest, need); +#endif + return digest; } -static void +#define NKEYS 6 + +#define MAX_PROP 20 +#define SEP "," + +char * +get_match(char *client, char *server) +{ + char *sproposals[MAX_PROP]; + char *c, *s, *p, *ret, *cp, *sp; + int i, j, nproposals; + + c = cp = xstrdup(client); + s = sp = xstrdup(server); + + for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&sp, SEP)), i++) { + if (i < MAX_PROP) + sproposals[i] = p; + else + break; + } + nproposals = i; + + for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&cp, SEP)), i++) { + for (j = 0; j < nproposals; j++) { + if (strcmp(p, sproposals[j]) == 0) { + ret = xstrdup(p); + xfree(c); + xfree(s); + return ret; + } + } + } + xfree(c); + xfree(s); + return NULL; +} +void choose_enc(Enc *enc, char *client, char *server) { - char *name = match_list(client, server, NULL); + char *name = get_match(client, server); if (name == NULL) fatal("no matching cipher found: client %s server %s", client, server); - if ((enc->cipher = cipher_by_name(name)) == NULL) + enc->cipher = cipher_by_name(name); + if (enc->cipher == NULL) fatal("matching cipher is not supported: %s", name); enc->name = name; enc->enabled = 0; enc->iv = NULL; enc->key = NULL; - enc->key_len = cipher_keylen(enc->cipher); - enc->block_size = cipher_blocksize(enc->cipher); } -static void +void choose_mac(Mac *mac, char *client, char *server) { - char *name = match_list(client, server, NULL); + char *name = get_match(client, server); if (name == NULL) fatal("no matching mac found: client %s server %s", client, server); - if (mac_init(mac, name) < 0) + if (strcmp(name, "hmac-md5") == 0) { + mac->md = EVP_md5(); + } else if (strcmp(name, "hmac-sha1") == 0) { + mac->md = EVP_sha1(); + } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) { + mac->md = EVP_ripemd160(); + } else { fatal("unsupported mac %s", name); - /* truncate the key */ - if (datafellows & SSH_BUG_HMAC) - mac->key_len = 16; + } mac->name = name; + mac->mac_len = mac->md->md_size; + mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len; mac->key = NULL; mac->enabled = 0; } -static void +void choose_comp(Comp *comp, char *client, char *server) { - char *name = match_list(client, server, NULL); + char *name = get_match(client, server); if (name == NULL) fatal("no matching comp found: client %s server %s", client, server); if (strcmp(name, "zlib") == 0) { @@ -272,10 +439,10 @@ } comp->name = name; } -static void +void choose_kex(Kex *k, char *client, char *server) { - k->name = match_list(client, server, NULL); + k->name = get_match(client, server); if (k->name == NULL) fatal("no kex alg"); if (strcmp(k->name, KEX_DH1) == 0) { @@ -285,169 +452,77 @@ } else fatal("bad kex alg %s", k->name); } -static void +void choose_hostkeyalg(Kex *k, char *client, char *server) { - char *hostkeyalg = match_list(client, server, NULL); + char *hostkeyalg = get_match(client, server); if (hostkeyalg == NULL) fatal("no hostkey alg"); k->hostkey_type = key_type_from_name(hostkeyalg); if (k->hostkey_type == KEY_UNSPEC) fatal("bad hostkey alg '%s'", hostkeyalg); - xfree(hostkeyalg); } -static void -kex_choose_conf(Kex *kex) +Kex * +kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server) { - Newkeys *newkeys; - char **my, **peer; - char **cprop, **sprop; - int nenc, nmac, ncomp; int mode; int ctos; /* direction: if true client-to-server */ int need; + Kex *k; - my = kex_buf2prop(&kex->my); - peer = kex_buf2prop(&kex->peer); + k = xmalloc(sizeof(*k)); + memset(k, 0, sizeof(*k)); + k->server = server; - if (kex->server) { - cprop=peer; - sprop=my; - } else { - cprop=my; - sprop=peer; - } - - /* Algorithm Negotiation */ for (mode = 0; mode < MODE_MAX; mode++) { - newkeys = xmalloc(sizeof(*newkeys)); - memset(newkeys, 0, sizeof(*newkeys)); - kex->newkeys[mode] = newkeys; - ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); + int nenc, nmac, ncomp; + ctos = (!k->server && mode == MODE_OUT) || (k->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 (&newkeys->enc, cprop[nenc], sprop[nenc]); - choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); - choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); + 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]); debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", - newkeys->enc.name, - newkeys->mac.name, - newkeys->comp.name); + k->enc[mode].name, + k->mac[mode].name, + k->comp[mode].name); } - choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); - choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], + choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); + choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); need = 0; for (mode = 0; mode < MODE_MAX; mode++) { - newkeys = kex->newkeys[mode]; - if (need < newkeys->enc.key_len) - need = newkeys->enc.key_len; - if (need < newkeys->enc.block_size) - need = newkeys->enc.block_size; - if (need < newkeys->mac.key_len) - need = newkeys->mac.key_len; + 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; } /* XXX need runden? */ - kex->we_need = need; - - kex_prop_free(my); - kex_prop_free(peer); + k->we_need = need; + return k; } -static u_char * -derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) +int +kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret) { - Buffer b; - const EVP_MD *evp_md = EVP_sha1(); - EVP_MD_CTX md; - char c = id; - int have; - int mdsz = EVP_MD_size(evp_md); - u_char *digest = xmalloc(roundup(need, mdsz)); + int i; + int mode; + int ctos; + unsigned char *keys[NKEYS]; - buffer_init(&b); - buffer_put_bignum2(&b, shared_secret); - - /* K1 = HASH(K || H || "A" || session_id) */ - EVP_DigestInit(&md, evp_md); - if (!(datafellows & SSH_BUG_DERIVEKEY)) - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestUpdate(&md, hash, mdsz); - EVP_DigestUpdate(&md, &c, 1); - EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); - EVP_DigestFinal(&md, digest, NULL); - - /* - * expand key: - * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) - * Key = K1 || K2 || ... || Kn - */ - for (have = mdsz; need > have; have += mdsz) { - EVP_DigestInit(&md, evp_md); - if (!(datafellows & SSH_BUG_DERIVEKEY)) - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestUpdate(&md, hash, mdsz); - EVP_DigestUpdate(&md, digest, have); - EVP_DigestFinal(&md, digest + have, NULL); - } - buffer_free(&b); -#ifdef DEBUG_KEX - fprintf(stderr, "key '%c'== ", c); - dump_digest("key", digest, need); -#endif - return digest; -} - -Newkeys *current_keys[MODE_MAX]; - -#define NKEYS 6 -void -kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) -{ - u_char *keys[NKEYS]; - int i, mode, ctos; - for (i = 0; i < NKEYS; i++) - keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); + keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret); - debug("kex_derive_keys"); for (mode = 0; mode < MODE_MAX; mode++) { - current_keys[mode] = kex->newkeys[mode]; - kex->newkeys[mode] = NULL; - ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); - current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; - current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; - current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; + 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]; } + return 0; } - -Newkeys * -kex_get_newkeys(int mode) -{ - Newkeys *ret; - - ret = current_keys[mode]; - current_keys[mode] = NULL; - return ret; -} - -#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) -void -dump_digest(char *msg, u_char *digest, int len) -{ - int i; - - fprintf(stderr, "%s\n", msg); - for (i = 0; i< len; i++) { - fprintf(stderr, "%02x", digest[i]); - if (i%32 == 31) - fprintf(stderr, "\n"); - else if (i%8 == 7) - fprintf(stderr, " "); - } - fprintf(stderr, "\n"); -} -#endif