1*47dd1d1bSDag-Erling Smørgrav /* $OpenBSD: kex.c,v 1.136 2018/02/07 02:06:50 jsing 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 28761efaa7SDag-Erling Smørgrav 29761efaa7SDag-Erling Smørgrav #include <signal.h> 30761efaa7SDag-Erling Smørgrav #include <stdarg.h> 31761efaa7SDag-Erling Smørgrav #include <stdio.h> 32761efaa7SDag-Erling Smørgrav #include <stdlib.h> 33761efaa7SDag-Erling Smørgrav #include <string.h> 34a04a10f8SKris Kennaway 35a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 361e8db6e2SBrian Feldman #include <openssl/crypto.h> 37076ad2f8SDag-Erling Smørgrav #include <openssl/dh.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" 52bc5531deSDag-Erling Smørgrav 53bc5531deSDag-Erling Smørgrav #include "ssherr.h" 54bc5531deSDag-Erling Smørgrav #include "sshbuf.h" 55f7167e0eSDag-Erling Smørgrav #include "digest.h" 56a04a10f8SKris Kennaway 57ae1f160dSDag-Erling Smørgrav /* prototype */ 58bc5531deSDag-Erling Smørgrav static int kex_choose_conf(struct ssh *); 594f52dfbbSDag-Erling Smørgrav static int kex_input_newkeys(int, u_int32_t, struct ssh *); 601e8db6e2SBrian Feldman 61acc1a9efSDag-Erling Smørgrav static const char *proposal_names[PROPOSAL_MAX] = { 62acc1a9efSDag-Erling Smørgrav "KEX algorithms", 63acc1a9efSDag-Erling Smørgrav "host key algorithms", 64acc1a9efSDag-Erling Smørgrav "ciphers ctos", 65acc1a9efSDag-Erling Smørgrav "ciphers stoc", 66acc1a9efSDag-Erling Smørgrav "MACs ctos", 67acc1a9efSDag-Erling Smørgrav "MACs stoc", 68acc1a9efSDag-Erling Smørgrav "compression ctos", 69acc1a9efSDag-Erling Smørgrav "compression stoc", 70acc1a9efSDag-Erling Smørgrav "languages ctos", 71acc1a9efSDag-Erling Smørgrav "languages stoc", 72acc1a9efSDag-Erling Smørgrav }; 73acc1a9efSDag-Erling Smørgrav 74e4a9863fSDag-Erling Smørgrav struct kexalg { 75e4a9863fSDag-Erling Smørgrav char *name; 76bc5531deSDag-Erling Smørgrav u_int type; 77e4a9863fSDag-Erling Smørgrav int ec_nid; 78f7167e0eSDag-Erling Smørgrav int hash_alg; 79e4a9863fSDag-Erling Smørgrav }; 80e4a9863fSDag-Erling Smørgrav static const struct kexalg kexalgs[] = { 81a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 82f7167e0eSDag-Erling Smørgrav { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 83076ad2f8SDag-Erling Smørgrav { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 84076ad2f8SDag-Erling Smørgrav { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, 85076ad2f8SDag-Erling Smørgrav { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, 86076ad2f8SDag-Erling Smørgrav { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 }, 87f7167e0eSDag-Erling Smørgrav { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 88e4a9863fSDag-Erling Smørgrav #ifdef HAVE_EVP_SHA256 89f7167e0eSDag-Erling Smørgrav { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 90a0ee8cc6SDag-Erling Smørgrav #endif /* HAVE_EVP_SHA256 */ 91e4a9863fSDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 92f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 93f7167e0eSDag-Erling Smørgrav NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 94f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, 95f7167e0eSDag-Erling Smørgrav SSH_DIGEST_SHA384 }, 96f7167e0eSDag-Erling Smørgrav # ifdef OPENSSL_HAS_NISTP521 97f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 98f7167e0eSDag-Erling Smørgrav SSH_DIGEST_SHA512 }, 99a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_NISTP521 */ 100a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 101a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 102bc5531deSDag-Erling Smørgrav #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) 103f7167e0eSDag-Erling Smørgrav { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 104ca86bcf2SDag-Erling Smørgrav { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 105bc5531deSDag-Erling Smørgrav #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 106f7167e0eSDag-Erling Smørgrav { NULL, -1, -1, -1}, 107e4a9863fSDag-Erling Smørgrav }; 108e4a9863fSDag-Erling Smørgrav 109e4a9863fSDag-Erling Smørgrav char * 110f7167e0eSDag-Erling Smørgrav kex_alg_list(char sep) 111e4a9863fSDag-Erling Smørgrav { 112bc5531deSDag-Erling Smørgrav char *ret = NULL, *tmp; 113e4a9863fSDag-Erling Smørgrav size_t nlen, rlen = 0; 114e4a9863fSDag-Erling Smørgrav const struct kexalg *k; 115e4a9863fSDag-Erling Smørgrav 116e4a9863fSDag-Erling Smørgrav for (k = kexalgs; k->name != NULL; k++) { 117e4a9863fSDag-Erling Smørgrav if (ret != NULL) 118f7167e0eSDag-Erling Smørgrav ret[rlen++] = sep; 119e4a9863fSDag-Erling Smørgrav nlen = strlen(k->name); 120bc5531deSDag-Erling Smørgrav if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 121bc5531deSDag-Erling Smørgrav free(ret); 122bc5531deSDag-Erling Smørgrav return NULL; 123bc5531deSDag-Erling Smørgrav } 124bc5531deSDag-Erling Smørgrav ret = tmp; 125e4a9863fSDag-Erling Smørgrav memcpy(ret + rlen, k->name, nlen + 1); 126e4a9863fSDag-Erling Smørgrav rlen += nlen; 127e4a9863fSDag-Erling Smørgrav } 128e4a9863fSDag-Erling Smørgrav return ret; 129e4a9863fSDag-Erling Smørgrav } 130e4a9863fSDag-Erling Smørgrav 131e4a9863fSDag-Erling Smørgrav static const struct kexalg * 132e4a9863fSDag-Erling Smørgrav kex_alg_by_name(const char *name) 133e4a9863fSDag-Erling Smørgrav { 134e4a9863fSDag-Erling Smørgrav const struct kexalg *k; 135e4a9863fSDag-Erling Smørgrav 136e4a9863fSDag-Erling Smørgrav for (k = kexalgs; k->name != NULL; k++) { 137e4a9863fSDag-Erling Smørgrav if (strcmp(k->name, name) == 0) 138e4a9863fSDag-Erling Smørgrav return k; 139e4a9863fSDag-Erling Smørgrav } 140e4a9863fSDag-Erling Smørgrav return NULL; 141e4a9863fSDag-Erling Smørgrav } 142e4a9863fSDag-Erling Smørgrav 1434a421b63SDag-Erling Smørgrav /* Validate KEX method name list */ 1444a421b63SDag-Erling Smørgrav int 1454a421b63SDag-Erling Smørgrav kex_names_valid(const char *names) 1464a421b63SDag-Erling Smørgrav { 1474a421b63SDag-Erling Smørgrav char *s, *cp, *p; 1484a421b63SDag-Erling Smørgrav 1494a421b63SDag-Erling Smørgrav if (names == NULL || strcmp(names, "") == 0) 1504a421b63SDag-Erling Smørgrav return 0; 151bc5531deSDag-Erling Smørgrav if ((s = cp = strdup(names)) == NULL) 152bc5531deSDag-Erling Smørgrav return 0; 1534a421b63SDag-Erling Smørgrav for ((p = strsep(&cp, ",")); p && *p != '\0'; 1544a421b63SDag-Erling Smørgrav (p = strsep(&cp, ","))) { 155e4a9863fSDag-Erling Smørgrav if (kex_alg_by_name(p) == NULL) { 1564a421b63SDag-Erling Smørgrav error("Unsupported KEX algorithm \"%.100s\"", p); 157e4a9863fSDag-Erling Smørgrav free(s); 1584a421b63SDag-Erling Smørgrav return 0; 1594a421b63SDag-Erling Smørgrav } 1604a421b63SDag-Erling Smørgrav } 1614a421b63SDag-Erling Smørgrav debug3("kex names ok: [%s]", names); 162e4a9863fSDag-Erling Smørgrav free(s); 1634a421b63SDag-Erling Smørgrav return 1; 1644a421b63SDag-Erling Smørgrav } 1654a421b63SDag-Erling Smørgrav 166eccfee6eSDag-Erling Smørgrav /* 167eccfee6eSDag-Erling Smørgrav * Concatenate algorithm names, avoiding duplicates in the process. 168eccfee6eSDag-Erling Smørgrav * Caller must free returned string. 169eccfee6eSDag-Erling Smørgrav */ 170eccfee6eSDag-Erling Smørgrav char * 171eccfee6eSDag-Erling Smørgrav kex_names_cat(const char *a, const char *b) 172eccfee6eSDag-Erling Smørgrav { 173d93a896eSDag-Erling Smørgrav char *ret = NULL, *tmp = NULL, *cp, *p, *m; 174eccfee6eSDag-Erling Smørgrav size_t len; 175eccfee6eSDag-Erling Smørgrav 176eccfee6eSDag-Erling Smørgrav if (a == NULL || *a == '\0') 177eccfee6eSDag-Erling Smørgrav return NULL; 178eccfee6eSDag-Erling Smørgrav if (b == NULL || *b == '\0') 179eccfee6eSDag-Erling Smørgrav return strdup(a); 180eccfee6eSDag-Erling Smørgrav if (strlen(b) > 1024*1024) 181eccfee6eSDag-Erling Smørgrav return NULL; 182eccfee6eSDag-Erling Smørgrav len = strlen(a) + strlen(b) + 2; 183eccfee6eSDag-Erling Smørgrav if ((tmp = cp = strdup(b)) == NULL || 184eccfee6eSDag-Erling Smørgrav (ret = calloc(1, len)) == NULL) { 185eccfee6eSDag-Erling Smørgrav free(tmp); 186eccfee6eSDag-Erling Smørgrav return NULL; 187eccfee6eSDag-Erling Smørgrav } 188eccfee6eSDag-Erling Smørgrav strlcpy(ret, a, len); 189eccfee6eSDag-Erling Smørgrav for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { 190d93a896eSDag-Erling Smørgrav if ((m = match_list(ret, p, NULL)) != NULL) { 191d93a896eSDag-Erling Smørgrav free(m); 192eccfee6eSDag-Erling Smørgrav continue; /* Algorithm already present */ 193d93a896eSDag-Erling Smørgrav } 194eccfee6eSDag-Erling Smørgrav if (strlcat(ret, ",", len) >= len || 195eccfee6eSDag-Erling Smørgrav strlcat(ret, p, len) >= len) { 196eccfee6eSDag-Erling Smørgrav free(tmp); 197eccfee6eSDag-Erling Smørgrav free(ret); 198eccfee6eSDag-Erling Smørgrav return NULL; /* Shouldn't happen */ 199eccfee6eSDag-Erling Smørgrav } 200eccfee6eSDag-Erling Smørgrav } 201eccfee6eSDag-Erling Smørgrav free(tmp); 202eccfee6eSDag-Erling Smørgrav return ret; 203eccfee6eSDag-Erling Smørgrav } 204eccfee6eSDag-Erling Smørgrav 205eccfee6eSDag-Erling Smørgrav /* 206eccfee6eSDag-Erling Smørgrav * Assemble a list of algorithms from a default list and a string from a 207eccfee6eSDag-Erling Smørgrav * configuration file. The user-provided string may begin with '+' to 208d93a896eSDag-Erling Smørgrav * indicate that it should be appended to the default or '-' that the 209d93a896eSDag-Erling Smørgrav * specified names should be removed. 210eccfee6eSDag-Erling Smørgrav */ 211eccfee6eSDag-Erling Smørgrav int 212eccfee6eSDag-Erling Smørgrav kex_assemble_names(const char *def, char **list) 213eccfee6eSDag-Erling Smørgrav { 214eccfee6eSDag-Erling Smørgrav char *ret; 215eccfee6eSDag-Erling Smørgrav 216eccfee6eSDag-Erling Smørgrav if (list == NULL || *list == NULL || **list == '\0') { 217eccfee6eSDag-Erling Smørgrav *list = strdup(def); 218eccfee6eSDag-Erling Smørgrav return 0; 219eccfee6eSDag-Erling Smørgrav } 220d93a896eSDag-Erling Smørgrav if (**list == '+') { 221eccfee6eSDag-Erling Smørgrav if ((ret = kex_names_cat(def, *list + 1)) == NULL) 222eccfee6eSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 223eccfee6eSDag-Erling Smørgrav free(*list); 224eccfee6eSDag-Erling Smørgrav *list = ret; 225d93a896eSDag-Erling Smørgrav } else if (**list == '-') { 226d93a896eSDag-Erling Smørgrav if ((ret = match_filter_list(def, *list + 1)) == NULL) 227d93a896eSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 228d93a896eSDag-Erling Smørgrav free(*list); 229d93a896eSDag-Erling Smørgrav *list = ret; 230d93a896eSDag-Erling Smørgrav } 231d93a896eSDag-Erling Smørgrav 232eccfee6eSDag-Erling Smørgrav return 0; 233eccfee6eSDag-Erling Smørgrav } 234eccfee6eSDag-Erling Smørgrav 2351765946bSDag-Erling Smørgrav /* put algorithm proposal into buffer */ 236bc5531deSDag-Erling Smørgrav int 237bc5531deSDag-Erling Smørgrav kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 238a04a10f8SKris Kennaway { 239043840dfSDag-Erling Smørgrav u_int i; 240bc5531deSDag-Erling Smørgrav int r; 2411e8db6e2SBrian Feldman 242bc5531deSDag-Erling Smørgrav sshbuf_reset(b); 243bc5531deSDag-Erling Smørgrav 244545d5ecaSDag-Erling Smørgrav /* 245545d5ecaSDag-Erling Smørgrav * add a dummy cookie, the cookie will be overwritten by 246545d5ecaSDag-Erling Smørgrav * kex_send_kexinit(), each time a kexinit is set 247545d5ecaSDag-Erling Smørgrav */ 248bc5531deSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) { 249bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(b, 0)) != 0) 250bc5531deSDag-Erling Smørgrav return r; 251bc5531deSDag-Erling Smørgrav } 252bc5531deSDag-Erling Smørgrav for (i = 0; i < PROPOSAL_MAX; i++) { 253bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 254bc5531deSDag-Erling Smørgrav return r; 255bc5531deSDag-Erling Smørgrav } 256bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 257bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 258bc5531deSDag-Erling Smørgrav return r; 259bc5531deSDag-Erling Smørgrav return 0; 260a04a10f8SKris Kennaway } 261a04a10f8SKris Kennaway 2621e8db6e2SBrian Feldman /* parse buffer and return algorithm proposal */ 263bc5531deSDag-Erling Smørgrav int 264bc5531deSDag-Erling Smørgrav kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 2652632b0c8SKris Kennaway { 266bc5531deSDag-Erling Smørgrav struct sshbuf *b = NULL; 267bc5531deSDag-Erling Smørgrav u_char v; 268d4af9e69SDag-Erling Smørgrav u_int i; 269bc5531deSDag-Erling Smørgrav char **proposal = NULL; 270bc5531deSDag-Erling Smørgrav int r; 2712632b0c8SKris Kennaway 272bc5531deSDag-Erling Smørgrav *propp = NULL; 273bc5531deSDag-Erling Smørgrav if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 274bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 275bc5531deSDag-Erling Smørgrav if ((b = sshbuf_fromb(raw)) == NULL) { 276bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 277bc5531deSDag-Erling Smørgrav goto out; 278bc5531deSDag-Erling Smørgrav } 279bc5531deSDag-Erling Smørgrav if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 280bc5531deSDag-Erling Smørgrav goto out; 2812632b0c8SKris Kennaway /* extract kex init proposal strings */ 2822632b0c8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) { 283bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 284bc5531deSDag-Erling Smørgrav goto out; 285acc1a9efSDag-Erling Smørgrav debug2("%s: %s", proposal_names[i], proposal[i]); 2862632b0c8SKris Kennaway } 2871e8db6e2SBrian Feldman /* first kex follows / reserved */ 288fc1ba28aSDag-Erling Smørgrav if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ 289fc1ba28aSDag-Erling Smørgrav (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ 290bc5531deSDag-Erling Smørgrav goto out; 291d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows != NULL) 292fc1ba28aSDag-Erling Smørgrav *first_kex_follows = v; 293fc1ba28aSDag-Erling Smørgrav debug2("first_kex_follows %d ", v); 294fc1ba28aSDag-Erling Smørgrav debug2("reserved %u ", i); 295bc5531deSDag-Erling Smørgrav r = 0; 296bc5531deSDag-Erling Smørgrav *propp = proposal; 297bc5531deSDag-Erling Smørgrav out: 298bc5531deSDag-Erling Smørgrav if (r != 0 && proposal != NULL) 299bc5531deSDag-Erling Smørgrav kex_prop_free(proposal); 300bc5531deSDag-Erling Smørgrav sshbuf_free(b); 301bc5531deSDag-Erling Smørgrav return r; 3025b9b2fafSBrian Feldman } 3035b9b2fafSBrian Feldman 304bc5531deSDag-Erling Smørgrav void 3051e8db6e2SBrian Feldman kex_prop_free(char **proposal) 306a04a10f8SKris Kennaway { 307043840dfSDag-Erling Smørgrav u_int i; 3081e8db6e2SBrian Feldman 309557f75e5SDag-Erling Smørgrav if (proposal == NULL) 310557f75e5SDag-Erling Smørgrav return; 3111e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 312e4a9863fSDag-Erling Smørgrav free(proposal[i]); 313e4a9863fSDag-Erling Smørgrav free(proposal); 314a04a10f8SKris Kennaway } 315a04a10f8SKris Kennaway 316d4af9e69SDag-Erling Smørgrav /* ARGSUSED */ 317bc5531deSDag-Erling Smørgrav static int 3184f52dfbbSDag-Erling Smørgrav kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh) 319a04a10f8SKris Kennaway { 320acc1a9efSDag-Erling Smørgrav int r; 321acc1a9efSDag-Erling Smørgrav 322acc1a9efSDag-Erling Smørgrav error("kex protocol error: type %d seq %u", type, seq); 323acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || 324acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, seq)) != 0 || 325acc1a9efSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 326acc1a9efSDag-Erling Smørgrav return r; 327bc5531deSDag-Erling Smørgrav return 0; 328a04a10f8SKris Kennaway } 329a04a10f8SKris Kennaway 330ae1f160dSDag-Erling Smørgrav static void 331bc5531deSDag-Erling Smørgrav kex_reset_dispatch(struct ssh *ssh) 3325b9b2fafSBrian Feldman { 333bc5531deSDag-Erling Smørgrav ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 334ae1f160dSDag-Erling Smørgrav SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 3355b9b2fafSBrian Feldman } 3365b9b2fafSBrian Feldman 337acc1a9efSDag-Erling Smørgrav static int 338acc1a9efSDag-Erling Smørgrav kex_send_ext_info(struct ssh *ssh) 339acc1a9efSDag-Erling Smørgrav { 340acc1a9efSDag-Erling Smørgrav int r; 341ca86bcf2SDag-Erling Smørgrav char *algs; 342acc1a9efSDag-Erling Smørgrav 343d93a896eSDag-Erling Smørgrav if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) 344ca86bcf2SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 345acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || 346acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, 1)) != 0 || 347acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || 348ca86bcf2SDag-Erling Smørgrav (r = sshpkt_put_cstring(ssh, algs)) != 0 || 349acc1a9efSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 350ca86bcf2SDag-Erling Smørgrav goto out; 351ca86bcf2SDag-Erling Smørgrav /* success */ 352ca86bcf2SDag-Erling Smørgrav r = 0; 353ca86bcf2SDag-Erling Smørgrav out: 354ca86bcf2SDag-Erling Smørgrav free(algs); 355acc1a9efSDag-Erling Smørgrav return r; 356acc1a9efSDag-Erling Smørgrav } 357acc1a9efSDag-Erling Smørgrav 358bc5531deSDag-Erling Smørgrav int 359bc5531deSDag-Erling Smørgrav kex_send_newkeys(struct ssh *ssh) 360a04a10f8SKris Kennaway { 361bc5531deSDag-Erling Smørgrav int r; 362a04a10f8SKris Kennaway 363bc5531deSDag-Erling Smørgrav kex_reset_dispatch(ssh); 364bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 365bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 366bc5531deSDag-Erling Smørgrav return r; 3671e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS sent"); 368d0c8c0bcSDag-Erling Smørgrav debug("expecting SSH2_MSG_NEWKEYS"); 369bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 370acc1a9efSDag-Erling Smørgrav if (ssh->kex->ext_info_c) 371acc1a9efSDag-Erling Smørgrav if ((r = kex_send_ext_info(ssh)) != 0) 372acc1a9efSDag-Erling Smørgrav return r; 373bc5531deSDag-Erling Smørgrav return 0; 374bc5531deSDag-Erling Smørgrav } 3751e8db6e2SBrian Feldman 376acc1a9efSDag-Erling Smørgrav int 3774f52dfbbSDag-Erling Smørgrav kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh) 378acc1a9efSDag-Erling Smørgrav { 379acc1a9efSDag-Erling Smørgrav struct kex *kex = ssh->kex; 380acc1a9efSDag-Erling Smørgrav u_int32_t i, ninfo; 3814f52dfbbSDag-Erling Smørgrav char *name, *found; 3824f52dfbbSDag-Erling Smørgrav u_char *val; 3834f52dfbbSDag-Erling Smørgrav size_t vlen; 384acc1a9efSDag-Erling Smørgrav int r; 385acc1a9efSDag-Erling Smørgrav 386acc1a9efSDag-Erling Smørgrav debug("SSH2_MSG_EXT_INFO received"); 387acc1a9efSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); 388acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) 389acc1a9efSDag-Erling Smørgrav return r; 390acc1a9efSDag-Erling Smørgrav for (i = 0; i < ninfo; i++) { 391acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) 392acc1a9efSDag-Erling Smørgrav return r; 3934f52dfbbSDag-Erling Smørgrav if ((r = sshpkt_get_string(ssh, &val, &vlen)) != 0) { 394acc1a9efSDag-Erling Smørgrav free(name); 395acc1a9efSDag-Erling Smørgrav return r; 396acc1a9efSDag-Erling Smørgrav } 397acc1a9efSDag-Erling Smørgrav if (strcmp(name, "server-sig-algs") == 0) { 3984f52dfbbSDag-Erling Smørgrav /* Ensure no \0 lurking in value */ 3994f52dfbbSDag-Erling Smørgrav if (memchr(val, '\0', vlen) != NULL) { 4004f52dfbbSDag-Erling Smørgrav error("%s: nul byte in %s", __func__, name); 4014f52dfbbSDag-Erling Smørgrav return SSH_ERR_INVALID_FORMAT; 4024f52dfbbSDag-Erling Smørgrav } 4034f52dfbbSDag-Erling Smørgrav debug("%s: %s=<%s>", __func__, name, val); 404acc1a9efSDag-Erling Smørgrav found = match_list("rsa-sha2-256", val, NULL); 405acc1a9efSDag-Erling Smørgrav if (found) { 406acc1a9efSDag-Erling Smørgrav kex->rsa_sha2 = 256; 407acc1a9efSDag-Erling Smørgrav free(found); 408acc1a9efSDag-Erling Smørgrav } 409acc1a9efSDag-Erling Smørgrav found = match_list("rsa-sha2-512", val, NULL); 410acc1a9efSDag-Erling Smørgrav if (found) { 411acc1a9efSDag-Erling Smørgrav kex->rsa_sha2 = 512; 412acc1a9efSDag-Erling Smørgrav free(found); 413acc1a9efSDag-Erling Smørgrav } 4144f52dfbbSDag-Erling Smørgrav } else 4154f52dfbbSDag-Erling Smørgrav debug("%s: %s (unrecognised)", __func__, name); 416acc1a9efSDag-Erling Smørgrav free(name); 417acc1a9efSDag-Erling Smørgrav free(val); 418acc1a9efSDag-Erling Smørgrav } 419acc1a9efSDag-Erling Smørgrav return sshpkt_get_end(ssh); 420acc1a9efSDag-Erling Smørgrav } 421acc1a9efSDag-Erling Smørgrav 422bc5531deSDag-Erling Smørgrav static int 4234f52dfbbSDag-Erling Smørgrav kex_input_newkeys(int type, u_int32_t seq, struct ssh *ssh) 424bc5531deSDag-Erling Smørgrav { 425bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 426bc5531deSDag-Erling Smørgrav int r; 427bc5531deSDag-Erling Smørgrav 428bc5531deSDag-Erling Smørgrav debug("SSH2_MSG_NEWKEYS received"); 429bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 430d93a896eSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 431bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_end(ssh)) != 0) 432bc5531deSDag-Erling Smørgrav return r; 433ca86bcf2SDag-Erling Smørgrav if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0) 434ca86bcf2SDag-Erling Smørgrav return r; 4351e8db6e2SBrian Feldman kex->done = 1; 436bc5531deSDag-Erling Smørgrav sshbuf_reset(kex->peer); 437bc5531deSDag-Erling Smørgrav /* sshbuf_reset(kex->my); */ 4381e8db6e2SBrian Feldman kex->flags &= ~KEX_INIT_SENT; 439e4a9863fSDag-Erling Smørgrav free(kex->name); 4401e8db6e2SBrian Feldman kex->name = NULL; 441bc5531deSDag-Erling Smørgrav return 0; 442a04a10f8SKris Kennaway } 443a04a10f8SKris Kennaway 444bc5531deSDag-Erling Smørgrav int 445bc5531deSDag-Erling Smørgrav kex_send_kexinit(struct ssh *ssh) 446a04a10f8SKris Kennaway { 447545d5ecaSDag-Erling Smørgrav u_char *cookie; 448bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 449bc5531deSDag-Erling Smørgrav int r; 450545d5ecaSDag-Erling Smørgrav 451bc5531deSDag-Erling Smørgrav if (kex == NULL) 452bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 453bc5531deSDag-Erling Smørgrav if (kex->flags & KEX_INIT_SENT) 454bc5531deSDag-Erling Smørgrav return 0; 4551e8db6e2SBrian Feldman kex->done = 0; 456545d5ecaSDag-Erling Smørgrav 457545d5ecaSDag-Erling Smørgrav /* generate a random cookie */ 458bc5531deSDag-Erling Smørgrav if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 459bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_FORMAT; 460bc5531deSDag-Erling Smørgrav if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 461bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 462bc5531deSDag-Erling Smørgrav arc4random_buf(cookie, KEX_COOKIE_LEN); 463bc5531deSDag-Erling Smørgrav 464bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 465bc5531deSDag-Erling Smørgrav (r = sshpkt_putb(ssh, kex->my)) != 0 || 466bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 467bc5531deSDag-Erling Smørgrav return r; 4681e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT sent"); 4691e8db6e2SBrian Feldman kex->flags |= KEX_INIT_SENT; 470bc5531deSDag-Erling Smørgrav return 0; 4711e8db6e2SBrian Feldman } 472a04a10f8SKris Kennaway 473d4af9e69SDag-Erling Smørgrav /* ARGSUSED */ 474bc5531deSDag-Erling Smørgrav int 4754f52dfbbSDag-Erling Smørgrav kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) 4761e8db6e2SBrian Feldman { 477bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 478bc5531deSDag-Erling Smørgrav const u_char *ptr; 479bc5531deSDag-Erling Smørgrav u_int i; 480bc5531deSDag-Erling Smørgrav size_t dlen; 481bc5531deSDag-Erling Smørgrav int r; 4822632b0c8SKris Kennaway 4831e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 4841e8db6e2SBrian Feldman if (kex == NULL) 485bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 4861e8db6e2SBrian Feldman 487ca86bcf2SDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); 488bc5531deSDag-Erling Smørgrav ptr = sshpkt_ptr(ssh, &dlen); 489bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 490bc5531deSDag-Erling Smørgrav return r; 4911e8db6e2SBrian Feldman 4921e8db6e2SBrian Feldman /* discard packet */ 4931e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 494bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 495bc5531deSDag-Erling Smørgrav return r; 4961e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 497bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 498bc5531deSDag-Erling Smørgrav return r; 4996888a9beSDag-Erling Smørgrav /* 5006888a9beSDag-Erling Smørgrav * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 5016888a9beSDag-Erling Smørgrav * KEX method has the server move first, but a server might be using 5026888a9beSDag-Erling Smørgrav * a custom method or one that we otherwise don't support. We should 5036888a9beSDag-Erling Smørgrav * be prepared to remember first_kex_follows here so we can eat a 5046888a9beSDag-Erling Smørgrav * packet later. 5056888a9beSDag-Erling Smørgrav * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 5066888a9beSDag-Erling Smørgrav * for cases where the server *doesn't* go first. I guess we should 5076888a9beSDag-Erling Smørgrav * ignore it when it is set for these cases, which is what we do now. 5086888a9beSDag-Erling Smørgrav */ 509bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 510bc5531deSDag-Erling Smørgrav (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 511bc5531deSDag-Erling Smørgrav (r = sshpkt_get_end(ssh)) != 0) 512bc5531deSDag-Erling Smørgrav return r; 5131e8db6e2SBrian Feldman 5141e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 515bc5531deSDag-Erling Smørgrav if ((r = kex_send_kexinit(ssh)) != 0) 516bc5531deSDag-Erling Smørgrav return r; 517bc5531deSDag-Erling Smørgrav if ((r = kex_choose_conf(ssh)) != 0) 518bc5531deSDag-Erling Smørgrav return r; 5191e8db6e2SBrian Feldman 520bc5531deSDag-Erling Smørgrav if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 521bc5531deSDag-Erling Smørgrav return (kex->kex[kex->kex_type])(ssh); 5221e8db6e2SBrian Feldman 523bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 5241e8db6e2SBrian Feldman } 525a04a10f8SKris Kennaway 526bc5531deSDag-Erling Smørgrav int 527bc5531deSDag-Erling Smørgrav kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 528bc5531deSDag-Erling Smørgrav { 529bc5531deSDag-Erling Smørgrav struct kex *kex; 530bc5531deSDag-Erling Smørgrav int r; 531bc5531deSDag-Erling Smørgrav 532bc5531deSDag-Erling Smørgrav *kexp = NULL; 533bc5531deSDag-Erling Smørgrav if ((kex = calloc(1, sizeof(*kex))) == NULL) 534bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 535bc5531deSDag-Erling Smørgrav if ((kex->peer = sshbuf_new()) == NULL || 536bc5531deSDag-Erling Smørgrav (kex->my = sshbuf_new()) == NULL) { 537bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 538bc5531deSDag-Erling Smørgrav goto out; 539bc5531deSDag-Erling Smørgrav } 540bc5531deSDag-Erling Smørgrav if ((r = kex_prop2buf(kex->my, proposal)) != 0) 541bc5531deSDag-Erling Smørgrav goto out; 542bc5531deSDag-Erling Smørgrav kex->done = 0; 543bc5531deSDag-Erling Smørgrav kex_reset_dispatch(ssh); 544d93a896eSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 545bc5531deSDag-Erling Smørgrav r = 0; 546bc5531deSDag-Erling Smørgrav *kexp = kex; 547bc5531deSDag-Erling Smørgrav out: 548bc5531deSDag-Erling Smørgrav if (r != 0) 549bc5531deSDag-Erling Smørgrav kex_free(kex); 550bc5531deSDag-Erling Smørgrav return r; 551bc5531deSDag-Erling Smørgrav } 552bc5531deSDag-Erling Smørgrav 553bc5531deSDag-Erling Smørgrav void 554bc5531deSDag-Erling Smørgrav kex_free_newkeys(struct newkeys *newkeys) 555bc5531deSDag-Erling Smørgrav { 556bc5531deSDag-Erling Smørgrav if (newkeys == NULL) 557bc5531deSDag-Erling Smørgrav return; 558bc5531deSDag-Erling Smørgrav if (newkeys->enc.key) { 559bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 560bc5531deSDag-Erling Smørgrav free(newkeys->enc.key); 561bc5531deSDag-Erling Smørgrav newkeys->enc.key = NULL; 562bc5531deSDag-Erling Smørgrav } 563bc5531deSDag-Erling Smørgrav if (newkeys->enc.iv) { 564acc1a9efSDag-Erling Smørgrav explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len); 565bc5531deSDag-Erling Smørgrav free(newkeys->enc.iv); 566bc5531deSDag-Erling Smørgrav newkeys->enc.iv = NULL; 567bc5531deSDag-Erling Smørgrav } 568bc5531deSDag-Erling Smørgrav free(newkeys->enc.name); 569bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 570bc5531deSDag-Erling Smørgrav free(newkeys->comp.name); 571bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 572bc5531deSDag-Erling Smørgrav mac_clear(&newkeys->mac); 573bc5531deSDag-Erling Smørgrav if (newkeys->mac.key) { 574bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 575bc5531deSDag-Erling Smørgrav free(newkeys->mac.key); 576bc5531deSDag-Erling Smørgrav newkeys->mac.key = NULL; 577bc5531deSDag-Erling Smørgrav } 578bc5531deSDag-Erling Smørgrav free(newkeys->mac.name); 579bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 580bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys, sizeof(*newkeys)); 581bc5531deSDag-Erling Smørgrav free(newkeys); 582bc5531deSDag-Erling Smørgrav } 583bc5531deSDag-Erling Smørgrav 584bc5531deSDag-Erling Smørgrav void 585bc5531deSDag-Erling Smørgrav kex_free(struct kex *kex) 586bc5531deSDag-Erling Smørgrav { 587bc5531deSDag-Erling Smørgrav u_int mode; 588bc5531deSDag-Erling Smørgrav 589bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL 590bc5531deSDag-Erling Smørgrav DH_free(kex->dh); 591bc5531deSDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 592bc5531deSDag-Erling Smørgrav EC_KEY_free(kex->ec_client_key); 593bc5531deSDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 594bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 595bc5531deSDag-Erling Smørgrav for (mode = 0; mode < MODE_MAX; mode++) { 596bc5531deSDag-Erling Smørgrav kex_free_newkeys(kex->newkeys[mode]); 597bc5531deSDag-Erling Smørgrav kex->newkeys[mode] = NULL; 598bc5531deSDag-Erling Smørgrav } 599bc5531deSDag-Erling Smørgrav sshbuf_free(kex->peer); 600bc5531deSDag-Erling Smørgrav sshbuf_free(kex->my); 601bc5531deSDag-Erling Smørgrav free(kex->session_id); 602bc5531deSDag-Erling Smørgrav free(kex->client_version_string); 603bc5531deSDag-Erling Smørgrav free(kex->server_version_string); 604eccfee6eSDag-Erling Smørgrav free(kex->failed_choice); 605acc1a9efSDag-Erling Smørgrav free(kex->hostkey_alg); 606acc1a9efSDag-Erling Smørgrav free(kex->name); 607bc5531deSDag-Erling Smørgrav free(kex); 608bc5531deSDag-Erling Smørgrav } 609bc5531deSDag-Erling Smørgrav 610bc5531deSDag-Erling Smørgrav int 611bc5531deSDag-Erling Smørgrav kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 612bc5531deSDag-Erling Smørgrav { 613bc5531deSDag-Erling Smørgrav int r; 614bc5531deSDag-Erling Smørgrav 615bc5531deSDag-Erling Smørgrav if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 616bc5531deSDag-Erling Smørgrav return r; 617bc5531deSDag-Erling Smørgrav if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 618bc5531deSDag-Erling Smørgrav kex_free(ssh->kex); 619bc5531deSDag-Erling Smørgrav ssh->kex = NULL; 620bc5531deSDag-Erling Smørgrav return r; 621bc5531deSDag-Erling Smørgrav } 622bc5531deSDag-Erling Smørgrav return 0; 623bc5531deSDag-Erling Smørgrav } 624bc5531deSDag-Erling Smørgrav 625acc1a9efSDag-Erling Smørgrav /* 626acc1a9efSDag-Erling Smørgrav * Request key re-exchange, returns 0 on success or a ssherr.h error 627acc1a9efSDag-Erling Smørgrav * code otherwise. Must not be called if KEX is incomplete or in-progress. 628acc1a9efSDag-Erling Smørgrav */ 629acc1a9efSDag-Erling Smørgrav int 630acc1a9efSDag-Erling Smørgrav kex_start_rekex(struct ssh *ssh) 631acc1a9efSDag-Erling Smørgrav { 632acc1a9efSDag-Erling Smørgrav if (ssh->kex == NULL) { 633acc1a9efSDag-Erling Smørgrav error("%s: no kex", __func__); 634acc1a9efSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 635acc1a9efSDag-Erling Smørgrav } 636acc1a9efSDag-Erling Smørgrav if (ssh->kex->done == 0) { 637acc1a9efSDag-Erling Smørgrav error("%s: requested twice", __func__); 638acc1a9efSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 639acc1a9efSDag-Erling Smørgrav } 640acc1a9efSDag-Erling Smørgrav ssh->kex->done = 0; 641acc1a9efSDag-Erling Smørgrav return kex_send_kexinit(ssh); 642acc1a9efSDag-Erling Smørgrav } 643acc1a9efSDag-Erling Smørgrav 644bc5531deSDag-Erling Smørgrav static int 645bc5531deSDag-Erling Smørgrav choose_enc(struct sshenc *enc, char *client, char *server) 646a04a10f8SKris Kennaway { 6471e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 648bc5531deSDag-Erling Smørgrav 649a04a10f8SKris Kennaway if (name == NULL) 650bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_CIPHER_ALG_MATCH; 651d93a896eSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) { 652d93a896eSDag-Erling Smørgrav free(name); 653bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 654d93a896eSDag-Erling Smørgrav } 655a04a10f8SKris Kennaway enc->name = name; 656a04a10f8SKris Kennaway enc->enabled = 0; 657a04a10f8SKris Kennaway enc->iv = NULL; 6586888a9beSDag-Erling Smørgrav enc->iv_len = cipher_ivlen(enc->cipher); 659a04a10f8SKris Kennaway enc->key = NULL; 660ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 661ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 662bc5531deSDag-Erling Smørgrav return 0; 663a04a10f8SKris Kennaway } 664761efaa7SDag-Erling Smørgrav 665bc5531deSDag-Erling Smørgrav static int 666bc5531deSDag-Erling Smørgrav choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 667a04a10f8SKris Kennaway { 6681e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 669bc5531deSDag-Erling Smørgrav 670a04a10f8SKris Kennaway if (name == NULL) 671bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_MAC_ALG_MATCH; 672d93a896eSDag-Erling Smørgrav if (mac_setup(mac, name) < 0) { 673d93a896eSDag-Erling Smørgrav free(name); 674bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 675d93a896eSDag-Erling Smørgrav } 676a04a10f8SKris Kennaway mac->name = name; 677a04a10f8SKris Kennaway mac->key = NULL; 678a04a10f8SKris Kennaway mac->enabled = 0; 679bc5531deSDag-Erling Smørgrav return 0; 680a04a10f8SKris Kennaway } 681761efaa7SDag-Erling Smørgrav 682bc5531deSDag-Erling Smørgrav static int 683bc5531deSDag-Erling Smørgrav choose_comp(struct sshcomp *comp, char *client, char *server) 684a04a10f8SKris Kennaway { 6851e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 686bc5531deSDag-Erling Smørgrav 687a04a10f8SKris Kennaway if (name == NULL) 688bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_COMPRESS_ALG_MATCH; 689043840dfSDag-Erling Smørgrav if (strcmp(name, "zlib@openssh.com") == 0) { 690043840dfSDag-Erling Smørgrav comp->type = COMP_DELAYED; 691043840dfSDag-Erling Smørgrav } else if (strcmp(name, "zlib") == 0) { 692043840dfSDag-Erling Smørgrav comp->type = COMP_ZLIB; 693a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 694043840dfSDag-Erling Smørgrav comp->type = COMP_NONE; 695a04a10f8SKris Kennaway } else { 696d93a896eSDag-Erling Smørgrav free(name); 697bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 698a04a10f8SKris Kennaway } 699a04a10f8SKris Kennaway comp->name = name; 700bc5531deSDag-Erling Smørgrav return 0; 701a04a10f8SKris Kennaway } 702761efaa7SDag-Erling Smørgrav 703bc5531deSDag-Erling Smørgrav static int 704bc5531deSDag-Erling Smørgrav choose_kex(struct kex *k, char *client, char *server) 705a04a10f8SKris Kennaway { 706e4a9863fSDag-Erling Smørgrav const struct kexalg *kexalg; 707e4a9863fSDag-Erling Smørgrav 7081e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 709bc5531deSDag-Erling Smørgrav 710acc1a9efSDag-Erling Smørgrav debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); 711a04a10f8SKris Kennaway if (k->name == NULL) 712bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_KEX_ALG_MATCH; 713e4a9863fSDag-Erling Smørgrav if ((kexalg = kex_alg_by_name(k->name)) == NULL) 714bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 715e4a9863fSDag-Erling Smørgrav k->kex_type = kexalg->type; 716f7167e0eSDag-Erling Smørgrav k->hash_alg = kexalg->hash_alg; 717e4a9863fSDag-Erling Smørgrav k->ec_nid = kexalg->ec_nid; 718bc5531deSDag-Erling Smørgrav return 0; 719a04a10f8SKris Kennaway } 720021d409fSDag-Erling Smørgrav 721bc5531deSDag-Erling Smørgrav static int 722bc5531deSDag-Erling Smørgrav choose_hostkeyalg(struct kex *k, char *client, char *server) 723a04a10f8SKris Kennaway { 724acc1a9efSDag-Erling Smørgrav k->hostkey_alg = match_list(client, server, NULL); 725bc5531deSDag-Erling Smørgrav 726acc1a9efSDag-Erling Smørgrav debug("kex: host key algorithm: %s", 727acc1a9efSDag-Erling Smørgrav k->hostkey_alg ? k->hostkey_alg : "(no match)"); 728acc1a9efSDag-Erling Smørgrav if (k->hostkey_alg == NULL) 729bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 730acc1a9efSDag-Erling Smørgrav k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); 7311e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 732bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 733acc1a9efSDag-Erling Smørgrav k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); 734bc5531deSDag-Erling Smørgrav return 0; 735a04a10f8SKris Kennaway } 736a04a10f8SKris Kennaway 737d0c8c0bcSDag-Erling Smørgrav static int 738d0c8c0bcSDag-Erling Smørgrav proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 739d0c8c0bcSDag-Erling Smørgrav { 740d0c8c0bcSDag-Erling Smørgrav static int check[] = { 741d0c8c0bcSDag-Erling Smørgrav PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 742d0c8c0bcSDag-Erling Smørgrav }; 743d0c8c0bcSDag-Erling Smørgrav int *idx; 744d0c8c0bcSDag-Erling Smørgrav char *p; 745d0c8c0bcSDag-Erling Smørgrav 746d0c8c0bcSDag-Erling Smørgrav for (idx = &check[0]; *idx != -1; idx++) { 747d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(my[*idx], ',')) != NULL) 748d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 749d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(peer[*idx], ',')) != NULL) 750d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 751d0c8c0bcSDag-Erling Smørgrav if (strcmp(my[*idx], peer[*idx]) != 0) { 752d0c8c0bcSDag-Erling Smørgrav debug2("proposal mismatch: my %s peer %s", 753d0c8c0bcSDag-Erling Smørgrav my[*idx], peer[*idx]); 754d0c8c0bcSDag-Erling Smørgrav return (0); 755d0c8c0bcSDag-Erling Smørgrav } 756d0c8c0bcSDag-Erling Smørgrav } 757d0c8c0bcSDag-Erling Smørgrav debug2("proposals match"); 758d0c8c0bcSDag-Erling Smørgrav return (1); 759d0c8c0bcSDag-Erling Smørgrav } 760d0c8c0bcSDag-Erling Smørgrav 761bc5531deSDag-Erling Smørgrav static int 762bc5531deSDag-Erling Smørgrav kex_choose_conf(struct ssh *ssh) 763a04a10f8SKris Kennaway { 764bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 765bc5531deSDag-Erling Smørgrav struct newkeys *newkeys; 766bc5531deSDag-Erling Smørgrav char **my = NULL, **peer = NULL; 7671e8db6e2SBrian Feldman char **cprop, **sprop; 7681e8db6e2SBrian Feldman int nenc, nmac, ncomp; 769f7167e0eSDag-Erling Smørgrav u_int mode, ctos, need, dh_need, authlen; 770bc5531deSDag-Erling Smørgrav int r, first_kex_follows; 771a04a10f8SKris Kennaway 772acc1a9efSDag-Erling Smørgrav debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); 773acc1a9efSDag-Erling Smørgrav if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) 774acc1a9efSDag-Erling Smørgrav goto out; 775acc1a9efSDag-Erling Smørgrav debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server"); 776acc1a9efSDag-Erling Smørgrav if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 777bc5531deSDag-Erling Smørgrav goto out; 778a04a10f8SKris Kennaway 7791e8db6e2SBrian Feldman if (kex->server) { 7801e8db6e2SBrian Feldman cprop=peer; 7811e8db6e2SBrian Feldman sprop=my; 7821e8db6e2SBrian Feldman } else { 7831e8db6e2SBrian Feldman cprop=my; 7841e8db6e2SBrian Feldman sprop=peer; 7851e8db6e2SBrian Feldman } 7861e8db6e2SBrian Feldman 787acc1a9efSDag-Erling Smørgrav /* Check whether client supports ext_info_c */ 788acc1a9efSDag-Erling Smørgrav if (kex->server) { 789acc1a9efSDag-Erling Smørgrav char *ext; 790bc5531deSDag-Erling Smørgrav 791acc1a9efSDag-Erling Smørgrav ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); 792ca86bcf2SDag-Erling Smørgrav kex->ext_info_c = (ext != NULL); 793acc1a9efSDag-Erling Smørgrav free(ext); 794b15c8340SDag-Erling Smørgrav } 795b15c8340SDag-Erling Smørgrav 7961e8db6e2SBrian Feldman /* Algorithm Negotiation */ 797acc1a9efSDag-Erling Smørgrav if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 798acc1a9efSDag-Erling Smørgrav sprop[PROPOSAL_KEX_ALGS])) != 0) { 799acc1a9efSDag-Erling Smørgrav kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; 800acc1a9efSDag-Erling Smørgrav peer[PROPOSAL_KEX_ALGS] = NULL; 801acc1a9efSDag-Erling Smørgrav goto out; 802acc1a9efSDag-Erling Smørgrav } 803acc1a9efSDag-Erling Smørgrav if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 804acc1a9efSDag-Erling Smørgrav sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { 805acc1a9efSDag-Erling Smørgrav kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; 806acc1a9efSDag-Erling Smørgrav peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; 807acc1a9efSDag-Erling Smørgrav goto out; 808acc1a9efSDag-Erling Smørgrav } 809a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 810bc5531deSDag-Erling Smørgrav if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 811bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 812bc5531deSDag-Erling Smørgrav goto out; 813bc5531deSDag-Erling Smørgrav } 8141e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 815d4af9e69SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 816d4af9e69SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 817a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 818a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 819a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 820bc5531deSDag-Erling Smørgrav if ((r = choose_enc(&newkeys->enc, cprop[nenc], 821eccfee6eSDag-Erling Smørgrav sprop[nenc])) != 0) { 822eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[nenc]; 823eccfee6eSDag-Erling Smørgrav peer[nenc] = NULL; 824bc5531deSDag-Erling Smørgrav goto out; 825eccfee6eSDag-Erling Smørgrav } 8266888a9beSDag-Erling Smørgrav authlen = cipher_authlen(newkeys->enc.cipher); 827bc5531deSDag-Erling Smørgrav /* ignore mac for authenticated encryption */ 828bc5531deSDag-Erling Smørgrav if (authlen == 0 && 829bc5531deSDag-Erling Smørgrav (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 830eccfee6eSDag-Erling Smørgrav sprop[nmac])) != 0) { 831eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[nmac]; 832eccfee6eSDag-Erling Smørgrav peer[nmac] = NULL; 833bc5531deSDag-Erling Smørgrav goto out; 834eccfee6eSDag-Erling Smørgrav } 835bc5531deSDag-Erling Smørgrav if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 836eccfee6eSDag-Erling Smørgrav sprop[ncomp])) != 0) { 837eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[ncomp]; 838eccfee6eSDag-Erling Smørgrav peer[ncomp] = NULL; 839bc5531deSDag-Erling Smørgrav goto out; 840eccfee6eSDag-Erling Smørgrav } 841acc1a9efSDag-Erling Smørgrav debug("kex: %s cipher: %s MAC: %s compression: %s", 842a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 8431e8db6e2SBrian Feldman newkeys->enc.name, 8446888a9beSDag-Erling Smørgrav authlen == 0 ? newkeys->mac.name : "<implicit>", 8451e8db6e2SBrian Feldman newkeys->comp.name); 846a04a10f8SKris Kennaway } 847f7167e0eSDag-Erling Smørgrav need = dh_need = 0; 848a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 8491e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 850ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.key_len); 851ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.block_size); 852ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.iv_len); 853ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->mac.key_len); 854ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, cipher_seclen(newkeys->enc.cipher)); 855ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->enc.block_size); 856ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len); 857ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->mac.key_len); 858a04a10f8SKris Kennaway } 8592632b0c8SKris Kennaway /* XXX need runden? */ 8601e8db6e2SBrian Feldman kex->we_need = need; 861f7167e0eSDag-Erling Smørgrav kex->dh_need = dh_need; 8621e8db6e2SBrian Feldman 863d0c8c0bcSDag-Erling Smørgrav /* ignore the next message if the proposals do not match */ 864*47dd1d1bSDag-Erling Smørgrav if (first_kex_follows && !proposals_match(my, peer)) 865bc5531deSDag-Erling Smørgrav ssh->dispatch_skip_packets = 1; 866bc5531deSDag-Erling Smørgrav r = 0; 867bc5531deSDag-Erling Smørgrav out: 8681e8db6e2SBrian Feldman kex_prop_free(my); 8691e8db6e2SBrian Feldman kex_prop_free(peer); 870bc5531deSDag-Erling Smørgrav return r; 871a04a10f8SKris Kennaway } 872a04a10f8SKris Kennaway 873bc5531deSDag-Erling Smørgrav static int 874bc5531deSDag-Erling Smørgrav derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 875bc5531deSDag-Erling Smørgrav const struct sshbuf *shared_secret, u_char **keyp) 876a04a10f8SKris Kennaway { 877bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 878bc5531deSDag-Erling Smørgrav struct ssh_digest_ctx *hashctx = NULL; 8791e8db6e2SBrian Feldman char c = id; 880043840dfSDag-Erling Smørgrav u_int have; 881f7167e0eSDag-Erling Smørgrav size_t mdsz; 882043840dfSDag-Erling Smørgrav u_char *digest; 883bc5531deSDag-Erling Smørgrav int r; 884043840dfSDag-Erling Smørgrav 885f7167e0eSDag-Erling Smørgrav if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 886bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 887ca86bcf2SDag-Erling Smørgrav if ((digest = calloc(1, ROUNDUP(need, mdsz))) == NULL) { 888bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 889bc5531deSDag-Erling Smørgrav goto out; 890bc5531deSDag-Erling Smørgrav } 8911e8db6e2SBrian Feldman 8921e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 893bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 894bc5531deSDag-Erling Smørgrav ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 895f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, hash, hashlen) != 0 || 896f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, &c, 1) != 0 || 897f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, kex->session_id, 898bc5531deSDag-Erling Smørgrav kex->session_id_len) != 0 || 899bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, digest, mdsz) != 0) { 900bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 901bc5531deSDag-Erling Smørgrav goto out; 902bc5531deSDag-Erling Smørgrav } 903f7167e0eSDag-Erling Smørgrav ssh_digest_free(hashctx); 904bc5531deSDag-Erling Smørgrav hashctx = NULL; 9051e8db6e2SBrian Feldman 9061e8db6e2SBrian Feldman /* 9071e8db6e2SBrian Feldman * expand key: 9081e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 9091e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 9101e8db6e2SBrian Feldman */ 9111e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 912bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 913bc5531deSDag-Erling Smørgrav ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 914f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, hash, hashlen) != 0 || 915bc5531deSDag-Erling Smørgrav ssh_digest_update(hashctx, digest, have) != 0 || 916bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 917bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 918bc5531deSDag-Erling Smørgrav goto out; 9191e8db6e2SBrian Feldman } 920bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 921bc5531deSDag-Erling Smørgrav hashctx = NULL; 922bc5531deSDag-Erling Smørgrav } 9231e8db6e2SBrian Feldman #ifdef DEBUG_KEX 9241e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 9251e8db6e2SBrian Feldman dump_digest("key", digest, need); 9261e8db6e2SBrian Feldman #endif 927bc5531deSDag-Erling Smørgrav *keyp = digest; 928bc5531deSDag-Erling Smørgrav digest = NULL; 929bc5531deSDag-Erling Smørgrav r = 0; 930bc5531deSDag-Erling Smørgrav out: 931bc5531deSDag-Erling Smørgrav free(digest); 932bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 933bc5531deSDag-Erling Smørgrav return r; 9341e8db6e2SBrian Feldman } 9351e8db6e2SBrian Feldman 9361e8db6e2SBrian Feldman #define NKEYS 6 937bc5531deSDag-Erling Smørgrav int 938bc5531deSDag-Erling Smørgrav kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 939bc5531deSDag-Erling Smørgrav const struct sshbuf *shared_secret) 9401e8db6e2SBrian Feldman { 941bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 9421e8db6e2SBrian Feldman u_char *keys[NKEYS]; 943bc5531deSDag-Erling Smørgrav u_int i, j, mode, ctos; 944bc5531deSDag-Erling Smørgrav int r; 945a04a10f8SKris Kennaway 946021d409fSDag-Erling Smørgrav for (i = 0; i < NKEYS; i++) { 947bc5531deSDag-Erling Smørgrav if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 948bc5531deSDag-Erling Smørgrav shared_secret, &keys[i])) != 0) { 949bc5531deSDag-Erling Smørgrav for (j = 0; j < i; j++) 950bc5531deSDag-Erling Smørgrav free(keys[j]); 951bc5531deSDag-Erling Smørgrav return r; 952021d409fSDag-Erling Smørgrav } 953bc5531deSDag-Erling Smørgrav } 954a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 955761efaa7SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 956761efaa7SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 957bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 958bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 959bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 960a04a10f8SKris Kennaway } 961bc5531deSDag-Erling Smørgrav return 0; 962a04a10f8SKris Kennaway } 9631e8db6e2SBrian Feldman 964a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 965bc5531deSDag-Erling Smørgrav int 966bc5531deSDag-Erling Smørgrav kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 967bc5531deSDag-Erling Smørgrav const BIGNUM *secret) 968f7167e0eSDag-Erling Smørgrav { 969bc5531deSDag-Erling Smørgrav struct sshbuf *shared_secret; 970bc5531deSDag-Erling Smørgrav int r; 971f7167e0eSDag-Erling Smørgrav 972bc5531deSDag-Erling Smørgrav if ((shared_secret = sshbuf_new()) == NULL) 973bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 974bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 975bc5531deSDag-Erling Smørgrav r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 976bc5531deSDag-Erling Smørgrav sshbuf_free(shared_secret); 977bc5531deSDag-Erling Smørgrav return r; 978f7167e0eSDag-Erling Smørgrav } 979a0ee8cc6SDag-Erling Smørgrav #endif 980f7167e0eSDag-Erling Smørgrav 981d74d50a8SDag-Erling Smørgrav 9824a421b63SDag-Erling Smørgrav #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 9831e8db6e2SBrian Feldman void 9841e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 9851e8db6e2SBrian Feldman { 9861e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 987bc5531deSDag-Erling Smørgrav sshbuf_dump_data(digest, len, stderr); 9881e8db6e2SBrian Feldman } 9891e8db6e2SBrian Feldman #endif 990