torture_config.c: Add test for +,-,^ config feature

It should be possible to use features to add,remove,prioritize
algorithms in the algorithm list from the config file.

Signed-off-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
Norbert Pocs
2022-11-10 10:50:52 +01:00
committed by Jakub Jelen
parent 80c986bf89
commit abe222e1e8

View File

@@ -40,6 +40,9 @@ extern LIBSSH_THREAD int ssh_log_level;
#define LIBSSH_TESTCONFIG10 "libssh_testconfig10.tmp"
#define LIBSSH_TESTCONFIG11 "libssh_testconfig11.tmp"
#define LIBSSH_TESTCONFIG12 "libssh_testconfig12.tmp"
#define LIBSSH_TESTCONFIG14 "libssh_testconfig14.tmp"
#define LIBSSH_TESTCONFIG15 "libssh_testconfig15.tmp"
#define LIBSSH_TESTCONFIG16 "libssh_testconfig16.tmp"
#define LIBSSH_TESTCONFIGGLOB "libssh_testc*[36].tmp"
#define LIBSSH_TEST_PUBKEYTYPES "libssh_test_PubkeyAcceptedKeyTypes.tmp"
#define LIBSSH_TEST_PUBKEYALGORITHMS "libssh_test_PubkeyAcceptedAlgorithms.tmp"
@@ -181,6 +184,27 @@ extern LIBSSH_THREAD int ssh_log_level;
"IdentityFile id_rsa_one\n" \
"IdentityFile id_ecdsa_two\n"
/* +,-,^ features for all supported list */
/* kex won't work in fips */
#define LIBSSH_TESTCONFIG_STRING14 \
"HostKeyAlgorithms +ssh-rsa\n" \
"Ciphers +aes128-cbc,aes256-cbc\n" \
"KexAlgorithms +diffie-hellman-group14-sha1,diffie-hellman-group1-sha1\n" \
"MACs +hmac-sha1,hmac-sha1-etm@openssh.com\n"
/* have to be algorithms which are in the default list */
#define LIBSSH_TESTCONFIG_STRING15 \
"HostKeyAlgorithms -rsa-sha2-512,rsa-sha2-256\n" \
"Ciphers -aes256-ctr\n" \
"KexAlgorithms -diffie-hellman-group18-sha512,diffie-hellman-group16-sha512\n" \
"MACs -hmac-sha2-256-etm@openssh.com\n"
#define LIBSSH_TESTCONFIG_STRING16 \
"HostKeyAlgorithms ^rsa-sha2-512,rsa-sha2-256\n" \
"Ciphers ^aes256-cbc\n" \
"KexAlgorithms ^diffie-hellman-group18-sha512,diffie-hellman-group16-sha512\n" \
"MACs ^hmac-sha1\n"
#define LIBSSH_TEST_PUBKEYTYPES_STRING \
"PubkeyAcceptedKeyTypes "PUBKEYACCEPTEDTYPES"\n"
@@ -238,6 +262,9 @@ static int setup_config_files(void **state)
unlink(LIBSSH_TESTCONFIG10);
unlink(LIBSSH_TESTCONFIG11);
unlink(LIBSSH_TESTCONFIG12);
unlink(LIBSSH_TESTCONFIG14);
unlink(LIBSSH_TESTCONFIG15);
unlink(LIBSSH_TESTCONFIG16);
unlink(LIBSSH_TEST_PUBKEYTYPES);
unlink(LIBSSH_TEST_PUBKEYALGORITHMS);
unlink(LIBSSH_TEST_NONEWLINEEND);
@@ -285,6 +312,14 @@ static int setup_config_files(void **state)
torture_write_file(LIBSSH_TESTCONFIG12,
LIBSSH_TESTCONFIG_STRING12);
/* +,-,^ feature */
torture_write_file(LIBSSH_TESTCONFIG14,
LIBSSH_TESTCONFIG_STRING14);
torture_write_file(LIBSSH_TESTCONFIG15,
LIBSSH_TESTCONFIG_STRING15);
torture_write_file(LIBSSH_TESTCONFIG16,
LIBSSH_TESTCONFIG_STRING16);
torture_write_file(LIBSSH_TEST_PUBKEYTYPES,
LIBSSH_TEST_PUBKEYTYPES_STRING);
@@ -316,6 +351,9 @@ static int teardown_config_files(void **state)
unlink(LIBSSH_TESTCONFIG10);
unlink(LIBSSH_TESTCONFIG11);
unlink(LIBSSH_TESTCONFIG12);
unlink(LIBSSH_TESTCONFIG14);
unlink(LIBSSH_TESTCONFIG15);
unlink(LIBSSH_TESTCONFIG16);
unlink(LIBSSH_TEST_PUBKEYTYPES);
unlink(LIBSSH_TEST_PUBKEYALGORITHMS);
@@ -1267,6 +1305,349 @@ static void torture_config_rekey_string(void **state)
torture_config_rekey(state, NULL, LIBSSH_TESTCONFIG_STRING12);
}
/**
* @brief Remove substring from a string
*
* @param occurrence 0 means "remove the first occurrence"
* 1 means "remove the second occurrence" and so on
*/
static void helper_remove_substring(char *s, const char *subs, int occurrence) {
char *p;
/* remove the substring from the defaults */
p = strstr(s, subs);
assert_non_null(p);
/* look for second occurrence */
for (int i = 0; i < occurrence; i++) {
p = strstr(p + 1, subs);
assert_non_null(p);
}
memmove(p, p + strlen(subs), strlen(p + strlen(subs)) + 1);
}
/**
* @brief test that openssh style '+' feature works
*/
static void torture_config_plus(void **state,
const char *file, const char *string)
{
ssh_session session = *state;
const char *def_hostkeys = ssh_kex_get_default_methods(SSH_HOSTKEYS);
const char *fips_hostkeys = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
const char *def_ciphers = ssh_kex_get_default_methods(SSH_CRYPT_C_S);
const char *fips_ciphers = ssh_kex_get_fips_methods(SSH_CRYPT_C_S);
const char *def_kex = ssh_kex_get_default_methods(SSH_KEX);
const char *fips_kex = ssh_kex_get_fips_methods(SSH_KEX);
const char *def_mac = ssh_kex_get_default_methods(SSH_MAC_C_S);
const char *fips_mac = ssh_kex_get_fips_methods(SSH_MAC_C_S);
const char *hostkeys_added = ",ssh-rsa";
const char *ciphers_added = "aes128-cbc,aes256-cbc";
const char *kex_added = ",diffie-hellman-group14-sha1,diffie-hellman-group1-sha1";
const char *mac_added = ",hmac-sha1,hmac-sha1-etm@openssh.com";
char *awaited = NULL;
int rc;
_parse_config(session, file, string, SSH_OK);
/* check hostkeys */
if (ssh_fips_mode()) {
/* ssh-rsa is disabled in fips */
assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], fips_hostkeys);
} else {
awaited = calloc(strlen(def_hostkeys) + strlen(hostkeys_added) + 1, 1);
rc = snprintf(awaited, strlen(def_hostkeys) + strlen(hostkeys_added) + 1,
"%s%s", def_hostkeys, hostkeys_added);
assert_int_equal(rc, strlen(def_hostkeys) + strlen(hostkeys_added));
assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], awaited);
free(awaited);
}
/* check ciphers */
if (ssh_fips_mode()) {
/* already all supported is in the list */
assert_string_equal(session->opts.wanted_methods[SSH_CRYPT_C_S], fips_ciphers);
} else {
awaited = calloc(strlen(def_ciphers) + strlen(ciphers_added) + 1, 1);
rc = snprintf(awaited, strlen(def_ciphers) + strlen(ciphers_added) + 1,
"%s%s", def_ciphers, ciphers_added);
assert_int_equal(rc, strlen(def_ciphers) + strlen(ciphers_added));
assert_string_equal(session->opts.wanted_methods[SSH_CRYPT_C_S], awaited);
free(awaited);
}
/* check kex */
if (ssh_fips_mode()) {
/* sha1 is disabled in fips */
assert_string_equal(session->opts.wanted_methods[SSH_KEX], fips_kex);
} else {
awaited = calloc(strlen(def_kex) + strlen(kex_added) + 1, 1);
rc = snprintf(awaited, strlen(def_kex) + strlen(kex_added) + 1,
"%s%s", def_kex, kex_added);
assert_int_equal(rc, strlen(def_kex) + strlen(kex_added));
assert_string_equal(session->opts.wanted_methods[SSH_KEX], awaited);
free(awaited);
}
/* check mac */
if (ssh_fips_mode()) {
/* the added algos are already in the fips_methods */
assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], fips_mac);
} else {
awaited = calloc(strlen(def_mac) + strlen(mac_added) + 1, 1);
rc = snprintf(awaited, strlen(def_mac) + strlen(mac_added) + 1,
"%s%s", def_mac, mac_added);
assert_int_equal(rc, strlen(def_mac) + strlen(mac_added));
assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], awaited);
free(awaited);
}
}
/**
* @brief test that openssh style '+' feature works from file
*/
static void torture_config_plus_file(void **state)
{
torture_config_plus(state, LIBSSH_TESTCONFIG14, NULL);
}
/**
* @brief test that openssh style '+' feature works from string
*/
static void torture_config_plus_string(void **state)
{
torture_config_plus(state, NULL, LIBSSH_TESTCONFIG_STRING14);
}
/**
* @brief test that openssh style '-' feature works from string
*/
static void torture_config_minus(void **state,
const char *file, const char *string)
{
ssh_session session = *state;
const char *def_hostkeys = ssh_kex_get_default_methods(SSH_HOSTKEYS);
const char *fips_hostkeys = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
const char *def_ciphers = ssh_kex_get_default_methods(SSH_CRYPT_C_S);
const char *fips_ciphers = ssh_kex_get_fips_methods(SSH_CRYPT_C_S);
const char *def_kex = ssh_kex_get_default_methods(SSH_KEX);
const char *fips_kex = ssh_kex_get_fips_methods(SSH_KEX);
const char *def_mac = ssh_kex_get_default_methods(SSH_MAC_C_S);
const char *fips_mac = ssh_kex_get_fips_methods(SSH_MAC_C_S);
const char *hostkeys_removed = ",rsa-sha2-512,rsa-sha2-256";
const char *ciphers_removed = ",aes256-ctr";
const char *kex_removed = ",diffie-hellman-group18-sha512,diffie-hellman-group16-sha512";
const char *fips_kex_removed = ",diffie-hellman-group16-sha512,diffie-hellman-group18-sha512";
const char *mac_removed = "hmac-sha2-256-etm@openssh.com,";
char *awaited = NULL;
int rc;
_parse_config(session, file, string, SSH_OK);
/* check hostkeys */
if (ssh_fips_mode()) {
awaited = calloc(strlen(fips_hostkeys) + 1, 1);
rc = snprintf(awaited, strlen(fips_hostkeys) + 1, "%s", fips_hostkeys);
assert_int_equal(rc, strlen(fips_hostkeys));
} else {
awaited = calloc(strlen(def_hostkeys) + 1, 1);
rc = snprintf(awaited, strlen(def_hostkeys) + 1, "%s", def_hostkeys);
assert_int_equal(rc, strlen(def_hostkeys));
}
/* remove the substring from the defaults */
helper_remove_substring(awaited, hostkeys_removed, 0);
assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], awaited);
free(awaited);
/* check ciphers */
if (ssh_fips_mode()) {
awaited = calloc(strlen(fips_ciphers) + 1, 1);
rc = snprintf(awaited, strlen(fips_ciphers) + 1, "%s", fips_ciphers);
assert_int_equal(rc, strlen(fips_ciphers));
} else {
awaited = calloc(strlen(def_ciphers) + 1, 1);
rc = snprintf(awaited, strlen(def_ciphers) + 1, "%s", def_ciphers);
assert_int_equal(rc, strlen(def_ciphers));
/* remove the comma at the end of the list */
awaited[strlen(awaited) - 1] = '\0';
}
/* remove the substring from the defaults */
helper_remove_substring(awaited, ciphers_removed, 0);
assert_string_equal(session->opts.wanted_methods[SSH_CRYPT_C_S], awaited);
free(awaited);
/* check kex */
if (ssh_fips_mode()) {
awaited = calloc(strlen(fips_kex) + 1, 1);
rc = snprintf(awaited, strlen(fips_kex) + 1, "%s", fips_kex);
assert_int_equal(rc, strlen(fips_kex));
/* remove the substring from the defaults */
helper_remove_substring(awaited, fips_kex_removed, 0);
} else {
awaited = calloc(strlen(def_kex) + 1, 1);
rc = snprintf(awaited, strlen(def_kex) + 1, "%s", def_kex);
assert_int_equal(rc, strlen(def_kex));
/* remove the substring from the defaults */
helper_remove_substring(awaited, kex_removed, 0);
}
assert_string_equal(session->opts.wanted_methods[SSH_KEX], awaited);
free(awaited);
/* check mac */
if (ssh_fips_mode()) {
awaited = calloc(strlen(fips_mac) + 1, 1);
rc = snprintf(awaited, strlen(fips_mac) + 1, "%s", fips_mac);
assert_int_equal(rc, strlen(fips_mac));
} else {
awaited = calloc(strlen(def_mac) + 1, 1);
rc = snprintf(awaited, strlen(def_mac) + 1, "%s", def_mac);
assert_int_equal(rc, strlen(def_mac));
}
/* remove the substring from the defaults */
helper_remove_substring(awaited, mac_removed, 0);
assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], awaited);
free(awaited);
}
/**
* @brief test that openssh style '-' feature works from file
*/
static void torture_config_minus_file(void **state)
{
torture_config_minus(state, LIBSSH_TESTCONFIG15, NULL);
}
/**
* @brief test that openssh style '-' feature works from string
*/
static void torture_config_minus_string(void **state)
{
torture_config_minus(state, NULL, LIBSSH_TESTCONFIG_STRING15);
}
/**
* @brief test that openssh style '^' feature works from string
*/
static void torture_config_caret(void **state,
const char *file, const char *string)
{
ssh_session session = *state;
const char *def_hostkeys = ssh_kex_get_default_methods(SSH_HOSTKEYS);
const char *fips_hostkeys = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
const char *def_ciphers = ssh_kex_get_default_methods(SSH_CRYPT_C_S);
const char *fips_ciphers = ssh_kex_get_fips_methods(SSH_CRYPT_C_S);
const char *def_kex = ssh_kex_get_default_methods(SSH_KEX);
const char *fips_kex = ssh_kex_get_fips_methods(SSH_KEX);
const char *def_mac = ssh_kex_get_default_methods(SSH_MAC_C_S);
const char *fips_mac = ssh_kex_get_fips_methods(SSH_MAC_C_S);
const char *hostkeys_prio = "rsa-sha2-512,rsa-sha2-256";
const char *ciphers_prio = "aes256-cbc,";
const char *kex_prio = "diffie-hellman-group18-sha512,diffie-hellman-group16-sha512,";
const char *fips_kex_prio = ",diffie-hellman-group16-sha512,diffie-hellman-group18-sha512";
const char *mac_prio = "hmac-sha1,";
char *awaited = NULL;
int rc;
_parse_config(session, file, string, SSH_OK);
/* check hostkeys */
/* +2 for the added comma and the \0 */
if (ssh_fips_mode()) {
awaited = calloc(strlen(hostkeys_prio) + strlen(fips_hostkeys) + 2, 1);
rc = snprintf(awaited, strlen(hostkeys_prio) + strlen(fips_hostkeys) + 2,
"%s,%s", hostkeys_prio, fips_hostkeys);
assert_int_equal(rc, strlen(hostkeys_prio) + strlen(fips_hostkeys) + 1);
} else {
awaited = calloc(strlen(def_hostkeys) + strlen(hostkeys_prio) + 2, 1);
rc = snprintf(awaited, strlen(hostkeys_prio) + strlen(def_hostkeys) + 2,
"%s,%s", hostkeys_prio, def_hostkeys);
assert_int_equal(rc, strlen(hostkeys_prio) + strlen(def_hostkeys) + 1);
}
/* remove the substring from the defaults */
helper_remove_substring(awaited, hostkeys_prio, 1);
/* remove the comma at the end of the list */
awaited[strlen(awaited) - 1] = '\0';
assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], awaited);
free(awaited);
/* check ciphers */
if (ssh_fips_mode()) {
awaited = calloc(strlen(ciphers_prio) + strlen(fips_ciphers) + 1, 1);
rc = snprintf(awaited, strlen(ciphers_prio) + strlen(fips_ciphers) + 1,
"%s%s", ciphers_prio, fips_ciphers);
assert_int_equal(rc, strlen(ciphers_prio) + strlen(fips_ciphers));
/* remove the substring from the defaults */
helper_remove_substring(awaited, ciphers_prio, 1);
} else {
/* + 2 because the '\0' and the comma */
awaited = calloc(strlen(ciphers_prio) + strlen(def_ciphers) + 1, 1);
rc = snprintf(awaited, strlen(ciphers_prio) + strlen(def_ciphers) + 1,
"%s%s", ciphers_prio, def_ciphers);
assert_int_equal(rc, strlen(ciphers_prio) + strlen(def_ciphers));
/* remove the comma at the end of the list */
awaited[strlen(awaited) - 1] = '\0';
}
assert_string_equal(session->opts.wanted_methods[SSH_CRYPT_C_S], awaited);
free(awaited);
/* check kex */
if (ssh_fips_mode()) {
awaited = calloc(strlen(kex_prio) + strlen(fips_kex) + 1, 1);
rc = snprintf(awaited, strlen(kex_prio) + strlen(fips_kex) + 1,
"%s%s", kex_prio, fips_kex);
assert_int_equal(rc, strlen(kex_prio) + strlen(fips_kex));
/* remove the substring from the defaults */
/* the default list has different order of these two algos than the fips
* and because here is a braindead string substitution being done,
* change the order and remove the first occurrence of it */
helper_remove_substring(awaited, fips_kex_prio, 0);
} else {
awaited = calloc(strlen(kex_prio) + strlen(def_kex) + 1, 1);
rc = snprintf(awaited, strlen(kex_prio) + strlen(def_kex) + 1,
"%s%s", kex_prio, def_kex);
assert_int_equal(rc, strlen(def_kex) + strlen(kex_prio));
/* remove the substring from the defaults */
helper_remove_substring(awaited, kex_prio, 1);
}
assert_string_equal(session->opts.wanted_methods[SSH_KEX], awaited);
free(awaited);
/* check mac */
if (ssh_fips_mode()) {
awaited = calloc(strlen(mac_prio) + strlen(fips_mac) + 1, 1);
rc = snprintf(awaited, strlen(mac_prio) + strlen(fips_mac) + 1, "%s%s", mac_prio, fips_mac);
assert_int_equal(rc, strlen(mac_prio) + strlen(fips_mac));
/* the fips list contains hmac-sha1 algo */
helper_remove_substring(awaited, mac_prio, 1);
} else {
awaited = calloc(strlen(mac_prio) + strlen(def_mac) + 1, 1);
/* the mac is not in default; it is added to the list */
rc = snprintf(awaited, strlen(mac_prio) + strlen(def_mac) + 1, "%s%s", mac_prio, def_mac);
assert_int_equal(rc, strlen(mac_prio) + strlen(def_mac));
}
assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], awaited);
free(awaited);
}
/**
* @brief test that openssh style '^' feature works from file
*/
static void torture_config_caret_file(void **state)
{
torture_config_caret(state, LIBSSH_TESTCONFIG16, NULL);
}
/**
* @brief test that openssh style '^' feature works from string
*/
static void torture_config_caret_string(void **state)
{
torture_config_caret(state, NULL, LIBSSH_TESTCONFIG_STRING16);
}
/**
* @brief test PubkeyAcceptedKeyTypes helper function
*/
@@ -1848,6 +2229,18 @@ int torture_run_tests(void)
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_rekey_string,
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_plus_file,
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_plus_string,
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_minus_file,
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_minus_string,
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_caret_file,
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_caret_string,
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_pubkeytypes_file,
setup, teardown),
cmocka_unit_test_setup_teardown(torture_config_pubkeytypes_string,