1*d93a896eSDag-Erling Smørgrav /* $OpenBSD: kex.c,v 1.131 2017/03/15 07:07:39 markus 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 57761efaa7SDag-Erling Smørgrav #if OPENSSL_VERSION_NUMBER >= 0x00907000L 58761efaa7SDag-Erling Smørgrav # if defined(HAVE_EVP_SHA256) 59761efaa7SDag-Erling Smørgrav # define evp_ssh_sha256 EVP_sha256 60761efaa7SDag-Erling Smørgrav # else 61761efaa7SDag-Erling Smørgrav extern const EVP_MD *evp_ssh_sha256(void); 62761efaa7SDag-Erling Smørgrav # endif 63761efaa7SDag-Erling Smørgrav #endif 64761efaa7SDag-Erling Smørgrav 65ae1f160dSDag-Erling Smørgrav /* prototype */ 66bc5531deSDag-Erling Smørgrav static int kex_choose_conf(struct ssh *); 67bc5531deSDag-Erling Smørgrav static int kex_input_newkeys(int, u_int32_t, void *); 681e8db6e2SBrian Feldman 69acc1a9efSDag-Erling Smørgrav static const char *proposal_names[PROPOSAL_MAX] = { 70acc1a9efSDag-Erling Smørgrav "KEX algorithms", 71acc1a9efSDag-Erling Smørgrav "host key algorithms", 72acc1a9efSDag-Erling Smørgrav "ciphers ctos", 73acc1a9efSDag-Erling Smørgrav "ciphers stoc", 74acc1a9efSDag-Erling Smørgrav "MACs ctos", 75acc1a9efSDag-Erling Smørgrav "MACs stoc", 76acc1a9efSDag-Erling Smørgrav "compression ctos", 77acc1a9efSDag-Erling Smørgrav "compression stoc", 78acc1a9efSDag-Erling Smørgrav "languages ctos", 79acc1a9efSDag-Erling Smørgrav "languages stoc", 80acc1a9efSDag-Erling Smørgrav }; 81acc1a9efSDag-Erling Smørgrav 82e4a9863fSDag-Erling Smørgrav struct kexalg { 83e4a9863fSDag-Erling Smørgrav char *name; 84bc5531deSDag-Erling Smørgrav u_int type; 85e4a9863fSDag-Erling Smørgrav int ec_nid; 86f7167e0eSDag-Erling Smørgrav int hash_alg; 87e4a9863fSDag-Erling Smørgrav }; 88e4a9863fSDag-Erling Smørgrav static const struct kexalg kexalgs[] = { 89a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 90f7167e0eSDag-Erling Smørgrav { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 91076ad2f8SDag-Erling Smørgrav { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 92076ad2f8SDag-Erling Smørgrav { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, 93076ad2f8SDag-Erling Smørgrav { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, 94076ad2f8SDag-Erling Smørgrav { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 }, 95f7167e0eSDag-Erling Smørgrav { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 96e4a9863fSDag-Erling Smørgrav #ifdef HAVE_EVP_SHA256 97f7167e0eSDag-Erling Smørgrav { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 98a0ee8cc6SDag-Erling Smørgrav #endif /* HAVE_EVP_SHA256 */ 99e4a9863fSDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 100f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 101f7167e0eSDag-Erling Smørgrav NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 102f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, 103f7167e0eSDag-Erling Smørgrav SSH_DIGEST_SHA384 }, 104f7167e0eSDag-Erling Smørgrav # ifdef OPENSSL_HAS_NISTP521 105f7167e0eSDag-Erling Smørgrav { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 106f7167e0eSDag-Erling Smørgrav SSH_DIGEST_SHA512 }, 107a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_NISTP521 */ 108a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 109a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 110bc5531deSDag-Erling Smørgrav #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) 111f7167e0eSDag-Erling Smørgrav { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 112ca86bcf2SDag-Erling Smørgrav { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 113bc5531deSDag-Erling Smørgrav #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 114f7167e0eSDag-Erling Smørgrav { NULL, -1, -1, -1}, 115e4a9863fSDag-Erling Smørgrav }; 116e4a9863fSDag-Erling Smørgrav 117e4a9863fSDag-Erling Smørgrav char * 118f7167e0eSDag-Erling Smørgrav kex_alg_list(char sep) 119e4a9863fSDag-Erling Smørgrav { 120bc5531deSDag-Erling Smørgrav char *ret = NULL, *tmp; 121e4a9863fSDag-Erling Smørgrav size_t nlen, rlen = 0; 122e4a9863fSDag-Erling Smørgrav const struct kexalg *k; 123e4a9863fSDag-Erling Smørgrav 124e4a9863fSDag-Erling Smørgrav for (k = kexalgs; k->name != NULL; k++) { 125e4a9863fSDag-Erling Smørgrav if (ret != NULL) 126f7167e0eSDag-Erling Smørgrav ret[rlen++] = sep; 127e4a9863fSDag-Erling Smørgrav nlen = strlen(k->name); 128bc5531deSDag-Erling Smørgrav if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 129bc5531deSDag-Erling Smørgrav free(ret); 130bc5531deSDag-Erling Smørgrav return NULL; 131bc5531deSDag-Erling Smørgrav } 132bc5531deSDag-Erling Smørgrav ret = tmp; 133e4a9863fSDag-Erling Smørgrav memcpy(ret + rlen, k->name, nlen + 1); 134e4a9863fSDag-Erling Smørgrav rlen += nlen; 135e4a9863fSDag-Erling Smørgrav } 136e4a9863fSDag-Erling Smørgrav return ret; 137e4a9863fSDag-Erling Smørgrav } 138e4a9863fSDag-Erling Smørgrav 139e4a9863fSDag-Erling Smørgrav static const struct kexalg * 140e4a9863fSDag-Erling Smørgrav kex_alg_by_name(const char *name) 141e4a9863fSDag-Erling Smørgrav { 142e4a9863fSDag-Erling Smørgrav const struct kexalg *k; 143e4a9863fSDag-Erling Smørgrav 144e4a9863fSDag-Erling Smørgrav for (k = kexalgs; k->name != NULL; k++) { 145e4a9863fSDag-Erling Smørgrav if (strcmp(k->name, name) == 0) 146e4a9863fSDag-Erling Smørgrav return k; 147e4a9863fSDag-Erling Smørgrav } 148e4a9863fSDag-Erling Smørgrav return NULL; 149e4a9863fSDag-Erling Smørgrav } 150e4a9863fSDag-Erling Smørgrav 1514a421b63SDag-Erling Smørgrav /* Validate KEX method name list */ 1524a421b63SDag-Erling Smørgrav int 1534a421b63SDag-Erling Smørgrav kex_names_valid(const char *names) 1544a421b63SDag-Erling Smørgrav { 1554a421b63SDag-Erling Smørgrav char *s, *cp, *p; 1564a421b63SDag-Erling Smørgrav 1574a421b63SDag-Erling Smørgrav if (names == NULL || strcmp(names, "") == 0) 1584a421b63SDag-Erling Smørgrav return 0; 159bc5531deSDag-Erling Smørgrav if ((s = cp = strdup(names)) == NULL) 160bc5531deSDag-Erling Smørgrav return 0; 1614a421b63SDag-Erling Smørgrav for ((p = strsep(&cp, ",")); p && *p != '\0'; 1624a421b63SDag-Erling Smørgrav (p = strsep(&cp, ","))) { 163e4a9863fSDag-Erling Smørgrav if (kex_alg_by_name(p) == NULL) { 1644a421b63SDag-Erling Smørgrav error("Unsupported KEX algorithm \"%.100s\"", p); 165e4a9863fSDag-Erling Smørgrav free(s); 1664a421b63SDag-Erling Smørgrav return 0; 1674a421b63SDag-Erling Smørgrav } 1684a421b63SDag-Erling Smørgrav } 1694a421b63SDag-Erling Smørgrav debug3("kex names ok: [%s]", names); 170e4a9863fSDag-Erling Smørgrav free(s); 1714a421b63SDag-Erling Smørgrav return 1; 1724a421b63SDag-Erling Smørgrav } 1734a421b63SDag-Erling Smørgrav 174eccfee6eSDag-Erling Smørgrav /* 175eccfee6eSDag-Erling Smørgrav * Concatenate algorithm names, avoiding duplicates in the process. 176eccfee6eSDag-Erling Smørgrav * Caller must free returned string. 177eccfee6eSDag-Erling Smørgrav */ 178eccfee6eSDag-Erling Smørgrav char * 179eccfee6eSDag-Erling Smørgrav kex_names_cat(const char *a, const char *b) 180eccfee6eSDag-Erling Smørgrav { 181*d93a896eSDag-Erling Smørgrav char *ret = NULL, *tmp = NULL, *cp, *p, *m; 182eccfee6eSDag-Erling Smørgrav size_t len; 183eccfee6eSDag-Erling Smørgrav 184eccfee6eSDag-Erling Smørgrav if (a == NULL || *a == '\0') 185eccfee6eSDag-Erling Smørgrav return NULL; 186eccfee6eSDag-Erling Smørgrav if (b == NULL || *b == '\0') 187eccfee6eSDag-Erling Smørgrav return strdup(a); 188eccfee6eSDag-Erling Smørgrav if (strlen(b) > 1024*1024) 189eccfee6eSDag-Erling Smørgrav return NULL; 190eccfee6eSDag-Erling Smørgrav len = strlen(a) + strlen(b) + 2; 191eccfee6eSDag-Erling Smørgrav if ((tmp = cp = strdup(b)) == NULL || 192eccfee6eSDag-Erling Smørgrav (ret = calloc(1, len)) == NULL) { 193eccfee6eSDag-Erling Smørgrav free(tmp); 194eccfee6eSDag-Erling Smørgrav return NULL; 195eccfee6eSDag-Erling Smørgrav } 196eccfee6eSDag-Erling Smørgrav strlcpy(ret, a, len); 197eccfee6eSDag-Erling Smørgrav for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { 198*d93a896eSDag-Erling Smørgrav if ((m = match_list(ret, p, NULL)) != NULL) { 199*d93a896eSDag-Erling Smørgrav free(m); 200eccfee6eSDag-Erling Smørgrav continue; /* Algorithm already present */ 201*d93a896eSDag-Erling Smørgrav } 202eccfee6eSDag-Erling Smørgrav if (strlcat(ret, ",", len) >= len || 203eccfee6eSDag-Erling Smørgrav strlcat(ret, p, len) >= len) { 204eccfee6eSDag-Erling Smørgrav free(tmp); 205eccfee6eSDag-Erling Smørgrav free(ret); 206eccfee6eSDag-Erling Smørgrav return NULL; /* Shouldn't happen */ 207eccfee6eSDag-Erling Smørgrav } 208eccfee6eSDag-Erling Smørgrav } 209eccfee6eSDag-Erling Smørgrav free(tmp); 210eccfee6eSDag-Erling Smørgrav return ret; 211eccfee6eSDag-Erling Smørgrav } 212eccfee6eSDag-Erling Smørgrav 213eccfee6eSDag-Erling Smørgrav /* 214eccfee6eSDag-Erling Smørgrav * Assemble a list of algorithms from a default list and a string from a 215eccfee6eSDag-Erling Smørgrav * configuration file. The user-provided string may begin with '+' to 216*d93a896eSDag-Erling Smørgrav * indicate that it should be appended to the default or '-' that the 217*d93a896eSDag-Erling Smørgrav * specified names should be removed. 218eccfee6eSDag-Erling Smørgrav */ 219eccfee6eSDag-Erling Smørgrav int 220eccfee6eSDag-Erling Smørgrav kex_assemble_names(const char *def, char **list) 221eccfee6eSDag-Erling Smørgrav { 222eccfee6eSDag-Erling Smørgrav char *ret; 223eccfee6eSDag-Erling Smørgrav 224eccfee6eSDag-Erling Smørgrav if (list == NULL || *list == NULL || **list == '\0') { 225eccfee6eSDag-Erling Smørgrav *list = strdup(def); 226eccfee6eSDag-Erling Smørgrav return 0; 227eccfee6eSDag-Erling Smørgrav } 228*d93a896eSDag-Erling Smørgrav if (**list == '+') { 229eccfee6eSDag-Erling Smørgrav if ((ret = kex_names_cat(def, *list + 1)) == NULL) 230eccfee6eSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 231eccfee6eSDag-Erling Smørgrav free(*list); 232eccfee6eSDag-Erling Smørgrav *list = ret; 233*d93a896eSDag-Erling Smørgrav } else if (**list == '-') { 234*d93a896eSDag-Erling Smørgrav if ((ret = match_filter_list(def, *list + 1)) == NULL) 235*d93a896eSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 236*d93a896eSDag-Erling Smørgrav free(*list); 237*d93a896eSDag-Erling Smørgrav *list = ret; 238*d93a896eSDag-Erling Smørgrav } 239*d93a896eSDag-Erling Smørgrav 240eccfee6eSDag-Erling Smørgrav return 0; 241eccfee6eSDag-Erling Smørgrav } 242eccfee6eSDag-Erling Smørgrav 2431765946bSDag-Erling Smørgrav /* put algorithm proposal into buffer */ 244bc5531deSDag-Erling Smørgrav int 245bc5531deSDag-Erling Smørgrav kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 246a04a10f8SKris Kennaway { 247043840dfSDag-Erling Smørgrav u_int i; 248bc5531deSDag-Erling Smørgrav int r; 2491e8db6e2SBrian Feldman 250bc5531deSDag-Erling Smørgrav sshbuf_reset(b); 251bc5531deSDag-Erling Smørgrav 252545d5ecaSDag-Erling Smørgrav /* 253545d5ecaSDag-Erling Smørgrav * add a dummy cookie, the cookie will be overwritten by 254545d5ecaSDag-Erling Smørgrav * kex_send_kexinit(), each time a kexinit is set 255545d5ecaSDag-Erling Smørgrav */ 256bc5531deSDag-Erling Smørgrav for (i = 0; i < KEX_COOKIE_LEN; i++) { 257bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(b, 0)) != 0) 258bc5531deSDag-Erling Smørgrav return r; 259bc5531deSDag-Erling Smørgrav } 260bc5531deSDag-Erling Smørgrav for (i = 0; i < PROPOSAL_MAX; i++) { 261bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 262bc5531deSDag-Erling Smørgrav return r; 263bc5531deSDag-Erling Smørgrav } 264bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 265bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 266bc5531deSDag-Erling Smørgrav return r; 267bc5531deSDag-Erling Smørgrav return 0; 268a04a10f8SKris Kennaway } 269a04a10f8SKris Kennaway 2701e8db6e2SBrian Feldman /* parse buffer and return algorithm proposal */ 271bc5531deSDag-Erling Smørgrav int 272bc5531deSDag-Erling Smørgrav kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 2732632b0c8SKris Kennaway { 274bc5531deSDag-Erling Smørgrav struct sshbuf *b = NULL; 275bc5531deSDag-Erling Smørgrav u_char v; 276d4af9e69SDag-Erling Smørgrav u_int i; 277bc5531deSDag-Erling Smørgrav char **proposal = NULL; 278bc5531deSDag-Erling Smørgrav int r; 2792632b0c8SKris Kennaway 280bc5531deSDag-Erling Smørgrav *propp = NULL; 281bc5531deSDag-Erling Smørgrav if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 282bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 283bc5531deSDag-Erling Smørgrav if ((b = sshbuf_fromb(raw)) == NULL) { 284bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 285bc5531deSDag-Erling Smørgrav goto out; 286bc5531deSDag-Erling Smørgrav } 287bc5531deSDag-Erling Smørgrav if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 288bc5531deSDag-Erling Smørgrav goto out; 2892632b0c8SKris Kennaway /* extract kex init proposal strings */ 2902632b0c8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) { 291bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 292bc5531deSDag-Erling Smørgrav goto out; 293acc1a9efSDag-Erling Smørgrav debug2("%s: %s", proposal_names[i], proposal[i]); 2942632b0c8SKris Kennaway } 2951e8db6e2SBrian Feldman /* first kex follows / reserved */ 296fc1ba28aSDag-Erling Smørgrav if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ 297fc1ba28aSDag-Erling Smørgrav (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ 298bc5531deSDag-Erling Smørgrav goto out; 299d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows != NULL) 300fc1ba28aSDag-Erling Smørgrav *first_kex_follows = v; 301fc1ba28aSDag-Erling Smørgrav debug2("first_kex_follows %d ", v); 302fc1ba28aSDag-Erling Smørgrav debug2("reserved %u ", i); 303bc5531deSDag-Erling Smørgrav r = 0; 304bc5531deSDag-Erling Smørgrav *propp = proposal; 305bc5531deSDag-Erling Smørgrav out: 306bc5531deSDag-Erling Smørgrav if (r != 0 && proposal != NULL) 307bc5531deSDag-Erling Smørgrav kex_prop_free(proposal); 308bc5531deSDag-Erling Smørgrav sshbuf_free(b); 309bc5531deSDag-Erling Smørgrav return r; 3105b9b2fafSBrian Feldman } 3115b9b2fafSBrian Feldman 312bc5531deSDag-Erling Smørgrav void 3131e8db6e2SBrian Feldman kex_prop_free(char **proposal) 314a04a10f8SKris Kennaway { 315043840dfSDag-Erling Smørgrav u_int i; 3161e8db6e2SBrian Feldman 317557f75e5SDag-Erling Smørgrav if (proposal == NULL) 318557f75e5SDag-Erling Smørgrav return; 3191e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 320e4a9863fSDag-Erling Smørgrav free(proposal[i]); 321e4a9863fSDag-Erling Smørgrav free(proposal); 322a04a10f8SKris Kennaway } 323a04a10f8SKris Kennaway 324d4af9e69SDag-Erling Smørgrav /* ARGSUSED */ 325bc5531deSDag-Erling Smørgrav static int 326ae1f160dSDag-Erling Smørgrav kex_protocol_error(int type, u_int32_t seq, void *ctxt) 327a04a10f8SKris Kennaway { 328acc1a9efSDag-Erling Smørgrav struct ssh *ssh = active_state; /* XXX */ 329acc1a9efSDag-Erling Smørgrav int r; 330acc1a9efSDag-Erling Smørgrav 331acc1a9efSDag-Erling Smørgrav error("kex protocol error: type %d seq %u", type, seq); 332acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || 333acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, seq)) != 0 || 334acc1a9efSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 335acc1a9efSDag-Erling Smørgrav return r; 336bc5531deSDag-Erling Smørgrav return 0; 337a04a10f8SKris Kennaway } 338a04a10f8SKris Kennaway 339ae1f160dSDag-Erling Smørgrav static void 340bc5531deSDag-Erling Smørgrav kex_reset_dispatch(struct ssh *ssh) 3415b9b2fafSBrian Feldman { 342bc5531deSDag-Erling Smørgrav ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 343ae1f160dSDag-Erling Smørgrav SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 3445b9b2fafSBrian Feldman } 3455b9b2fafSBrian Feldman 346acc1a9efSDag-Erling Smørgrav static int 347acc1a9efSDag-Erling Smørgrav kex_send_ext_info(struct ssh *ssh) 348acc1a9efSDag-Erling Smørgrav { 349acc1a9efSDag-Erling Smørgrav int r; 350ca86bcf2SDag-Erling Smørgrav char *algs; 351acc1a9efSDag-Erling Smørgrav 352*d93a896eSDag-Erling Smørgrav if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) 353ca86bcf2SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 354acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || 355acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_u32(ssh, 1)) != 0 || 356acc1a9efSDag-Erling Smørgrav (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || 357ca86bcf2SDag-Erling Smørgrav (r = sshpkt_put_cstring(ssh, algs)) != 0 || 358acc1a9efSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 359ca86bcf2SDag-Erling Smørgrav goto out; 360ca86bcf2SDag-Erling Smørgrav /* success */ 361ca86bcf2SDag-Erling Smørgrav r = 0; 362ca86bcf2SDag-Erling Smørgrav out: 363ca86bcf2SDag-Erling Smørgrav free(algs); 364acc1a9efSDag-Erling Smørgrav return r; 365acc1a9efSDag-Erling Smørgrav } 366acc1a9efSDag-Erling Smørgrav 367bc5531deSDag-Erling Smørgrav int 368bc5531deSDag-Erling Smørgrav kex_send_newkeys(struct ssh *ssh) 369a04a10f8SKris Kennaway { 370bc5531deSDag-Erling Smørgrav int r; 371a04a10f8SKris Kennaway 372bc5531deSDag-Erling Smørgrav kex_reset_dispatch(ssh); 373bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 374bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 375bc5531deSDag-Erling Smørgrav return r; 3761e8db6e2SBrian Feldman debug("SSH2_MSG_NEWKEYS sent"); 377d0c8c0bcSDag-Erling Smørgrav debug("expecting SSH2_MSG_NEWKEYS"); 378bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 379acc1a9efSDag-Erling Smørgrav if (ssh->kex->ext_info_c) 380acc1a9efSDag-Erling Smørgrav if ((r = kex_send_ext_info(ssh)) != 0) 381acc1a9efSDag-Erling Smørgrav return r; 382bc5531deSDag-Erling Smørgrav return 0; 383bc5531deSDag-Erling Smørgrav } 3841e8db6e2SBrian Feldman 385acc1a9efSDag-Erling Smørgrav int 386acc1a9efSDag-Erling Smørgrav kex_input_ext_info(int type, u_int32_t seq, void *ctxt) 387acc1a9efSDag-Erling Smørgrav { 388acc1a9efSDag-Erling Smørgrav struct ssh *ssh = ctxt; 389acc1a9efSDag-Erling Smørgrav struct kex *kex = ssh->kex; 390acc1a9efSDag-Erling Smørgrav u_int32_t i, ninfo; 391acc1a9efSDag-Erling Smørgrav char *name, *val, *found; 392acc1a9efSDag-Erling Smørgrav int r; 393acc1a9efSDag-Erling Smørgrav 394acc1a9efSDag-Erling Smørgrav debug("SSH2_MSG_EXT_INFO received"); 395acc1a9efSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); 396acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) 397acc1a9efSDag-Erling Smørgrav return r; 398acc1a9efSDag-Erling Smørgrav for (i = 0; i < ninfo; i++) { 399acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) 400acc1a9efSDag-Erling Smørgrav return r; 401acc1a9efSDag-Erling Smørgrav if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) { 402acc1a9efSDag-Erling Smørgrav free(name); 403acc1a9efSDag-Erling Smørgrav return r; 404acc1a9efSDag-Erling Smørgrav } 405acc1a9efSDag-Erling Smørgrav debug("%s: %s=<%s>", __func__, name, val); 406acc1a9efSDag-Erling Smørgrav if (strcmp(name, "server-sig-algs") == 0) { 407acc1a9efSDag-Erling Smørgrav found = match_list("rsa-sha2-256", val, NULL); 408acc1a9efSDag-Erling Smørgrav if (found) { 409acc1a9efSDag-Erling Smørgrav kex->rsa_sha2 = 256; 410acc1a9efSDag-Erling Smørgrav free(found); 411acc1a9efSDag-Erling Smørgrav } 412acc1a9efSDag-Erling Smørgrav found = match_list("rsa-sha2-512", val, NULL); 413acc1a9efSDag-Erling Smørgrav if (found) { 414acc1a9efSDag-Erling Smørgrav kex->rsa_sha2 = 512; 415acc1a9efSDag-Erling Smørgrav free(found); 416acc1a9efSDag-Erling Smørgrav } 417acc1a9efSDag-Erling Smørgrav } 418acc1a9efSDag-Erling Smørgrav free(name); 419acc1a9efSDag-Erling Smørgrav free(val); 420acc1a9efSDag-Erling Smørgrav } 421acc1a9efSDag-Erling Smørgrav return sshpkt_get_end(ssh); 422acc1a9efSDag-Erling Smørgrav } 423acc1a9efSDag-Erling Smørgrav 424bc5531deSDag-Erling Smørgrav static int 425bc5531deSDag-Erling Smørgrav kex_input_newkeys(int type, u_int32_t seq, void *ctxt) 426bc5531deSDag-Erling Smørgrav { 427bc5531deSDag-Erling Smørgrav struct ssh *ssh = ctxt; 428bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 429bc5531deSDag-Erling Smørgrav int r; 430bc5531deSDag-Erling Smørgrav 431bc5531deSDag-Erling Smørgrav debug("SSH2_MSG_NEWKEYS received"); 432bc5531deSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 433*d93a896eSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 434bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_end(ssh)) != 0) 435bc5531deSDag-Erling Smørgrav return r; 436ca86bcf2SDag-Erling Smørgrav if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0) 437ca86bcf2SDag-Erling Smørgrav return r; 4381e8db6e2SBrian Feldman kex->done = 1; 439bc5531deSDag-Erling Smørgrav sshbuf_reset(kex->peer); 440bc5531deSDag-Erling Smørgrav /* sshbuf_reset(kex->my); */ 4411e8db6e2SBrian Feldman kex->flags &= ~KEX_INIT_SENT; 442e4a9863fSDag-Erling Smørgrav free(kex->name); 4431e8db6e2SBrian Feldman kex->name = NULL; 444bc5531deSDag-Erling Smørgrav return 0; 445a04a10f8SKris Kennaway } 446a04a10f8SKris Kennaway 447bc5531deSDag-Erling Smørgrav int 448bc5531deSDag-Erling Smørgrav kex_send_kexinit(struct ssh *ssh) 449a04a10f8SKris Kennaway { 450545d5ecaSDag-Erling Smørgrav u_char *cookie; 451bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 452bc5531deSDag-Erling Smørgrav int r; 453545d5ecaSDag-Erling Smørgrav 454bc5531deSDag-Erling Smørgrav if (kex == NULL) 455bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 456bc5531deSDag-Erling Smørgrav if (kex->flags & KEX_INIT_SENT) 457bc5531deSDag-Erling Smørgrav return 0; 4581e8db6e2SBrian Feldman kex->done = 0; 459545d5ecaSDag-Erling Smørgrav 460545d5ecaSDag-Erling Smørgrav /* generate a random cookie */ 461bc5531deSDag-Erling Smørgrav if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 462bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_FORMAT; 463bc5531deSDag-Erling Smørgrav if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 464bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 465bc5531deSDag-Erling Smørgrav arc4random_buf(cookie, KEX_COOKIE_LEN); 466bc5531deSDag-Erling Smørgrav 467bc5531deSDag-Erling Smørgrav if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 468bc5531deSDag-Erling Smørgrav (r = sshpkt_putb(ssh, kex->my)) != 0 || 469bc5531deSDag-Erling Smørgrav (r = sshpkt_send(ssh)) != 0) 470bc5531deSDag-Erling Smørgrav return r; 4711e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT sent"); 4721e8db6e2SBrian Feldman kex->flags |= KEX_INIT_SENT; 473bc5531deSDag-Erling Smørgrav return 0; 4741e8db6e2SBrian Feldman } 475a04a10f8SKris Kennaway 476d4af9e69SDag-Erling Smørgrav /* ARGSUSED */ 477bc5531deSDag-Erling Smørgrav int 478ae1f160dSDag-Erling Smørgrav kex_input_kexinit(int type, u_int32_t seq, void *ctxt) 4791e8db6e2SBrian Feldman { 480bc5531deSDag-Erling Smørgrav struct ssh *ssh = ctxt; 481bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 482bc5531deSDag-Erling Smørgrav const u_char *ptr; 483bc5531deSDag-Erling Smørgrav u_int i; 484bc5531deSDag-Erling Smørgrav size_t dlen; 485bc5531deSDag-Erling Smørgrav int r; 4862632b0c8SKris Kennaway 4871e8db6e2SBrian Feldman debug("SSH2_MSG_KEXINIT received"); 4881e8db6e2SBrian Feldman if (kex == NULL) 489bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 4901e8db6e2SBrian Feldman 491ca86bcf2SDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); 492bc5531deSDag-Erling Smørgrav ptr = sshpkt_ptr(ssh, &dlen); 493bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 494bc5531deSDag-Erling Smørgrav return r; 4951e8db6e2SBrian Feldman 4961e8db6e2SBrian Feldman /* discard packet */ 4971e8db6e2SBrian Feldman for (i = 0; i < KEX_COOKIE_LEN; i++) 498bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 499bc5531deSDag-Erling Smørgrav return r; 5001e8db6e2SBrian Feldman for (i = 0; i < PROPOSAL_MAX; i++) 501bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 502bc5531deSDag-Erling Smørgrav return r; 5036888a9beSDag-Erling Smørgrav /* 5046888a9beSDag-Erling Smørgrav * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 5056888a9beSDag-Erling Smørgrav * KEX method has the server move first, but a server might be using 5066888a9beSDag-Erling Smørgrav * a custom method or one that we otherwise don't support. We should 5076888a9beSDag-Erling Smørgrav * be prepared to remember first_kex_follows here so we can eat a 5086888a9beSDag-Erling Smørgrav * packet later. 5096888a9beSDag-Erling Smørgrav * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 5106888a9beSDag-Erling Smørgrav * for cases where the server *doesn't* go first. I guess we should 5116888a9beSDag-Erling Smørgrav * ignore it when it is set for these cases, which is what we do now. 5126888a9beSDag-Erling Smørgrav */ 513bc5531deSDag-Erling Smørgrav if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 514bc5531deSDag-Erling Smørgrav (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 515bc5531deSDag-Erling Smørgrav (r = sshpkt_get_end(ssh)) != 0) 516bc5531deSDag-Erling Smørgrav return r; 5171e8db6e2SBrian Feldman 5181e8db6e2SBrian Feldman if (!(kex->flags & KEX_INIT_SENT)) 519bc5531deSDag-Erling Smørgrav if ((r = kex_send_kexinit(ssh)) != 0) 520bc5531deSDag-Erling Smørgrav return r; 521bc5531deSDag-Erling Smørgrav if ((r = kex_choose_conf(ssh)) != 0) 522bc5531deSDag-Erling Smørgrav return r; 5231e8db6e2SBrian Feldman 524bc5531deSDag-Erling Smørgrav if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 525bc5531deSDag-Erling Smørgrav return (kex->kex[kex->kex_type])(ssh); 5261e8db6e2SBrian Feldman 527bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 5281e8db6e2SBrian Feldman } 529a04a10f8SKris Kennaway 530bc5531deSDag-Erling Smørgrav int 531bc5531deSDag-Erling Smørgrav kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 532bc5531deSDag-Erling Smørgrav { 533bc5531deSDag-Erling Smørgrav struct kex *kex; 534bc5531deSDag-Erling Smørgrav int r; 535bc5531deSDag-Erling Smørgrav 536bc5531deSDag-Erling Smørgrav *kexp = NULL; 537bc5531deSDag-Erling Smørgrav if ((kex = calloc(1, sizeof(*kex))) == NULL) 538bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 539bc5531deSDag-Erling Smørgrav if ((kex->peer = sshbuf_new()) == NULL || 540bc5531deSDag-Erling Smørgrav (kex->my = sshbuf_new()) == NULL) { 541bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 542bc5531deSDag-Erling Smørgrav goto out; 543bc5531deSDag-Erling Smørgrav } 544bc5531deSDag-Erling Smørgrav if ((r = kex_prop2buf(kex->my, proposal)) != 0) 545bc5531deSDag-Erling Smørgrav goto out; 546bc5531deSDag-Erling Smørgrav kex->done = 0; 547bc5531deSDag-Erling Smørgrav kex_reset_dispatch(ssh); 548*d93a896eSDag-Erling Smørgrav ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 549bc5531deSDag-Erling Smørgrav r = 0; 550bc5531deSDag-Erling Smørgrav *kexp = kex; 551bc5531deSDag-Erling Smørgrav out: 552bc5531deSDag-Erling Smørgrav if (r != 0) 553bc5531deSDag-Erling Smørgrav kex_free(kex); 554bc5531deSDag-Erling Smørgrav return r; 555bc5531deSDag-Erling Smørgrav } 556bc5531deSDag-Erling Smørgrav 557bc5531deSDag-Erling Smørgrav void 558bc5531deSDag-Erling Smørgrav kex_free_newkeys(struct newkeys *newkeys) 559bc5531deSDag-Erling Smørgrav { 560bc5531deSDag-Erling Smørgrav if (newkeys == NULL) 561bc5531deSDag-Erling Smørgrav return; 562bc5531deSDag-Erling Smørgrav if (newkeys->enc.key) { 563bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 564bc5531deSDag-Erling Smørgrav free(newkeys->enc.key); 565bc5531deSDag-Erling Smørgrav newkeys->enc.key = NULL; 566bc5531deSDag-Erling Smørgrav } 567bc5531deSDag-Erling Smørgrav if (newkeys->enc.iv) { 568acc1a9efSDag-Erling Smørgrav explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len); 569bc5531deSDag-Erling Smørgrav free(newkeys->enc.iv); 570bc5531deSDag-Erling Smørgrav newkeys->enc.iv = NULL; 571bc5531deSDag-Erling Smørgrav } 572bc5531deSDag-Erling Smørgrav free(newkeys->enc.name); 573bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 574bc5531deSDag-Erling Smørgrav free(newkeys->comp.name); 575bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 576bc5531deSDag-Erling Smørgrav mac_clear(&newkeys->mac); 577bc5531deSDag-Erling Smørgrav if (newkeys->mac.key) { 578bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 579bc5531deSDag-Erling Smørgrav free(newkeys->mac.key); 580bc5531deSDag-Erling Smørgrav newkeys->mac.key = NULL; 581bc5531deSDag-Erling Smørgrav } 582bc5531deSDag-Erling Smørgrav free(newkeys->mac.name); 583bc5531deSDag-Erling Smørgrav explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 584bc5531deSDag-Erling Smørgrav explicit_bzero(newkeys, sizeof(*newkeys)); 585bc5531deSDag-Erling Smørgrav free(newkeys); 586bc5531deSDag-Erling Smørgrav } 587bc5531deSDag-Erling Smørgrav 588bc5531deSDag-Erling Smørgrav void 589bc5531deSDag-Erling Smørgrav kex_free(struct kex *kex) 590bc5531deSDag-Erling Smørgrav { 591bc5531deSDag-Erling Smørgrav u_int mode; 592bc5531deSDag-Erling Smørgrav 593bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL 594bc5531deSDag-Erling Smørgrav if (kex->dh) 595bc5531deSDag-Erling Smørgrav DH_free(kex->dh); 596bc5531deSDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 597bc5531deSDag-Erling Smørgrav if (kex->ec_client_key) 598bc5531deSDag-Erling Smørgrav EC_KEY_free(kex->ec_client_key); 599bc5531deSDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 600bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 601bc5531deSDag-Erling Smørgrav for (mode = 0; mode < MODE_MAX; mode++) { 602bc5531deSDag-Erling Smørgrav kex_free_newkeys(kex->newkeys[mode]); 603bc5531deSDag-Erling Smørgrav kex->newkeys[mode] = NULL; 604bc5531deSDag-Erling Smørgrav } 605bc5531deSDag-Erling Smørgrav sshbuf_free(kex->peer); 606bc5531deSDag-Erling Smørgrav sshbuf_free(kex->my); 607bc5531deSDag-Erling Smørgrav free(kex->session_id); 608bc5531deSDag-Erling Smørgrav free(kex->client_version_string); 609bc5531deSDag-Erling Smørgrav free(kex->server_version_string); 610eccfee6eSDag-Erling Smørgrav free(kex->failed_choice); 611acc1a9efSDag-Erling Smørgrav free(kex->hostkey_alg); 612acc1a9efSDag-Erling Smørgrav free(kex->name); 613bc5531deSDag-Erling Smørgrav free(kex); 614bc5531deSDag-Erling Smørgrav } 615bc5531deSDag-Erling Smørgrav 616bc5531deSDag-Erling Smørgrav int 617bc5531deSDag-Erling Smørgrav kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 618bc5531deSDag-Erling Smørgrav { 619bc5531deSDag-Erling Smørgrav int r; 620bc5531deSDag-Erling Smørgrav 621bc5531deSDag-Erling Smørgrav if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 622bc5531deSDag-Erling Smørgrav return r; 623bc5531deSDag-Erling Smørgrav if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 624bc5531deSDag-Erling Smørgrav kex_free(ssh->kex); 625bc5531deSDag-Erling Smørgrav ssh->kex = NULL; 626bc5531deSDag-Erling Smørgrav return r; 627bc5531deSDag-Erling Smørgrav } 628bc5531deSDag-Erling Smørgrav return 0; 629bc5531deSDag-Erling Smørgrav } 630bc5531deSDag-Erling Smørgrav 631acc1a9efSDag-Erling Smørgrav /* 632acc1a9efSDag-Erling Smørgrav * Request key re-exchange, returns 0 on success or a ssherr.h error 633acc1a9efSDag-Erling Smørgrav * code otherwise. Must not be called if KEX is incomplete or in-progress. 634acc1a9efSDag-Erling Smørgrav */ 635acc1a9efSDag-Erling Smørgrav int 636acc1a9efSDag-Erling Smørgrav kex_start_rekex(struct ssh *ssh) 637acc1a9efSDag-Erling Smørgrav { 638acc1a9efSDag-Erling Smørgrav if (ssh->kex == NULL) { 639acc1a9efSDag-Erling Smørgrav error("%s: no kex", __func__); 640acc1a9efSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 641acc1a9efSDag-Erling Smørgrav } 642acc1a9efSDag-Erling Smørgrav if (ssh->kex->done == 0) { 643acc1a9efSDag-Erling Smørgrav error("%s: requested twice", __func__); 644acc1a9efSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 645acc1a9efSDag-Erling Smørgrav } 646acc1a9efSDag-Erling Smørgrav ssh->kex->done = 0; 647acc1a9efSDag-Erling Smørgrav return kex_send_kexinit(ssh); 648acc1a9efSDag-Erling Smørgrav } 649acc1a9efSDag-Erling Smørgrav 650bc5531deSDag-Erling Smørgrav static int 651bc5531deSDag-Erling Smørgrav choose_enc(struct sshenc *enc, char *client, char *server) 652a04a10f8SKris Kennaway { 6531e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 654bc5531deSDag-Erling Smørgrav 655a04a10f8SKris Kennaway if (name == NULL) 656bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_CIPHER_ALG_MATCH; 657*d93a896eSDag-Erling Smørgrav if ((enc->cipher = cipher_by_name(name)) == NULL) { 658*d93a896eSDag-Erling Smørgrav free(name); 659bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 660*d93a896eSDag-Erling Smørgrav } 661a04a10f8SKris Kennaway enc->name = name; 662a04a10f8SKris Kennaway enc->enabled = 0; 663a04a10f8SKris Kennaway enc->iv = NULL; 6646888a9beSDag-Erling Smørgrav enc->iv_len = cipher_ivlen(enc->cipher); 665a04a10f8SKris Kennaway enc->key = NULL; 666ae1f160dSDag-Erling Smørgrav enc->key_len = cipher_keylen(enc->cipher); 667ae1f160dSDag-Erling Smørgrav enc->block_size = cipher_blocksize(enc->cipher); 668bc5531deSDag-Erling Smørgrav return 0; 669a04a10f8SKris Kennaway } 670761efaa7SDag-Erling Smørgrav 671bc5531deSDag-Erling Smørgrav static int 672bc5531deSDag-Erling Smørgrav choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 673a04a10f8SKris Kennaway { 6741e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 675bc5531deSDag-Erling Smørgrav 676a04a10f8SKris Kennaway if (name == NULL) 677bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_MAC_ALG_MATCH; 678*d93a896eSDag-Erling Smørgrav if (mac_setup(mac, name) < 0) { 679*d93a896eSDag-Erling Smørgrav free(name); 680bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 681*d93a896eSDag-Erling Smørgrav } 6821e8db6e2SBrian Feldman /* truncate the key */ 683bc5531deSDag-Erling Smørgrav if (ssh->compat & SSH_BUG_HMAC) 6841e8db6e2SBrian Feldman mac->key_len = 16; 685a04a10f8SKris Kennaway mac->name = name; 686a04a10f8SKris Kennaway mac->key = NULL; 687a04a10f8SKris Kennaway mac->enabled = 0; 688bc5531deSDag-Erling Smørgrav return 0; 689a04a10f8SKris Kennaway } 690761efaa7SDag-Erling Smørgrav 691bc5531deSDag-Erling Smørgrav static int 692bc5531deSDag-Erling Smørgrav choose_comp(struct sshcomp *comp, char *client, char *server) 693a04a10f8SKris Kennaway { 6941e8db6e2SBrian Feldman char *name = match_list(client, server, NULL); 695bc5531deSDag-Erling Smørgrav 696a04a10f8SKris Kennaway if (name == NULL) 697bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_COMPRESS_ALG_MATCH; 698043840dfSDag-Erling Smørgrav if (strcmp(name, "zlib@openssh.com") == 0) { 699043840dfSDag-Erling Smørgrav comp->type = COMP_DELAYED; 700043840dfSDag-Erling Smørgrav } else if (strcmp(name, "zlib") == 0) { 701043840dfSDag-Erling Smørgrav comp->type = COMP_ZLIB; 702a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 703043840dfSDag-Erling Smørgrav comp->type = COMP_NONE; 704a04a10f8SKris Kennaway } else { 705*d93a896eSDag-Erling Smørgrav free(name); 706bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 707a04a10f8SKris Kennaway } 708a04a10f8SKris Kennaway comp->name = name; 709bc5531deSDag-Erling Smørgrav return 0; 710a04a10f8SKris Kennaway } 711761efaa7SDag-Erling Smørgrav 712bc5531deSDag-Erling Smørgrav static int 713bc5531deSDag-Erling Smørgrav choose_kex(struct kex *k, char *client, char *server) 714a04a10f8SKris Kennaway { 715e4a9863fSDag-Erling Smørgrav const struct kexalg *kexalg; 716e4a9863fSDag-Erling Smørgrav 7171e8db6e2SBrian Feldman k->name = match_list(client, server, NULL); 718bc5531deSDag-Erling Smørgrav 719acc1a9efSDag-Erling Smørgrav debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); 720a04a10f8SKris Kennaway if (k->name == NULL) 721bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_KEX_ALG_MATCH; 722e4a9863fSDag-Erling Smørgrav if ((kexalg = kex_alg_by_name(k->name)) == NULL) 723bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 724e4a9863fSDag-Erling Smørgrav k->kex_type = kexalg->type; 725f7167e0eSDag-Erling Smørgrav k->hash_alg = kexalg->hash_alg; 726e4a9863fSDag-Erling Smørgrav k->ec_nid = kexalg->ec_nid; 727bc5531deSDag-Erling Smørgrav return 0; 728a04a10f8SKris Kennaway } 729021d409fSDag-Erling Smørgrav 730bc5531deSDag-Erling Smørgrav static int 731bc5531deSDag-Erling Smørgrav choose_hostkeyalg(struct kex *k, char *client, char *server) 732a04a10f8SKris Kennaway { 733acc1a9efSDag-Erling Smørgrav k->hostkey_alg = match_list(client, server, NULL); 734bc5531deSDag-Erling Smørgrav 735acc1a9efSDag-Erling Smørgrav debug("kex: host key algorithm: %s", 736acc1a9efSDag-Erling Smørgrav k->hostkey_alg ? k->hostkey_alg : "(no match)"); 737acc1a9efSDag-Erling Smørgrav if (k->hostkey_alg == NULL) 738bc5531deSDag-Erling Smørgrav return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 739acc1a9efSDag-Erling Smørgrav k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); 7401e8db6e2SBrian Feldman if (k->hostkey_type == KEY_UNSPEC) 741bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 742acc1a9efSDag-Erling Smørgrav k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); 743bc5531deSDag-Erling Smørgrav return 0; 744a04a10f8SKris Kennaway } 745a04a10f8SKris Kennaway 746d0c8c0bcSDag-Erling Smørgrav static int 747d0c8c0bcSDag-Erling Smørgrav proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 748d0c8c0bcSDag-Erling Smørgrav { 749d0c8c0bcSDag-Erling Smørgrav static int check[] = { 750d0c8c0bcSDag-Erling Smørgrav PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 751d0c8c0bcSDag-Erling Smørgrav }; 752d0c8c0bcSDag-Erling Smørgrav int *idx; 753d0c8c0bcSDag-Erling Smørgrav char *p; 754d0c8c0bcSDag-Erling Smørgrav 755d0c8c0bcSDag-Erling Smørgrav for (idx = &check[0]; *idx != -1; idx++) { 756d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(my[*idx], ',')) != NULL) 757d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 758d0c8c0bcSDag-Erling Smørgrav if ((p = strchr(peer[*idx], ',')) != NULL) 759d0c8c0bcSDag-Erling Smørgrav *p = '\0'; 760d0c8c0bcSDag-Erling Smørgrav if (strcmp(my[*idx], peer[*idx]) != 0) { 761d0c8c0bcSDag-Erling Smørgrav debug2("proposal mismatch: my %s peer %s", 762d0c8c0bcSDag-Erling Smørgrav my[*idx], peer[*idx]); 763d0c8c0bcSDag-Erling Smørgrav return (0); 764d0c8c0bcSDag-Erling Smørgrav } 765d0c8c0bcSDag-Erling Smørgrav } 766d0c8c0bcSDag-Erling Smørgrav debug2("proposals match"); 767d0c8c0bcSDag-Erling Smørgrav return (1); 768d0c8c0bcSDag-Erling Smørgrav } 769d0c8c0bcSDag-Erling Smørgrav 770bc5531deSDag-Erling Smørgrav static int 771bc5531deSDag-Erling Smørgrav kex_choose_conf(struct ssh *ssh) 772a04a10f8SKris Kennaway { 773bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 774bc5531deSDag-Erling Smørgrav struct newkeys *newkeys; 775bc5531deSDag-Erling Smørgrav char **my = NULL, **peer = NULL; 7761e8db6e2SBrian Feldman char **cprop, **sprop; 7771e8db6e2SBrian Feldman int nenc, nmac, ncomp; 778f7167e0eSDag-Erling Smørgrav u_int mode, ctos, need, dh_need, authlen; 779bc5531deSDag-Erling Smørgrav int r, first_kex_follows; 780a04a10f8SKris Kennaway 781acc1a9efSDag-Erling Smørgrav debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); 782acc1a9efSDag-Erling Smørgrav if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) 783acc1a9efSDag-Erling Smørgrav goto out; 784acc1a9efSDag-Erling Smørgrav debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server"); 785acc1a9efSDag-Erling Smørgrav if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 786bc5531deSDag-Erling Smørgrav goto out; 787a04a10f8SKris Kennaway 7881e8db6e2SBrian Feldman if (kex->server) { 7891e8db6e2SBrian Feldman cprop=peer; 7901e8db6e2SBrian Feldman sprop=my; 7911e8db6e2SBrian Feldman } else { 7921e8db6e2SBrian Feldman cprop=my; 7931e8db6e2SBrian Feldman sprop=peer; 7941e8db6e2SBrian Feldman } 7951e8db6e2SBrian Feldman 796acc1a9efSDag-Erling Smørgrav /* Check whether client supports ext_info_c */ 797acc1a9efSDag-Erling Smørgrav if (kex->server) { 798acc1a9efSDag-Erling Smørgrav char *ext; 799bc5531deSDag-Erling Smørgrav 800acc1a9efSDag-Erling Smørgrav ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); 801ca86bcf2SDag-Erling Smørgrav kex->ext_info_c = (ext != NULL); 802acc1a9efSDag-Erling Smørgrav free(ext); 803b15c8340SDag-Erling Smørgrav } 804b15c8340SDag-Erling Smørgrav 8051e8db6e2SBrian Feldman /* Algorithm Negotiation */ 806acc1a9efSDag-Erling Smørgrav if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 807acc1a9efSDag-Erling Smørgrav sprop[PROPOSAL_KEX_ALGS])) != 0) { 808acc1a9efSDag-Erling Smørgrav kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; 809acc1a9efSDag-Erling Smørgrav peer[PROPOSAL_KEX_ALGS] = NULL; 810acc1a9efSDag-Erling Smørgrav goto out; 811acc1a9efSDag-Erling Smørgrav } 812acc1a9efSDag-Erling Smørgrav if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 813acc1a9efSDag-Erling Smørgrav sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { 814acc1a9efSDag-Erling Smørgrav kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; 815acc1a9efSDag-Erling Smørgrav peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; 816acc1a9efSDag-Erling Smørgrav goto out; 817acc1a9efSDag-Erling Smørgrav } 818a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 819bc5531deSDag-Erling Smørgrav if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 820bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 821bc5531deSDag-Erling Smørgrav goto out; 822bc5531deSDag-Erling Smørgrav } 8231e8db6e2SBrian Feldman kex->newkeys[mode] = newkeys; 824d4af9e69SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 825d4af9e69SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 826a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 827a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 828a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 829bc5531deSDag-Erling Smørgrav if ((r = choose_enc(&newkeys->enc, cprop[nenc], 830eccfee6eSDag-Erling Smørgrav sprop[nenc])) != 0) { 831eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[nenc]; 832eccfee6eSDag-Erling Smørgrav peer[nenc] = NULL; 833bc5531deSDag-Erling Smørgrav goto out; 834eccfee6eSDag-Erling Smørgrav } 8356888a9beSDag-Erling Smørgrav authlen = cipher_authlen(newkeys->enc.cipher); 836bc5531deSDag-Erling Smørgrav /* ignore mac for authenticated encryption */ 837bc5531deSDag-Erling Smørgrav if (authlen == 0 && 838bc5531deSDag-Erling Smørgrav (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 839eccfee6eSDag-Erling Smørgrav sprop[nmac])) != 0) { 840eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[nmac]; 841eccfee6eSDag-Erling Smørgrav peer[nmac] = NULL; 842bc5531deSDag-Erling Smørgrav goto out; 843eccfee6eSDag-Erling Smørgrav } 844bc5531deSDag-Erling Smørgrav if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 845eccfee6eSDag-Erling Smørgrav sprop[ncomp])) != 0) { 846eccfee6eSDag-Erling Smørgrav kex->failed_choice = peer[ncomp]; 847eccfee6eSDag-Erling Smørgrav peer[ncomp] = NULL; 848bc5531deSDag-Erling Smørgrav goto out; 849eccfee6eSDag-Erling Smørgrav } 850acc1a9efSDag-Erling Smørgrav debug("kex: %s cipher: %s MAC: %s compression: %s", 851a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 8521e8db6e2SBrian Feldman newkeys->enc.name, 8536888a9beSDag-Erling Smørgrav authlen == 0 ? newkeys->mac.name : "<implicit>", 8541e8db6e2SBrian Feldman newkeys->comp.name); 855a04a10f8SKris Kennaway } 856f7167e0eSDag-Erling Smørgrav need = dh_need = 0; 857a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 8581e8db6e2SBrian Feldman newkeys = kex->newkeys[mode]; 859ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.key_len); 860ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.block_size); 861ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->enc.iv_len); 862ca86bcf2SDag-Erling Smørgrav need = MAXIMUM(need, newkeys->mac.key_len); 863ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, cipher_seclen(newkeys->enc.cipher)); 864ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->enc.block_size); 865ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len); 866ca86bcf2SDag-Erling Smørgrav dh_need = MAXIMUM(dh_need, newkeys->mac.key_len); 867a04a10f8SKris Kennaway } 8682632b0c8SKris Kennaway /* XXX need runden? */ 8691e8db6e2SBrian Feldman kex->we_need = need; 870f7167e0eSDag-Erling Smørgrav kex->dh_need = dh_need; 8711e8db6e2SBrian Feldman 872d0c8c0bcSDag-Erling Smørgrav /* ignore the next message if the proposals do not match */ 873d0c8c0bcSDag-Erling Smørgrav if (first_kex_follows && !proposals_match(my, peer) && 874bc5531deSDag-Erling Smørgrav !(ssh->compat & SSH_BUG_FIRSTKEX)) 875bc5531deSDag-Erling Smørgrav ssh->dispatch_skip_packets = 1; 876bc5531deSDag-Erling Smørgrav r = 0; 877bc5531deSDag-Erling Smørgrav out: 8781e8db6e2SBrian Feldman kex_prop_free(my); 8791e8db6e2SBrian Feldman kex_prop_free(peer); 880bc5531deSDag-Erling Smørgrav return r; 881a04a10f8SKris Kennaway } 882a04a10f8SKris Kennaway 883bc5531deSDag-Erling Smørgrav static int 884bc5531deSDag-Erling Smørgrav derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 885bc5531deSDag-Erling Smørgrav const struct sshbuf *shared_secret, u_char **keyp) 886a04a10f8SKris Kennaway { 887bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 888bc5531deSDag-Erling Smørgrav struct ssh_digest_ctx *hashctx = NULL; 8891e8db6e2SBrian Feldman char c = id; 890043840dfSDag-Erling Smørgrav u_int have; 891f7167e0eSDag-Erling Smørgrav size_t mdsz; 892043840dfSDag-Erling Smørgrav u_char *digest; 893bc5531deSDag-Erling Smørgrav int r; 894043840dfSDag-Erling Smørgrav 895f7167e0eSDag-Erling Smørgrav if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 896bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 897ca86bcf2SDag-Erling Smørgrav if ((digest = calloc(1, ROUNDUP(need, mdsz))) == NULL) { 898bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 899bc5531deSDag-Erling Smørgrav goto out; 900bc5531deSDag-Erling Smørgrav } 9011e8db6e2SBrian Feldman 9021e8db6e2SBrian Feldman /* K1 = HASH(K || H || "A" || session_id) */ 903bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 904bc5531deSDag-Erling Smørgrav ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 905f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, hash, hashlen) != 0 || 906f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, &c, 1) != 0 || 907f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, kex->session_id, 908bc5531deSDag-Erling Smørgrav kex->session_id_len) != 0 || 909bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, digest, mdsz) != 0) { 910bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 911bc5531deSDag-Erling Smørgrav goto out; 912bc5531deSDag-Erling Smørgrav } 913f7167e0eSDag-Erling Smørgrav ssh_digest_free(hashctx); 914bc5531deSDag-Erling Smørgrav hashctx = NULL; 9151e8db6e2SBrian Feldman 9161e8db6e2SBrian Feldman /* 9171e8db6e2SBrian Feldman * expand key: 9181e8db6e2SBrian Feldman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 9191e8db6e2SBrian Feldman * Key = K1 || K2 || ... || Kn 9201e8db6e2SBrian Feldman */ 9211e8db6e2SBrian Feldman for (have = mdsz; need > have; have += mdsz) { 922bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 923bc5531deSDag-Erling Smørgrav ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 924f7167e0eSDag-Erling Smørgrav ssh_digest_update(hashctx, hash, hashlen) != 0 || 925bc5531deSDag-Erling Smørgrav ssh_digest_update(hashctx, digest, have) != 0 || 926bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 927bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 928bc5531deSDag-Erling Smørgrav goto out; 9291e8db6e2SBrian Feldman } 930bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 931bc5531deSDag-Erling Smørgrav hashctx = NULL; 932bc5531deSDag-Erling Smørgrav } 9331e8db6e2SBrian Feldman #ifdef DEBUG_KEX 9341e8db6e2SBrian Feldman fprintf(stderr, "key '%c'== ", c); 9351e8db6e2SBrian Feldman dump_digest("key", digest, need); 9361e8db6e2SBrian Feldman #endif 937bc5531deSDag-Erling Smørgrav *keyp = digest; 938bc5531deSDag-Erling Smørgrav digest = NULL; 939bc5531deSDag-Erling Smørgrav r = 0; 940bc5531deSDag-Erling Smørgrav out: 941bc5531deSDag-Erling Smørgrav free(digest); 942bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 943bc5531deSDag-Erling Smørgrav return r; 9441e8db6e2SBrian Feldman } 9451e8db6e2SBrian Feldman 9461e8db6e2SBrian Feldman #define NKEYS 6 947bc5531deSDag-Erling Smørgrav int 948bc5531deSDag-Erling Smørgrav kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 949bc5531deSDag-Erling Smørgrav const struct sshbuf *shared_secret) 9501e8db6e2SBrian Feldman { 951bc5531deSDag-Erling Smørgrav struct kex *kex = ssh->kex; 9521e8db6e2SBrian Feldman u_char *keys[NKEYS]; 953bc5531deSDag-Erling Smørgrav u_int i, j, mode, ctos; 954bc5531deSDag-Erling Smørgrav int r; 955a04a10f8SKris Kennaway 956021d409fSDag-Erling Smørgrav for (i = 0; i < NKEYS; i++) { 957bc5531deSDag-Erling Smørgrav if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 958bc5531deSDag-Erling Smørgrav shared_secret, &keys[i])) != 0) { 959bc5531deSDag-Erling Smørgrav for (j = 0; j < i; j++) 960bc5531deSDag-Erling Smørgrav free(keys[j]); 961bc5531deSDag-Erling Smørgrav return r; 962021d409fSDag-Erling Smørgrav } 963bc5531deSDag-Erling Smørgrav } 964a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 965761efaa7SDag-Erling Smørgrav ctos = (!kex->server && mode == MODE_OUT) || 966761efaa7SDag-Erling Smørgrav (kex->server && mode == MODE_IN); 967bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 968bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 969bc5531deSDag-Erling Smørgrav kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 970a04a10f8SKris Kennaway } 971bc5531deSDag-Erling Smørgrav return 0; 972a04a10f8SKris Kennaway } 9731e8db6e2SBrian Feldman 974a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL 975bc5531deSDag-Erling Smørgrav int 976bc5531deSDag-Erling Smørgrav kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 977bc5531deSDag-Erling Smørgrav const BIGNUM *secret) 978f7167e0eSDag-Erling Smørgrav { 979bc5531deSDag-Erling Smørgrav struct sshbuf *shared_secret; 980bc5531deSDag-Erling Smørgrav int r; 981f7167e0eSDag-Erling Smørgrav 982bc5531deSDag-Erling Smørgrav if ((shared_secret = sshbuf_new()) == NULL) 983bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 984bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 985bc5531deSDag-Erling Smørgrav r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 986bc5531deSDag-Erling Smørgrav sshbuf_free(shared_secret); 987bc5531deSDag-Erling Smørgrav return r; 988f7167e0eSDag-Erling Smørgrav } 989a0ee8cc6SDag-Erling Smørgrav #endif 990f7167e0eSDag-Erling Smørgrav 991a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_SSH1 992bc5531deSDag-Erling Smørgrav int 993d74d50a8SDag-Erling Smørgrav derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 994d74d50a8SDag-Erling Smørgrav u_int8_t cookie[8], u_int8_t id[16]) 995d74d50a8SDag-Erling Smørgrav { 996bc5531deSDag-Erling Smørgrav u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; 997bc5531deSDag-Erling Smørgrav struct ssh_digest_ctx *hashctx = NULL; 998bc5531deSDag-Erling Smørgrav size_t hlen, slen; 999bc5531deSDag-Erling Smørgrav int r; 1000d74d50a8SDag-Erling Smørgrav 1001bc5531deSDag-Erling Smørgrav hlen = BN_num_bytes(host_modulus); 1002bc5531deSDag-Erling Smørgrav slen = BN_num_bytes(server_modulus); 1003bc5531deSDag-Erling Smørgrav if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || 1004bc5531deSDag-Erling Smørgrav slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) 1005bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_BITS_MISMATCH; 1006bc5531deSDag-Erling Smørgrav if (BN_bn2bin(host_modulus, hbuf) <= 0 || 1007bc5531deSDag-Erling Smørgrav BN_bn2bin(server_modulus, sbuf) <= 0) { 1008bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 1009bc5531deSDag-Erling Smørgrav goto out; 1010bc5531deSDag-Erling Smørgrav } 1011bc5531deSDag-Erling Smørgrav if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { 1012bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 1013bc5531deSDag-Erling Smørgrav goto out; 1014bc5531deSDag-Erling Smørgrav } 1015bc5531deSDag-Erling Smørgrav if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || 1016bc5531deSDag-Erling Smørgrav ssh_digest_update(hashctx, sbuf, slen) != 0 || 1017bc5531deSDag-Erling Smørgrav ssh_digest_update(hashctx, cookie, 8) != 0 || 1018bc5531deSDag-Erling Smørgrav ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { 1019bc5531deSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 1020bc5531deSDag-Erling Smørgrav goto out; 1021bc5531deSDag-Erling Smørgrav } 1022f7167e0eSDag-Erling Smørgrav memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); 1023bc5531deSDag-Erling Smørgrav r = 0; 1024bc5531deSDag-Erling Smørgrav out: 1025bc5531deSDag-Erling Smørgrav ssh_digest_free(hashctx); 1026bc5531deSDag-Erling Smørgrav explicit_bzero(hbuf, sizeof(hbuf)); 1027bc5531deSDag-Erling Smørgrav explicit_bzero(sbuf, sizeof(sbuf)); 1028b83788ffSDag-Erling Smørgrav explicit_bzero(obuf, sizeof(obuf)); 1029bc5531deSDag-Erling Smørgrav return r; 1030d74d50a8SDag-Erling Smørgrav } 1031a0ee8cc6SDag-Erling Smørgrav #endif 1032d74d50a8SDag-Erling Smørgrav 10334a421b63SDag-Erling Smørgrav #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 10341e8db6e2SBrian Feldman void 10351e8db6e2SBrian Feldman dump_digest(char *msg, u_char *digest, int len) 10361e8db6e2SBrian Feldman { 10371e8db6e2SBrian Feldman fprintf(stderr, "%s\n", msg); 1038bc5531deSDag-Erling Smørgrav sshbuf_dump_data(digest, len, stderr); 10391e8db6e2SBrian Feldman } 10401e8db6e2SBrian Feldman #endif 1041