/* * Testing tool for TLSv1 client routines using HTTPS * Copyright (c) 2011, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include #include "common.h" #include "crypto/tls.h" 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 = 0; 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; #ifdef CONFIG_TLS_INTERNAL_SERVER out = tls_connection_handshake2(tls, conn, in, &appl, &need_more_data); #else out = tls_connection_handshake(tls, conn, in, &appl); #endif 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; } wpabuf_free(out); out = NULL; 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; } wpabuf_free(out); out = NULL; wpa_printf(MSG_INFO, "Reading HTTP response"); for (;;) { int need_more_data = 0; in = https_recv(s); if (in == NULL) goto done; #ifdef CONFIG_TLS_INTERNAL_SERVER out = tls_connection_decrypt2(tls, conn, in, &need_more_data); #else out = tls_connection_decrypt(tls, conn, in); #endif 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; }