]>
Commit | Line | Data |
---|---|---|
b49ec259 JM |
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 | ||
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 | ||
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 | ||
70 | static void https_tls_log_cb(void *ctx, const char *msg) | |
71 | { | |
72 | wpa_printf(MSG_DEBUG, "TLS: %s", msg); | |
73 | } | |
74 | ||
75 | ||
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(¶ms, 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, ¶ms)) { | |
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 | ||
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 | } |