1323124Sdes/* $OpenBSD: kex.c,v 1.118 2016/05/02 10:26:04 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> 38323124Sdes#include <openssl/dh.h> 39295367Sdes#endif 4076259Sgreen 4160573Skris#include "ssh2.h" 4261209Skris#include "packet.h" 4360573Skris#include "compat.h" 4476259Sgreen#include "cipher.h" 45295367Sdes#include "sshkey.h" 4660573Skris#include "kex.h" 4776259Sgreen#include "log.h" 4876259Sgreen#include "mac.h" 4976259Sgreen#include "match.h" 50295367Sdes#include "misc.h" 5176259Sgreen#include "dispatch.h" 5298675Sdes#include "monitor.h" 53295367Sdes 54295367Sdes#include "ssherr.h" 55295367Sdes#include "sshbuf.h" 56262566Sdes#include "digest.h" 5760573Skris 58162852Sdes#if OPENSSL_VERSION_NUMBER >= 0x00907000L 59162852Sdes# if defined(HAVE_EVP_SHA256) 60162852Sdes# define evp_ssh_sha256 EVP_sha256 61162852Sdes# else 62162852Sdesextern const EVP_MD *evp_ssh_sha256(void); 63162852Sdes# endif 64162852Sdes#endif 65162852Sdes 6692555Sdes/* prototype */ 67295367Sdesstatic int kex_choose_conf(struct ssh *); 68295367Sdesstatic int kex_input_newkeys(int, u_int32_t, void *); 6976259Sgreen 70296781Sdesstatic const char *proposal_names[PROPOSAL_MAX] = { 71296781Sdes "KEX algorithms", 72296781Sdes "host key algorithms", 73296781Sdes "ciphers ctos", 74296781Sdes "ciphers stoc", 75296781Sdes "MACs ctos", 76296781Sdes "MACs stoc", 77296781Sdes "compression ctos", 78296781Sdes "compression stoc", 79296781Sdes "languages ctos", 80296781Sdes "languages stoc", 81296781Sdes}; 82296781Sdes 83255767Sdesstruct kexalg { 84255767Sdes char *name; 85295367Sdes u_int type; 86255767Sdes int ec_nid; 87262566Sdes int hash_alg; 88255767Sdes}; 89255767Sdesstatic const struct kexalg kexalgs[] = { 90295367Sdes#ifdef WITH_OPENSSL 91262566Sdes { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 92323124Sdes { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 93323124Sdes { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, 94323124Sdes { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, 95323124Sdes { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 }, 96262566Sdes { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 97255767Sdes#ifdef HAVE_EVP_SHA256 98262566Sdes { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 99295367Sdes#endif /* HAVE_EVP_SHA256 */ 100255767Sdes#ifdef OPENSSL_HAS_ECC 101262566Sdes { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 102262566Sdes NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 103262566Sdes { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, 104262566Sdes SSH_DIGEST_SHA384 }, 105262566Sdes# ifdef OPENSSL_HAS_NISTP521 106262566Sdes { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 107262566Sdes SSH_DIGEST_SHA512 }, 108295367Sdes# endif /* OPENSSL_HAS_NISTP521 */ 109295367Sdes#endif /* OPENSSL_HAS_ECC */ 110295367Sdes#endif /* WITH_OPENSSL */ 111295367Sdes#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) 112262566Sdes { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 113295367Sdes#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 114262566Sdes { NULL, -1, -1, -1}, 115255767Sdes}; 116255767Sdes 117255767Sdeschar * 118262566Sdeskex_alg_list(char sep) 119255767Sdes{ 120295367Sdes char *ret = NULL, *tmp; 121255767Sdes size_t nlen, rlen = 0; 122255767Sdes const struct kexalg *k; 123255767Sdes 124255767Sdes for (k = kexalgs; k->name != NULL; k++) { 125255767Sdes if (ret != NULL) 126262566Sdes ret[rlen++] = sep; 127255767Sdes nlen = strlen(k->name); 128295367Sdes if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 129295367Sdes free(ret); 130295367Sdes return NULL; 131295367Sdes } 132295367Sdes ret = tmp; 133255767Sdes memcpy(ret + rlen, k->name, nlen + 1); 134255767Sdes rlen += nlen; 135255767Sdes } 136255767Sdes return ret; 137255767Sdes} 138255767Sdes 139255767Sdesstatic const struct kexalg * 140255767Sdeskex_alg_by_name(const char *name) 141255767Sdes{ 142255767Sdes const struct kexalg *k; 143255767Sdes 144255767Sdes for (k = kexalgs; k->name != NULL; k++) { 145255767Sdes if (strcmp(k->name, name) == 0) 146255767Sdes return k; 147255767Sdes } 148255767Sdes return NULL; 149255767Sdes} 150255767Sdes 151221420Sdes/* Validate KEX method name list */ 152221420Sdesint 153221420Sdeskex_names_valid(const char *names) 154221420Sdes{ 155221420Sdes char *s, *cp, *p; 156221420Sdes 157221420Sdes if (names == NULL || strcmp(names, "") == 0) 158221420Sdes return 0; 159295367Sdes if ((s = cp = strdup(names)) == NULL) 160295367Sdes return 0; 161221420Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; 162221420Sdes (p = strsep(&cp, ","))) { 163255767Sdes if (kex_alg_by_name(p) == NULL) { 164221420Sdes error("Unsupported KEX algorithm \"%.100s\"", p); 165255767Sdes free(s); 166221420Sdes return 0; 167221420Sdes } 168221420Sdes } 169221420Sdes debug3("kex names ok: [%s]", names); 170255767Sdes free(s); 171221420Sdes return 1; 172221420Sdes} 173221420Sdes 174295367Sdes/* 175295367Sdes * Concatenate algorithm names, avoiding duplicates in the process. 176295367Sdes * Caller must free returned string. 177295367Sdes */ 178295367Sdeschar * 179295367Sdeskex_names_cat(const char *a, const char *b) 180295367Sdes{ 181295367Sdes char *ret = NULL, *tmp = NULL, *cp, *p; 182295367Sdes size_t len; 183295367Sdes 184295367Sdes if (a == NULL || *a == '\0') 185295367Sdes return NULL; 186295367Sdes if (b == NULL || *b == '\0') 187295367Sdes return strdup(a); 188295367Sdes if (strlen(b) > 1024*1024) 189295367Sdes return NULL; 190295367Sdes len = strlen(a) + strlen(b) + 2; 191295367Sdes if ((tmp = cp = strdup(b)) == NULL || 192295367Sdes (ret = calloc(1, len)) == NULL) { 193295367Sdes free(tmp); 194295367Sdes return NULL; 195295367Sdes } 196295367Sdes strlcpy(ret, a, len); 197295367Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { 198295367Sdes if (match_list(ret, p, NULL) != NULL) 199295367Sdes continue; /* Algorithm already present */ 200295367Sdes if (strlcat(ret, ",", len) >= len || 201295367Sdes strlcat(ret, p, len) >= len) { 202295367Sdes free(tmp); 203295367Sdes free(ret); 204295367Sdes return NULL; /* Shouldn't happen */ 205295367Sdes } 206295367Sdes } 207295367Sdes free(tmp); 208295367Sdes return ret; 209295367Sdes} 210295367Sdes 211295367Sdes/* 212295367Sdes * Assemble a list of algorithms from a default list and a string from a 213295367Sdes * configuration file. The user-provided string may begin with '+' to 214295367Sdes * indicate that it should be appended to the default. 215295367Sdes */ 216295367Sdesint 217295367Sdeskex_assemble_names(const char *def, char **list) 218295367Sdes{ 219295367Sdes char *ret; 220295367Sdes 221295367Sdes if (list == NULL || *list == NULL || **list == '\0') { 222295367Sdes *list = strdup(def); 223295367Sdes return 0; 224295367Sdes } 225295367Sdes if (**list != '+') { 226295367Sdes return 0; 227295367Sdes } 228295367Sdes 229295367Sdes if ((ret = kex_names_cat(def, *list + 1)) == NULL) 230295367Sdes return SSH_ERR_ALLOC_FAIL; 231295367Sdes free(*list); 232295367Sdes *list = ret; 233295367Sdes return 0; 234295367Sdes} 235295367Sdes 236294693Sdes/* put algorithm proposal into buffer */ 237295367Sdesint 238295367Sdeskex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 23960573Skris{ 240149749Sdes u_int i; 241295367Sdes int r; 24276259Sgreen 243295367Sdes sshbuf_reset(b); 244295367Sdes 24598675Sdes /* 24698675Sdes * add a dummy cookie, the cookie will be overwritten by 24798675Sdes * kex_send_kexinit(), each time a kexinit is set 24898675Sdes */ 249295367Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) { 250295367Sdes if ((r = sshbuf_put_u8(b, 0)) != 0) 251295367Sdes return r; 252295367Sdes } 253295367Sdes for (i = 0; i < PROPOSAL_MAX; i++) { 254295367Sdes if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 255295367Sdes return r; 256295367Sdes } 257295367Sdes if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 258295367Sdes (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 259295367Sdes return r; 260295367Sdes return 0; 26160573Skris} 26260573Skris 26376259Sgreen/* parse buffer and return algorithm proposal */ 264295367Sdesint 265295367Sdeskex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 26661209Skris{ 267295367Sdes struct sshbuf *b = NULL; 268295367Sdes u_char v; 269181111Sdes u_int i; 270295367Sdes char **proposal = NULL; 271295367Sdes int r; 27261209Skris 273295367Sdes *propp = NULL; 274295367Sdes if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 275295367Sdes return SSH_ERR_ALLOC_FAIL; 276295367Sdes if ((b = sshbuf_fromb(raw)) == NULL) { 277295367Sdes r = SSH_ERR_ALLOC_FAIL; 278295367Sdes goto out; 279295367Sdes } 280295367Sdes if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 281295367Sdes goto out; 28261209Skris /* extract kex init proposal strings */ 28361209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 284295367Sdes if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 285295367Sdes goto out; 286296781Sdes debug2("%s: %s", proposal_names[i], proposal[i]); 28761209Skris } 28876259Sgreen /* first kex follows / reserved */ 289295367Sdes if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ 290295367Sdes (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ 291295367Sdes goto out; 292113908Sdes if (first_kex_follows != NULL) 293295367Sdes *first_kex_follows = v; 294295367Sdes debug2("first_kex_follows %d ", v); 295295367Sdes debug2("reserved %u ", i); 296295367Sdes r = 0; 297295367Sdes *propp = proposal; 298295367Sdes out: 299295367Sdes if (r != 0 && proposal != NULL) 300295367Sdes kex_prop_free(proposal); 301295367Sdes sshbuf_free(b); 302295367Sdes return r; 30361209Skris} 30461209Skris 305295367Sdesvoid 30676259Sgreenkex_prop_free(char **proposal) 30760573Skris{ 308149749Sdes u_int i; 30960573Skris 310295367Sdes if (proposal == NULL) 311295367Sdes return; 31276259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 313255767Sdes free(proposal[i]); 314255767Sdes free(proposal); 31560573Skris} 31660573Skris 317181111Sdes/* ARGSUSED */ 318295367Sdesstatic int 31992555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt) 32060573Skris{ 321296781Sdes struct ssh *ssh = active_state; /* XXX */ 322296781Sdes int r; 323296781Sdes 324296781Sdes error("kex protocol error: type %d seq %u", type, seq); 325296781Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || 326296781Sdes (r = sshpkt_put_u32(ssh, seq)) != 0 || 327296781Sdes (r = sshpkt_send(ssh)) != 0) 328296781Sdes return r; 329295367Sdes return 0; 33060573Skris} 33160573Skris 33292555Sdesstatic void 333295367Sdeskex_reset_dispatch(struct ssh *ssh) 33469587Sgreen{ 335295367Sdes ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 33692555Sdes SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 337295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 33869587Sgreen} 33969587Sgreen 340296781Sdesstatic int 341296781Sdeskex_send_ext_info(struct ssh *ssh) 342296781Sdes{ 343296781Sdes int r; 344296781Sdes 345296781Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || 346296781Sdes (r = sshpkt_put_u32(ssh, 1)) != 0 || 347296781Sdes (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || 348296781Sdes (r = sshpkt_put_cstring(ssh, "rsa-sha2-256,rsa-sha2-512")) != 0 || 349296781Sdes (r = sshpkt_send(ssh)) != 0) 350296781Sdes return r; 351296781Sdes return 0; 352296781Sdes} 353296781Sdes 354295367Sdesint 355295367Sdeskex_send_newkeys(struct ssh *ssh) 35669587Sgreen{ 357295367Sdes int r; 35869587Sgreen 359295367Sdes kex_reset_dispatch(ssh); 360295367Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 361295367Sdes (r = sshpkt_send(ssh)) != 0) 362295367Sdes return r; 36376259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 364295367Sdes debug("expecting SSH2_MSG_NEWKEYS"); 365295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 366296781Sdes if (ssh->kex->ext_info_c) 367296781Sdes if ((r = kex_send_ext_info(ssh)) != 0) 368296781Sdes return r; 369295367Sdes return 0; 370295367Sdes} 37169587Sgreen 372296781Sdesint 373296781Sdeskex_input_ext_info(int type, u_int32_t seq, void *ctxt) 374296781Sdes{ 375296781Sdes struct ssh *ssh = ctxt; 376296781Sdes struct kex *kex = ssh->kex; 377296781Sdes u_int32_t i, ninfo; 378296781Sdes char *name, *val, *found; 379296781Sdes int r; 380296781Sdes 381296781Sdes debug("SSH2_MSG_EXT_INFO received"); 382296781Sdes ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); 383296781Sdes if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) 384296781Sdes return r; 385296781Sdes for (i = 0; i < ninfo; i++) { 386296781Sdes if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) 387296781Sdes return r; 388296781Sdes if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) { 389296781Sdes free(name); 390296781Sdes return r; 391296781Sdes } 392296781Sdes debug("%s: %s=<%s>", __func__, name, val); 393296781Sdes if (strcmp(name, "server-sig-algs") == 0) { 394296781Sdes found = match_list("rsa-sha2-256", val, NULL); 395296781Sdes if (found) { 396296781Sdes kex->rsa_sha2 = 256; 397296781Sdes free(found); 398296781Sdes } 399296781Sdes found = match_list("rsa-sha2-512", val, NULL); 400296781Sdes if (found) { 401296781Sdes kex->rsa_sha2 = 512; 402296781Sdes free(found); 403296781Sdes } 404296781Sdes } 405296781Sdes free(name); 406296781Sdes free(val); 407296781Sdes } 408296781Sdes return sshpkt_get_end(ssh); 409296781Sdes} 410296781Sdes 411295367Sdesstatic int 412295367Sdeskex_input_newkeys(int type, u_int32_t seq, void *ctxt) 413295367Sdes{ 414295367Sdes struct ssh *ssh = ctxt; 415295367Sdes struct kex *kex = ssh->kex; 416295367Sdes int r; 417295367Sdes 41876259Sgreen debug("SSH2_MSG_NEWKEYS received"); 419295367Sdes ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 420295367Sdes if ((r = sshpkt_get_end(ssh)) != 0) 421295367Sdes return r; 42276259Sgreen kex->done = 1; 423295367Sdes sshbuf_reset(kex->peer); 424295367Sdes /* sshbuf_reset(kex->my); */ 42576259Sgreen kex->flags &= ~KEX_INIT_SENT; 426255767Sdes free(kex->name); 42776259Sgreen kex->name = NULL; 428295367Sdes return 0; 42969587Sgreen} 43069587Sgreen 431295367Sdesint 432295367Sdeskex_send_kexinit(struct ssh *ssh) 43360573Skris{ 43498675Sdes u_char *cookie; 435295367Sdes struct kex *kex = ssh->kex; 436295367Sdes int r; 43798675Sdes 438295367Sdes if (kex == NULL) 439295367Sdes return SSH_ERR_INTERNAL_ERROR; 440295367Sdes if (kex->flags & KEX_INIT_SENT) 441295367Sdes return 0; 44276259Sgreen kex->done = 0; 44398675Sdes 44498675Sdes /* generate a random cookie */ 445295367Sdes if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 446295367Sdes return SSH_ERR_INVALID_FORMAT; 447295367Sdes if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 448295367Sdes return SSH_ERR_INTERNAL_ERROR; 449295367Sdes arc4random_buf(cookie, KEX_COOKIE_LEN); 450295367Sdes 451295367Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 452295367Sdes (r = sshpkt_putb(ssh, kex->my)) != 0 || 453295367Sdes (r = sshpkt_send(ssh)) != 0) 454295367Sdes return r; 45576259Sgreen debug("SSH2_MSG_KEXINIT sent"); 45676259Sgreen kex->flags |= KEX_INIT_SENT; 457295367Sdes return 0; 45860573Skris} 45960573Skris 460181111Sdes/* ARGSUSED */ 461295367Sdesint 46292555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 46360573Skris{ 464295367Sdes struct ssh *ssh = ctxt; 465295367Sdes struct kex *kex = ssh->kex; 466295367Sdes const u_char *ptr; 467295367Sdes u_int i; 468295367Sdes size_t dlen; 469295367Sdes int r; 47060573Skris 47176259Sgreen debug("SSH2_MSG_KEXINIT received"); 47276259Sgreen if (kex == NULL) 473295367Sdes return SSH_ERR_INVALID_ARGUMENT; 47460573Skris 475295367Sdes ptr = sshpkt_ptr(ssh, &dlen); 476295367Sdes if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 477295367Sdes return r; 47860573Skris 47976259Sgreen /* discard packet */ 48076259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 481295367Sdes if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 482295367Sdes return r; 48376259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 484295367Sdes if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 485295367Sdes return r; 486248619Sdes /* 487248619Sdes * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 488248619Sdes * KEX method has the server move first, but a server might be using 489248619Sdes * a custom method or one that we otherwise don't support. We should 490248619Sdes * be prepared to remember first_kex_follows here so we can eat a 491248619Sdes * packet later. 492248619Sdes * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 493248619Sdes * for cases where the server *doesn't* go first. I guess we should 494248619Sdes * ignore it when it is set for these cases, which is what we do now. 495248619Sdes */ 496295367Sdes if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 497295367Sdes (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 498295367Sdes (r = sshpkt_get_end(ssh)) != 0) 499295367Sdes return r; 50060573Skris 501295367Sdes if (!(kex->flags & KEX_INIT_SENT)) 502295367Sdes if ((r = kex_send_kexinit(ssh)) != 0) 503295367Sdes return r; 504295367Sdes if ((r = kex_choose_conf(ssh)) != 0) 505295367Sdes return r; 506295367Sdes 507295367Sdes if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 508295367Sdes return (kex->kex[kex->kex_type])(ssh); 509295367Sdes 510295367Sdes return SSH_ERR_INTERNAL_ERROR; 51160573Skris} 51260573Skris 513295367Sdesint 514295367Sdeskex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 51569587Sgreen{ 516295367Sdes struct kex *kex; 517295367Sdes int r; 51869587Sgreen 519295367Sdes *kexp = NULL; 520295367Sdes if ((kex = calloc(1, sizeof(*kex))) == NULL) 521295367Sdes return SSH_ERR_ALLOC_FAIL; 522295367Sdes if ((kex->peer = sshbuf_new()) == NULL || 523295367Sdes (kex->my = sshbuf_new()) == NULL) { 524295367Sdes r = SSH_ERR_ALLOC_FAIL; 525295367Sdes goto out; 526295367Sdes } 527295367Sdes if ((r = kex_prop2buf(kex->my, proposal)) != 0) 528295367Sdes goto out; 52976259Sgreen kex->done = 0; 530295367Sdes kex_reset_dispatch(ssh); 531295367Sdes r = 0; 532295367Sdes *kexp = kex; 533295367Sdes out: 534295367Sdes if (r != 0) 535295367Sdes kex_free(kex); 536295367Sdes return r; 537295367Sdes} 53869587Sgreen 539295367Sdesvoid 540295367Sdeskex_free_newkeys(struct newkeys *newkeys) 541295367Sdes{ 542295367Sdes if (newkeys == NULL) 543295367Sdes return; 544295367Sdes if (newkeys->enc.key) { 545295367Sdes explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 546295367Sdes free(newkeys->enc.key); 547295367Sdes newkeys->enc.key = NULL; 548295367Sdes } 549295367Sdes if (newkeys->enc.iv) { 550296781Sdes explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len); 551295367Sdes free(newkeys->enc.iv); 552295367Sdes newkeys->enc.iv = NULL; 553295367Sdes } 554295367Sdes free(newkeys->enc.name); 555295367Sdes explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 556295367Sdes free(newkeys->comp.name); 557295367Sdes explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 558295367Sdes mac_clear(&newkeys->mac); 559295367Sdes if (newkeys->mac.key) { 560295367Sdes explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 561295367Sdes free(newkeys->mac.key); 562295367Sdes newkeys->mac.key = NULL; 563295367Sdes } 564295367Sdes free(newkeys->mac.name); 565295367Sdes explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 566295367Sdes explicit_bzero(newkeys, sizeof(*newkeys)); 567295367Sdes free(newkeys); 568295367Sdes} 56969587Sgreen 570295367Sdesvoid 571295367Sdeskex_free(struct kex *kex) 572295367Sdes{ 573295367Sdes u_int mode; 574295367Sdes 575295367Sdes#ifdef WITH_OPENSSL 576295367Sdes if (kex->dh) 577295367Sdes DH_free(kex->dh); 578295367Sdes#ifdef OPENSSL_HAS_ECC 579295367Sdes if (kex->ec_client_key) 580295367Sdes EC_KEY_free(kex->ec_client_key); 581295367Sdes#endif /* OPENSSL_HAS_ECC */ 582295367Sdes#endif /* WITH_OPENSSL */ 583295367Sdes for (mode = 0; mode < MODE_MAX; mode++) { 584295367Sdes kex_free_newkeys(kex->newkeys[mode]); 585295367Sdes kex->newkeys[mode] = NULL; 586295367Sdes } 587295367Sdes sshbuf_free(kex->peer); 588295367Sdes sshbuf_free(kex->my); 589295367Sdes free(kex->session_id); 590295367Sdes free(kex->client_version_string); 591295367Sdes free(kex->server_version_string); 592295367Sdes free(kex->failed_choice); 593296781Sdes free(kex->hostkey_alg); 594296781Sdes free(kex->name); 595295367Sdes free(kex); 59669587Sgreen} 59769587Sgreen 598295367Sdesint 599295367Sdeskex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 60060573Skris{ 601295367Sdes int r; 60260573Skris 603295367Sdes if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 604295367Sdes return r; 605295367Sdes if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 606295367Sdes kex_free(ssh->kex); 607295367Sdes ssh->kex = NULL; 608295367Sdes return r; 60960573Skris } 610295367Sdes return 0; 61160573Skris} 61260573Skris 613296781Sdes/* 614296781Sdes * Request key re-exchange, returns 0 on success or a ssherr.h error 615296781Sdes * code otherwise. Must not be called if KEX is incomplete or in-progress. 616296781Sdes */ 617296781Sdesint 618296781Sdeskex_start_rekex(struct ssh *ssh) 619296781Sdes{ 620296781Sdes if (ssh->kex == NULL) { 621296781Sdes error("%s: no kex", __func__); 622296781Sdes return SSH_ERR_INTERNAL_ERROR; 623296781Sdes } 624296781Sdes if (ssh->kex->done == 0) { 625296781Sdes error("%s: requested twice", __func__); 626296781Sdes return SSH_ERR_INTERNAL_ERROR; 627296781Sdes } 628296781Sdes ssh->kex->done = 0; 629296781Sdes return kex_send_kexinit(ssh); 630296781Sdes} 631296781Sdes 632295367Sdesstatic int 633295367Sdeschoose_enc(struct sshenc *enc, char *client, char *server) 63460573Skris{ 63576259Sgreen char *name = match_list(client, server, NULL); 636295367Sdes 63760573Skris if (name == NULL) 638295367Sdes return SSH_ERR_NO_CIPHER_ALG_MATCH; 63992555Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) 640295367Sdes return SSH_ERR_INTERNAL_ERROR; 64160573Skris enc->name = name; 64260573Skris enc->enabled = 0; 64360573Skris enc->iv = NULL; 644248619Sdes enc->iv_len = cipher_ivlen(enc->cipher); 64560573Skris enc->key = NULL; 64692555Sdes enc->key_len = cipher_keylen(enc->cipher); 64792555Sdes enc->block_size = cipher_blocksize(enc->cipher); 648295367Sdes return 0; 64960573Skris} 650162852Sdes 651295367Sdesstatic int 652295367Sdeschoose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 65360573Skris{ 65476259Sgreen char *name = match_list(client, server, NULL); 655295367Sdes 65660573Skris if (name == NULL) 657295367Sdes return SSH_ERR_NO_MAC_ALG_MATCH; 658181111Sdes if (mac_setup(mac, name) < 0) 659295367Sdes return SSH_ERR_INTERNAL_ERROR; 66076259Sgreen /* truncate the key */ 661295367Sdes if (ssh->compat & SSH_BUG_HMAC) 66276259Sgreen mac->key_len = 16; 66360573Skris mac->name = name; 66460573Skris mac->key = NULL; 66560573Skris mac->enabled = 0; 666295367Sdes return 0; 66760573Skris} 668162852Sdes 669295367Sdesstatic int 670295367Sdeschoose_comp(struct sshcomp *comp, char *client, char *server) 67160573Skris{ 67276259Sgreen char *name = match_list(client, server, NULL); 673295367Sdes 67460573Skris if (name == NULL) 675295367Sdes return SSH_ERR_NO_COMPRESS_ALG_MATCH; 676149749Sdes if (strcmp(name, "zlib@openssh.com") == 0) { 677149749Sdes comp->type = COMP_DELAYED; 678149749Sdes } else if (strcmp(name, "zlib") == 0) { 679149749Sdes comp->type = COMP_ZLIB; 68060573Skris } else if (strcmp(name, "none") == 0) { 681149749Sdes comp->type = COMP_NONE; 68260573Skris } else { 683295367Sdes return SSH_ERR_INTERNAL_ERROR; 68460573Skris } 68560573Skris comp->name = name; 686295367Sdes return 0; 68760573Skris} 688162852Sdes 689295367Sdesstatic int 690295367Sdeschoose_kex(struct kex *k, char *client, char *server) 69160573Skris{ 692255767Sdes const struct kexalg *kexalg; 693255767Sdes 69476259Sgreen k->name = match_list(client, server, NULL); 695295367Sdes 696296781Sdes debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); 69760573Skris if (k->name == NULL) 698295367Sdes return SSH_ERR_NO_KEX_ALG_MATCH; 699255767Sdes if ((kexalg = kex_alg_by_name(k->name)) == NULL) 700295367Sdes return SSH_ERR_INTERNAL_ERROR; 701255767Sdes k->kex_type = kexalg->type; 702262566Sdes k->hash_alg = kexalg->hash_alg; 703255767Sdes k->ec_nid = kexalg->ec_nid; 704295367Sdes return 0; 70560573Skris} 706157016Sdes 707295367Sdesstatic int 708295367Sdeschoose_hostkeyalg(struct kex *k, char *client, char *server) 70960573Skris{ 710296781Sdes k->hostkey_alg = match_list(client, server, NULL); 711295367Sdes 712296781Sdes debug("kex: host key algorithm: %s", 713296781Sdes k->hostkey_alg ? k->hostkey_alg : "(no match)"); 714296781Sdes if (k->hostkey_alg == NULL) 715295367Sdes return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 716296781Sdes k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); 71776259Sgreen if (k->hostkey_type == KEY_UNSPEC) 718295367Sdes return SSH_ERR_INTERNAL_ERROR; 719296781Sdes k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); 720295367Sdes return 0; 72160573Skris} 72260573Skris 723126274Sdesstatic int 724113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 725113908Sdes{ 726113908Sdes static int check[] = { 727113908Sdes PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 728113908Sdes }; 729113908Sdes int *idx; 730113908Sdes char *p; 731113908Sdes 732113908Sdes for (idx = &check[0]; *idx != -1; idx++) { 733113908Sdes if ((p = strchr(my[*idx], ',')) != NULL) 734113908Sdes *p = '\0'; 735113908Sdes if ((p = strchr(peer[*idx], ',')) != NULL) 736113908Sdes *p = '\0'; 737113908Sdes if (strcmp(my[*idx], peer[*idx]) != 0) { 738113908Sdes debug2("proposal mismatch: my %s peer %s", 739113908Sdes my[*idx], peer[*idx]); 740113908Sdes return (0); 741113908Sdes } 742113908Sdes } 743113908Sdes debug2("proposals match"); 744113908Sdes return (1); 745113908Sdes} 746113908Sdes 747295367Sdesstatic int 748295367Sdeskex_choose_conf(struct ssh *ssh) 74960573Skris{ 750295367Sdes struct kex *kex = ssh->kex; 751295367Sdes struct newkeys *newkeys; 752295367Sdes char **my = NULL, **peer = NULL; 75376259Sgreen char **cprop, **sprop; 75476259Sgreen int nenc, nmac, ncomp; 755262566Sdes u_int mode, ctos, need, dh_need, authlen; 756295367Sdes int r, first_kex_follows; 75760573Skris 758296781Sdes debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); 759296781Sdes if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) 760295367Sdes goto out; 761296781Sdes debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server"); 762296781Sdes if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 763296781Sdes goto out; 76460573Skris 76576259Sgreen if (kex->server) { 76676259Sgreen cprop=peer; 76776259Sgreen sprop=my; 76876259Sgreen } else { 76976259Sgreen cprop=my; 77076259Sgreen sprop=peer; 77176259Sgreen } 77276259Sgreen 773296781Sdes /* Check whether client supports ext_info_c */ 774296781Sdes if (kex->server) { 775296781Sdes char *ext; 776295367Sdes 777296781Sdes ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); 778296781Sdes if (ext) { 779296781Sdes kex->ext_info_c = 1; 780296781Sdes free(ext); 781204917Sdes } 782204917Sdes } 783204917Sdes 78476259Sgreen /* Algorithm Negotiation */ 785296781Sdes if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 786296781Sdes sprop[PROPOSAL_KEX_ALGS])) != 0) { 787296781Sdes kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; 788296781Sdes peer[PROPOSAL_KEX_ALGS] = NULL; 789296781Sdes goto out; 790296781Sdes } 791296781Sdes if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 792296781Sdes sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { 793296781Sdes kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; 794296781Sdes peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; 795296781Sdes goto out; 796296781Sdes } 79760573Skris for (mode = 0; mode < MODE_MAX; mode++) { 798295367Sdes if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 799295367Sdes r = SSH_ERR_ALLOC_FAIL; 800295367Sdes goto out; 801295367Sdes } 80276259Sgreen kex->newkeys[mode] = newkeys; 803181111Sdes ctos = (!kex->server && mode == MODE_OUT) || 804181111Sdes (kex->server && mode == MODE_IN); 80560573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 80660573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 80760573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 808295367Sdes if ((r = choose_enc(&newkeys->enc, cprop[nenc], 809295367Sdes sprop[nenc])) != 0) { 810295367Sdes kex->failed_choice = peer[nenc]; 811295367Sdes peer[nenc] = NULL; 812295367Sdes goto out; 813295367Sdes } 814295367Sdes authlen = cipher_authlen(newkeys->enc.cipher); 815248619Sdes /* ignore mac for authenticated encryption */ 816295367Sdes if (authlen == 0 && 817295367Sdes (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 818295367Sdes sprop[nmac])) != 0) { 819295367Sdes kex->failed_choice = peer[nmac]; 820295367Sdes peer[nmac] = NULL; 821295367Sdes goto out; 822295367Sdes } 823295367Sdes if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 824295367Sdes sprop[ncomp])) != 0) { 825295367Sdes kex->failed_choice = peer[ncomp]; 826295367Sdes peer[ncomp] = NULL; 827295367Sdes goto out; 828295367Sdes } 829296781Sdes debug("kex: %s cipher: %s MAC: %s compression: %s", 83060573Skris ctos ? "client->server" : "server->client", 83176259Sgreen newkeys->enc.name, 832248619Sdes authlen == 0 ? newkeys->mac.name : "<implicit>", 83376259Sgreen newkeys->comp.name); 83460573Skris } 835262566Sdes need = dh_need = 0; 83660573Skris for (mode = 0; mode < MODE_MAX; mode++) { 83776259Sgreen newkeys = kex->newkeys[mode]; 838262566Sdes need = MAX(need, newkeys->enc.key_len); 839262566Sdes need = MAX(need, newkeys->enc.block_size); 840262566Sdes need = MAX(need, newkeys->enc.iv_len); 841262566Sdes need = MAX(need, newkeys->mac.key_len); 842262566Sdes dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher)); 843262566Sdes dh_need = MAX(dh_need, newkeys->enc.block_size); 844262566Sdes dh_need = MAX(dh_need, newkeys->enc.iv_len); 845262566Sdes dh_need = MAX(dh_need, newkeys->mac.key_len); 84660573Skris } 84761209Skris /* XXX need runden? */ 84876259Sgreen kex->we_need = need; 849262566Sdes kex->dh_need = dh_need; 85076259Sgreen 851113908Sdes /* ignore the next message if the proposals do not match */ 852126274Sdes if (first_kex_follows && !proposals_match(my, peer) && 853295367Sdes !(ssh->compat & SSH_BUG_FIRSTKEX)) 854295367Sdes ssh->dispatch_skip_packets = 1; 855295367Sdes r = 0; 856295367Sdes out: 85776259Sgreen kex_prop_free(my); 85876259Sgreen kex_prop_free(peer); 859295367Sdes return r; 86060573Skris} 86160573Skris 862295367Sdesstatic int 863295367Sdesderive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 864295367Sdes const struct sshbuf *shared_secret, u_char **keyp) 86560573Skris{ 866295367Sdes struct kex *kex = ssh->kex; 867295367Sdes struct ssh_digest_ctx *hashctx = NULL; 86876259Sgreen char c = id; 869149749Sdes u_int have; 870262566Sdes size_t mdsz; 871149749Sdes u_char *digest; 872295367Sdes int r; 87360573Skris 874262566Sdes if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 875295367Sdes return SSH_ERR_INVALID_ARGUMENT; 876295367Sdes if ((digest = calloc(1, roundup(need, mdsz))) == NULL) { 877295367Sdes r = SSH_ERR_ALLOC_FAIL; 878295367Sdes goto out; 879295367Sdes } 880149749Sdes 88176259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 882295367Sdes if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 883295367Sdes ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 884262566Sdes ssh_digest_update(hashctx, hash, hashlen) != 0 || 885262566Sdes ssh_digest_update(hashctx, &c, 1) != 0 || 886262566Sdes ssh_digest_update(hashctx, kex->session_id, 887295367Sdes kex->session_id_len) != 0 || 888295367Sdes ssh_digest_final(hashctx, digest, mdsz) != 0) { 889295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 890295367Sdes goto out; 891295367Sdes } 892262566Sdes ssh_digest_free(hashctx); 893295367Sdes hashctx = NULL; 89476259Sgreen 89576259Sgreen /* 89676259Sgreen * expand key: 89776259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 89876259Sgreen * Key = K1 || K2 || ... || Kn 89976259Sgreen */ 90076259Sgreen for (have = mdsz; need > have; have += mdsz) { 901295367Sdes if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 902295367Sdes ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 903262566Sdes ssh_digest_update(hashctx, hash, hashlen) != 0 || 904295367Sdes ssh_digest_update(hashctx, digest, have) != 0 || 905295367Sdes ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 906295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 907295367Sdes goto out; 908295367Sdes } 909262566Sdes ssh_digest_free(hashctx); 910295367Sdes hashctx = NULL; 91176259Sgreen } 91276259Sgreen#ifdef DEBUG_KEX 91376259Sgreen fprintf(stderr, "key '%c'== ", c); 91476259Sgreen dump_digest("key", digest, need); 91576259Sgreen#endif 916295367Sdes *keyp = digest; 917295367Sdes digest = NULL; 918295367Sdes r = 0; 919295367Sdes out: 920296781Sdes free(digest); 921295367Sdes ssh_digest_free(hashctx); 922295367Sdes return r; 92376259Sgreen} 92476259Sgreen 92576259Sgreen#define NKEYS 6 926295367Sdesint 927295367Sdeskex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 928295367Sdes const struct sshbuf *shared_secret) 92976259Sgreen{ 930295367Sdes struct kex *kex = ssh->kex; 93176259Sgreen u_char *keys[NKEYS]; 932295367Sdes u_int i, j, mode, ctos; 933295367Sdes int r; 93476259Sgreen 935157016Sdes for (i = 0; i < NKEYS; i++) { 936295367Sdes if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 937295367Sdes shared_secret, &keys[i])) != 0) { 938295367Sdes for (j = 0; j < i; j++) 939295367Sdes free(keys[j]); 940295367Sdes return r; 941295367Sdes } 942157016Sdes } 94360573Skris for (mode = 0; mode < MODE_MAX; mode++) { 944162852Sdes ctos = (!kex->server && mode == MODE_OUT) || 945162852Sdes (kex->server && mode == MODE_IN); 946295367Sdes kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 947295367Sdes kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 948295367Sdes kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 94960573Skris } 950295367Sdes return 0; 95160573Skris} 95276259Sgreen 953295367Sdes#ifdef WITH_OPENSSL 954295367Sdesint 955295367Sdeskex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 956295367Sdes const BIGNUM *secret) 957262566Sdes{ 958295367Sdes struct sshbuf *shared_secret; 959295367Sdes int r; 960262566Sdes 961295367Sdes if ((shared_secret = sshbuf_new()) == NULL) 962295367Sdes return SSH_ERR_ALLOC_FAIL; 963295367Sdes if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 964295367Sdes r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 965295367Sdes sshbuf_free(shared_secret); 966295367Sdes return r; 967262566Sdes} 968295367Sdes#endif 969262566Sdes 970295367Sdes#ifdef WITH_SSH1 971295367Sdesint 972137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 973137015Sdes u_int8_t cookie[8], u_int8_t id[16]) 974137015Sdes{ 975295367Sdes u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; 976295367Sdes struct ssh_digest_ctx *hashctx = NULL; 977295367Sdes size_t hlen, slen; 978295367Sdes int r; 979137015Sdes 980295367Sdes hlen = BN_num_bytes(host_modulus); 981295367Sdes slen = BN_num_bytes(server_modulus); 982295367Sdes if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || 983295367Sdes slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) 984295367Sdes return SSH_ERR_KEY_BITS_MISMATCH; 985295367Sdes if (BN_bn2bin(host_modulus, hbuf) <= 0 || 986295367Sdes BN_bn2bin(server_modulus, sbuf) <= 0) { 987295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 988295367Sdes goto out; 989295367Sdes } 990295367Sdes if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { 991295367Sdes r = SSH_ERR_ALLOC_FAIL; 992295367Sdes goto out; 993295367Sdes } 994295367Sdes if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || 995295367Sdes ssh_digest_update(hashctx, sbuf, slen) != 0 || 996295367Sdes ssh_digest_update(hashctx, cookie, 8) != 0 || 997295367Sdes ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { 998295367Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 999295367Sdes goto out; 1000295367Sdes } 1001262566Sdes memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); 1002295367Sdes r = 0; 1003295367Sdes out: 1004295367Sdes ssh_digest_free(hashctx); 1005295367Sdes explicit_bzero(hbuf, sizeof(hbuf)); 1006295367Sdes explicit_bzero(sbuf, sizeof(sbuf)); 1007264377Sdes explicit_bzero(obuf, sizeof(obuf)); 1008295367Sdes return r; 1009137015Sdes} 1010295367Sdes#endif 1011137015Sdes 1012221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 101376259Sgreenvoid 101476259Sgreendump_digest(char *msg, u_char *digest, int len) 101576259Sgreen{ 101676259Sgreen fprintf(stderr, "%s\n", msg); 1017295367Sdes sshbuf_dump_data(digest, len, stderr); 101876259Sgreen} 101976259Sgreen#endif 1020