]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
tests: TLS fuzzing tool
authorJouni Malinen <j@w1.fi>
Sat, 9 Feb 2019 19:07:24 +0000 (21:07 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 11 Feb 2019 00:35:29 +0000 (02:35 +0200)
Add test-tls program that can be used for fuzzing the internal TLS
client and server implementations. This tool can write client or server
messages into a file as an initialization step and for the fuzzing step,
that file (with potential modifications) can be used to replace the
internally generated message contents.

The TEST_FUZZ=y build parameter is used to make a special build where a
hardcoded random number generator and hardcoded timestamp are used to
force deterministic behavior for the TLS operations.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/crypto/Makefile
src/lib.rules
src/tls/tlsv1_client_write.c
src/tls/tlsv1_server_write.c
src/utils/os_unix.c
tests/Makefile
tests/test-tls.c [new file with mode: 0644]

index ee93e41fbbb177416d2c9fbaf30e2ec859f56f13..ab108daac835e57309ed9de5944fb505e37d25e1 100644 (file)
@@ -62,7 +62,9 @@ LIB_OBJS += crypto_internal-modexp.o
 LIB_OBJS += crypto_internal-rsa.o
 LIB_OBJS += tls_internal.o
 LIB_OBJS += fips_prf_internal.o
+ifndef TEST_FUZZ
 LIB_OBJS += random.o
+endif
 
 
 libcrypto.a: $(LIB_OBJS)
index 0c79d992a6aa4196f386f0e5397167295585e1b0..4ec4711e36acfa23b55ca8a10909a7f4be28c171 100644 (file)
@@ -6,6 +6,11 @@ ifndef CFLAGS
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
+ifdef TEST_FUZZ
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+CFLAGS += -DTEST_FUZZ
+endif
+
 CFLAGS += -I.. -I../utils
 
 
index 04d895e61926aad62fe3f28700615405e11c5133..4a1147b69e7616a3e0431a662b65bf55c42df153 100644 (file)
@@ -72,6 +72,9 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        *out_len = 0;
 
        os_get_time(&now);
+#ifdef TEST_FUZZ
+       now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
        WPA_PUT_BE32(conn->client_random, now.sec);
        if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
                wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
index 892b74573930d9789199f3c2dc2c73fcdd533793..8d36cf1353910bba9e6fff71fd02a9ef8fb9f71c 100644 (file)
@@ -53,6 +53,9 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
        pos += TLS_RECORD_HEADER_LEN;
 
        os_get_time(&now);
+#ifdef TEST_FUZZ
+       now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
        WPA_PUT_BE32(conn->server_random, now.sec);
        if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
                wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
index 1894fcdb0cf25c9d101e3ffd02c68d6122d56b29..acc6975587422181b1588f9041a8f2f23d93ad24 100644 (file)
@@ -250,6 +250,13 @@ void os_daemonize_terminate(const char *pid_file)
 
 int os_get_random(unsigned char *buf, size_t len)
 {
+#ifdef TEST_FUZZ
+       size_t i;
+
+       for (i = 0; i < len; i++)
+               buf[i] = i & 0xff;
+       return 0;
+#else /* TEST_FUZZ */
        FILE *f;
        size_t rc;
 
@@ -266,6 +273,7 @@ int os_get_random(unsigned char *buf, size_t len)
        fclose(f);
 
        return rc != len ? -1 : 0;
+#endif /* TEST_FUZZ */
 }
 
 
index ba5d94bae32e8e2ac57085bdd31b519544b4a771..93a844b473fac4fa88cbe8efd94527a0491bd181 100644 (file)
@@ -17,6 +17,11 @@ ifndef CFLAGS
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
+ifdef TEST_FUZZ
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+CFLAGS += -DTEST_FUZZ
+endif
+
 CFLAGS += -I../src
 CFLAGS += -I../src/utils
 
@@ -77,6 +82,9 @@ test-sha1: test-sha1.o $(LIBS)
 test-sha256: test-sha256.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
 
+test-tls: test-tls.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
+
 test-x509: test-x509.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
 
@@ -99,6 +107,7 @@ clean:
        $(MAKE) -C ../src clean
        rm -f $(TESTS) *~ *.o *.d
        rm -f test-https
+       rm -f test-tls
        rm -f test_x509v3_nist.out.*
        rm -f test_x509v3_nist2.out.*
 
diff --git a/tests/test-tls.c b/tests/test-tls.c
new file mode 100644 (file)
index 0000000..9941fb5
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Testing tool for TLSv1 client/server routines
+ * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+
+
+static void usage(void) {
+       wpa_printf(MSG_INFO,
+                  "usage: test-tls <server/client> <read/write> <file>");
+       exit(-1);
+}
+
+
+static void write_msg(FILE *f, struct wpabuf *msg)
+{
+       u8 len[2];
+
+       wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
+                  (unsigned int) wpabuf_len(msg));
+       WPA_PUT_BE16(len, wpabuf_len(msg));
+       fwrite(len, 2, 1, f);
+       fwrite(wpabuf_head(msg), wpabuf_len(msg), 1, f);
+}
+
+
+static struct wpabuf * read_msg(FILE *f)
+{
+       u8 len[2];
+       u16 msg_len;
+       struct wpabuf *msg;
+
+       if (fread(len, 2, 1, f) != 1) {
+               wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
+               return NULL;
+       }
+       msg_len = WPA_GET_BE16(len);
+
+       msg = wpabuf_alloc(msg_len);
+       if (!msg)
+               return NULL;
+       if (msg_len > 0 &&
+           fread(wpabuf_put(msg, msg_len), msg_len, 1, f) != 1) {
+               wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
+                          msg_len);
+               wpabuf_free(msg);
+               return NULL;
+       }
+       wpa_hexdump_buf(MSG_DEBUG, "TEST: Read message from file", msg);
+
+       return msg;
+}
+
+
+int main(int argc, char *argv[])
+{
+       struct tls_config conf;
+       void *tls_server, *tls_client;
+       struct tls_connection_params params;
+       struct tls_connection *conn_server = NULL, *conn_client = NULL;
+       int ret = -1;
+       struct wpabuf *in = NULL, *out = NULL, *appl;
+       enum { SERVER, CLIENT } test_peer;
+       enum { READ, WRITE } test_oper;
+       const char *file;
+       FILE *f;
+
+       wpa_debug_level = 0;
+       wpa_debug_show_keys = 1;
+
+       if (argc < 4)
+               usage();
+
+       if (os_strcmp(argv[1], "server") == 0)
+               test_peer = SERVER;
+       else if (os_strcmp(argv[1], "client") == 0)
+               test_peer = CLIENT;
+       else
+               usage();
+
+       if (os_strcmp(argv[2], "read") == 0)
+               test_oper = READ;
+       else if (os_strcmp(argv[2], "write") == 0)
+               test_oper = WRITE;
+       else
+               usage();
+
+       file = argv[3];
+
+       f = fopen(file, test_oper == READ ? "r" : "w");
+       if (!f)
+               return -1;
+
+       os_memset(&conf, 0, sizeof(conf));
+       tls_server = tls_init(&conf);
+       tls_client = tls_init(&conf);
+       if (!tls_server || !tls_client)
+               goto fail;
+
+       os_memset(&params, 0, sizeof(params));
+       params.ca_cert = "hwsim/auth_serv/ca.pem";
+       params.client_cert = "hwsim/auth_serv/server.pem";
+       params.private_key = "hwsim/auth_serv/server.key";
+       params.dh_file = "hwsim/auth_serv/dh.conf";
+
+       if (tls_global_set_params(tls_server, &params)) {
+               wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
+               goto fail;
+       }
+
+       conn_server = tls_connection_init(tls_server);
+       conn_client = tls_connection_init(tls_client);
+       if (!conn_server || !conn_client)
+               goto fail;
+
+       in = NULL;
+       for (;;) {
+               appl = NULL;
+               if (test_peer == CLIENT && test_oper == READ)
+                       out = read_msg(f);
+               else
+                       out = tls_connection_handshake(tls_client, conn_client,
+                                                      in, &appl);
+               wpabuf_free(in);
+               in = NULL;
+               if (!out)
+                       goto fail;
+               if (test_peer == CLIENT && test_oper == WRITE &&
+                   wpabuf_len(out) > 0)
+                       write_msg(f, out);
+               if (!(test_peer == CLIENT && test_oper == READ) &&
+                   tls_connection_get_failed(tls_client, conn_client)) {
+                       wpa_printf(MSG_ERROR, "TLS handshake failed");
+                       goto fail;
+               }
+               if (((test_peer == CLIENT && test_oper == READ) ||
+                    tls_connection_established(tls_client, conn_client)) &&
+                   ((test_peer == SERVER && test_oper == READ) ||
+                    tls_connection_established(tls_server, conn_server)))
+                       break;
+
+               appl = NULL;
+               if (test_peer == SERVER && test_oper == READ)
+                       in = read_msg(f);
+               else
+                       in = tls_connection_server_handshake(tls_server,
+                                                            conn_server,
+                                                            out, &appl);
+               wpabuf_free(out);
+               out = NULL;
+               if (!in)
+                       goto fail;
+               if (test_peer == SERVER && test_oper == WRITE)
+                       write_msg(f, in);
+               if (!(test_peer == SERVER && test_oper == READ) &&
+                   tls_connection_get_failed(tls_server, conn_server)) {
+                       wpa_printf(MSG_ERROR, "TLS handshake failed");
+                       goto fail;
+               }
+               if (((test_peer == CLIENT && test_oper == READ) ||
+                    tls_connection_established(tls_client, conn_client)) &&
+                   ((test_peer == SERVER && test_oper == READ) ||
+                    tls_connection_established(tls_server, conn_server)))
+                       break;
+       }
+
+       wpabuf_free(in);
+       in = wpabuf_alloc(100);
+       if (!in)
+               goto fail;
+       wpabuf_put_str(in, "PING");
+       wpabuf_free(out);
+       if (test_peer == CLIENT && test_oper == READ)
+               out = read_msg(f);
+       else
+               out = tls_connection_encrypt(tls_client, conn_client, in);
+       wpabuf_free(in);
+       in = NULL;
+       if (!out)
+               goto fail;
+       if (test_peer == CLIENT && test_oper == WRITE)
+               write_msg(f, out);
+
+       if (!(test_peer == SERVER && test_oper == READ)) {
+               in = tls_connection_decrypt(tls_server, conn_server, out);
+               wpabuf_free(out);
+               out = NULL;
+               if (!in)
+                       goto fail;
+               wpa_hexdump_buf(MSG_DEBUG, "Server decrypted ApplData", in);
+       }
+
+       wpabuf_free(in);
+       in = wpabuf_alloc(100);
+       if (!in)
+               goto fail;
+       wpabuf_put_str(in, "PONG");
+       wpabuf_free(out);
+       if (test_peer == SERVER && test_oper == READ)
+               out = read_msg(f);
+       else
+               out = tls_connection_encrypt(tls_server, conn_server, in);
+       wpabuf_free(in);
+       in = NULL;
+       if (!out)
+               goto fail;
+       if (test_peer == SERVER && test_oper == WRITE)
+               write_msg(f, out);
+
+       if (!(test_peer == CLIENT && test_oper == READ)) {
+               in = tls_connection_decrypt(tls_client, conn_client, out);
+               wpabuf_free(out);
+               out = NULL;
+               if (!in)
+                       goto fail;
+               wpa_hexdump_buf(MSG_DEBUG, "Client decrypted ApplData", in);
+       }
+
+       ret = 0;
+fail:
+       if (tls_server) {
+               if (conn_server)
+                       tls_connection_deinit(tls_server, conn_server);
+               tls_deinit(tls_server);
+       }
+       if (tls_client) {
+               if (conn_client)
+                       tls_connection_deinit(tls_server, conn_client);
+               tls_deinit(tls_client);
+       }
+       wpabuf_free(in);
+       wpabuf_free(out);
+       fclose(f);
+
+       return ret;
+}