diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index c33f7a0d..389100bd 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -43,10 +43,16 @@ if (UNIX AND NOT WIN32) torture_channel ) - if (WITH_SERVER AND WITH_GEX) + if (WITH_SERVER) set(LIBSSH_UNIT_TESTS ${LIBSSH_UNIT_TESTS} - torture_moduli) + torture_bind_config) + + if (WITH_GEX) + set(LIBSSH_UNIT_TESTS + ${LIBSSH_UNIT_TESTS} + torture_moduli) + endif() endif() diff --git a/tests/unittests/torture_bind_config.c b/tests/unittests/torture_bind_config.c new file mode 100644 index 00000000..edb8aa1a --- /dev/null +++ b/tests/unittests/torture_bind_config.c @@ -0,0 +1,805 @@ +/* + * torture_bind_config.c - Tests for server side configuration + * + * This file is part of the SSH Library + * + * Copyright (c) 2019 by Red Hat, Inc. + * + * Author: Anderson Toshiyuki Sasaki + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#define LIBSSH_STATIC + +#include "torture.h" +#include "torture_key.h" + +#include +#include + +extern LIBSSH_THREAD int ssh_log_level; + +#define LOGLEVEL "verbose" +#define LOGLEVEL2 "fatal" +#define LISTEN_ADDRESS "::1" +#define LISTEN_ADDRESS2 "::2" +#define KEXALGORITHMS "ecdh-sha2-nistp521,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha1" +#define KEXALGORITHMS2 "ecdh-sha2-nistp521" +#define CIPHERS "aes128-ctr,aes192-ctr,aes256-ctr" +#define CIPHERS2 "aes256-ctr" +#define HOSTKEYALGORITHMS "ssh-ed25519,ecdsa-sha2-nistp521,ssh-rsa" +#define HOSTKEYALGORITHMS2 "ssh-rsa" +#define PUBKEYACCEPTEDTYPES "rsa-sha2-512,ssh-rsa,ecdsa-sha2-nistp521" +#define PUBKEYACCEPTEDTYPES2 "ssh-rsa" +#define MACS "hmac-sha1,hmac-sha2-256,hmac-sha2-512,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com" +#define MACS2 "hmac-sha1" + +#ifdef HAVE_DSA +#define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa" +#endif +#define LIBSSH_RSA_TESTKEY "libssh_testkey.id_rsa" +#define LIBSSH_ED25519_TESTKEY "libssh_testkey.id_ed25519" +#ifdef HAVE_ECC +#define LIBSSH_ECDSA_521_TESTKEY "libssh_testkey.id_ecdsa521" +#endif + +#define LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS "libssh_test_bind_config_listenaddress" +#define LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS2 "libssh_test_bind_config_listenaddress2" +#define LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS_TWICE "libssh_test_bind_config_listenaddress_twice" +#define LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS_TWICE_REC "libssh_test_bind_config_listenaddress_twice_rec" +#define LIBSSH_TEST_BIND_CONFIG_PORT "libssh_test_bind_config_port" +#define LIBSSH_TEST_BIND_CONFIG_PORT2 "libssh_test_bind_config_port2" +#define LIBSSH_TEST_BIND_CONFIG_PORT_TWICE "libssh_test_bind_config_port_twice" +#define LIBSSH_TEST_BIND_CONFIG_PORT_TWICE_REC "libssh_test_bind_config_port_twice_rec" +#define LIBSSH_TEST_BIND_CONFIG_HOSTKEY "libssh_test_bind_config_hostkey" +#define LIBSSH_TEST_BIND_CONFIG_HOSTKEY2 "libssh_test_bind_config_hostkey2" +#define LIBSSH_TEST_BIND_CONFIG_HOSTKEY_TWICE "libssh_test_bind_config_hostkey_twice" +#define LIBSSH_TEST_BIND_CONFIG_HOSTKEY_TWICE_REC "libssh_test_bind_config_hostkey_twice_rec" +#define LIBSSH_TEST_BIND_CONFIG_LOGLEVEL "libssh_test_bind_config_loglevel" +#define LIBSSH_TEST_BIND_CONFIG_LOGLEVEL2 "libssh_test_bind_config_loglevel2" +#define LIBSSH_TEST_BIND_CONFIG_LOGLEVEL_TWICE "libssh_test_bind_config_loglevel_twice" +#define LIBSSH_TEST_BIND_CONFIG_LOGLEVEL_TWICE_REC "libssh_test_bind_config_loglevel_twice_rec" +#define LIBSSH_TEST_BIND_CONFIG_CIPHERS "libssh_test_bind_config_ciphers" +#define LIBSSH_TEST_BIND_CONFIG_CIPHERS2 "libssh_test_bind_config_ciphers2" +#define LIBSSH_TEST_BIND_CONFIG_CIPHERS_TWICE "libssh_test_bind_config_ciphers_twice" +#define LIBSSH_TEST_BIND_CONFIG_CIPHERS_TWICE_REC "libssh_test_bind_config_ciphers_twice_rec" +#define LIBSSH_TEST_BIND_CONFIG_MACS "libssh_test_bind_config_macs" +#define LIBSSH_TEST_BIND_CONFIG_MACS2 "libssh_test_bind_config_macs2" +#define LIBSSH_TEST_BIND_CONFIG_MACS_TWICE "libssh_test_bind_config_macs_twice" +#define LIBSSH_TEST_BIND_CONFIG_MACS_TWICE_REC "libssh_test_bind_config_macs_twice_rec" +#define LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS "libssh_test_bind_config_kexalgorithms" +#define LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS2 "libssh_test_bind_config_kexalgorithms2" +#define LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS_TWICE "libssh_test_bind_config_kexalgorithms_twice" +#define LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS_TWICE_REC "libssh_test_bind_config_kexalgorithms_twice_rec" + +#define LIBSSH_TEST_BIND_CONFIG_FULL "libssh_test_bind_config_full" +#define LIBSSH_TEST_BIND_CONFIG_INCLUDE "libssh_test_bind_config_include" +#define LIBSSH_TEST_BIND_CONFIG_INCLUDE_RECURSIVE "libssh_test_bind_config_include_recursive" +#define LIBSSH_TEST_BIND_CONFIG_CORNER_CASES "libssh_test_bind_config_corner_cases" + +const char template[] = "temp_dir_XXXXXX"; + +struct bind_st { + char *cwd; + char *temp_dir; + ssh_bind bind; +}; + +static int setup_config_files(void **state) +{ + struct bind_st *test_state = NULL; + char *cwd = NULL; + char *tmp_dir = NULL; + int rc = 0; + + test_state = (struct bind_st *)malloc(sizeof(struct bind_st)); + assert_non_null(test_state); + + cwd = torture_get_current_working_dir(); + assert_non_null(cwd); + + tmp_dir = torture_make_temp_dir(template); + assert_non_null(tmp_dir); + + test_state->cwd = cwd; + test_state->temp_dir = tmp_dir; + + *state = test_state; + + rc = torture_change_dir(tmp_dir); + assert_int_equal(rc, 0); + + printf("Changed directory to: %s\n", tmp_dir); + + /* For ed25519 the test keys are not available in legacy PEM format. Using + * the new OpenSSH format for all algorithms */ + torture_write_file(LIBSSH_RSA_TESTKEY, + torture_get_openssh_testkey(SSH_KEYTYPE_RSA, 0, 0)); + + torture_write_file(LIBSSH_ED25519_TESTKEY, + torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0, 0)); +#ifdef HAVE_ECC + torture_write_file(LIBSSH_ECDSA_521_TESTKEY, + torture_get_openssh_testkey(SSH_KEYTYPE_ECDSA, 521, 0)); +#endif +#ifdef HAVE_DSA + torture_write_file(LIBSSH_DSA_TESTKEY, + torture_get_openssh_testkey(SSH_KEYTYPE_DSS, 0, 0)); +#endif + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS, + "ListenAddress "LISTEN_ADDRESS"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS2, + "ListenAddress "LISTEN_ADDRESS2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS_TWICE, + "ListenAddress "LISTEN_ADDRESS"\n" + "ListenAddress "LISTEN_ADDRESS2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS_TWICE_REC, + "ListenAddress "LISTEN_ADDRESS"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS2"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_PORT, + "Port 123\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_PORT2, + "Port 456\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_PORT_TWICE, + "Port 123\n" + "Port 456\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_PORT_TWICE_REC, + "Port 123\n" + "Include "LIBSSH_TEST_BIND_CONFIG_PORT2"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_HOSTKEY, + "HostKey "LIBSSH_ED25519_TESTKEY"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_HOSTKEY2, + "HostKey "LIBSSH_RSA_TESTKEY"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_HOSTKEY_TWICE, + "HostKey "LIBSSH_ED25519_TESTKEY"\n" + "HostKey "LIBSSH_RSA_TESTKEY"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_HOSTKEY_TWICE_REC, + "HostKey "LIBSSH_ED25519_TESTKEY"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_HOSTKEY2"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_LOGLEVEL, + "LogLevel "LOGLEVEL"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_LOGLEVEL2, + "LogLevel "LOGLEVEL2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_LOGLEVEL_TWICE, + "LogLevel "LOGLEVEL"\n" + "LogLevel "LOGLEVEL2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_LOGLEVEL_TWICE_REC, + "LogLevel "LOGLEVEL"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_LOGLEVEL2"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_CIPHERS, + "Ciphers "CIPHERS"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_CIPHERS2, + "Ciphers "CIPHERS2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_CIPHERS_TWICE, + "Ciphers "CIPHERS"\n" + "Ciphers "CIPHERS2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_CIPHERS_TWICE_REC, + "Ciphers "CIPHERS"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_CIPHERS2"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_MACS, + "MACs "MACS"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_MACS2, + "MACs "MACS2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_MACS_TWICE, + "MACs "MACS"\n" + "MACs "MACS2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_MACS_TWICE_REC, + "MACs "MACS"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_MACS2"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS, + "KexAlgorithms "KEXALGORITHMS"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS2, + "KexAlgorithms "KEXALGORITHMS2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS_TWICE, + "KexAlgorithms "KEXALGORITHMS"\n" + "KexAlgorithms "KEXALGORITHMS2"\n"); + torture_write_file(LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS_TWICE_REC, + "KexAlgorithms "KEXALGORITHMS"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS2"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_FULL, + "ListenAddress "LISTEN_ADDRESS"\n" + "Port 123\n" + "HostKey "LIBSSH_ED25519_TESTKEY"\n" + "LogLevel "LOGLEVEL"\n" + "Ciphers "CIPHERS"\n" + "MACs "MACS"\n" + "KexAlgorithms "KEXALGORITHMS"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_INCLUDE, + "Include "LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_PORT"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_HOSTKEY"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_LOGLEVEL"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_CIPHERS"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_MACS"\n" + "Include "LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS"\n"); + + torture_write_file(LIBSSH_TEST_BIND_CONFIG_INCLUDE_RECURSIVE, + "Include "LIBSSH_TEST_BIND_CONFIG_INCLUDE"\n"); + + /* Unsupported options and corner cases */ + torture_write_file(LIBSSH_TEST_BIND_CONFIG_CORNER_CASES, + "\n" /* empty line */ + "# comment line\n" + " # comment line not starting with hash\n" + "UnknownConfigurationOption yes\n" + "Ciphers "CIPHERS"\n"); + + return 0; +} + +static int sshbind_setup(void **state) +{ + int rc; + struct bind_st *test_state = NULL; + + rc = setup_config_files((void **)&test_state); + assert_int_equal(rc, 0); + assert_non_null(test_state); + + test_state->bind = ssh_bind_new(); + assert_non_null(test_state->bind); + + *state = test_state; + + return 0; +} + +static int sshbind_teardown(void **state) +{ + struct bind_st *test_state = NULL; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + + assert_non_null(test_state); + assert_non_null(test_state->cwd); + assert_non_null(test_state->temp_dir); + assert_non_null(test_state->bind); + + rc = torture_change_dir(test_state->cwd); + assert_int_equal(rc, 0); + + rc = torture_rmdirs(test_state->temp_dir); + assert_int_equal(rc, 0); + + SAFE_FREE(test_state->temp_dir); + SAFE_FREE(test_state->cwd); + ssh_bind_free(test_state->bind); + SAFE_FREE(test_state); + + return 0; +} + +static void torture_bind_config_listen_address(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS); + assert_int_equal(rc, 0); + assert_non_null(bind->bindaddr); + assert_string_equal(bind->bindaddr, LISTEN_ADDRESS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS_TWICE); + assert_int_equal(rc, 0); + assert_non_null(bind->bindaddr); + assert_string_equal(bind->bindaddr, LISTEN_ADDRESS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS_TWICE_REC); + assert_int_equal(rc, 0); + assert_non_null(bind->bindaddr); + assert_string_equal(bind->bindaddr, LISTEN_ADDRESS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_LISTENADDRESS2); + assert_int_equal(rc, 0); + assert_non_null(bind->bindaddr); + assert_string_equal(bind->bindaddr, LISTEN_ADDRESS2); + +} + +static void torture_bind_config_port(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_PORT); + assert_int_equal(rc, 0); + assert_int_equal(bind->bindport, 123); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_PORT_TWICE); + assert_int_equal(rc, 0); + assert_int_equal(bind->bindport, 123); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_PORT_TWICE_REC); + assert_int_equal(rc, 0); + assert_int_equal(bind->bindport, 123); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_PORT2); + assert_int_equal(rc, 0); + assert_int_equal(bind->bindport, 456); +} + +static void torture_bind_config_hostkey(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_HOSTKEY); + assert_int_equal(rc, 0); + assert_non_null(bind->ed25519key); + assert_string_equal(bind->ed25519key, LIBSSH_ED25519_TESTKEY); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_HOSTKEY_TWICE); + assert_int_equal(rc, 0); + assert_non_null(bind->ed25519key); + assert_string_equal(bind->ed25519key, LIBSSH_ED25519_TESTKEY); + assert_non_null(bind->rsakey); + assert_string_equal(bind->rsakey, LIBSSH_RSA_TESTKEY); +} + +static void torture_bind_config_hostkey_twice_rec(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_HOSTKEY_TWICE_REC); + assert_int_equal(rc, 0); + assert_non_null(bind->ed25519key); + assert_string_equal(bind->ed25519key, LIBSSH_ED25519_TESTKEY); + assert_non_null(bind->rsakey); + assert_string_equal(bind->rsakey, LIBSSH_RSA_TESTKEY); +} + +static void torture_bind_config_hostkey_separately(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_HOSTKEY); + assert_int_equal(rc, 0); + assert_non_null(bind->ed25519key); + assert_string_equal(bind->ed25519key, LIBSSH_ED25519_TESTKEY); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_HOSTKEY2); + assert_int_equal(rc, 0); + assert_non_null(bind->rsakey); + assert_string_equal(bind->rsakey, LIBSSH_RSA_TESTKEY); + assert_non_null(bind->ed25519key); + assert_string_equal(bind->ed25519key, LIBSSH_ED25519_TESTKEY); +} + +static void torture_bind_config_loglevel(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + int previous_level, new_level; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + previous_level = ssh_get_log_level(); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_LOGLEVEL); + assert_int_equal(rc, 0); + + new_level = ssh_get_log_level(); + assert_int_equal(new_level, 2); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_LOGLEVEL_TWICE); + assert_int_equal(rc, 0); + + new_level = ssh_get_log_level(); + assert_int_equal(new_level, 2); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_LOGLEVEL_TWICE_REC); + assert_int_equal(rc, 0); + + new_level = ssh_get_log_level(); + assert_int_equal(new_level, 2); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_LOGLEVEL2); + assert_int_equal(rc, 0); + + new_level = ssh_get_log_level(); + assert_int_equal(new_level, 1); + + rc = ssh_set_log_level(previous_level); + assert_int_equal(rc, SSH_OK); +} + +static void torture_bind_config_ciphers(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_CIPHERS); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_C_S]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_C_S], CIPHERS); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_S_C]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_S_C], CIPHERS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_CIPHERS_TWICE); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_C_S]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_C_S], CIPHERS); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_S_C]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_S_C], CIPHERS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_CIPHERS_TWICE_REC); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_C_S]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_C_S], CIPHERS); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_S_C]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_S_C], CIPHERS); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_CIPHERS2); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_C_S]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_C_S], CIPHERS2); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_S_C]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_S_C], CIPHERS2); + +} + +static void torture_bind_config_macs(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_MACS); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_MAC_S_C]); + assert_string_equal(bind->wanted_methods[SSH_MAC_S_C], MACS); + + assert_non_null(bind->wanted_methods[SSH_MAC_C_S]); + assert_string_equal(bind->wanted_methods[SSH_MAC_C_S], MACS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_MACS_TWICE); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_MAC_S_C]); + assert_string_equal(bind->wanted_methods[SSH_MAC_S_C], MACS); + + assert_non_null(bind->wanted_methods[SSH_MAC_C_S]); + assert_string_equal(bind->wanted_methods[SSH_MAC_C_S], MACS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_MACS_TWICE_REC); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_MAC_S_C]); + assert_string_equal(bind->wanted_methods[SSH_MAC_S_C], MACS); + + assert_non_null(bind->wanted_methods[SSH_MAC_C_S]); + assert_string_equal(bind->wanted_methods[SSH_MAC_C_S], MACS); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_MACS2); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_MAC_S_C]); + assert_string_equal(bind->wanted_methods[SSH_MAC_S_C], MACS2); + + assert_non_null(bind->wanted_methods[SSH_MAC_C_S]); + assert_string_equal(bind->wanted_methods[SSH_MAC_C_S], MACS2); +} + +static void torture_bind_config_kexalgorithms(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS); + assert_int_equal(rc, 0); + assert_non_null(bind->wanted_methods[SSH_KEX]); + assert_string_equal(bind->wanted_methods[SSH_KEX], KEXALGORITHMS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS_TWICE); + assert_int_equal(rc, 0); + assert_non_null(bind->wanted_methods[SSH_KEX]); + assert_string_equal(bind->wanted_methods[SSH_KEX], KEXALGORITHMS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS_TWICE_REC); + assert_int_equal(rc, 0); + assert_non_null(bind->wanted_methods[SSH_KEX]); + assert_string_equal(bind->wanted_methods[SSH_KEX], KEXALGORITHMS); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_KEXALGORITHMS2); + assert_int_equal(rc, 0); + assert_non_null(bind->wanted_methods[SSH_KEX]); + assert_string_equal(bind->wanted_methods[SSH_KEX], KEXALGORITHMS2); + +} + +static int assert_full_bind_config(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int new_level; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + new_level = ssh_get_log_level(); + assert_int_equal(new_level, 2); + + assert_non_null(bind->bindaddr); + assert_string_equal(bind->bindaddr, LISTEN_ADDRESS); + + assert_int_equal(bind->bindport, 123); + + assert_non_null(bind->ed25519key); + assert_string_equal(bind->ed25519key, LIBSSH_ED25519_TESTKEY); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_C_S]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_C_S], CIPHERS); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_S_C]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_S_C], CIPHERS); + + assert_non_null(bind->wanted_methods[SSH_MAC_S_C]); + assert_string_equal(bind->wanted_methods[SSH_MAC_S_C], MACS); + + assert_non_null(bind->wanted_methods[SSH_MAC_C_S]); + assert_string_equal(bind->wanted_methods[SSH_MAC_C_S], MACS); + + assert_non_null(bind->wanted_methods[SSH_KEX]); + assert_string_equal(bind->wanted_methods[SSH_KEX], KEXALGORITHMS); + + return 0; +} + +static void torture_bind_config_full(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + int previous_level; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + previous_level = ssh_get_log_level(); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_FULL); + assert_int_equal(rc, 0); + + rc = assert_full_bind_config(state); + assert_int_equal(rc, 0); + + rc = ssh_set_log_level(previous_level); + assert_int_equal(rc, SSH_OK); +} + +static void torture_bind_config_include(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + int previous_level; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + previous_level = ssh_get_log_level(); + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_INCLUDE); + assert_int_equal(rc, 0); + + rc = assert_full_bind_config(state); + assert_int_equal(rc, 0); + + rc = ssh_set_log_level(previous_level); + assert_int_equal(rc, SSH_OK); +} + +static void torture_bind_config_include_recursive(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + int previous_level; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + previous_level = ssh_get_log_level(); + + rc = ssh_bind_config_parse_file(bind, + LIBSSH_TEST_BIND_CONFIG_INCLUDE_RECURSIVE); + assert_int_equal(rc, 0); + + rc = assert_full_bind_config(state); + assert_int_equal(rc, 0); + + rc = ssh_set_log_level(previous_level); + assert_int_equal(rc, SSH_OK); +} + +/** + * @brief Verify the configuration parser does not choke on unknown + * or unsupported configuration options + */ +static void torture_bind_config_corner_cases(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_config_parse_file(bind, LIBSSH_TEST_BIND_CONFIG_CORNER_CASES); + assert_int_equal(rc, 0); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_C_S]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_C_S], CIPHERS); + + assert_non_null(bind->wanted_methods[SSH_CRYPT_S_C]); + assert_string_equal(bind->wanted_methods[SSH_CRYPT_S_C], CIPHERS); +} + +int torture_run_tests(void) +{ + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(torture_bind_config_listen_address, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_port, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_hostkey, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_hostkey_twice_rec, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_hostkey_separately, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_loglevel, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_ciphers, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_macs, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_kexalgorithms, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_full, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_include, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_include_recursive, + sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_config_corner_cases, + sshbind_setup, sshbind_teardown), + }; + + ssh_init(); + torture_filter_tests(tests); + rc = cmocka_run_group_tests(tests, NULL, NULL); + ssh_finalize(); + return rc; +}