aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorSteffan Karger2016-11-08 21:18:22 +0100
committerGert Doering2016-11-16 20:09:08 +0100
commit3b185161de1254af746494007b7e81d17f632d4b (patch)
tree09eeec3253f795dde8a2e1ad5b398276f32fc7e1 /tests
parentc6e24fa3e16c32f9b427e360fd07102f613aa5c6 (diff)
downloadopenvpn-3b185161de1254af746494007b7e81d17f632d4b.zip
openvpn-3b185161de1254af746494007b7e81d17f632d4b.tar.gz
Add --tls-crypt unit tests
These help verify the tls-crypt functionality - they already caught a bug during development. We should however probably also add some t_client tests once this feature is in. To test --tls-crypt with as few dependencies as possible, this adds a mock implementation of msg() (or actually x_msg()). For debugging purposes, the mock implementation can be made to really log by calling mock_set_debug_level(), but defaults to (almost) no logging. Signed-off-by: Steffan Karger <steffan.karger@fox-it.com> Acked-by: Gert Doering <gert@greenie.muc.de> Message-Id: <1478636302-9678-6-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12973.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Diffstat (limited to 'tests')
-rw-r--r--tests/unit_tests/openvpn/Makefile.am22
-rw-r--r--tests/unit_tests/openvpn/mock_msg.c92
-rw-r--r--tests/unit_tests/openvpn/mock_msg.h35
-rw-r--r--tests/unit_tests/openvpn/test_argv.c10
-rw-r--r--tests/unit_tests/openvpn/test_tls_crypt.c242
5 files changed, 390 insertions, 11 deletions
diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am
index b706fae..632ff58 100644
--- a/tests/unit_tests/openvpn/Makefile.am
+++ b/tests/unit_tests/openvpn/Makefile.am
@@ -2,8 +2,13 @@ AUTOMAKE_OPTIONS = foreign
check_PROGRAMS = argv_testdriver
+if ENABLE_CRYPTO
+check_PROGRAMS += tls_crypt_testdriver
+endif
+
TESTS = $(check_PROGRAMS)
+openvpn_includedir = $(top_srcdir)/include
openvpn_srcdir = $(top_srcdir)/src/openvpn
compat_srcdir = $(top_srcdir)/src/compat
@@ -11,7 +16,22 @@ argv_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) \
$(OPTIONAL_CRYPTO_CFLAGS)
argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line \
$(OPTIONAL_CRYPTO_LIBS)
-argv_testdriver_SOURCES = test_argv.c \
+argv_testdriver_SOURCES = test_argv.c mock_msg.c \
$(openvpn_srcdir)/platform.c \
$(openvpn_srcdir)/buffer.c \
$(openvpn_srcdir)/argv.c
+
+tls_crypt_testdriver_CFLAGS = @TEST_CFLAGS@ \
+ -I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \
+ $(OPTIONAL_CRYPTO_CFLAGS)
+tls_crypt_testdriver_LDFLAGS = @TEST_LDFLAGS@ \
+ $(OPTIONAL_CRYPTO_LIBS)
+tls_crypt_testdriver_SOURCES = test_tls_crypt.c mock_msg.c \
+ $(openvpn_srcdir)/buffer.c \
+ $(openvpn_srcdir)/crypto.c \
+ $(openvpn_srcdir)/crypto_mbedtls.c \
+ $(openvpn_srcdir)/crypto_openssl.c \
+ $(openvpn_srcdir)/otime.c \
+ $(openvpn_srcdir)/packet_id.c \
+ $(openvpn_srcdir)/platform.c \
+ $(openvpn_srcdir)/tls_crypt.c
diff --git a/tests/unit_tests/openvpn/mock_msg.c b/tests/unit_tests/openvpn/mock_msg.c
new file mode 100644
index 0000000..54b6017
--- /dev/null
+++ b/tests/unit_tests/openvpn/mock_msg.c
@@ -0,0 +1,92 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2016 Fox Crypto B.V. <openvpn@fox-it.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "errlevel.h"
+#include "error.h"
+
+unsigned int x_debug_level = 0; /* Default to (almost) no debugging output */
+bool fatal_error_triggered = false;
+
+void mock_set_debug_level(int level)
+{
+ x_debug_level = level;
+}
+
+void x_msg_va (const unsigned int flags, const char *format,
+ va_list arglist)
+{
+ if (flags & M_FATAL)
+ {
+ fatal_error_triggered = true;
+ printf("FATAL ERROR:");
+ }
+ vprintf(format, arglist);
+ printf("\n");
+}
+
+void x_msg (const unsigned int flags, const char *format, ...)
+{
+ va_list arglist;
+ va_start (arglist, format);
+ x_msg_va (flags, format, arglist);
+ va_end (arglist);
+}
+
+void
+assert_failed (const char *filename, int line, const char *condition)
+{
+ if (condition)
+ printf ("Assertion failed at %s:%d (%s)", filename, line, condition);
+ else
+ printf ("Assertion failed at %s:%d", filename, line);
+ exit (1);
+}
+
+/*
+ * Fail memory allocation. Don't use msg() because it tries
+ * to allocate memory as part of its operation.
+ */
+void
+out_of_memory (void)
+{
+ fprintf (stderr, "Out of Memory\n");
+ exit (1);
+}
+
+bool
+dont_mute (unsigned int flags)
+{
+ return true;
+}
diff --git a/tests/unit_tests/openvpn/mock_msg.h b/tests/unit_tests/openvpn/mock_msg.h
new file mode 100644
index 0000000..5d93a1a
--- /dev/null
+++ b/tests/unit_tests/openvpn/mock_msg.h
@@ -0,0 +1,35 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2016 Fox Crypto B.V. <openvpn@fox-it.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MOCK_MSG_H
+#define MOCK_MSG_H
+
+/**
+ * Mock debug level defaults to 0, which gives clean(-ish) test reports. Call
+ * this function from your test driver to increase debug output when you
+ * need debug output.
+ */
+void mock_set_debug_level(int level);
+
+#endif /* MOCK_MSG */
diff --git a/tests/unit_tests/openvpn/test_argv.c b/tests/unit_tests/openvpn/test_argv.c
index 3945634..4d17557 100644
--- a/tests/unit_tests/openvpn/test_argv.c
+++ b/tests/unit_tests/openvpn/test_argv.c
@@ -14,16 +14,6 @@
#include "buffer.h"
/*
- * Dummy symbols that need to be defined due to them being
- * referenced in #include'd header files and their includes
- */
-unsigned int x_debug_level;
-bool dont_mute (unsigned int flags) { return true; }
-void assert_failed (const char *filename, int line, const char *condition) { exit(0); }
-void out_of_memory (void) { }
-void x_msg (const unsigned int flags, const char *format, ...) { }
-
-/*
* This is defined here to prevent #include'ing misc.h
* which makes things difficult beyond any recognition
*/
diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c
new file mode 100644
index 0000000..473a232
--- /dev/null
+++ b/tests/unit_tests/openvpn/test_tls_crypt.c
@@ -0,0 +1,242 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2016 Fox Crypto B.V. <openvpn@fox-it.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#ifdef ENABLE_CRYPTO
+
+#include "syshead.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "tls_crypt.h"
+
+#include "mock_msg.h"
+
+#define TESTBUF_SIZE 128
+
+const char plaintext_short[1];
+
+struct test_context {
+ struct crypto_options co;
+ struct key_type kt;
+ struct buffer source;
+ struct buffer ciphertext;
+ struct buffer unwrapped;
+};
+
+static int setup(void **state) {
+ struct test_context *ctx = calloc(1, sizeof(*ctx));
+
+ ctx->kt.cipher = cipher_kt_get ("AES-256-CTR");
+ ctx->kt.cipher_length = cipher_kt_key_size (ctx->kt.cipher);
+ ctx->kt.digest = md_kt_get ("SHA256");
+ ctx->kt.hmac_length = md_kt_size (ctx->kt.digest);
+
+ struct key key = { 0 };
+
+ init_key_ctx (&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST");
+ init_key_ctx (&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST");
+
+ packet_id_init (&ctx->co.packet_id, 0, 0, "test", 0);
+
+ ctx->source = alloc_buf(TESTBUF_SIZE);
+ ctx->ciphertext = alloc_buf(TESTBUF_SIZE);
+ ctx->unwrapped = alloc_buf(TESTBUF_SIZE);
+
+ /* Write test plaintext */
+ buf_write(&ctx->source, plaintext_short, sizeof(plaintext_short));
+
+ /* Write dummy opcode and session id */
+ buf_write(&ctx->ciphertext, "012345678", 1 + 8);
+
+ *state = ctx;
+
+ return 0;
+}
+
+static int teardown(void **state) {
+ struct test_context *ctx = (struct test_context *) *state;
+
+ free_buf (&ctx->source);
+ free_buf (&ctx->ciphertext);
+ free_buf (&ctx->unwrapped);
+
+ free_key_ctx_bi (&ctx->co.key_ctx_bi);
+
+ free(ctx);
+
+ return 0;
+}
+
+/**
+ * Check that short messages are successfully wrapped-and-unwrapped.
+ */
+static void tls_crypt_loopback(void **state) {
+ struct test_context *ctx = (struct test_context *) *state;
+
+ assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co));
+ assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
+ assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
+ assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped));
+ assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped),
+ BLEN(&ctx->source));
+}
+
+/**
+ * Check that zero-byte messages are successfully wrapped-and-unwrapped.
+ */
+static void tls_crypt_loopback_zero_len(void **state) {
+ struct test_context *ctx = (struct test_context *) *state;
+
+ buf_clear(&ctx->source);
+
+ assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co));
+ assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
+ assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
+ assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped));
+ assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped),
+ BLEN(&ctx->source));
+}
+
+/**
+ * Check that max-length messages are successfully wrapped-and-unwrapped.
+ */
+static void tls_crypt_loopback_max_len(void **state) {
+ struct test_context *ctx = (struct test_context *) *state;
+
+ buf_clear(&ctx->source);
+ assert_non_null (buf_write_alloc (&ctx->source,
+ TESTBUF_SIZE - BLEN (&ctx->ciphertext) - tls_crypt_buf_overhead()));
+
+ assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co));
+ assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
+ assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
+ assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped));
+ assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped),
+ BLEN(&ctx->source));
+}
+
+/**
+ * Check that too-long messages are gracefully rejected.
+ */
+static void tls_crypt_fail_msg_too_long(void **state) {
+ struct test_context *ctx = (struct test_context *) *state;
+
+ buf_clear(&ctx->source);
+ assert_non_null (buf_write_alloc (&ctx->source,
+ TESTBUF_SIZE - BLEN (&ctx->ciphertext) - tls_crypt_buf_overhead() + 1));
+ assert_false (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co));
+}
+
+/**
+ * Check that packets that were wrapped (or unwrapped) with a different key
+ * are not accepted.
+ */
+static void tls_crypt_fail_invalid_key(void **state) {
+ struct test_context *ctx = (struct test_context *) *state;
+
+ /* Change decrypt key */
+ struct key key = { { 1 } };
+ free_key_ctx (&ctx->co.key_ctx_bi.decrypt);
+ init_key_ctx (&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST");
+
+ assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co));
+ assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
+ assert_false (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
+}
+
+/**
+ * Check that replayed packets are not accepted.
+ */
+static void tls_crypt_fail_replay(void **state) {
+ struct test_context *ctx = (struct test_context *) *state;
+
+ assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co));
+ assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
+ struct buffer tmp = ctx->ciphertext;
+ assert_true (tls_crypt_unwrap (&tmp, &ctx->unwrapped, &ctx->co));
+ buf_clear (&ctx->unwrapped);
+ assert_false (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
+}
+
+/**
+ * Check that packet replays are accepted when CO_IGNORE_PACKET_ID is set. This
+ * is used for the first control channel packet that arrives, because we don't
+ * know the packet ID yet.
+ */
+static void tls_crypt_ignore_replay(void **state) {
+ struct test_context *ctx = (struct test_context *) *state;
+
+ ctx->co.flags |= CO_IGNORE_PACKET_ID;
+
+ assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co));
+ assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
+ struct buffer tmp = ctx->ciphertext;
+ assert_true (tls_crypt_unwrap (&tmp, &ctx->unwrapped, &ctx->co));
+ buf_clear (&ctx->unwrapped);
+ assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(tls_crypt_loopback, setup, teardown),
+ cmocka_unit_test_setup_teardown(tls_crypt_loopback_zero_len,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(tls_crypt_loopback_max_len,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(tls_crypt_fail_msg_too_long,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(tls_crypt_fail_invalid_key,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(tls_crypt_fail_replay,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(tls_crypt_ignore_replay,
+ setup, teardown),
+ };
+
+#if defined(ENABLE_CRYPTO_OPENSSL)
+ OpenSSL_add_all_algorithms();
+#endif
+
+ int ret = cmocka_run_group_tests_name("tls-crypt tests", tests, NULL, NULL);
+
+#if defined(ENABLE_CRYPTO_OPENSSL)
+ EVP_cleanup();
+#endif
+
+ return ret;
+}
+
+#endif /* ENABLE_CRYPTO */