1d059297112922cabb0c674840589be8db821fd9aAdam Langley/* $OpenBSD: kex.c,v 1.105 2015/01/30 00:22:25 djm Exp $ */ 2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Redistribution and use in source and binary forms, with or without 6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * modification, are permitted provided that the following conditions 7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * are met: 8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 1. Redistributions of source code must retain the above copyright 9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * notice, this list of conditions and the following disclaimer. 10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 2. Redistributions in binary form must reproduce the above copyright 11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * notice, this list of conditions and the following disclaimer in the 12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * documentation and/or other materials provided with the distribution. 13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h" 27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 28d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <sys/param.h> /* MAX roundup */ 29bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 30bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <signal.h> 31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdarg.h> 32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdio.h> 33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdlib.h> 34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h> 35bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 36d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL 37bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <openssl/crypto.h> 38d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <openssl/dh.h> 39d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif 40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh2.h" 42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "packet.h" 43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "compat.h" 44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "cipher.h" 45d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshkey.h" 46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "kex.h" 47bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h" 48bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "mac.h" 49bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "match.h" 50d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "misc.h" 51bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "dispatch.h" 52bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "monitor.h" 53bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "roaming.h" 54bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 55d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h" 56d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshbuf.h" 57d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "digest.h" 58d059297112922cabb0c674840589be8db821fd9aAdam Langley 59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#if OPENSSL_VERSION_NUMBER >= 0x00907000L 60bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# if defined(HAVE_EVP_SHA256) 61bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# define evp_ssh_sha256 EVP_sha256 62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# else 63bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern const EVP_MD *evp_ssh_sha256(void); 64bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# endif 65bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 66bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* prototype */ 68d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int kex_choose_conf(struct ssh *); 69d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int kex_input_newkeys(int, u_int32_t, void *); 70d059297112922cabb0c674840589be8db821fd9aAdam Langley 71d059297112922cabb0c674840589be8db821fd9aAdam Langleystruct kexalg { 72d059297112922cabb0c674840589be8db821fd9aAdam Langley char *name; 73d059297112922cabb0c674840589be8db821fd9aAdam Langley u_int type; 74d059297112922cabb0c674840589be8db821fd9aAdam Langley int ec_nid; 75d059297112922cabb0c674840589be8db821fd9aAdam Langley int hash_alg; 76d059297112922cabb0c674840589be8db821fd9aAdam Langley}; 77d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic const struct kexalg kexalgs[] = { 78d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL 79d059297112922cabb0c674840589be8db821fd9aAdam Langley { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 80d059297112922cabb0c674840589be8db821fd9aAdam Langley { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 81d059297112922cabb0c674840589be8db821fd9aAdam Langley { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 82d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef HAVE_EVP_SHA256 83d059297112922cabb0c674840589be8db821fd9aAdam Langley { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 84d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* HAVE_EVP_SHA256 */ 85d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef OPENSSL_HAS_ECC 86d059297112922cabb0c674840589be8db821fd9aAdam Langley { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 87d059297112922cabb0c674840589be8db821fd9aAdam Langley NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 88d059297112922cabb0c674840589be8db821fd9aAdam Langley { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, 89d059297112922cabb0c674840589be8db821fd9aAdam Langley SSH_DIGEST_SHA384 }, 90d059297112922cabb0c674840589be8db821fd9aAdam Langley# ifdef OPENSSL_HAS_NISTP521 91d059297112922cabb0c674840589be8db821fd9aAdam Langley { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 92d059297112922cabb0c674840589be8db821fd9aAdam Langley SSH_DIGEST_SHA512 }, 93d059297112922cabb0c674840589be8db821fd9aAdam Langley# endif /* OPENSSL_HAS_NISTP521 */ 94d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* OPENSSL_HAS_ECC */ 95d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_OPENSSL */ 96d059297112922cabb0c674840589be8db821fd9aAdam Langley#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) 97d059297112922cabb0c674840589be8db821fd9aAdam Langley { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 98d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 99d059297112922cabb0c674840589be8db821fd9aAdam Langley { NULL, -1, -1, -1}, 100d059297112922cabb0c674840589be8db821fd9aAdam Langley}; 101d059297112922cabb0c674840589be8db821fd9aAdam Langley 102d059297112922cabb0c674840589be8db821fd9aAdam Langleychar * 103d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_alg_list(char sep) 104d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 105d059297112922cabb0c674840589be8db821fd9aAdam Langley char *ret = NULL, *tmp; 106d059297112922cabb0c674840589be8db821fd9aAdam Langley size_t nlen, rlen = 0; 107d059297112922cabb0c674840589be8db821fd9aAdam Langley const struct kexalg *k; 108d059297112922cabb0c674840589be8db821fd9aAdam Langley 109d059297112922cabb0c674840589be8db821fd9aAdam Langley for (k = kexalgs; k->name != NULL; k++) { 110d059297112922cabb0c674840589be8db821fd9aAdam Langley if (ret != NULL) 111d059297112922cabb0c674840589be8db821fd9aAdam Langley ret[rlen++] = sep; 112d059297112922cabb0c674840589be8db821fd9aAdam Langley nlen = strlen(k->name); 113d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 114d059297112922cabb0c674840589be8db821fd9aAdam Langley free(ret); 115d059297112922cabb0c674840589be8db821fd9aAdam Langley return NULL; 116d059297112922cabb0c674840589be8db821fd9aAdam Langley } 117d059297112922cabb0c674840589be8db821fd9aAdam Langley ret = tmp; 118d059297112922cabb0c674840589be8db821fd9aAdam Langley memcpy(ret + rlen, k->name, nlen + 1); 119d059297112922cabb0c674840589be8db821fd9aAdam Langley rlen += nlen; 120d059297112922cabb0c674840589be8db821fd9aAdam Langley } 121d059297112922cabb0c674840589be8db821fd9aAdam Langley return ret; 122d059297112922cabb0c674840589be8db821fd9aAdam Langley} 123d059297112922cabb0c674840589be8db821fd9aAdam Langley 124d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic const struct kexalg * 125d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_alg_by_name(const char *name) 126d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 127d059297112922cabb0c674840589be8db821fd9aAdam Langley const struct kexalg *k; 128d059297112922cabb0c674840589be8db821fd9aAdam Langley 129d059297112922cabb0c674840589be8db821fd9aAdam Langley for (k = kexalgs; k->name != NULL; k++) { 130d059297112922cabb0c674840589be8db821fd9aAdam Langley if (strcmp(k->name, name) == 0) 131d059297112922cabb0c674840589be8db821fd9aAdam Langley return k; 132d059297112922cabb0c674840589be8db821fd9aAdam Langley } 133d059297112922cabb0c674840589be8db821fd9aAdam Langley return NULL; 134d059297112922cabb0c674840589be8db821fd9aAdam Langley} 135bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 136bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Validate KEX method name list */ 137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint 138bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmankex_names_valid(const char *names) 139bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *s, *cp, *p; 141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 142bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (names == NULL || strcmp(names, "") == 0) 143bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 144d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((s = cp = strdup(names)) == NULL) 145d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 146bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for ((p = strsep(&cp, ",")); p && *p != '\0'; 147bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (p = strsep(&cp, ","))) { 148d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex_alg_by_name(p) == NULL) { 149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Unsupported KEX algorithm \"%.100s\"", p); 150d059297112922cabb0c674840589be8db821fd9aAdam Langley free(s); 151bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 152bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 154bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug3("kex names ok: [%s]", names); 155d059297112922cabb0c674840589be8db821fd9aAdam Langley free(s); 156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 1; 157bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 158bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* put algorithm proposal into buffer */ 160d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 161d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 163bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int i; 164d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 165d059297112922cabb0c674840589be8db821fd9aAdam Langley 166d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_reset(b); 167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * add a dummy cookie, the cookie will be overwritten by 170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * kex_send_kexinit(), each time a kexinit is set 171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 172d059297112922cabb0c674840589be8db821fd9aAdam Langley for (i = 0; i < KEX_COOKIE_LEN; i++) { 173d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshbuf_put_u8(b, 0)) != 0) 174d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 175d059297112922cabb0c674840589be8db821fd9aAdam Langley } 176d059297112922cabb0c674840589be8db821fd9aAdam Langley for (i = 0; i < PROPOSAL_MAX; i++) { 177d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) 178d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 179d059297112922cabb0c674840589be8db821fd9aAdam Langley } 180d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ 181d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ 182d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 183d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 184bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 186bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* parse buffer and return algorithm proposal */ 187d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 188d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) 189bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 190d059297112922cabb0c674840589be8db821fd9aAdam Langley struct sshbuf *b = NULL; 191d059297112922cabb0c674840589be8db821fd9aAdam Langley u_char v; 192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int i; 193d059297112922cabb0c674840589be8db821fd9aAdam Langley char **proposal = NULL; 194d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 195d059297112922cabb0c674840589be8db821fd9aAdam Langley 196d059297112922cabb0c674840589be8db821fd9aAdam Langley *propp = NULL; 197d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) 198d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_ALLOC_FAIL; 199d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((b = sshbuf_fromb(raw)) == NULL) { 200d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 201d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 202d059297112922cabb0c674840589be8db821fd9aAdam Langley } 203d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 204d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 205bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* extract kex init proposal strings */ 206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < PROPOSAL_MAX; i++) { 207d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 208d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("kex_parse_kexinit: %s", proposal[i]); 210bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* first kex follows / reserved */ 212d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshbuf_get_u8(b, &v)) != 0 || 213d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshbuf_get_u32(b, &i)) != 0) 214d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 215bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (first_kex_follows != NULL) 216bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *first_kex_follows = i; 217d059297112922cabb0c674840589be8db821fd9aAdam Langley debug2("kex_parse_kexinit: first_kex_follows %d ", v); 218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("kex_parse_kexinit: reserved %u ", i); 219d059297112922cabb0c674840589be8db821fd9aAdam Langley r = 0; 220d059297112922cabb0c674840589be8db821fd9aAdam Langley *propp = proposal; 221d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 222d059297112922cabb0c674840589be8db821fd9aAdam Langley if (r != 0 && proposal != NULL) 223d059297112922cabb0c674840589be8db821fd9aAdam Langley kex_prop_free(proposal); 224d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_free(b); 225d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 226bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 227bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 228d059297112922cabb0c674840589be8db821fd9aAdam Langleyvoid 229bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmankex_prop_free(char **proposal) 230bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 231bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int i; 232bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 233bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < PROPOSAL_MAX; i++) 234d059297112922cabb0c674840589be8db821fd9aAdam Langley free(proposal[i]); 235d059297112922cabb0c674840589be8db821fd9aAdam Langley free(proposal); 236bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 237bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 238bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* ARGSUSED */ 239d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 240bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmankex_protocol_error(int type, u_int32_t seq, void *ctxt) 241bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 242bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Hm, kex protocol error: type %d seq %u", type, seq); 243d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 244bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 245bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 246bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void 247d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_reset_dispatch(struct ssh *ssh) 248bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 249d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, 250bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 251d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 252bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 253bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 254d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 255d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_send_newkeys(struct ssh *ssh) 256bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 257d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 258bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 259d059297112922cabb0c674840589be8db821fd9aAdam Langley kex_reset_dispatch(ssh); 260d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || 261d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_send(ssh)) != 0) 262d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 263bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("SSH2_MSG_NEWKEYS sent"); 264bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("expecting SSH2_MSG_NEWKEYS"); 265d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 266d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 267d059297112922cabb0c674840589be8db821fd9aAdam Langley} 268d059297112922cabb0c674840589be8db821fd9aAdam Langley 269d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 270d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_input_newkeys(int type, u_int32_t seq, void *ctxt) 271d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 272d059297112922cabb0c674840589be8db821fd9aAdam Langley struct ssh *ssh = ctxt; 273d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 274d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 275bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 276d059297112922cabb0c674840589be8db821fd9aAdam Langley debug("SSH2_MSG_NEWKEYS received"); 277d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); 278d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_get_end(ssh)) != 0) 279d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 280bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->done = 1; 281d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_reset(kex->peer); 282d059297112922cabb0c674840589be8db821fd9aAdam Langley /* sshbuf_reset(kex->my); */ 283bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->flags &= ~KEX_INIT_SENT; 284d059297112922cabb0c674840589be8db821fd9aAdam Langley free(kex->name); 285bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->name = NULL; 286d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 287bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 288bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 289d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 290d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_send_kexinit(struct ssh *ssh) 291bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 292bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_char *cookie; 293d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 294d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 295bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 296d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex == NULL) 297d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INTERNAL_ERROR; 298d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->flags & KEX_INIT_SENT) 299d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 300bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->done = 0; 301bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 302bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* generate a random cookie */ 303d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 304d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INVALID_FORMAT; 305d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 306d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INTERNAL_ERROR; 307d059297112922cabb0c674840589be8db821fd9aAdam Langley arc4random_buf(cookie, KEX_COOKIE_LEN); 308d059297112922cabb0c674840589be8db821fd9aAdam Langley 309d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 310d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_putb(ssh, kex->my)) != 0 || 311d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_send(ssh)) != 0) 312d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 313bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("SSH2_MSG_KEXINIT sent"); 314bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->flags |= KEX_INIT_SENT; 315d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 316bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 317bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 318bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* ARGSUSED */ 319d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 320bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmankex_input_kexinit(int type, u_int32_t seq, void *ctxt) 321bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 322d059297112922cabb0c674840589be8db821fd9aAdam Langley struct ssh *ssh = ctxt; 323d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 324d059297112922cabb0c674840589be8db821fd9aAdam Langley const u_char *ptr; 325d059297112922cabb0c674840589be8db821fd9aAdam Langley u_int i; 326d059297112922cabb0c674840589be8db821fd9aAdam Langley size_t dlen; 327d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 328bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 329bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("SSH2_MSG_KEXINIT received"); 330bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (kex == NULL) 331d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INVALID_ARGUMENT; 332bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 333d059297112922cabb0c674840589be8db821fd9aAdam Langley ptr = sshpkt_ptr(ssh, &dlen); 334d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 335d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 336bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 337bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* discard packet */ 338bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < KEX_COOKIE_LEN; i++) 339d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 340d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 341bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < PROPOSAL_MAX; i++) 342d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 343d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 344d059297112922cabb0c674840589be8db821fd9aAdam Langley /* 345d059297112922cabb0c674840589be8db821fd9aAdam Langley * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 346d059297112922cabb0c674840589be8db821fd9aAdam Langley * KEX method has the server move first, but a server might be using 347d059297112922cabb0c674840589be8db821fd9aAdam Langley * a custom method or one that we otherwise don't support. We should 348d059297112922cabb0c674840589be8db821fd9aAdam Langley * be prepared to remember first_kex_follows here so we can eat a 349d059297112922cabb0c674840589be8db821fd9aAdam Langley * packet later. 350d059297112922cabb0c674840589be8db821fd9aAdam Langley * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means 351d059297112922cabb0c674840589be8db821fd9aAdam Langley * for cases where the server *doesn't* go first. I guess we should 352d059297112922cabb0c674840589be8db821fd9aAdam Langley * ignore it when it is set for these cases, which is what we do now. 353d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 354d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ 355d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ 356d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = sshpkt_get_end(ssh)) != 0) 357d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 358d059297112922cabb0c674840589be8db821fd9aAdam Langley 359d059297112922cabb0c674840589be8db821fd9aAdam Langley if (!(kex->flags & KEX_INIT_SENT)) 360d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_send_kexinit(ssh)) != 0) 361d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 362d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_choose_conf(ssh)) != 0) 363d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 364d059297112922cabb0c674840589be8db821fd9aAdam Langley 365d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 366d059297112922cabb0c674840589be8db821fd9aAdam Langley return (kex->kex[kex->kex_type])(ssh); 367bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 368d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INTERNAL_ERROR; 369bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 370bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 371d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 372d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 373bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 374d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex; 375d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 376d059297112922cabb0c674840589be8db821fd9aAdam Langley 377d059297112922cabb0c674840589be8db821fd9aAdam Langley *kexp = NULL; 378d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((kex = calloc(1, sizeof(*kex))) == NULL) 379d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_ALLOC_FAIL; 380d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((kex->peer = sshbuf_new()) == NULL || 381d059297112922cabb0c674840589be8db821fd9aAdam Langley (kex->my = sshbuf_new()) == NULL) { 382d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 383d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 384d059297112922cabb0c674840589be8db821fd9aAdam Langley } 385d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_prop2buf(kex->my, proposal)) != 0) 386d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 387bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->done = 0; 388d059297112922cabb0c674840589be8db821fd9aAdam Langley kex_reset_dispatch(ssh); 389d059297112922cabb0c674840589be8db821fd9aAdam Langley r = 0; 390d059297112922cabb0c674840589be8db821fd9aAdam Langley *kexp = kex; 391d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 392d059297112922cabb0c674840589be8db821fd9aAdam Langley if (r != 0) 393d059297112922cabb0c674840589be8db821fd9aAdam Langley kex_free(kex); 394d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 395bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 396bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 397d059297112922cabb0c674840589be8db821fd9aAdam Langleyvoid 398d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_free_newkeys(struct newkeys *newkeys) 399bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 400d059297112922cabb0c674840589be8db821fd9aAdam Langley if (newkeys == NULL) 401d059297112922cabb0c674840589be8db821fd9aAdam Langley return; 402d059297112922cabb0c674840589be8db821fd9aAdam Langley if (newkeys->enc.key) { 403d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); 404d059297112922cabb0c674840589be8db821fd9aAdam Langley free(newkeys->enc.key); 405d059297112922cabb0c674840589be8db821fd9aAdam Langley newkeys->enc.key = NULL; 406d059297112922cabb0c674840589be8db821fd9aAdam Langley } 407d059297112922cabb0c674840589be8db821fd9aAdam Langley if (newkeys->enc.iv) { 408d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size); 409d059297112922cabb0c674840589be8db821fd9aAdam Langley free(newkeys->enc.iv); 410d059297112922cabb0c674840589be8db821fd9aAdam Langley newkeys->enc.iv = NULL; 411d059297112922cabb0c674840589be8db821fd9aAdam Langley } 412d059297112922cabb0c674840589be8db821fd9aAdam Langley free(newkeys->enc.name); 413d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); 414d059297112922cabb0c674840589be8db821fd9aAdam Langley free(newkeys->comp.name); 415d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); 416d059297112922cabb0c674840589be8db821fd9aAdam Langley mac_clear(&newkeys->mac); 417d059297112922cabb0c674840589be8db821fd9aAdam Langley if (newkeys->mac.key) { 418d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); 419d059297112922cabb0c674840589be8db821fd9aAdam Langley free(newkeys->mac.key); 420d059297112922cabb0c674840589be8db821fd9aAdam Langley newkeys->mac.key = NULL; 421d059297112922cabb0c674840589be8db821fd9aAdam Langley } 422d059297112922cabb0c674840589be8db821fd9aAdam Langley free(newkeys->mac.name); 423d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); 424d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(newkeys, sizeof(*newkeys)); 425d059297112922cabb0c674840589be8db821fd9aAdam Langley free(newkeys); 426d059297112922cabb0c674840589be8db821fd9aAdam Langley} 427bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 428d059297112922cabb0c674840589be8db821fd9aAdam Langleyvoid 429d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_free(struct kex *kex) 430d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 431d059297112922cabb0c674840589be8db821fd9aAdam Langley u_int mode; 432d059297112922cabb0c674840589be8db821fd9aAdam Langley 433d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL 434d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->dh) 435d059297112922cabb0c674840589be8db821fd9aAdam Langley DH_free(kex->dh); 436d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef OPENSSL_HAS_ECC 437d059297112922cabb0c674840589be8db821fd9aAdam Langley if (kex->ec_client_key) 438d059297112922cabb0c674840589be8db821fd9aAdam Langley EC_KEY_free(kex->ec_client_key); 439d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* OPENSSL_HAS_ECC */ 440d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_OPENSSL */ 441d059297112922cabb0c674840589be8db821fd9aAdam Langley for (mode = 0; mode < MODE_MAX; mode++) { 442d059297112922cabb0c674840589be8db821fd9aAdam Langley kex_free_newkeys(kex->newkeys[mode]); 443d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->newkeys[mode] = NULL; 444d059297112922cabb0c674840589be8db821fd9aAdam Langley } 445d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_free(kex->peer); 446d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_free(kex->my); 447d059297112922cabb0c674840589be8db821fd9aAdam Langley free(kex->session_id); 448d059297112922cabb0c674840589be8db821fd9aAdam Langley free(kex->client_version_string); 449d059297112922cabb0c674840589be8db821fd9aAdam Langley free(kex->server_version_string); 450d059297112922cabb0c674840589be8db821fd9aAdam Langley free(kex); 451d059297112922cabb0c674840589be8db821fd9aAdam Langley} 452bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 453d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 454d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 455d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 456d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 457d059297112922cabb0c674840589be8db821fd9aAdam Langley 458d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) 459d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 460d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ 461d059297112922cabb0c674840589be8db821fd9aAdam Langley kex_free(ssh->kex); 462d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh->kex = NULL; 463d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 464bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 465d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 466bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 467bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 468d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 469d059297112922cabb0c674840589be8db821fd9aAdam Langleychoose_enc(struct sshenc *enc, char *client, char *server) 470bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 471bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *name = match_list(client, server, NULL); 472d059297112922cabb0c674840589be8db821fd9aAdam Langley 473bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (name == NULL) 474d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_NO_CIPHER_ALG_MATCH; 475bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((enc->cipher = cipher_by_name(name)) == NULL) 476d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INTERNAL_ERROR; 477bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enc->name = name; 478bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enc->enabled = 0; 479bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enc->iv = NULL; 480d059297112922cabb0c674840589be8db821fd9aAdam Langley enc->iv_len = cipher_ivlen(enc->cipher); 481bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enc->key = NULL; 482bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enc->key_len = cipher_keylen(enc->cipher); 483bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enc->block_size = cipher_blocksize(enc->cipher); 484d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 485bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 486bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 487d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 488d059297112922cabb0c674840589be8db821fd9aAdam Langleychoose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) 489bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 490bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *name = match_list(client, server, NULL); 491d059297112922cabb0c674840589be8db821fd9aAdam Langley 492bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (name == NULL) 493d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_NO_MAC_ALG_MATCH; 494bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (mac_setup(mac, name) < 0) 495d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INTERNAL_ERROR; 496bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* truncate the key */ 497d059297112922cabb0c674840589be8db821fd9aAdam Langley if (ssh->compat & SSH_BUG_HMAC) 498bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman mac->key_len = 16; 499bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman mac->name = name; 500bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman mac->key = NULL; 501bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman mac->enabled = 0; 502d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 503bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 504bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 505d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 506d059297112922cabb0c674840589be8db821fd9aAdam Langleychoose_comp(struct sshcomp *comp, char *client, char *server) 507bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 508bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *name = match_list(client, server, NULL); 509d059297112922cabb0c674840589be8db821fd9aAdam Langley 510bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (name == NULL) 511d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_NO_COMPRESS_ALG_MATCH; 512bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (strcmp(name, "zlib@openssh.com") == 0) { 513bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman comp->type = COMP_DELAYED; 514bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else if (strcmp(name, "zlib") == 0) { 515bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman comp->type = COMP_ZLIB; 516bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else if (strcmp(name, "none") == 0) { 517bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman comp->type = COMP_NONE; 518bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 519d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INTERNAL_ERROR; 520bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 521bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman comp->name = name; 522d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 523bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 524bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 525d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 526d059297112922cabb0c674840589be8db821fd9aAdam Langleychoose_kex(struct kex *k, char *client, char *server) 527bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 528d059297112922cabb0c674840589be8db821fd9aAdam Langley const struct kexalg *kexalg; 529d059297112922cabb0c674840589be8db821fd9aAdam Langley 530bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman k->name = match_list(client, server, NULL); 531d059297112922cabb0c674840589be8db821fd9aAdam Langley 532bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (k->name == NULL) 533d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_NO_KEX_ALG_MATCH; 534d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((kexalg = kex_alg_by_name(k->name)) == NULL) 535d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INTERNAL_ERROR; 536d059297112922cabb0c674840589be8db821fd9aAdam Langley k->kex_type = kexalg->type; 537d059297112922cabb0c674840589be8db821fd9aAdam Langley k->hash_alg = kexalg->hash_alg; 538d059297112922cabb0c674840589be8db821fd9aAdam Langley k->ec_nid = kexalg->ec_nid; 539d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 540bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 541bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 542d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 543d059297112922cabb0c674840589be8db821fd9aAdam Langleychoose_hostkeyalg(struct kex *k, char *client, char *server) 544bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 545bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *hostkeyalg = match_list(client, server, NULL); 546d059297112922cabb0c674840589be8db821fd9aAdam Langley 547bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (hostkeyalg == NULL) 548d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 549d059297112922cabb0c674840589be8db821fd9aAdam Langley k->hostkey_type = sshkey_type_from_name(hostkeyalg); 550bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (k->hostkey_type == KEY_UNSPEC) 551d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INTERNAL_ERROR; 552d059297112922cabb0c674840589be8db821fd9aAdam Langley k->hostkey_nid = sshkey_ecdsa_nid_from_name(hostkeyalg); 553d059297112922cabb0c674840589be8db821fd9aAdam Langley free(hostkeyalg); 554d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 555bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 556bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 557bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 558bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanproposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 559bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 560bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman static int check[] = { 561bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 562bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman }; 563bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int *idx; 564bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *p; 565bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 566bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (idx = &check[0]; *idx != -1; idx++) { 567bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((p = strchr(my[*idx], ',')) != NULL) 568bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *p = '\0'; 569bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((p = strchr(peer[*idx], ',')) != NULL) 570bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *p = '\0'; 571bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (strcmp(my[*idx], peer[*idx]) != 0) { 572bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("proposal mismatch: my %s peer %s", 573bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman my[*idx], peer[*idx]); 574bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return (0); 575bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 576bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 577bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("proposals match"); 578bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return (1); 579bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 580bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 581d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 582d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_choose_conf(struct ssh *ssh) 583bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 584d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 585d059297112922cabb0c674840589be8db821fd9aAdam Langley struct newkeys *newkeys; 586d059297112922cabb0c674840589be8db821fd9aAdam Langley char **my = NULL, **peer = NULL; 587bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char **cprop, **sprop; 588bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int nenc, nmac, ncomp; 589d059297112922cabb0c674840589be8db821fd9aAdam Langley u_int mode, ctos, need, dh_need, authlen; 590d059297112922cabb0c674840589be8db821fd9aAdam Langley int r, first_kex_follows; 591bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 592d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || 593d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 594d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 595bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 596bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (kex->server) { 597bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cprop=peer; 598bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sprop=my; 599bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 600bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cprop=my; 601bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sprop=peer; 602bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 603bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 604bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Check whether server offers roaming */ 605bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!kex->server) { 606d059297112922cabb0c674840589be8db821fd9aAdam Langley char *roaming = match_list(KEX_RESUME, 607d059297112922cabb0c674840589be8db821fd9aAdam Langley peer[PROPOSAL_KEX_ALGS], NULL); 608d059297112922cabb0c674840589be8db821fd9aAdam Langley 609bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (roaming) { 610bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->roaming = 1; 611d059297112922cabb0c674840589be8db821fd9aAdam Langley free(roaming); 612bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 613bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 614bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 615bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Algorithm Negotiation */ 616bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (mode = 0; mode < MODE_MAX; mode++) { 617d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 618d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 619d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 620d059297112922cabb0c674840589be8db821fd9aAdam Langley } 621bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->newkeys[mode] = newkeys; 622bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ctos = (!kex->server && mode == MODE_OUT) || 623bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (kex->server && mode == MODE_IN); 624bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 625bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 626bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 627d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = choose_enc(&newkeys->enc, cprop[nenc], 628d059297112922cabb0c674840589be8db821fd9aAdam Langley sprop[nenc])) != 0) 629d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 630d059297112922cabb0c674840589be8db821fd9aAdam Langley authlen = cipher_authlen(newkeys->enc.cipher); 631d059297112922cabb0c674840589be8db821fd9aAdam Langley /* ignore mac for authenticated encryption */ 632d059297112922cabb0c674840589be8db821fd9aAdam Langley if (authlen == 0 && 633d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 634d059297112922cabb0c674840589be8db821fd9aAdam Langley sprop[nmac])) != 0) 635d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 636d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 637d059297112922cabb0c674840589be8db821fd9aAdam Langley sprop[ncomp])) != 0) 638d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 639bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("kex: %s %s %s %s", 640bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ctos ? "client->server" : "server->client", 641bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman newkeys->enc.name, 642d059297112922cabb0c674840589be8db821fd9aAdam Langley authlen == 0 ? newkeys->mac.name : "<implicit>", 643bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman newkeys->comp.name); 644bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 645d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 646d059297112922cabb0c674840589be8db821fd9aAdam Langley sprop[PROPOSAL_KEX_ALGS])) != 0 || 647d059297112922cabb0c674840589be8db821fd9aAdam Langley (r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 648d059297112922cabb0c674840589be8db821fd9aAdam Langley sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) 649d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 650d059297112922cabb0c674840589be8db821fd9aAdam Langley need = dh_need = 0; 651bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (mode = 0; mode < MODE_MAX; mode++) { 652bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman newkeys = kex->newkeys[mode]; 653d059297112922cabb0c674840589be8db821fd9aAdam Langley need = MAX(need, newkeys->enc.key_len); 654d059297112922cabb0c674840589be8db821fd9aAdam Langley need = MAX(need, newkeys->enc.block_size); 655d059297112922cabb0c674840589be8db821fd9aAdam Langley need = MAX(need, newkeys->enc.iv_len); 656d059297112922cabb0c674840589be8db821fd9aAdam Langley need = MAX(need, newkeys->mac.key_len); 657d059297112922cabb0c674840589be8db821fd9aAdam Langley dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher)); 658d059297112922cabb0c674840589be8db821fd9aAdam Langley dh_need = MAX(dh_need, newkeys->enc.block_size); 659d059297112922cabb0c674840589be8db821fd9aAdam Langley dh_need = MAX(dh_need, newkeys->enc.iv_len); 660d059297112922cabb0c674840589be8db821fd9aAdam Langley dh_need = MAX(dh_need, newkeys->mac.key_len); 661bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 662bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* XXX need runden? */ 663bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex->we_need = need; 664d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->dh_need = dh_need; 665bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 666bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* ignore the next message if the proposals do not match */ 667bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (first_kex_follows && !proposals_match(my, peer) && 668d059297112922cabb0c674840589be8db821fd9aAdam Langley !(ssh->compat & SSH_BUG_FIRSTKEX)) 669d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh->dispatch_skip_packets = 1; 670d059297112922cabb0c674840589be8db821fd9aAdam Langley r = 0; 671d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 672bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex_prop_free(my); 673bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kex_prop_free(peer); 674d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 675bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 676bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 677d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 678d059297112922cabb0c674840589be8db821fd9aAdam Langleyderive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, 679d059297112922cabb0c674840589be8db821fd9aAdam Langley const struct sshbuf *shared_secret, u_char **keyp) 680bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 681d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 682d059297112922cabb0c674840589be8db821fd9aAdam Langley struct ssh_digest_ctx *hashctx = NULL; 683bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char c = id; 684bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int have; 685d059297112922cabb0c674840589be8db821fd9aAdam Langley size_t mdsz; 686bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_char *digest; 687d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 688bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 689d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) 690d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_INVALID_ARGUMENT; 691d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((digest = calloc(1, roundup(need, mdsz))) == NULL) { 692d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 693d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 694d059297112922cabb0c674840589be8db821fd9aAdam Langley } 695bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 696bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* K1 = HASH(K || H || "A" || session_id) */ 697d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 698d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 699d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update(hashctx, hash, hashlen) != 0 || 700d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update(hashctx, &c, 1) != 0 || 701d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update(hashctx, kex->session_id, 702d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->session_id_len) != 0 || 703d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_final(hashctx, digest, mdsz) != 0) { 704d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_LIBCRYPTO_ERROR; 705d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 706d059297112922cabb0c674840589be8db821fd9aAdam Langley } 707d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_free(hashctx); 708d059297112922cabb0c674840589be8db821fd9aAdam Langley hashctx = NULL; 709bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 710bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 711bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * expand key: 712bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 713bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Key = K1 || K2 || ... || Kn 714bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 715bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (have = mdsz; need > have; have += mdsz) { 716d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || 717d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update_buffer(hashctx, shared_secret) != 0 || 718d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update(hashctx, hash, hashlen) != 0 || 719d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update(hashctx, digest, have) != 0 || 720d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 721d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_LIBCRYPTO_ERROR; 722d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 723d059297112922cabb0c674840589be8db821fd9aAdam Langley } 724d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_free(hashctx); 725d059297112922cabb0c674840589be8db821fd9aAdam Langley hashctx = NULL; 726bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 727bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_KEX 728bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fprintf(stderr, "key '%c'== ", c); 729bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman dump_digest("key", digest, need); 730bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 731d059297112922cabb0c674840589be8db821fd9aAdam Langley *keyp = digest; 732d059297112922cabb0c674840589be8db821fd9aAdam Langley digest = NULL; 733d059297112922cabb0c674840589be8db821fd9aAdam Langley r = 0; 734d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 735d059297112922cabb0c674840589be8db821fd9aAdam Langley if (digest) 736d059297112922cabb0c674840589be8db821fd9aAdam Langley free(digest); 737d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_free(hashctx); 738d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 739bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 740bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 741bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define NKEYS 6 742d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 743d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, 744d059297112922cabb0c674840589be8db821fd9aAdam Langley const struct sshbuf *shared_secret) 745bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 746d059297112922cabb0c674840589be8db821fd9aAdam Langley struct kex *kex = ssh->kex; 747bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_char *keys[NKEYS]; 748d059297112922cabb0c674840589be8db821fd9aAdam Langley u_int i, j, mode, ctos; 749d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 750bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 751bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < NKEYS; i++) { 752d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, 753d059297112922cabb0c674840589be8db821fd9aAdam Langley shared_secret, &keys[i])) != 0) { 754d059297112922cabb0c674840589be8db821fd9aAdam Langley for (j = 0; j < i; j++) 755d059297112922cabb0c674840589be8db821fd9aAdam Langley free(keys[j]); 756d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 757d059297112922cabb0c674840589be8db821fd9aAdam Langley } 758bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 759bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (mode = 0; mode < MODE_MAX; mode++) { 760bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ctos = (!kex->server && mode == MODE_OUT) || 761bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (kex->server && mode == MODE_IN); 762d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; 763d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; 764d059297112922cabb0c674840589be8db821fd9aAdam Langley kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; 765bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 766d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 767bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 768bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 769d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL 770d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 771d059297112922cabb0c674840589be8db821fd9aAdam Langleykex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 772d059297112922cabb0c674840589be8db821fd9aAdam Langley const BIGNUM *secret) 773bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 774d059297112922cabb0c674840589be8db821fd9aAdam Langley struct sshbuf *shared_secret; 775d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 776d059297112922cabb0c674840589be8db821fd9aAdam Langley 777d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((shared_secret = sshbuf_new()) == NULL) 778d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_ALLOC_FAIL; 779d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) 780d059297112922cabb0c674840589be8db821fd9aAdam Langley r = kex_derive_keys(ssh, hash, hashlen, shared_secret); 781d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_free(shared_secret); 782d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 783bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 784d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif 785bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 786d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1 787d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 788bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanderive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 789bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int8_t cookie[8], u_int8_t id[16]) 790bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 791d059297112922cabb0c674840589be8db821fd9aAdam Langley u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; 792d059297112922cabb0c674840589be8db821fd9aAdam Langley struct ssh_digest_ctx *hashctx = NULL; 793d059297112922cabb0c674840589be8db821fd9aAdam Langley size_t hlen, slen; 794d059297112922cabb0c674840589be8db821fd9aAdam Langley int r; 795d059297112922cabb0c674840589be8db821fd9aAdam Langley 796d059297112922cabb0c674840589be8db821fd9aAdam Langley hlen = BN_num_bytes(host_modulus); 797d059297112922cabb0c674840589be8db821fd9aAdam Langley slen = BN_num_bytes(server_modulus); 798d059297112922cabb0c674840589be8db821fd9aAdam Langley if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || 799d059297112922cabb0c674840589be8db821fd9aAdam Langley slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) 800d059297112922cabb0c674840589be8db821fd9aAdam Langley return SSH_ERR_KEY_BITS_MISMATCH; 801d059297112922cabb0c674840589be8db821fd9aAdam Langley if (BN_bn2bin(host_modulus, hbuf) <= 0 || 802d059297112922cabb0c674840589be8db821fd9aAdam Langley BN_bn2bin(server_modulus, sbuf) <= 0) { 803d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_LIBCRYPTO_ERROR; 804d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 805d059297112922cabb0c674840589be8db821fd9aAdam Langley } 806d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { 807d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_ALLOC_FAIL; 808d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 809d059297112922cabb0c674840589be8db821fd9aAdam Langley } 810d059297112922cabb0c674840589be8db821fd9aAdam Langley if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || 811d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update(hashctx, sbuf, slen) != 0 || 812d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_update(hashctx, cookie, 8) != 0 || 813d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { 814d059297112922cabb0c674840589be8db821fd9aAdam Langley r = SSH_ERR_LIBCRYPTO_ERROR; 815d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 816d059297112922cabb0c674840589be8db821fd9aAdam Langley } 817d059297112922cabb0c674840589be8db821fd9aAdam Langley memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); 818d059297112922cabb0c674840589be8db821fd9aAdam Langley r = 0; 819d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 820d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_digest_free(hashctx); 821d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(hbuf, sizeof(hbuf)); 822d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(sbuf, sizeof(sbuf)); 823d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(obuf, sizeof(obuf)); 824d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 825bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 826d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif 827bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 828bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 829bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid 830bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmandump_digest(char *msg, u_char *digest, int len) 831bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 832bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fprintf(stderr, "%s\n", msg); 833d059297112922cabb0c674840589be8db821fd9aAdam Langley sshbuf_dump_data(digest, len, stderr); 834bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 835bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 836