 1ac9c020b5
			
		
	
	
		1ac9c020b5
		
	
	
	
	
		
			
			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>
		
			
				
	
	
		
			243 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			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(¶ms, 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, ¶ms)) {
 | |
| 		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;
 | |
| }
 |