kex.c revision 162852
1162852Sdes/* $OpenBSD: kex.c,v 1.76 2006/08/03 03:34:42 deraadt Exp $ */ 260573Skris/* 392555Sdes * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 460573Skris * 560573Skris * Redistribution and use in source and binary forms, with or without 660573Skris * modification, are permitted provided that the following conditions 760573Skris * are met: 860573Skris * 1. Redistributions of source code must retain the above copyright 960573Skris * notice, this list of conditions and the following disclaimer. 1060573Skris * 2. Redistributions in binary form must reproduce the above copyright 1160573Skris * notice, this list of conditions and the following disclaimer in the 1260573Skris * documentation and/or other materials provided with the distribution. 1360573Skris * 1460573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1560573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1660573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1760573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1860573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1960573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2060573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2160573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2260573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2360573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2460573Skris */ 2560573Skris 2660573Skris#include "includes.h" 2760573Skris 28162852Sdes#include <sys/param.h> 29162852Sdes 30162852Sdes#include <signal.h> 31162852Sdes#include <stdarg.h> 32162852Sdes#include <stdio.h> 33162852Sdes#include <stdlib.h> 34162852Sdes#include <string.h> 35162852Sdes 3676259Sgreen#include <openssl/crypto.h> 3776259Sgreen 38162852Sdes#include "xmalloc.h" 3960573Skris#include "ssh2.h" 4060573Skris#include "buffer.h" 4161209Skris#include "packet.h" 4260573Skris#include "compat.h" 4376259Sgreen#include "cipher.h" 44162852Sdes#include "key.h" 4560573Skris#include "kex.h" 4676259Sgreen#include "log.h" 4776259Sgreen#include "mac.h" 4876259Sgreen#include "match.h" 4976259Sgreen#include "dispatch.h" 5098675Sdes#include "monitor.h" 5160573Skris 5261209Skris#define KEX_COOKIE_LEN 16 5361209Skris 54162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L 55162852Sdes# if defined(HAVE_EVP_SHA256) 56162852Sdes# define evp_ssh_sha256 EVP_sha256 57162852Sdes# else 58162852Sdesextern const EVP_MD *evp_ssh_sha256(void); 59162852Sdes# endif 60162852Sdes#endif 61162852Sdes 6292555Sdes/* prototype */ 6392555Sdesstatic void kex_kexinit_finish(Kex *); 6492555Sdesstatic void kex_choose_conf(Kex *); 6576259Sgreen 6676259Sgreen/* put algorithm proposal into buffer */ 6792555Sdesstatic void 6876259Sgreenkex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 6960573Skris{ 70149749Sdes u_int i; 7176259Sgreen 7276259Sgreen buffer_clear(b); 7398675Sdes /* 7498675Sdes * add a dummy cookie, the cookie will be overwritten by 7598675Sdes * kex_send_kexinit(), each time a kexinit is set 7698675Sdes */ 7798675Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) 7898675Sdes buffer_put_char(b, 0); 7960573Skris for (i = 0; i < PROPOSAL_MAX; i++) 8076259Sgreen buffer_put_cstring(b, proposal[i]); 8176259Sgreen buffer_put_char(b, 0); /* first_kex_packet_follows */ 8276259Sgreen buffer_put_int(b, 0); /* uint32 reserved */ 8360573Skris} 8460573Skris 8576259Sgreen/* parse buffer and return algorithm proposal */ 8692555Sdesstatic char ** 87113908Sdeskex_buf2prop(Buffer *raw, int *first_kex_follows) 8861209Skris{ 8976259Sgreen Buffer b; 9061209Skris int i; 9176259Sgreen char **proposal; 9261209Skris 93162852Sdes proposal = xcalloc(PROPOSAL_MAX, sizeof(char *)); 9461209Skris 9576259Sgreen buffer_init(&b); 9676259Sgreen buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 9761209Skris /* skip cookie */ 9861209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) 9976259Sgreen buffer_get_char(&b); 10061209Skris /* extract kex init proposal strings */ 10161209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 10276259Sgreen proposal[i] = buffer_get_string(&b,NULL); 10376259Sgreen debug2("kex_parse_kexinit: %s", proposal[i]); 10461209Skris } 10576259Sgreen /* first kex follows / reserved */ 10676259Sgreen i = buffer_get_char(&b); 107113908Sdes if (first_kex_follows != NULL) 108113908Sdes *first_kex_follows = i; 10976259Sgreen debug2("kex_parse_kexinit: first_kex_follows %d ", i); 11076259Sgreen i = buffer_get_int(&b); 11176259Sgreen debug2("kex_parse_kexinit: reserved %d ", i); 11276259Sgreen buffer_free(&b); 11376259Sgreen return proposal; 11461209Skris} 11561209Skris 11692555Sdesstatic void 11776259Sgreenkex_prop_free(char **proposal) 11860573Skris{ 119149749Sdes u_int i; 12060573Skris 12176259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 12276259Sgreen xfree(proposal[i]); 12376259Sgreen xfree(proposal); 12460573Skris} 12560573Skris 12692555Sdesstatic void 12792555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt) 12860573Skris{ 12992555Sdes error("Hm, kex protocol error: type %d seq %u", type, seq); 13060573Skris} 13160573Skris 13292555Sdesstatic void 13392555Sdeskex_reset_dispatch(void) 13469587Sgreen{ 13592555Sdes dispatch_range(SSH2_MSG_TRANSPORT_MIN, 13692555Sdes SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 13792555Sdes dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 13869587Sgreen} 13969587Sgreen 14076259Sgreenvoid 14176259Sgreenkex_finish(Kex *kex) 14269587Sgreen{ 14392555Sdes kex_reset_dispatch(); 14469587Sgreen 14576259Sgreen packet_start(SSH2_MSG_NEWKEYS); 14676259Sgreen packet_send(); 14776259Sgreen /* packet_write_wait(); */ 14876259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 14969587Sgreen 150113908Sdes debug("expecting SSH2_MSG_NEWKEYS"); 15192555Sdes packet_read_expect(SSH2_MSG_NEWKEYS); 15292555Sdes packet_check_eom(); 15376259Sgreen debug("SSH2_MSG_NEWKEYS received"); 15469587Sgreen 15576259Sgreen kex->done = 1; 15676259Sgreen buffer_clear(&kex->peer); 15776259Sgreen /* buffer_clear(&kex->my); */ 15876259Sgreen kex->flags &= ~KEX_INIT_SENT; 15976259Sgreen xfree(kex->name); 16076259Sgreen kex->name = NULL; 16169587Sgreen} 16269587Sgreen 16360573Skrisvoid 16476259Sgreenkex_send_kexinit(Kex *kex) 16560573Skris{ 166137015Sdes u_int32_t rnd = 0; 16798675Sdes u_char *cookie; 168149749Sdes u_int i; 16998675Sdes 17076259Sgreen if (kex == NULL) { 17176259Sgreen error("kex_send_kexinit: no kex, cannot rekey"); 17276259Sgreen return; 17360573Skris } 17476259Sgreen if (kex->flags & KEX_INIT_SENT) { 17576259Sgreen debug("KEX_INIT_SENT"); 17676259Sgreen return; 17776259Sgreen } 17876259Sgreen kex->done = 0; 17998675Sdes 18098675Sdes /* generate a random cookie */ 18198675Sdes if (buffer_len(&kex->my) < KEX_COOKIE_LEN) 18298675Sdes fatal("kex_send_kexinit: kex proposal too short"); 18398675Sdes cookie = buffer_ptr(&kex->my); 18498675Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) { 18598675Sdes if (i % 4 == 0) 186137015Sdes rnd = arc4random(); 187137015Sdes cookie[i] = rnd; 188137015Sdes rnd >>= 8; 18998675Sdes } 19076259Sgreen packet_start(SSH2_MSG_KEXINIT); 19176259Sgreen packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 19276259Sgreen packet_send(); 19376259Sgreen debug("SSH2_MSG_KEXINIT sent"); 19476259Sgreen kex->flags |= KEX_INIT_SENT; 19560573Skris} 19660573Skris 19776259Sgreenvoid 19892555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 19960573Skris{ 20076259Sgreen char *ptr; 201149749Sdes u_int i, dlen; 20276259Sgreen Kex *kex = (Kex *)ctxt; 20360573Skris 20476259Sgreen debug("SSH2_MSG_KEXINIT received"); 20576259Sgreen if (kex == NULL) 20676259Sgreen fatal("kex_input_kexinit: no kex, cannot rekey"); 20760573Skris 20876259Sgreen ptr = packet_get_raw(&dlen); 20976259Sgreen buffer_append(&kex->peer, ptr, dlen); 21060573Skris 21176259Sgreen /* discard packet */ 21276259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 21376259Sgreen packet_get_char(); 21476259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 21576259Sgreen xfree(packet_get_string(NULL)); 21699060Sdes (void) packet_get_char(); 21799060Sdes (void) packet_get_int(); 21892555Sdes packet_check_eom(); 21960573Skris 22076259Sgreen kex_kexinit_finish(kex); 22160573Skris} 22260573Skris 22376259SgreenKex * 22476259Sgreenkex_setup(char *proposal[PROPOSAL_MAX]) 22569587Sgreen{ 22676259Sgreen Kex *kex; 22769587Sgreen 228162852Sdes kex = xcalloc(1, sizeof(*kex)); 22976259Sgreen buffer_init(&kex->peer); 23076259Sgreen buffer_init(&kex->my); 23176259Sgreen kex_prop2buf(&kex->my, proposal); 23276259Sgreen kex->done = 0; 23369587Sgreen 23476259Sgreen kex_send_kexinit(kex); /* we start */ 23592555Sdes kex_reset_dispatch(); 23669587Sgreen 23776259Sgreen return kex; 23869587Sgreen} 23969587Sgreen 24092555Sdesstatic void 24176259Sgreenkex_kexinit_finish(Kex *kex) 24260573Skris{ 24376259Sgreen if (!(kex->flags & KEX_INIT_SENT)) 24476259Sgreen kex_send_kexinit(kex); 24560573Skris 24676259Sgreen kex_choose_conf(kex); 24760573Skris 248113908Sdes if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && 249113908Sdes kex->kex[kex->kex_type] != NULL) { 250113908Sdes (kex->kex[kex->kex_type])(kex); 251113908Sdes } else { 25276259Sgreen fatal("Unsupported key exchange %d", kex->kex_type); 25360573Skris } 25460573Skris} 25560573Skris 25692555Sdesstatic void 25760573Skrischoose_enc(Enc *enc, char *client, char *server) 25860573Skris{ 25976259Sgreen char *name = match_list(client, server, NULL); 26060573Skris if (name == NULL) 26160573Skris fatal("no matching cipher found: client %s server %s", client, server); 26292555Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) 26369587Sgreen fatal("matching cipher is not supported: %s", name); 26460573Skris enc->name = name; 26560573Skris enc->enabled = 0; 26660573Skris enc->iv = NULL; 26760573Skris enc->key = NULL; 26892555Sdes enc->key_len = cipher_keylen(enc->cipher); 26992555Sdes enc->block_size = cipher_blocksize(enc->cipher); 27060573Skris} 271162852Sdes 27292555Sdesstatic void 27360573Skrischoose_mac(Mac *mac, char *client, char *server) 27460573Skris{ 27576259Sgreen char *name = match_list(client, server, NULL); 27660573Skris if (name == NULL) 27760573Skris fatal("no matching mac found: client %s server %s", client, server); 27876259Sgreen if (mac_init(mac, name) < 0) 27960573Skris fatal("unsupported mac %s", name); 28076259Sgreen /* truncate the key */ 28176259Sgreen if (datafellows & SSH_BUG_HMAC) 28276259Sgreen mac->key_len = 16; 28360573Skris mac->name = name; 28460573Skris mac->key = NULL; 28560573Skris mac->enabled = 0; 28660573Skris} 287162852Sdes 28892555Sdesstatic void 28960573Skrischoose_comp(Comp *comp, char *client, char *server) 29060573Skris{ 29176259Sgreen char *name = match_list(client, server, NULL); 29260573Skris if (name == NULL) 29360573Skris fatal("no matching comp found: client %s server %s", client, server); 294149749Sdes if (strcmp(name, "zlib@openssh.com") == 0) { 295149749Sdes comp->type = COMP_DELAYED; 296149749Sdes } else if (strcmp(name, "zlib") == 0) { 297149749Sdes comp->type = COMP_ZLIB; 29860573Skris } else if (strcmp(name, "none") == 0) { 299149749Sdes comp->type = COMP_NONE; 30060573Skris } else { 30160573Skris fatal("unsupported comp %s", name); 30260573Skris } 30360573Skris comp->name = name; 30460573Skris} 305162852Sdes 30692555Sdesstatic void 30760573Skrischoose_kex(Kex *k, char *client, char *server) 30860573Skris{ 30976259Sgreen k->name = match_list(client, server, NULL); 31060573Skris if (k->name == NULL) 31160573Skris fatal("no kex alg"); 31269587Sgreen if (strcmp(k->name, KEX_DH1) == 0) { 313113908Sdes k->kex_type = KEX_DH_GRP1_SHA1; 314157016Sdes k->evp_md = EVP_sha1(); 315137015Sdes } else if (strcmp(k->name, KEX_DH14) == 0) { 316137015Sdes k->kex_type = KEX_DH_GRP14_SHA1; 317157016Sdes k->evp_md = EVP_sha1(); 318157016Sdes } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { 319113908Sdes k->kex_type = KEX_DH_GEX_SHA1; 320157016Sdes k->evp_md = EVP_sha1(); 321162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L 322162852Sdes } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { 323162852Sdes k->kex_type = KEX_DH_GEX_SHA256; 324162852Sdes k->evp_md = evp_ssh_sha256(); 325162852Sdes#endif 32669587Sgreen } else 32760573Skris fatal("bad kex alg %s", k->name); 32860573Skris} 329157016Sdes 33092555Sdesstatic void 33160573Skrischoose_hostkeyalg(Kex *k, char *client, char *server) 33260573Skris{ 33376259Sgreen char *hostkeyalg = match_list(client, server, NULL); 33476259Sgreen if (hostkeyalg == NULL) 33560573Skris fatal("no hostkey alg"); 33676259Sgreen k->hostkey_type = key_type_from_name(hostkeyalg); 33776259Sgreen if (k->hostkey_type == KEY_UNSPEC) 33876259Sgreen fatal("bad hostkey alg '%s'", hostkeyalg); 33976259Sgreen xfree(hostkeyalg); 34060573Skris} 34160573Skris 342126274Sdesstatic int 343113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 344113908Sdes{ 345113908Sdes static int check[] = { 346113908Sdes PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 347113908Sdes }; 348113908Sdes int *idx; 349113908Sdes char *p; 350113908Sdes 351113908Sdes for (idx = &check[0]; *idx != -1; idx++) { 352113908Sdes if ((p = strchr(my[*idx], ',')) != NULL) 353113908Sdes *p = '\0'; 354113908Sdes if ((p = strchr(peer[*idx], ',')) != NULL) 355113908Sdes *p = '\0'; 356113908Sdes if (strcmp(my[*idx], peer[*idx]) != 0) { 357113908Sdes debug2("proposal mismatch: my %s peer %s", 358113908Sdes my[*idx], peer[*idx]); 359113908Sdes return (0); 360113908Sdes } 361113908Sdes } 362113908Sdes debug2("proposals match"); 363113908Sdes return (1); 364113908Sdes} 365113908Sdes 36692555Sdesstatic void 36776259Sgreenkex_choose_conf(Kex *kex) 36860573Skris{ 36976259Sgreen Newkeys *newkeys; 37076259Sgreen char **my, **peer; 37176259Sgreen char **cprop, **sprop; 37276259Sgreen int nenc, nmac, ncomp; 373149749Sdes u_int mode, ctos, need; 374113908Sdes int first_kex_follows, type; 37560573Skris 376113908Sdes my = kex_buf2prop(&kex->my, NULL); 377113908Sdes peer = kex_buf2prop(&kex->peer, &first_kex_follows); 37860573Skris 37976259Sgreen if (kex->server) { 38076259Sgreen cprop=peer; 38176259Sgreen sprop=my; 38276259Sgreen } else { 38376259Sgreen cprop=my; 38476259Sgreen sprop=peer; 38576259Sgreen } 38676259Sgreen 38776259Sgreen /* Algorithm Negotiation */ 38860573Skris for (mode = 0; mode < MODE_MAX; mode++) { 389162852Sdes newkeys = xcalloc(1, sizeof(*newkeys)); 39076259Sgreen kex->newkeys[mode] = newkeys; 39176259Sgreen ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 39260573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 39360573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 39460573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 39576259Sgreen choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 39676259Sgreen choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 39776259Sgreen choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 39860573Skris debug("kex: %s %s %s %s", 39960573Skris ctos ? "client->server" : "server->client", 40076259Sgreen newkeys->enc.name, 40176259Sgreen newkeys->mac.name, 40276259Sgreen newkeys->comp.name); 40360573Skris } 40476259Sgreen choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 40576259Sgreen choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 40660573Skris sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 40760573Skris need = 0; 40860573Skris for (mode = 0; mode < MODE_MAX; mode++) { 40976259Sgreen newkeys = kex->newkeys[mode]; 41092555Sdes if (need < newkeys->enc.key_len) 41192555Sdes need = newkeys->enc.key_len; 41292555Sdes if (need < newkeys->enc.block_size) 41392555Sdes need = newkeys->enc.block_size; 41476259Sgreen if (need < newkeys->mac.key_len) 41576259Sgreen need = newkeys->mac.key_len; 41660573Skris } 41761209Skris /* XXX need runden? */ 41876259Sgreen kex->we_need = need; 41976259Sgreen 420113908Sdes /* ignore the next message if the proposals do not match */ 421126274Sdes if (first_kex_follows && !proposals_match(my, peer) && 422149749Sdes !(datafellows & SSH_BUG_FIRSTKEX)) { 423113908Sdes type = packet_read(); 424113908Sdes debug2("skipping next packet (type %u)", type); 425113908Sdes } 426113908Sdes 42776259Sgreen kex_prop_free(my); 42876259Sgreen kex_prop_free(peer); 42960573Skris} 43060573Skris 43192555Sdesstatic u_char * 432157016Sdesderive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, 433157016Sdes BIGNUM *shared_secret) 43460573Skris{ 43576259Sgreen Buffer b; 43676259Sgreen EVP_MD_CTX md; 43776259Sgreen char c = id; 438149749Sdes u_int have; 439157016Sdes int mdsz; 440149749Sdes u_char *digest; 44160573Skris 442157016Sdes if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) 443157016Sdes fatal("bad kex md size %d", mdsz); 444162852Sdes digest = xmalloc(roundup(need, mdsz)); 445149749Sdes 44676259Sgreen buffer_init(&b); 44776259Sgreen buffer_put_bignum2(&b, shared_secret); 44876259Sgreen 44976259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 450157016Sdes EVP_DigestInit(&md, kex->evp_md); 45192555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 45292555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 453157016Sdes EVP_DigestUpdate(&md, hash, hashlen); 45476259Sgreen EVP_DigestUpdate(&md, &c, 1); 45576259Sgreen EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 45676259Sgreen EVP_DigestFinal(&md, digest, NULL); 45776259Sgreen 45876259Sgreen /* 45976259Sgreen * expand key: 46076259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 46176259Sgreen * Key = K1 || K2 || ... || Kn 46276259Sgreen */ 46376259Sgreen for (have = mdsz; need > have; have += mdsz) { 464157016Sdes EVP_DigestInit(&md, kex->evp_md); 46592555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 46692555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 467157016Sdes EVP_DigestUpdate(&md, hash, hashlen); 46876259Sgreen EVP_DigestUpdate(&md, digest, have); 46976259Sgreen EVP_DigestFinal(&md, digest + have, NULL); 47076259Sgreen } 47176259Sgreen buffer_free(&b); 47276259Sgreen#ifdef DEBUG_KEX 47376259Sgreen fprintf(stderr, "key '%c'== ", c); 47476259Sgreen dump_digest("key", digest, need); 47576259Sgreen#endif 47676259Sgreen return digest; 47776259Sgreen} 47876259Sgreen 47976259SgreenNewkeys *current_keys[MODE_MAX]; 48076259Sgreen 48176259Sgreen#define NKEYS 6 48276259Sgreenvoid 483157016Sdeskex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) 48476259Sgreen{ 48576259Sgreen u_char *keys[NKEYS]; 486149749Sdes u_int i, mode, ctos; 48776259Sgreen 488157016Sdes for (i = 0; i < NKEYS; i++) { 489157016Sdes keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, 490157016Sdes shared_secret); 491157016Sdes } 49260573Skris 493113908Sdes debug2("kex_derive_keys"); 49460573Skris for (mode = 0; mode < MODE_MAX; mode++) { 49576259Sgreen current_keys[mode] = kex->newkeys[mode]; 49676259Sgreen kex->newkeys[mode] = NULL; 497162852Sdes ctos = (!kex->server && mode == MODE_OUT) || 498162852Sdes (kex->server && mode == MODE_IN); 49976259Sgreen current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 50076259Sgreen current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 50176259Sgreen current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 50260573Skris } 50360573Skris} 50476259Sgreen 50576259SgreenNewkeys * 50676259Sgreenkex_get_newkeys(int mode) 50776259Sgreen{ 50876259Sgreen Newkeys *ret; 50976259Sgreen 51076259Sgreen ret = current_keys[mode]; 51176259Sgreen current_keys[mode] = NULL; 51276259Sgreen return ret; 51376259Sgreen} 51476259Sgreen 515137015Sdesvoid 516137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 517137015Sdes u_int8_t cookie[8], u_int8_t id[16]) 518137015Sdes{ 519137015Sdes const EVP_MD *evp_md = EVP_md5(); 520137015Sdes EVP_MD_CTX md; 521137015Sdes u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; 522137015Sdes int len; 523137015Sdes 524137015Sdes EVP_DigestInit(&md, evp_md); 525137015Sdes 526137015Sdes len = BN_num_bytes(host_modulus); 527149749Sdes if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 528137015Sdes fatal("%s: bad host modulus (len %d)", __func__, len); 529137015Sdes BN_bn2bin(host_modulus, nbuf); 530137015Sdes EVP_DigestUpdate(&md, nbuf, len); 531137015Sdes 532137015Sdes len = BN_num_bytes(server_modulus); 533149749Sdes if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 534137015Sdes fatal("%s: bad server modulus (len %d)", __func__, len); 535137015Sdes BN_bn2bin(server_modulus, nbuf); 536137015Sdes EVP_DigestUpdate(&md, nbuf, len); 537137015Sdes 538137015Sdes EVP_DigestUpdate(&md, cookie, 8); 539137015Sdes 540137015Sdes EVP_DigestFinal(&md, obuf, NULL); 541137015Sdes memcpy(id, obuf, 16); 542137015Sdes 543137015Sdes memset(nbuf, 0, sizeof(nbuf)); 544137015Sdes memset(obuf, 0, sizeof(obuf)); 545137015Sdes memset(&md, 0, sizeof(md)); 546137015Sdes} 547137015Sdes 54876259Sgreen#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 54976259Sgreenvoid 55076259Sgreendump_digest(char *msg, u_char *digest, int len) 55176259Sgreen{ 552149749Sdes u_int i; 55376259Sgreen 55476259Sgreen fprintf(stderr, "%s\n", msg); 55592555Sdes for (i = 0; i< len; i++) { 55676259Sgreen fprintf(stderr, "%02x", digest[i]); 55776259Sgreen if (i%32 == 31) 55876259Sgreen fprintf(stderr, "\n"); 55976259Sgreen else if (i%8 == 7) 56076259Sgreen fprintf(stderr, " "); 56176259Sgreen } 56276259Sgreen fprintf(stderr, "\n"); 56376259Sgreen} 56476259Sgreen#endif 565