Blame src/kex.c

Packit Service 31306d
/*
Packit Service 31306d
 * kex.c - key exchange
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2003-2008 by Aris Adamantiadis
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <string.h>
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <stdbool.h>
Packit Service 31306d
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/buffer.h"
Packit Service 31306d
#include "libssh/dh.h"
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
#include "libssh/dh-gex.h"
Packit Service 31306d
#endif /* WITH_GEX */
Packit Service 31306d
#include "libssh/kex.h"
Packit Service 31306d
#include "libssh/session.h"
Packit Service 31306d
#include "libssh/ssh2.h"
Packit Service 31306d
#include "libssh/string.h"
Packit Service 31306d
#include "libssh/curve25519.h"
Packit Service 31306d
#include "libssh/knownhosts.h"
Packit Service 31306d
#include "libssh/misc.h"
Packit Service 31306d
#include "libssh/pki.h"
Packit Service 31306d
#include "libssh/bignum.h"
Packit Service 31306d
#include "libssh/token.h"
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_BLOWFISH_CIPHER
Packit Service 31306d
# if defined(HAVE_OPENSSL_BLOWFISH_H) || defined(HAVE_LIBGCRYPT) || defined(HAVE_LIBMBEDCRYPTO)
Packit Service 31306d
#  define BLOWFISH "blowfish-cbc,"
Packit Service 31306d
# else
Packit Service 31306d
#  define BLOWFISH ""
Packit Service 31306d
# endif
Packit Service 31306d
#else
Packit Service 31306d
# define BLOWFISH ""
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_LIBGCRYPT
Packit Service 31306d
# define AES "aes256-gcm@openssh.com,aes128-gcm@openssh.com," \
Packit Service 31306d
             "aes256-ctr,aes192-ctr,aes128-ctr," \
Packit Service 31306d
             "aes256-cbc,aes192-cbc,aes128-cbc,"
Packit Service 31306d
# define DES "3des-cbc"
Packit Service 31306d
# define DES_SUPPORTED "3des-cbc"
Packit Service 31306d
Packit Service 31306d
#elif defined(HAVE_LIBMBEDCRYPTO)
Packit Service 31306d
# ifdef MBEDTLS_GCM_C
Packit Service 31306d
#  define GCM "aes256-gcm@openssh.com,aes128-gcm@openssh.com,"
Packit Service 31306d
# else
Packit Service 31306d
#  define GCM ""
Packit Service 31306d
# endif /* MBEDTLS_GCM_C */
Packit Service 31306d
# define AES GCM "aes256-ctr,aes192-ctr,aes128-ctr," \
Packit Service 31306d
             "aes256-cbc,aes192-cbc,aes128-cbc,"
Packit Service 31306d
# define DES "3des-cbc"
Packit Service 31306d
# define DES_SUPPORTED "3des-cbc"
Packit Service 31306d
Packit Service 31306d
#elif defined(HAVE_LIBCRYPTO)
Packit Service 31306d
# ifdef HAVE_OPENSSL_AES_H
Packit Service 31306d
#  ifdef HAVE_OPENSSL_EVP_AES_GCM
Packit Service 31306d
#   define GCM "aes256-gcm@openssh.com,aes128-gcm@openssh.com,"
Packit Service 31306d
#  else
Packit Service 31306d
#   define GCM ""
Packit Service 31306d
#  endif /* HAVE_OPENSSL_EVP_AES_GCM */
Packit Service 31306d
#  ifdef BROKEN_AES_CTR
Packit Service 31306d
#   define AES GCM "aes256-cbc,aes192-cbc,aes128-cbc,"
Packit Service 31306d
#  else /* BROKEN_AES_CTR */
Packit Service 31306d
#   define AES GCM "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
Packit Service 31306d
#  endif /* BROKEN_AES_CTR */
Packit Service 31306d
# else /* HAVE_OPENSSL_AES_H */
Packit Service 31306d
#  define AES ""
Packit Service 31306d
# endif /* HAVE_OPENSSL_AES_H */
Packit Service 31306d
Packit Service 31306d
# define DES "3des-cbc"
Packit Service 31306d
# define DES_SUPPORTED "3des-cbc"
Packit Service 31306d
#endif /* HAVE_LIBCRYPTO */
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_ZLIB
Packit Service 31306d
#define ZLIB "none,zlib,zlib@openssh.com"
Packit Service 31306d
#else
Packit Service 31306d
#define ZLIB "none"
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_CURVE25519
Packit Service 31306d
#define CURVE25519 "curve25519-sha256,curve25519-sha256@libssh.org,"
Packit Service 31306d
#else
Packit Service 31306d
#define CURVE25519 ""
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_ECDH
Packit Service 31306d
#define ECDH "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
Packit Service 31306d
#define EC_HOSTKEYS "ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256,"
Packit Service 31306d
#define EC_PUBLIC_KEY_ALGORITHMS "ecdsa-sha2-nistp521-cert-v01@openssh.com," \
Packit Service 31306d
                                 "ecdsa-sha2-nistp384-cert-v01@openssh.com," \
Packit Service 31306d
                                 "ecdsa-sha2-nistp256-cert-v01@openssh.com,"
Packit Service 31306d
#else
Packit Service 31306d
#define EC_HOSTKEYS ""
Packit Service 31306d
#define EC_PUBLIC_KEY_ALGORITHMS ""
Packit Service 31306d
#define ECDH ""
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_DSA
Packit Service 31306d
#define DSA_HOSTKEYS ",ssh-dss"
Packit Service 31306d
#define DSA_PUBLIC_KEY_ALGORITHMS ",ssh-dss-cert-v01@openssh.com"
Packit Service 31306d
#else
Packit Service 31306d
#define DSA_HOSTKEYS ""
Packit Service 31306d
#define DSA_PUBLIC_KEY_ALGORITHMS ""
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#define HOSTKEYS "ssh-ed25519," \
Packit Service 31306d
                 EC_HOSTKEYS \
Packit Service 31306d
                 "rsa-sha2-512," \
Packit Service 31306d
                 "rsa-sha2-256," \
Packit Service 31306d
                 "ssh-rsa" \
Packit Service 31306d
                 DSA_HOSTKEYS
Packit Service 31306d
#define PUBLIC_KEY_ALGORITHMS "ssh-ed25519-cert-v01@openssh.com," \
Packit Service 31306d
                              EC_PUBLIC_KEY_ALGORITHMS \
Packit Service 31306d
                              "rsa-sha2-512-cert-v01@openssh.com," \
Packit Service 31306d
                              "rsa-sha2-256-cert-v01@openssh.com," \
Packit Service 31306d
                              "ssh-rsa-cert-v01@openssh.com" \
Packit Service 31306d
                              DSA_PUBLIC_KEY_ALGORITHMS "," \
Packit Service 31306d
                              HOSTKEYS
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
#define GEX_SHA256 "diffie-hellman-group-exchange-sha256,"
Packit Service 31306d
#define GEX_SHA1 "diffie-hellman-group-exchange-sha1,"
Packit Service 31306d
#else
Packit Service 31306d
#define GEX_SHA256
Packit Service 31306d
#define GEX_SHA1
Packit Service 31306d
#endif /* WITH_GEX */
Packit Service 31306d
Packit Service 31306d
#define CHACHA20 "chacha20-poly1305@openssh.com,"
Packit Service 31306d
Packit Service 31306d
#define KEY_EXCHANGE \
Packit Service 31306d
    CURVE25519 \
Packit Service 31306d
    ECDH \
Packit Service 31306d
    "diffie-hellman-group18-sha512,diffie-hellman-group16-sha512," \
Packit Service 31306d
    GEX_SHA256 \
Packit Service 31306d
    "diffie-hellman-group14-sha256," \
Packit Service 31306d
    "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
Packit Service 31306d
#define KEY_EXCHANGE_SUPPORTED \
Packit Service 31306d
    GEX_SHA1 \
Packit Service 31306d
    KEY_EXCHANGE
Packit Service 31306d
Packit Service 31306d
/* RFC 8308 */
Packit Service 31306d
#define KEX_EXTENSION_CLIENT "ext-info-c"
Packit Service 31306d
Packit Service 31306d
/* Allowed algorithms in FIPS mode */
Packit Service 31306d
#define FIPS_ALLOWED_CIPHERS "aes256-gcm@openssh.com,"\
Packit Service 31306d
                             "aes256-ctr,"\
Packit Service 31306d
                             "aes256-cbc,"\
Packit Service 31306d
                             "aes128-gcm@openssh.com,"\
Packit Service 31306d
                             "aes128-ctr,"\
Packit Service 31306d
                             "aes128-cbc"
Packit Service 31306d
Packit Service 31306d
#define FIPS_ALLOWED_HOSTKEYS EC_HOSTKEYS \
Packit Service 31306d
                              "rsa-sha2-512," \
Packit Service 31306d
                              "rsa-sha2-256"
Packit Service 31306d
Packit Service 31306d
#define FIPS_ALLOWED_PUBLIC_KEY_ALGORITHMS EC_PUBLIC_KEY_ALGORITHMS \
Packit Service 31306d
                                           "rsa-sha2-512-cert-v01@openssh.com," \
Packit Service 31306d
                                           "rsa-sha2-256-cert-v01@openssh.com," \
Packit Service 31306d
                                           FIPS_ALLOWED_HOSTKEYS
Packit Service 31306d
Packit Service 31306d
#define FIPS_ALLOWED_KEX "ecdh-sha2-nistp256,"\
Packit Service 31306d
                         "ecdh-sha2-nistp384,"\
Packit Service 31306d
                         "ecdh-sha2-nistp521,"\
Packit Service 31306d
                         "diffie-hellman-group-exchange-sha256,"\
Packit Service 31306d
                         "diffie-hellman-group14-sha256,"\
Packit Service 31306d
                         "diffie-hellman-group16-sha512,"\
Packit Service 31306d
                         "diffie-hellman-group18-sha512"
Packit Service 31306d
Packit Service 31306d
#define FIPS_ALLOWED_MACS "hmac-sha2-256-etm@openssh.com,"\
Packit Service 31306d
                          "hmac-sha1-etm@openssh.com,"\
Packit Service 31306d
                          "hmac-sha2-512-etm@openssh.com,"\
Packit Service 31306d
                          "hmac-sha2-256,"\
Packit Service 31306d
                          "hmac-sha1,"\
Packit Service 31306d
                          "hmac-sha2-512"
Packit Service 31306d
Packit Service 31306d
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
Packit Service 31306d
static const char *fips_methods[] = {
Packit Service 31306d
    FIPS_ALLOWED_KEX,
Packit Service 31306d
    FIPS_ALLOWED_PUBLIC_KEY_ALGORITHMS,
Packit Service 31306d
    FIPS_ALLOWED_CIPHERS,
Packit Service 31306d
    FIPS_ALLOWED_CIPHERS,
Packit Service 31306d
    FIPS_ALLOWED_MACS,
Packit Service 31306d
    FIPS_ALLOWED_MACS,
Packit Service 31306d
    ZLIB,
Packit Service 31306d
    ZLIB,
Packit Service 31306d
    "",
Packit Service 31306d
    "",
Packit Service 31306d
    NULL
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
Packit Service 31306d
static const char *default_methods[] = {
Packit Service 31306d
  KEY_EXCHANGE,
Packit Service 31306d
  PUBLIC_KEY_ALGORITHMS,
Packit Service 31306d
  AES BLOWFISH DES,
Packit Service 31306d
  AES BLOWFISH DES,
Packit Service 31306d
  "hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1",
Packit Service 31306d
  "hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1",
Packit Service 31306d
  "none",
Packit Service 31306d
  "none",
Packit Service 31306d
  "",
Packit Service 31306d
  "",
Packit Service 31306d
  NULL
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
Packit Service 31306d
static const char *supported_methods[] = {
Packit Service 31306d
  KEY_EXCHANGE_SUPPORTED,
Packit Service 31306d
  PUBLIC_KEY_ALGORITHMS,
Packit Service 31306d
  CHACHA20 AES BLOWFISH DES_SUPPORTED,
Packit Service 31306d
  CHACHA20 AES BLOWFISH DES_SUPPORTED,
Packit Service 31306d
  "hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1",
Packit Service 31306d
  "hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1",
Packit Service 31306d
  ZLIB,
Packit Service 31306d
  ZLIB,
Packit Service 31306d
  "",
Packit Service 31306d
  "",
Packit Service 31306d
  NULL
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
/* descriptions of the key exchange packet */
Packit Service 31306d
static const char *ssh_kex_descriptions[] = {
Packit Service 31306d
  "kex algos",
Packit Service 31306d
  "server host key algo",
Packit Service 31306d
  "encryption client->server",
Packit Service 31306d
  "encryption server->client",
Packit Service 31306d
  "mac algo client->server",
Packit Service 31306d
  "mac algo server->client",
Packit Service 31306d
  "compression algo client->server",
Packit Service 31306d
  "compression algo server->client",
Packit Service 31306d
  "languages client->server",
Packit Service 31306d
  "languages server->client",
Packit Service 31306d
  NULL
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
const char *ssh_kex_get_default_methods(uint32_t algo)
Packit Service 31306d
{
Packit Service 31306d
    if (algo >= SSH_KEX_METHODS) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return default_methods[algo];
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
const char *ssh_kex_get_supported_method(uint32_t algo)
Packit Service 31306d
{
Packit Service 31306d
    if (algo >= SSH_KEX_METHODS) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return supported_methods[algo];
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
const char *ssh_kex_get_description(uint32_t algo) {
Packit Service 31306d
  if (algo >= SSH_KEX_METHODS) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return ssh_kex_descriptions[algo];
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
const char *ssh_kex_get_fips_methods(uint32_t algo) {
Packit Service 31306d
  if (algo >= SSH_KEX_METHODS) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return fips_methods[algo];
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 * @brief returns whether the first client key exchange algorithm or
Packit Service 31306d
 *        hostkey type matches its server counterpart
Packit Service 31306d
 * @returns whether the first client key exchange algorithm or hostkey type
Packit Service 31306d
 *          matches its server counterpart
Packit Service 31306d
 */
Packit Service 31306d
static int cmp_first_kex_algo(const char *client_str,
Packit Service 31306d
                              const char *server_str) {
Packit Service 31306d
    size_t client_kex_len;
Packit Service 31306d
    size_t server_kex_len;
Packit Service 31306d
Packit Service 31306d
    char *colon;
Packit Service 31306d
Packit Service 31306d
    int is_wrong = 1;
Packit Service 31306d
Packit Service 31306d
    colon = strchr(client_str, ',');
Packit Service 31306d
    if (colon == NULL) {
Packit Service 31306d
        client_kex_len = strlen(client_str);
Packit Service 31306d
    } else {
Packit Service 31306d
        client_kex_len = colon - client_str;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    colon = strchr(server_str, ',');
Packit Service 31306d
    if (colon == NULL) {
Packit Service 31306d
        server_kex_len = strlen(server_str);
Packit Service 31306d
    } else {
Packit Service 31306d
        server_kex_len = colon - server_str;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (client_kex_len != server_kex_len) {
Packit Service 31306d
        return is_wrong;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    is_wrong = (strncmp(client_str, server_str, client_kex_len) != 0);
Packit Service 31306d
Packit Service 31306d
    return is_wrong;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
SSH_PACKET_CALLBACK(ssh_packet_kexinit)
Packit Service 31306d
{
Packit Service 31306d
    int i, ok;
Packit Service 31306d
    int server_kex = session->server;
Packit Service 31306d
    ssh_string str = NULL;
Packit Service 31306d
    char *strings[SSH_KEX_METHODS] = {0};
Packit Service 31306d
    char *rsa_sig_ext = NULL;
Packit Service 31306d
    int rc = SSH_ERROR;
Packit Service 31306d
    size_t len;
Packit Service 31306d
Packit Service 31306d
    uint8_t first_kex_packet_follows = 0;
Packit Service 31306d
    uint32_t kexinit_reserved = 0;
Packit Service 31306d
Packit Service 31306d
    (void)type;
Packit Service 31306d
    (void)user;
Packit Service 31306d
Packit Service 31306d
    if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_INFO, "Initiating key re-exchange");
Packit Service 31306d
    } else if (session->session_state != SSH_SESSION_STATE_INITIAL_KEX) {
Packit Service 31306d
        ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (server_kex) {
Packit Service 31306d
        len = ssh_buffer_get_data(packet,session->next_crypto->client_kex.cookie, 16);
Packit Service 31306d
        if (len != 16) {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        ok = ssh_hashbufin_add_cookie(session, session->next_crypto->client_kex.cookie);
Packit Service 31306d
        if (ok < 0) {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
    } else {
Packit Service 31306d
        len = ssh_buffer_get_data(packet,session->next_crypto->server_kex.cookie, 16);
Packit Service 31306d
        if (len != 16) {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        ok = ssh_hashbufin_add_cookie(session, session->next_crypto->server_kex.cookie);
Packit Service 31306d
        if (ok < 0) {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    for (i = 0; i < SSH_KEX_METHODS; i++) {
Packit Service 31306d
        str = ssh_buffer_get_ssh_string(packet);
Packit Service 31306d
        if (str == NULL) {
Packit Service 31306d
          goto error;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = ssh_buffer_add_ssh_string(session->in_hashbuf, str);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL, "Error adding string in hash buffer");
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        strings[i] = ssh_string_to_char(str);
Packit Service 31306d
        if (strings[i] == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        SSH_STRING_FREE(str);
Packit Service 31306d
        str = NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* copy the server kex info into an array of strings */
Packit Service 31306d
    if (server_kex) {
Packit Service 31306d
        for (i = 0; i < SSH_KEX_METHODS; i++) {
Packit Service 31306d
            session->next_crypto->client_kex.methods[i] = strings[i];
Packit Service 31306d
        }
Packit Service 31306d
    } else { /* client */
Packit Service 31306d
        for (i = 0; i < SSH_KEX_METHODS; i++) {
Packit Service 31306d
            session->next_crypto->server_kex.methods[i] = strings[i];
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /*
Packit Service 31306d
     * Handle the two final fields for the KEXINIT message (RFC 4253 7.1):
Packit Service 31306d
     *
Packit Service 31306d
     *      boolean      first_kex_packet_follows
Packit Service 31306d
     *      uint32       0 (reserved for future extension)
Packit Service 31306d
     *
Packit Service 31306d
     * Notably if clients set 'first_kex_packet_follows', it is expected
Packit Service 31306d
     * that its value is included when computing the session ID (see
Packit Service 31306d
     * 'make_sessionid').
Packit Service 31306d
     */
Packit Service 31306d
    if (server_kex) {
Packit Service 31306d
        rc = ssh_buffer_get_u8(packet, &first_kex_packet_follows);
Packit Service 31306d
        if (rc != 1) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = ssh_buffer_add_u8(session->in_hashbuf, first_kex_packet_follows);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = ssh_buffer_add_u32(session->in_hashbuf, kexinit_reserved);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * If client sent a ext-info-c message in the kex list, it supports
Packit Service 31306d
         * RFC 8308 extension negotiation.
Packit Service 31306d
         */
Packit Service 31306d
        ok = ssh_match_group(session->next_crypto->client_kex.methods[SSH_KEX],
Packit Service 31306d
                             KEX_EXTENSION_CLIENT);
Packit Service 31306d
        if (ok) {
Packit Service 31306d
            const char *hostkeys = NULL;
Packit Service 31306d
Packit Service 31306d
            /* The client supports extension negotiation */
Packit Service 31306d
            session->extensions |= SSH_EXT_NEGOTIATION;
Packit Service 31306d
            /*
Packit Service 31306d
             * RFC 8332 Section 3.1: Use for Server Authentication
Packit Service 31306d
             * Check what algorithms were provided in the SSH_HOSTKEYS list
Packit Service 31306d
             * by the client and enable the respective extensions to provide
Packit Service 31306d
             * correct signature in the next packet if RSA is negotiated
Packit Service 31306d
             */
Packit Service 31306d
            hostkeys = session->next_crypto->client_kex.methods[SSH_HOSTKEYS];
Packit Service 31306d
            ok = ssh_match_group(hostkeys, "rsa-sha2-512");
Packit Service 31306d
            if (ok) {
Packit Service 31306d
                /* Check if rsa-sha2-512 is allowed by config */
Packit Service 31306d
                if (session->opts.wanted_methods[SSH_HOSTKEYS] != NULL) {
Packit Service 31306d
                    char *is_allowed =
Packit Service 31306d
                        ssh_find_matching(session->opts.wanted_methods[SSH_HOSTKEYS],
Packit Service 31306d
                                          "rsa-sha2-512");
Packit Service 31306d
                    if (is_allowed != NULL) {
Packit Service 31306d
                        session->extensions |= SSH_EXT_SIG_RSA_SHA512;
Packit Service 31306d
                    }
Packit Service 31306d
                    SAFE_FREE(is_allowed);
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            ok = ssh_match_group(hostkeys, "rsa-sha2-256");
Packit Service 31306d
            if (ok) {
Packit Service 31306d
                /* Check if rsa-sha2-256 is allowed by config */
Packit Service 31306d
                if (session->opts.wanted_methods[SSH_HOSTKEYS] != NULL) {
Packit Service 31306d
                    char *is_allowed =
Packit Service 31306d
                        ssh_find_matching(session->opts.wanted_methods[SSH_HOSTKEYS],
Packit Service 31306d
                                          "rsa-sha2-256");
Packit Service 31306d
                    if (is_allowed != NULL) {
Packit Service 31306d
                        session->extensions |= SSH_EXT_SIG_RSA_SHA256;
Packit Service 31306d
                    }
Packit Service 31306d
                    SAFE_FREE(is_allowed);
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            /*
Packit Service 31306d
             * Ensure that the client preference is honored for the case
Packit Service 31306d
             * both signature types are enabled.
Packit Service 31306d
             */
Packit Service 31306d
            if ((session->extensions & SSH_EXT_SIG_RSA_SHA256) &&
Packit Service 31306d
                (session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
Packit Service 31306d
                session->extensions &= ~(SSH_EXT_SIG_RSA_SHA256 | SSH_EXT_SIG_RSA_SHA512);
Packit Service 31306d
                rsa_sig_ext = ssh_find_matching("rsa-sha2-512,rsa-sha2-256",
Packit Service 31306d
                                                session->next_crypto->client_kex.methods[SSH_HOSTKEYS]);
Packit Service 31306d
                if (rsa_sig_ext == NULL) {
Packit Service 31306d
                    goto error; /* should never happen */
Packit Service 31306d
                } else if (strcmp(rsa_sig_ext, "rsa-sha2-512") == 0) {
Packit Service 31306d
                    session->extensions |= SSH_EXT_SIG_RSA_SHA512;
Packit Service 31306d
                } else if (strcmp(rsa_sig_ext, "rsa-sha2-256") == 0) {
Packit Service 31306d
                    session->extensions |= SSH_EXT_SIG_RSA_SHA256;
Packit Service 31306d
                } else {
Packit Service 31306d
                    SAFE_FREE(rsa_sig_ext);
Packit Service 31306d
                    goto error; /* should never happen */
Packit Service 31306d
                }
Packit Service 31306d
                SAFE_FREE(rsa_sig_ext);
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            SSH_LOG(SSH_LOG_DEBUG, "The client supports extension "
Packit Service 31306d
                    "negotiation. Enabled signature algorithms: %s%s",
Packit Service 31306d
                    session->extensions & SSH_EXT_SIG_RSA_SHA256 ? "SHA256" : "",
Packit Service 31306d
                    session->extensions & SSH_EXT_SIG_RSA_SHA512 ? " SHA512" : "");
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * Remember whether 'first_kex_packet_follows' was set and the client
Packit Service 31306d
         * guess was wrong: in this case the next SSH_MSG_KEXDH_INIT message
Packit Service 31306d
         * must be ignored.
Packit Service 31306d
         */
Packit Service 31306d
        if (first_kex_packet_follows) {
Packit Service 31306d
          session->first_kex_follows_guess_wrong =
Packit Service 31306d
            cmp_first_kex_algo(session->next_crypto->client_kex.methods[SSH_KEX],
Packit Service 31306d
                               session->next_crypto->server_kex.methods[SSH_KEX]) ||
Packit Service 31306d
            cmp_first_kex_algo(session->next_crypto->client_kex.methods[SSH_HOSTKEYS],
Packit Service 31306d
                               session->next_crypto->server_kex.methods[SSH_HOSTKEYS]);
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Note, that his overwrites authenticated state in case of rekeying */
Packit Service 31306d
    session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED;
Packit Service 31306d
    session->dh_handshake_state = DH_STATE_INIT;
Packit Service 31306d
    session->ssh_connection_callback(session);
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
Packit Service 31306d
error:
Packit Service 31306d
    SSH_STRING_FREE(str);
Packit Service 31306d
    for (i = 0; i < SSH_KEX_METHODS; i++) {
Packit Service 31306d
        if (server_kex) {
Packit Service 31306d
            session->next_crypto->client_kex.methods[i] = NULL;
Packit Service 31306d
        } else { /* client */
Packit Service 31306d
            session->next_crypto->server_kex.methods[i] = NULL;
Packit Service 31306d
        }
Packit Service 31306d
        SAFE_FREE(strings[i]);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    session->session_state = SSH_SESSION_STATE_ERROR;
Packit Service 31306d
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
void ssh_list_kex(struct ssh_kex_struct *kex) {
Packit Service 31306d
  int i = 0;
Packit Service 31306d
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
  ssh_log_hexdump("session cookie", kex->cookie, 16);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
  for(i = 0; i < SSH_KEX_METHODS; i++) {
Packit Service 31306d
    if (kex->methods[i] == NULL) {
Packit Service 31306d
      continue;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_LOG(SSH_LOG_FUNCTIONS, "%s: %s",
Packit Service 31306d
        ssh_kex_descriptions[i], kex->methods[i]);
Packit Service 31306d
  }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief selects the hostkey mechanisms to be chosen for the key exchange,
Packit Service 31306d
 * as some hostkey mechanisms may be present in known_hosts files.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns a cstring containing a comma-separated list of hostkey methods.
Packit Service 31306d
 *          NULL if no method matches
Packit Service 31306d
 */
Packit Service 31306d
char *ssh_client_select_hostkeys(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    const char *wanted = NULL;
Packit Service 31306d
    char *wanted_without_certs = NULL;
Packit Service 31306d
    char *known_hosts_algorithms = NULL;
Packit Service 31306d
    char *known_hosts_ordered = NULL;
Packit Service 31306d
    char *new_hostkeys = NULL;
Packit Service 31306d
    char *fips_hostkeys = NULL;
Packit Service 31306d
Packit Service 31306d
    wanted = session->opts.wanted_methods[SSH_HOSTKEYS];
Packit Service 31306d
    if (wanted == NULL) {
Packit Service 31306d
        if (ssh_fips_mode()) {
Packit Service 31306d
            wanted = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
Packit Service 31306d
        } else {
Packit Service 31306d
            wanted = ssh_kex_get_default_methods(SSH_HOSTKEYS);
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* This removes the certificate types, unsupported for now */
Packit Service 31306d
    wanted_without_certs = ssh_find_all_matching(HOSTKEYS, wanted);
Packit Service 31306d
    if (wanted_without_certs == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARNING,
Packit Service 31306d
                "List of allowed host key algorithms is empty or contains only "
Packit Service 31306d
                "unsupported algorithms");
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
            "Order of wanted host keys: \"%s\"",
Packit Service 31306d
            wanted_without_certs);
Packit Service 31306d
Packit Service 31306d
    known_hosts_algorithms = ssh_known_hosts_get_algorithms_names(session);
Packit Service 31306d
    if (known_hosts_algorithms == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
                "No key found in known_hosts; "
Packit Service 31306d
                "changing host key method to \"%s\"",
Packit Service 31306d
                wanted_without_certs);
Packit Service 31306d
Packit Service 31306d
        return wanted_without_certs;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
            "Algorithms found in known_hosts files: \"%s\"",
Packit Service 31306d
            known_hosts_algorithms);
Packit Service 31306d
Packit Service 31306d
    /* Filter and order the keys from known_hosts according to wanted list */
Packit Service 31306d
    known_hosts_ordered = ssh_find_all_matching(known_hosts_algorithms,
Packit Service 31306d
                                                wanted_without_certs);
Packit Service 31306d
    SAFE_FREE(known_hosts_algorithms);
Packit Service 31306d
    if (known_hosts_ordered == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
                "No key found in known_hosts is allowed; "
Packit Service 31306d
                "changing host key method to \"%s\"",
Packit Service 31306d
                wanted_without_certs);
Packit Service 31306d
Packit Service 31306d
        return wanted_without_certs;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Append the other supported keys after the preferred ones
Packit Service 31306d
     * This function tolerates NULL pointers in parameters */
Packit Service 31306d
    new_hostkeys = ssh_append_without_duplicates(known_hosts_ordered,
Packit Service 31306d
                                                 wanted_without_certs);
Packit Service 31306d
    SAFE_FREE(known_hosts_ordered);
Packit Service 31306d
    SAFE_FREE(wanted_without_certs);
Packit Service 31306d
    if (new_hostkeys == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_fips_mode()) {
Packit Service 31306d
        /* Filter out algorithms not allowed in FIPS mode */
Packit Service 31306d
        fips_hostkeys = ssh_keep_fips_algos(SSH_HOSTKEYS, new_hostkeys);
Packit Service 31306d
        SAFE_FREE(new_hostkeys);
Packit Service 31306d
        if (fips_hostkeys == NULL) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARNING,
Packit Service 31306d
                    "None of the wanted host keys or keys in known_hosts files "
Packit Service 31306d
                    "is allowed in FIPS mode.");
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
        new_hostkeys = fips_hostkeys;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
            "Changing host key method to \"%s\"",
Packit Service 31306d
            new_hostkeys);
Packit Service 31306d
Packit Service 31306d
    return new_hostkeys;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief sets the key exchange parameters to be sent to the server,
Packit Service 31306d
 *        in function of the options and available methods.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_set_client_kex(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    struct ssh_kex_struct *client = &session->next_crypto->client_kex;
Packit Service 31306d
    const char *wanted;
Packit Service 31306d
    char *kex = NULL;
Packit Service 31306d
    char *kex_tmp = NULL;
Packit Service 31306d
    int ok;
Packit Service 31306d
    int i;
Packit Service 31306d
    size_t kex_len, len;
Packit Service 31306d
Packit Service 31306d
    ok = ssh_get_random(client->cookie, 16, 0);
Packit Service 31306d
    if (!ok) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "PRNG error");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    memset(client->methods, 0, SSH_KEX_METHODS * sizeof(char **));
Packit Service 31306d
Packit Service 31306d
    /* Set the list of allowed algorithms in order of preference, if it hadn't
Packit Service 31306d
     * been set yet. */
Packit Service 31306d
    for (i = 0; i < SSH_KEX_METHODS; i++) {
Packit Service 31306d
        if (i == SSH_HOSTKEYS) {
Packit Service 31306d
            /* Set the hostkeys in the following order:
Packit Service 31306d
             * - First: keys present in known_hosts files ordered by preference
Packit Service 31306d
             * - Next: other wanted algorithms ordered by preference */
Packit Service 31306d
            client->methods[i] = ssh_client_select_hostkeys(session);
Packit Service 31306d
            if (client->methods[i] == NULL) {
Packit Service 31306d
                ssh_set_error_oom(session);
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        wanted = session->opts.wanted_methods[i];
Packit Service 31306d
        if (wanted == NULL) {
Packit Service 31306d
            if (ssh_fips_mode()) {
Packit Service 31306d
                wanted = fips_methods[i];
Packit Service 31306d
            } else {
Packit Service 31306d
                wanted = default_methods[i];
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        client->methods[i] = strdup(wanted);
Packit Service 31306d
        if (client->methods[i] == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* For rekeying, skip the extension negotiation */
Packit Service 31306d
    if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) {
Packit Service 31306d
        return SSH_OK;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Here we append  ext-info-c  to the list of kex algorithms */
Packit Service 31306d
    kex = client->methods[SSH_KEX];
Packit Service 31306d
    len = strlen(kex);
Packit Service 31306d
    if (len + strlen(KEX_EXTENSION_CLIENT) + 2 < len) {
Packit Service 31306d
        /* Overflow */
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    kex_len = len + strlen(KEX_EXTENSION_CLIENT) + 2; /* comma, NULL */
Packit Service 31306d
    kex_tmp = realloc(kex, kex_len);
Packit Service 31306d
    if (kex_tmp == NULL) {
Packit Service 31306d
        free(kex);
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    snprintf(kex_tmp + len, kex_len - len, ",%s", KEX_EXTENSION_CLIENT);
Packit Service 31306d
    client->methods[SSH_KEX] = kex_tmp;
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @brief Select the different methods on basis of client's and
Packit Service 31306d
 * server's kex messages, and watches out if a match is possible.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_kex_select_methods (ssh_session session){
Packit Service 31306d
    struct ssh_kex_struct *server = &session->next_crypto->server_kex;
Packit Service 31306d
    struct ssh_kex_struct *client = &session->next_crypto->client_kex;
Packit Service 31306d
    char *ext_start = NULL;
Packit Service 31306d
    int i;
Packit Service 31306d
Packit Service 31306d
    /* Here we should drop the  ext-info-c  from the list so we avoid matching.
Packit Service 31306d
     * it. We added it to the end, so we can just truncate the string here */
Packit Service 31306d
    ext_start = strstr(client->methods[SSH_KEX], ","KEX_EXTENSION_CLIENT);
Packit Service 31306d
    if (ext_start != NULL) {
Packit Service 31306d
        ext_start[0] = '\0';
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    for (i = 0; i < SSH_KEX_METHODS; i++) {
Packit Service 31306d
        session->next_crypto->kex_methods[i]=ssh_find_matching(server->methods[i],client->methods[i]);
Packit Service 31306d
        if(session->next_crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S){
Packit Service 31306d
            ssh_set_error(session,SSH_FATAL,"kex error : no match for method %s: server [%s], client [%s]",
Packit Service 31306d
                    ssh_kex_descriptions[i],server->methods[i],client->methods[i]);
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        } else if ((i >= SSH_LANG_C_S) && (session->next_crypto->kex_methods[i] == NULL)) {
Packit Service 31306d
            /* we can safely do that for languages */
Packit Service 31306d
            session->next_crypto->kex_methods[i] = strdup("");
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha1") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha256") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA256;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group16-sha512") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_DH_GROUP16_SHA512;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group18-sha512") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_DH_GROUP18_SHA512;
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha1") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_DH_GEX_SHA1;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha256") == 0){
Packit Service 31306d
        session->next_crypto->kex_type=SSH_KEX_DH_GEX_SHA256;
Packit Service 31306d
#endif /* WITH_GEX */
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp384") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP384;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp521") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP521;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
Packit Service 31306d
    } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256") == 0){
Packit Service 31306d
      session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_LOG(SSH_LOG_INFO, "Negotiated %s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_KEX],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_HOSTKEYS],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_CRYPT_C_S],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_CRYPT_S_C],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_MAC_C_S],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_MAC_S_C],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_COMP_C_S],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_COMP_S_C],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_LANG_C_S],
Packit Service 31306d
            session->next_crypto->kex_methods[SSH_LANG_S_C]
Packit Service 31306d
    );
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
/* this function only sends the predefined set of kex methods */
Packit Service 31306d
int ssh_send_kex(ssh_session session, int server_kex) {
Packit Service 31306d
  struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex :
Packit Service 31306d
      &session->next_crypto->client_kex);
Packit Service 31306d
  ssh_string str = NULL;
Packit Service 31306d
  int i;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  rc = ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                       "bP",
Packit Service 31306d
                       SSH2_MSG_KEXINIT,
Packit Service 31306d
                       16,
Packit Service 31306d
                       kex->cookie); /* cookie */
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
    goto error;
Packit Service 31306d
  if (ssh_hashbufout_add_cookie(session) < 0) {
Packit Service 31306d
    goto error;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ssh_list_kex(kex);
Packit Service 31306d
Packit Service 31306d
  for (i = 0; i < SSH_KEX_METHODS; i++) {
Packit Service 31306d
    str = ssh_string_from_char(kex->methods[i]);
Packit Service 31306d
    if (str == NULL) {
Packit Service 31306d
      goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_buffer_add_ssh_string(session->out_hashbuf, str) < 0) {
Packit Service 31306d
      goto error;
Packit Service 31306d
    }
Packit Service 31306d
    if (ssh_buffer_add_ssh_string(session->out_buffer, str) < 0) {
Packit Service 31306d
      goto error;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_STRING_FREE(str);
Packit Service 31306d
    str = NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                       "bd",
Packit Service 31306d
                       0,
Packit Service 31306d
                       0);
Packit Service 31306d
  if (rc != SSH_OK) {
Packit Service 31306d
    goto error;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_packet_send(session) == SSH_ERROR) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_KEXINIT sent");
Packit Service 31306d
  return 0;
Packit Service 31306d
error:
Packit Service 31306d
  ssh_buffer_reinit(session->out_buffer);
Packit Service 31306d
  ssh_buffer_reinit(session->out_hashbuf);
Packit Service 31306d
  SSH_STRING_FREE(str);
Packit Service 31306d
Packit Service 31306d
  return -1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * Key re-exchange (rekey) is triggered by this function.
Packit Service 31306d
 * It can not be called again after the rekey is initialized!
Packit Service 31306d
 */
Packit Service 31306d
int ssh_send_rekex(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
        /* Rekey/Key exchange is already in progress */
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "Attempting rekey in bad state");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->current_crypto == NULL) {
Packit Service 31306d
        /* No current crypto used -- can not exchange it */
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "No crypto to rekey");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->client) {
Packit Service 31306d
        rc = ssh_set_client_kex(session);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_PACKET, "Failed to set client kex");
Packit Service 31306d
            return rc;
Packit Service 31306d
        }
Packit Service 31306d
    } else {
Packit Service 31306d
#ifdef WITH_SERVER
Packit Service 31306d
        rc = server_set_kex(session);
Packit Service 31306d
        if (rc == SSH_ERROR) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_PACKET, "Failed to set server kex");
Packit Service 31306d
            return rc;
Packit Service 31306d
        }
Packit Service 31306d
#else
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "Invalid session state.");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
#endif /* WITH_SERVER */
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    session->dh_handshake_state = DH_STATE_INIT;
Packit Service 31306d
    rc = ssh_send_kex(session, session->server);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "Failed to send kex");
Packit Service 31306d
        return rc;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Reset the handshake state */
Packit Service 31306d
    session->dh_handshake_state = DH_STATE_INIT_SENT;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* returns a copy of the provided list if everything is supported,
Packit Service 31306d
 * otherwise a new list of the supported algorithms */
Packit Service 31306d
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list)
Packit Service 31306d
{
Packit Service 31306d
    if (algo > SSH_LANG_S_C) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return ssh_find_all_matching(supported_methods[algo], list);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Return a new allocated string containing only the FIPS allowed
Packit Service 31306d
 * algorithms from the list.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] algo  The type of the methods to filter
Packit Service 31306d
 * @param[in] list  The list to be filtered
Packit Service 31306d
 *
Packit Service 31306d
 * @return A new allocated list containing only the FIPS allowed algorithms from
Packit Service 31306d
 * the list; NULL in case of error.
Packit Service 31306d
 */
Packit Service 31306d
char *ssh_keep_fips_algos(enum ssh_kex_types_e algo, const char *list)
Packit Service 31306d
{
Packit Service 31306d
    if (algo > SSH_LANG_S_C) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return ssh_find_all_matching(fips_methods[algo], list);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_make_sessionid(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string num = NULL;
Packit Service 31306d
    ssh_buffer server_hash = NULL;
Packit Service 31306d
    ssh_buffer client_hash = NULL;
Packit Service 31306d
    ssh_buffer buf = NULL;
Packit Service 31306d
    ssh_string server_pubkey_blob = NULL;
Packit Service 31306d
    const_bignum client_pubkey, server_pubkey;
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
    const_bignum modulus, generator;
Packit Service 31306d
#endif
Packit Service 31306d
    int rc = SSH_ERROR;
Packit Service 31306d
Packit Service 31306d
    buf = ssh_buffer_new();
Packit Service 31306d
    if (buf == NULL) {
Packit Service 31306d
        return rc;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(buf,
Packit Service 31306d
                         "ss",
Packit Service 31306d
                         session->clientbanner,
Packit Service 31306d
                         session->serverbanner);
Packit Service 31306d
    if (rc == SSH_ERROR) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->client) {
Packit Service 31306d
        server_hash = session->in_hashbuf;
Packit Service 31306d
        client_hash = session->out_hashbuf;
Packit Service 31306d
    } else {
Packit Service 31306d
        server_hash = session->out_hashbuf;
Packit Service 31306d
        client_hash = session->in_hashbuf;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /*
Packit Service 31306d
     * Handle the two final fields for the KEXINIT message (RFC 4253 7.1):
Packit Service 31306d
     *
Packit Service 31306d
     *      boolean      first_kex_packet_follows
Packit Service 31306d
     *      uint32       0 (reserved for future extension)
Packit Service 31306d
     */
Packit Service 31306d
    rc = ssh_buffer_add_u8(server_hash, 0);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_buffer_add_u32(server_hash, 0);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* These fields are handled for the server case in ssh_packet_kexinit. */
Packit Service 31306d
    if (session->client) {
Packit Service 31306d
        rc = ssh_buffer_add_u8(client_hash, 0);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        rc = ssh_buffer_add_u32(client_hash, 0);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(buf,
Packit Service 31306d
                         "dPdPS",
Packit Service 31306d
                         ssh_buffer_get_len(client_hash),
Packit Service 31306d
                         ssh_buffer_get_len(client_hash),
Packit Service 31306d
                         ssh_buffer_get(client_hash),
Packit Service 31306d
                         ssh_buffer_get_len(server_hash),
Packit Service 31306d
                         ssh_buffer_get_len(server_hash),
Packit Service 31306d
                         ssh_buffer_get(server_hash),
Packit Service 31306d
                         server_pubkey_blob);
Packit Service 31306d
    SSH_STRING_FREE(server_pubkey_blob);
Packit Service 31306d
    if(rc != SSH_OK){
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch(session->next_crypto->kex_type) {
Packit Service 31306d
    case SSH_KEX_DH_GROUP1_SHA1:
Packit Service 31306d
    case SSH_KEX_DH_GROUP14_SHA1:
Packit Service 31306d
    case SSH_KEX_DH_GROUP14_SHA256:
Packit Service 31306d
    case SSH_KEX_DH_GROUP16_SHA512:
Packit Service 31306d
    case SSH_KEX_DH_GROUP18_SHA512:
Packit Service 31306d
        rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
Packit Service 31306d
                                     DH_CLIENT_KEYPAIR, NULL, &client_pubkey);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
Packit Service 31306d
                                     DH_SERVER_KEYPAIR, NULL, &server_pubkey);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        rc = ssh_buffer_pack(buf,
Packit Service 31306d
                             "BB",
Packit Service 31306d
                             client_pubkey,
Packit Service 31306d
                             server_pubkey);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
    case SSH_KEX_DH_GEX_SHA1:
Packit Service 31306d
    case SSH_KEX_DH_GEX_SHA256:
Packit Service 31306d
        rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
Packit Service 31306d
                                     DH_CLIENT_KEYPAIR, NULL, &client_pubkey);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
Packit Service 31306d
                                     DH_SERVER_KEYPAIR, NULL, &server_pubkey);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        rc = ssh_dh_get_parameters(session->next_crypto->dh_ctx,
Packit Service 31306d
                                   &modulus, &generator);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        rc = ssh_buffer_pack(buf,
Packit Service 31306d
                    "dddBBBB",
Packit Service 31306d
                    session->next_crypto->dh_pmin,
Packit Service 31306d
                    session->next_crypto->dh_pn,
Packit Service 31306d
                    session->next_crypto->dh_pmax,
Packit Service 31306d
                    modulus,
Packit Service 31306d
                    generator,
Packit Service 31306d
                    client_pubkey,
Packit Service 31306d
                    server_pubkey);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
#endif /* WITH_GEX */
Packit Service 31306d
#ifdef HAVE_ECDH
Packit Service 31306d
    case SSH_KEX_ECDH_SHA2_NISTP256:
Packit Service 31306d
    case SSH_KEX_ECDH_SHA2_NISTP384:
Packit Service 31306d
    case SSH_KEX_ECDH_SHA2_NISTP521:
Packit Service 31306d
        if (session->next_crypto->ecdh_client_pubkey == NULL ||
Packit Service 31306d
            session->next_crypto->ecdh_server_pubkey == NULL) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing");
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        rc = ssh_buffer_pack(buf,
Packit Service 31306d
                             "SS",
Packit Service 31306d
                             session->next_crypto->ecdh_client_pubkey,
Packit Service 31306d
                             session->next_crypto->ecdh_server_pubkey);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
#endif
Packit Service 31306d
#ifdef HAVE_CURVE25519
Packit Service 31306d
    case SSH_KEX_CURVE25519_SHA256:
Packit Service 31306d
    case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
Packit Service 31306d
        rc = ssh_buffer_pack(buf,
Packit Service 31306d
                             "dPdP",
Packit Service 31306d
                             CURVE25519_PUBKEY_SIZE,
Packit Service 31306d
                             (size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_client_pubkey,
Packit Service 31306d
                             CURVE25519_PUBKEY_SIZE,
Packit Service 31306d
                             (size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_server_pubkey);
Packit Service 31306d
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
#endif
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_buffer_pack(buf, "B", session->next_crypto->shared_secret);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
    ssh_log_hexdump("hash buffer", ssh_buffer_get(buf), ssh_buffer_get_len(buf));
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    switch (session->next_crypto->kex_type) {
Packit Service 31306d
    case SSH_KEX_DH_GROUP1_SHA1:
Packit Service 31306d
    case SSH_KEX_DH_GROUP14_SHA1:
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
    case SSH_KEX_DH_GEX_SHA1:
Packit Service 31306d
#endif /* WITH_GEX */
Packit Service 31306d
        session->next_crypto->digest_len = SHA_DIGEST_LENGTH;
Packit Service 31306d
        session->next_crypto->digest_type = SSH_KDF_SHA1;
Packit Service 31306d
        session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
Packit Service 31306d
        if (session->next_crypto->secret_hash == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        sha1(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
Packit Service 31306d
                                   session->next_crypto->secret_hash);
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEX_DH_GROUP14_SHA256:
Packit Service 31306d
    case SSH_KEX_ECDH_SHA2_NISTP256:
Packit Service 31306d
    case SSH_KEX_CURVE25519_SHA256:
Packit Service 31306d
    case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
    case SSH_KEX_DH_GEX_SHA256:
Packit Service 31306d
#endif /* WITH_GEX */
Packit Service 31306d
        session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
Packit Service 31306d
        session->next_crypto->digest_type = SSH_KDF_SHA256;
Packit Service 31306d
        session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
Packit Service 31306d
        if (session->next_crypto->secret_hash == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        sha256(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
Packit Service 31306d
                                     session->next_crypto->secret_hash);
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEX_ECDH_SHA2_NISTP384:
Packit Service 31306d
        session->next_crypto->digest_len = SHA384_DIGEST_LENGTH;
Packit Service 31306d
        session->next_crypto->digest_type = SSH_KDF_SHA384;
Packit Service 31306d
        session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
Packit Service 31306d
        if (session->next_crypto->secret_hash == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        sha384(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
Packit Service 31306d
                                     session->next_crypto->secret_hash);
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEX_DH_GROUP16_SHA512:
Packit Service 31306d
    case SSH_KEX_DH_GROUP18_SHA512:
Packit Service 31306d
    case SSH_KEX_ECDH_SHA2_NISTP521:
Packit Service 31306d
        session->next_crypto->digest_len = SHA512_DIGEST_LENGTH;
Packit Service 31306d
        session->next_crypto->digest_type = SSH_KDF_SHA512;
Packit Service 31306d
        session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
Packit Service 31306d
        if (session->next_crypto->secret_hash == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        sha512(ssh_buffer_get(buf),
Packit Service 31306d
               ssh_buffer_get_len(buf),
Packit Service 31306d
               session->next_crypto->secret_hash);
Packit Service 31306d
        break;
Packit Service 31306d
    }
Packit Service 31306d
    /* During the first kex, secret hash and session ID are equal. However, after
Packit Service 31306d
     * a key re-exchange, a new secret hash is calculated. This hash will not replace
Packit Service 31306d
     * but complement existing session id.
Packit Service 31306d
     */
Packit Service 31306d
    if (!session->next_crypto->session_id) {
Packit Service 31306d
        session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
Packit Service 31306d
        if (session->next_crypto->session_id == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,
Packit Service 31306d
                session->next_crypto->digest_len);
Packit Service 31306d
    }
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
    printf("Session hash: \n");
Packit Service 31306d
    ssh_log_hexdump("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
Packit Service 31306d
    ssh_log_hexdump("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    rc = SSH_OK;
Packit Service 31306d
error:
Packit Service 31306d
    SSH_BUFFER_FREE(buf);
Packit Service 31306d
    SSH_BUFFER_FREE(client_hash);
Packit Service 31306d
    SSH_BUFFER_FREE(server_hash);
Packit Service 31306d
Packit Service 31306d
    session->in_hashbuf = NULL;
Packit Service 31306d
    session->out_hashbuf = NULL;
Packit Service 31306d
Packit Service 31306d
    SSH_STRING_FREE(num);
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_hashbufout_add_cookie(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    session->out_hashbuf = ssh_buffer_new();
Packit Service 31306d
    if (session->out_hashbuf == NULL) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_allocate_size(session->out_hashbuf,
Packit Service 31306d
            sizeof(uint8_t) + 16);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        ssh_buffer_reinit(session->out_hashbuf);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_buffer_add_u8(session->out_hashbuf, 20) < 0) {
Packit Service 31306d
        ssh_buffer_reinit(session->out_hashbuf);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->server) {
Packit Service 31306d
        if (ssh_buffer_add_data(session->out_hashbuf,
Packit Service 31306d
                    session->next_crypto->server_kex.cookie, 16) < 0) {
Packit Service 31306d
            ssh_buffer_reinit(session->out_hashbuf);
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
    } else {
Packit Service 31306d
        if (ssh_buffer_add_data(session->out_hashbuf,
Packit Service 31306d
                    session->next_crypto->client_kex.cookie, 16) < 0) {
Packit Service 31306d
            ssh_buffer_reinit(session->out_hashbuf);
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    session->in_hashbuf = ssh_buffer_new();
Packit Service 31306d
    if (session->in_hashbuf == NULL) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_allocate_size(session->in_hashbuf,
Packit Service 31306d
            sizeof(uint8_t) + 20 + 16);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        ssh_buffer_reinit(session->in_hashbuf);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_buffer_add_u8(session->in_hashbuf, 20) < 0) {
Packit Service 31306d
        ssh_buffer_reinit(session->in_hashbuf);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
    if (ssh_buffer_add_data(session->in_hashbuf,cookie, 16) < 0) {
Packit Service 31306d
        ssh_buffer_reinit(session->in_hashbuf);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_generate_session_keys(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string k_string = NULL;
Packit Service 31306d
    struct ssh_crypto_struct *crypto = session->next_crypto;
Packit Service 31306d
    unsigned char *key = NULL;
Packit Service 31306d
    unsigned char *IV_cli_to_srv = NULL;
Packit Service 31306d
    unsigned char *IV_srv_to_cli = NULL;
Packit Service 31306d
    unsigned char *enckey_cli_to_srv = NULL;
Packit Service 31306d
    unsigned char *enckey_srv_to_cli = NULL;
Packit Service 31306d
    unsigned char *intkey_cli_to_srv = NULL;
Packit Service 31306d
    unsigned char *intkey_srv_to_cli = NULL;
Packit Service 31306d
    size_t key_len = 0;
Packit Service 31306d
    size_t IV_len = 0;
Packit Service 31306d
    size_t enckey_cli_to_srv_len = 0;
Packit Service 31306d
    size_t enckey_srv_to_cli_len = 0;
Packit Service 31306d
    size_t intkey_cli_to_srv_len = 0;
Packit Service 31306d
    size_t intkey_srv_to_cli_len = 0;
Packit Service 31306d
    int rc = -1;
Packit Service 31306d
Packit Service 31306d
    k_string = ssh_make_bignum_string(crypto->shared_secret);
Packit Service 31306d
    if (k_string == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    /* See RFC4251 Section 5 for the definition of mpint which is the
Packit Service 31306d
     * encoding we need to use for key in the SSH KDF */
Packit Service 31306d
    key = (unsigned char *)k_string;
Packit Service 31306d
    key_len = ssh_string_len(k_string) + 4;
Packit Service 31306d
Packit Service 31306d
    IV_len = crypto->digest_len;
Packit Service 31306d
    if (session->client) {
Packit Service 31306d
        enckey_cli_to_srv_len = crypto->out_cipher->keysize / 8;
Packit Service 31306d
        enckey_srv_to_cli_len = crypto->in_cipher->keysize / 8;
Packit Service 31306d
        intkey_cli_to_srv_len = hmac_digest_len(crypto->out_hmac);
Packit Service 31306d
        intkey_srv_to_cli_len = hmac_digest_len(crypto->in_hmac);
Packit Service 31306d
    } else {
Packit Service 31306d
        enckey_cli_to_srv_len = crypto->in_cipher->keysize / 8;
Packit Service 31306d
        enckey_srv_to_cli_len = crypto->out_cipher->keysize / 8;
Packit Service 31306d
        intkey_cli_to_srv_len = hmac_digest_len(crypto->in_hmac);
Packit Service 31306d
        intkey_srv_to_cli_len = hmac_digest_len(crypto->out_hmac);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    IV_cli_to_srv = malloc(IV_len);
Packit Service 31306d
    IV_srv_to_cli = malloc(IV_len);
Packit Service 31306d
    enckey_cli_to_srv = malloc(enckey_cli_to_srv_len);
Packit Service 31306d
    enckey_srv_to_cli = malloc(enckey_srv_to_cli_len);
Packit Service 31306d
    intkey_cli_to_srv = malloc(intkey_cli_to_srv_len);
Packit Service 31306d
    intkey_srv_to_cli = malloc(intkey_srv_to_cli_len);
Packit Service 31306d
    if (IV_cli_to_srv == NULL || IV_srv_to_cli == NULL ||
Packit Service 31306d
        enckey_cli_to_srv == NULL || enckey_srv_to_cli == NULL ||
Packit Service 31306d
        intkey_cli_to_srv == NULL || intkey_srv_to_cli == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* IV */
Packit Service 31306d
    rc = ssh_kdf(crypto, key, key_len, 'A', IV_cli_to_srv, IV_len);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_kdf(crypto, key, key_len, 'B', IV_srv_to_cli, IV_len);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    /* Encryption Key */
Packit Service 31306d
    rc = ssh_kdf(crypto, key, key_len, 'C', enckey_cli_to_srv,
Packit Service 31306d
                 enckey_cli_to_srv_len);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_kdf(crypto, key, key_len, 'D', enckey_srv_to_cli,
Packit Service 31306d
                 enckey_srv_to_cli_len);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    /* Integrity Key */
Packit Service 31306d
    rc = ssh_kdf(crypto, key, key_len, 'E', intkey_cli_to_srv,
Packit Service 31306d
                 intkey_cli_to_srv_len);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_kdf(crypto, key, key_len, 'F', intkey_srv_to_cli,
Packit Service 31306d
                 intkey_srv_to_cli_len);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->client) {
Packit Service 31306d
        crypto->encryptIV = IV_cli_to_srv;
Packit Service 31306d
        crypto->decryptIV = IV_srv_to_cli;
Packit Service 31306d
        crypto->encryptkey = enckey_cli_to_srv;
Packit Service 31306d
        crypto->decryptkey = enckey_srv_to_cli;
Packit Service 31306d
        crypto->encryptMAC = intkey_cli_to_srv;
Packit Service 31306d
        crypto->decryptMAC = intkey_srv_to_cli;
Packit Service 31306d
    } else {
Packit Service 31306d
        crypto->encryptIV = IV_srv_to_cli;
Packit Service 31306d
        crypto->decryptIV = IV_cli_to_srv;
Packit Service 31306d
        crypto->encryptkey = enckey_srv_to_cli;
Packit Service 31306d
        crypto->decryptkey = enckey_cli_to_srv;
Packit Service 31306d
        crypto->encryptMAC = intkey_srv_to_cli;
Packit Service 31306d
        crypto->decryptMAC = intkey_cli_to_srv;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
    ssh_log_hexdump("Client to Server IV", IV_cli_to_srv, IV_len);
Packit Service 31306d
    ssh_log_hexdump("Server to Client IV", IV_srv_to_cli, IV_len);
Packit Service 31306d
    ssh_log_hexdump("Client to Server Encryption Key", enckey_cli_to_srv,
Packit Service 31306d
                   enckey_cli_to_srv_len);
Packit Service 31306d
    ssh_log_hexdump("Server to Client Encryption Key", enckey_srv_to_cli,
Packit Service 31306d
                   enckey_srv_to_cli_len);
Packit Service 31306d
    ssh_log_hexdump("Client to Server Integrity Key", intkey_cli_to_srv,
Packit Service 31306d
                   intkey_cli_to_srv_len);
Packit Service 31306d
    ssh_log_hexdump("Server to Client Integrity Key", intkey_srv_to_cli,
Packit Service 31306d
                   intkey_srv_to_cli_len);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    rc = 0;
Packit Service 31306d
error:
Packit Service 31306d
    ssh_string_burn(k_string);
Packit Service 31306d
    SSH_STRING_FREE(k_string);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        free(IV_cli_to_srv);
Packit Service 31306d
        free(IV_srv_to_cli);
Packit Service 31306d
        free(enckey_cli_to_srv);
Packit Service 31306d
        free(enckey_srv_to_cli);
Packit Service 31306d
        free(intkey_cli_to_srv);
Packit Service 31306d
        free(intkey_srv_to_cli);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}