1*190cef3dSDag-Erling Smørgrav /* $OpenBSD: kex.c,v 1.141 2018/07/09 13:37:10 sf 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') 177*190cef3dSDag-Erling Smørgrav return strdup(b); 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 212*190cef3dSDag-Erling Smørgrav kex_assemble_names(char **listp, const char *def, const char *all) 213eccfee6eSDag-Erling Smørgrav { 214*190cef3dSDag-Erling Smørgrav char *cp, *tmp, *patterns; 215*190cef3dSDag-Erling Smørgrav char *list = NULL, *ret = NULL, *matching = NULL, *opatterns = NULL; 216*190cef3dSDag-Erling Smørgrav int r = SSH_ERR_INTERNAL_ERROR; 217eccfee6eSDag-Erling Smørgrav 218*190cef3dSDag-Erling Smørgrav if (listp == NULL || *listp == NULL || **listp == '\0') { 219*190cef3dSDag-Erling Smørgrav if ((*listp = strdup(def)) == NULL) 220*190cef3dSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 221eccfee6eSDag-Erling Smørgrav return 0; 222eccfee6eSDag-Erling Smørgrav } 223*190cef3dSDag-Erling Smørgrav 224*190cef3dSDag-Erling Smørgrav list = *listp; 225*190cef3dSDag-Erling Smørgrav *listp = NULL; 226*190cef3dSDag-Erling Smørgrav if (*list == '+') { 227*190cef3dSDag-Erling Smørgrav /* Append names to default list */ 228*190cef3dSDag-Erling Smørgrav if ((tmp = kex_names_cat(def, list + 1)) == NULL) { 229*190cef3dSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 230*190cef3dSDag-Erling Smørgrav goto fail; 231*190cef3dSDag-Erling Smørgrav } 232*190cef3dSDag-Erling Smørgrav free(list); 233*190cef3dSDag-Erling Smørgrav list = tmp; 234*190cef3dSDag-Erling Smørgrav } else if (*list == '-') { 235*190cef3dSDag-Erling Smørgrav /* Remove names from default list */ 236*190cef3dSDag-Erling Smørgrav if ((*listp = match_filter_blacklist(def, list + 1)) == NULL) { 237*190cef3dSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 238*190cef3dSDag-Erling Smørgrav goto fail; 239*190cef3dSDag-Erling Smørgrav } 240*190cef3dSDag-Erling Smørgrav free(list); 241*190cef3dSDag-Erling Smørgrav /* filtering has already been done */ 242*190cef3dSDag-Erling Smørgrav return 0; 243*190cef3dSDag-Erling Smørgrav } else { 244*190cef3dSDag-Erling Smørgrav /* Explicit list, overrides default - just use "list" as is */ 245d93a896eSDag-Erling Smørgrav } 246d93a896eSDag-Erling Smørgrav 247*190cef3dSDag-Erling Smørgrav /* 248*190cef3dSDag-Erling Smørgrav * The supplied names may be a pattern-list. For the -list case, 249*190cef3dSDag-Erling Smørgrav * the patterns are applied above. For the +list and explicit list 250*190cef3dSDag-Erling Smørgrav * cases we need to do it now. 251*190cef3dSDag-Erling Smørgrav */ 252*190cef3dSDag-Erling Smørgrav ret = NULL; 253*190cef3dSDag-Erling Smørgrav if ((patterns = opatterns = strdup(list)) == NULL) { 254*190cef3dSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 255*190cef3dSDag-Erling Smørgrav goto fail; 256*190cef3dSDag-Erling Smørgrav } 257*190cef3dSDag-Erling Smørgrav /* Apply positive (i.e. non-negated) patterns from the list */ 258*190cef3dSDag-Erling Smørgrav while ((cp = strsep(&patterns, ",")) != NULL) { 259*190cef3dSDag-Erling Smørgrav if (*cp == '!') { 260*190cef3dSDag-Erling Smørgrav /* negated matches are not supported here */ 261*190cef3dSDag-Erling Smørgrav r = SSH_ERR_INVALID_ARGUMENT; 262*190cef3dSDag-Erling Smørgrav goto fail; 263*190cef3dSDag-Erling Smørgrav } 264*190cef3dSDag-Erling Smørgrav free(matching); 265*190cef3dSDag-Erling Smørgrav if ((matching = match_filter_whitelist(all, cp)) == NULL) { 266*190cef3dSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 267*190cef3dSDag-Erling Smørgrav goto fail; 268*190cef3dSDag-Erling Smørgrav } 269*190cef3dSDag-Erling Smørgrav if ((tmp = kex_names_cat(ret, matching)) == NULL) { 270*190cef3dSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 271*190cef3dSDag-Erling Smørgrav goto fail; 272*190cef3dSDag-Erling Smørgrav } 273*190cef3dSDag-Erling Smørgrav free(ret); 274*190cef3dSDag-Erling Smørgrav ret = tmp; 275*190cef3dSDag-Erling Smørgrav } 276*190cef3dSDag-Erling Smørgrav if (ret == NULL || *ret == '\0') { 277*190cef3dSDag-Erling Smørgrav /* An empty name-list is an error */ 278*190cef3dSDag-Erling Smørgrav /* XXX better error code? */ 279*190cef3dSDag-Erling Smørgrav r = SSH_ERR_INVALID_ARGUMENT; 280*190cef3dSDag-Erling Smørgrav goto fail; 281*190cef3dSDag-Erling Smørgrav } 282*190cef3dSDag-Erling Smørgrav 283*190cef3dSDag-Erling Smørgrav /* success */ 284*190cef3dSDag-Erling Smørgrav *listp = ret; 285*190cef3dSDag-Erling Smørgrav ret = NULL; 286*190cef3dSDag-Erling Smørgrav r = 0; 287*190cef3dSDag-Erling Smørgrav 288*190cef3dSDag-Erling Smørgrav fail: 289*190cef3dSDag-Erling Smørgrav free(matching); 290*190cef3dSDag-Erling Smørgrav free(opatterns); 291*190cef3dSDag-Erling Smørgrav free(list); 292*190cef3dSDag-Erling Smørgrav free(ret); 293*190cef3dSDag-Erling Smørgrav return r; 294eccfee6eSDag-Erling Smørgrav } 295eccfee6eSDag-Erling Smørgrav 2961765946bSDag-Erling Smørgrav /* put algorithm proposal into buffer */ 297bc5531deSDag-Erling Smørgrav int 298bc5531deSDag-Erling Smørgrav kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 299a04a10f8SKris Kennaway { 300043840dfSDag-Erling Smørgrav u_int i; 301bc5531deSDag-Erling Smørgrav int r; 3021e8db6e2SBrian Feldman 303bc5531deSDag-Erling Smørgrav sshbuf_reset(b); 304bc5531deSDag-Erling Smørgrav 305545d5ecaSDag-Erling Smørgrav /* 306545d5ecaSDag-Erling Smørgrav * add a dummy cookie, the cookie will be overwritten by 307545d5ecaSDag-Erling Smørgrav * kex_send_kexinit(), each time a kexinit is set 308545d5ecaSDag-Erling Smørgrav */ 309bc5531deSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) { 310bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(b, 0)) != 0) 311bc5531deSDag-Erling Smørgrav return r; 312bc5531deSDag-Erling Smørgrav } 313bc5531deSDag-Erling Smørgrav for (i = 0; i < PROPOSAL_MAX; i++) { 314bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 315bc5531deSDag-Erling Smørgrav return r; 316bc5531deSDag-Erling Smørgrav } 317bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 318bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 319bc5531deSDag-Erling Smørgrav return r; 320bc5531deSDag-Erling Smørgrav return 0; 321a04a10f8SKris Kennaway } 322a04a10f8SKris Kennaway 3231e8db6e2SBrian Feldman /* parse buffer and return algorithm proposal */ 324bc5531deSDag-Erling Smørgrav int 325bc5531deSDag-Erling Smørgrav kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 3262632b0c8SKris Kennaway { 327bc5531deSDag-Erling Smørgrav struct sshbuf *b = NULL; 328bc5531deSDag-Erling Smørgrav u_char v; 329d4af9e69SDag-Erling Smørgrav u_int i; 330bc5531deSDag-Erling Smørgrav char **proposal = NULL; 331bc5531deSDag-Erling Smørgrav int r; 3322632b0c8SKris Kennaway 333bc5531deSDag-Erling Smørgrav *propp = NULL; 334bc5531deSDag-Erling Smørgrav if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 335bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 336bc5531deSDag-Erling Smørgrav if ((b = sshbuf_fromb(raw)) == NULL) { 337bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 338bc5531deSDag-Erling Smørgrav goto out; 339bc5531deSDag-Erling Smørgrav } 340bc5531deSDag-Erling Smørgrav if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 341bc5531deSDag-Erling Smørgrav goto out; 3422632b0c8SKris Kennaway /* extract kex init proposal strings */ 3432632b0c8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) { 344bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 345bc5531deSDag-Erling Smørgrav goto out; 346acc1a9efSDag-Erling Smørgrav debug2("%s: %s", proposal_names[i], proposal[i]); 3472632b0c8SKris Kennaway } 3481e8db6e2SBrian Feldman /* first kex follows / reserved */ 349fc1ba28aSDag-Erling Smørgrav if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ 350fc1ba28aSDag-Erling Smørgrav (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ 351bc5531deSDag-Erling Smørgrav goto out; 352d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows != NULL) 353fc1ba28aSDag-Erling Smørgrav *first_kex_follows = v; 354fc1ba28aSDag-Erling Smørgrav debug2("first_kex_follows %d ", v); 355fc1ba28aSDag-Erling Smørgrav debug2("reserved %u ", i); 356bc5531deSDag-Erling Smørgrav r = 0; 357bc5531deSDag-Erling Smørgrav *propp = proposal; 358bc5531deSDag-Erling Smørgrav out: 359bc5531deSDag-Erling Smørgrav if (r != 0 && proposal != NULL) 360bc5531deSDag-Erling Smørgrav kex_prop_free(proposal); 361bc5531deSDag-Erling Smørgrav sshbuf_free(b); 362bc5531deSDag-Erling Smørgrav return r; 3635b9b2fafSBrian Feldman } 3645b9b2fafSBrian Feldman 365bc5531deSDag-Erling Smørgrav void 3661e8db6e2SBrian Feldman kex_prop_free(char **proposal) 367a04a10f8SKris Kennaway { 368043840dfSDag-Erling Smørgrav u_int i; 3691e8db6e2SBrian Feldman 370557f75e5SDag-Erling Smørgrav if (proposal == NULL) 371557f75e5SDag-Erling Smørgrav return; 3721e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 373e4a9863fSDag-Erling Smørgrav free(proposal[i]); 374e4a9863fSDag-Erling Smørgrav free(proposal); 375a04a10f8SKris Kennaway } 376a04a10f8SKris Kennaway 377d4af9e69SDag-Erling Smørgrav /* ARGSUSED */ 378bc5531deSDag-Erling Smørgrav static int 3794f52dfbbSDag-Erling Smørgrav kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh) 380a04a10f8SKris Kennaway { 381acc1a9efSDag-Erling Smørgrav int r; 382acc1a9efSDag-Erling Smørgrav 383acc1a9efSDag-Erling Smørgrav error("kex protocol error: type %d seq %u", type, seq); 384acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || 385acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, seq)) != 0 || 386acc1a9efSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 387acc1a9efSDag-Erling Smørgrav return r; 388bc5531deSDag-Erling Smørgrav return 0; 389a04a10f8SKris Kennaway } 390a04a10f8SKris Kennaway 391ae1f160dSDag-Erling Smørgrav static void 392bc5531deSDag-Erling Smørgrav kex_reset_dispatch(struct ssh *ssh) 3935b9b2fafSBrian Feldman { 394bc5531deSDag-Erling Smørgrav ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 395ae1f160dSDag-Erling Smørgrav SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 3965b9b2fafSBrian Feldman } 3975b9b2fafSBrian Feldman 398acc1a9efSDag-Erling Smørgrav static int 399acc1a9efSDag-Erling Smørgrav kex_send_ext_info(struct ssh *ssh) 400acc1a9efSDag-Erling Smørgrav { 401acc1a9efSDag-Erling Smørgrav int r; 402ca86bcf2SDag-Erling Smørgrav char *algs; 403acc1a9efSDag-Erling Smørgrav 404d93a896eSDag-Erling Smørgrav if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) 405ca86bcf2SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 406*190cef3dSDag-Erling Smørgrav /* XXX filter algs list by allowed pubkey/hostbased types */ 407acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || 408acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, 1)) != 0 || 409acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || 410ca86bcf2SDag-Erling Smørgrav (r = sshpkt_put_cstring(ssh, algs)) != 0 || 411acc1a9efSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 412ca86bcf2SDag-Erling Smørgrav goto out; 413ca86bcf2SDag-Erling Smørgrav /* success */ 414ca86bcf2SDag-Erling Smørgrav r = 0; 415ca86bcf2SDag-Erling Smørgrav out: 416ca86bcf2SDag-Erling Smørgrav free(algs); 417acc1a9efSDag-Erling Smørgrav return r; 418acc1a9efSDag-Erling Smørgrav } 419acc1a9efSDag-Erling Smørgrav 420bc5531deSDag-Erling Smørgrav int 421bc5531deSDag-Erling Smørgrav kex_send_newkeys(struct ssh *ssh) 422a04a10f8SKris Kennaway { 423bc5531deSDag-Erling Smørgrav int r; 424a04a10f8SKris Kennaway 425bc5531deSDag-Erling Smørgrav kex_reset_dispatch(ssh); 426bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 427bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 428bc5531deSDag-Erling Smørgrav return r; 4291e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS sent"); 430d0c8c0bcSDag-Erling Smørgrav debug("expecting SSH2_MSG_NEWKEYS"); 431bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 432acc1a9efSDag-Erling Smørgrav if (ssh->kex->ext_info_c) 433acc1a9efSDag-Erling Smørgrav if ((r = kex_send_ext_info(ssh)) != 0) 434acc1a9efSDag-Erling Smørgrav return r; 435bc5531deSDag-Erling Smørgrav return 0; 436bc5531deSDag-Erling Smørgrav } 4371e8db6e2SBrian Feldman 438acc1a9efSDag-Erling Smørgrav int 4394f52dfbbSDag-Erling Smørgrav kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh) 440acc1a9efSDag-Erling Smørgrav { 441acc1a9efSDag-Erling Smørgrav struct kex *kex = ssh->kex; 442acc1a9efSDag-Erling Smørgrav u_int32_t i, ninfo; 443*190cef3dSDag-Erling Smørgrav char *name; 4444f52dfbbSDag-Erling Smørgrav u_char *val; 4454f52dfbbSDag-Erling Smørgrav size_t vlen; 446acc1a9efSDag-Erling Smørgrav int r; 447acc1a9efSDag-Erling Smørgrav 448acc1a9efSDag-Erling Smørgrav debug("SSH2_MSG_EXT_INFO received"); 449acc1a9efSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); 450acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) 451acc1a9efSDag-Erling Smørgrav return r; 452acc1a9efSDag-Erling Smørgrav for (i = 0; i < ninfo; i++) { 453acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) 454acc1a9efSDag-Erling Smørgrav return r; 4554f52dfbbSDag-Erling Smørgrav if ((r = sshpkt_get_string(ssh, &val, &vlen)) != 0) { 456acc1a9efSDag-Erling Smørgrav free(name); 457acc1a9efSDag-Erling Smørgrav return r; 458acc1a9efSDag-Erling Smørgrav } 459acc1a9efSDag-Erling Smørgrav if (strcmp(name, "server-sig-algs") == 0) { 4604f52dfbbSDag-Erling Smørgrav /* Ensure no \0 lurking in value */ 4614f52dfbbSDag-Erling Smørgrav if (memchr(val, '\0', vlen) != NULL) { 4624f52dfbbSDag-Erling Smørgrav error("%s: nul byte in %s", __func__, name); 4634f52dfbbSDag-Erling Smørgrav return SSH_ERR_INVALID_FORMAT; 4644f52dfbbSDag-Erling Smørgrav } 4654f52dfbbSDag-Erling Smørgrav debug("%s: %s=<%s>", __func__, name, val); 466*190cef3dSDag-Erling Smørgrav kex->server_sig_algs = val; 467*190cef3dSDag-Erling Smørgrav val = NULL; 4684f52dfbbSDag-Erling Smørgrav } else 4694f52dfbbSDag-Erling Smørgrav debug("%s: %s (unrecognised)", __func__, name); 470acc1a9efSDag-Erling Smørgrav free(name); 471acc1a9efSDag-Erling Smørgrav free(val); 472acc1a9efSDag-Erling Smørgrav } 473acc1a9efSDag-Erling Smørgrav return sshpkt_get_end(ssh); 474acc1a9efSDag-Erling Smørgrav } 475acc1a9efSDag-Erling Smørgrav 476bc5531deSDag-Erling Smørgrav static int 4774f52dfbbSDag-Erling Smørgrav kex_input_newkeys(int type, u_int32_t seq, struct ssh *ssh) 478bc5531deSDag-Erling Smørgrav { 479bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 480bc5531deSDag-Erling Smørgrav int r; 481bc5531deSDag-Erling Smørgrav 482bc5531deSDag-Erling Smørgrav debug("SSH2_MSG_NEWKEYS received"); 483bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 484d93a896eSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 485bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_end(ssh)) != 0) 486bc5531deSDag-Erling Smørgrav return r; 487ca86bcf2SDag-Erling Smørgrav if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0) 488ca86bcf2SDag-Erling Smørgrav return r; 4891e8db6e2SBrian Feldman kex->done = 1; 490bc5531deSDag-Erling Smørgrav sshbuf_reset(kex->peer); 491bc5531deSDag-Erling Smørgrav /* sshbuf_reset(kex->my); */ 4921e8db6e2SBrian Feldman kex->flags &= ~KEX_INIT_SENT; 493e4a9863fSDag-Erling Smørgrav free(kex->name); 4941e8db6e2SBrian Feldman kex->name = NULL; 495bc5531deSDag-Erling Smørgrav return 0; 496a04a10f8SKris Kennaway } 497a04a10f8SKris Kennaway 498bc5531deSDag-Erling Smørgrav int 499bc5531deSDag-Erling Smørgrav kex_send_kexinit(struct ssh *ssh) 500a04a10f8SKris Kennaway { 501545d5ecaSDag-Erling Smørgrav u_char *cookie; 502bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 503bc5531deSDag-Erling Smørgrav int r; 504545d5ecaSDag-Erling Smørgrav 505bc5531deSDag-Erling Smørgrav if (kex == NULL) 506bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 507bc5531deSDag-Erling Smørgrav if (kex->flags & KEX_INIT_SENT) 508bc5531deSDag-Erling Smørgrav return 0; 5091e8db6e2SBrian Feldman kex->done = 0; 510545d5ecaSDag-Erling Smørgrav 511545d5ecaSDag-Erling Smørgrav /* generate a random cookie */ 512bc5531deSDag-Erling Smørgrav if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 513bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_FORMAT; 514bc5531deSDag-Erling Smørgrav if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 515bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 516bc5531deSDag-Erling Smørgrav arc4random_buf(cookie, KEX_COOKIE_LEN); 517bc5531deSDag-Erling Smørgrav 518bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 519bc5531deSDag-Erling Smørgrav (r = sshpkt_putb(ssh, kex->my)) != 0 || 520bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 521bc5531deSDag-Erling Smørgrav return r; 5221e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT sent"); 5231e8db6e2SBrian Feldman kex->flags |= KEX_INIT_SENT; 524bc5531deSDag-Erling Smørgrav return 0; 5251e8db6e2SBrian Feldman } 526a04a10f8SKris Kennaway 527d4af9e69SDag-Erling Smørgrav /* ARGSUSED */ 528bc5531deSDag-Erling Smørgrav int 5294f52dfbbSDag-Erling Smørgrav kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) 5301e8db6e2SBrian Feldman { 531bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 532bc5531deSDag-Erling Smørgrav const u_char *ptr; 533bc5531deSDag-Erling Smørgrav u_int i; 534bc5531deSDag-Erling Smørgrav size_t dlen; 535bc5531deSDag-Erling Smørgrav int r; 5362632b0c8SKris Kennaway 5371e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 5381e8db6e2SBrian Feldman if (kex == NULL) 539bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 5401e8db6e2SBrian Feldman 541ca86bcf2SDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); 542bc5531deSDag-Erling Smørgrav ptr = sshpkt_ptr(ssh, &dlen); 543bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 544bc5531deSDag-Erling Smørgrav return r; 5451e8db6e2SBrian Feldman 5461e8db6e2SBrian Feldman /* discard packet */ 5471e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 548bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 549bc5531deSDag-Erling Smørgrav return r; 5501e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 551bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 552bc5531deSDag-Erling Smørgrav return r; 5536888a9beSDag-Erling Smørgrav /* 5546888a9beSDag-Erling Smørgrav * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 5556888a9beSDag-Erling Smørgrav * KEX method has the server move first, but a server might be using 5566888a9beSDag-Erling Smørgrav * a custom method or one that we otherwise don't support. We should 5576888a9beSDag-Erling Smørgrav * be prepared to remember first_kex_follows here so we can eat a 5586888a9beSDag-Erling Smørgrav * packet later. 5596888a9beSDag-Erling Smørgrav * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 5606888a9beSDag-Erling Smørgrav * for cases where the server *doesn't* go first. I guess we should 5616888a9beSDag-Erling Smørgrav * ignore it when it is set for these cases, which is what we do now. 5626888a9beSDag-Erling Smørgrav */ 563bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 564bc5531deSDag-Erling Smørgrav (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 565bc5531deSDag-Erling Smørgrav (r = sshpkt_get_end(ssh)) != 0) 566bc5531deSDag-Erling Smørgrav return r; 5671e8db6e2SBrian Feldman 5681e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 569bc5531deSDag-Erling Smørgrav if ((r = kex_send_kexinit(ssh)) != 0) 570bc5531deSDag-Erling Smørgrav return r; 571bc5531deSDag-Erling Smørgrav if ((r = kex_choose_conf(ssh)) != 0) 572bc5531deSDag-Erling Smørgrav return r; 5731e8db6e2SBrian Feldman 574bc5531deSDag-Erling Smørgrav if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 575bc5531deSDag-Erling Smørgrav return (kex->kex[kex->kex_type])(ssh); 5761e8db6e2SBrian Feldman 577bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 5781e8db6e2SBrian Feldman } 579a04a10f8SKris Kennaway 580bc5531deSDag-Erling Smørgrav int 581bc5531deSDag-Erling Smørgrav kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 582bc5531deSDag-Erling Smørgrav { 583bc5531deSDag-Erling Smørgrav struct kex *kex; 584bc5531deSDag-Erling Smørgrav int r; 585bc5531deSDag-Erling Smørgrav 586bc5531deSDag-Erling Smørgrav *kexp = NULL; 587bc5531deSDag-Erling Smørgrav if ((kex = calloc(1, sizeof(*kex))) == NULL) 588bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 589bc5531deSDag-Erling Smørgrav if ((kex->peer = sshbuf_new()) == NULL || 590bc5531deSDag-Erling Smørgrav (kex->my = sshbuf_new()) == NULL) { 591bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 592bc5531deSDag-Erling Smørgrav goto out; 593bc5531deSDag-Erling Smørgrav } 594bc5531deSDag-Erling Smørgrav if ((r = kex_prop2buf(kex->my, proposal)) != 0) 595bc5531deSDag-Erling Smørgrav goto out; 596bc5531deSDag-Erling Smørgrav kex->done = 0; 597bc5531deSDag-Erling Smørgrav kex_reset_dispatch(ssh); 598d93a896eSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 599bc5531deSDag-Erling Smørgrav r = 0; 600bc5531deSDag-Erling Smørgrav *kexp = kex; 601bc5531deSDag-Erling Smørgrav out: 602bc5531deSDag-Erling Smørgrav if (r != 0) 603bc5531deSDag-Erling Smørgrav kex_free(kex); 604bc5531deSDag-Erling Smørgrav return r; 605bc5531deSDag-Erling Smørgrav } 606bc5531deSDag-Erling Smørgrav 607bc5531deSDag-Erling Smørgrav void 608bc5531deSDag-Erling Smørgrav kex_free_newkeys(struct newkeys *newkeys) 609bc5531deSDag-Erling Smørgrav { 610bc5531deSDag-Erling Smørgrav if (newkeys == NULL) 611bc5531deSDag-Erling Smørgrav return; 612bc5531deSDag-Erling Smørgrav if (newkeys->enc.key) { 613bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 614bc5531deSDag-Erling Smørgrav free(newkeys->enc.key); 615bc5531deSDag-Erling Smørgrav newkeys->enc.key = NULL; 616bc5531deSDag-Erling Smørgrav } 617bc5531deSDag-Erling Smørgrav if (newkeys->enc.iv) { 618acc1a9efSDag-Erling Smørgrav explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len); 619bc5531deSDag-Erling Smørgrav free(newkeys->enc.iv); 620bc5531deSDag-Erling Smørgrav newkeys->enc.iv = NULL; 621bc5531deSDag-Erling Smørgrav } 622bc5531deSDag-Erling Smørgrav free(newkeys->enc.name); 623bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 624bc5531deSDag-Erling Smørgrav free(newkeys->comp.name); 625bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 626bc5531deSDag-Erling Smørgrav mac_clear(&newkeys->mac); 627bc5531deSDag-Erling Smørgrav if (newkeys->mac.key) { 628bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 629bc5531deSDag-Erling Smørgrav free(newkeys->mac.key); 630bc5531deSDag-Erling Smørgrav newkeys->mac.key = NULL; 631bc5531deSDag-Erling Smørgrav } 632bc5531deSDag-Erling Smørgrav free(newkeys->mac.name); 633bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 634bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys, sizeof(*newkeys)); 635bc5531deSDag-Erling Smørgrav free(newkeys); 636bc5531deSDag-Erling Smørgrav } 637bc5531deSDag-Erling Smørgrav 638bc5531deSDag-Erling Smørgrav void 639bc5531deSDag-Erling Smørgrav kex_free(struct kex *kex) 640bc5531deSDag-Erling Smørgrav { 641bc5531deSDag-Erling Smørgrav u_int mode; 642bc5531deSDag-Erling Smørgrav 643bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL 644bc5531deSDag-Erling Smørgrav DH_free(kex->dh); 645bc5531deSDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 646bc5531deSDag-Erling Smørgrav EC_KEY_free(kex->ec_client_key); 647bc5531deSDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 648bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 649bc5531deSDag-Erling Smørgrav for (mode = 0; mode < MODE_MAX; mode++) { 650bc5531deSDag-Erling Smørgrav kex_free_newkeys(kex->newkeys[mode]); 651bc5531deSDag-Erling Smørgrav kex->newkeys[mode] = NULL; 652bc5531deSDag-Erling Smørgrav } 653bc5531deSDag-Erling Smørgrav sshbuf_free(kex->peer); 654bc5531deSDag-Erling Smørgrav sshbuf_free(kex->my); 655bc5531deSDag-Erling Smørgrav free(kex->session_id); 656bc5531deSDag-Erling Smørgrav free(kex->client_version_string); 657bc5531deSDag-Erling Smørgrav free(kex->server_version_string); 658eccfee6eSDag-Erling Smørgrav free(kex->failed_choice); 659acc1a9efSDag-Erling Smørgrav free(kex->hostkey_alg); 660acc1a9efSDag-Erling Smørgrav free(kex->name); 661bc5531deSDag-Erling Smørgrav free(kex); 662bc5531deSDag-Erling Smørgrav } 663bc5531deSDag-Erling Smørgrav 664bc5531deSDag-Erling Smørgrav int 665bc5531deSDag-Erling Smørgrav kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 666bc5531deSDag-Erling Smørgrav { 667bc5531deSDag-Erling Smørgrav int r; 668bc5531deSDag-Erling Smørgrav 669bc5531deSDag-Erling Smørgrav if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 670bc5531deSDag-Erling Smørgrav return r; 671bc5531deSDag-Erling Smørgrav if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 672bc5531deSDag-Erling Smørgrav kex_free(ssh->kex); 673bc5531deSDag-Erling Smørgrav ssh->kex = NULL; 674bc5531deSDag-Erling Smørgrav return r; 675bc5531deSDag-Erling Smørgrav } 676bc5531deSDag-Erling Smørgrav return 0; 677bc5531deSDag-Erling Smørgrav } 678bc5531deSDag-Erling Smørgrav 679acc1a9efSDag-Erling Smørgrav /* 680acc1a9efSDag-Erling Smørgrav * Request key re-exchange, returns 0 on success or a ssherr.h error 681acc1a9efSDag-Erling Smørgrav * code otherwise. Must not be called if KEX is incomplete or in-progress. 682acc1a9efSDag-Erling Smørgrav */ 683acc1a9efSDag-Erling Smørgrav int 684acc1a9efSDag-Erling Smørgrav kex_start_rekex(struct ssh *ssh) 685acc1a9efSDag-Erling Smørgrav { 686acc1a9efSDag-Erling Smørgrav if (ssh->kex == NULL) { 687acc1a9efSDag-Erling Smørgrav error("%s: no kex", __func__); 688acc1a9efSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 689acc1a9efSDag-Erling Smørgrav } 690acc1a9efSDag-Erling Smørgrav if (ssh->kex->done == 0) { 691acc1a9efSDag-Erling Smørgrav error("%s: requested twice", __func__); 692acc1a9efSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 693acc1a9efSDag-Erling Smørgrav } 694acc1a9efSDag-Erling Smørgrav ssh->kex->done = 0; 695acc1a9efSDag-Erling Smørgrav return kex_send_kexinit(ssh); 696acc1a9efSDag-Erling Smørgrav } 697acc1a9efSDag-Erling Smørgrav 698bc5531deSDag-Erling Smørgrav static int 699bc5531deSDag-Erling Smørgrav choose_enc(struct sshenc *enc, char *client, char *server) 700a04a10f8SKris Kennaway { 7011e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 702bc5531deSDag-Erling Smørgrav 703a04a10f8SKris Kennaway if (name == NULL) 704bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_CIPHER_ALG_MATCH; 705d93a896eSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) { 706d93a896eSDag-Erling Smørgrav free(name); 707bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 708d93a896eSDag-Erling Smørgrav } 709a04a10f8SKris Kennaway enc->name = name; 710a04a10f8SKris Kennaway enc->enabled = 0; 711a04a10f8SKris Kennaway enc->iv = NULL; 7126888a9beSDag-Erling Smørgrav enc->iv_len = cipher_ivlen(enc->cipher); 713a04a10f8SKris Kennaway enc->key = NULL; 714ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 715ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 716bc5531deSDag-Erling Smørgrav return 0; 717a04a10f8SKris Kennaway } 718761efaa7SDag-Erling Smørgrav 719bc5531deSDag-Erling Smørgrav static int 720bc5531deSDag-Erling Smørgrav choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 721a04a10f8SKris Kennaway { 7221e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 723bc5531deSDag-Erling Smørgrav 724a04a10f8SKris Kennaway if (name == NULL) 725bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_MAC_ALG_MATCH; 726d93a896eSDag-Erling Smørgrav if (mac_setup(mac, name) < 0) { 727d93a896eSDag-Erling Smørgrav free(name); 728bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 729d93a896eSDag-Erling Smørgrav } 730a04a10f8SKris Kennaway mac->name = name; 731a04a10f8SKris Kennaway mac->key = NULL; 732a04a10f8SKris Kennaway mac->enabled = 0; 733bc5531deSDag-Erling Smørgrav return 0; 734a04a10f8SKris Kennaway } 735761efaa7SDag-Erling Smørgrav 736bc5531deSDag-Erling Smørgrav static int 737bc5531deSDag-Erling Smørgrav choose_comp(struct sshcomp *comp, char *client, char *server) 738a04a10f8SKris Kennaway { 7391e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 740bc5531deSDag-Erling Smørgrav 741a04a10f8SKris Kennaway if (name == NULL) 742bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_COMPRESS_ALG_MATCH; 743043840dfSDag-Erling Smørgrav if (strcmp(name, "zlib@openssh.com") == 0) { 744043840dfSDag-Erling Smørgrav comp->type = COMP_DELAYED; 745043840dfSDag-Erling Smørgrav } else if (strcmp(name, "zlib") == 0) { 746043840dfSDag-Erling Smørgrav comp->type = COMP_ZLIB; 747a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 748043840dfSDag-Erling Smørgrav comp->type = COMP_NONE; 749a04a10f8SKris Kennaway } else { 750d93a896eSDag-Erling Smørgrav free(name); 751bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 752a04a10f8SKris Kennaway } 753a04a10f8SKris Kennaway comp->name = name; 754bc5531deSDag-Erling Smørgrav return 0; 755a04a10f8SKris Kennaway } 756761efaa7SDag-Erling Smørgrav 757bc5531deSDag-Erling Smørgrav static int 758bc5531deSDag-Erling Smørgrav choose_kex(struct kex *k, char *client, char *server) 759a04a10f8SKris Kennaway { 760e4a9863fSDag-Erling Smørgrav const struct kexalg *kexalg; 761e4a9863fSDag-Erling Smørgrav 7621e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 763bc5531deSDag-Erling Smørgrav 764acc1a9efSDag-Erling Smørgrav debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); 765a04a10f8SKris Kennaway if (k->name == NULL) 766bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_KEX_ALG_MATCH; 767e4a9863fSDag-Erling Smørgrav if ((kexalg = kex_alg_by_name(k->name)) == NULL) 768bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 769e4a9863fSDag-Erling Smørgrav k->kex_type = kexalg->type; 770f7167e0eSDag-Erling Smørgrav k->hash_alg = kexalg->hash_alg; 771e4a9863fSDag-Erling Smørgrav k->ec_nid = kexalg->ec_nid; 772bc5531deSDag-Erling Smørgrav return 0; 773a04a10f8SKris Kennaway } 774021d409fSDag-Erling Smørgrav 775bc5531deSDag-Erling Smørgrav static int 776bc5531deSDag-Erling Smørgrav choose_hostkeyalg(struct kex *k, char *client, char *server) 777a04a10f8SKris Kennaway { 778acc1a9efSDag-Erling Smørgrav k->hostkey_alg = match_list(client, server, NULL); 779bc5531deSDag-Erling Smørgrav 780acc1a9efSDag-Erling Smørgrav debug("kex: host key algorithm: %s", 781acc1a9efSDag-Erling Smørgrav k->hostkey_alg ? k->hostkey_alg : "(no match)"); 782acc1a9efSDag-Erling Smørgrav if (k->hostkey_alg == NULL) 783bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 784acc1a9efSDag-Erling Smørgrav k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); 7851e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 786bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 787acc1a9efSDag-Erling Smørgrav k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); 788bc5531deSDag-Erling Smørgrav return 0; 789a04a10f8SKris Kennaway } 790a04a10f8SKris Kennaway 791d0c8c0bcSDag-Erling Smørgrav static int 792d0c8c0bcSDag-Erling Smørgrav proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 793d0c8c0bcSDag-Erling Smørgrav { 794d0c8c0bcSDag-Erling Smørgrav static int check[] = { 795d0c8c0bcSDag-Erling Smørgrav PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 796d0c8c0bcSDag-Erling Smørgrav }; 797d0c8c0bcSDag-Erling Smørgrav int *idx; 798d0c8c0bcSDag-Erling Smørgrav char *p; 799d0c8c0bcSDag-Erling Smørgrav 800d0c8c0bcSDag-Erling Smørgrav for (idx = &check[0]; *idx != -1; idx++) { 801d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(my[*idx], ',')) != NULL) 802d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 803d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(peer[*idx], ',')) != NULL) 804d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 805d0c8c0bcSDag-Erling Smørgrav if (strcmp(my[*idx], peer[*idx]) != 0) { 806d0c8c0bcSDag-Erling Smørgrav debug2("proposal mismatch: my %s peer %s", 807d0c8c0bcSDag-Erling Smørgrav my[*idx], peer[*idx]); 808d0c8c0bcSDag-Erling Smørgrav return (0); 809d0c8c0bcSDag-Erling Smørgrav } 810d0c8c0bcSDag-Erling Smørgrav } 811d0c8c0bcSDag-Erling Smørgrav debug2("proposals match"); 812d0c8c0bcSDag-Erling Smørgrav return (1); 813d0c8c0bcSDag-Erling Smørgrav } 814d0c8c0bcSDag-Erling Smørgrav 815bc5531deSDag-Erling Smørgrav static int 816bc5531deSDag-Erling Smørgrav kex_choose_conf(struct ssh *ssh) 817a04a10f8SKris Kennaway { 818bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 819bc5531deSDag-Erling Smørgrav struct newkeys *newkeys; 820bc5531deSDag-Erling Smørgrav char **my = NULL, **peer = NULL; 8211e8db6e2SBrian Feldman char **cprop, **sprop; 8221e8db6e2SBrian Feldman int nenc, nmac, ncomp; 823f7167e0eSDag-Erling Smørgrav u_int mode, ctos, need, dh_need, authlen; 824bc5531deSDag-Erling Smørgrav int r, first_kex_follows; 825a04a10f8SKris Kennaway 826acc1a9efSDag-Erling Smørgrav debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); 827acc1a9efSDag-Erling Smørgrav if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) 828acc1a9efSDag-Erling Smørgrav goto out; 829acc1a9efSDag-Erling Smørgrav debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server"); 830acc1a9efSDag-Erling Smørgrav if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 831bc5531deSDag-Erling Smørgrav goto out; 832a04a10f8SKris Kennaway 8331e8db6e2SBrian Feldman if (kex->server) { 8341e8db6e2SBrian Feldman cprop=peer; 8351e8db6e2SBrian Feldman sprop=my; 8361e8db6e2SBrian Feldman } else { 8371e8db6e2SBrian Feldman cprop=my; 8381e8db6e2SBrian Feldman sprop=peer; 8391e8db6e2SBrian Feldman } 8401e8db6e2SBrian Feldman 841acc1a9efSDag-Erling Smørgrav /* Check whether client supports ext_info_c */ 842acc1a9efSDag-Erling Smørgrav if (kex->server) { 843acc1a9efSDag-Erling Smørgrav char *ext; 844bc5531deSDag-Erling Smørgrav 845acc1a9efSDag-Erling Smørgrav ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); 846ca86bcf2SDag-Erling Smørgrav kex->ext_info_c = (ext != NULL); 847acc1a9efSDag-Erling Smørgrav free(ext); 848b15c8340SDag-Erling Smørgrav } 849b15c8340SDag-Erling Smørgrav 8501e8db6e2SBrian Feldman /* Algorithm Negotiation */ 851acc1a9efSDag-Erling Smørgrav if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 852acc1a9efSDag-Erling Smørgrav sprop[PROPOSAL_KEX_ALGS])) != 0) { 853acc1a9efSDag-Erling Smørgrav kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; 854acc1a9efSDag-Erling Smørgrav peer[PROPOSAL_KEX_ALGS] = NULL; 855acc1a9efSDag-Erling Smørgrav goto out; 856acc1a9efSDag-Erling Smørgrav } 857acc1a9efSDag-Erling Smørgrav if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 858acc1a9efSDag-Erling Smørgrav sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { 859acc1a9efSDag-Erling Smørgrav kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; 860acc1a9efSDag-Erling Smørgrav peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; 861acc1a9efSDag-Erling Smørgrav goto out; 862acc1a9efSDag-Erling Smørgrav } 863a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 864bc5531deSDag-Erling Smørgrav if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 865bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 866bc5531deSDag-Erling Smørgrav goto out; 867bc5531deSDag-Erling Smørgrav } 8681e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 869d4af9e69SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 870d4af9e69SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 871a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 872a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 873a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 874bc5531deSDag-Erling Smørgrav if ((r = choose_enc(&newkeys->enc, cprop[nenc], 875eccfee6eSDag-Erling Smørgrav sprop[nenc])) != 0) { 876eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[nenc]; 877eccfee6eSDag-Erling Smørgrav peer[nenc] = NULL; 878bc5531deSDag-Erling Smørgrav goto out; 879eccfee6eSDag-Erling Smørgrav } 8806888a9beSDag-Erling Smørgrav authlen = cipher_authlen(newkeys->enc.cipher); 881bc5531deSDag-Erling Smørgrav /* ignore mac for authenticated encryption */ 882bc5531deSDag-Erling Smørgrav if (authlen == 0 && 883bc5531deSDag-Erling Smørgrav (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 884eccfee6eSDag-Erling Smørgrav sprop[nmac])) != 0) { 885eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[nmac]; 886eccfee6eSDag-Erling Smørgrav peer[nmac] = NULL; 887bc5531deSDag-Erling Smørgrav goto out; 888eccfee6eSDag-Erling Smørgrav } 889bc5531deSDag-Erling Smørgrav if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 890eccfee6eSDag-Erling Smørgrav sprop[ncomp])) != 0) { 891eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[ncomp]; 892eccfee6eSDag-Erling Smørgrav peer[ncomp] = NULL; 893bc5531deSDag-Erling Smørgrav goto out; 894eccfee6eSDag-Erling Smørgrav } 895acc1a9efSDag-Erling Smørgrav debug("kex: %s cipher: %s MAC: %s compression: %s", 896a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 8971e8db6e2SBrian Feldman newkeys->enc.name, 8986888a9beSDag-Erling Smørgrav authlen == 0 ? newkeys->mac.name : "<implicit>", 8991e8db6e2SBrian Feldman newkeys->comp.name); 900a04a10f8SKris Kennaway } 901f7167e0eSDag-Erling Smørgrav need = dh_need = 0; 902a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 9031e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 904ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.key_len); 905ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.block_size); 906ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.iv_len); 907ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->mac.key_len); 908ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, cipher_seclen(newkeys->enc.cipher)); 909ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->enc.block_size); 910ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len); 911ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->mac.key_len); 912a04a10f8SKris Kennaway } 9132632b0c8SKris Kennaway /* XXX need runden? */ 9141e8db6e2SBrian Feldman kex->we_need = need; 915f7167e0eSDag-Erling Smørgrav kex->dh_need = dh_need; 9161e8db6e2SBrian Feldman 917d0c8c0bcSDag-Erling Smørgrav /* ignore the next message if the proposals do not match */ 91847dd1d1bSDag-Erling Smørgrav if (first_kex_follows && !proposals_match(my, peer)) 919bc5531deSDag-Erling Smørgrav ssh->dispatch_skip_packets = 1; 920bc5531deSDag-Erling Smørgrav r = 0; 921bc5531deSDag-Erling Smørgrav out: 9221e8db6e2SBrian Feldman kex_prop_free(my); 9231e8db6e2SBrian Feldman kex_prop_free(peer); 924bc5531deSDag-Erling Smørgrav return r; 925a04a10f8SKris Kennaway } 926a04a10f8SKris Kennaway 927bc5531deSDag-Erling Smørgrav static int 928bc5531deSDag-Erling Smørgrav derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 929bc5531deSDag-Erling Smørgrav const struct sshbuf *shared_secret, u_char **keyp) 930a04a10f8SKris Kennaway { 931bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 932bc5531deSDag-Erling Smørgrav struct ssh_digest_ctx *hashctx = NULL; 9331e8db6e2SBrian Feldman char c = id; 934043840dfSDag-Erling Smørgrav u_int have; 935f7167e0eSDag-Erling Smørgrav size_t mdsz; 936043840dfSDag-Erling Smørgrav u_char *digest; 937bc5531deSDag-Erling Smørgrav int r; 938043840dfSDag-Erling Smørgrav 939f7167e0eSDag-Erling Smørgrav if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 940bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 941ca86bcf2SDag-Erling Smørgrav if ((digest = calloc(1, ROUNDUP(need, mdsz))) == NULL) { 942bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 943bc5531deSDag-Erling Smørgrav goto out; 944bc5531deSDag-Erling Smørgrav } 9451e8db6e2SBrian Feldman 9461e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 947bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 948bc5531deSDag-Erling Smørgrav ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 949f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, hash, hashlen) != 0 || 950f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, &c, 1) != 0 || 951f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, kex->session_id, 952bc5531deSDag-Erling Smørgrav kex->session_id_len) != 0 || 953bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, digest, mdsz) != 0) { 954bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 955bc5531deSDag-Erling Smørgrav goto out; 956bc5531deSDag-Erling Smørgrav } 957f7167e0eSDag-Erling Smørgrav ssh_digest_free(hashctx); 958bc5531deSDag-Erling Smørgrav hashctx = NULL; 9591e8db6e2SBrian Feldman 9601e8db6e2SBrian Feldman /* 9611e8db6e2SBrian Feldman * expand key: 9621e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 9631e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 9641e8db6e2SBrian Feldman */ 9651e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 966bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 967bc5531deSDag-Erling Smørgrav ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 968f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, hash, hashlen) != 0 || 969bc5531deSDag-Erling Smørgrav ssh_digest_update(hashctx, digest, have) != 0 || 970bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 971bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 972bc5531deSDag-Erling Smørgrav goto out; 9731e8db6e2SBrian Feldman } 974bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 975bc5531deSDag-Erling Smørgrav hashctx = NULL; 976bc5531deSDag-Erling Smørgrav } 9771e8db6e2SBrian Feldman #ifdef DEBUG_KEX 9781e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 9791e8db6e2SBrian Feldman dump_digest("key", digest, need); 9801e8db6e2SBrian Feldman #endif 981bc5531deSDag-Erling Smørgrav *keyp = digest; 982bc5531deSDag-Erling Smørgrav digest = NULL; 983bc5531deSDag-Erling Smørgrav r = 0; 984bc5531deSDag-Erling Smørgrav out: 985bc5531deSDag-Erling Smørgrav free(digest); 986bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 987bc5531deSDag-Erling Smørgrav return r; 9881e8db6e2SBrian Feldman } 9891e8db6e2SBrian Feldman 9901e8db6e2SBrian Feldman #define NKEYS 6 991bc5531deSDag-Erling Smørgrav int 992bc5531deSDag-Erling Smørgrav kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 993bc5531deSDag-Erling Smørgrav const struct sshbuf *shared_secret) 9941e8db6e2SBrian Feldman { 995bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 9961e8db6e2SBrian Feldman u_char *keys[NKEYS]; 997bc5531deSDag-Erling Smørgrav u_int i, j, mode, ctos; 998bc5531deSDag-Erling Smørgrav int r; 999a04a10f8SKris Kennaway 1000021d409fSDag-Erling Smørgrav for (i = 0; i < NKEYS; i++) { 1001bc5531deSDag-Erling Smørgrav if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 1002bc5531deSDag-Erling Smørgrav shared_secret, &keys[i])) != 0) { 1003bc5531deSDag-Erling Smørgrav for (j = 0; j < i; j++) 1004bc5531deSDag-Erling Smørgrav free(keys[j]); 1005bc5531deSDag-Erling Smørgrav return r; 1006021d409fSDag-Erling Smørgrav } 1007bc5531deSDag-Erling Smørgrav } 1008a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 1009761efaa7SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 1010761efaa7SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 1011bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 1012bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 1013bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 1014a04a10f8SKris Kennaway } 1015bc5531deSDag-Erling Smørgrav return 0; 1016a04a10f8SKris Kennaway } 10171e8db6e2SBrian Feldman 1018a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 1019bc5531deSDag-Erling Smørgrav int 1020bc5531deSDag-Erling Smørgrav kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 1021bc5531deSDag-Erling Smørgrav const BIGNUM *secret) 1022f7167e0eSDag-Erling Smørgrav { 1023bc5531deSDag-Erling Smørgrav struct sshbuf *shared_secret; 1024bc5531deSDag-Erling Smørgrav int r; 1025f7167e0eSDag-Erling Smørgrav 1026bc5531deSDag-Erling Smørgrav if ((shared_secret = sshbuf_new()) == NULL) 1027bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 1028bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 1029bc5531deSDag-Erling Smørgrav r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 1030bc5531deSDag-Erling Smørgrav sshbuf_free(shared_secret); 1031bc5531deSDag-Erling Smørgrav return r; 1032f7167e0eSDag-Erling Smørgrav } 1033a0ee8cc6SDag-Erling Smørgrav #endif 1034f7167e0eSDag-Erling Smørgrav 1035d74d50a8SDag-Erling Smørgrav 10364a421b63SDag-Erling Smørgrav #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 10371e8db6e2SBrian Feldman void 10381e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 10391e8db6e2SBrian Feldman { 10401e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 1041bc5531deSDag-Erling Smørgrav sshbuf_dump_data(digest, len, stderr); 10421e8db6e2SBrian Feldman } 10431e8db6e2SBrian Feldman #endif 1044