kex.c revision 204917
1204917Sdes/* $OpenBSD: kex.c,v 1.82 2009/10/24 11:13:54 andreas 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" 51204917Sdes#include "roaming.h" 5260573Skris 53162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L 54162852Sdes# if defined(HAVE_EVP_SHA256) 55162852Sdes# define evp_ssh_sha256 EVP_sha256 56162852Sdes# else 57162852Sdesextern const EVP_MD *evp_ssh_sha256(void); 58162852Sdes# endif 59162852Sdes#endif 60162852Sdes 6192555Sdes/* prototype */ 6292555Sdesstatic void kex_kexinit_finish(Kex *); 6392555Sdesstatic void kex_choose_conf(Kex *); 6476259Sgreen 6576259Sgreen/* put algorithm proposal into buffer */ 6692555Sdesstatic void 6776259Sgreenkex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 6860573Skris{ 69149749Sdes u_int i; 7076259Sgreen 7176259Sgreen buffer_clear(b); 7298675Sdes /* 7398675Sdes * add a dummy cookie, the cookie will be overwritten by 7498675Sdes * kex_send_kexinit(), each time a kexinit is set 7598675Sdes */ 7698675Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) 7798675Sdes buffer_put_char(b, 0); 7860573Skris for (i = 0; i < PROPOSAL_MAX; i++) 7976259Sgreen buffer_put_cstring(b, proposal[i]); 8076259Sgreen buffer_put_char(b, 0); /* first_kex_packet_follows */ 8176259Sgreen buffer_put_int(b, 0); /* uint32 reserved */ 8260573Skris} 8360573Skris 8476259Sgreen/* parse buffer and return algorithm proposal */ 8592555Sdesstatic char ** 86113908Sdeskex_buf2prop(Buffer *raw, int *first_kex_follows) 8761209Skris{ 8876259Sgreen Buffer b; 89181111Sdes u_int i; 9076259Sgreen char **proposal; 9161209Skris 92162852Sdes proposal = xcalloc(PROPOSAL_MAX, sizeof(char *)); 9361209Skris 9476259Sgreen buffer_init(&b); 9576259Sgreen buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 9661209Skris /* skip cookie */ 9761209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) 9876259Sgreen buffer_get_char(&b); 9961209Skris /* extract kex init proposal strings */ 10061209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 10176259Sgreen proposal[i] = buffer_get_string(&b,NULL); 10276259Sgreen debug2("kex_parse_kexinit: %s", proposal[i]); 10361209Skris } 10476259Sgreen /* first kex follows / reserved */ 10576259Sgreen i = buffer_get_char(&b); 106113908Sdes if (first_kex_follows != NULL) 107113908Sdes *first_kex_follows = i; 10876259Sgreen debug2("kex_parse_kexinit: first_kex_follows %d ", i); 10976259Sgreen i = buffer_get_int(&b); 110181111Sdes debug2("kex_parse_kexinit: reserved %u ", i); 11176259Sgreen buffer_free(&b); 11276259Sgreen return proposal; 11361209Skris} 11461209Skris 11592555Sdesstatic void 11676259Sgreenkex_prop_free(char **proposal) 11760573Skris{ 118149749Sdes u_int i; 11960573Skris 12076259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 12176259Sgreen xfree(proposal[i]); 12276259Sgreen xfree(proposal); 12360573Skris} 12460573Skris 125181111Sdes/* ARGSUSED */ 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 197181111Sdes/* ARGSUSED */ 19876259Sgreenvoid 19992555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 20060573Skris{ 20176259Sgreen char *ptr; 202149749Sdes u_int i, dlen; 20376259Sgreen Kex *kex = (Kex *)ctxt; 20460573Skris 20576259Sgreen debug("SSH2_MSG_KEXINIT received"); 20676259Sgreen if (kex == NULL) 20776259Sgreen fatal("kex_input_kexinit: no kex, cannot rekey"); 20860573Skris 20976259Sgreen ptr = packet_get_raw(&dlen); 21076259Sgreen buffer_append(&kex->peer, ptr, dlen); 21160573Skris 21276259Sgreen /* discard packet */ 21376259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 21476259Sgreen packet_get_char(); 21576259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 21676259Sgreen xfree(packet_get_string(NULL)); 21799060Sdes (void) packet_get_char(); 21899060Sdes (void) packet_get_int(); 21992555Sdes packet_check_eom(); 22060573Skris 22176259Sgreen kex_kexinit_finish(kex); 22260573Skris} 22360573Skris 22476259SgreenKex * 22576259Sgreenkex_setup(char *proposal[PROPOSAL_MAX]) 22669587Sgreen{ 22776259Sgreen Kex *kex; 22869587Sgreen 229162852Sdes kex = xcalloc(1, sizeof(*kex)); 23076259Sgreen buffer_init(&kex->peer); 23176259Sgreen buffer_init(&kex->my); 23276259Sgreen kex_prop2buf(&kex->my, proposal); 23376259Sgreen kex->done = 0; 23469587Sgreen 23576259Sgreen kex_send_kexinit(kex); /* we start */ 23692555Sdes kex_reset_dispatch(); 23769587Sgreen 23876259Sgreen return kex; 23969587Sgreen} 24069587Sgreen 24192555Sdesstatic void 24276259Sgreenkex_kexinit_finish(Kex *kex) 24360573Skris{ 24476259Sgreen if (!(kex->flags & KEX_INIT_SENT)) 24576259Sgreen kex_send_kexinit(kex); 24660573Skris 24776259Sgreen kex_choose_conf(kex); 24860573Skris 249113908Sdes if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && 250113908Sdes kex->kex[kex->kex_type] != NULL) { 251113908Sdes (kex->kex[kex->kex_type])(kex); 252113908Sdes } else { 25376259Sgreen fatal("Unsupported key exchange %d", kex->kex_type); 25460573Skris } 25560573Skris} 25660573Skris 25792555Sdesstatic void 25860573Skrischoose_enc(Enc *enc, char *client, char *server) 25960573Skris{ 26076259Sgreen char *name = match_list(client, server, NULL); 26160573Skris if (name == NULL) 262181111Sdes fatal("no matching cipher found: client %s server %s", 263181111Sdes client, server); 26492555Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) 26569587Sgreen fatal("matching cipher is not supported: %s", name); 26660573Skris enc->name = name; 26760573Skris enc->enabled = 0; 26860573Skris enc->iv = NULL; 26960573Skris enc->key = NULL; 27092555Sdes enc->key_len = cipher_keylen(enc->cipher); 27192555Sdes enc->block_size = cipher_blocksize(enc->cipher); 27260573Skris} 273162852Sdes 27492555Sdesstatic void 27560573Skrischoose_mac(Mac *mac, char *client, char *server) 27660573Skris{ 27776259Sgreen char *name = match_list(client, server, NULL); 27860573Skris if (name == NULL) 279181111Sdes fatal("no matching mac found: client %s server %s", 280181111Sdes client, server); 281181111Sdes if (mac_setup(mac, name) < 0) 28260573Skris fatal("unsupported mac %s", name); 28376259Sgreen /* truncate the key */ 28476259Sgreen if (datafellows & SSH_BUG_HMAC) 28576259Sgreen mac->key_len = 16; 28660573Skris mac->name = name; 28760573Skris mac->key = NULL; 28860573Skris mac->enabled = 0; 28960573Skris} 290162852Sdes 29192555Sdesstatic void 29260573Skrischoose_comp(Comp *comp, char *client, char *server) 29360573Skris{ 29476259Sgreen char *name = match_list(client, server, NULL); 29560573Skris if (name == NULL) 29660573Skris fatal("no matching comp found: client %s server %s", client, server); 297149749Sdes if (strcmp(name, "zlib@openssh.com") == 0) { 298149749Sdes comp->type = COMP_DELAYED; 299149749Sdes } else if (strcmp(name, "zlib") == 0) { 300149749Sdes comp->type = COMP_ZLIB; 30160573Skris } else if (strcmp(name, "none") == 0) { 302149749Sdes comp->type = COMP_NONE; 30360573Skris } else { 30460573Skris fatal("unsupported comp %s", name); 30560573Skris } 30660573Skris comp->name = name; 30760573Skris} 308162852Sdes 30992555Sdesstatic void 31060573Skrischoose_kex(Kex *k, char *client, char *server) 31160573Skris{ 31276259Sgreen k->name = match_list(client, server, NULL); 31360573Skris if (k->name == NULL) 314181111Sdes fatal("Unable to negotiate a key exchange method"); 31569587Sgreen if (strcmp(k->name, KEX_DH1) == 0) { 316113908Sdes k->kex_type = KEX_DH_GRP1_SHA1; 317157016Sdes k->evp_md = EVP_sha1(); 318137015Sdes } else if (strcmp(k->name, KEX_DH14) == 0) { 319137015Sdes k->kex_type = KEX_DH_GRP14_SHA1; 320157016Sdes k->evp_md = EVP_sha1(); 321157016Sdes } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { 322113908Sdes k->kex_type = KEX_DH_GEX_SHA1; 323157016Sdes k->evp_md = EVP_sha1(); 324162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L 325162852Sdes } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { 326162852Sdes k->kex_type = KEX_DH_GEX_SHA256; 327162852Sdes k->evp_md = evp_ssh_sha256(); 328162852Sdes#endif 32969587Sgreen } else 33060573Skris fatal("bad kex alg %s", k->name); 33160573Skris} 332157016Sdes 33392555Sdesstatic void 33460573Skrischoose_hostkeyalg(Kex *k, char *client, char *server) 33560573Skris{ 33676259Sgreen char *hostkeyalg = match_list(client, server, NULL); 33776259Sgreen if (hostkeyalg == NULL) 33860573Skris fatal("no hostkey alg"); 33976259Sgreen k->hostkey_type = key_type_from_name(hostkeyalg); 34076259Sgreen if (k->hostkey_type == KEY_UNSPEC) 34176259Sgreen fatal("bad hostkey alg '%s'", hostkeyalg); 34276259Sgreen xfree(hostkeyalg); 34360573Skris} 34460573Skris 345126274Sdesstatic int 346113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 347113908Sdes{ 348113908Sdes static int check[] = { 349113908Sdes PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 350113908Sdes }; 351113908Sdes int *idx; 352113908Sdes char *p; 353113908Sdes 354113908Sdes for (idx = &check[0]; *idx != -1; idx++) { 355113908Sdes if ((p = strchr(my[*idx], ',')) != NULL) 356113908Sdes *p = '\0'; 357113908Sdes if ((p = strchr(peer[*idx], ',')) != NULL) 358113908Sdes *p = '\0'; 359113908Sdes if (strcmp(my[*idx], peer[*idx]) != 0) { 360113908Sdes debug2("proposal mismatch: my %s peer %s", 361113908Sdes my[*idx], peer[*idx]); 362113908Sdes return (0); 363113908Sdes } 364113908Sdes } 365113908Sdes debug2("proposals match"); 366113908Sdes return (1); 367113908Sdes} 368113908Sdes 36992555Sdesstatic void 37076259Sgreenkex_choose_conf(Kex *kex) 37160573Skris{ 37276259Sgreen Newkeys *newkeys; 37376259Sgreen char **my, **peer; 37476259Sgreen char **cprop, **sprop; 37576259Sgreen int nenc, nmac, ncomp; 376149749Sdes u_int mode, ctos, need; 377113908Sdes int first_kex_follows, type; 37860573Skris 379113908Sdes my = kex_buf2prop(&kex->my, NULL); 380113908Sdes peer = kex_buf2prop(&kex->peer, &first_kex_follows); 38160573Skris 38276259Sgreen if (kex->server) { 38376259Sgreen cprop=peer; 38476259Sgreen sprop=my; 38576259Sgreen } else { 38676259Sgreen cprop=my; 38776259Sgreen sprop=peer; 38876259Sgreen } 38976259Sgreen 390204917Sdes /* Check whether server offers roaming */ 391204917Sdes if (!kex->server) { 392204917Sdes char *roaming; 393204917Sdes roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); 394204917Sdes if (roaming) { 395204917Sdes kex->roaming = 1; 396204917Sdes xfree(roaming); 397204917Sdes } 398204917Sdes } 399204917Sdes 40076259Sgreen /* Algorithm Negotiation */ 40160573Skris for (mode = 0; mode < MODE_MAX; mode++) { 402162852Sdes newkeys = xcalloc(1, sizeof(*newkeys)); 40376259Sgreen kex->newkeys[mode] = newkeys; 404181111Sdes ctos = (!kex->server && mode == MODE_OUT) || 405181111Sdes (kex->server && mode == MODE_IN); 40660573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 40760573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 40860573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 40976259Sgreen choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 41076259Sgreen choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 41176259Sgreen choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 41260573Skris debug("kex: %s %s %s %s", 41360573Skris ctos ? "client->server" : "server->client", 41476259Sgreen newkeys->enc.name, 41576259Sgreen newkeys->mac.name, 41676259Sgreen newkeys->comp.name); 41760573Skris } 41876259Sgreen choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 41976259Sgreen choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 42060573Skris sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 42160573Skris need = 0; 42260573Skris for (mode = 0; mode < MODE_MAX; mode++) { 42376259Sgreen newkeys = kex->newkeys[mode]; 42492555Sdes if (need < newkeys->enc.key_len) 42592555Sdes need = newkeys->enc.key_len; 42692555Sdes if (need < newkeys->enc.block_size) 42792555Sdes need = newkeys->enc.block_size; 42876259Sgreen if (need < newkeys->mac.key_len) 42976259Sgreen need = newkeys->mac.key_len; 43060573Skris } 43161209Skris /* XXX need runden? */ 43276259Sgreen kex->we_need = need; 43376259Sgreen 434113908Sdes /* ignore the next message if the proposals do not match */ 435126274Sdes if (first_kex_follows && !proposals_match(my, peer) && 436149749Sdes !(datafellows & SSH_BUG_FIRSTKEX)) { 437113908Sdes type = packet_read(); 438113908Sdes debug2("skipping next packet (type %u)", type); 439113908Sdes } 440113908Sdes 44176259Sgreen kex_prop_free(my); 44276259Sgreen kex_prop_free(peer); 44360573Skris} 44460573Skris 44592555Sdesstatic u_char * 446157016Sdesderive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, 447157016Sdes BIGNUM *shared_secret) 44860573Skris{ 44976259Sgreen Buffer b; 45076259Sgreen EVP_MD_CTX md; 45176259Sgreen char c = id; 452149749Sdes u_int have; 453157016Sdes int mdsz; 454149749Sdes u_char *digest; 45560573Skris 456157016Sdes if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) 457157016Sdes fatal("bad kex md size %d", mdsz); 458162852Sdes digest = xmalloc(roundup(need, mdsz)); 459149749Sdes 46076259Sgreen buffer_init(&b); 46176259Sgreen buffer_put_bignum2(&b, shared_secret); 46276259Sgreen 46376259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 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, &c, 1); 46976259Sgreen EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 47076259Sgreen EVP_DigestFinal(&md, digest, NULL); 47176259Sgreen 47276259Sgreen /* 47376259Sgreen * expand key: 47476259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 47576259Sgreen * Key = K1 || K2 || ... || Kn 47676259Sgreen */ 47776259Sgreen for (have = mdsz; need > have; have += mdsz) { 478157016Sdes EVP_DigestInit(&md, kex->evp_md); 47992555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 48092555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 481157016Sdes EVP_DigestUpdate(&md, hash, hashlen); 48276259Sgreen EVP_DigestUpdate(&md, digest, have); 48376259Sgreen EVP_DigestFinal(&md, digest + have, NULL); 48476259Sgreen } 48576259Sgreen buffer_free(&b); 48676259Sgreen#ifdef DEBUG_KEX 48776259Sgreen fprintf(stderr, "key '%c'== ", c); 48876259Sgreen dump_digest("key", digest, need); 48976259Sgreen#endif 49076259Sgreen return digest; 49176259Sgreen} 49276259Sgreen 49376259SgreenNewkeys *current_keys[MODE_MAX]; 49476259Sgreen 49576259Sgreen#define NKEYS 6 49676259Sgreenvoid 497157016Sdeskex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) 49876259Sgreen{ 49976259Sgreen u_char *keys[NKEYS]; 500149749Sdes u_int i, mode, ctos; 50176259Sgreen 502157016Sdes for (i = 0; i < NKEYS; i++) { 503157016Sdes keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, 504157016Sdes shared_secret); 505157016Sdes } 50660573Skris 507113908Sdes debug2("kex_derive_keys"); 50860573Skris for (mode = 0; mode < MODE_MAX; mode++) { 50976259Sgreen current_keys[mode] = kex->newkeys[mode]; 51076259Sgreen kex->newkeys[mode] = NULL; 511162852Sdes ctos = (!kex->server && mode == MODE_OUT) || 512162852Sdes (kex->server && mode == MODE_IN); 51376259Sgreen current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 51476259Sgreen current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 51576259Sgreen current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 51660573Skris } 51760573Skris} 51876259Sgreen 51976259SgreenNewkeys * 52076259Sgreenkex_get_newkeys(int mode) 52176259Sgreen{ 52276259Sgreen Newkeys *ret; 52376259Sgreen 52476259Sgreen ret = current_keys[mode]; 52576259Sgreen current_keys[mode] = NULL; 52676259Sgreen return ret; 52776259Sgreen} 52876259Sgreen 529137015Sdesvoid 530137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 531137015Sdes u_int8_t cookie[8], u_int8_t id[16]) 532137015Sdes{ 533137015Sdes const EVP_MD *evp_md = EVP_md5(); 534137015Sdes EVP_MD_CTX md; 535137015Sdes u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; 536137015Sdes int len; 537137015Sdes 538137015Sdes EVP_DigestInit(&md, evp_md); 539137015Sdes 540137015Sdes len = BN_num_bytes(host_modulus); 541149749Sdes if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 542137015Sdes fatal("%s: bad host modulus (len %d)", __func__, len); 543137015Sdes BN_bn2bin(host_modulus, nbuf); 544137015Sdes EVP_DigestUpdate(&md, nbuf, len); 545137015Sdes 546137015Sdes len = BN_num_bytes(server_modulus); 547149749Sdes if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 548137015Sdes fatal("%s: bad server modulus (len %d)", __func__, len); 549137015Sdes BN_bn2bin(server_modulus, nbuf); 550137015Sdes EVP_DigestUpdate(&md, nbuf, len); 551137015Sdes 552137015Sdes EVP_DigestUpdate(&md, cookie, 8); 553137015Sdes 554137015Sdes EVP_DigestFinal(&md, obuf, NULL); 555137015Sdes memcpy(id, obuf, 16); 556137015Sdes 557137015Sdes memset(nbuf, 0, sizeof(nbuf)); 558137015Sdes memset(obuf, 0, sizeof(obuf)); 559137015Sdes memset(&md, 0, sizeof(md)); 560137015Sdes} 561137015Sdes 56276259Sgreen#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 56376259Sgreenvoid 56476259Sgreendump_digest(char *msg, u_char *digest, int len) 56576259Sgreen{ 566149749Sdes u_int i; 56776259Sgreen 56876259Sgreen fprintf(stderr, "%s\n", msg); 569181111Sdes for (i = 0; i < len; i++) { 57076259Sgreen fprintf(stderr, "%02x", digest[i]); 57176259Sgreen if (i%32 == 31) 57276259Sgreen fprintf(stderr, "\n"); 57376259Sgreen else if (i%8 == 7) 57476259Sgreen fprintf(stderr, " "); 57576259Sgreen } 57676259Sgreen fprintf(stderr, "\n"); 57776259Sgreen} 57876259Sgreen#endif 579