1*eccfee6eSDag-Erling Smørgrav /* $OpenBSD: kex.c,v 1.109 2015/07/30 00:01:34 djm Exp $ */ 2a04a10f8SKris Kennaway /* 3ae1f160dSDag-Erling Smørgrav * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4a04a10f8SKris Kennaway * 5a04a10f8SKris Kennaway * Redistribution and use in source and binary forms, with or without 6a04a10f8SKris Kennaway * modification, are permitted provided that the following conditions 7a04a10f8SKris Kennaway * are met: 8a04a10f8SKris Kennaway * 1. Redistributions of source code must retain the above copyright 9a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer. 10a04a10f8SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 11a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer in the 12a04a10f8SKris Kennaway * documentation and/or other materials provided with the distribution. 13a04a10f8SKris Kennaway * 14a04a10f8SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15a04a10f8SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16a04a10f8SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17a04a10f8SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18a04a10f8SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19a04a10f8SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20a04a10f8SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21a04a10f8SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22a04a10f8SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23a04a10f8SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24a04a10f8SKris Kennaway */ 25a04a10f8SKris Kennaway 26a04a10f8SKris Kennaway #include "includes.h" 27761efaa7SDag-Erling Smørgrav 28bc5531deSDag-Erling Smørgrav #include <sys/param.h> /* MAX roundup */ 29761efaa7SDag-Erling Smørgrav 30761efaa7SDag-Erling Smørgrav #include <signal.h> 31761efaa7SDag-Erling Smørgrav #include <stdarg.h> 32761efaa7SDag-Erling Smørgrav #include <stdio.h> 33761efaa7SDag-Erling Smørgrav #include <stdlib.h> 34761efaa7SDag-Erling Smørgrav #include <string.h> 35a04a10f8SKris Kennaway 36a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 371e8db6e2SBrian Feldman #include <openssl/crypto.h> 38a0ee8cc6SDag-Erling Smørgrav #endif 391e8db6e2SBrian Feldman 40761efaa7SDag-Erling Smørgrav #include "ssh2.h" 412632b0c8SKris Kennaway #include "packet.h" 42a04a10f8SKris Kennaway #include "compat.h" 431e8db6e2SBrian Feldman #include "cipher.h" 44bc5531deSDag-Erling Smørgrav #include "sshkey.h" 45761efaa7SDag-Erling Smørgrav #include "kex.h" 461e8db6e2SBrian Feldman #include "log.h" 471e8db6e2SBrian Feldman #include "mac.h" 481e8db6e2SBrian Feldman #include "match.h" 49bc5531deSDag-Erling Smørgrav #include "misc.h" 501e8db6e2SBrian Feldman #include "dispatch.h" 51545d5ecaSDag-Erling Smørgrav #include "monitor.h" 52b15c8340SDag-Erling Smørgrav #include "roaming.h" 53bc5531deSDag-Erling Smørgrav 54bc5531deSDag-Erling Smørgrav #include "ssherr.h" 55bc5531deSDag-Erling Smørgrav #include "sshbuf.h" 56f7167e0eSDag-Erling Smørgrav #include "digest.h" 57a04a10f8SKris Kennaway 58761efaa7SDag-Erling Smørgrav #if OPENSSL_VERSION_NUMBER >= 0x00907000L 59761efaa7SDag-Erling Smørgrav # if defined(HAVE_EVP_SHA256) 60761efaa7SDag-Erling Smørgrav # define evp_ssh_sha256 EVP_sha256 61761efaa7SDag-Erling Smørgrav # else 62761efaa7SDag-Erling Smørgrav extern const EVP_MD *evp_ssh_sha256(void); 63761efaa7SDag-Erling Smørgrav # endif 64761efaa7SDag-Erling Smørgrav #endif 65761efaa7SDag-Erling Smørgrav 66ae1f160dSDag-Erling Smørgrav /* prototype */ 67bc5531deSDag-Erling Smørgrav static int kex_choose_conf(struct ssh *); 68bc5531deSDag-Erling Smørgrav static int kex_input_newkeys(int, u_int32_t, void *); 691e8db6e2SBrian Feldman 70e4a9863fSDag-Erling Smørgrav struct kexalg { 71e4a9863fSDag-Erling Smørgrav char *name; 72bc5531deSDag-Erling Smørgrav u_int type; 73e4a9863fSDag-Erling Smørgrav int ec_nid; 74f7167e0eSDag-Erling Smørgrav int hash_alg; 75e4a9863fSDag-Erling Smørgrav }; 76e4a9863fSDag-Erling Smørgrav static const struct kexalg kexalgs[] = { 77a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 78f7167e0eSDag-Erling Smørgrav { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 79f7167e0eSDag-Erling Smørgrav { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 80f7167e0eSDag-Erling Smørgrav { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 81e4a9863fSDag-Erling Smørgrav #ifdef HAVE_EVP_SHA256 82f7167e0eSDag-Erling Smørgrav { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 83a0ee8cc6SDag-Erling Smørgrav #endif /* HAVE_EVP_SHA256 */ 84e4a9863fSDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 85f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 86f7167e0eSDag-Erling Smørgrav NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 87f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, 88f7167e0eSDag-Erling Smørgrav SSH_DIGEST_SHA384 }, 89f7167e0eSDag-Erling Smørgrav # ifdef OPENSSL_HAS_NISTP521 90f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 91f7167e0eSDag-Erling Smørgrav SSH_DIGEST_SHA512 }, 92a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_NISTP521 */ 93a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 94a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 95bc5531deSDag-Erling Smørgrav #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) 96f7167e0eSDag-Erling Smørgrav { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 97bc5531deSDag-Erling Smørgrav #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 98f7167e0eSDag-Erling Smørgrav { NULL, -1, -1, -1}, 99e4a9863fSDag-Erling Smørgrav }; 100e4a9863fSDag-Erling Smørgrav 101e4a9863fSDag-Erling Smørgrav char * 102f7167e0eSDag-Erling Smørgrav kex_alg_list(char sep) 103e4a9863fSDag-Erling Smørgrav { 104bc5531deSDag-Erling Smørgrav char *ret = NULL, *tmp; 105e4a9863fSDag-Erling Smørgrav size_t nlen, rlen = 0; 106e4a9863fSDag-Erling Smørgrav const struct kexalg *k; 107e4a9863fSDag-Erling Smørgrav 108e4a9863fSDag-Erling Smørgrav for (k = kexalgs; k->name != NULL; k++) { 109e4a9863fSDag-Erling Smørgrav if (ret != NULL) 110f7167e0eSDag-Erling Smørgrav ret[rlen++] = sep; 111e4a9863fSDag-Erling Smørgrav nlen = strlen(k->name); 112bc5531deSDag-Erling Smørgrav if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 113bc5531deSDag-Erling Smørgrav free(ret); 114bc5531deSDag-Erling Smørgrav return NULL; 115bc5531deSDag-Erling Smørgrav } 116bc5531deSDag-Erling Smørgrav ret = tmp; 117e4a9863fSDag-Erling Smørgrav memcpy(ret + rlen, k->name, nlen + 1); 118e4a9863fSDag-Erling Smørgrav rlen += nlen; 119e4a9863fSDag-Erling Smørgrav } 120e4a9863fSDag-Erling Smørgrav return ret; 121e4a9863fSDag-Erling Smørgrav } 122e4a9863fSDag-Erling Smørgrav 123e4a9863fSDag-Erling Smørgrav static const struct kexalg * 124e4a9863fSDag-Erling Smørgrav kex_alg_by_name(const char *name) 125e4a9863fSDag-Erling Smørgrav { 126e4a9863fSDag-Erling Smørgrav const struct kexalg *k; 127e4a9863fSDag-Erling Smørgrav 128e4a9863fSDag-Erling Smørgrav for (k = kexalgs; k->name != NULL; k++) { 129e4a9863fSDag-Erling Smørgrav if (strcmp(k->name, name) == 0) 130e4a9863fSDag-Erling Smørgrav return k; 131e4a9863fSDag-Erling Smørgrav } 132e4a9863fSDag-Erling Smørgrav return NULL; 133e4a9863fSDag-Erling Smørgrav } 134e4a9863fSDag-Erling Smørgrav 1354a421b63SDag-Erling Smørgrav /* Validate KEX method name list */ 1364a421b63SDag-Erling Smørgrav int 1374a421b63SDag-Erling Smørgrav kex_names_valid(const char *names) 1384a421b63SDag-Erling Smørgrav { 1394a421b63SDag-Erling Smørgrav char *s, *cp, *p; 1404a421b63SDag-Erling Smørgrav 1414a421b63SDag-Erling Smørgrav if (names == NULL || strcmp(names, "") == 0) 1424a421b63SDag-Erling Smørgrav return 0; 143bc5531deSDag-Erling Smørgrav if ((s = cp = strdup(names)) == NULL) 144bc5531deSDag-Erling Smørgrav return 0; 1454a421b63SDag-Erling Smørgrav for ((p = strsep(&cp, ",")); p && *p != '\0'; 1464a421b63SDag-Erling Smørgrav (p = strsep(&cp, ","))) { 147e4a9863fSDag-Erling Smørgrav if (kex_alg_by_name(p) == NULL) { 1484a421b63SDag-Erling Smørgrav error("Unsupported KEX algorithm \"%.100s\"", p); 149e4a9863fSDag-Erling Smørgrav free(s); 1504a421b63SDag-Erling Smørgrav return 0; 1514a421b63SDag-Erling Smørgrav } 1524a421b63SDag-Erling Smørgrav } 1534a421b63SDag-Erling Smørgrav debug3("kex names ok: [%s]", names); 154e4a9863fSDag-Erling Smørgrav free(s); 1554a421b63SDag-Erling Smørgrav return 1; 1564a421b63SDag-Erling Smørgrav } 1574a421b63SDag-Erling Smørgrav 158*eccfee6eSDag-Erling Smørgrav /* 159*eccfee6eSDag-Erling Smørgrav * Concatenate algorithm names, avoiding duplicates in the process. 160*eccfee6eSDag-Erling Smørgrav * Caller must free returned string. 161*eccfee6eSDag-Erling Smørgrav */ 162*eccfee6eSDag-Erling Smørgrav char * 163*eccfee6eSDag-Erling Smørgrav kex_names_cat(const char *a, const char *b) 164*eccfee6eSDag-Erling Smørgrav { 165*eccfee6eSDag-Erling Smørgrav char *ret = NULL, *tmp = NULL, *cp, *p; 166*eccfee6eSDag-Erling Smørgrav size_t len; 167*eccfee6eSDag-Erling Smørgrav 168*eccfee6eSDag-Erling Smørgrav if (a == NULL || *a == '\0') 169*eccfee6eSDag-Erling Smørgrav return NULL; 170*eccfee6eSDag-Erling Smørgrav if (b == NULL || *b == '\0') 171*eccfee6eSDag-Erling Smørgrav return strdup(a); 172*eccfee6eSDag-Erling Smørgrav if (strlen(b) > 1024*1024) 173*eccfee6eSDag-Erling Smørgrav return NULL; 174*eccfee6eSDag-Erling Smørgrav len = strlen(a) + strlen(b) + 2; 175*eccfee6eSDag-Erling Smørgrav if ((tmp = cp = strdup(b)) == NULL || 176*eccfee6eSDag-Erling Smørgrav (ret = calloc(1, len)) == NULL) { 177*eccfee6eSDag-Erling Smørgrav free(tmp); 178*eccfee6eSDag-Erling Smørgrav return NULL; 179*eccfee6eSDag-Erling Smørgrav } 180*eccfee6eSDag-Erling Smørgrav strlcpy(ret, a, len); 181*eccfee6eSDag-Erling Smørgrav for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { 182*eccfee6eSDag-Erling Smørgrav if (match_list(ret, p, NULL) != NULL) 183*eccfee6eSDag-Erling Smørgrav continue; /* Algorithm already present */ 184*eccfee6eSDag-Erling Smørgrav if (strlcat(ret, ",", len) >= len || 185*eccfee6eSDag-Erling Smørgrav strlcat(ret, p, len) >= len) { 186*eccfee6eSDag-Erling Smørgrav free(tmp); 187*eccfee6eSDag-Erling Smørgrav free(ret); 188*eccfee6eSDag-Erling Smørgrav return NULL; /* Shouldn't happen */ 189*eccfee6eSDag-Erling Smørgrav } 190*eccfee6eSDag-Erling Smørgrav } 191*eccfee6eSDag-Erling Smørgrav free(tmp); 192*eccfee6eSDag-Erling Smørgrav return ret; 193*eccfee6eSDag-Erling Smørgrav } 194*eccfee6eSDag-Erling Smørgrav 195*eccfee6eSDag-Erling Smørgrav /* 196*eccfee6eSDag-Erling Smørgrav * Assemble a list of algorithms from a default list and a string from a 197*eccfee6eSDag-Erling Smørgrav * configuration file. The user-provided string may begin with '+' to 198*eccfee6eSDag-Erling Smørgrav * indicate that it should be appended to the default. 199*eccfee6eSDag-Erling Smørgrav */ 200*eccfee6eSDag-Erling Smørgrav int 201*eccfee6eSDag-Erling Smørgrav kex_assemble_names(const char *def, char **list) 202*eccfee6eSDag-Erling Smørgrav { 203*eccfee6eSDag-Erling Smørgrav char *ret; 204*eccfee6eSDag-Erling Smørgrav 205*eccfee6eSDag-Erling Smørgrav if (list == NULL || *list == NULL || **list == '\0') { 206*eccfee6eSDag-Erling Smørgrav *list = strdup(def); 207*eccfee6eSDag-Erling Smørgrav return 0; 208*eccfee6eSDag-Erling Smørgrav } 209*eccfee6eSDag-Erling Smørgrav if (**list != '+') { 210*eccfee6eSDag-Erling Smørgrav return 0; 211*eccfee6eSDag-Erling Smørgrav } 212*eccfee6eSDag-Erling Smørgrav 213*eccfee6eSDag-Erling Smørgrav if ((ret = kex_names_cat(def, *list + 1)) == NULL) 214*eccfee6eSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 215*eccfee6eSDag-Erling Smørgrav free(*list); 216*eccfee6eSDag-Erling Smørgrav *list = ret; 217*eccfee6eSDag-Erling Smørgrav return 0; 218*eccfee6eSDag-Erling Smørgrav } 219*eccfee6eSDag-Erling Smørgrav 2201765946bSDag-Erling Smørgrav /* put algorithm proposal into buffer */ 221bc5531deSDag-Erling Smørgrav int 222bc5531deSDag-Erling Smørgrav kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 223a04a10f8SKris Kennaway { 224043840dfSDag-Erling Smørgrav u_int i; 225bc5531deSDag-Erling Smørgrav int r; 2261e8db6e2SBrian Feldman 227bc5531deSDag-Erling Smørgrav sshbuf_reset(b); 228bc5531deSDag-Erling Smørgrav 229545d5ecaSDag-Erling Smørgrav /* 230545d5ecaSDag-Erling Smørgrav * add a dummy cookie, the cookie will be overwritten by 231545d5ecaSDag-Erling Smørgrav * kex_send_kexinit(), each time a kexinit is set 232545d5ecaSDag-Erling Smørgrav */ 233bc5531deSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) { 234bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(b, 0)) != 0) 235bc5531deSDag-Erling Smørgrav return r; 236bc5531deSDag-Erling Smørgrav } 237bc5531deSDag-Erling Smørgrav for (i = 0; i < PROPOSAL_MAX; i++) { 238bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 239bc5531deSDag-Erling Smørgrav return r; 240bc5531deSDag-Erling Smørgrav } 241bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 242bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 243bc5531deSDag-Erling Smørgrav return r; 244bc5531deSDag-Erling Smørgrav return 0; 245a04a10f8SKris Kennaway } 246a04a10f8SKris Kennaway 2471e8db6e2SBrian Feldman /* parse buffer and return algorithm proposal */ 248bc5531deSDag-Erling Smørgrav int 249bc5531deSDag-Erling Smørgrav kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 2502632b0c8SKris Kennaway { 251bc5531deSDag-Erling Smørgrav struct sshbuf *b = NULL; 252bc5531deSDag-Erling Smørgrav u_char v; 253d4af9e69SDag-Erling Smørgrav u_int i; 254bc5531deSDag-Erling Smørgrav char **proposal = NULL; 255bc5531deSDag-Erling Smørgrav int r; 2562632b0c8SKris Kennaway 257bc5531deSDag-Erling Smørgrav *propp = NULL; 258bc5531deSDag-Erling Smørgrav if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 259bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 260bc5531deSDag-Erling Smørgrav if ((b = sshbuf_fromb(raw)) == NULL) { 261bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 262bc5531deSDag-Erling Smørgrav goto out; 263bc5531deSDag-Erling Smørgrav } 264bc5531deSDag-Erling Smørgrav if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 265bc5531deSDag-Erling Smørgrav goto out; 2662632b0c8SKris Kennaway /* extract kex init proposal strings */ 2672632b0c8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) { 268bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 269bc5531deSDag-Erling Smørgrav goto out; 2701e8db6e2SBrian Feldman debug2("kex_parse_kexinit: %s", proposal[i]); 2712632b0c8SKris Kennaway } 2721e8db6e2SBrian Feldman /* first kex follows / reserved */ 273bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u8(b, &v)) != 0 || 274bc5531deSDag-Erling Smørgrav (r = sshbuf_get_u32(b, &i)) != 0) 275bc5531deSDag-Erling Smørgrav goto out; 276d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows != NULL) 277d0c8c0bcSDag-Erling Smørgrav *first_kex_follows = i; 278bc5531deSDag-Erling Smørgrav debug2("kex_parse_kexinit: first_kex_follows %d ", v); 279d4af9e69SDag-Erling Smørgrav debug2("kex_parse_kexinit: reserved %u ", i); 280bc5531deSDag-Erling Smørgrav r = 0; 281bc5531deSDag-Erling Smørgrav *propp = proposal; 282bc5531deSDag-Erling Smørgrav out: 283bc5531deSDag-Erling Smørgrav if (r != 0 && proposal != NULL) 284bc5531deSDag-Erling Smørgrav kex_prop_free(proposal); 285bc5531deSDag-Erling Smørgrav sshbuf_free(b); 286bc5531deSDag-Erling Smørgrav return r; 2875b9b2fafSBrian Feldman } 2885b9b2fafSBrian Feldman 289bc5531deSDag-Erling Smørgrav void 2901e8db6e2SBrian Feldman kex_prop_free(char **proposal) 291a04a10f8SKris Kennaway { 292043840dfSDag-Erling Smørgrav u_int i; 2931e8db6e2SBrian Feldman 294557f75e5SDag-Erling Smørgrav if (proposal == NULL) 295557f75e5SDag-Erling Smørgrav return; 2961e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 297e4a9863fSDag-Erling Smørgrav free(proposal[i]); 298e4a9863fSDag-Erling Smørgrav free(proposal); 299a04a10f8SKris Kennaway } 300a04a10f8SKris Kennaway 301d4af9e69SDag-Erling Smørgrav /* ARGSUSED */ 302bc5531deSDag-Erling Smørgrav static int 303ae1f160dSDag-Erling Smørgrav kex_protocol_error(int type, u_int32_t seq, void *ctxt) 304a04a10f8SKris Kennaway { 305ae1f160dSDag-Erling Smørgrav error("Hm, kex protocol error: type %d seq %u", type, seq); 306bc5531deSDag-Erling Smørgrav return 0; 307a04a10f8SKris Kennaway } 308a04a10f8SKris Kennaway 309ae1f160dSDag-Erling Smørgrav static void 310bc5531deSDag-Erling Smørgrav kex_reset_dispatch(struct ssh *ssh) 3115b9b2fafSBrian Feldman { 312bc5531deSDag-Erling Smørgrav ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 313ae1f160dSDag-Erling Smørgrav SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 314bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 3155b9b2fafSBrian Feldman } 3165b9b2fafSBrian Feldman 317bc5531deSDag-Erling Smørgrav int 318bc5531deSDag-Erling Smørgrav kex_send_newkeys(struct ssh *ssh) 319a04a10f8SKris Kennaway { 320bc5531deSDag-Erling Smørgrav int r; 321a04a10f8SKris Kennaway 322bc5531deSDag-Erling Smørgrav kex_reset_dispatch(ssh); 323bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 324bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 325bc5531deSDag-Erling Smørgrav return r; 3261e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS sent"); 327d0c8c0bcSDag-Erling Smørgrav debug("expecting SSH2_MSG_NEWKEYS"); 328bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 329bc5531deSDag-Erling Smørgrav return 0; 330bc5531deSDag-Erling Smørgrav } 3311e8db6e2SBrian Feldman 332bc5531deSDag-Erling Smørgrav static int 333bc5531deSDag-Erling Smørgrav kex_input_newkeys(int type, u_int32_t seq, void *ctxt) 334bc5531deSDag-Erling Smørgrav { 335bc5531deSDag-Erling Smørgrav struct ssh *ssh = ctxt; 336bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 337bc5531deSDag-Erling Smørgrav int r; 338bc5531deSDag-Erling Smørgrav 339bc5531deSDag-Erling Smørgrav debug("SSH2_MSG_NEWKEYS received"); 340bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 341bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_end(ssh)) != 0) 342bc5531deSDag-Erling Smørgrav return r; 3431e8db6e2SBrian Feldman kex->done = 1; 344bc5531deSDag-Erling Smørgrav sshbuf_reset(kex->peer); 345bc5531deSDag-Erling Smørgrav /* sshbuf_reset(kex->my); */ 3461e8db6e2SBrian Feldman kex->flags &= ~KEX_INIT_SENT; 347e4a9863fSDag-Erling Smørgrav free(kex->name); 3481e8db6e2SBrian Feldman kex->name = NULL; 349bc5531deSDag-Erling Smørgrav return 0; 350a04a10f8SKris Kennaway } 351a04a10f8SKris Kennaway 352bc5531deSDag-Erling Smørgrav int 353bc5531deSDag-Erling Smørgrav kex_send_kexinit(struct ssh *ssh) 354a04a10f8SKris Kennaway { 355545d5ecaSDag-Erling Smørgrav u_char *cookie; 356bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 357bc5531deSDag-Erling Smørgrav int r; 358545d5ecaSDag-Erling Smørgrav 359bc5531deSDag-Erling Smørgrav if (kex == NULL) 360bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 361bc5531deSDag-Erling Smørgrav if (kex->flags & KEX_INIT_SENT) 362bc5531deSDag-Erling Smørgrav return 0; 3631e8db6e2SBrian Feldman kex->done = 0; 364545d5ecaSDag-Erling Smørgrav 365545d5ecaSDag-Erling Smørgrav /* generate a random cookie */ 366bc5531deSDag-Erling Smørgrav if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 367bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_FORMAT; 368bc5531deSDag-Erling Smørgrav if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 369bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 370bc5531deSDag-Erling Smørgrav arc4random_buf(cookie, KEX_COOKIE_LEN); 371bc5531deSDag-Erling Smørgrav 372bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 373bc5531deSDag-Erling Smørgrav (r = sshpkt_putb(ssh, kex->my)) != 0 || 374bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 375bc5531deSDag-Erling Smørgrav return r; 3761e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT sent"); 3771e8db6e2SBrian Feldman kex->flags |= KEX_INIT_SENT; 378bc5531deSDag-Erling Smørgrav return 0; 3791e8db6e2SBrian Feldman } 380a04a10f8SKris Kennaway 381d4af9e69SDag-Erling Smørgrav /* ARGSUSED */ 382bc5531deSDag-Erling Smørgrav int 383ae1f160dSDag-Erling Smørgrav kex_input_kexinit(int type, u_int32_t seq, void *ctxt) 3841e8db6e2SBrian Feldman { 385bc5531deSDag-Erling Smørgrav struct ssh *ssh = ctxt; 386bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 387bc5531deSDag-Erling Smørgrav const u_char *ptr; 388bc5531deSDag-Erling Smørgrav u_int i; 389bc5531deSDag-Erling Smørgrav size_t dlen; 390bc5531deSDag-Erling Smørgrav int r; 3912632b0c8SKris Kennaway 3921e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 3931e8db6e2SBrian Feldman if (kex == NULL) 394bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 3951e8db6e2SBrian Feldman 396bc5531deSDag-Erling Smørgrav ptr = sshpkt_ptr(ssh, &dlen); 397bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 398bc5531deSDag-Erling Smørgrav return r; 3991e8db6e2SBrian Feldman 4001e8db6e2SBrian Feldman /* discard packet */ 4011e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 402bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 403bc5531deSDag-Erling Smørgrav return r; 4041e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 405bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 406bc5531deSDag-Erling Smørgrav return r; 4076888a9beSDag-Erling Smørgrav /* 4086888a9beSDag-Erling Smørgrav * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 4096888a9beSDag-Erling Smørgrav * KEX method has the server move first, but a server might be using 4106888a9beSDag-Erling Smørgrav * a custom method or one that we otherwise don't support. We should 4116888a9beSDag-Erling Smørgrav * be prepared to remember first_kex_follows here so we can eat a 4126888a9beSDag-Erling Smørgrav * packet later. 4136888a9beSDag-Erling Smørgrav * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 4146888a9beSDag-Erling Smørgrav * for cases where the server *doesn't* go first. I guess we should 4156888a9beSDag-Erling Smørgrav * ignore it when it is set for these cases, which is what we do now. 4166888a9beSDag-Erling Smørgrav */ 417bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 418bc5531deSDag-Erling Smørgrav (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 419bc5531deSDag-Erling Smørgrav (r = sshpkt_get_end(ssh)) != 0) 420bc5531deSDag-Erling Smørgrav return r; 4211e8db6e2SBrian Feldman 4221e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 423bc5531deSDag-Erling Smørgrav if ((r = kex_send_kexinit(ssh)) != 0) 424bc5531deSDag-Erling Smørgrav return r; 425bc5531deSDag-Erling Smørgrav if ((r = kex_choose_conf(ssh)) != 0) 426bc5531deSDag-Erling Smørgrav return r; 4271e8db6e2SBrian Feldman 428bc5531deSDag-Erling Smørgrav if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 429bc5531deSDag-Erling Smørgrav return (kex->kex[kex->kex_type])(ssh); 4301e8db6e2SBrian Feldman 431bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 4321e8db6e2SBrian Feldman } 433a04a10f8SKris Kennaway 434bc5531deSDag-Erling Smørgrav int 435bc5531deSDag-Erling Smørgrav kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 436bc5531deSDag-Erling Smørgrav { 437bc5531deSDag-Erling Smørgrav struct kex *kex; 438bc5531deSDag-Erling Smørgrav int r; 439bc5531deSDag-Erling Smørgrav 440bc5531deSDag-Erling Smørgrav *kexp = NULL; 441bc5531deSDag-Erling Smørgrav if ((kex = calloc(1, sizeof(*kex))) == NULL) 442bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 443bc5531deSDag-Erling Smørgrav if ((kex->peer = sshbuf_new()) == NULL || 444bc5531deSDag-Erling Smørgrav (kex->my = sshbuf_new()) == NULL) { 445bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 446bc5531deSDag-Erling Smørgrav goto out; 447bc5531deSDag-Erling Smørgrav } 448bc5531deSDag-Erling Smørgrav if ((r = kex_prop2buf(kex->my, proposal)) != 0) 449bc5531deSDag-Erling Smørgrav goto out; 450bc5531deSDag-Erling Smørgrav kex->done = 0; 451bc5531deSDag-Erling Smørgrav kex_reset_dispatch(ssh); 452bc5531deSDag-Erling Smørgrav r = 0; 453bc5531deSDag-Erling Smørgrav *kexp = kex; 454bc5531deSDag-Erling Smørgrav out: 455bc5531deSDag-Erling Smørgrav if (r != 0) 456bc5531deSDag-Erling Smørgrav kex_free(kex); 457bc5531deSDag-Erling Smørgrav return r; 458bc5531deSDag-Erling Smørgrav } 459bc5531deSDag-Erling Smørgrav 460bc5531deSDag-Erling Smørgrav void 461bc5531deSDag-Erling Smørgrav kex_free_newkeys(struct newkeys *newkeys) 462bc5531deSDag-Erling Smørgrav { 463bc5531deSDag-Erling Smørgrav if (newkeys == NULL) 464bc5531deSDag-Erling Smørgrav return; 465bc5531deSDag-Erling Smørgrav if (newkeys->enc.key) { 466bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 467bc5531deSDag-Erling Smørgrav free(newkeys->enc.key); 468bc5531deSDag-Erling Smørgrav newkeys->enc.key = NULL; 469bc5531deSDag-Erling Smørgrav } 470bc5531deSDag-Erling Smørgrav if (newkeys->enc.iv) { 471bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size); 472bc5531deSDag-Erling Smørgrav free(newkeys->enc.iv); 473bc5531deSDag-Erling Smørgrav newkeys->enc.iv = NULL; 474bc5531deSDag-Erling Smørgrav } 475bc5531deSDag-Erling Smørgrav free(newkeys->enc.name); 476bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 477bc5531deSDag-Erling Smørgrav free(newkeys->comp.name); 478bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 479bc5531deSDag-Erling Smørgrav mac_clear(&newkeys->mac); 480bc5531deSDag-Erling Smørgrav if (newkeys->mac.key) { 481bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 482bc5531deSDag-Erling Smørgrav free(newkeys->mac.key); 483bc5531deSDag-Erling Smørgrav newkeys->mac.key = NULL; 484bc5531deSDag-Erling Smørgrav } 485bc5531deSDag-Erling Smørgrav free(newkeys->mac.name); 486bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 487bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys, sizeof(*newkeys)); 488bc5531deSDag-Erling Smørgrav free(newkeys); 489bc5531deSDag-Erling Smørgrav } 490bc5531deSDag-Erling Smørgrav 491bc5531deSDag-Erling Smørgrav void 492bc5531deSDag-Erling Smørgrav kex_free(struct kex *kex) 493bc5531deSDag-Erling Smørgrav { 494bc5531deSDag-Erling Smørgrav u_int mode; 495bc5531deSDag-Erling Smørgrav 496bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL 497bc5531deSDag-Erling Smørgrav if (kex->dh) 498bc5531deSDag-Erling Smørgrav DH_free(kex->dh); 499bc5531deSDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 500bc5531deSDag-Erling Smørgrav if (kex->ec_client_key) 501bc5531deSDag-Erling Smørgrav EC_KEY_free(kex->ec_client_key); 502bc5531deSDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 503bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 504bc5531deSDag-Erling Smørgrav for (mode = 0; mode < MODE_MAX; mode++) { 505bc5531deSDag-Erling Smørgrav kex_free_newkeys(kex->newkeys[mode]); 506bc5531deSDag-Erling Smørgrav kex->newkeys[mode] = NULL; 507bc5531deSDag-Erling Smørgrav } 508bc5531deSDag-Erling Smørgrav sshbuf_free(kex->peer); 509bc5531deSDag-Erling Smørgrav sshbuf_free(kex->my); 510bc5531deSDag-Erling Smørgrav free(kex->session_id); 511bc5531deSDag-Erling Smørgrav free(kex->client_version_string); 512bc5531deSDag-Erling Smørgrav free(kex->server_version_string); 513*eccfee6eSDag-Erling Smørgrav free(kex->failed_choice); 514bc5531deSDag-Erling Smørgrav free(kex); 515bc5531deSDag-Erling Smørgrav } 516bc5531deSDag-Erling Smørgrav 517bc5531deSDag-Erling Smørgrav int 518bc5531deSDag-Erling Smørgrav kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 519bc5531deSDag-Erling Smørgrav { 520bc5531deSDag-Erling Smørgrav int r; 521bc5531deSDag-Erling Smørgrav 522bc5531deSDag-Erling Smørgrav if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 523bc5531deSDag-Erling Smørgrav return r; 524bc5531deSDag-Erling Smørgrav if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 525bc5531deSDag-Erling Smørgrav kex_free(ssh->kex); 526bc5531deSDag-Erling Smørgrav ssh->kex = NULL; 527bc5531deSDag-Erling Smørgrav return r; 528bc5531deSDag-Erling Smørgrav } 529bc5531deSDag-Erling Smørgrav return 0; 530bc5531deSDag-Erling Smørgrav } 531bc5531deSDag-Erling Smørgrav 532bc5531deSDag-Erling Smørgrav static int 533bc5531deSDag-Erling Smørgrav choose_enc(struct sshenc *enc, char *client, char *server) 534a04a10f8SKris Kennaway { 5351e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 536bc5531deSDag-Erling Smørgrav 537a04a10f8SKris Kennaway if (name == NULL) 538bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_CIPHER_ALG_MATCH; 539ae1f160dSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) 540bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 541a04a10f8SKris Kennaway enc->name = name; 542a04a10f8SKris Kennaway enc->enabled = 0; 543a04a10f8SKris Kennaway enc->iv = NULL; 5446888a9beSDag-Erling Smørgrav enc->iv_len = cipher_ivlen(enc->cipher); 545a04a10f8SKris Kennaway enc->key = NULL; 546ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 547ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 548bc5531deSDag-Erling Smørgrav return 0; 549a04a10f8SKris Kennaway } 550761efaa7SDag-Erling Smørgrav 551bc5531deSDag-Erling Smørgrav static int 552bc5531deSDag-Erling Smørgrav choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 553a04a10f8SKris Kennaway { 5541e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 555bc5531deSDag-Erling Smørgrav 556a04a10f8SKris Kennaway if (name == NULL) 557bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_MAC_ALG_MATCH; 558d4af9e69SDag-Erling Smørgrav if (mac_setup(mac, name) < 0) 559bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 5601e8db6e2SBrian Feldman /* truncate the key */ 561bc5531deSDag-Erling Smørgrav if (ssh->compat & SSH_BUG_HMAC) 5621e8db6e2SBrian Feldman mac->key_len = 16; 563a04a10f8SKris Kennaway mac->name = name; 564a04a10f8SKris Kennaway mac->key = NULL; 565a04a10f8SKris Kennaway mac->enabled = 0; 566bc5531deSDag-Erling Smørgrav return 0; 567a04a10f8SKris Kennaway } 568761efaa7SDag-Erling Smørgrav 569bc5531deSDag-Erling Smørgrav static int 570bc5531deSDag-Erling Smørgrav choose_comp(struct sshcomp *comp, char *client, char *server) 571a04a10f8SKris Kennaway { 5721e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 573bc5531deSDag-Erling Smørgrav 574a04a10f8SKris Kennaway if (name == NULL) 575bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_COMPRESS_ALG_MATCH; 576043840dfSDag-Erling Smørgrav if (strcmp(name, "zlib@openssh.com") == 0) { 577043840dfSDag-Erling Smørgrav comp->type = COMP_DELAYED; 578043840dfSDag-Erling Smørgrav } else if (strcmp(name, "zlib") == 0) { 579043840dfSDag-Erling Smørgrav comp->type = COMP_ZLIB; 580a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 581043840dfSDag-Erling Smørgrav comp->type = COMP_NONE; 582a04a10f8SKris Kennaway } else { 583bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 584a04a10f8SKris Kennaway } 585a04a10f8SKris Kennaway comp->name = name; 586bc5531deSDag-Erling Smørgrav return 0; 587a04a10f8SKris Kennaway } 588761efaa7SDag-Erling Smørgrav 589bc5531deSDag-Erling Smørgrav static int 590bc5531deSDag-Erling Smørgrav choose_kex(struct kex *k, char *client, char *server) 591a04a10f8SKris Kennaway { 592e4a9863fSDag-Erling Smørgrav const struct kexalg *kexalg; 593e4a9863fSDag-Erling Smørgrav 5941e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 595bc5531deSDag-Erling Smørgrav 596a04a10f8SKris Kennaway if (k->name == NULL) 597bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_KEX_ALG_MATCH; 598e4a9863fSDag-Erling Smørgrav if ((kexalg = kex_alg_by_name(k->name)) == NULL) 599bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 600e4a9863fSDag-Erling Smørgrav k->kex_type = kexalg->type; 601f7167e0eSDag-Erling Smørgrav k->hash_alg = kexalg->hash_alg; 602e4a9863fSDag-Erling Smørgrav k->ec_nid = kexalg->ec_nid; 603bc5531deSDag-Erling Smørgrav return 0; 604a04a10f8SKris Kennaway } 605021d409fSDag-Erling Smørgrav 606bc5531deSDag-Erling Smørgrav static int 607bc5531deSDag-Erling Smørgrav choose_hostkeyalg(struct kex *k, char *client, char *server) 608a04a10f8SKris Kennaway { 6091e8db6e2SBrian Feldman char *hostkeyalg = match_list(client, server, NULL); 610bc5531deSDag-Erling Smørgrav 6111e8db6e2SBrian Feldman if (hostkeyalg == NULL) 612bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 613bc5531deSDag-Erling Smørgrav k->hostkey_type = sshkey_type_from_name(hostkeyalg); 6141e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 615bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 616bc5531deSDag-Erling Smørgrav k->hostkey_nid = sshkey_ecdsa_nid_from_name(hostkeyalg); 617e4a9863fSDag-Erling Smørgrav free(hostkeyalg); 618bc5531deSDag-Erling Smørgrav return 0; 619a04a10f8SKris Kennaway } 620a04a10f8SKris Kennaway 621d0c8c0bcSDag-Erling Smørgrav static int 622d0c8c0bcSDag-Erling Smørgrav proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 623d0c8c0bcSDag-Erling Smørgrav { 624d0c8c0bcSDag-Erling Smørgrav static int check[] = { 625d0c8c0bcSDag-Erling Smørgrav PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 626d0c8c0bcSDag-Erling Smørgrav }; 627d0c8c0bcSDag-Erling Smørgrav int *idx; 628d0c8c0bcSDag-Erling Smørgrav char *p; 629d0c8c0bcSDag-Erling Smørgrav 630d0c8c0bcSDag-Erling Smørgrav for (idx = &check[0]; *idx != -1; idx++) { 631d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(my[*idx], ',')) != NULL) 632d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 633d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(peer[*idx], ',')) != NULL) 634d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 635d0c8c0bcSDag-Erling Smørgrav if (strcmp(my[*idx], peer[*idx]) != 0) { 636d0c8c0bcSDag-Erling Smørgrav debug2("proposal mismatch: my %s peer %s", 637d0c8c0bcSDag-Erling Smørgrav my[*idx], peer[*idx]); 638d0c8c0bcSDag-Erling Smørgrav return (0); 639d0c8c0bcSDag-Erling Smørgrav } 640d0c8c0bcSDag-Erling Smørgrav } 641d0c8c0bcSDag-Erling Smørgrav debug2("proposals match"); 642d0c8c0bcSDag-Erling Smørgrav return (1); 643d0c8c0bcSDag-Erling Smørgrav } 644d0c8c0bcSDag-Erling Smørgrav 645bc5531deSDag-Erling Smørgrav static int 646bc5531deSDag-Erling Smørgrav kex_choose_conf(struct ssh *ssh) 647a04a10f8SKris Kennaway { 648bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 649bc5531deSDag-Erling Smørgrav struct newkeys *newkeys; 650bc5531deSDag-Erling Smørgrav char **my = NULL, **peer = NULL; 6511e8db6e2SBrian Feldman char **cprop, **sprop; 6521e8db6e2SBrian Feldman int nenc, nmac, ncomp; 653f7167e0eSDag-Erling Smørgrav u_int mode, ctos, need, dh_need, authlen; 654bc5531deSDag-Erling Smørgrav int r, first_kex_follows; 655a04a10f8SKris Kennaway 656bc5531deSDag-Erling Smørgrav if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || 657bc5531deSDag-Erling Smørgrav (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 658bc5531deSDag-Erling Smørgrav goto out; 659a04a10f8SKris Kennaway 6601e8db6e2SBrian Feldman if (kex->server) { 6611e8db6e2SBrian Feldman cprop=peer; 6621e8db6e2SBrian Feldman sprop=my; 6631e8db6e2SBrian Feldman } else { 6641e8db6e2SBrian Feldman cprop=my; 6651e8db6e2SBrian Feldman sprop=peer; 6661e8db6e2SBrian Feldman } 6671e8db6e2SBrian Feldman 668b15c8340SDag-Erling Smørgrav /* Check whether server offers roaming */ 669b15c8340SDag-Erling Smørgrav if (!kex->server) { 670bc5531deSDag-Erling Smørgrav char *roaming = match_list(KEX_RESUME, 671bc5531deSDag-Erling Smørgrav peer[PROPOSAL_KEX_ALGS], NULL); 672bc5531deSDag-Erling Smørgrav 673b15c8340SDag-Erling Smørgrav if (roaming) { 674b15c8340SDag-Erling Smørgrav kex->roaming = 1; 675e4a9863fSDag-Erling Smørgrav free(roaming); 676b15c8340SDag-Erling Smørgrav } 677b15c8340SDag-Erling Smørgrav } 678b15c8340SDag-Erling Smørgrav 6791e8db6e2SBrian Feldman /* Algorithm Negotiation */ 680a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 681bc5531deSDag-Erling Smørgrav if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 682bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 683bc5531deSDag-Erling Smørgrav goto out; 684bc5531deSDag-Erling Smørgrav } 6851e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 686d4af9e69SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 687d4af9e69SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 688a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 689a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 690a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 691bc5531deSDag-Erling Smørgrav if ((r = choose_enc(&newkeys->enc, cprop[nenc], 692*eccfee6eSDag-Erling Smørgrav sprop[nenc])) != 0) { 693*eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[nenc]; 694*eccfee6eSDag-Erling Smørgrav peer[nenc] = NULL; 695bc5531deSDag-Erling Smørgrav goto out; 696*eccfee6eSDag-Erling Smørgrav } 6976888a9beSDag-Erling Smørgrav authlen = cipher_authlen(newkeys->enc.cipher); 698bc5531deSDag-Erling Smørgrav /* ignore mac for authenticated encryption */ 699bc5531deSDag-Erling Smørgrav if (authlen == 0 && 700bc5531deSDag-Erling Smørgrav (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 701*eccfee6eSDag-Erling Smørgrav sprop[nmac])) != 0) { 702*eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[nmac]; 703*eccfee6eSDag-Erling Smørgrav peer[nmac] = NULL; 704bc5531deSDag-Erling Smørgrav goto out; 705*eccfee6eSDag-Erling Smørgrav } 706bc5531deSDag-Erling Smørgrav if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 707*eccfee6eSDag-Erling Smørgrav sprop[ncomp])) != 0) { 708*eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[ncomp]; 709*eccfee6eSDag-Erling Smørgrav peer[ncomp] = NULL; 710bc5531deSDag-Erling Smørgrav goto out; 711*eccfee6eSDag-Erling Smørgrav } 712a04a10f8SKris Kennaway debug("kex: %s %s %s %s", 713a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 7141e8db6e2SBrian Feldman newkeys->enc.name, 7156888a9beSDag-Erling Smørgrav authlen == 0 ? newkeys->mac.name : "<implicit>", 7161e8db6e2SBrian Feldman newkeys->comp.name); 717a04a10f8SKris Kennaway } 718bc5531deSDag-Erling Smørgrav if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 719*eccfee6eSDag-Erling Smørgrav sprop[PROPOSAL_KEX_ALGS])) != 0) { 720*eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; 721*eccfee6eSDag-Erling Smørgrav peer[PROPOSAL_KEX_ALGS] = NULL; 722bc5531deSDag-Erling Smørgrav goto out; 723*eccfee6eSDag-Erling Smørgrav } 724*eccfee6eSDag-Erling Smørgrav if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 725*eccfee6eSDag-Erling Smørgrav sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { 726*eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; 727*eccfee6eSDag-Erling Smørgrav peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; 728*eccfee6eSDag-Erling Smørgrav goto out; 729*eccfee6eSDag-Erling Smørgrav } 730f7167e0eSDag-Erling Smørgrav need = dh_need = 0; 731a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 7321e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 733f7167e0eSDag-Erling Smørgrav need = MAX(need, newkeys->enc.key_len); 734f7167e0eSDag-Erling Smørgrav need = MAX(need, newkeys->enc.block_size); 735f7167e0eSDag-Erling Smørgrav need = MAX(need, newkeys->enc.iv_len); 736f7167e0eSDag-Erling Smørgrav need = MAX(need, newkeys->mac.key_len); 737f7167e0eSDag-Erling Smørgrav dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher)); 738f7167e0eSDag-Erling Smørgrav dh_need = MAX(dh_need, newkeys->enc.block_size); 739f7167e0eSDag-Erling Smørgrav dh_need = MAX(dh_need, newkeys->enc.iv_len); 740f7167e0eSDag-Erling Smørgrav dh_need = MAX(dh_need, newkeys->mac.key_len); 741a04a10f8SKris Kennaway } 7422632b0c8SKris Kennaway /* XXX need runden? */ 7431e8db6e2SBrian Feldman kex->we_need = need; 744f7167e0eSDag-Erling Smørgrav kex->dh_need = dh_need; 7451e8db6e2SBrian Feldman 746d0c8c0bcSDag-Erling Smørgrav /* ignore the next message if the proposals do not match */ 747d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows && !proposals_match(my, peer) && 748bc5531deSDag-Erling Smørgrav !(ssh->compat & SSH_BUG_FIRSTKEX)) 749bc5531deSDag-Erling Smørgrav ssh->dispatch_skip_packets = 1; 750bc5531deSDag-Erling Smørgrav r = 0; 751bc5531deSDag-Erling Smørgrav out: 7521e8db6e2SBrian Feldman kex_prop_free(my); 7531e8db6e2SBrian Feldman kex_prop_free(peer); 754bc5531deSDag-Erling Smørgrav return r; 755a04a10f8SKris Kennaway } 756a04a10f8SKris Kennaway 757bc5531deSDag-Erling Smørgrav static int 758bc5531deSDag-Erling Smørgrav derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 759bc5531deSDag-Erling Smørgrav const struct sshbuf *shared_secret, u_char **keyp) 760a04a10f8SKris Kennaway { 761bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 762bc5531deSDag-Erling Smørgrav struct ssh_digest_ctx *hashctx = NULL; 7631e8db6e2SBrian Feldman char c = id; 764043840dfSDag-Erling Smørgrav u_int have; 765f7167e0eSDag-Erling Smørgrav size_t mdsz; 766043840dfSDag-Erling Smørgrav u_char *digest; 767bc5531deSDag-Erling Smørgrav int r; 768043840dfSDag-Erling Smørgrav 769f7167e0eSDag-Erling Smørgrav if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 770bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 771bc5531deSDag-Erling Smørgrav if ((digest = calloc(1, roundup(need, mdsz))) == NULL) { 772bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 773bc5531deSDag-Erling Smørgrav goto out; 774bc5531deSDag-Erling Smørgrav } 7751e8db6e2SBrian Feldman 7761e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 777bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 778bc5531deSDag-Erling Smørgrav ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 779f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, hash, hashlen) != 0 || 780f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, &c, 1) != 0 || 781f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, kex->session_id, 782bc5531deSDag-Erling Smørgrav kex->session_id_len) != 0 || 783bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, digest, mdsz) != 0) { 784bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 785bc5531deSDag-Erling Smørgrav goto out; 786bc5531deSDag-Erling Smørgrav } 787f7167e0eSDag-Erling Smørgrav ssh_digest_free(hashctx); 788bc5531deSDag-Erling Smørgrav hashctx = NULL; 7891e8db6e2SBrian Feldman 7901e8db6e2SBrian Feldman /* 7911e8db6e2SBrian Feldman * expand key: 7921e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 7931e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 7941e8db6e2SBrian Feldman */ 7951e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 796bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 797bc5531deSDag-Erling Smørgrav ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 798f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, hash, hashlen) != 0 || 799bc5531deSDag-Erling Smørgrav ssh_digest_update(hashctx, digest, have) != 0 || 800bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 801bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 802bc5531deSDag-Erling Smørgrav goto out; 8031e8db6e2SBrian Feldman } 804bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 805bc5531deSDag-Erling Smørgrav hashctx = NULL; 806bc5531deSDag-Erling Smørgrav } 8071e8db6e2SBrian Feldman #ifdef DEBUG_KEX 8081e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 8091e8db6e2SBrian Feldman dump_digest("key", digest, need); 8101e8db6e2SBrian Feldman #endif 811bc5531deSDag-Erling Smørgrav *keyp = digest; 812bc5531deSDag-Erling Smørgrav digest = NULL; 813bc5531deSDag-Erling Smørgrav r = 0; 814bc5531deSDag-Erling Smørgrav out: 815bc5531deSDag-Erling Smørgrav if (digest) 816bc5531deSDag-Erling Smørgrav free(digest); 817bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 818bc5531deSDag-Erling Smørgrav return r; 8191e8db6e2SBrian Feldman } 8201e8db6e2SBrian Feldman 8211e8db6e2SBrian Feldman #define NKEYS 6 822bc5531deSDag-Erling Smørgrav int 823bc5531deSDag-Erling Smørgrav kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 824bc5531deSDag-Erling Smørgrav const struct sshbuf *shared_secret) 8251e8db6e2SBrian Feldman { 826bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 8271e8db6e2SBrian Feldman u_char *keys[NKEYS]; 828bc5531deSDag-Erling Smørgrav u_int i, j, mode, ctos; 829bc5531deSDag-Erling Smørgrav int r; 830a04a10f8SKris Kennaway 831021d409fSDag-Erling Smørgrav for (i = 0; i < NKEYS; i++) { 832bc5531deSDag-Erling Smørgrav if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 833bc5531deSDag-Erling Smørgrav shared_secret, &keys[i])) != 0) { 834bc5531deSDag-Erling Smørgrav for (j = 0; j < i; j++) 835bc5531deSDag-Erling Smørgrav free(keys[j]); 836bc5531deSDag-Erling Smørgrav return r; 837021d409fSDag-Erling Smørgrav } 838bc5531deSDag-Erling Smørgrav } 839a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 840761efaa7SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 841761efaa7SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 842bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 843bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 844bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 845a04a10f8SKris Kennaway } 846bc5531deSDag-Erling Smørgrav return 0; 847a04a10f8SKris Kennaway } 8481e8db6e2SBrian Feldman 849a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 850bc5531deSDag-Erling Smørgrav int 851bc5531deSDag-Erling Smørgrav kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 852bc5531deSDag-Erling Smørgrav const BIGNUM *secret) 853f7167e0eSDag-Erling Smørgrav { 854bc5531deSDag-Erling Smørgrav struct sshbuf *shared_secret; 855bc5531deSDag-Erling Smørgrav int r; 856f7167e0eSDag-Erling Smørgrav 857bc5531deSDag-Erling Smørgrav if ((shared_secret = sshbuf_new()) == NULL) 858bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 859bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 860bc5531deSDag-Erling Smørgrav r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 861bc5531deSDag-Erling Smørgrav sshbuf_free(shared_secret); 862bc5531deSDag-Erling Smørgrav return r; 863f7167e0eSDag-Erling Smørgrav } 864a0ee8cc6SDag-Erling Smørgrav #endif 865f7167e0eSDag-Erling Smørgrav 866a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_SSH1 867bc5531deSDag-Erling Smørgrav int 868d74d50a8SDag-Erling Smørgrav derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 869d74d50a8SDag-Erling Smørgrav u_int8_t cookie[8], u_int8_t id[16]) 870d74d50a8SDag-Erling Smørgrav { 871bc5531deSDag-Erling Smørgrav u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; 872bc5531deSDag-Erling Smørgrav struct ssh_digest_ctx *hashctx = NULL; 873bc5531deSDag-Erling Smørgrav size_t hlen, slen; 874bc5531deSDag-Erling Smørgrav int r; 875d74d50a8SDag-Erling Smørgrav 876bc5531deSDag-Erling Smørgrav hlen = BN_num_bytes(host_modulus); 877bc5531deSDag-Erling Smørgrav slen = BN_num_bytes(server_modulus); 878bc5531deSDag-Erling Smørgrav if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || 879bc5531deSDag-Erling Smørgrav slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) 880bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_BITS_MISMATCH; 881bc5531deSDag-Erling Smørgrav if (BN_bn2bin(host_modulus, hbuf) <= 0 || 882bc5531deSDag-Erling Smørgrav BN_bn2bin(server_modulus, sbuf) <= 0) { 883bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 884bc5531deSDag-Erling Smørgrav goto out; 885bc5531deSDag-Erling Smørgrav } 886bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { 887bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 888bc5531deSDag-Erling Smørgrav goto out; 889bc5531deSDag-Erling Smørgrav } 890bc5531deSDag-Erling Smørgrav if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || 891bc5531deSDag-Erling Smørgrav ssh_digest_update(hashctx, sbuf, slen) != 0 || 892bc5531deSDag-Erling Smørgrav ssh_digest_update(hashctx, cookie, 8) != 0 || 893bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { 894bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 895bc5531deSDag-Erling Smørgrav goto out; 896bc5531deSDag-Erling Smørgrav } 897f7167e0eSDag-Erling Smørgrav memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); 898bc5531deSDag-Erling Smørgrav r = 0; 899bc5531deSDag-Erling Smørgrav out: 900bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 901bc5531deSDag-Erling Smørgrav explicit_bzero(hbuf, sizeof(hbuf)); 902bc5531deSDag-Erling Smørgrav explicit_bzero(sbuf, sizeof(sbuf)); 903b83788ffSDag-Erling Smørgrav explicit_bzero(obuf, sizeof(obuf)); 904bc5531deSDag-Erling Smørgrav return r; 905d74d50a8SDag-Erling Smørgrav } 906a0ee8cc6SDag-Erling Smørgrav #endif 907d74d50a8SDag-Erling Smørgrav 9084a421b63SDag-Erling Smørgrav #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 9091e8db6e2SBrian Feldman void 9101e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 9111e8db6e2SBrian Feldman { 9121e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 913bc5531deSDag-Erling Smørgrav sshbuf_dump_data(digest, len, stderr); 9141e8db6e2SBrian Feldman } 9151e8db6e2SBrian Feldman #endif 916