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