14a3138825d3985f5645027c9309d758c60dfb45
[BearSSL] / tools / sslio.c
1 /*
2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <errno.h>
30
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <poll.h>
39
40 #include "brssl.h"
41 #include "bearssl.h"
42
43 static void
44 dump_blob(const char *name, const void *data, size_t len)
45 {
46 const unsigned char *buf;
47 size_t u;
48
49 buf = data;
50 fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len);
51 for (u = 0; u < len; u ++) {
52 if ((u & 15) == 0) {
53 fprintf(stderr, "\n%08lX ", (unsigned long)u);
54 } else if ((u & 7) == 0) {
55 fprintf(stderr, " ");
56 }
57 fprintf(stderr, " %02x", buf[u]);
58 }
59 fprintf(stderr, "\n");
60 }
61
62 /*
63 * Inspect the provided data in case it is a "command" to trigger a
64 * special behaviour. If the command is recognised, then it is executed
65 * and this function returns 1. Otherwise, this function returns 0.
66 */
67 static int
68 run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len)
69 {
70 /*
71 * A single static slot for saving session parameters.
72 */
73 static br_ssl_session_parameters slot;
74 static int slot_used = 0;
75
76 size_t u;
77
78 if (len < 2 || len > 3) {
79 return 0;
80 }
81 if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) {
82 return 0;
83 }
84 if (len == 2 && buf[1] != '\n') {
85 return 0;
86 }
87 switch (buf[0]) {
88 case 'Q':
89 fprintf(stderr, "closing...\n");
90 br_ssl_engine_close(cc);
91 return 1;
92 case 'R':
93 if (br_ssl_engine_renegotiate(cc)) {
94 fprintf(stderr, "renegotiating...\n");
95 } else {
96 fprintf(stderr, "not renegotiating.\n");
97 }
98 return 1;
99 case 'F':
100 /*
101 * Session forget is nominally client-only. But the
102 * session parameters are in the engine structure, which
103 * is the first field of the client context, so the cast
104 * still works properly. On the server, this forgetting
105 * has no effect.
106 */
107 fprintf(stderr, "forgetting session...\n");
108 br_ssl_client_forget_session((br_ssl_client_context *)cc);
109 return 1;
110 case 'S':
111 fprintf(stderr, "saving session parameters...\n");
112 br_ssl_engine_get_session_parameters(cc, &slot);
113 fprintf(stderr, " id = ");
114 for (u = 0; u < slot.session_id_len; u ++) {
115 fprintf(stderr, "%02X", slot.session_id[u]);
116 }
117 fprintf(stderr, "\n");
118 slot_used = 1;
119 return 1;
120 case 'P':
121 if (slot_used) {
122 fprintf(stderr, "restoring session parameters...\n");
123 fprintf(stderr, " id = ");
124 for (u = 0; u < slot.session_id_len; u ++) {
125 fprintf(stderr, "%02X", slot.session_id[u]);
126 }
127 fprintf(stderr, "\n");
128 br_ssl_engine_set_session_parameters(cc, &slot);
129 return 1;
130 }
131 return 0;
132 default:
133 return 0;
134 }
135 }
136
137 /* see brssl.h */
138 int
139 run_ssl_engine(br_ssl_engine_context *cc, int fd, unsigned flags)
140 {
141 int hsdetails;
142 int retcode;
143 int verbose;
144 int trace;
145
146 hsdetails = 0;
147 retcode = 0;
148 verbose = (flags & RUN_ENGINE_VERBOSE) != 0;
149 trace = (flags & RUN_ENGINE_TRACE) != 0;
150
151 /*
152 * Make sure that stdin and stdout are non-blocking.
153 */
154 fcntl(0, F_SETFL, O_NONBLOCK);
155 fcntl(1, F_SETFL, O_NONBLOCK);
156
157 /*
158 * Perform the loop.
159 */
160 for (;;) {
161 unsigned st;
162 int sendrec, recvrec, sendapp, recvapp;
163 struct pollfd pfd[3];
164 int n;
165 size_t u, k_fd, k_in, k_out;
166
167 /*
168 * Get current engine state.
169 */
170 st = br_ssl_engine_current_state(cc);
171 if (st == BR_SSL_CLOSED) {
172 int err;
173
174 err = br_ssl_engine_last_error(cc);
175 if (err == BR_ERR_OK) {
176 if (verbose) {
177 fprintf(stderr,
178 "SSL closed normally\n");
179 }
180 retcode = 0;
181 goto engine_exit;
182 } else {
183 fprintf(stderr, "ERROR: SSL error %d", err);
184 retcode = err;
185 if (err >= BR_ERR_SEND_FATAL_ALERT) {
186 err -= BR_ERR_SEND_FATAL_ALERT;
187 fprintf(stderr,
188 " (sent alert %d)\n", err);
189 } else if (err >= BR_ERR_RECV_FATAL_ALERT) {
190 err -= BR_ERR_RECV_FATAL_ALERT;
191 fprintf(stderr,
192 " (received alert %d)\n", err);
193 } else {
194 const char *ename;
195
196 ename = find_error_name(err, NULL);
197 if (ename == NULL) {
198 ename = "unknown";
199 }
200 fprintf(stderr, " (%s)\n", ename);
201 }
202 goto engine_exit;
203 }
204 }
205
206 /*
207 * Compute descriptors that must be polled, depending
208 * on engine state.
209 */
210 sendrec = ((st & BR_SSL_SENDREC) != 0);
211 recvrec = ((st & BR_SSL_RECVREC) != 0);
212 sendapp = ((st & BR_SSL_SENDAPP) != 0);
213 recvapp = ((st & BR_SSL_RECVAPP) != 0);
214 if (verbose && sendapp && !hsdetails) {
215 char csn[80];
216 const char *pname;
217
218 fprintf(stderr, "Handshake completed\n");
219 fprintf(stderr, " version: ");
220 switch (cc->session.version) {
221 case BR_SSL30:
222 fprintf(stderr, "SSL 3.0");
223 break;
224 case BR_TLS10:
225 fprintf(stderr, "TLS 1.0");
226 break;
227 case BR_TLS11:
228 fprintf(stderr, "TLS 1.1");
229 break;
230 case BR_TLS12:
231 fprintf(stderr, "TLS 1.2");
232 break;
233 default:
234 fprintf(stderr, "unknown (0x%04X)",
235 (unsigned)cc->session.version);
236 break;
237 }
238 fprintf(stderr, "\n");
239 get_suite_name_ext(
240 cc->session.cipher_suite, csn, sizeof csn);
241 fprintf(stderr, " cipher suite: %s\n", csn);
242 if (uses_ecdhe(cc->session.cipher_suite)) {
243 get_curve_name_ext(
244 br_ssl_engine_get_ecdhe_curve(cc),
245 csn, sizeof csn);
246 fprintf(stderr,
247 " ECDHE curve: %s\n", csn);
248 }
249 fprintf(stderr, " secure renegotiation: %s\n",
250 cc->reneg == 1 ? "no" : "yes");
251 pname = br_ssl_engine_get_selected_protocol(cc);
252 if (pname != NULL) {
253 fprintf(stderr,
254 " protocol name (ALPN): %s\n",
255 pname);
256 }
257 hsdetails = 1;
258 }
259
260 k_fd = 0;
261 k_in = 0;
262 k_out = 0;
263
264 u = 0;
265 if (sendrec || recvrec) {
266 pfd[u].fd = fd;
267 pfd[u].revents = 0;
268 pfd[u].events = 0;
269 if (sendrec) {
270 pfd[u].events |= POLLOUT;
271 }
272 if (recvrec) {
273 pfd[u].events |= POLLIN;
274 }
275 k_fd = u;
276 u ++;
277 }
278 if (sendapp) {
279 pfd[u].fd = 0;
280 pfd[u].revents = 0;
281 pfd[u].events = POLLIN;
282 k_in = u;
283 u ++;
284 }
285 if (recvapp) {
286 pfd[u].fd = 1;
287 pfd[u].revents = 0;
288 pfd[u].events = POLLOUT;
289 k_out = u;
290 u ++;
291 }
292 n = poll(pfd, u, -1);
293 if (n < 0) {
294 if (errno == EINTR) {
295 continue;
296 }
297 perror("ERROR: poll()");
298 retcode = -2;
299 goto engine_exit;
300 }
301 if (n == 0) {
302 continue;
303 }
304
305 /*
306 * We transform closures/errors into read+write accesses
307 * so as to force the read() or write() call that will
308 * detect the situation.
309 */
310 while (u -- > 0) {
311 if (pfd[u].revents & (POLLERR | POLLHUP)) {
312 pfd[u].revents |= POLLIN | POLLOUT;
313 }
314 }
315
316 /*
317 * We give preference to outgoing data, on stdout and on
318 * the socket.
319 */
320 if (recvapp) {
321 if (pfd[k_out].revents & POLLOUT) {
322 unsigned char *buf;
323 size_t len;
324 ssize_t wlen;
325
326 buf = br_ssl_engine_recvapp_buf(cc, &len);
327 wlen = write(1, buf, len);
328 if (wlen <= 0) {
329 if (verbose) {
330 fprintf(stderr,
331 "stdout closed...\n");
332 }
333 retcode = -2;
334 goto engine_exit;
335 }
336 br_ssl_engine_recvapp_ack(cc, wlen);
337 continue;
338 }
339 }
340 if (sendrec) {
341 if (pfd[k_fd].revents & POLLOUT) {
342 unsigned char *buf;
343 size_t len;
344 ssize_t wlen;
345
346 buf = br_ssl_engine_sendrec_buf(cc, &len);
347 wlen = write(fd, buf, len);
348 if (wlen <= 0) {
349 if (verbose) {
350 fprintf(stderr,
351 "socket closed...\n");
352 }
353 retcode = -1;
354 goto engine_exit;
355 }
356 if (trace) {
357 dump_blob("Outgoing bytes", buf, wlen);
358 }
359 br_ssl_engine_sendrec_ack(cc, wlen);
360 continue;
361 }
362 }
363 if (recvrec) {
364 if (pfd[k_fd].revents & POLLIN) {
365 unsigned char *buf;
366 size_t len;
367 ssize_t rlen;
368
369 buf = br_ssl_engine_recvrec_buf(cc, &len);
370 rlen = read(fd, buf, len);
371 if (rlen <= 0) {
372 if (verbose) {
373 fprintf(stderr,
374 "socket closed...\n");
375 }
376 retcode = -1;
377 goto engine_exit;
378 }
379 if (trace) {
380 dump_blob("Incoming bytes", buf, rlen);
381 }
382 br_ssl_engine_recvrec_ack(cc, rlen);
383 continue;
384 }
385 }
386 if (sendapp) {
387 if (pfd[k_in].revents & POLLIN) {
388 unsigned char *buf;
389 size_t len;
390 ssize_t rlen;
391
392 buf = br_ssl_engine_sendapp_buf(cc, &len);
393 rlen = read(0, buf, len);
394 if (rlen <= 0) {
395 if (verbose) {
396 fprintf(stderr,
397 "stdin closed...\n");
398 }
399 br_ssl_engine_close(cc);
400 } else if (!run_command(cc, buf, rlen)) {
401 br_ssl_engine_sendapp_ack(cc, rlen);
402 }
403 br_ssl_engine_flush(cc, 0);
404 continue;
405 }
406 }
407
408 /* We should never reach that point. */
409 fprintf(stderr, "ERROR: poll() misbehaves\n");
410 retcode = -2;
411 goto engine_exit;
412 }
413
414 /*
415 * Release allocated structures.
416 */
417 engine_exit:
418 return retcode;
419 }