[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 04/17] tests: add migration tests of TLS with x509 credentials
From: |
Dr. David Alan Gilbert (git) |
Subject: |
[PULL 04/17] tests: add migration tests of TLS with x509 credentials |
Date: |
Mon, 16 May 2022 16:37:59 +0100 |
From: Daniel P. Berrangé <berrange@redhat.com>
This validates that we correctly handle migration success and failure
scenarios when using TLS with x509 certificates. There are quite a few
different scenarios that matter in relation to hostname validation.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20220426160048.812266-5-berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
dgilbert: Manual merge due to ifdef change in 3
---
meson.build | 1 +
tests/qtest/meson.build | 5 +
tests/qtest/migration-test.c | 383 ++++++++++++++++++++++++++++++++++-
3 files changed, 386 insertions(+), 3 deletions(-)
diff --git a/meson.build b/meson.build
index 9b20dcd143..93aa31a9e4 100644
--- a/meson.build
+++ b/meson.build
@@ -1742,6 +1742,7 @@ config_host_data.set('CONFIG_KEYUTILS', keyutils.found())
config_host_data.set('CONFIG_GETTID', has_gettid)
config_host_data.set('CONFIG_GNUTLS', gnutls.found())
config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
+config_host_data.set('CONFIG_TASN1', tasn1.found())
config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
config_host_data.set('CONFIG_NETTLE', nettle.found())
config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 166450135d..b425484920 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -276,6 +276,11 @@ tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c']
migration_files = [files('migration-helpers.c')]
if gnutls.found()
migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls]
+
+ if tasn1.found()
+ migration_files += [files('../unit/crypto-tls-x509-helpers.c',
+ '../unit/pkix_asn1_tab.c'), tasn1]
+ endif
endif
qtests = {
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 2eefc9c1ff..5a3edf2da6 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -29,6 +29,9 @@
#include "tests/migration/migration-test.h"
#ifdef CONFIG_GNUTLS
# include "tests/unit/crypto-tls-psk-helpers.h"
+# ifdef CONFIG_TASN1
+# include "tests/unit/crypto-tls-x509-helpers.h"
+# endif /* CONFIG_TASN1 */
#endif /* CONFIG_GNUTLS */
/* For dirty ring test; so far only x86_64 is supported */
@@ -736,6 +739,234 @@ test_migrate_tls_psk_finish(QTestState *from,
g_free(data->pskfile);
g_free(data);
}
+
+#ifdef CONFIG_TASN1
+typedef struct {
+ char *workdir;
+ char *keyfile;
+ char *cacert;
+ char *servercert;
+ char *serverkey;
+ char *clientcert;
+ char *clientkey;
+} TestMigrateTLSX509Data;
+
+typedef struct {
+ bool verifyclient;
+ bool clientcert;
+ bool hostileclient;
+ bool authzclient;
+ const char *certhostname;
+ const char *certipaddr;
+} TestMigrateTLSX509;
+
+static void *
+test_migrate_tls_x509_start_common(QTestState *from,
+ QTestState *to,
+ TestMigrateTLSX509 *args)
+{
+ TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
+ QDict *rsp;
+
+ data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
+ data->keyfile = g_strdup_printf("%s/key.pem", data->workdir);
+
+ data->cacert = g_strdup_printf("%s/ca-cert.pem", data->workdir);
+ data->serverkey = g_strdup_printf("%s/server-key.pem", data->workdir);
+ data->servercert = g_strdup_printf("%s/server-cert.pem", data->workdir);
+ if (args->clientcert) {
+ data->clientkey = g_strdup_printf("%s/client-key.pem", data->workdir);
+ data->clientcert = g_strdup_printf("%s/client-cert.pem",
data->workdir);
+ }
+
+ mkdir(data->workdir, 0700);
+
+ test_tls_init(data->keyfile);
+ g_assert(link(data->keyfile, data->serverkey) == 0);
+ if (args->clientcert) {
+ g_assert(link(data->keyfile, data->clientkey) == 0);
+ }
+
+ TLS_ROOT_REQ_SIMPLE(cacertreq, data->cacert);
+ if (args->clientcert) {
+ TLS_CERT_REQ_SIMPLE_CLIENT(servercertreq, cacertreq,
+ args->hostileclient ?
+ QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME :
+ QCRYPTO_TLS_TEST_CLIENT_NAME,
+ data->clientcert);
+ }
+
+ TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq,
+ data->servercert,
+ args->certhostname,
+ args->certipaddr);
+
+ rsp = wait_command(from,
+ "{ 'execute': 'object-add',"
+ " 'arguments': { 'qom-type': 'tls-creds-x509',"
+ " 'id': 'tlscredsx509client0',"
+ " 'endpoint': 'client',"
+ " 'dir': %s,"
+ " 'sanity-check': true,"
+ " 'verify-peer': true} }",
+ data->workdir);
+ qobject_unref(rsp);
+ migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0");
+ if (args->certhostname) {
+ migrate_set_parameter_str(from, "tls-hostname", args->certhostname);
+ }
+
+ rsp = wait_command(to,
+ "{ 'execute': 'object-add',"
+ " 'arguments': { 'qom-type': 'tls-creds-x509',"
+ " 'id': 'tlscredsx509server0',"
+ " 'endpoint': 'server',"
+ " 'dir': %s,"
+ " 'sanity-check': true,"
+ " 'verify-peer': %i} }",
+ data->workdir, args->verifyclient);
+ qobject_unref(rsp);
+ migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0");
+
+ if (args->authzclient) {
+ rsp = wait_command(to,
+ "{ 'execute': 'object-add',"
+ " 'arguments': { 'qom-type': 'authz-simple',"
+ " 'id': 'tlsauthz0',"
+ " 'identity': %s} }",
+ "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME);
+ migrate_set_parameter_str(to, "tls-authz", "tlsauthz0");
+ }
+
+ return data;
+}
+
+/*
+ * The normal case: match server's cert hostname against
+ * whatever host we were telling QEMU to connect to (if any)
+ */
+static void *
+test_migrate_tls_x509_start_default_host(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .certipaddr = "127.0.0.1"
+ };
+ return test_migrate_tls_x509_start_common(from, to, &args);
+}
+
+/*
+ * The unusual case: the server's cert is different from
+ * the address we're telling QEMU to connect to (if any),
+ * so we must give QEMU an explicit hostname to validate
+ */
+static void *
+test_migrate_tls_x509_start_override_host(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .certhostname = "qemu.org",
+ };
+ return test_migrate_tls_x509_start_common(from, to, &args);
+}
+
+/*
+ * The unusual case: the server's cert is different from
+ * the address we're telling QEMU to connect to, and so we
+ * expect the client to reject the server
+ */
+static void *
+test_migrate_tls_x509_start_mismatch_host(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .certipaddr = "10.0.0.1",
+ };
+ return test_migrate_tls_x509_start_common(from, to, &args);
+}
+
+static void *
+test_migrate_tls_x509_start_friendly_client(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .authzclient = true,
+ .certipaddr = "127.0.0.1",
+ };
+ return test_migrate_tls_x509_start_common(from, to, &args);
+}
+
+static void *
+test_migrate_tls_x509_start_hostile_client(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .clientcert = true,
+ .hostileclient = true,
+ .authzclient = true,
+ .certipaddr = "127.0.0.1",
+ };
+ return test_migrate_tls_x509_start_common(from, to, &args);
+}
+
+/*
+ * The case with no client certificate presented,
+ * and no server verification
+ */
+static void *
+test_migrate_tls_x509_start_allow_anon_client(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .certipaddr = "127.0.0.1",
+ };
+ return test_migrate_tls_x509_start_common(from, to, &args);
+}
+
+/*
+ * The case with no client certificate presented,
+ * and server verification rejecting
+ */
+static void *
+test_migrate_tls_x509_start_reject_anon_client(QTestState *from,
+ QTestState *to)
+{
+ TestMigrateTLSX509 args = {
+ .verifyclient = true,
+ .certipaddr = "127.0.0.1",
+ };
+ return test_migrate_tls_x509_start_common(from, to, &args);
+}
+
+static void
+test_migrate_tls_x509_finish(QTestState *from,
+ QTestState *to,
+ void *opaque)
+{
+ TestMigrateTLSX509Data *data = opaque;
+
+ test_tls_cleanup(data->keyfile);
+ unlink(data->cacert);
+ unlink(data->servercert);
+ unlink(data->serverkey);
+ unlink(data->clientcert);
+ unlink(data->clientkey);
+ rmdir(data->workdir);
+
+ g_free(data->workdir);
+ g_free(data->keyfile);
+ g_free(data);
+}
+#endif /* CONFIG_TASN1 */
#endif /* CONFIG_GNUTLS */
static int migrate_postcopy_prepare(QTestState **from_ptr,
@@ -1020,6 +1251,21 @@ static void test_precopy_unix_plain(void)
test_precopy_common(&args);
}
+
+static void test_precopy_unix_dirty_ring(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .start = {
+ .use_dirty_ring = true,
+ },
+ .listen_uri = uri,
+ .connect_uri = uri,
+ };
+
+ test_precopy_common(&args);
+}
+
#ifdef CONFIG_GNUTLS
static void test_precopy_unix_tls_psk(void)
{
@@ -1033,21 +1279,39 @@ static void test_precopy_unix_tls_psk(void)
test_precopy_common(&args);
}
-#endif
-static void test_precopy_unix_dirty_ring(void)
+#ifdef CONFIG_TASN1
+static void test_precopy_unix_tls_x509_default_host(void)
{
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
MigrateCommon args = {
.start = {
- .use_dirty_ring = true,
+ .hide_stderr = true,
},
+ .connect_uri = uri,
.listen_uri = uri,
+ .start_hook = test_migrate_tls_x509_start_default_host,
+ .finish_hook = test_migrate_tls_x509_finish,
+ .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_unix_tls_x509_override_host(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
.connect_uri = uri,
+ .listen_uri = uri,
+ .start_hook = test_migrate_tls_x509_start_override_host,
+ .finish_hook = test_migrate_tls_x509_finish,
};
test_precopy_common(&args);
}
+#endif /* CONFIG_TASN1 */
+#endif /* CONFIG_GNUTLS */
#if 0
/* Currently upset on aarch64 TCG */
@@ -1174,6 +1438,97 @@ static void test_precopy_tcp_tls_psk_mismatch(void)
test_precopy_common(&args);
}
+
+#ifdef CONFIG_TASN1
+static void test_precopy_tcp_tls_x509_default_host(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = test_migrate_tls_x509_start_default_host,
+ .finish_hook = test_migrate_tls_x509_finish,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_override_host(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = test_migrate_tls_x509_start_override_host,
+ .finish_hook = test_migrate_tls_x509_finish,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_mismatch_host(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = test_migrate_tls_x509_start_mismatch_host,
+ .finish_hook = test_migrate_tls_x509_finish,
+ .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_friendly_client(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = test_migrate_tls_x509_start_friendly_client,
+ .finish_hook = test_migrate_tls_x509_finish,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_hostile_client(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = test_migrate_tls_x509_start_hostile_client,
+ .finish_hook = test_migrate_tls_x509_finish,
+ .result = MIG_TEST_FAIL,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_allow_anon_client(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = test_migrate_tls_x509_start_allow_anon_client,
+ .finish_hook = test_migrate_tls_x509_finish,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_tcp_tls_x509_reject_anon_client(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "tcp:127.0.0.1:0",
+ .start_hook = test_migrate_tls_x509_start_reject_anon_client,
+ .finish_hook = test_migrate_tls_x509_finish,
+ .result = MIG_TEST_FAIL,
+ };
+
+ test_precopy_common(&args);
+}
+#endif /* CONFIG_TASN1 */
#endif /* CONFIG_GNUTLS */
static void *test_migrate_fd_start_hook(QTestState *from,
@@ -1642,6 +1997,12 @@ int main(int argc, char **argv)
#ifdef CONFIG_GNUTLS
qtest_add_func("/migration/precopy/unix/tls/psk",
test_precopy_unix_tls_psk);
+#ifdef CONFIG_TASN1
+ qtest_add_func("/migration/precopy/unix/tls/x509/default-host",
+ test_precopy_unix_tls_x509_default_host);
+ qtest_add_func("/migration/precopy/unix/tls/x509/override-host",
+ test_precopy_unix_tls_x509_override_host);
+#endif /* CONFIG_TASN1 */
#endif /* CONFIG_GNUTLS */
qtest_add_func("/migration/precopy/tcp/plain", test_precopy_tcp_plain);
@@ -1650,6 +2011,22 @@ int main(int argc, char **argv)
test_precopy_tcp_tls_psk_match);
qtest_add_func("/migration/precopy/tcp/tls/psk/mismatch",
test_precopy_tcp_tls_psk_mismatch);
+#ifdef CONFIG_TASN1
+ qtest_add_func("/migration/precopy/tcp/tls/x509/default-host",
+ test_precopy_tcp_tls_x509_default_host);
+ qtest_add_func("/migration/precopy/tcp/tls/x509/override-host",
+ test_precopy_tcp_tls_x509_override_host);
+ qtest_add_func("/migration/precopy/tcp/tls/x509/mismatch-host",
+ test_precopy_tcp_tls_x509_mismatch_host);
+ qtest_add_func("/migration/precopy/tcp/tls/x509/friendly-client",
+ test_precopy_tcp_tls_x509_friendly_client);
+ qtest_add_func("/migration/precopy/tcp/tls/x509/hostile-client",
+ test_precopy_tcp_tls_x509_hostile_client);
+ qtest_add_func("/migration/precopy/tcp/tls/x509/allow-anon-client",
+ test_precopy_tcp_tls_x509_allow_anon_client);
+ qtest_add_func("/migration/precopy/tcp/tls/x509/reject-anon-client",
+ test_precopy_tcp_tls_x509_reject_anon_client);
+#endif /* CONFIG_TASN1 */
#endif /* CONFIG_GNUTLS */
/* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */
--
2.36.1
- [PULL 00/17] migration queue, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 01/17] tests: fix encoding of IP addresses in x509 certs, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 03/17] tests: add migration tests of TLS with PSK credentials, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 02/17] tests: add more helper macros for creating TLS x509 certs, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 05/17] tests: convert XBZRLE migration test to use common helper, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 04/17] tests: add migration tests of TLS with x509 credentials,
Dr. David Alan Gilbert (git) <=
- [PULL 06/17] tests: convert multifd migration tests to use common helper, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 07/17] tests: add multifd migration tests of TLS with PSK credentials, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 08/17] tests: add multifd migration tests of TLS with x509 credentials, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 10/17] meson.build: Fix docker-test-build@alpine when including linux/errqueue.h, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 09/17] tests: ensure migration status isn't reported as failed, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 11/17] QIOChannel: Add flags on io_writev and introduce io_flush callback, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 13/17] migration: Add zero-copy-send parameter for QMP/HMP for Linux, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 12/17] QIOChannelSocket: Implement io_writev zero copy flag & io_flush for CONFIG_LINUX, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 16/17] multifd: Send header packet without flags if zero-copy-send is enabled, Dr. David Alan Gilbert (git), 2022/05/16
- [PULL 14/17] migration: Add migrate_use_tls() helper, Dr. David Alan Gilbert (git), 2022/05/16