1323136Sdes/* $OpenBSD: kex.c,v 1.131 2017/03/15 07:07:39 markus 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 29162852Sdes#include <signal.h> 30162852Sdes#include <stdarg.h> 31162852Sdes#include <stdio.h> 32162852Sdes#include <stdlib.h> 33162852Sdes#include <string.h> 34162852Sdes 35294328Sdes#ifdef WITH_OPENSSL 3676259Sgreen#include <openssl/crypto.h> 37323129Sdes#include <openssl/dh.h> 38294328Sdes#endif 3976259Sgreen 4060573Skris#include "ssh2.h" 4161209Skris#include "packet.h" 4260573Skris#include "compat.h" 4376259Sgreen#include "cipher.h" 44294332Sdes#include "sshkey.h" 4560573Skris#include "kex.h" 4676259Sgreen#include "log.h" 4776259Sgreen#include "mac.h" 4876259Sgreen#include "match.h" 49294332Sdes#include "misc.h" 5076259Sgreen#include "dispatch.h" 5198675Sdes#include "monitor.h" 52294332Sdes 53294332Sdes#include "ssherr.h" 54294332Sdes#include "sshbuf.h" 55261320Sdes#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 */ 66294332Sdesstatic int kex_choose_conf(struct ssh *); 67294332Sdesstatic int kex_input_newkeys(int, u_int32_t, void *); 6876259Sgreen 69296633Sdesstatic const char *proposal_names[PROPOSAL_MAX] = { 70296633Sdes "KEX algorithms", 71296633Sdes "host key algorithms", 72296633Sdes "ciphers ctos", 73296633Sdes "ciphers stoc", 74296633Sdes "MACs ctos", 75296633Sdes "MACs stoc", 76296633Sdes "compression ctos", 77296633Sdes "compression stoc", 78296633Sdes "languages ctos", 79296633Sdes "languages stoc", 80296633Sdes}; 81296633Sdes 82255767Sdesstruct kexalg { 83255767Sdes char *name; 84294332Sdes u_int type; 85255767Sdes int ec_nid; 86261320Sdes int hash_alg; 87255767Sdes}; 88255767Sdesstatic const struct kexalg kexalgs[] = { 89294328Sdes#ifdef WITH_OPENSSL 90261320Sdes { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 91323129Sdes { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 92323129Sdes { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, 93323129Sdes { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, 94323129Sdes { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 }, 95261320Sdes { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 96255767Sdes#ifdef HAVE_EVP_SHA256 97261320Sdes { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 98294328Sdes#endif /* HAVE_EVP_SHA256 */ 99255767Sdes#ifdef OPENSSL_HAS_ECC 100261320Sdes { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 101261320Sdes NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 102261320Sdes { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, 103261320Sdes SSH_DIGEST_SHA384 }, 104261320Sdes# ifdef OPENSSL_HAS_NISTP521 105261320Sdes { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 106261320Sdes SSH_DIGEST_SHA512 }, 107294328Sdes# endif /* OPENSSL_HAS_NISTP521 */ 108294328Sdes#endif /* OPENSSL_HAS_ECC */ 109294328Sdes#endif /* WITH_OPENSSL */ 110294332Sdes#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) 111261320Sdes { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 112323134Sdes { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 113294332Sdes#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 114261320Sdes { NULL, -1, -1, -1}, 115255767Sdes}; 116255767Sdes 117255767Sdeschar * 118261320Sdeskex_alg_list(char sep) 119255767Sdes{ 120294332Sdes 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) 126261320Sdes ret[rlen++] = sep; 127255767Sdes nlen = strlen(k->name); 128294332Sdes if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 129294332Sdes free(ret); 130294332Sdes return NULL; 131294332Sdes } 132294332Sdes 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; 159294332Sdes if ((s = cp = strdup(names)) == NULL) 160294332Sdes 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 174294464Sdes/* 175294464Sdes * Concatenate algorithm names, avoiding duplicates in the process. 176294464Sdes * Caller must free returned string. 177294464Sdes */ 178294464Sdeschar * 179294464Sdeskex_names_cat(const char *a, const char *b) 180294464Sdes{ 181323136Sdes char *ret = NULL, *tmp = NULL, *cp, *p, *m; 182294464Sdes size_t len; 183294464Sdes 184294464Sdes if (a == NULL || *a == '\0') 185294464Sdes return NULL; 186294464Sdes if (b == NULL || *b == '\0') 187294464Sdes return strdup(a); 188294464Sdes if (strlen(b) > 1024*1024) 189294464Sdes return NULL; 190294464Sdes len = strlen(a) + strlen(b) + 2; 191294464Sdes if ((tmp = cp = strdup(b)) == NULL || 192294464Sdes (ret = calloc(1, len)) == NULL) { 193294464Sdes free(tmp); 194294464Sdes return NULL; 195294464Sdes } 196294464Sdes strlcpy(ret, a, len); 197294464Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { 198323136Sdes if ((m = match_list(ret, p, NULL)) != NULL) { 199323136Sdes free(m); 200294464Sdes continue; /* Algorithm already present */ 201323136Sdes } 202294464Sdes if (strlcat(ret, ",", len) >= len || 203294464Sdes strlcat(ret, p, len) >= len) { 204294464Sdes free(tmp); 205294464Sdes free(ret); 206294464Sdes return NULL; /* Shouldn't happen */ 207294464Sdes } 208294464Sdes } 209294464Sdes free(tmp); 210294464Sdes return ret; 211294464Sdes} 212294464Sdes 213294464Sdes/* 214294464Sdes * Assemble a list of algorithms from a default list and a string from a 215294464Sdes * configuration file. The user-provided string may begin with '+' to 216323136Sdes * indicate that it should be appended to the default or '-' that the 217323136Sdes * specified names should be removed. 218294464Sdes */ 219294464Sdesint 220294464Sdeskex_assemble_names(const char *def, char **list) 221294464Sdes{ 222294464Sdes char *ret; 223294464Sdes 224294464Sdes if (list == NULL || *list == NULL || **list == '\0') { 225294464Sdes *list = strdup(def); 226294464Sdes return 0; 227294464Sdes } 228323136Sdes if (**list == '+') { 229323136Sdes if ((ret = kex_names_cat(def, *list + 1)) == NULL) 230323136Sdes return SSH_ERR_ALLOC_FAIL; 231323136Sdes free(*list); 232323136Sdes *list = ret; 233323136Sdes } else if (**list == '-') { 234323136Sdes if ((ret = match_filter_list(def, *list + 1)) == NULL) 235323136Sdes return SSH_ERR_ALLOC_FAIL; 236323136Sdes free(*list); 237323136Sdes *list = ret; 238294464Sdes } 239294464Sdes 240294464Sdes return 0; 241294464Sdes} 242294464Sdes 243291198Sdes/* put algorithm proposal into buffer */ 244294332Sdesint 245294332Sdeskex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 24660573Skris{ 247149749Sdes u_int i; 248294332Sdes int r; 24976259Sgreen 250294332Sdes sshbuf_reset(b); 251294332Sdes 25298675Sdes /* 25398675Sdes * add a dummy cookie, the cookie will be overwritten by 25498675Sdes * kex_send_kexinit(), each time a kexinit is set 25598675Sdes */ 256294332Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) { 257294332Sdes if ((r = sshbuf_put_u8(b, 0)) != 0) 258294332Sdes return r; 259294332Sdes } 260294332Sdes for (i = 0; i < PROPOSAL_MAX; i++) { 261294332Sdes if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 262294332Sdes return r; 263294332Sdes } 264294332Sdes if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 265294332Sdes (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 266294332Sdes return r; 267294332Sdes return 0; 26860573Skris} 26960573Skris 27076259Sgreen/* parse buffer and return algorithm proposal */ 271294332Sdesint 272294332Sdeskex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 27361209Skris{ 274294332Sdes struct sshbuf *b = NULL; 275294332Sdes u_char v; 276181111Sdes u_int i; 277294332Sdes char **proposal = NULL; 278294332Sdes int r; 27961209Skris 280294332Sdes *propp = NULL; 281294332Sdes if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 282294332Sdes return SSH_ERR_ALLOC_FAIL; 283294332Sdes if ((b = sshbuf_fromb(raw)) == NULL) { 284294332Sdes r = SSH_ERR_ALLOC_FAIL; 285294332Sdes goto out; 286294332Sdes } 287294332Sdes if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 288294332Sdes goto out; 28961209Skris /* extract kex init proposal strings */ 29061209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 291294332Sdes if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 292294332Sdes goto out; 293296633Sdes debug2("%s: %s", proposal_names[i], proposal[i]); 29461209Skris } 29576259Sgreen /* first kex follows / reserved */ 296294496Sdes if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ 297294496Sdes (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ 298294332Sdes goto out; 299113908Sdes if (first_kex_follows != NULL) 300294496Sdes *first_kex_follows = v; 301294496Sdes debug2("first_kex_follows %d ", v); 302294496Sdes debug2("reserved %u ", i); 303294332Sdes r = 0; 304294332Sdes *propp = proposal; 305294332Sdes out: 306294332Sdes if (r != 0 && proposal != NULL) 307294332Sdes kex_prop_free(proposal); 308294332Sdes sshbuf_free(b); 309294332Sdes return r; 31061209Skris} 31161209Skris 312294332Sdesvoid 31376259Sgreenkex_prop_free(char **proposal) 31460573Skris{ 315149749Sdes u_int i; 31660573Skris 317294336Sdes if (proposal == NULL) 318294336Sdes return; 31976259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 320255767Sdes free(proposal[i]); 321255767Sdes free(proposal); 32260573Skris} 32360573Skris 324181111Sdes/* ARGSUSED */ 325294332Sdesstatic int 32692555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt) 32760573Skris{ 328296633Sdes struct ssh *ssh = active_state; /* XXX */ 329296633Sdes int r; 330296633Sdes 331296633Sdes error("kex protocol error: type %d seq %u", type, seq); 332296633Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || 333296633Sdes (r = sshpkt_put_u32(ssh, seq)) != 0 || 334296633Sdes (r = sshpkt_send(ssh)) != 0) 335296633Sdes return r; 336294332Sdes return 0; 33760573Skris} 33860573Skris 33992555Sdesstatic void 340294332Sdeskex_reset_dispatch(struct ssh *ssh) 34169587Sgreen{ 342294332Sdes ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 34392555Sdes SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 34469587Sgreen} 34569587Sgreen 346296633Sdesstatic int 347296633Sdeskex_send_ext_info(struct ssh *ssh) 348296633Sdes{ 349296633Sdes int r; 350323134Sdes char *algs; 351296633Sdes 352323136Sdes if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) 353323134Sdes return SSH_ERR_ALLOC_FAIL; 354296633Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || 355296633Sdes (r = sshpkt_put_u32(ssh, 1)) != 0 || 356296633Sdes (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || 357323134Sdes (r = sshpkt_put_cstring(ssh, algs)) != 0 || 358296633Sdes (r = sshpkt_send(ssh)) != 0) 359323134Sdes goto out; 360323134Sdes /* success */ 361323134Sdes r = 0; 362323134Sdes out: 363323134Sdes free(algs); 364323134Sdes return r; 365296633Sdes} 366296633Sdes 367294332Sdesint 368294332Sdeskex_send_newkeys(struct ssh *ssh) 36969587Sgreen{ 370294332Sdes int r; 37169587Sgreen 372294332Sdes kex_reset_dispatch(ssh); 373294332Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 374294332Sdes (r = sshpkt_send(ssh)) != 0) 375294332Sdes return r; 37676259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 377294332Sdes debug("expecting SSH2_MSG_NEWKEYS"); 378294332Sdes ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 379296633Sdes if (ssh->kex->ext_info_c) 380296633Sdes if ((r = kex_send_ext_info(ssh)) != 0) 381296633Sdes return r; 382294332Sdes return 0; 383294332Sdes} 38469587Sgreen 385296633Sdesint 386296633Sdeskex_input_ext_info(int type, u_int32_t seq, void *ctxt) 387296633Sdes{ 388296633Sdes struct ssh *ssh = ctxt; 389296633Sdes struct kex *kex = ssh->kex; 390296633Sdes u_int32_t i, ninfo; 391296633Sdes char *name, *val, *found; 392296633Sdes int r; 393296633Sdes 394296633Sdes debug("SSH2_MSG_EXT_INFO received"); 395296633Sdes ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); 396296633Sdes if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) 397296633Sdes return r; 398296633Sdes for (i = 0; i < ninfo; i++) { 399296633Sdes if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) 400296633Sdes return r; 401296633Sdes if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) { 402296633Sdes free(name); 403296633Sdes return r; 404296633Sdes } 405296633Sdes debug("%s: %s=<%s>", __func__, name, val); 406296633Sdes if (strcmp(name, "server-sig-algs") == 0) { 407296633Sdes found = match_list("rsa-sha2-256", val, NULL); 408296633Sdes if (found) { 409296633Sdes kex->rsa_sha2 = 256; 410296633Sdes free(found); 411296633Sdes } 412296633Sdes found = match_list("rsa-sha2-512", val, NULL); 413296633Sdes if (found) { 414296633Sdes kex->rsa_sha2 = 512; 415296633Sdes free(found); 416296633Sdes } 417296633Sdes } 418296633Sdes free(name); 419296633Sdes free(val); 420296633Sdes } 421296633Sdes return sshpkt_get_end(ssh); 422296633Sdes} 423296633Sdes 424294332Sdesstatic int 425294332Sdeskex_input_newkeys(int type, u_int32_t seq, void *ctxt) 426294332Sdes{ 427294332Sdes struct ssh *ssh = ctxt; 428294332Sdes struct kex *kex = ssh->kex; 429294332Sdes int r; 430294332Sdes 43176259Sgreen debug("SSH2_MSG_NEWKEYS received"); 432294332Sdes ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 433323136Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 434294332Sdes if ((r = sshpkt_get_end(ssh)) != 0) 435294332Sdes return r; 436323134Sdes if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0) 437323134Sdes return r; 43876259Sgreen kex->done = 1; 439294332Sdes sshbuf_reset(kex->peer); 440294332Sdes /* sshbuf_reset(kex->my); */ 44176259Sgreen kex->flags &= ~KEX_INIT_SENT; 442255767Sdes free(kex->name); 44376259Sgreen kex->name = NULL; 444294332Sdes return 0; 44569587Sgreen} 44669587Sgreen 447294332Sdesint 448294332Sdeskex_send_kexinit(struct ssh *ssh) 44960573Skris{ 45098675Sdes u_char *cookie; 451294332Sdes struct kex *kex = ssh->kex; 452294332Sdes int r; 45398675Sdes 454294332Sdes if (kex == NULL) 455294332Sdes return SSH_ERR_INTERNAL_ERROR; 456294332Sdes if (kex->flags & KEX_INIT_SENT) 457294332Sdes return 0; 45876259Sgreen kex->done = 0; 45998675Sdes 46098675Sdes /* generate a random cookie */ 461294332Sdes if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 462294332Sdes return SSH_ERR_INVALID_FORMAT; 463294332Sdes if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 464294332Sdes return SSH_ERR_INTERNAL_ERROR; 465294332Sdes arc4random_buf(cookie, KEX_COOKIE_LEN); 466294332Sdes 467294332Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 468294332Sdes (r = sshpkt_putb(ssh, kex->my)) != 0 || 469294332Sdes (r = sshpkt_send(ssh)) != 0) 470294332Sdes return r; 47176259Sgreen debug("SSH2_MSG_KEXINIT sent"); 47276259Sgreen kex->flags |= KEX_INIT_SENT; 473294332Sdes return 0; 47460573Skris} 47560573Skris 476181111Sdes/* ARGSUSED */ 477294332Sdesint 47892555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 47960573Skris{ 480294332Sdes struct ssh *ssh = ctxt; 481294332Sdes struct kex *kex = ssh->kex; 482294332Sdes const u_char *ptr; 483294332Sdes u_int i; 484294332Sdes size_t dlen; 485294332Sdes int r; 48660573Skris 48776259Sgreen debug("SSH2_MSG_KEXINIT received"); 48876259Sgreen if (kex == NULL) 489294332Sdes return SSH_ERR_INVALID_ARGUMENT; 49060573Skris 491323134Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); 492294332Sdes ptr = sshpkt_ptr(ssh, &dlen); 493294332Sdes if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 494294332Sdes return r; 49560573Skris 49676259Sgreen /* discard packet */ 49776259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 498294332Sdes if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 499294332Sdes return r; 50076259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 501294332Sdes if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 502294332Sdes return r; 503248619Sdes /* 504248619Sdes * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 505248619Sdes * KEX method has the server move first, but a server might be using 506248619Sdes * a custom method or one that we otherwise don't support. We should 507248619Sdes * be prepared to remember first_kex_follows here so we can eat a 508248619Sdes * packet later. 509248619Sdes * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 510248619Sdes * for cases where the server *doesn't* go first. I guess we should 511248619Sdes * ignore it when it is set for these cases, which is what we do now. 512248619Sdes */ 513294332Sdes if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 514294332Sdes (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 515294332Sdes (r = sshpkt_get_end(ssh)) != 0) 516294332Sdes return r; 51760573Skris 518294332Sdes if (!(kex->flags & KEX_INIT_SENT)) 519294332Sdes if ((r = kex_send_kexinit(ssh)) != 0) 520294332Sdes return r; 521294332Sdes if ((r = kex_choose_conf(ssh)) != 0) 522294332Sdes return r; 523294332Sdes 524294332Sdes if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 525294332Sdes return (kex->kex[kex->kex_type])(ssh); 526294332Sdes 527294332Sdes return SSH_ERR_INTERNAL_ERROR; 52860573Skris} 52960573Skris 530294332Sdesint 531294332Sdeskex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 53269587Sgreen{ 533294332Sdes struct kex *kex; 534294332Sdes int r; 53569587Sgreen 536294332Sdes *kexp = NULL; 537294332Sdes if ((kex = calloc(1, sizeof(*kex))) == NULL) 538294332Sdes return SSH_ERR_ALLOC_FAIL; 539294332Sdes if ((kex->peer = sshbuf_new()) == NULL || 540294332Sdes (kex->my = sshbuf_new()) == NULL) { 541294332Sdes r = SSH_ERR_ALLOC_FAIL; 542294332Sdes goto out; 543294332Sdes } 544294332Sdes if ((r = kex_prop2buf(kex->my, proposal)) != 0) 545294332Sdes goto out; 54676259Sgreen kex->done = 0; 547294332Sdes kex_reset_dispatch(ssh); 548323136Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 549294332Sdes r = 0; 550294332Sdes *kexp = kex; 551294332Sdes out: 552294332Sdes if (r != 0) 553294332Sdes kex_free(kex); 554294332Sdes return r; 555294332Sdes} 55669587Sgreen 557294332Sdesvoid 558294332Sdeskex_free_newkeys(struct newkeys *newkeys) 559294332Sdes{ 560294332Sdes if (newkeys == NULL) 561294332Sdes return; 562294332Sdes if (newkeys->enc.key) { 563294332Sdes explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 564294332Sdes free(newkeys->enc.key); 565294332Sdes newkeys->enc.key = NULL; 566294332Sdes } 567294332Sdes if (newkeys->enc.iv) { 568296633Sdes explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len); 569294332Sdes free(newkeys->enc.iv); 570294332Sdes newkeys->enc.iv = NULL; 571294332Sdes } 572294332Sdes free(newkeys->enc.name); 573294332Sdes explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 574294332Sdes free(newkeys->comp.name); 575294332Sdes explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 576294332Sdes mac_clear(&newkeys->mac); 577294332Sdes if (newkeys->mac.key) { 578294332Sdes explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 579294332Sdes free(newkeys->mac.key); 580294332Sdes newkeys->mac.key = NULL; 581294332Sdes } 582294332Sdes free(newkeys->mac.name); 583294332Sdes explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 584294332Sdes explicit_bzero(newkeys, sizeof(*newkeys)); 585294332Sdes free(newkeys); 586294332Sdes} 58769587Sgreen 588294332Sdesvoid 589294332Sdeskex_free(struct kex *kex) 590294332Sdes{ 591294332Sdes u_int mode; 592294332Sdes 593294332Sdes#ifdef WITH_OPENSSL 594294332Sdes if (kex->dh) 595294332Sdes DH_free(kex->dh); 596294332Sdes#ifdef OPENSSL_HAS_ECC 597294332Sdes if (kex->ec_client_key) 598294332Sdes EC_KEY_free(kex->ec_client_key); 599294332Sdes#endif /* OPENSSL_HAS_ECC */ 600294332Sdes#endif /* WITH_OPENSSL */ 601294332Sdes for (mode = 0; mode < MODE_MAX; mode++) { 602294332Sdes kex_free_newkeys(kex->newkeys[mode]); 603294332Sdes kex->newkeys[mode] = NULL; 604294332Sdes } 605294332Sdes sshbuf_free(kex->peer); 606294332Sdes sshbuf_free(kex->my); 607294332Sdes free(kex->session_id); 608294332Sdes free(kex->client_version_string); 609294332Sdes free(kex->server_version_string); 610294464Sdes free(kex->failed_choice); 611296633Sdes free(kex->hostkey_alg); 612296633Sdes free(kex->name); 613294332Sdes free(kex); 61469587Sgreen} 61569587Sgreen 616294332Sdesint 617294332Sdeskex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 61860573Skris{ 619294332Sdes int r; 62060573Skris 621294332Sdes if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 622294332Sdes return r; 623294332Sdes if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 624294332Sdes kex_free(ssh->kex); 625294332Sdes ssh->kex = NULL; 626294332Sdes return r; 62760573Skris } 628294332Sdes return 0; 62960573Skris} 63060573Skris 631296633Sdes/* 632296633Sdes * Request key re-exchange, returns 0 on success or a ssherr.h error 633296633Sdes * code otherwise. Must not be called if KEX is incomplete or in-progress. 634296633Sdes */ 635296633Sdesint 636296633Sdeskex_start_rekex(struct ssh *ssh) 637296633Sdes{ 638296633Sdes if (ssh->kex == NULL) { 639296633Sdes error("%s: no kex", __func__); 640296633Sdes return SSH_ERR_INTERNAL_ERROR; 641296633Sdes } 642296633Sdes if (ssh->kex->done == 0) { 643296633Sdes error("%s: requested twice", __func__); 644296633Sdes return SSH_ERR_INTERNAL_ERROR; 645296633Sdes } 646296633Sdes ssh->kex->done = 0; 647296633Sdes return kex_send_kexinit(ssh); 648296633Sdes} 649296633Sdes 650294332Sdesstatic int 651294332Sdeschoose_enc(struct sshenc *enc, char *client, char *server) 65260573Skris{ 65376259Sgreen char *name = match_list(client, server, NULL); 654294332Sdes 65560573Skris if (name == NULL) 656294332Sdes return SSH_ERR_NO_CIPHER_ALG_MATCH; 657323136Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) { 658323136Sdes free(name); 659294332Sdes return SSH_ERR_INTERNAL_ERROR; 660323136Sdes } 66160573Skris enc->name = name; 66260573Skris enc->enabled = 0; 66360573Skris enc->iv = NULL; 664248619Sdes enc->iv_len = cipher_ivlen(enc->cipher); 66560573Skris enc->key = NULL; 66692555Sdes enc->key_len = cipher_keylen(enc->cipher); 66792555Sdes enc->block_size = cipher_blocksize(enc->cipher); 668294332Sdes return 0; 66960573Skris} 670162852Sdes 671294332Sdesstatic int 672294332Sdeschoose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 67360573Skris{ 67476259Sgreen char *name = match_list(client, server, NULL); 675294332Sdes 67660573Skris if (name == NULL) 677294332Sdes return SSH_ERR_NO_MAC_ALG_MATCH; 678323136Sdes if (mac_setup(mac, name) < 0) { 679323136Sdes free(name); 680294332Sdes return SSH_ERR_INTERNAL_ERROR; 681323136Sdes } 68276259Sgreen /* truncate the key */ 683294332Sdes if (ssh->compat & SSH_BUG_HMAC) 68476259Sgreen mac->key_len = 16; 68560573Skris mac->name = name; 68660573Skris mac->key = NULL; 68760573Skris mac->enabled = 0; 688294332Sdes return 0; 68960573Skris} 690162852Sdes 691294332Sdesstatic int 692294332Sdeschoose_comp(struct sshcomp *comp, char *client, char *server) 69360573Skris{ 69476259Sgreen char *name = match_list(client, server, NULL); 695294332Sdes 69660573Skris if (name == NULL) 697294332Sdes return SSH_ERR_NO_COMPRESS_ALG_MATCH; 698149749Sdes if (strcmp(name, "zlib@openssh.com") == 0) { 699149749Sdes comp->type = COMP_DELAYED; 700149749Sdes } else if (strcmp(name, "zlib") == 0) { 701149749Sdes comp->type = COMP_ZLIB; 70260573Skris } else if (strcmp(name, "none") == 0) { 703149749Sdes comp->type = COMP_NONE; 70460573Skris } else { 705323136Sdes free(name); 706294332Sdes return SSH_ERR_INTERNAL_ERROR; 70760573Skris } 70860573Skris comp->name = name; 709294332Sdes return 0; 71060573Skris} 711162852Sdes 712294332Sdesstatic int 713294332Sdeschoose_kex(struct kex *k, char *client, char *server) 71460573Skris{ 715255767Sdes const struct kexalg *kexalg; 716255767Sdes 71776259Sgreen k->name = match_list(client, server, NULL); 718294332Sdes 719296633Sdes debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); 72060573Skris if (k->name == NULL) 721294332Sdes return SSH_ERR_NO_KEX_ALG_MATCH; 722255767Sdes if ((kexalg = kex_alg_by_name(k->name)) == NULL) 723294332Sdes return SSH_ERR_INTERNAL_ERROR; 724255767Sdes k->kex_type = kexalg->type; 725261320Sdes k->hash_alg = kexalg->hash_alg; 726255767Sdes k->ec_nid = kexalg->ec_nid; 727294332Sdes return 0; 72860573Skris} 729157016Sdes 730294332Sdesstatic int 731294332Sdeschoose_hostkeyalg(struct kex *k, char *client, char *server) 73260573Skris{ 733296633Sdes k->hostkey_alg = match_list(client, server, NULL); 734294332Sdes 735296633Sdes debug("kex: host key algorithm: %s", 736296633Sdes k->hostkey_alg ? k->hostkey_alg : "(no match)"); 737296633Sdes if (k->hostkey_alg == NULL) 738294332Sdes return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 739296633Sdes k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); 74076259Sgreen if (k->hostkey_type == KEY_UNSPEC) 741294332Sdes return SSH_ERR_INTERNAL_ERROR; 742296633Sdes k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); 743294332Sdes return 0; 74460573Skris} 74560573Skris 746126274Sdesstatic int 747113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 748113908Sdes{ 749113908Sdes static int check[] = { 750113908Sdes PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 751113908Sdes }; 752113908Sdes int *idx; 753113908Sdes char *p; 754113908Sdes 755113908Sdes for (idx = &check[0]; *idx != -1; idx++) { 756113908Sdes if ((p = strchr(my[*idx], ',')) != NULL) 757113908Sdes *p = '\0'; 758113908Sdes if ((p = strchr(peer[*idx], ',')) != NULL) 759113908Sdes *p = '\0'; 760113908Sdes if (strcmp(my[*idx], peer[*idx]) != 0) { 761113908Sdes debug2("proposal mismatch: my %s peer %s", 762113908Sdes my[*idx], peer[*idx]); 763113908Sdes return (0); 764113908Sdes } 765113908Sdes } 766113908Sdes debug2("proposals match"); 767113908Sdes return (1); 768113908Sdes} 769113908Sdes 770294332Sdesstatic int 771294332Sdeskex_choose_conf(struct ssh *ssh) 77260573Skris{ 773294332Sdes struct kex *kex = ssh->kex; 774294332Sdes struct newkeys *newkeys; 775294332Sdes char **my = NULL, **peer = NULL; 77676259Sgreen char **cprop, **sprop; 77776259Sgreen int nenc, nmac, ncomp; 778261320Sdes u_int mode, ctos, need, dh_need, authlen; 779294332Sdes int r, first_kex_follows; 78060573Skris 781296633Sdes debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); 782296633Sdes if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) 783294332Sdes goto out; 784296633Sdes debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server"); 785296633Sdes if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 786296633Sdes goto out; 78760573Skris 78876259Sgreen if (kex->server) { 78976259Sgreen cprop=peer; 79076259Sgreen sprop=my; 79176259Sgreen } else { 79276259Sgreen cprop=my; 79376259Sgreen sprop=peer; 79476259Sgreen } 79576259Sgreen 796296633Sdes /* Check whether client supports ext_info_c */ 797296633Sdes if (kex->server) { 798296633Sdes char *ext; 799294332Sdes 800296633Sdes ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); 801323134Sdes kex->ext_info_c = (ext != NULL); 802323134Sdes free(ext); 803204917Sdes } 804204917Sdes 80576259Sgreen /* Algorithm Negotiation */ 806296633Sdes if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 807296633Sdes sprop[PROPOSAL_KEX_ALGS])) != 0) { 808296633Sdes kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; 809296633Sdes peer[PROPOSAL_KEX_ALGS] = NULL; 810296633Sdes goto out; 811296633Sdes } 812296633Sdes if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 813296633Sdes sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { 814296633Sdes kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; 815296633Sdes peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; 816296633Sdes goto out; 817296633Sdes } 81860573Skris for (mode = 0; mode < MODE_MAX; mode++) { 819294332Sdes if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 820294332Sdes r = SSH_ERR_ALLOC_FAIL; 821294332Sdes goto out; 822294332Sdes } 82376259Sgreen kex->newkeys[mode] = newkeys; 824181111Sdes ctos = (!kex->server && mode == MODE_OUT) || 825181111Sdes (kex->server && mode == MODE_IN); 82660573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 82760573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 82860573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 829294332Sdes if ((r = choose_enc(&newkeys->enc, cprop[nenc], 830294464Sdes sprop[nenc])) != 0) { 831294464Sdes kex->failed_choice = peer[nenc]; 832294464Sdes peer[nenc] = NULL; 833294332Sdes goto out; 834294464Sdes } 835294332Sdes authlen = cipher_authlen(newkeys->enc.cipher); 836248619Sdes /* ignore mac for authenticated encryption */ 837294332Sdes if (authlen == 0 && 838294332Sdes (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 839294464Sdes sprop[nmac])) != 0) { 840294464Sdes kex->failed_choice = peer[nmac]; 841294464Sdes peer[nmac] = NULL; 842294332Sdes goto out; 843294464Sdes } 844294332Sdes if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 845294464Sdes sprop[ncomp])) != 0) { 846294464Sdes kex->failed_choice = peer[ncomp]; 847294464Sdes peer[ncomp] = NULL; 848294332Sdes goto out; 849294464Sdes } 850296633Sdes debug("kex: %s cipher: %s MAC: %s compression: %s", 85160573Skris ctos ? "client->server" : "server->client", 85276259Sgreen newkeys->enc.name, 853248619Sdes authlen == 0 ? newkeys->mac.name : "<implicit>", 85476259Sgreen newkeys->comp.name); 85560573Skris } 856261320Sdes need = dh_need = 0; 85760573Skris for (mode = 0; mode < MODE_MAX; mode++) { 85876259Sgreen newkeys = kex->newkeys[mode]; 859323134Sdes need = MAXIMUM(need, newkeys->enc.key_len); 860323134Sdes need = MAXIMUM(need, newkeys->enc.block_size); 861323134Sdes need = MAXIMUM(need, newkeys->enc.iv_len); 862323134Sdes need = MAXIMUM(need, newkeys->mac.key_len); 863323134Sdes dh_need = MAXIMUM(dh_need, cipher_seclen(newkeys->enc.cipher)); 864323134Sdes dh_need = MAXIMUM(dh_need, newkeys->enc.block_size); 865323134Sdes dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len); 866323134Sdes dh_need = MAXIMUM(dh_need, newkeys->mac.key_len); 86760573Skris } 86861209Skris /* XXX need runden? */ 86976259Sgreen kex->we_need = need; 870261320Sdes kex->dh_need = dh_need; 87176259Sgreen 872113908Sdes /* ignore the next message if the proposals do not match */ 873126274Sdes if (first_kex_follows && !proposals_match(my, peer) && 874294332Sdes !(ssh->compat & SSH_BUG_FIRSTKEX)) 875294332Sdes ssh->dispatch_skip_packets = 1; 876294332Sdes r = 0; 877294332Sdes out: 87876259Sgreen kex_prop_free(my); 87976259Sgreen kex_prop_free(peer); 880294332Sdes return r; 88160573Skris} 88260573Skris 883294332Sdesstatic int 884294332Sdesderive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 885294332Sdes const struct sshbuf *shared_secret, u_char **keyp) 88660573Skris{ 887294332Sdes struct kex *kex = ssh->kex; 888294332Sdes struct ssh_digest_ctx *hashctx = NULL; 88976259Sgreen char c = id; 890149749Sdes u_int have; 891261320Sdes size_t mdsz; 892149749Sdes u_char *digest; 893294332Sdes int r; 89460573Skris 895261320Sdes if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 896294332Sdes return SSH_ERR_INVALID_ARGUMENT; 897323134Sdes if ((digest = calloc(1, ROUNDUP(need, mdsz))) == NULL) { 898294332Sdes r = SSH_ERR_ALLOC_FAIL; 899294332Sdes goto out; 900294332Sdes } 901149749Sdes 90276259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 903294332Sdes if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 904294332Sdes ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 905261320Sdes ssh_digest_update(hashctx, hash, hashlen) != 0 || 906261320Sdes ssh_digest_update(hashctx, &c, 1) != 0 || 907261320Sdes ssh_digest_update(hashctx, kex->session_id, 908294332Sdes kex->session_id_len) != 0 || 909294332Sdes ssh_digest_final(hashctx, digest, mdsz) != 0) { 910294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 911294332Sdes goto out; 912294332Sdes } 913261320Sdes ssh_digest_free(hashctx); 914294332Sdes hashctx = NULL; 91576259Sgreen 91676259Sgreen /* 91776259Sgreen * expand key: 91876259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 91976259Sgreen * Key = K1 || K2 || ... || Kn 92076259Sgreen */ 92176259Sgreen for (have = mdsz; need > have; have += mdsz) { 922294332Sdes if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 923294332Sdes ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 924261320Sdes ssh_digest_update(hashctx, hash, hashlen) != 0 || 925294332Sdes ssh_digest_update(hashctx, digest, have) != 0 || 926294332Sdes ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 927294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 928294332Sdes goto out; 929294332Sdes } 930261320Sdes ssh_digest_free(hashctx); 931294332Sdes hashctx = NULL; 93276259Sgreen } 93376259Sgreen#ifdef DEBUG_KEX 93476259Sgreen fprintf(stderr, "key '%c'== ", c); 93576259Sgreen dump_digest("key", digest, need); 93676259Sgreen#endif 937294332Sdes *keyp = digest; 938294332Sdes digest = NULL; 939294332Sdes r = 0; 940294332Sdes out: 941296633Sdes free(digest); 942294332Sdes ssh_digest_free(hashctx); 943294332Sdes return r; 94476259Sgreen} 94576259Sgreen 94676259Sgreen#define NKEYS 6 947294332Sdesint 948294332Sdeskex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 949294332Sdes const struct sshbuf *shared_secret) 95076259Sgreen{ 951294332Sdes struct kex *kex = ssh->kex; 95276259Sgreen u_char *keys[NKEYS]; 953294332Sdes u_int i, j, mode, ctos; 954294332Sdes int r; 95576259Sgreen 956157016Sdes for (i = 0; i < NKEYS; i++) { 957294332Sdes if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 958294332Sdes shared_secret, &keys[i])) != 0) { 959294332Sdes for (j = 0; j < i; j++) 960294332Sdes free(keys[j]); 961294332Sdes return r; 962294332Sdes } 963157016Sdes } 96460573Skris for (mode = 0; mode < MODE_MAX; mode++) { 965162852Sdes ctos = (!kex->server && mode == MODE_OUT) || 966162852Sdes (kex->server && mode == MODE_IN); 967294332Sdes kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 968294332Sdes kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 969294332Sdes kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 97060573Skris } 971294332Sdes return 0; 97260573Skris} 97376259Sgreen 974294328Sdes#ifdef WITH_OPENSSL 975294332Sdesint 976294332Sdeskex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 977294332Sdes const BIGNUM *secret) 978261320Sdes{ 979294332Sdes struct sshbuf *shared_secret; 980294332Sdes int r; 981261320Sdes 982294332Sdes if ((shared_secret = sshbuf_new()) == NULL) 983294332Sdes return SSH_ERR_ALLOC_FAIL; 984294332Sdes if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 985294332Sdes r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 986294332Sdes sshbuf_free(shared_secret); 987294332Sdes return r; 988261320Sdes} 989294328Sdes#endif 990261320Sdes 991294328Sdes#ifdef WITH_SSH1 992294332Sdesint 993137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 994137015Sdes u_int8_t cookie[8], u_int8_t id[16]) 995137015Sdes{ 996294332Sdes u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; 997294332Sdes struct ssh_digest_ctx *hashctx = NULL; 998294332Sdes size_t hlen, slen; 999294332Sdes int r; 1000137015Sdes 1001294332Sdes hlen = BN_num_bytes(host_modulus); 1002294332Sdes slen = BN_num_bytes(server_modulus); 1003294332Sdes if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || 1004294332Sdes slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) 1005294332Sdes return SSH_ERR_KEY_BITS_MISMATCH; 1006294332Sdes if (BN_bn2bin(host_modulus, hbuf) <= 0 || 1007294332Sdes BN_bn2bin(server_modulus, sbuf) <= 0) { 1008294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 1009294332Sdes goto out; 1010294332Sdes } 1011294332Sdes if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { 1012294332Sdes r = SSH_ERR_ALLOC_FAIL; 1013294332Sdes goto out; 1014294332Sdes } 1015294332Sdes if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || 1016294332Sdes ssh_digest_update(hashctx, sbuf, slen) != 0 || 1017294332Sdes ssh_digest_update(hashctx, cookie, 8) != 0 || 1018294332Sdes ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { 1019294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 1020294332Sdes goto out; 1021294332Sdes } 1022261320Sdes memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); 1023294332Sdes r = 0; 1024294332Sdes out: 1025294332Sdes ssh_digest_free(hashctx); 1026294332Sdes explicit_bzero(hbuf, sizeof(hbuf)); 1027294332Sdes explicit_bzero(sbuf, sizeof(sbuf)); 1028263712Sdes explicit_bzero(obuf, sizeof(obuf)); 1029294332Sdes return r; 1030137015Sdes} 1031294328Sdes#endif 1032137015Sdes 1033221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 103476259Sgreenvoid 103576259Sgreendump_digest(char *msg, u_char *digest, int len) 103676259Sgreen{ 103776259Sgreen fprintf(stderr, "%s\n", msg); 1038294332Sdes sshbuf_dump_data(digest, len, stderr); 103976259Sgreen} 104076259Sgreen#endif 1041