kex.c revision 221420
1221420Sdes/* $OpenBSD: kex.c,v 1.86 2010/09/22 05:01:29 djm 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 65221420Sdes/* Validate KEX method name list */ 66221420Sdesint 67221420Sdeskex_names_valid(const char *names) 68221420Sdes{ 69221420Sdes char *s, *cp, *p; 70221420Sdes 71221420Sdes if (names == NULL || strcmp(names, "") == 0) 72221420Sdes return 0; 73221420Sdes s = cp = xstrdup(names); 74221420Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; 75221420Sdes (p = strsep(&cp, ","))) { 76221420Sdes if (strcmp(p, KEX_DHGEX_SHA256) != 0 && 77221420Sdes strcmp(p, KEX_DHGEX_SHA1) != 0 && 78221420Sdes strcmp(p, KEX_DH14) != 0 && 79221420Sdes strcmp(p, KEX_DH1) != 0 && 80221420Sdes (strncmp(p, KEX_ECDH_SHA2_STEM, 81221420Sdes sizeof(KEX_ECDH_SHA2_STEM) - 1) != 0 || 82221420Sdes kex_ecdh_name_to_nid(p) == -1)) { 83221420Sdes error("Unsupported KEX algorithm \"%.100s\"", p); 84221420Sdes xfree(s); 85221420Sdes return 0; 86221420Sdes } 87221420Sdes } 88221420Sdes debug3("kex names ok: [%s]", names); 89221420Sdes xfree(s); 90221420Sdes return 1; 91221420Sdes} 92221420Sdes 9376259Sgreen/* put algorithm proposal into buffer */ 9492555Sdesstatic void 9576259Sgreenkex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 9660573Skris{ 97149749Sdes u_int i; 9876259Sgreen 9976259Sgreen buffer_clear(b); 10098675Sdes /* 10198675Sdes * add a dummy cookie, the cookie will be overwritten by 10298675Sdes * kex_send_kexinit(), each time a kexinit is set 10398675Sdes */ 10498675Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) 10598675Sdes buffer_put_char(b, 0); 10660573Skris for (i = 0; i < PROPOSAL_MAX; i++) 10776259Sgreen buffer_put_cstring(b, proposal[i]); 10876259Sgreen buffer_put_char(b, 0); /* first_kex_packet_follows */ 10976259Sgreen buffer_put_int(b, 0); /* uint32 reserved */ 11060573Skris} 11160573Skris 11276259Sgreen/* parse buffer and return algorithm proposal */ 11392555Sdesstatic char ** 114113908Sdeskex_buf2prop(Buffer *raw, int *first_kex_follows) 11561209Skris{ 11676259Sgreen Buffer b; 117181111Sdes u_int i; 11876259Sgreen char **proposal; 11961209Skris 120162852Sdes proposal = xcalloc(PROPOSAL_MAX, sizeof(char *)); 12161209Skris 12276259Sgreen buffer_init(&b); 12376259Sgreen buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 12461209Skris /* skip cookie */ 12561209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) 12676259Sgreen buffer_get_char(&b); 12761209Skris /* extract kex init proposal strings */ 12861209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 129221420Sdes proposal[i] = buffer_get_cstring(&b,NULL); 13076259Sgreen debug2("kex_parse_kexinit: %s", proposal[i]); 13161209Skris } 13276259Sgreen /* first kex follows / reserved */ 13376259Sgreen i = buffer_get_char(&b); 134113908Sdes if (first_kex_follows != NULL) 135113908Sdes *first_kex_follows = i; 13676259Sgreen debug2("kex_parse_kexinit: first_kex_follows %d ", i); 13776259Sgreen i = buffer_get_int(&b); 138181111Sdes debug2("kex_parse_kexinit: reserved %u ", i); 13976259Sgreen buffer_free(&b); 14076259Sgreen return proposal; 14161209Skris} 14261209Skris 14392555Sdesstatic void 14476259Sgreenkex_prop_free(char **proposal) 14560573Skris{ 146149749Sdes u_int i; 14760573Skris 14876259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 14976259Sgreen xfree(proposal[i]); 15076259Sgreen xfree(proposal); 15160573Skris} 15260573Skris 153181111Sdes/* ARGSUSED */ 15492555Sdesstatic void 15592555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt) 15660573Skris{ 15792555Sdes error("Hm, kex protocol error: type %d seq %u", type, seq); 15860573Skris} 15960573Skris 16092555Sdesstatic void 16192555Sdeskex_reset_dispatch(void) 16269587Sgreen{ 16392555Sdes dispatch_range(SSH2_MSG_TRANSPORT_MIN, 16492555Sdes SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 16592555Sdes dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 16669587Sgreen} 16769587Sgreen 16876259Sgreenvoid 16976259Sgreenkex_finish(Kex *kex) 17069587Sgreen{ 17192555Sdes kex_reset_dispatch(); 17269587Sgreen 17376259Sgreen packet_start(SSH2_MSG_NEWKEYS); 17476259Sgreen packet_send(); 17576259Sgreen /* packet_write_wait(); */ 17676259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 17769587Sgreen 178113908Sdes debug("expecting SSH2_MSG_NEWKEYS"); 17992555Sdes packet_read_expect(SSH2_MSG_NEWKEYS); 18092555Sdes packet_check_eom(); 18176259Sgreen debug("SSH2_MSG_NEWKEYS received"); 18269587Sgreen 18376259Sgreen kex->done = 1; 18476259Sgreen buffer_clear(&kex->peer); 18576259Sgreen /* buffer_clear(&kex->my); */ 18676259Sgreen kex->flags &= ~KEX_INIT_SENT; 18776259Sgreen xfree(kex->name); 18876259Sgreen kex->name = NULL; 18969587Sgreen} 19069587Sgreen 19160573Skrisvoid 19276259Sgreenkex_send_kexinit(Kex *kex) 19360573Skris{ 194137015Sdes u_int32_t rnd = 0; 19598675Sdes u_char *cookie; 196149749Sdes u_int i; 19798675Sdes 19876259Sgreen if (kex == NULL) { 19976259Sgreen error("kex_send_kexinit: no kex, cannot rekey"); 20076259Sgreen return; 20160573Skris } 20276259Sgreen if (kex->flags & KEX_INIT_SENT) { 20376259Sgreen debug("KEX_INIT_SENT"); 20476259Sgreen return; 20576259Sgreen } 20676259Sgreen kex->done = 0; 20798675Sdes 20898675Sdes /* generate a random cookie */ 20998675Sdes if (buffer_len(&kex->my) < KEX_COOKIE_LEN) 21098675Sdes fatal("kex_send_kexinit: kex proposal too short"); 21198675Sdes cookie = buffer_ptr(&kex->my); 21298675Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) { 21398675Sdes if (i % 4 == 0) 214137015Sdes rnd = arc4random(); 215137015Sdes cookie[i] = rnd; 216137015Sdes rnd >>= 8; 21798675Sdes } 21876259Sgreen packet_start(SSH2_MSG_KEXINIT); 21976259Sgreen packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 22076259Sgreen packet_send(); 22176259Sgreen debug("SSH2_MSG_KEXINIT sent"); 22276259Sgreen kex->flags |= KEX_INIT_SENT; 22360573Skris} 22460573Skris 225181111Sdes/* ARGSUSED */ 22676259Sgreenvoid 22792555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 22860573Skris{ 22976259Sgreen char *ptr; 230149749Sdes u_int i, dlen; 23176259Sgreen Kex *kex = (Kex *)ctxt; 23260573Skris 23376259Sgreen debug("SSH2_MSG_KEXINIT received"); 23476259Sgreen if (kex == NULL) 23576259Sgreen fatal("kex_input_kexinit: no kex, cannot rekey"); 23660573Skris 23776259Sgreen ptr = packet_get_raw(&dlen); 23876259Sgreen buffer_append(&kex->peer, ptr, dlen); 23960573Skris 24076259Sgreen /* discard packet */ 24176259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 24276259Sgreen packet_get_char(); 24376259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 24476259Sgreen xfree(packet_get_string(NULL)); 24599060Sdes (void) packet_get_char(); 24699060Sdes (void) packet_get_int(); 24792555Sdes packet_check_eom(); 24860573Skris 24976259Sgreen kex_kexinit_finish(kex); 25060573Skris} 25160573Skris 25276259SgreenKex * 25376259Sgreenkex_setup(char *proposal[PROPOSAL_MAX]) 25469587Sgreen{ 25576259Sgreen Kex *kex; 25669587Sgreen 257162852Sdes kex = xcalloc(1, sizeof(*kex)); 25876259Sgreen buffer_init(&kex->peer); 25976259Sgreen buffer_init(&kex->my); 26076259Sgreen kex_prop2buf(&kex->my, proposal); 26176259Sgreen kex->done = 0; 26269587Sgreen 26376259Sgreen kex_send_kexinit(kex); /* we start */ 26492555Sdes kex_reset_dispatch(); 26569587Sgreen 26676259Sgreen return kex; 26769587Sgreen} 26869587Sgreen 26992555Sdesstatic void 27076259Sgreenkex_kexinit_finish(Kex *kex) 27160573Skris{ 27276259Sgreen if (!(kex->flags & KEX_INIT_SENT)) 27376259Sgreen kex_send_kexinit(kex); 27460573Skris 27576259Sgreen kex_choose_conf(kex); 27660573Skris 277113908Sdes if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && 278113908Sdes kex->kex[kex->kex_type] != NULL) { 279113908Sdes (kex->kex[kex->kex_type])(kex); 280113908Sdes } else { 28176259Sgreen fatal("Unsupported key exchange %d", kex->kex_type); 28260573Skris } 28360573Skris} 28460573Skris 28592555Sdesstatic void 28660573Skrischoose_enc(Enc *enc, char *client, char *server) 28760573Skris{ 28876259Sgreen char *name = match_list(client, server, NULL); 28960573Skris if (name == NULL) 290181111Sdes fatal("no matching cipher found: client %s server %s", 291181111Sdes client, server); 29292555Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) 29369587Sgreen fatal("matching cipher is not supported: %s", name); 29460573Skris enc->name = name; 29560573Skris enc->enabled = 0; 29660573Skris enc->iv = NULL; 29760573Skris enc->key = NULL; 29892555Sdes enc->key_len = cipher_keylen(enc->cipher); 29992555Sdes enc->block_size = cipher_blocksize(enc->cipher); 30060573Skris} 301162852Sdes 30292555Sdesstatic void 30360573Skrischoose_mac(Mac *mac, char *client, char *server) 30460573Skris{ 30576259Sgreen char *name = match_list(client, server, NULL); 30660573Skris if (name == NULL) 307181111Sdes fatal("no matching mac found: client %s server %s", 308181111Sdes client, server); 309181111Sdes if (mac_setup(mac, name) < 0) 31060573Skris fatal("unsupported mac %s", name); 31176259Sgreen /* truncate the key */ 31276259Sgreen if (datafellows & SSH_BUG_HMAC) 31376259Sgreen mac->key_len = 16; 31460573Skris mac->name = name; 31560573Skris mac->key = NULL; 31660573Skris mac->enabled = 0; 31760573Skris} 318162852Sdes 31992555Sdesstatic void 32060573Skrischoose_comp(Comp *comp, char *client, char *server) 32160573Skris{ 32276259Sgreen char *name = match_list(client, server, NULL); 32360573Skris if (name == NULL) 32460573Skris fatal("no matching comp found: client %s server %s", client, server); 325149749Sdes if (strcmp(name, "zlib@openssh.com") == 0) { 326149749Sdes comp->type = COMP_DELAYED; 327149749Sdes } else if (strcmp(name, "zlib") == 0) { 328149749Sdes comp->type = COMP_ZLIB; 32960573Skris } else if (strcmp(name, "none") == 0) { 330149749Sdes comp->type = COMP_NONE; 33160573Skris } else { 33260573Skris fatal("unsupported comp %s", name); 33360573Skris } 33460573Skris comp->name = name; 33560573Skris} 336162852Sdes 33792555Sdesstatic void 33860573Skrischoose_kex(Kex *k, char *client, char *server) 33960573Skris{ 34076259Sgreen k->name = match_list(client, server, NULL); 34160573Skris if (k->name == NULL) 342181111Sdes fatal("Unable to negotiate a key exchange method"); 34369587Sgreen if (strcmp(k->name, KEX_DH1) == 0) { 344113908Sdes k->kex_type = KEX_DH_GRP1_SHA1; 345157016Sdes k->evp_md = EVP_sha1(); 346137015Sdes } else if (strcmp(k->name, KEX_DH14) == 0) { 347137015Sdes k->kex_type = KEX_DH_GRP14_SHA1; 348157016Sdes k->evp_md = EVP_sha1(); 349157016Sdes } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { 350113908Sdes k->kex_type = KEX_DH_GEX_SHA1; 351157016Sdes k->evp_md = EVP_sha1(); 352162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L 353162852Sdes } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { 354162852Sdes k->kex_type = KEX_DH_GEX_SHA256; 355162852Sdes k->evp_md = evp_ssh_sha256(); 356221420Sdes } else if (strncmp(k->name, KEX_ECDH_SHA2_STEM, 357221420Sdes sizeof(KEX_ECDH_SHA2_STEM) - 1) == 0) { 358221420Sdes k->kex_type = KEX_ECDH_SHA2; 359221420Sdes k->evp_md = kex_ecdh_name_to_evpmd(k->name); 360162852Sdes#endif 36169587Sgreen } else 36260573Skris fatal("bad kex alg %s", k->name); 36360573Skris} 364157016Sdes 36592555Sdesstatic void 36660573Skrischoose_hostkeyalg(Kex *k, char *client, char *server) 36760573Skris{ 36876259Sgreen char *hostkeyalg = match_list(client, server, NULL); 36976259Sgreen if (hostkeyalg == NULL) 37060573Skris fatal("no hostkey alg"); 37176259Sgreen k->hostkey_type = key_type_from_name(hostkeyalg); 37276259Sgreen if (k->hostkey_type == KEY_UNSPEC) 37376259Sgreen fatal("bad hostkey alg '%s'", hostkeyalg); 37476259Sgreen xfree(hostkeyalg); 37560573Skris} 37660573Skris 377126274Sdesstatic int 378113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 379113908Sdes{ 380113908Sdes static int check[] = { 381113908Sdes PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 382113908Sdes }; 383113908Sdes int *idx; 384113908Sdes char *p; 385113908Sdes 386113908Sdes for (idx = &check[0]; *idx != -1; idx++) { 387113908Sdes if ((p = strchr(my[*idx], ',')) != NULL) 388113908Sdes *p = '\0'; 389113908Sdes if ((p = strchr(peer[*idx], ',')) != NULL) 390113908Sdes *p = '\0'; 391113908Sdes if (strcmp(my[*idx], peer[*idx]) != 0) { 392113908Sdes debug2("proposal mismatch: my %s peer %s", 393113908Sdes my[*idx], peer[*idx]); 394113908Sdes return (0); 395113908Sdes } 396113908Sdes } 397113908Sdes debug2("proposals match"); 398113908Sdes return (1); 399113908Sdes} 400113908Sdes 40192555Sdesstatic void 40276259Sgreenkex_choose_conf(Kex *kex) 40360573Skris{ 40476259Sgreen Newkeys *newkeys; 40576259Sgreen char **my, **peer; 40676259Sgreen char **cprop, **sprop; 40776259Sgreen int nenc, nmac, ncomp; 408149749Sdes u_int mode, ctos, need; 409113908Sdes int first_kex_follows, type; 41060573Skris 411113908Sdes my = kex_buf2prop(&kex->my, NULL); 412113908Sdes peer = kex_buf2prop(&kex->peer, &first_kex_follows); 41360573Skris 41476259Sgreen if (kex->server) { 41576259Sgreen cprop=peer; 41676259Sgreen sprop=my; 41776259Sgreen } else { 41876259Sgreen cprop=my; 41976259Sgreen sprop=peer; 42076259Sgreen } 42176259Sgreen 422204917Sdes /* Check whether server offers roaming */ 423204917Sdes if (!kex->server) { 424204917Sdes char *roaming; 425204917Sdes roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); 426204917Sdes if (roaming) { 427204917Sdes kex->roaming = 1; 428204917Sdes xfree(roaming); 429204917Sdes } 430204917Sdes } 431204917Sdes 43276259Sgreen /* Algorithm Negotiation */ 43360573Skris for (mode = 0; mode < MODE_MAX; mode++) { 434162852Sdes newkeys = xcalloc(1, sizeof(*newkeys)); 43576259Sgreen kex->newkeys[mode] = newkeys; 436181111Sdes ctos = (!kex->server && mode == MODE_OUT) || 437181111Sdes (kex->server && mode == MODE_IN); 43860573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 43960573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 44060573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 44176259Sgreen choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 44276259Sgreen choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 44376259Sgreen choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 44460573Skris debug("kex: %s %s %s %s", 44560573Skris ctos ? "client->server" : "server->client", 44676259Sgreen newkeys->enc.name, 44776259Sgreen newkeys->mac.name, 44876259Sgreen newkeys->comp.name); 44960573Skris } 45076259Sgreen choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 45176259Sgreen choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 45260573Skris sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 45360573Skris need = 0; 45460573Skris for (mode = 0; mode < MODE_MAX; mode++) { 45576259Sgreen newkeys = kex->newkeys[mode]; 45692555Sdes if (need < newkeys->enc.key_len) 45792555Sdes need = newkeys->enc.key_len; 45892555Sdes if (need < newkeys->enc.block_size) 45992555Sdes need = newkeys->enc.block_size; 46076259Sgreen if (need < newkeys->mac.key_len) 46176259Sgreen need = newkeys->mac.key_len; 46260573Skris } 46361209Skris /* XXX need runden? */ 46476259Sgreen kex->we_need = need; 46576259Sgreen 466113908Sdes /* ignore the next message if the proposals do not match */ 467126274Sdes if (first_kex_follows && !proposals_match(my, peer) && 468149749Sdes !(datafellows & SSH_BUG_FIRSTKEX)) { 469113908Sdes type = packet_read(); 470113908Sdes debug2("skipping next packet (type %u)", type); 471113908Sdes } 472113908Sdes 47376259Sgreen kex_prop_free(my); 47476259Sgreen kex_prop_free(peer); 47560573Skris} 47660573Skris 47792555Sdesstatic u_char * 478157016Sdesderive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, 479157016Sdes BIGNUM *shared_secret) 48060573Skris{ 48176259Sgreen Buffer b; 48276259Sgreen EVP_MD_CTX md; 48376259Sgreen char c = id; 484149749Sdes u_int have; 485157016Sdes int mdsz; 486149749Sdes u_char *digest; 48760573Skris 488157016Sdes if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) 489157016Sdes fatal("bad kex md size %d", mdsz); 490162852Sdes digest = xmalloc(roundup(need, mdsz)); 491149749Sdes 49276259Sgreen buffer_init(&b); 49376259Sgreen buffer_put_bignum2(&b, shared_secret); 49476259Sgreen 49576259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 496157016Sdes EVP_DigestInit(&md, kex->evp_md); 49792555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 49892555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 499157016Sdes EVP_DigestUpdate(&md, hash, hashlen); 50076259Sgreen EVP_DigestUpdate(&md, &c, 1); 50176259Sgreen EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 50276259Sgreen EVP_DigestFinal(&md, digest, NULL); 50376259Sgreen 50476259Sgreen /* 50576259Sgreen * expand key: 50676259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 50776259Sgreen * Key = K1 || K2 || ... || Kn 50876259Sgreen */ 50976259Sgreen for (have = mdsz; need > have; have += mdsz) { 510157016Sdes EVP_DigestInit(&md, kex->evp_md); 51192555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 51292555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 513157016Sdes EVP_DigestUpdate(&md, hash, hashlen); 51476259Sgreen EVP_DigestUpdate(&md, digest, have); 51576259Sgreen EVP_DigestFinal(&md, digest + have, NULL); 51676259Sgreen } 51776259Sgreen buffer_free(&b); 51876259Sgreen#ifdef DEBUG_KEX 51976259Sgreen fprintf(stderr, "key '%c'== ", c); 52076259Sgreen dump_digest("key", digest, need); 52176259Sgreen#endif 52276259Sgreen return digest; 52376259Sgreen} 52476259Sgreen 52576259SgreenNewkeys *current_keys[MODE_MAX]; 52676259Sgreen 52776259Sgreen#define NKEYS 6 52876259Sgreenvoid 529157016Sdeskex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) 53076259Sgreen{ 53176259Sgreen u_char *keys[NKEYS]; 532149749Sdes u_int i, mode, ctos; 53376259Sgreen 534157016Sdes for (i = 0; i < NKEYS; i++) { 535157016Sdes keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, 536157016Sdes shared_secret); 537157016Sdes } 53860573Skris 539113908Sdes debug2("kex_derive_keys"); 54060573Skris for (mode = 0; mode < MODE_MAX; mode++) { 54176259Sgreen current_keys[mode] = kex->newkeys[mode]; 54276259Sgreen kex->newkeys[mode] = NULL; 543162852Sdes ctos = (!kex->server && mode == MODE_OUT) || 544162852Sdes (kex->server && mode == MODE_IN); 54576259Sgreen current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 54676259Sgreen current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 54776259Sgreen current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 54860573Skris } 54960573Skris} 55076259Sgreen 55176259SgreenNewkeys * 55276259Sgreenkex_get_newkeys(int mode) 55376259Sgreen{ 55476259Sgreen Newkeys *ret; 55576259Sgreen 55676259Sgreen ret = current_keys[mode]; 55776259Sgreen current_keys[mode] = NULL; 55876259Sgreen return ret; 55976259Sgreen} 56076259Sgreen 561137015Sdesvoid 562137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 563137015Sdes u_int8_t cookie[8], u_int8_t id[16]) 564137015Sdes{ 565137015Sdes const EVP_MD *evp_md = EVP_md5(); 566137015Sdes EVP_MD_CTX md; 567137015Sdes u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; 568137015Sdes int len; 569137015Sdes 570137015Sdes EVP_DigestInit(&md, evp_md); 571137015Sdes 572137015Sdes len = BN_num_bytes(host_modulus); 573149749Sdes if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 574137015Sdes fatal("%s: bad host modulus (len %d)", __func__, len); 575137015Sdes BN_bn2bin(host_modulus, nbuf); 576137015Sdes EVP_DigestUpdate(&md, nbuf, len); 577137015Sdes 578137015Sdes len = BN_num_bytes(server_modulus); 579149749Sdes if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) 580137015Sdes fatal("%s: bad server modulus (len %d)", __func__, len); 581137015Sdes BN_bn2bin(server_modulus, nbuf); 582137015Sdes EVP_DigestUpdate(&md, nbuf, len); 583137015Sdes 584137015Sdes EVP_DigestUpdate(&md, cookie, 8); 585137015Sdes 586137015Sdes EVP_DigestFinal(&md, obuf, NULL); 587137015Sdes memcpy(id, obuf, 16); 588137015Sdes 589137015Sdes memset(nbuf, 0, sizeof(nbuf)); 590137015Sdes memset(obuf, 0, sizeof(obuf)); 591137015Sdes memset(&md, 0, sizeof(md)); 592137015Sdes} 593137015Sdes 594221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 59576259Sgreenvoid 59676259Sgreendump_digest(char *msg, u_char *digest, int len) 59776259Sgreen{ 598221420Sdes int i; 59976259Sgreen 60076259Sgreen fprintf(stderr, "%s\n", msg); 601181111Sdes for (i = 0; i < len; i++) { 60276259Sgreen fprintf(stderr, "%02x", digest[i]); 60376259Sgreen if (i%32 == 31) 60476259Sgreen fprintf(stderr, "\n"); 60576259Sgreen else if (i%8 == 7) 60676259Sgreen fprintf(stderr, " "); 60776259Sgreen } 60876259Sgreen fprintf(stderr, "\n"); 60976259Sgreen} 61076259Sgreen#endif 611