kex.c revision 294336
1294336Sdes/* $OpenBSD: kex.c,v 1.106 2015/04/17 13:25:52 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 28294332Sdes#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 36294328Sdes#ifdef WITH_OPENSSL 3776259Sgreen#include <openssl/crypto.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" 52204917Sdes#include "roaming.h" 53294332Sdes 54294332Sdes#include "ssherr.h" 55294332Sdes#include "sshbuf.h" 56261320Sdes#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 */ 67294332Sdesstatic int kex_choose_conf(struct ssh *); 68294332Sdesstatic int kex_input_newkeys(int, u_int32_t, void *); 6976259Sgreen 70255767Sdesstruct kexalg { 71255767Sdes char *name; 72294332Sdes u_int type; 73255767Sdes int ec_nid; 74261320Sdes int hash_alg; 75255767Sdes}; 76255767Sdesstatic const struct kexalg kexalgs[] = { 77294328Sdes#ifdef WITH_OPENSSL 78261320Sdes { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 79261320Sdes { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 80261320Sdes { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 81255767Sdes#ifdef HAVE_EVP_SHA256 82261320Sdes { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 83294328Sdes#endif /* HAVE_EVP_SHA256 */ 84255767Sdes#ifdef OPENSSL_HAS_ECC 85261320Sdes { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 86261320Sdes NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 87261320Sdes { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, 88261320Sdes SSH_DIGEST_SHA384 }, 89261320Sdes# ifdef OPENSSL_HAS_NISTP521 90261320Sdes { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 91261320Sdes SSH_DIGEST_SHA512 }, 92294328Sdes# endif /* OPENSSL_HAS_NISTP521 */ 93294328Sdes#endif /* OPENSSL_HAS_ECC */ 94294328Sdes#endif /* WITH_OPENSSL */ 95294332Sdes#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) 96261320Sdes { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 97294332Sdes#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 98261320Sdes { NULL, -1, -1, -1}, 99255767Sdes}; 100255767Sdes 101255767Sdeschar * 102261320Sdeskex_alg_list(char sep) 103255767Sdes{ 104294332Sdes char *ret = NULL, *tmp; 105255767Sdes size_t nlen, rlen = 0; 106255767Sdes const struct kexalg *k; 107255767Sdes 108255767Sdes for (k = kexalgs; k->name != NULL; k++) { 109255767Sdes if (ret != NULL) 110261320Sdes ret[rlen++] = sep; 111255767Sdes nlen = strlen(k->name); 112294332Sdes if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 113294332Sdes free(ret); 114294332Sdes return NULL; 115294332Sdes } 116294332Sdes ret = tmp; 117255767Sdes memcpy(ret + rlen, k->name, nlen + 1); 118255767Sdes rlen += nlen; 119255767Sdes } 120255767Sdes return ret; 121255767Sdes} 122255767Sdes 123255767Sdesstatic const struct kexalg * 124255767Sdeskex_alg_by_name(const char *name) 125255767Sdes{ 126255767Sdes const struct kexalg *k; 127255767Sdes 128255767Sdes for (k = kexalgs; k->name != NULL; k++) { 129255767Sdes if (strcmp(k->name, name) == 0) 130255767Sdes return k; 131255767Sdes } 132255767Sdes return NULL; 133255767Sdes} 134255767Sdes 135221420Sdes/* Validate KEX method name list */ 136221420Sdesint 137221420Sdeskex_names_valid(const char *names) 138221420Sdes{ 139221420Sdes char *s, *cp, *p; 140221420Sdes 141221420Sdes if (names == NULL || strcmp(names, "") == 0) 142221420Sdes return 0; 143294332Sdes if ((s = cp = strdup(names)) == NULL) 144294332Sdes return 0; 145221420Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; 146221420Sdes (p = strsep(&cp, ","))) { 147255767Sdes if (kex_alg_by_name(p) == NULL) { 148221420Sdes error("Unsupported KEX algorithm \"%.100s\"", p); 149255767Sdes free(s); 150221420Sdes return 0; 151221420Sdes } 152221420Sdes } 153221420Sdes debug3("kex names ok: [%s]", names); 154255767Sdes free(s); 155221420Sdes return 1; 156221420Sdes} 157221420Sdes 158291198Sdes/* put algorithm proposal into buffer */ 159294332Sdesint 160294332Sdeskex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 16160573Skris{ 162149749Sdes u_int i; 163294332Sdes int r; 16476259Sgreen 165294332Sdes sshbuf_reset(b); 166294332Sdes 16798675Sdes /* 16898675Sdes * add a dummy cookie, the cookie will be overwritten by 16998675Sdes * kex_send_kexinit(), each time a kexinit is set 17098675Sdes */ 171294332Sdes for (i = 0; i < KEX_COOKIE_LEN; i++) { 172294332Sdes if ((r = sshbuf_put_u8(b, 0)) != 0) 173294332Sdes return r; 174294332Sdes } 175294332Sdes for (i = 0; i < PROPOSAL_MAX; i++) { 176294332Sdes if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 177294332Sdes return r; 178294332Sdes } 179294332Sdes if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 180294332Sdes (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 181294332Sdes return r; 182294332Sdes return 0; 18360573Skris} 18460573Skris 18576259Sgreen/* parse buffer and return algorithm proposal */ 186294332Sdesint 187294332Sdeskex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 18861209Skris{ 189294332Sdes struct sshbuf *b = NULL; 190294332Sdes u_char v; 191181111Sdes u_int i; 192294332Sdes char **proposal = NULL; 193294332Sdes int r; 19461209Skris 195294332Sdes *propp = NULL; 196294332Sdes if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 197294332Sdes return SSH_ERR_ALLOC_FAIL; 198294332Sdes if ((b = sshbuf_fromb(raw)) == NULL) { 199294332Sdes r = SSH_ERR_ALLOC_FAIL; 200294332Sdes goto out; 201294332Sdes } 202294332Sdes if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 203294332Sdes goto out; 20461209Skris /* extract kex init proposal strings */ 20561209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 206294332Sdes if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 207294332Sdes goto out; 20876259Sgreen debug2("kex_parse_kexinit: %s", proposal[i]); 20961209Skris } 21076259Sgreen /* first kex follows / reserved */ 211294332Sdes if ((r = sshbuf_get_u8(b, &v)) != 0 || 212294332Sdes (r = sshbuf_get_u32(b, &i)) != 0) 213294332Sdes goto out; 214113908Sdes if (first_kex_follows != NULL) 215113908Sdes *first_kex_follows = i; 216294332Sdes debug2("kex_parse_kexinit: first_kex_follows %d ", v); 217181111Sdes debug2("kex_parse_kexinit: reserved %u ", i); 218294332Sdes r = 0; 219294332Sdes *propp = proposal; 220294332Sdes out: 221294332Sdes if (r != 0 && proposal != NULL) 222294332Sdes kex_prop_free(proposal); 223294332Sdes sshbuf_free(b); 224294332Sdes return r; 22561209Skris} 22661209Skris 227294332Sdesvoid 22876259Sgreenkex_prop_free(char **proposal) 22960573Skris{ 230149749Sdes u_int i; 23160573Skris 232294336Sdes if (proposal == NULL) 233294336Sdes return; 23476259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 235255767Sdes free(proposal[i]); 236255767Sdes free(proposal); 23760573Skris} 23860573Skris 239181111Sdes/* ARGSUSED */ 240294332Sdesstatic int 24192555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt) 24260573Skris{ 24392555Sdes error("Hm, kex protocol error: type %d seq %u", type, seq); 244294332Sdes return 0; 24560573Skris} 24660573Skris 24792555Sdesstatic void 248294332Sdeskex_reset_dispatch(struct ssh *ssh) 24969587Sgreen{ 250294332Sdes ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 25192555Sdes SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 252294332Sdes ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 25369587Sgreen} 25469587Sgreen 255294332Sdesint 256294332Sdeskex_send_newkeys(struct ssh *ssh) 25769587Sgreen{ 258294332Sdes int r; 25969587Sgreen 260294332Sdes kex_reset_dispatch(ssh); 261294332Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 262294332Sdes (r = sshpkt_send(ssh)) != 0) 263294332Sdes return r; 26476259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 265294332Sdes debug("expecting SSH2_MSG_NEWKEYS"); 266294332Sdes ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 267294332Sdes return 0; 268294332Sdes} 26969587Sgreen 270294332Sdesstatic int 271294332Sdeskex_input_newkeys(int type, u_int32_t seq, void *ctxt) 272294332Sdes{ 273294332Sdes struct ssh *ssh = ctxt; 274294332Sdes struct kex *kex = ssh->kex; 275294332Sdes int r; 276294332Sdes 27776259Sgreen debug("SSH2_MSG_NEWKEYS received"); 278294332Sdes ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 279294332Sdes if ((r = sshpkt_get_end(ssh)) != 0) 280294332Sdes return r; 28176259Sgreen kex->done = 1; 282294332Sdes sshbuf_reset(kex->peer); 283294332Sdes /* sshbuf_reset(kex->my); */ 28476259Sgreen kex->flags &= ~KEX_INIT_SENT; 285255767Sdes free(kex->name); 28676259Sgreen kex->name = NULL; 287294332Sdes return 0; 28869587Sgreen} 28969587Sgreen 290294332Sdesint 291294332Sdeskex_send_kexinit(struct ssh *ssh) 29260573Skris{ 29398675Sdes u_char *cookie; 294294332Sdes struct kex *kex = ssh->kex; 295294332Sdes int r; 29698675Sdes 297294332Sdes if (kex == NULL) 298294332Sdes return SSH_ERR_INTERNAL_ERROR; 299294332Sdes if (kex->flags & KEX_INIT_SENT) 300294332Sdes return 0; 30176259Sgreen kex->done = 0; 30298675Sdes 30398675Sdes /* generate a random cookie */ 304294332Sdes if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 305294332Sdes return SSH_ERR_INVALID_FORMAT; 306294332Sdes if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 307294332Sdes return SSH_ERR_INTERNAL_ERROR; 308294332Sdes arc4random_buf(cookie, KEX_COOKIE_LEN); 309294332Sdes 310294332Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 311294332Sdes (r = sshpkt_putb(ssh, kex->my)) != 0 || 312294332Sdes (r = sshpkt_send(ssh)) != 0) 313294332Sdes return r; 31476259Sgreen debug("SSH2_MSG_KEXINIT sent"); 31576259Sgreen kex->flags |= KEX_INIT_SENT; 316294332Sdes return 0; 31760573Skris} 31860573Skris 319181111Sdes/* ARGSUSED */ 320294332Sdesint 32192555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 32260573Skris{ 323294332Sdes struct ssh *ssh = ctxt; 324294332Sdes struct kex *kex = ssh->kex; 325294332Sdes const u_char *ptr; 326294332Sdes u_int i; 327294332Sdes size_t dlen; 328294332Sdes int r; 32960573Skris 33076259Sgreen debug("SSH2_MSG_KEXINIT received"); 33176259Sgreen if (kex == NULL) 332294332Sdes return SSH_ERR_INVALID_ARGUMENT; 33360573Skris 334294332Sdes ptr = sshpkt_ptr(ssh, &dlen); 335294332Sdes if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 336294332Sdes return r; 33760573Skris 33876259Sgreen /* discard packet */ 33976259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 340294332Sdes if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 341294332Sdes return r; 34276259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 343294332Sdes if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 344294332Sdes return r; 345248619Sdes /* 346248619Sdes * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 347248619Sdes * KEX method has the server move first, but a server might be using 348248619Sdes * a custom method or one that we otherwise don't support. We should 349248619Sdes * be prepared to remember first_kex_follows here so we can eat a 350248619Sdes * packet later. 351248619Sdes * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 352248619Sdes * for cases where the server *doesn't* go first. I guess we should 353248619Sdes * ignore it when it is set for these cases, which is what we do now. 354248619Sdes */ 355294332Sdes if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 356294332Sdes (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 357294332Sdes (r = sshpkt_get_end(ssh)) != 0) 358294332Sdes return r; 35960573Skris 360294332Sdes if (!(kex->flags & KEX_INIT_SENT)) 361294332Sdes if ((r = kex_send_kexinit(ssh)) != 0) 362294332Sdes return r; 363294332Sdes if ((r = kex_choose_conf(ssh)) != 0) 364294332Sdes return r; 365294332Sdes 366294332Sdes if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 367294332Sdes return (kex->kex[kex->kex_type])(ssh); 368294332Sdes 369294332Sdes return SSH_ERR_INTERNAL_ERROR; 37060573Skris} 37160573Skris 372294332Sdesint 373294332Sdeskex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 37469587Sgreen{ 375294332Sdes struct kex *kex; 376294332Sdes int r; 37769587Sgreen 378294332Sdes *kexp = NULL; 379294332Sdes if ((kex = calloc(1, sizeof(*kex))) == NULL) 380294332Sdes return SSH_ERR_ALLOC_FAIL; 381294332Sdes if ((kex->peer = sshbuf_new()) == NULL || 382294332Sdes (kex->my = sshbuf_new()) == NULL) { 383294332Sdes r = SSH_ERR_ALLOC_FAIL; 384294332Sdes goto out; 385294332Sdes } 386294332Sdes if ((r = kex_prop2buf(kex->my, proposal)) != 0) 387294332Sdes goto out; 38876259Sgreen kex->done = 0; 389294332Sdes kex_reset_dispatch(ssh); 390294332Sdes r = 0; 391294332Sdes *kexp = kex; 392294332Sdes out: 393294332Sdes if (r != 0) 394294332Sdes kex_free(kex); 395294332Sdes return r; 396294332Sdes} 39769587Sgreen 398294332Sdesvoid 399294332Sdeskex_free_newkeys(struct newkeys *newkeys) 400294332Sdes{ 401294332Sdes if (newkeys == NULL) 402294332Sdes return; 403294332Sdes if (newkeys->enc.key) { 404294332Sdes explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 405294332Sdes free(newkeys->enc.key); 406294332Sdes newkeys->enc.key = NULL; 407294332Sdes } 408294332Sdes if (newkeys->enc.iv) { 409294332Sdes explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size); 410294332Sdes free(newkeys->enc.iv); 411294332Sdes newkeys->enc.iv = NULL; 412294332Sdes } 413294332Sdes free(newkeys->enc.name); 414294332Sdes explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 415294332Sdes free(newkeys->comp.name); 416294332Sdes explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 417294332Sdes mac_clear(&newkeys->mac); 418294332Sdes if (newkeys->mac.key) { 419294332Sdes explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 420294332Sdes free(newkeys->mac.key); 421294332Sdes newkeys->mac.key = NULL; 422294332Sdes } 423294332Sdes free(newkeys->mac.name); 424294332Sdes explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 425294332Sdes explicit_bzero(newkeys, sizeof(*newkeys)); 426294332Sdes free(newkeys); 427294332Sdes} 42869587Sgreen 429294332Sdesvoid 430294332Sdeskex_free(struct kex *kex) 431294332Sdes{ 432294332Sdes u_int mode; 433294332Sdes 434294332Sdes#ifdef WITH_OPENSSL 435294332Sdes if (kex->dh) 436294332Sdes DH_free(kex->dh); 437294332Sdes#ifdef OPENSSL_HAS_ECC 438294332Sdes if (kex->ec_client_key) 439294332Sdes EC_KEY_free(kex->ec_client_key); 440294332Sdes#endif /* OPENSSL_HAS_ECC */ 441294332Sdes#endif /* WITH_OPENSSL */ 442294332Sdes for (mode = 0; mode < MODE_MAX; mode++) { 443294332Sdes kex_free_newkeys(kex->newkeys[mode]); 444294332Sdes kex->newkeys[mode] = NULL; 445294332Sdes } 446294332Sdes sshbuf_free(kex->peer); 447294332Sdes sshbuf_free(kex->my); 448294332Sdes free(kex->session_id); 449294332Sdes free(kex->client_version_string); 450294332Sdes free(kex->server_version_string); 451294332Sdes free(kex); 45269587Sgreen} 45369587Sgreen 454294332Sdesint 455294332Sdeskex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 45660573Skris{ 457294332Sdes int r; 45860573Skris 459294332Sdes if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 460294332Sdes return r; 461294332Sdes if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 462294332Sdes kex_free(ssh->kex); 463294332Sdes ssh->kex = NULL; 464294332Sdes return r; 46560573Skris } 466294332Sdes return 0; 46760573Skris} 46860573Skris 469294332Sdesstatic int 470294332Sdeschoose_enc(struct sshenc *enc, char *client, char *server) 47160573Skris{ 47276259Sgreen char *name = match_list(client, server, NULL); 473294332Sdes 47460573Skris if (name == NULL) 475294332Sdes return SSH_ERR_NO_CIPHER_ALG_MATCH; 47692555Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) 477294332Sdes return SSH_ERR_INTERNAL_ERROR; 47860573Skris enc->name = name; 47960573Skris enc->enabled = 0; 48060573Skris enc->iv = NULL; 481248619Sdes enc->iv_len = cipher_ivlen(enc->cipher); 48260573Skris enc->key = NULL; 48392555Sdes enc->key_len = cipher_keylen(enc->cipher); 48492555Sdes enc->block_size = cipher_blocksize(enc->cipher); 485294332Sdes return 0; 48660573Skris} 487162852Sdes 488294332Sdesstatic int 489294332Sdeschoose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 49060573Skris{ 49176259Sgreen char *name = match_list(client, server, NULL); 492294332Sdes 49360573Skris if (name == NULL) 494294332Sdes return SSH_ERR_NO_MAC_ALG_MATCH; 495181111Sdes if (mac_setup(mac, name) < 0) 496294332Sdes return SSH_ERR_INTERNAL_ERROR; 49776259Sgreen /* truncate the key */ 498294332Sdes if (ssh->compat & SSH_BUG_HMAC) 49976259Sgreen mac->key_len = 16; 50060573Skris mac->name = name; 50160573Skris mac->key = NULL; 50260573Skris mac->enabled = 0; 503294332Sdes return 0; 50460573Skris} 505162852Sdes 506294332Sdesstatic int 507294332Sdeschoose_comp(struct sshcomp *comp, char *client, char *server) 50860573Skris{ 50976259Sgreen char *name = match_list(client, server, NULL); 510294332Sdes 51160573Skris if (name == NULL) 512294332Sdes return SSH_ERR_NO_COMPRESS_ALG_MATCH; 513149749Sdes if (strcmp(name, "zlib@openssh.com") == 0) { 514149749Sdes comp->type = COMP_DELAYED; 515149749Sdes } else if (strcmp(name, "zlib") == 0) { 516149749Sdes comp->type = COMP_ZLIB; 51760573Skris } else if (strcmp(name, "none") == 0) { 518149749Sdes comp->type = COMP_NONE; 51960573Skris } else { 520294332Sdes return SSH_ERR_INTERNAL_ERROR; 52160573Skris } 52260573Skris comp->name = name; 523294332Sdes return 0; 52460573Skris} 525162852Sdes 526294332Sdesstatic int 527294332Sdeschoose_kex(struct kex *k, char *client, char *server) 52860573Skris{ 529255767Sdes const struct kexalg *kexalg; 530255767Sdes 53176259Sgreen k->name = match_list(client, server, NULL); 532294332Sdes 53360573Skris if (k->name == NULL) 534294332Sdes return SSH_ERR_NO_KEX_ALG_MATCH; 535255767Sdes if ((kexalg = kex_alg_by_name(k->name)) == NULL) 536294332Sdes return SSH_ERR_INTERNAL_ERROR; 537255767Sdes k->kex_type = kexalg->type; 538261320Sdes k->hash_alg = kexalg->hash_alg; 539255767Sdes k->ec_nid = kexalg->ec_nid; 540294332Sdes return 0; 54160573Skris} 542157016Sdes 543294332Sdesstatic int 544294332Sdeschoose_hostkeyalg(struct kex *k, char *client, char *server) 54560573Skris{ 54676259Sgreen char *hostkeyalg = match_list(client, server, NULL); 547294332Sdes 54876259Sgreen if (hostkeyalg == NULL) 549294332Sdes return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 550294332Sdes k->hostkey_type = sshkey_type_from_name(hostkeyalg); 55176259Sgreen if (k->hostkey_type == KEY_UNSPEC) 552294332Sdes return SSH_ERR_INTERNAL_ERROR; 553294332Sdes k->hostkey_nid = sshkey_ecdsa_nid_from_name(hostkeyalg); 554255767Sdes free(hostkeyalg); 555294332Sdes return 0; 55660573Skris} 55760573Skris 558126274Sdesstatic int 559113908Sdesproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 560113908Sdes{ 561113908Sdes static int check[] = { 562113908Sdes PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 563113908Sdes }; 564113908Sdes int *idx; 565113908Sdes char *p; 566113908Sdes 567113908Sdes for (idx = &check[0]; *idx != -1; idx++) { 568113908Sdes if ((p = strchr(my[*idx], ',')) != NULL) 569113908Sdes *p = '\0'; 570113908Sdes if ((p = strchr(peer[*idx], ',')) != NULL) 571113908Sdes *p = '\0'; 572113908Sdes if (strcmp(my[*idx], peer[*idx]) != 0) { 573113908Sdes debug2("proposal mismatch: my %s peer %s", 574113908Sdes my[*idx], peer[*idx]); 575113908Sdes return (0); 576113908Sdes } 577113908Sdes } 578113908Sdes debug2("proposals match"); 579113908Sdes return (1); 580113908Sdes} 581113908Sdes 582294332Sdesstatic int 583294332Sdeskex_choose_conf(struct ssh *ssh) 58460573Skris{ 585294332Sdes struct kex *kex = ssh->kex; 586294332Sdes struct newkeys *newkeys; 587294332Sdes char **my = NULL, **peer = NULL; 58876259Sgreen char **cprop, **sprop; 58976259Sgreen int nenc, nmac, ncomp; 590261320Sdes u_int mode, ctos, need, dh_need, authlen; 591294332Sdes int r, first_kex_follows; 59260573Skris 593294332Sdes if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || 594294332Sdes (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 595294332Sdes goto out; 59660573Skris 59776259Sgreen if (kex->server) { 59876259Sgreen cprop=peer; 59976259Sgreen sprop=my; 60076259Sgreen } else { 60176259Sgreen cprop=my; 60276259Sgreen sprop=peer; 60376259Sgreen } 60476259Sgreen 605204917Sdes /* Check whether server offers roaming */ 606204917Sdes if (!kex->server) { 607294332Sdes char *roaming = match_list(KEX_RESUME, 608294332Sdes peer[PROPOSAL_KEX_ALGS], NULL); 609294332Sdes 610204917Sdes if (roaming) { 611204917Sdes kex->roaming = 1; 612255767Sdes free(roaming); 613204917Sdes } 614204917Sdes } 615204917Sdes 61676259Sgreen /* Algorithm Negotiation */ 61760573Skris for (mode = 0; mode < MODE_MAX; mode++) { 618294332Sdes if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 619294332Sdes r = SSH_ERR_ALLOC_FAIL; 620294332Sdes goto out; 621294332Sdes } 62276259Sgreen kex->newkeys[mode] = newkeys; 623181111Sdes ctos = (!kex->server && mode == MODE_OUT) || 624181111Sdes (kex->server && mode == MODE_IN); 62560573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 62660573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 62760573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 628294332Sdes if ((r = choose_enc(&newkeys->enc, cprop[nenc], 629294332Sdes sprop[nenc])) != 0) 630294332Sdes goto out; 631294332Sdes authlen = cipher_authlen(newkeys->enc.cipher); 632248619Sdes /* ignore mac for authenticated encryption */ 633294332Sdes if (authlen == 0 && 634294332Sdes (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 635294332Sdes sprop[nmac])) != 0) 636294332Sdes goto out; 637294332Sdes if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 638294332Sdes sprop[ncomp])) != 0) 639294332Sdes goto out; 64060573Skris debug("kex: %s %s %s %s", 64160573Skris ctos ? "client->server" : "server->client", 64276259Sgreen newkeys->enc.name, 643248619Sdes authlen == 0 ? newkeys->mac.name : "<implicit>", 64476259Sgreen newkeys->comp.name); 64560573Skris } 646294332Sdes if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 647294332Sdes sprop[PROPOSAL_KEX_ALGS])) != 0 || 648294332Sdes (r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 649294332Sdes sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) 650294332Sdes goto out; 651261320Sdes need = dh_need = 0; 65260573Skris for (mode = 0; mode < MODE_MAX; mode++) { 65376259Sgreen newkeys = kex->newkeys[mode]; 654261320Sdes need = MAX(need, newkeys->enc.key_len); 655261320Sdes need = MAX(need, newkeys->enc.block_size); 656261320Sdes need = MAX(need, newkeys->enc.iv_len); 657261320Sdes need = MAX(need, newkeys->mac.key_len); 658261320Sdes dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher)); 659261320Sdes dh_need = MAX(dh_need, newkeys->enc.block_size); 660261320Sdes dh_need = MAX(dh_need, newkeys->enc.iv_len); 661261320Sdes dh_need = MAX(dh_need, newkeys->mac.key_len); 66260573Skris } 66361209Skris /* XXX need runden? */ 66476259Sgreen kex->we_need = need; 665261320Sdes kex->dh_need = dh_need; 66676259Sgreen 667113908Sdes /* ignore the next message if the proposals do not match */ 668126274Sdes if (first_kex_follows && !proposals_match(my, peer) && 669294332Sdes !(ssh->compat & SSH_BUG_FIRSTKEX)) 670294332Sdes ssh->dispatch_skip_packets = 1; 671294332Sdes r = 0; 672294332Sdes out: 67376259Sgreen kex_prop_free(my); 67476259Sgreen kex_prop_free(peer); 675294332Sdes return r; 67660573Skris} 67760573Skris 678294332Sdesstatic int 679294332Sdesderive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 680294332Sdes const struct sshbuf *shared_secret, u_char **keyp) 68160573Skris{ 682294332Sdes struct kex *kex = ssh->kex; 683294332Sdes struct ssh_digest_ctx *hashctx = NULL; 68476259Sgreen char c = id; 685149749Sdes u_int have; 686261320Sdes size_t mdsz; 687149749Sdes u_char *digest; 688294332Sdes int r; 68960573Skris 690261320Sdes if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 691294332Sdes return SSH_ERR_INVALID_ARGUMENT; 692294332Sdes if ((digest = calloc(1, roundup(need, mdsz))) == NULL) { 693294332Sdes r = SSH_ERR_ALLOC_FAIL; 694294332Sdes goto out; 695294332Sdes } 696149749Sdes 69776259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 698294332Sdes if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 699294332Sdes ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 700261320Sdes ssh_digest_update(hashctx, hash, hashlen) != 0 || 701261320Sdes ssh_digest_update(hashctx, &c, 1) != 0 || 702261320Sdes ssh_digest_update(hashctx, kex->session_id, 703294332Sdes kex->session_id_len) != 0 || 704294332Sdes ssh_digest_final(hashctx, digest, mdsz) != 0) { 705294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 706294332Sdes goto out; 707294332Sdes } 708261320Sdes ssh_digest_free(hashctx); 709294332Sdes hashctx = NULL; 71076259Sgreen 71176259Sgreen /* 71276259Sgreen * expand key: 71376259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 71476259Sgreen * Key = K1 || K2 || ... || Kn 71576259Sgreen */ 71676259Sgreen for (have = mdsz; need > have; have += mdsz) { 717294332Sdes if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 718294332Sdes ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 719261320Sdes ssh_digest_update(hashctx, hash, hashlen) != 0 || 720294332Sdes ssh_digest_update(hashctx, digest, have) != 0 || 721294332Sdes ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 722294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 723294332Sdes goto out; 724294332Sdes } 725261320Sdes ssh_digest_free(hashctx); 726294332Sdes hashctx = NULL; 72776259Sgreen } 72876259Sgreen#ifdef DEBUG_KEX 72976259Sgreen fprintf(stderr, "key '%c'== ", c); 73076259Sgreen dump_digest("key", digest, need); 73176259Sgreen#endif 732294332Sdes *keyp = digest; 733294332Sdes digest = NULL; 734294332Sdes r = 0; 735294332Sdes out: 736294332Sdes if (digest) 737294332Sdes free(digest); 738294332Sdes ssh_digest_free(hashctx); 739294332Sdes return r; 74076259Sgreen} 74176259Sgreen 74276259Sgreen#define NKEYS 6 743294332Sdesint 744294332Sdeskex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 745294332Sdes const struct sshbuf *shared_secret) 74676259Sgreen{ 747294332Sdes struct kex *kex = ssh->kex; 74876259Sgreen u_char *keys[NKEYS]; 749294332Sdes u_int i, j, mode, ctos; 750294332Sdes int r; 75176259Sgreen 752157016Sdes for (i = 0; i < NKEYS; i++) { 753294332Sdes if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 754294332Sdes shared_secret, &keys[i])) != 0) { 755294332Sdes for (j = 0; j < i; j++) 756294332Sdes free(keys[j]); 757294332Sdes return r; 758294332Sdes } 759157016Sdes } 76060573Skris for (mode = 0; mode < MODE_MAX; mode++) { 761162852Sdes ctos = (!kex->server && mode == MODE_OUT) || 762162852Sdes (kex->server && mode == MODE_IN); 763294332Sdes kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 764294332Sdes kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 765294332Sdes kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 76660573Skris } 767294332Sdes return 0; 76860573Skris} 76976259Sgreen 770294328Sdes#ifdef WITH_OPENSSL 771294332Sdesint 772294332Sdeskex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 773294332Sdes const BIGNUM *secret) 774261320Sdes{ 775294332Sdes struct sshbuf *shared_secret; 776294332Sdes int r; 777261320Sdes 778294332Sdes if ((shared_secret = sshbuf_new()) == NULL) 779294332Sdes return SSH_ERR_ALLOC_FAIL; 780294332Sdes if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 781294332Sdes r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 782294332Sdes sshbuf_free(shared_secret); 783294332Sdes return r; 784261320Sdes} 785294328Sdes#endif 786261320Sdes 787294328Sdes#ifdef WITH_SSH1 788294332Sdesint 789137015Sdesderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 790137015Sdes u_int8_t cookie[8], u_int8_t id[16]) 791137015Sdes{ 792294332Sdes u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; 793294332Sdes struct ssh_digest_ctx *hashctx = NULL; 794294332Sdes size_t hlen, slen; 795294332Sdes int r; 796137015Sdes 797294332Sdes hlen = BN_num_bytes(host_modulus); 798294332Sdes slen = BN_num_bytes(server_modulus); 799294332Sdes if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || 800294332Sdes slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) 801294332Sdes return SSH_ERR_KEY_BITS_MISMATCH; 802294332Sdes if (BN_bn2bin(host_modulus, hbuf) <= 0 || 803294332Sdes BN_bn2bin(server_modulus, sbuf) <= 0) { 804294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 805294332Sdes goto out; 806294332Sdes } 807294332Sdes if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { 808294332Sdes r = SSH_ERR_ALLOC_FAIL; 809294332Sdes goto out; 810294332Sdes } 811294332Sdes if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || 812294332Sdes ssh_digest_update(hashctx, sbuf, slen) != 0 || 813294332Sdes ssh_digest_update(hashctx, cookie, 8) != 0 || 814294332Sdes ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { 815294332Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 816294332Sdes goto out; 817294332Sdes } 818261320Sdes memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); 819294332Sdes r = 0; 820294332Sdes out: 821294332Sdes ssh_digest_free(hashctx); 822294332Sdes explicit_bzero(hbuf, sizeof(hbuf)); 823294332Sdes explicit_bzero(sbuf, sizeof(sbuf)); 824263712Sdes explicit_bzero(obuf, sizeof(obuf)); 825294332Sdes return r; 826137015Sdes} 827294328Sdes#endif 828137015Sdes 829221420Sdes#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 83076259Sgreenvoid 83176259Sgreendump_digest(char *msg, u_char *digest, int len) 83276259Sgreen{ 83376259Sgreen fprintf(stderr, "%s\n", msg); 834294332Sdes sshbuf_dump_data(digest, len, stderr); 83576259Sgreen} 83676259Sgreen#endif 837