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