hostapd/tests/test-tls.c
Jouni Malinen 1ac9c020b5 tests: TLS fuzzing tool
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>
2019-02-11 02:35:29 +02:00

243 lines
5.7 KiB
C

/*
* 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;
}