From d10b13982def0625e6dc505a41a64b6d3f203d1c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 13 Nov 2011 10:49:27 +0200 Subject: [PATCH] Add test-https for testing internal TLS client functionality This tool can be used to test the internal TLS client implementation against HTTPS servers. Signed-hostap: Jouni Malinen --- tests/.gitignore | 1 + tests/Makefile | 3 + tests/test-https.c | 230 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 tests/test-https.c diff --git a/tests/.gitignore b/tests/.gitignore index 5b992a312..27ee557d8 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,6 +1,7 @@ test-aes test-asn1 test-base64 +test-https test-list test-md4 test-md5 diff --git a/tests/Makefile b/tests/Makefile index 210a1b4d7..401275ac0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -45,6 +45,9 @@ test-asn1: test-asn1.o $(LIBS) test-base64: test-base64.o $(LIBS) $(LDO) $(LDFLAGS) -o $@ $^ +test-https: test-https.o $(LIBS) + $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS) + test-list: test-list.o $(LIBS) $(LDO) $(LDFLAGS) -o $@ $^ diff --git a/tests/test-https.c b/tests/test-https.c new file mode 100644 index 000000000..27e692ea3 --- /dev/null +++ b/tests/test-https.c @@ -0,0 +1,230 @@ +/* + * Testing tool for TLSv1 client routines using HTTPS + * Copyright (c) 2011, Jouni Malinen + * + * 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. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" +#include + +#include "common.h" +#include "crypto/tls.h" + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; + + +static void https_tls_event_cb(void *ctx, enum tls_event ev, + union tls_event_data *data) +{ + wpa_printf(MSG_DEBUG, "HTTPS: TLS event %d", ev); +} + + +static struct wpabuf * https_recv(int s) +{ + struct wpabuf *in; + int len, ret; + fd_set rfds; + struct timeval tv; + + in = wpabuf_alloc(20000); + if (in == NULL) + return NULL; + + FD_ZERO(&rfds); + FD_SET(s, &rfds); + tv.tv_sec = 5; + tv.tv_usec = 0; + + wpa_printf(MSG_DEBUG, "Waiting for more data"); + ret = select(s + 1, &rfds, NULL, NULL, &tv); + if (ret < 0) { + wpa_printf(MSG_ERROR, "select: %s", strerror(errno)); + wpabuf_free(in); + return NULL; + } + if (ret == 0) { + /* timeout */ + wpa_printf(MSG_INFO, "Timeout on waiting for data"); + wpabuf_free(in); + return NULL; + } + + len = recv(s, wpabuf_put(in, 0), wpabuf_tailroom(in), 0); + if (len < 0) { + wpa_printf(MSG_ERROR, "recv: %s", strerror(errno)); + wpabuf_free(in); + return NULL; + } + if (len == 0) { + wpa_printf(MSG_DEBUG, "No more data available"); + wpabuf_free(in); + return NULL; + } + wpa_printf(MSG_DEBUG, "Received %d bytes", len); + wpabuf_put(in, len); + + return in; +} + + +static int https_client(int s, const char *path) +{ + struct tls_config conf; + void *tls; + struct tls_connection *conn; + struct wpabuf *in, *out, *appl; + int res = -1; + int need_more_data; + + os_memset(&conf, 0, sizeof(conf)); + conf.event_cb = https_tls_event_cb; + tls = tls_init(&conf); + if (tls == NULL) + return -1; + + conn = tls_connection_init(tls); + if (conn == NULL) { + tls_deinit(tls); + return -1; + } + + in = NULL; + + for (;;) { + appl = NULL; + out = tls_connection_handshake2(tls, conn, in, &appl, + &need_more_data); + wpabuf_free(in); + in = NULL; + if (out == NULL) { + if (need_more_data) + goto read_more; + goto done; + } + if (tls_connection_get_failed(tls, conn)) { + wpa_printf(MSG_ERROR, "TLS handshake failed"); + goto done; + } + if (tls_connection_established(tls, conn)) + break; + wpa_printf(MSG_DEBUG, "Sending %d bytes", + (int) wpabuf_len(out)); + if (send(s, wpabuf_head(out), wpabuf_len(out), 0) < 0) { + wpa_printf(MSG_ERROR, "send: %s", strerror(errno)); + goto done; + } + wpabuf_free(out); + out = NULL; + + read_more: + in = https_recv(s); + if (in == NULL) + goto done; + } + + wpa_printf(MSG_INFO, "TLS connection established"); + if (appl) + wpa_hexdump_buf(MSG_DEBUG, "Received application data", appl); + + in = wpabuf_alloc(100 + os_strlen(path)); + if (in == NULL) + goto done; + wpabuf_put_str(in, "GET "); + wpabuf_put_str(in, path); + wpabuf_put_str(in, " HTTP/1.0\r\n\r\n"); + out = tls_connection_encrypt(tls, conn, in); + wpabuf_free(in); + in = NULL; + if (out == NULL) + goto done; + + wpa_printf(MSG_INFO, "Sending HTTP request: %d bytes", + (int) wpabuf_len(out)); + if (send(s, wpabuf_head(out), wpabuf_len(out), 0) < 0) { + wpa_printf(MSG_ERROR, "send: %s", strerror(errno)); + goto done; + } + + wpa_printf(MSG_INFO, "Reading HTTP response"); + for (;;) { + int need_more_data; + in = https_recv(s); + if (in == NULL) + goto done; + out = tls_connection_decrypt2(tls, conn, in, &need_more_data); + if (need_more_data) + wpa_printf(MSG_DEBUG, "HTTP: Need more data"); + wpabuf_free(in); + in = NULL; + if (out == NULL) + goto done; + wpa_hexdump_ascii(MSG_INFO, "Response", wpabuf_head(out), + wpabuf_len(out)); + wpabuf_free(out); + out = NULL; + } + + res = 0; +done: + wpabuf_free(out); + wpabuf_free(in); + wpabuf_free(appl); + tls_connection_deinit(tls, conn); + tls_deinit(tls); + + return res; +} + + +int main(int argc, char *argv[]) +{ + struct addrinfo hints, *result, *rp; + int res, s; + + wpa_debug_level = 0; + wpa_debug_show_keys = 1; + + if (argc < 4) { + wpa_printf(MSG_INFO, "usage: test-https server port path"); + return -1; + } + + os_memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + res = getaddrinfo(argv[1], argv[2], &hints, &result); + if (res) { + wpa_printf(MSG_ERROR, "getaddrinfo: %s", gai_strerror(res)); + return -1; + } + + for (rp = result; rp; rp = rp->ai_next) { + s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (s < 0) + continue; + if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) + break; + close(s); + } + freeaddrinfo(result); + + if (rp == NULL) { + wpa_printf(MSG_ERROR, "Could not connect"); + return -1; + } + + https_client(s, argv[3]); + close(s); + + return 0; +}