kex.c revision 231584
1221420Sdes/* $OpenBSD: kex.c,v 1.86 2010/09/22 05:01:29 djm Exp $ */ 2224638Sbrooks/* $FreeBSD: head/crypto/openssh/kex.c 231584 2012-02-13 11:59:59Z ed $ */ 360573Skris/* 492555Sdes * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 560573Skris * 660573Skris * Redistribution and use in source and binary forms, with or without 760573Skris * modification, are permitted provided that the following conditions 860573Skris * are met: 960573Skris * 1. Redistributions of source code must retain the above copyright 1060573Skris * notice, this list of conditions and the following disclaimer. 1160573Skris * 2. Redistributions in binary form must reproduce the above copyright 1260573Skris * notice, this list of conditions and the following disclaimer in the 1360573Skris * documentation and/or other materials provided with the distribution. 1460573Skris * 1560573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1660573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1760573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1860573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1960573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2060573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2160573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2260573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2360573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2460573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2560573Skris */ 2660573Skris 2760573Skris#include "includes.h" 2860573Skris 29162852Sdes#include <sys/param.h> 30162852Sdes 31162852Sdes#include <signal.h> 32162852Sdes#include <stdarg.h> 33162852Sdes#include <stdio.h> 34162852Sdes#include <stdlib.h> 35162852Sdes#include <string.h> 36162852Sdes 3776259Sgreen#include <openssl/crypto.h> 3876259Sgreen 39162852Sdes#include "xmalloc.h" 4060573Skris#include "ssh2.h" 4160573Skris#include "buffer.h" 4261209Skris#include "packet.h" 4360573Skris#include "compat.h" 4476259Sgreen#include "cipher.h" 45162852Sdes#include "key.h" 4660573Skris#include "kex.h" 4776259Sgreen#include "log.h" 4876259Sgreen#include "mac.h" 4976259Sgreen#include "match.h" 5076259Sgreen#include "dispatch.h" 5198675Sdes#include "monitor.h" 52204917Sdes#include "roaming.h" 5360573Skris 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 66221420Sdes/* Validate KEX method name list */ 67221420Sdesint 68221420Sdeskex_names_valid(const char *names) 69221420Sdes{ 70221420Sdes char *s, *cp, *p; 71221420Sdes 72221420Sdes if (names == NULL || strcmp(names, "") == 0) 73221420Sdes return 0; 74221420Sdes s = cp = xstrdup(names); 75221420Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; 76221420Sdes (p = strsep(&cp, ","))) { 77221420Sdes if (strcmp(p, KEX_DHGEX_SHA256) != 0 && 78221420Sdes strcmp(p, KEX_DHGEX_SHA1) != 0 && 79221420Sdes strcmp(p, KEX_DH14) != 0 && 80221420Sdes strcmp(p, KEX_DH1) != 0 && 81221420Sdes (strncmp(p, KEX_ECDH_SHA2_STEM, 82221420Sdes sizeof(KEX_ECDH_SHA2_STEM) - 1) != 0 || 83221420Sdes kex_ecdh_name_to_nid(p) == -1)) { 84221420Sdes error("Unsupported KEX algorithm \"%.100s\"", p); 85221420Sdes xfree(s); 86221420Sdes return 0; 87221420Sdes } 88221420Sdes } 89221420Sdes debug3("kex names ok: [%s]", names); 90221420Sdes xfree(s); 91221420Sdes return 1; 92221420Sdes} 93221420Sdes 94224638Sbrooks/* Put algorithm proposal into buffer. */ 95224638Sbrooks#ifndef NONE_CIPHER_ENABLED 9692555Sdesstatic void 97224638Sbrooks#else 98224638Sbrooks/* Also used in sshconnect2.c. */ 99224638Sbrooksvoid 100224638Sbrooks#endif 10176259Sgreenkex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 10260573Skris{ 103149749Sdes u_int i; 10476259Sgreen 10576259Sgreen buffer_clear(b); 10698675Sdes /* 10798675Sdes * add a dummy cookie, the cookie will be overwritten by 10898675Sdes * kex_send_kexinit(), each time a kexinit is set 10998675Sdes */ 11098675Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) 11198675Sdes buffer_put_char(b, 0); 11260573Skris for (i = 0; i < PROPOSAL_MAX; i++) 11376259Sgreen buffer_put_cstring(b, proposal[i]); 11476259Sgreen buffer_put_char(b, 0); /* first_kex_packet_follows */ 11576259Sgreen buffer_put_int(b, 0); /* uint32 reserved */ 11660573Skris} 11760573Skris 11876259Sgreen/* parse buffer and return algorithm proposal */ 11992555Sdesstatic char ** 120113908Sdeskex_buf2prop(Buffer *raw, int *first_kex_follows) 12161209Skris{ 12276259Sgreen Buffer b; 123181111Sdes u_int i; 12476259Sgreen char **proposal; 12561209Skris 126162852Sdes proposal = xcalloc(PROPOSAL_MAX, sizeof(char *)); 12761209Skris 12876259Sgreen buffer_init(&b); 12976259Sgreen buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 13061209Skris /* skip cookie */ 13161209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) 13276259Sgreen buffer_get_char(&b); 13361209Skris /* extract kex init proposal strings */ 13461209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 135221420Sdes proposal[i] = buffer_get_cstring(&b,NULL); 13676259Sgreen debug2("kex_parse_kexinit: %s", proposal[i]); 13761209Skris } 13876259Sgreen /* first kex follows / reserved */ 13976259Sgreen i = buffer_get_char(&b); 140113908Sdes if (first_kex_follows != NULL) 141113908Sdes *first_kex_follows = i; 14276259Sgreen debug2("kex_parse_kexinit: first_kex_follows %d ", i); 14376259Sgreen i = buffer_get_int(&b); 144181111Sdes debug2("kex_parse_kexinit: reserved %u ", i); 14576259Sgreen buffer_free(&b); 14676259Sgreen return proposal; 14761209Skris} 14861209Skris 14992555Sdesstatic void 15076259Sgreenkex_prop_free(char **proposal) 15160573Skris{ 152149749Sdes u_int i; 15360573Skris 15476259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 15576259Sgreen xfree(proposal[i]); 15676259Sgreen xfree(proposal); 15760573Skris} 15860573Skris 159181111Sdes/* ARGSUSED */ 16092555Sdesstatic void 16192555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt) 16260573Skris{ 16392555Sdes error("Hm, kex protocol error: type %d seq %u", type, seq); 16460573Skris} 16560573Skris 16692555Sdesstatic void 16792555Sdeskex_reset_dispatch(void) 16869587Sgreen{ 16992555Sdes dispatch_range(SSH2_MSG_TRANSPORT_MIN, 17092555Sdes SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 17192555Sdes dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 17269587Sgreen} 17369587Sgreen 17476259Sgreenvoid 17576259Sgreenkex_finish(Kex *kex) 17669587Sgreen{ 17792555Sdes kex_reset_dispatch(); 17869587Sgreen 17976259Sgreen packet_start(SSH2_MSG_NEWKEYS); 18076259Sgreen packet_send(); 18176259Sgreen /* packet_write_wait(); */ 18276259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 18369587Sgreen 184113908Sdes debug("expecting SSH2_MSG_NEWKEYS"); 18592555Sdes packet_read_expect(SSH2_MSG_NEWKEYS); 18692555Sdes packet_check_eom(); 18776259Sgreen debug("SSH2_MSG_NEWKEYS received"); 18869587Sgreen 18976259Sgreen kex->done = 1; 19076259Sgreen buffer_clear(&kex->peer); 19176259Sgreen /* buffer_clear(&kex->my); */ 19276259Sgreen kex->flags &= ~KEX_INIT_SENT; 19376259Sgreen xfree(kex->name); 19476259Sgreen kex->name = NULL; 19569587Sgreen} 19669587Sgreen 19760573Skrisvoid 19876259Sgreenkex_send_kexinit(Kex *kex) 19960573Skris{ 200137015Sdes u_int32_t rnd = 0; 20198675Sdes u_char *cookie; 202149749Sdes u_int i; 20398675Sdes 20476259Sgreen if (kex == NULL) { 20576259Sgreen error("kex_send_kexinit: no kex, cannot rekey"); 20676259Sgreen return; 20760573Skris } 20876259Sgreen if (kex->flags & KEX_INIT_SENT) { 20976259Sgreen debug("KEX_INIT_SENT"); 21076259Sgreen return; 21176259Sgreen } 21276259Sgreen kex->done = 0; 21398675Sdes 21498675Sdes /* generate a random cookie */ 21598675Sdes if (buffer_len(&kex->my) < KEX_COOKIE_LEN) 21698675Sdes fatal("kex_send_kexinit: kex proposal too short"); 21798675Sdes cookie = buffer_ptr(&kex->my); 21898675Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) { 21998675Sdes if (i % 4 == 0) 220137015Sdes rnd = arc4random(); 221137015Sdes cookie[i] = rnd; 222137015Sdes rnd >>= 8; 22398675Sdes } 22476259Sgreen packet_start(SSH2_MSG_KEXINIT); 22576259Sgreen packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 22676259Sgreen packet_send(); 22776259Sgreen debug("SSH2_MSG_KEXINIT sent"); 22876259Sgreen kex->flags |= KEX_INIT_SENT; 22960573Skris} 23060573Skris 231181111Sdes/* ARGSUSED */ 23276259Sgreenvoid 23392555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 23460573Skris{ 23576259Sgreen char *ptr; 236149749Sdes u_int i, dlen; 23776259Sgreen Kex *kex = (Kex *)ctxt; 23860573Skris 23976259Sgreen debug("SSH2_MSG_KEXINIT received"); 24076259Sgreen if (kex == NULL) 24176259Sgreen fatal("kex_input_kexinit: no kex, cannot rekey"); 24260573Skris 24376259Sgreen ptr = packet_get_raw(&dlen); 24476259Sgreen buffer_append(&kex->peer, ptr, dlen); 24560573Skris 24676259Sgreen /* discard packet */ 24776259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 24876259Sgreen packet_get_char(); 24976259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 25076259Sgreen xfree(packet_get_string(NULL)); 25199060Sdes (void) packet_get_char(); 25299060Sdes (void) packet_get_int(); 25392555Sdes packet_check_eom(); 25460573Skris 25576259Sgreen kex_kexinit_finish(kex); 25660573Skris} 25760573Skris 25876259SgreenKex * 25976259Sgreenkex_setup(char *proposal[PROPOSAL_MAX]) 26069587Sgreen{ 26176259Sgreen Kex *kex; 26269587Sgreen 263162852Sdes kex = xcalloc(1, sizeof(*kex)); 26476259Sgreen buffer_init(&kex->peer); 26576259Sgreen buffer_init(&kex->my); 26676259Sgreen kex_prop2buf(&kex->my, proposal); 26776259Sgreen kex->done = 0; 26869587Sgreen 26976259Sgreen kex_send_kexinit(kex); /* we start */ 27092555Sdes kex_reset_dispatch(); 27169587Sgreen 27276259Sgreen return kex; 27369587Sgreen} 27469587Sgreen 27592555Sdesstatic void 27676259Sgreenkex_kexinit_finish(Kex *kex) 27760573Skris{ 27876259Sgreen if (!(kex->flags & KEX_INIT_SENT)) 27976259Sgreen kex_send_kexinit(kex); 28060573Skris 28176259Sgreen kex_choose_conf(kex); 28260573Skris 283113908Sdes if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && 284113908Sdes kex->kex[kex->kex_type] != NULL) { 285113908Sdes (kex->kex[kex->kex_type])(kex); 286113908Sdes } else { 28776259Sgreen fatal("Unsupported key exchange %d", kex->kex_type); 28860573Skris } 28960573Skris} 29060573Skris 29192555Sdesstatic void 29260573Skrischoose_enc(Enc *enc, char *client, char *server) 29360573Skris{ 29476259Sgreen char *name = match_list(client, server, NULL); 29560573Skris if (name == NULL) 296181111Sdes fatal("no matching cipher found: client %s server %s", 297181111Sdes client, server); 29892555Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) 29969587Sgreen fatal("matching cipher is not supported: %s", name); 30060573Skris enc->name = name; 30160573Skris enc->enabled = 0; 30260573Skris enc->iv = NULL; 30360573Skris enc->key = NULL; 30492555Sdes enc->key_len = cipher_keylen(enc->cipher); 30592555Sdes enc->block_size = cipher_blocksize(enc->cipher); 30660573Skris} 307162852Sdes 30892555Sdesstatic void 30960573Skrischoose_mac(Mac *mac, char *client, char *server) 31060573Skris{ 31176259Sgreen char *name = match_list(client, server, NULL); 31260573Skris if (name == NULL) 313181111Sdes fatal("no matching mac found: client %s server %s", 314181111Sdes client, server); 315181111Sdes if (mac_setup(mac, name) < 0) 31660573Skris fatal("unsupported mac %s", name); 31776259Sgreen /* truncate the key */ 31876259Sgreen if (datafellows & SSH_BUG_HMAC) 31976259Sgreen mac->key_len = 16; 32060573Skris mac->name = name; 32160573Skris mac->key = NULL; 32260573Skris mac->enabled = 0; 32360573Skris} 324162852Sdes 32592555Sdesstatic void 32660573Skrischoose_comp(Comp *comp, char *client, char *server) 32760573Skris{ 32876259Sgreen char *name = match_list(client, server, NULL); 32960573Skris if (name == NULL) 33060573Skris fatal("no matching comp found: client %s server %s", client, server); 331149749Sdes if (strcmp(name, "zlib@openssh.com") == 0) { 332149749Sdes comp->type = COMP_DELAYED; 333149749Sdes } else if (strcmp(name, "zlib") == 0) { 334149749Sdes comp->type = COMP_ZLIB; 33560573Skris } else if (strcmp(name, "none") == 0) { 336149749Sdes comp->type = COMP_NONE; 33760573Skris } else { 33860573Skris fatal("unsupported comp %s", name); 33960573Skris } 34060573Skris comp->name = name; 34160573Skris} 342162852Sdes 34392555Sdesstatic void 34460573Skrischoose_kex(Kex *k, char *client, char *server) 34560573Skris{ 34676259Sgreen k->name = match_list(client, server, NULL); 34760573Skris if (k->name == NULL) 348181111Sdes fatal("Unable to negotiate a key exchange method"); 34969587Sgreen if (strcmp(k->name, KEX_DH1) == 0) { 350113908Sdes k->kex_type = KEX_DH_GRP1_SHA1; 351157016Sdes k->evp_md = EVP_sha1(); 352137015Sdes } else if (strcmp(k->name, KEX_DH14) == 0) { 353137015Sdes k->kex_type = KEX_DH_GRP14_SHA1; 354157016Sdes k->evp_md = EVP_sha1(); 355157016Sdes } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { 356113908Sdes k->kex_type = KEX_DH_GEX_SHA1; 357157016Sdes k->evp_md = EVP_sha1(); 358162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L 359162852Sdes } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { 360162852Sdes k->kex_type = KEX_DH_GEX_SHA256; 361162852Sdes k->evp_md = evp_ssh_sha256(); 362221420Sdes } else if (strncmp(k->name, KEX_ECDH_SHA2_STEM, 363221420Sdes sizeof(KEX_ECDH_SHA2_STEM) - 1) == 0) { 364221420Sdes k->kex_type = KEX_ECDH_SHA2; 365221420Sdes k->evp_md = kex_ecdh_name_to_evpmd(k->name); 366162852Sdes#endif 36769587Sgreen } else 36860573Skris fatal("bad kex alg %s", k->name); 36960573Skris} 370157016Sdes 37192555Sdesstatic void 37260573Skrischoose_hostkeyalg(Kex *k, char *client, char *server) 37360573Skris{ 37476259Sgreen char *hostkeyalg = match_list(client, server, NULL); 37576259Sgreen if (hostkeyalg == NULL) 37660573Skris fatal("no hostkey alg"); 37776259Sgreen k->hostkey_type = key_type_from_name(hostkeyalg); 37876259Sgreen if (k->hostkey_type == KEY_UNSPEC) 37976259Sgreen fatal("bad hostkey alg '%s'", hostkeyalg); 38076259Sgreen xfree(hostkeyalg); 38160573Skris} 38260573Skris 383126274Sdesstatic int 384113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 385113908Sdes{ 386113908Sdes static int check[] = { 387113908Sdes PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 388113908Sdes }; 389113908Sdes int *idx; 390113908Sdes char *p; 391113908Sdes 392113908Sdes for (idx = &check[0]; *idx != -1; idx++) { 393113908Sdes if ((p = strchr(my[*idx], ',')) != NULL) 394113908Sdes *p = '\0'; 395113908Sdes if ((p = strchr(peer[*idx], ',')) != NULL) 396113908Sdes *p = '\0'; 397113908Sdes if (strcmp(my[*idx], peer[*idx]) != 0) { 398113908Sdes debug2("proposal mismatch: my %s peer %s", 399113908Sdes my[*idx], peer[*idx]); 400113908Sdes return (0); 401113908Sdes } 402113908Sdes } 403113908Sdes debug2("proposals match"); 404113908Sdes return (1); 405113908Sdes} 406113908Sdes 40792555Sdesstatic void 40876259Sgreenkex_choose_conf(Kex *kex) 40960573Skris{ 41076259Sgreen Newkeys *newkeys; 41176259Sgreen char **my, **peer; 41276259Sgreen char **cprop, **sprop; 41376259Sgreen int nenc, nmac, ncomp; 414149749Sdes u_int mode, ctos, need; 415113908Sdes int first_kex_follows, type; 416224638Sbrooks#ifdef NONE_CIPHER_ENABLED 417224638Sbrooks int auth_flag; 418224638Sbrooks#endif 41960573Skris 420113908Sdes my = kex_buf2prop(&kex->my, NULL); 421113908Sdes peer = kex_buf2prop(&kex->peer, &first_kex_follows); 42260573Skris 42376259Sgreen if (kex->server) { 42476259Sgreen cprop=peer; 42576259Sgreen sprop=my; 42676259Sgreen } else { 42776259Sgreen cprop=my; 42876259Sgreen sprop=peer; 42976259Sgreen } 43076259Sgreen 431204917Sdes /* Check whether server offers roaming */ 432204917Sdes if (!kex->server) { 433204917Sdes char *roaming; 434204917Sdes roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); 435204917Sdes if (roaming) { 436204917Sdes kex->roaming = 1; 437204917Sdes xfree(roaming); 438204917Sdes } 439204917Sdes } 440204917Sdes 44176259Sgreen /* Algorithm Negotiation */ 442224638Sbrooks#ifdef NONE_CIPHER_ENABLED 443224638Sbrooks auth_flag = packet_get_authentication_state(); 444224638Sbrooks debug ("AUTH STATE is %d", auth_flag); 445224638Sbrooks#endif 44660573Skris for (mode = 0; mode < MODE_MAX; mode++) { 447162852Sdes newkeys = xcalloc(1, sizeof(*newkeys)); 44876259Sgreen kex->newkeys[mode] = newkeys; 449181111Sdes ctos = (!kex->server && mode == MODE_OUT) || 450181111Sdes (kex->server && mode == MODE_IN); 45160573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 45260573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 45360573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 45476259Sgreen choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 45576259Sgreen choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 45676259Sgreen choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 457224638Sbrooks#ifdef NONE_CIPHER_ENABLED 458224638Sbrooks debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name); 459224638Sbrooks if (strcmp(newkeys->enc.name, "none") == 0) { 460231584Sed debug("Requesting NONE. Authflag is %d", auth_flag); 461224638Sbrooks if (auth_flag == 1) 462224638Sbrooks debug("None requested post authentication."); 463224638Sbrooks else 464224638Sbrooks fatal("Pre-authentication none cipher requests " 465224638Sbrooks "are not allowed."); 466231584Sed } 467224638Sbrooks#endif 46860573Skris debug("kex: %s %s %s %s", 46960573Skris ctos ? "client->server" : "server->client", 47076259Sgreen newkeys->enc.name, 47176259Sgreen newkeys->mac.name, 47276259Sgreen newkeys->comp.name); 47360573Skris } 47476259Sgreen choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 47576259Sgreen choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 47660573Skris sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 47760573Skris need = 0; 47860573Skris for (mode = 0; mode < MODE_MAX; mode++) { 47976259Sgreen newkeys = kex->newkeys[mode]; 48092555Sdes if (need < newkeys->enc.key_len) 48192555Sdes need = newkeys->enc.key_len; 48292555Sdes if (need < newkeys->enc.block_size) 48392555Sdes need = newkeys->enc.block_size; 48476259Sgreen if (need < newkeys->mac.key_len) 48576259Sgreen need = newkeys->mac.key_len; 48660573Skris } 48761209Skris /* XXX need runden? */ 48876259Sgreen kex->we_need = need; 48976259Sgreen 490113908Sdes /* ignore the next message if the proposals do not match */ 491126274Sdes if (first_kex_follows && !proposals_match(my, peer) && 492149749Sdes !(datafellows & SSH_BUG_FIRSTKEX)) { 493113908Sdes type = packet_read(); 494113908Sdes debug2("skipping next packet (type %u)", type); 495113908Sdes } 496113908Sdes 49776259Sgreen kex_prop_free(my); 49876259Sgreen kex_prop_free(peer); 49960573Skris} 50060573Skris 50192555Sdesstatic u_char * 502157016Sdesderive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, 503157016Sdes BIGNUM *shared_secret) 50460573Skris{ 50576259Sgreen Buffer b; 50676259Sgreen EVP_MD_CTX md; 50776259Sgreen char c = id; 508149749Sdes u_int have; 509157016Sdes int mdsz; 510149749Sdes u_char *digest; 51160573Skris 512157016Sdes if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) 513157016Sdes fatal("bad kex md size %d", mdsz); 514162852Sdes digest = xmalloc(roundup(need, mdsz)); 515149749Sdes 51676259Sgreen buffer_init(&b); 51776259Sgreen buffer_put_bignum2(&b, shared_secret); 51876259Sgreen 51976259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 520157016Sdes EVP_DigestInit(&md, kex->evp_md); 52192555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 52292555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 523157016Sdes EVP_DigestUpdate(&md, hash, hashlen); 52476259Sgreen EVP_DigestUpdate(&md, &c, 1); 52576259Sgreen EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 52676259Sgreen EVP_DigestFinal(&md, digest, NULL); 52776259Sgreen 52876259Sgreen /* 52976259Sgreen * expand key: 53076259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 53176259Sgreen * Key = K1 || K2 || ... || Kn 53276259Sgreen */ 53376259Sgreen for (have = mdsz; need > have; have += mdsz) { 534157016Sdes EVP_DigestInit(&md, kex->evp_md); 53592555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 53692555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 537157016Sdes EVP_DigestUpdate(&md, hash, hashlen); 53876259Sgreen EVP_DigestUpdate(&md, digest, have); 53976259Sgreen EVP_DigestFinal(&md, digest + have, NULL); 54076259Sgreen } 54176259Sgreen buffer_free(&b); 54276259Sgreen#ifdef DEBUG_KEX 54376259Sgreen fprintf(stderr, "key '%c'== ", c); 54476259Sgreen dump_digest("key", digest, need); 54576259Sgreen#endif 54676259Sgreen return digest; 54776259Sgreen} 54876259Sgreen 54976259SgreenNewkeys *current_keys[MODE_MAX]; 55076259Sgreen 55176259Sgreen#define NKEYS 6 55276259Sgreenvoid 553157016Sdeskex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) 55476259Sgreen{ 55576259Sgreen u_char *keys[NKEYS]; 556149749Sdes u_int i, mode, ctos; 55776259Sgreen 558157016Sdes for (i = 0; i < NKEYS; i++) { 559157016Sdes keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, 560157016Sdes shared_secret); 561157016Sdes } 56260573Skris 563113908Sdes debug2("kex_derive_keys"); 56460573Skris for (mode = 0; mode < MODE_MAX; mode++) { 56576259Sgreen current_keys[mode] = kex->newkeys[mode]; 56676259Sgreen kex->newkeys[mode] = NULL; 567162852Sdes ctos = (!kex->server && mode == MODE_OUT) || 568162852Sdes (kex->server && mode == MODE_IN); 56976259Sgreen current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 57076259Sgreen current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 57176259Sgreen current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 57260573Skris } 57360573Skris} 57476259Sgreen 57576259SgreenNewkeys * 57676259Sgreenkex_get_newkeys(int mode) 57776259Sgreen{ 57876259Sgreen Newkeys *ret; 57976259Sgreen 58076259Sgreen ret = current_keys[mode]; 58176259Sgreen current_keys[mode] = NULL; 58276259Sgreen return ret; 58376259Sgreen} 58476259Sgreen 585137015Sdesvoid 586137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 587137015Sdes u_int8_t cookie[8], u_int8_t id[16]) 588137015Sdes{ 589137015Sdes const EVP_MD *evp_md = EVP_md5(); 590137015Sdes EVP_MD_CTX md; 591137015Sdes u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; 592137015Sdes int len; 593137015Sdes 594137015Sdes EVP_DigestInit(&md, evp_md); 595137015Sdes 596137015Sdes len = BN_num_bytes(host_modulus); 597149749Sdes if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 598137015Sdes fatal("%s: bad host modulus (len %d)", __func__, len); 599137015Sdes BN_bn2bin(host_modulus, nbuf); 600137015Sdes EVP_DigestUpdate(&md, nbuf, len); 601137015Sdes 602137015Sdes len = BN_num_bytes(server_modulus); 603149749Sdes if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 604137015Sdes fatal("%s: bad server modulus (len %d)", __func__, len); 605137015Sdes BN_bn2bin(server_modulus, nbuf); 606137015Sdes EVP_DigestUpdate(&md, nbuf, len); 607137015Sdes 608137015Sdes EVP_DigestUpdate(&md, cookie, 8); 609137015Sdes 610137015Sdes EVP_DigestFinal(&md, obuf, NULL); 611137015Sdes memcpy(id, obuf, 16); 612137015Sdes 613137015Sdes memset(nbuf, 0, sizeof(nbuf)); 614137015Sdes memset(obuf, 0, sizeof(obuf)); 615137015Sdes memset(&md, 0, sizeof(md)); 616137015Sdes} 617137015Sdes 618221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 61976259Sgreenvoid 62076259Sgreendump_digest(char *msg, u_char *digest, int len) 62176259Sgreen{ 622221420Sdes int i; 62376259Sgreen 62476259Sgreen fprintf(stderr, "%s\n", msg); 625181111Sdes for (i = 0; i < len; i++) { 62676259Sgreen fprintf(stderr, "%02x", digest[i]); 62776259Sgreen if (i%32 == 31) 62876259Sgreen fprintf(stderr, "\n"); 62976259Sgreen else if (i%8 == 7) 63076259Sgreen fprintf(stderr, " "); 63176259Sgreen } 63276259Sgreen fprintf(stderr, "\n"); 63376259Sgreen} 63476259Sgreen#endif 635