1  /*
2   * Testing tool for TLSv1 server routines using HTTPS
3   * Copyright (c) 2011-2019, Jouni Malinen <j@w1.fi>
4   *
5   * This software may be distributed under the terms of the BSD license.
6   * See README for more details.
7   */
8  
9  #include "includes.h"
10  
11  #include "common.h"
12  #include "crypto/tls.h"
13  
14  
https_tls_event_cb(void * ctx,enum tls_event ev,union tls_event_data * data)15  static void https_tls_event_cb(void *ctx, enum tls_event ev,
16  			       union tls_event_data *data)
17  {
18  	wpa_printf(MSG_DEBUG, "HTTPS: TLS event %d", ev);
19  }
20  
21  
https_recv(int s,int timeout_ms)22  static struct wpabuf * https_recv(int s, int timeout_ms)
23  {
24  	struct wpabuf *in;
25  	int len, ret;
26  	fd_set rfds;
27  	struct timeval tv;
28  
29  	in = wpabuf_alloc(20000);
30  	if (in == NULL)
31  		return NULL;
32  
33  	FD_ZERO(&rfds);
34  	FD_SET(s, &rfds);
35  	tv.tv_sec = timeout_ms / 1000;
36  	tv.tv_usec = timeout_ms % 1000;
37  
38  	wpa_printf(MSG_DEBUG, "Waiting for more data");
39  	ret = select(s + 1, &rfds, NULL, NULL, &tv);
40  	if (ret < 0) {
41  		wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
42  		wpabuf_free(in);
43  		return NULL;
44  	}
45  	if (ret == 0) {
46  		/* timeout */
47  		wpa_printf(MSG_INFO, "Timeout on waiting for data");
48  		wpabuf_free(in);
49  		return NULL;
50  	}
51  
52  	len = recv(s, wpabuf_put(in, 0), wpabuf_tailroom(in), 0);
53  	if (len < 0) {
54  		wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
55  		wpabuf_free(in);
56  		return NULL;
57  	}
58  	if (len == 0) {
59  		wpa_printf(MSG_DEBUG, "No more data available");
60  		wpabuf_free(in);
61  		return NULL;
62  	}
63  	wpa_printf(MSG_DEBUG, "Received %d bytes", len);
64  	wpabuf_put(in, len);
65  
66  	return in;
67  }
68  
69  
https_tls_log_cb(void * ctx,const char * msg)70  static void https_tls_log_cb(void *ctx, const char *msg)
71  {
72  	wpa_printf(MSG_DEBUG, "TLS: %s", msg);
73  }
74  
75  
https_server(int s)76  static int https_server(int s)
77  {
78  	struct tls_config conf;
79  	void *tls;
80  	struct tls_connection_params params;
81  	struct tls_connection *conn;
82  	struct wpabuf *in, *out, *appl;
83  	int res = -1;
84  
85  	os_memset(&conf, 0, sizeof(conf));
86  	conf.event_cb = https_tls_event_cb;
87  	tls = tls_init(&conf);
88  	if (!tls)
89  		return -1;
90  
91  	os_memset(&params, 0, sizeof(params));
92  	params.ca_cert = "hwsim/auth_serv/ca.pem";
93  	params.client_cert = "hwsim/auth_serv/server.pem";
94  	params.private_key = "hwsim/auth_serv/server.key";
95  	params.dh_file = "hwsim/auth_serv/dh.conf";
96  
97  	if (tls_global_set_params(tls, &params)) {
98  		wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
99  		tls_deinit(tls);
100  		return -1;
101  	}
102  
103  	conn = tls_connection_init(tls);
104  	if (!conn) {
105  		tls_deinit(tls);
106  		return -1;
107  	}
108  
109  	tls_connection_set_log_cb(conn, https_tls_log_cb, NULL);
110  
111  	for (;;) {
112  		in = https_recv(s, 5000);
113  		if (!in)
114  			goto done;
115  
116  		appl = NULL;
117  		out = tls_connection_server_handshake(tls, conn, in, &appl);
118  		wpabuf_free(in);
119  		in = NULL;
120  		if (!out) {
121  			if (!tls_connection_get_failed(tls, conn) &&
122  			    !tls_connection_established(tls, conn))
123  				continue;
124  			goto done;
125  		}
126  		wpa_printf(MSG_DEBUG, "Sending %d bytes",
127  			   (int) wpabuf_len(out));
128  		if (send(s, wpabuf_head(out), wpabuf_len(out), 0) < 0) {
129  			wpa_printf(MSG_ERROR, "send: %s", strerror(errno));
130  			goto done;
131  		}
132  		wpabuf_free(out);
133  		out = NULL;
134  		if (tls_connection_get_failed(tls, conn)) {
135  			wpa_printf(MSG_ERROR, "TLS handshake failed");
136  			goto done;
137  		}
138  		if (tls_connection_established(tls, conn))
139  			break;
140  	}
141  	wpabuf_free(out);
142  	out = NULL;
143  
144  	wpa_printf(MSG_INFO, "TLS connection established");
145  	if (appl)
146  		wpa_hexdump_buf(MSG_DEBUG, "Received application data", appl);
147  
148  	wpa_printf(MSG_INFO, "Reading HTTP request");
149  	for (;;) {
150  		int need_more_data;
151  
152  		in = https_recv(s, 5000);
153  		if (!in)
154  			goto done;
155  		out = tls_connection_decrypt2(tls, conn, in, &need_more_data);
156  		wpabuf_free(in);
157  		in = NULL;
158  		if (need_more_data) {
159  			wpa_printf(MSG_DEBUG, "HTTP: Need more data");
160  			continue;
161  		}
162  		if (!out)
163  			goto done;
164  		wpa_hexdump_ascii(MSG_INFO, "Request",
165  				  wpabuf_head(out), wpabuf_len(out));
166  		wpabuf_free(out);
167  		out = NULL;
168  		break;
169  	}
170  
171  	in = wpabuf_alloc(1000);
172  	if (!in)
173  		goto done;
174  	wpabuf_put_str(in, "HTTP/1.1 200 OK\r\n"
175  		       "Server: test-https_server\r\n"
176  		       "\r\n"
177  		       "<HTML><BODY>HELLO</BODY></HTML>\n");
178  	wpa_hexdump_ascii(MSG_DEBUG, "Response",
179  			  wpabuf_head(in), wpabuf_len(in));
180  	out = tls_connection_encrypt(tls, conn, in);
181  	wpabuf_free(in);
182  	in = NULL;
183  	wpa_hexdump_buf(MSG_DEBUG, "Encrypted response", out);
184  	if (!out)
185  		goto done;
186  
187  	wpa_printf(MSG_INFO, "Sending HTTP response: %d bytes",
188  		   (int) wpabuf_len(out));
189  	if (send(s, wpabuf_head(out), wpabuf_len(out), 0) < 0) {
190  		wpa_printf(MSG_ERROR, "send: %s", strerror(errno));
191  		goto done;
192  	}
193  	wpabuf_free(out);
194  	out = NULL;
195  
196  	res = 0;
197  done:
198  	wpabuf_free(out);
199  	wpabuf_free(in);
200  	wpabuf_free(appl);
201  	tls_connection_deinit(tls, conn);
202  	tls_deinit(tls);
203  	close(s);
204  
205  	return res;
206  }
207  
208  
main(int argc,char * argv[])209  int main(int argc, char *argv[])
210  {
211  	struct sockaddr_in sin;
212  	int port, s, conn;
213  	int on = 1;
214  
215  	wpa_debug_level = 0;
216  	wpa_debug_show_keys = 1;
217  
218  	if (argc < 2) {
219  		wpa_printf(MSG_INFO, "usage: test-https_server port");
220  		return -1;
221  	}
222  
223  	port = atoi(argv[1]);
224  
225  	s = socket(AF_INET, SOCK_STREAM, 0);
226  	if (s < 0) {
227  		perror("socket");
228  		return -1;
229  	}
230  
231  	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
232  		wpa_printf(MSG_DEBUG,
233  			   "HTTP: setsockopt(SO_REUSEADDR) failed: %s",
234  			   strerror(errno));
235  		/* try to continue anyway */
236  	}
237  
238  	os_memset(&sin, 0, sizeof(sin));
239  	sin.sin_family = AF_INET;
240  	sin.sin_port = htons(port);
241  	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
242  		perror("bind");
243  		close(s);
244  		return -1;
245  	}
246  
247  	if (listen(s, 10) < 0) {
248  		perror("listen");
249  		close(s);
250  		return -1;
251  	}
252  
253  	for (;;) {
254  		struct sockaddr_in addr;
255  		socklen_t addr_len = sizeof(addr);
256  
257  		conn = accept(s, (struct sockaddr *) &addr, &addr_len);
258  		if (conn < 0) {
259  			perror("accept");
260  			break;
261  		}
262  
263  		wpa_printf(MSG_DEBUG, "-------------------------------------");
264  		wpa_printf(MSG_DEBUG, "Connection from %s:%d",
265  			   inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
266  
267  		https_server(conn);
268  		wpa_printf(MSG_DEBUG, "Done with the connection");
269  		wpa_printf(MSG_DEBUG, "-------------------------------------");
270  	}
271  
272  	close(s);
273  
274  	return 0;
275  }
276