1296853Sdes/* $OpenBSD: kex.c,v 1.117 2016/02/08 10:57:07 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 28295367Sdes#include <sys/param.h> /* MAX roundup */ 29162852Sdes 30162852Sdes#include <signal.h> 31162852Sdes#include <stdarg.h> 32162852Sdes#include <stdio.h> 33162852Sdes#include <stdlib.h> 34162852Sdes#include <string.h> 35162852Sdes 36295367Sdes#ifdef WITH_OPENSSL 3776259Sgreen#include <openssl/crypto.h> 38295367Sdes#endif 3976259Sgreen 4060573Skris#include "ssh2.h" 4161209Skris#include "packet.h" 4260573Skris#include "compat.h" 4376259Sgreen#include "cipher.h" 44295367Sdes#include "sshkey.h" 4560573Skris#include "kex.h" 4676259Sgreen#include "log.h" 4776259Sgreen#include "mac.h" 4876259Sgreen#include "match.h" 49295367Sdes#include "misc.h" 5076259Sgreen#include "dispatch.h" 5198675Sdes#include "monitor.h" 52295367Sdes 53295367Sdes#include "ssherr.h" 54295367Sdes#include "sshbuf.h" 55262566Sdes#include "digest.h" 5660573Skris 57162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L 58162852Sdes# if defined(HAVE_EVP_SHA256) 59162852Sdes# define evp_ssh_sha256 EVP_sha256 60162852Sdes# else 61162852Sdesextern const EVP_MD *evp_ssh_sha256(void); 62162852Sdes# endif 63162852Sdes#endif 64162852Sdes 6592555Sdes/* prototype */ 66295367Sdesstatic int kex_choose_conf(struct ssh *); 67295367Sdesstatic int kex_input_newkeys(int, u_int32_t, void *); 6876259Sgreen 69296853Sdesstatic const char *proposal_names[PROPOSAL_MAX] = { 70296853Sdes "KEX algorithms", 71296853Sdes "host key algorithms", 72296853Sdes "ciphers ctos", 73296853Sdes "ciphers stoc", 74296853Sdes "MACs ctos", 75296853Sdes "MACs stoc", 76296853Sdes "compression ctos", 77296853Sdes "compression stoc", 78296853Sdes "languages ctos", 79296853Sdes "languages stoc", 80296853Sdes}; 81296853Sdes 82255767Sdesstruct kexalg { 83255767Sdes char *name; 84295367Sdes u_int type; 85255767Sdes int ec_nid; 86262566Sdes int hash_alg; 87255767Sdes}; 88255767Sdesstatic const struct kexalg kexalgs[] = { 89295367Sdes#ifdef WITH_OPENSSL 90262566Sdes { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 91262566Sdes { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 92262566Sdes { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 93255767Sdes#ifdef HAVE_EVP_SHA256 94262566Sdes { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 95295367Sdes#endif /* HAVE_EVP_SHA256 */ 96255767Sdes#ifdef OPENSSL_HAS_ECC 97262566Sdes { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 98262566Sdes NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 99262566Sdes { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, 100262566Sdes SSH_DIGEST_SHA384 }, 101262566Sdes# ifdef OPENSSL_HAS_NISTP521 102262566Sdes { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 103262566Sdes SSH_DIGEST_SHA512 }, 104295367Sdes# endif /* OPENSSL_HAS_NISTP521 */ 105295367Sdes#endif /* OPENSSL_HAS_ECC */ 106295367Sdes#endif /* WITH_OPENSSL */ 107295367Sdes#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) 108262566Sdes { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 109295367Sdes#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 110262566Sdes { NULL, -1, -1, -1}, 111255767Sdes}; 112255767Sdes 113255767Sdeschar * 114262566Sdeskex_alg_list(char sep) 115255767Sdes{ 116295367Sdes char *ret = NULL, *tmp; 117255767Sdes size_t nlen, rlen = 0; 118255767Sdes const struct kexalg *k; 119255767Sdes 120255767Sdes for (k = kexalgs; k->name != NULL; k++) { 121255767Sdes if (ret != NULL) 122262566Sdes ret[rlen++] = sep; 123255767Sdes nlen = strlen(k->name); 124295367Sdes if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 125295367Sdes free(ret); 126295367Sdes return NULL; 127295367Sdes } 128295367Sdes ret = tmp; 129255767Sdes memcpy(ret + rlen, k->name, nlen + 1); 130255767Sdes rlen += nlen; 131255767Sdes } 132255767Sdes return ret; 133255767Sdes} 134255767Sdes 135255767Sdesstatic const struct kexalg * 136255767Sdeskex_alg_by_name(const char *name) 137255767Sdes{ 138255767Sdes const struct kexalg *k; 139255767Sdes 140255767Sdes for (k = kexalgs; k->name != NULL; k++) { 141255767Sdes if (strcmp(k->name, name) == 0) 142255767Sdes return k; 143255767Sdes } 144255767Sdes return NULL; 145255767Sdes} 146255767Sdes 147221420Sdes/* Validate KEX method name list */ 148221420Sdesint 149221420Sdeskex_names_valid(const char *names) 150221420Sdes{ 151221420Sdes char *s, *cp, *p; 152221420Sdes 153221420Sdes if (names == NULL || strcmp(names, "") == 0) 154221420Sdes return 0; 155295367Sdes if ((s = cp = strdup(names)) == NULL) 156295367Sdes return 0; 157221420Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; 158221420Sdes (p = strsep(&cp, ","))) { 159255767Sdes if (kex_alg_by_name(p) == NULL) { 160221420Sdes error("Unsupported KEX algorithm \"%.100s\"", p); 161255767Sdes free(s); 162221420Sdes return 0; 163221420Sdes } 164221420Sdes } 165221420Sdes debug3("kex names ok: [%s]", names); 166255767Sdes free(s); 167221420Sdes return 1; 168221420Sdes} 169221420Sdes 170295367Sdes/* 171295367Sdes * Concatenate algorithm names, avoiding duplicates in the process. 172295367Sdes * Caller must free returned string. 173295367Sdes */ 174295367Sdeschar * 175295367Sdeskex_names_cat(const char *a, const char *b) 176295367Sdes{ 177295367Sdes char *ret = NULL, *tmp = NULL, *cp, *p; 178295367Sdes size_t len; 179295367Sdes 180295367Sdes if (a == NULL || *a == '\0') 181295367Sdes return NULL; 182295367Sdes if (b == NULL || *b == '\0') 183295367Sdes return strdup(a); 184295367Sdes if (strlen(b) > 1024*1024) 185295367Sdes return NULL; 186295367Sdes len = strlen(a) + strlen(b) + 2; 187295367Sdes if ((tmp = cp = strdup(b)) == NULL || 188295367Sdes (ret = calloc(1, len)) == NULL) { 189295367Sdes free(tmp); 190295367Sdes return NULL; 191295367Sdes } 192295367Sdes strlcpy(ret, a, len); 193295367Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { 194295367Sdes if (match_list(ret, p, NULL) != NULL) 195295367Sdes continue; /* Algorithm already present */ 196295367Sdes if (strlcat(ret, ",", len) >= len || 197295367Sdes strlcat(ret, p, len) >= len) { 198295367Sdes free(tmp); 199295367Sdes free(ret); 200295367Sdes return NULL; /* Shouldn't happen */ 201295367Sdes } 202295367Sdes } 203295367Sdes free(tmp); 204295367Sdes return ret; 205295367Sdes} 206295367Sdes 207295367Sdes/* 208295367Sdes * Assemble a list of algorithms from a default list and a string from a 209295367Sdes * configuration file. The user-provided string may begin with '+' to 210295367Sdes * indicate that it should be appended to the default. 211295367Sdes */ 212295367Sdesint 213295367Sdeskex_assemble_names(const char *def, char **list) 214295367Sdes{ 215295367Sdes char *ret; 216295367Sdes 217295367Sdes if (list == NULL || *list == NULL || **list == '\0') { 218295367Sdes *list = strdup(def); 219295367Sdes return 0; 220295367Sdes } 221295367Sdes if (**list != '+') { 222295367Sdes return 0; 223295367Sdes } 224295367Sdes 225295367Sdes if ((ret = kex_names_cat(def, *list + 1)) == NULL) 226295367Sdes return SSH_ERR_ALLOC_FAIL; 227295367Sdes free(*list); 228295367Sdes *list = ret; 229295367Sdes return 0; 230295367Sdes} 231295367Sdes 232294693Sdes/* put algorithm proposal into buffer */ 233295367Sdesint 234295367Sdeskex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 23560573Skris{ 236149749Sdes u_int i; 237295367Sdes int r; 23876259Sgreen 239295367Sdes sshbuf_reset(b); 240295367Sdes 24198675Sdes /* 24298675Sdes * add a dummy cookie, the cookie will be overwritten by 24398675Sdes * kex_send_kexinit(), each time a kexinit is set 24498675Sdes */ 245295367Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) { 246295367Sdes if ((r = sshbuf_put_u8(b, 0)) != 0) 247295367Sdes return r; 248295367Sdes } 249295367Sdes for (i = 0; i < PROPOSAL_MAX; i++) { 250295367Sdes if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 251295367Sdes return r; 252295367Sdes } 253295367Sdes if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 254295367Sdes (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 255295367Sdes return r; 256295367Sdes return 0; 25760573Skris} 25860573Skris 25976259Sgreen/* parse buffer and return algorithm proposal */ 260295367Sdesint 261295367Sdeskex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 26261209Skris{ 263295367Sdes struct sshbuf *b = NULL; 264295367Sdes u_char v; 265181111Sdes u_int i; 266295367Sdes char **proposal = NULL; 267295367Sdes int r; 26861209Skris 269295367Sdes *propp = NULL; 270295367Sdes if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 271295367Sdes return SSH_ERR_ALLOC_FAIL; 272295367Sdes if ((b = sshbuf_fromb(raw)) == NULL) { 273295367Sdes r = SSH_ERR_ALLOC_FAIL; 274295367Sdes goto out; 275295367Sdes } 276295367Sdes if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 277295367Sdes goto out; 27861209Skris /* extract kex init proposal strings */ 27961209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 280295367Sdes if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 281295367Sdes goto out; 282296853Sdes debug2("%s: %s", proposal_names[i], proposal[i]); 28361209Skris } 28476259Sgreen /* first kex follows / reserved */ 285295367Sdes if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ 286295367Sdes (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ 287295367Sdes goto out; 288113908Sdes if (first_kex_follows != NULL) 289295367Sdes *first_kex_follows = v; 290295367Sdes debug2("first_kex_follows %d ", v); 291295367Sdes debug2("reserved %u ", i); 292295367Sdes r = 0; 293295367Sdes *propp = proposal; 294295367Sdes out: 295295367Sdes if (r != 0 && proposal != NULL) 296295367Sdes kex_prop_free(proposal); 297295367Sdes sshbuf_free(b); 298295367Sdes return r; 29961209Skris} 30061209Skris 301295367Sdesvoid 30276259Sgreenkex_prop_free(char **proposal) 30360573Skris{ 304149749Sdes u_int i; 30560573Skris 306295367Sdes if (proposal == NULL) 307295367Sdes return; 30876259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 309255767Sdes free(proposal[i]); 310255767Sdes free(proposal); 31160573Skris} 31260573Skris 313181111Sdes/* ARGSUSED */ 314295367Sdesstatic int 31592555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt) 31660573Skris{ 317296853Sdes struct ssh *ssh = active_state; /* XXX */ 318296853Sdes int r; 319296853Sdes 320296853Sdes error("kex protocol error: type %d seq %u", type, seq); 321296853Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || 322296853Sdes (r = sshpkt_put_u32(ssh, seq)) != 0 || 323296853Sdes (r = sshpkt_send(ssh)) != 0) 324296853Sdes return r; 325295367Sdes return 0; 32660573Skris} 32760573Skris 32892555Sdesstatic void 329295367Sdeskex_reset_dispatch(struct ssh *ssh) 33069587Sgreen{ 331295367Sdes ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 33292555Sdes SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 333295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 33469587Sgreen} 33569587Sgreen 336296853Sdesstatic int 337296853Sdeskex_send_ext_info(struct ssh *ssh) 338296853Sdes{ 339296853Sdes int r; 340296853Sdes 341296853Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || 342296853Sdes (r = sshpkt_put_u32(ssh, 1)) != 0 || 343296853Sdes (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || 344296853Sdes (r = sshpkt_put_cstring(ssh, "rsa-sha2-256,rsa-sha2-512")) != 0 || 345296853Sdes (r = sshpkt_send(ssh)) != 0) 346296853Sdes return r; 347296853Sdes return 0; 348296853Sdes} 349296853Sdes 350295367Sdesint 351295367Sdeskex_send_newkeys(struct ssh *ssh) 35269587Sgreen{ 353295367Sdes int r; 35469587Sgreen 355295367Sdes kex_reset_dispatch(ssh); 356295367Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 357295367Sdes (r = sshpkt_send(ssh)) != 0) 358295367Sdes return r; 35976259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 360295367Sdes debug("expecting SSH2_MSG_NEWKEYS"); 361295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 362296853Sdes if (ssh->kex->ext_info_c) 363296853Sdes if ((r = kex_send_ext_info(ssh)) != 0) 364296853Sdes return r; 365295367Sdes return 0; 366295367Sdes} 36769587Sgreen 368296853Sdesint 369296853Sdeskex_input_ext_info(int type, u_int32_t seq, void *ctxt) 370296853Sdes{ 371296853Sdes struct ssh *ssh = ctxt; 372296853Sdes struct kex *kex = ssh->kex; 373296853Sdes u_int32_t i, ninfo; 374296853Sdes char *name, *val, *found; 375296853Sdes int r; 376296853Sdes 377296853Sdes debug("SSH2_MSG_EXT_INFO received"); 378296853Sdes ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); 379296853Sdes if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) 380296853Sdes return r; 381296853Sdes for (i = 0; i < ninfo; i++) { 382296853Sdes if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) 383296853Sdes return r; 384296853Sdes if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) { 385296853Sdes free(name); 386296853Sdes return r; 387296853Sdes } 388296853Sdes debug("%s: %s=<%s>", __func__, name, val); 389296853Sdes if (strcmp(name, "server-sig-algs") == 0) { 390296853Sdes found = match_list("rsa-sha2-256", val, NULL); 391296853Sdes if (found) { 392296853Sdes kex->rsa_sha2 = 256; 393296853Sdes free(found); 394296853Sdes } 395296853Sdes found = match_list("rsa-sha2-512", val, NULL); 396296853Sdes if (found) { 397296853Sdes kex->rsa_sha2 = 512; 398296853Sdes free(found); 399296853Sdes } 400296853Sdes } 401296853Sdes free(name); 402296853Sdes free(val); 403296853Sdes } 404296853Sdes return sshpkt_get_end(ssh); 405296853Sdes} 406296853Sdes 407295367Sdesstatic int 408295367Sdeskex_input_newkeys(int type, u_int32_t seq, void *ctxt) 409295367Sdes{ 410295367Sdes struct ssh *ssh = ctxt; 411295367Sdes struct kex *kex = ssh->kex; 412295367Sdes int r; 413295367Sdes 41476259Sgreen debug("SSH2_MSG_NEWKEYS received"); 415295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 416295367Sdes if ((r = sshpkt_get_end(ssh)) != 0) 417295367Sdes return r; 41876259Sgreen kex->done = 1; 419295367Sdes sshbuf_reset(kex->peer); 420295367Sdes /* sshbuf_reset(kex->my); */ 42176259Sgreen kex->flags &= ~KEX_INIT_SENT; 422255767Sdes free(kex->name); 42376259Sgreen kex->name = NULL; 424295367Sdes return 0; 42569587Sgreen} 42669587Sgreen 427295367Sdesint 428295367Sdeskex_send_kexinit(struct ssh *ssh) 42960573Skris{ 43098675Sdes u_char *cookie; 431295367Sdes struct kex *kex = ssh->kex; 432295367Sdes int r; 43398675Sdes 434295367Sdes if (kex == NULL) 435295367Sdes return SSH_ERR_INTERNAL_ERROR; 436295367Sdes if (kex->flags & KEX_INIT_SENT) 437295367Sdes return 0; 43876259Sgreen kex->done = 0; 43998675Sdes 44098675Sdes /* generate a random cookie */ 441295367Sdes if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 442295367Sdes return SSH_ERR_INVALID_FORMAT; 443295367Sdes if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 444295367Sdes return SSH_ERR_INTERNAL_ERROR; 445295367Sdes arc4random_buf(cookie, KEX_COOKIE_LEN); 446295367Sdes 447295367Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 448295367Sdes (r = sshpkt_putb(ssh, kex->my)) != 0 || 449295367Sdes (r = sshpkt_send(ssh)) != 0) 450295367Sdes return r; 45176259Sgreen debug("SSH2_MSG_KEXINIT sent"); 45276259Sgreen kex->flags |= KEX_INIT_SENT; 453295367Sdes return 0; 45460573Skris} 45560573Skris 456181111Sdes/* ARGSUSED */ 457295367Sdesint 45892555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 45960573Skris{ 460295367Sdes struct ssh *ssh = ctxt; 461295367Sdes struct kex *kex = ssh->kex; 462295367Sdes const u_char *ptr; 463295367Sdes u_int i; 464295367Sdes size_t dlen; 465295367Sdes int r; 46660573Skris 46776259Sgreen debug("SSH2_MSG_KEXINIT received"); 46876259Sgreen if (kex == NULL) 469295367Sdes return SSH_ERR_INVALID_ARGUMENT; 47060573Skris 471308203Sdelphij ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); 472295367Sdes ptr = sshpkt_ptr(ssh, &dlen); 473295367Sdes if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 474295367Sdes return r; 47560573Skris 47676259Sgreen /* discard packet */ 47776259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 478295367Sdes if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 479295367Sdes return r; 48076259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 481295367Sdes if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 482295367Sdes return r; 483248619Sdes /* 484248619Sdes * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 485248619Sdes * KEX method has the server move first, but a server might be using 486248619Sdes * a custom method or one that we otherwise don't support. We should 487248619Sdes * be prepared to remember first_kex_follows here so we can eat a 488248619Sdes * packet later. 489248619Sdes * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 490248619Sdes * for cases where the server *doesn't* go first. I guess we should 491248619Sdes * ignore it when it is set for these cases, which is what we do now. 492248619Sdes */ 493295367Sdes if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 494295367Sdes (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 495295367Sdes (r = sshpkt_get_end(ssh)) != 0) 496295367Sdes return r; 49760573Skris 498295367Sdes if (!(kex->flags & KEX_INIT_SENT)) 499295367Sdes if ((r = kex_send_kexinit(ssh)) != 0) 500295367Sdes return r; 501295367Sdes if ((r = kex_choose_conf(ssh)) != 0) 502295367Sdes return r; 503295367Sdes 504295367Sdes if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 505295367Sdes return (kex->kex[kex->kex_type])(ssh); 506295367Sdes 507295367Sdes return SSH_ERR_INTERNAL_ERROR; 50860573Skris} 50960573Skris 510295367Sdesint 511295367Sdeskex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 51269587Sgreen{ 513295367Sdes struct kex *kex; 514295367Sdes int r; 51569587Sgreen 516295367Sdes *kexp = NULL; 517295367Sdes if ((kex = calloc(1, sizeof(*kex))) == NULL) 518295367Sdes return SSH_ERR_ALLOC_FAIL; 519295367Sdes if ((kex->peer = sshbuf_new()) == NULL || 520295367Sdes (kex->my = sshbuf_new()) == NULL) { 521295367Sdes r = SSH_ERR_ALLOC_FAIL; 522295367Sdes goto out; 523295367Sdes } 524295367Sdes if ((r = kex_prop2buf(kex->my, proposal)) != 0) 525295367Sdes goto out; 52676259Sgreen kex->done = 0; 527295367Sdes kex_reset_dispatch(ssh); 528295367Sdes r = 0; 529295367Sdes *kexp = kex; 530295367Sdes out: 531295367Sdes if (r != 0) 532295367Sdes kex_free(kex); 533295367Sdes return r; 534295367Sdes} 53569587Sgreen 536295367Sdesvoid 537295367Sdeskex_free_newkeys(struct newkeys *newkeys) 538295367Sdes{ 539295367Sdes if (newkeys == NULL) 540295367Sdes return; 541295367Sdes if (newkeys->enc.key) { 542295367Sdes explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 543295367Sdes free(newkeys->enc.key); 544295367Sdes newkeys->enc.key = NULL; 545295367Sdes } 546295367Sdes if (newkeys->enc.iv) { 547296853Sdes explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len); 548295367Sdes free(newkeys->enc.iv); 549295367Sdes newkeys->enc.iv = NULL; 550295367Sdes } 551295367Sdes free(newkeys->enc.name); 552295367Sdes explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 553295367Sdes free(newkeys->comp.name); 554295367Sdes explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 555295367Sdes mac_clear(&newkeys->mac); 556295367Sdes if (newkeys->mac.key) { 557295367Sdes explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 558295367Sdes free(newkeys->mac.key); 559295367Sdes newkeys->mac.key = NULL; 560295367Sdes } 561295367Sdes free(newkeys->mac.name); 562295367Sdes explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 563295367Sdes explicit_bzero(newkeys, sizeof(*newkeys)); 564295367Sdes free(newkeys); 565295367Sdes} 56669587Sgreen 567295367Sdesvoid 568295367Sdeskex_free(struct kex *kex) 569295367Sdes{ 570295367Sdes u_int mode; 571295367Sdes 572295367Sdes#ifdef WITH_OPENSSL 573295367Sdes if (kex->dh) 574295367Sdes DH_free(kex->dh); 575295367Sdes#ifdef OPENSSL_HAS_ECC 576295367Sdes if (kex->ec_client_key) 577295367Sdes EC_KEY_free(kex->ec_client_key); 578295367Sdes#endif /* OPENSSL_HAS_ECC */ 579295367Sdes#endif /* WITH_OPENSSL */ 580295367Sdes for (mode = 0; mode < MODE_MAX; mode++) { 581295367Sdes kex_free_newkeys(kex->newkeys[mode]); 582295367Sdes kex->newkeys[mode] = NULL; 583295367Sdes } 584295367Sdes sshbuf_free(kex->peer); 585295367Sdes sshbuf_free(kex->my); 586295367Sdes free(kex->session_id); 587295367Sdes free(kex->client_version_string); 588295367Sdes free(kex->server_version_string); 589295367Sdes free(kex->failed_choice); 590296853Sdes free(kex->hostkey_alg); 591296853Sdes free(kex->name); 592295367Sdes free(kex); 59369587Sgreen} 59469587Sgreen 595295367Sdesint 596295367Sdeskex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 59760573Skris{ 598295367Sdes int r; 59960573Skris 600295367Sdes if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 601295367Sdes return r; 602295367Sdes if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 603295367Sdes kex_free(ssh->kex); 604295367Sdes ssh->kex = NULL; 605295367Sdes return r; 60660573Skris } 607295367Sdes return 0; 60860573Skris} 60960573Skris 610296853Sdes/* 611296853Sdes * Request key re-exchange, returns 0 on success or a ssherr.h error 612296853Sdes * code otherwise. Must not be called if KEX is incomplete or in-progress. 613296853Sdes */ 614296853Sdesint 615296853Sdeskex_start_rekex(struct ssh *ssh) 616296853Sdes{ 617296853Sdes if (ssh->kex == NULL) { 618296853Sdes error("%s: no kex", __func__); 619296853Sdes return SSH_ERR_INTERNAL_ERROR; 620296853Sdes } 621296853Sdes if (ssh->kex->done == 0) { 622296853Sdes error("%s: requested twice", __func__); 623296853Sdes return SSH_ERR_INTERNAL_ERROR; 624296853Sdes } 625296853Sdes ssh->kex->done = 0; 626296853Sdes return kex_send_kexinit(ssh); 627296853Sdes} 628296853Sdes 629295367Sdesstatic int 630295367Sdeschoose_enc(struct sshenc *enc, char *client, char *server) 63160573Skris{ 63276259Sgreen char *name = match_list(client, server, NULL); 633295367Sdes 63460573Skris if (name == NULL) 635295367Sdes return SSH_ERR_NO_CIPHER_ALG_MATCH; 63692555Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) 637295367Sdes return SSH_ERR_INTERNAL_ERROR; 63860573Skris enc->name = name; 63960573Skris enc->enabled = 0; 64060573Skris enc->iv = NULL; 641248619Sdes enc->iv_len = cipher_ivlen(enc->cipher); 64260573Skris enc->key = NULL; 64392555Sdes enc->key_len = cipher_keylen(enc->cipher); 64492555Sdes enc->block_size = cipher_blocksize(enc->cipher); 645295367Sdes return 0; 64660573Skris} 647162852Sdes 648295367Sdesstatic int 649295367Sdeschoose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 65060573Skris{ 65176259Sgreen char *name = match_list(client, server, NULL); 652295367Sdes 65360573Skris if (name == NULL) 654295367Sdes return SSH_ERR_NO_MAC_ALG_MATCH; 655181111Sdes if (mac_setup(mac, name) < 0) 656295367Sdes return SSH_ERR_INTERNAL_ERROR; 65776259Sgreen /* truncate the key */ 658295367Sdes if (ssh->compat & SSH_BUG_HMAC) 65976259Sgreen mac->key_len = 16; 66060573Skris mac->name = name; 66160573Skris mac->key = NULL; 66260573Skris mac->enabled = 0; 663295367Sdes return 0; 66460573Skris} 665162852Sdes 666295367Sdesstatic int 667295367Sdeschoose_comp(struct sshcomp *comp, char *client, char *server) 66860573Skris{ 66976259Sgreen char *name = match_list(client, server, NULL); 670295367Sdes 67160573Skris if (name == NULL) 672295367Sdes return SSH_ERR_NO_COMPRESS_ALG_MATCH; 673149749Sdes if (strcmp(name, "zlib@openssh.com") == 0) { 674149749Sdes comp->type = COMP_DELAYED; 675149749Sdes } else if (strcmp(name, "zlib") == 0) { 676149749Sdes comp->type = COMP_ZLIB; 67760573Skris } else if (strcmp(name, "none") == 0) { 678149749Sdes comp->type = COMP_NONE; 67960573Skris } else { 680295367Sdes return SSH_ERR_INTERNAL_ERROR; 68160573Skris } 68260573Skris comp->name = name; 683295367Sdes return 0; 68460573Skris} 685162852Sdes 686295367Sdesstatic int 687295367Sdeschoose_kex(struct kex *k, char *client, char *server) 68860573Skris{ 689255767Sdes const struct kexalg *kexalg; 690255767Sdes 69176259Sgreen k->name = match_list(client, server, NULL); 692295367Sdes 693296853Sdes debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); 69460573Skris if (k->name == NULL) 695295367Sdes return SSH_ERR_NO_KEX_ALG_MATCH; 696255767Sdes if ((kexalg = kex_alg_by_name(k->name)) == NULL) 697295367Sdes return SSH_ERR_INTERNAL_ERROR; 698255767Sdes k->kex_type = kexalg->type; 699262566Sdes k->hash_alg = kexalg->hash_alg; 700255767Sdes k->ec_nid = kexalg->ec_nid; 701295367Sdes return 0; 70260573Skris} 703157016Sdes 704295367Sdesstatic int 705295367Sdeschoose_hostkeyalg(struct kex *k, char *client, char *server) 70660573Skris{ 707296853Sdes k->hostkey_alg = match_list(client, server, NULL); 708295367Sdes 709296853Sdes debug("kex: host key algorithm: %s", 710296853Sdes k->hostkey_alg ? k->hostkey_alg : "(no match)"); 711296853Sdes if (k->hostkey_alg == NULL) 712295367Sdes return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 713296853Sdes k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); 71476259Sgreen if (k->hostkey_type == KEY_UNSPEC) 715295367Sdes return SSH_ERR_INTERNAL_ERROR; 716296853Sdes k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); 717295367Sdes return 0; 71860573Skris} 71960573Skris 720126274Sdesstatic int 721113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 722113908Sdes{ 723113908Sdes static int check[] = { 724113908Sdes PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 725113908Sdes }; 726113908Sdes int *idx; 727113908Sdes char *p; 728113908Sdes 729113908Sdes for (idx = &check[0]; *idx != -1; idx++) { 730113908Sdes if ((p = strchr(my[*idx], ',')) != NULL) 731113908Sdes *p = '\0'; 732113908Sdes if ((p = strchr(peer[*idx], ',')) != NULL) 733113908Sdes *p = '\0'; 734113908Sdes if (strcmp(my[*idx], peer[*idx]) != 0) { 735113908Sdes debug2("proposal mismatch: my %s peer %s", 736113908Sdes my[*idx], peer[*idx]); 737113908Sdes return (0); 738113908Sdes } 739113908Sdes } 740113908Sdes debug2("proposals match"); 741113908Sdes return (1); 742113908Sdes} 743113908Sdes 744295367Sdesstatic int 745295367Sdeskex_choose_conf(struct ssh *ssh) 74660573Skris{ 747295367Sdes struct kex *kex = ssh->kex; 748295367Sdes struct newkeys *newkeys; 749295367Sdes char **my = NULL, **peer = NULL; 75076259Sgreen char **cprop, **sprop; 75176259Sgreen int nenc, nmac, ncomp; 752262566Sdes u_int mode, ctos, need, dh_need, authlen; 753295367Sdes int r, first_kex_follows; 75460573Skris 755296853Sdes debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); 756296853Sdes if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) 757295367Sdes goto out; 758296853Sdes debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server"); 759296853Sdes if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 760296853Sdes goto out; 76160573Skris 76276259Sgreen if (kex->server) { 76376259Sgreen cprop=peer; 76476259Sgreen sprop=my; 76576259Sgreen } else { 76676259Sgreen cprop=my; 76776259Sgreen sprop=peer; 76876259Sgreen } 76976259Sgreen 770296853Sdes /* Check whether client supports ext_info_c */ 771296853Sdes if (kex->server) { 772296853Sdes char *ext; 773295367Sdes 774296853Sdes ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); 775296853Sdes if (ext) { 776296853Sdes kex->ext_info_c = 1; 777296853Sdes free(ext); 778204917Sdes } 779204917Sdes } 780204917Sdes 78176259Sgreen /* Algorithm Negotiation */ 782296853Sdes if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 783296853Sdes sprop[PROPOSAL_KEX_ALGS])) != 0) { 784296853Sdes kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; 785296853Sdes peer[PROPOSAL_KEX_ALGS] = NULL; 786296853Sdes goto out; 787296853Sdes } 788296853Sdes if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 789296853Sdes sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { 790296853Sdes kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; 791296853Sdes peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; 792296853Sdes goto out; 793296853Sdes } 79460573Skris for (mode = 0; mode < MODE_MAX; mode++) { 795295367Sdes if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 796295367Sdes r = SSH_ERR_ALLOC_FAIL; 797295367Sdes goto out; 798295367Sdes } 79976259Sgreen kex->newkeys[mode] = newkeys; 800181111Sdes ctos = (!kex->server && mode == MODE_OUT) || 801181111Sdes (kex->server && mode == MODE_IN); 80260573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 80360573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 80460573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 805295367Sdes if ((r = choose_enc(&newkeys->enc, cprop[nenc], 806295367Sdes sprop[nenc])) != 0) { 807295367Sdes kex->failed_choice = peer[nenc]; 808295367Sdes peer[nenc] = NULL; 809295367Sdes goto out; 810295367Sdes } 811295367Sdes authlen = cipher_authlen(newkeys->enc.cipher); 812248619Sdes /* ignore mac for authenticated encryption */ 813295367Sdes if (authlen == 0 && 814295367Sdes (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 815295367Sdes sprop[nmac])) != 0) { 816295367Sdes kex->failed_choice = peer[nmac]; 817295367Sdes peer[nmac] = NULL; 818295367Sdes goto out; 819295367Sdes } 820295367Sdes if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 821295367Sdes sprop[ncomp])) != 0) { 822295367Sdes kex->failed_choice = peer[ncomp]; 823295367Sdes peer[ncomp] = NULL; 824295367Sdes goto out; 825295367Sdes } 826296853Sdes debug("kex: %s cipher: %s MAC: %s compression: %s", 82760573Skris ctos ? "client->server" : "server->client", 82876259Sgreen newkeys->enc.name, 829248619Sdes authlen == 0 ? newkeys->mac.name : "<implicit>", 83076259Sgreen newkeys->comp.name); 83160573Skris } 832262566Sdes need = dh_need = 0; 83360573Skris for (mode = 0; mode < MODE_MAX; mode++) { 83476259Sgreen newkeys = kex->newkeys[mode]; 835262566Sdes need = MAX(need, newkeys->enc.key_len); 836262566Sdes need = MAX(need, newkeys->enc.block_size); 837262566Sdes need = MAX(need, newkeys->enc.iv_len); 838262566Sdes need = MAX(need, newkeys->mac.key_len); 839262566Sdes dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher)); 840262566Sdes dh_need = MAX(dh_need, newkeys->enc.block_size); 841262566Sdes dh_need = MAX(dh_need, newkeys->enc.iv_len); 842262566Sdes dh_need = MAX(dh_need, newkeys->mac.key_len); 84360573Skris } 84461209Skris /* XXX need runden? */ 84576259Sgreen kex->we_need = need; 846262566Sdes kex->dh_need = dh_need; 84776259Sgreen 848113908Sdes /* ignore the next message if the proposals do not match */ 849126274Sdes if (first_kex_follows && !proposals_match(my, peer) && 850295367Sdes !(ssh->compat & SSH_BUG_FIRSTKEX)) 851295367Sdes ssh->dispatch_skip_packets = 1; 852295367Sdes r = 0; 853295367Sdes out: 85476259Sgreen kex_prop_free(my); 85576259Sgreen kex_prop_free(peer); 856295367Sdes return r; 85760573Skris} 85860573Skris 859295367Sdesstatic int 860295367Sdesderive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 861295367Sdes const struct sshbuf *shared_secret, u_char **keyp) 86260573Skris{ 863295367Sdes struct kex *kex = ssh->kex; 864295367Sdes struct ssh_digest_ctx *hashctx = NULL; 86576259Sgreen char c = id; 866149749Sdes u_int have; 867262566Sdes size_t mdsz; 868149749Sdes u_char *digest; 869295367Sdes int r; 87060573Skris 871262566Sdes if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 872295367Sdes return SSH_ERR_INVALID_ARGUMENT; 873295367Sdes if ((digest = calloc(1, roundup(need, mdsz))) == NULL) { 874295367Sdes r = SSH_ERR_ALLOC_FAIL; 875295367Sdes goto out; 876295367Sdes } 877149749Sdes 87876259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 879295367Sdes if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 880295367Sdes ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 881262566Sdes ssh_digest_update(hashctx, hash, hashlen) != 0 || 882262566Sdes ssh_digest_update(hashctx, &c, 1) != 0 || 883262566Sdes ssh_digest_update(hashctx, kex->session_id, 884295367Sdes kex->session_id_len) != 0 || 885295367Sdes ssh_digest_final(hashctx, digest, mdsz) != 0) { 886295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 887295367Sdes goto out; 888295367Sdes } 889262566Sdes ssh_digest_free(hashctx); 890295367Sdes hashctx = NULL; 89176259Sgreen 89276259Sgreen /* 89376259Sgreen * expand key: 89476259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 89576259Sgreen * Key = K1 || K2 || ... || Kn 89676259Sgreen */ 89776259Sgreen for (have = mdsz; need > have; have += mdsz) { 898295367Sdes if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 899295367Sdes ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 900262566Sdes ssh_digest_update(hashctx, hash, hashlen) != 0 || 901295367Sdes ssh_digest_update(hashctx, digest, have) != 0 || 902295367Sdes ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 903295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 904295367Sdes goto out; 905295367Sdes } 906262566Sdes ssh_digest_free(hashctx); 907295367Sdes hashctx = NULL; 90876259Sgreen } 90976259Sgreen#ifdef DEBUG_KEX 91076259Sgreen fprintf(stderr, "key '%c'== ", c); 91176259Sgreen dump_digest("key", digest, need); 91276259Sgreen#endif 913295367Sdes *keyp = digest; 914295367Sdes digest = NULL; 915295367Sdes r = 0; 916295367Sdes out: 917296853Sdes free(digest); 918295367Sdes ssh_digest_free(hashctx); 919295367Sdes return r; 92076259Sgreen} 92176259Sgreen 92276259Sgreen#define NKEYS 6 923295367Sdesint 924295367Sdeskex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 925295367Sdes const struct sshbuf *shared_secret) 92676259Sgreen{ 927295367Sdes struct kex *kex = ssh->kex; 92876259Sgreen u_char *keys[NKEYS]; 929295367Sdes u_int i, j, mode, ctos; 930295367Sdes int r; 93176259Sgreen 932157016Sdes for (i = 0; i < NKEYS; i++) { 933295367Sdes if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 934295367Sdes shared_secret, &keys[i])) != 0) { 935295367Sdes for (j = 0; j < i; j++) 936295367Sdes free(keys[j]); 937295367Sdes return r; 938295367Sdes } 939157016Sdes } 94060573Skris for (mode = 0; mode < MODE_MAX; mode++) { 941162852Sdes ctos = (!kex->server && mode == MODE_OUT) || 942162852Sdes (kex->server && mode == MODE_IN); 943295367Sdes kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 944295367Sdes kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 945295367Sdes kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 94660573Skris } 947295367Sdes return 0; 94860573Skris} 94976259Sgreen 950295367Sdes#ifdef WITH_OPENSSL 951295367Sdesint 952295367Sdeskex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 953295367Sdes const BIGNUM *secret) 954262566Sdes{ 955295367Sdes struct sshbuf *shared_secret; 956295367Sdes int r; 957262566Sdes 958295367Sdes if ((shared_secret = sshbuf_new()) == NULL) 959295367Sdes return SSH_ERR_ALLOC_FAIL; 960295367Sdes if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 961295367Sdes r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 962295367Sdes sshbuf_free(shared_secret); 963295367Sdes return r; 964262566Sdes} 965295367Sdes#endif 966262566Sdes 967295367Sdes#ifdef WITH_SSH1 968295367Sdesint 969137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 970137015Sdes u_int8_t cookie[8], u_int8_t id[16]) 971137015Sdes{ 972295367Sdes u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; 973295367Sdes struct ssh_digest_ctx *hashctx = NULL; 974295367Sdes size_t hlen, slen; 975295367Sdes int r; 976137015Sdes 977295367Sdes hlen = BN_num_bytes(host_modulus); 978295367Sdes slen = BN_num_bytes(server_modulus); 979295367Sdes if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || 980295367Sdes slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) 981295367Sdes return SSH_ERR_KEY_BITS_MISMATCH; 982295367Sdes if (BN_bn2bin(host_modulus, hbuf) <= 0 || 983295367Sdes BN_bn2bin(server_modulus, sbuf) <= 0) { 984295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 985295367Sdes goto out; 986295367Sdes } 987295367Sdes if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { 988295367Sdes r = SSH_ERR_ALLOC_FAIL; 989295367Sdes goto out; 990295367Sdes } 991295367Sdes if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || 992295367Sdes ssh_digest_update(hashctx, sbuf, slen) != 0 || 993295367Sdes ssh_digest_update(hashctx, cookie, 8) != 0 || 994295367Sdes ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { 995295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 996295367Sdes goto out; 997295367Sdes } 998262566Sdes memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); 999295367Sdes r = 0; 1000295367Sdes out: 1001295367Sdes ssh_digest_free(hashctx); 1002295367Sdes explicit_bzero(hbuf, sizeof(hbuf)); 1003295367Sdes explicit_bzero(sbuf, sizeof(sbuf)); 1004264377Sdes explicit_bzero(obuf, sizeof(obuf)); 1005295367Sdes return r; 1006137015Sdes} 1007295367Sdes#endif 1008137015Sdes 1009221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 101076259Sgreenvoid 101176259Sgreendump_digest(char *msg, u_char *digest, int len) 101276259Sgreen{ 101376259Sgreen fprintf(stderr, "%s\n", msg); 1014295367Sdes sshbuf_dump_data(digest, len, stderr); 101576259Sgreen} 101676259Sgreen#endif 1017