Added seeder API. Also overhauled compile-time detection of features.
[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 #ifdef _WIN32
32 #include <winsock2.h>
33 #include <ws2tcpip.h>
34 #else
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netdb.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <poll.h>
43
44 #define SOCKET int
45 #define INVALID_SOCKET (-1)
46 #endif
47
48 #include "brssl.h"
49
50 static void
51 dump_blob(const char *name, const void *data, size_t len)
52 {
53 const unsigned char *buf;
54 size_t u;
55
56 buf = data;
57 fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len);
58 for (u = 0; u < len; u ++) {
59 if ((u & 15) == 0) {
60 fprintf(stderr, "\n%08lX ", (unsigned long)u);
61 } else if ((u & 7) == 0) {
62 fprintf(stderr, " ");
63 }
64 fprintf(stderr, " %02x", buf[u]);
65 }
66 fprintf(stderr, "\n");
67 }
68
69 /*
70 * Inspect the provided data in case it is a "command" to trigger a
71 * special behaviour. If the command is recognised, then it is executed
72 * and this function returns 1. Otherwise, this function returns 0.
73 */
74 static int
75 run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len)
76 {
77 /*
78 * A single static slot for saving session parameters.
79 */
80 static br_ssl_session_parameters slot;
81 static int slot_used = 0;
82
83 size_t u;
84
85 if (len < 2 || len > 3) {
86 return 0;
87 }
88 if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) {
89 return 0;
90 }
91 if (len == 2 && buf[1] != '\n') {
92 return 0;
93 }
94 switch (buf[0]) {
95 case 'Q':
96 fprintf(stderr, "closing...\n");
97 br_ssl_engine_close(cc);
98 return 1;
99 case 'R':
100 if (br_ssl_engine_renegotiate(cc)) {
101 fprintf(stderr, "renegotiating...\n");
102 } else {
103 fprintf(stderr, "not renegotiating.\n");
104 }
105 return 1;
106 case 'F':
107 /*
108 * Session forget is nominally client-only. But the
109 * session parameters are in the engine structure, which
110 * is the first field of the client context, so the cast
111 * still works properly. On the server, this forgetting
112 * has no effect.
113 */
114 fprintf(stderr, "forgetting session...\n");
115 br_ssl_client_forget_session((br_ssl_client_context *)cc);
116 return 1;
117 case 'S':
118 fprintf(stderr, "saving session parameters...\n");
119 br_ssl_engine_get_session_parameters(cc, &slot);
120 fprintf(stderr, " id = ");
121 for (u = 0; u < slot.session_id_len; u ++) {
122 fprintf(stderr, "%02X", slot.session_id[u]);
123 }
124 fprintf(stderr, "\n");
125 slot_used = 1;
126 return 1;
127 case 'P':
128 if (slot_used) {
129 fprintf(stderr, "restoring session parameters...\n");
130 fprintf(stderr, " id = ");
131 for (u = 0; u < slot.session_id_len; u ++) {
132 fprintf(stderr, "%02X", slot.session_id[u]);
133 }
134 fprintf(stderr, "\n");
135 br_ssl_engine_set_session_parameters(cc, &slot);
136 return 1;
137 }
138 return 0;
139 default:
140 return 0;
141 }
142 }
143
144 #ifdef _WIN32
145
146 typedef struct {
147 unsigned char buf[1024];
148 size_t ptr, len;
149 } in_buffer;
150
151 static int
152 in_return_bytes(in_buffer *bb, unsigned char *buf, size_t len)
153 {
154 if (bb->ptr < bb->len) {
155 size_t clen;
156
157 if (buf == NULL) {
158 return 1;
159 }
160 clen = bb->len - bb->ptr;
161 if (clen > len) {
162 clen = len;
163 }
164 memcpy(buf, bb->buf + bb->ptr, clen);
165 bb->ptr += clen;
166 if (bb->ptr == bb->len) {
167 bb->ptr = bb->len = 0;
168 }
169 return (int)clen;
170 }
171 return 0;
172 }
173
174 /*
175 * A buffered version of in_read(), using a buffer to return only
176 * full lines when feasible.
177 */
178 static int
179 in_read_buffered(HANDLE h_in, in_buffer *bb, unsigned char *buf, size_t len)
180 {
181 int n;
182
183 if (len == 0) {
184 return 0;
185 }
186 n = in_return_bytes(bb, buf, len);
187 if (n != 0) {
188 return n;
189 }
190 for (;;) {
191 INPUT_RECORD inrec;
192 DWORD v;
193
194 if (!PeekConsoleInput(h_in, &inrec, 1, &v)) {
195 fprintf(stderr, "ERROR: PeekConsoleInput()"
196 " failed with 0x%08lX\n",
197 (unsigned long)GetLastError());
198 return -1;
199 }
200 if (v == 0) {
201 return 0;
202 }
203 if (!ReadConsoleInput(h_in, &inrec, 1, &v)) {
204 fprintf(stderr, "ERROR: ReadConsoleInput()"
205 " failed with 0x%08lX\n",
206 (unsigned long)GetLastError());
207 return -1;
208 }
209 if (v == 0) {
210 return 0;
211 }
212 if (inrec.EventType == KEY_EVENT
213 && inrec.Event.KeyEvent.bKeyDown)
214 {
215 int c;
216
217 c = inrec.Event.KeyEvent.uChar.AsciiChar;
218 if (c == '\n' || c == '\r' || c == '\t'
219 || (c >= 32 && c != 127))
220 {
221 if (c == '\r') {
222 c = '\n';
223 }
224 bb->buf[bb->ptr ++] = (unsigned char)c;
225 printf("%c", c);
226 fflush(stdout);
227 bb->len = bb->ptr;
228 if (bb->len == sizeof bb->buf || c == '\n') {
229 bb->ptr = 0;
230 return in_return_bytes(bb, buf, len);
231 }
232 }
233 }
234 }
235 }
236
237 static int
238 in_avail_buffered(HANDLE h_in, in_buffer *bb)
239 {
240 return in_read_buffered(h_in, bb, NULL, 1);
241 }
242
243 #endif
244
245 /* see brssl.h */
246 int
247 run_ssl_engine(br_ssl_engine_context *cc, unsigned long fd, unsigned flags)
248 {
249 int hsdetails;
250 int retcode;
251 int verbose;
252 int trace;
253 #ifdef _WIN32
254 WSAEVENT fd_event;
255 int can_send, can_recv;
256 HANDLE h_in, h_out;
257 in_buffer bb;
258 #endif
259
260 hsdetails = 0;
261 retcode = 0;
262 verbose = (flags & RUN_ENGINE_VERBOSE) != 0;
263 trace = (flags & RUN_ENGINE_TRACE) != 0;
264
265 /*
266 * Print algorithm details.
267 */
268 if (verbose) {
269 const char *rngname;
270
271 fprintf(stderr, "Algorithms:\n");
272 br_prng_seeder_system(&rngname);
273 fprintf(stderr, " RNG: %s\n", rngname);
274 if (cc->iaes_cbcenc != 0) {
275 fprintf(stderr, " AES/CBC (enc): %s\n",
276 get_algo_name(cc->iaes_cbcenc, 0));
277 }
278 if (cc->iaes_cbcdec != 0) {
279 fprintf(stderr, " AES/CBC (dec): %s\n",
280 get_algo_name(cc->iaes_cbcdec, 0));
281 }
282 if (cc->iaes_ctr != 0) {
283 fprintf(stderr, " AES/CTR: %s\n",
284 get_algo_name(cc->iaes_cbcdec, 0));
285 }
286 if (cc->ides_cbcenc != 0) {
287 fprintf(stderr, " DES/CBC (enc): %s\n",
288 get_algo_name(cc->ides_cbcenc, 0));
289 }
290 if (cc->ides_cbcdec != 0) {
291 fprintf(stderr, " DES/CBC (dec): %s\n",
292 get_algo_name(cc->ides_cbcdec, 0));
293 }
294 if (cc->ighash != 0) {
295 fprintf(stderr, " GHASH (GCM): %s\n",
296 get_algo_name(cc->ighash, 0));
297 }
298 if (cc->ichacha != 0) {
299 fprintf(stderr, " ChaCha20: %s\n",
300 get_algo_name(cc->ichacha, 0));
301 }
302 if (cc->ipoly != 0) {
303 fprintf(stderr, " Poly1305: %s\n",
304 get_algo_name(cc->ipoly, 0));
305 }
306 if (cc->iec != 0) {
307 fprintf(stderr, " EC: %s\n",
308 get_algo_name(cc->iec, 0));
309 }
310 if (cc->iecdsa != 0) {
311 fprintf(stderr, " ECDSA: %s\n",
312 get_algo_name(cc->iecdsa, 0));
313 }
314 if (cc->irsavrfy != 0) {
315 fprintf(stderr, " RSA (vrfy): %s\n",
316 get_algo_name(cc->irsavrfy, 0));
317 }
318 }
319
320 #ifdef _WIN32
321 fd_event = WSA_INVALID_EVENT;
322 can_send = 0;
323 can_recv = 0;
324 bb.ptr = bb.len = 0;
325 #endif
326
327 /*
328 * On Unix systems, we need to follow three descriptors:
329 * standard input (0), standard output (1), and the socket
330 * itself (for both read and write). This is done with a poll()
331 * call.
332 *
333 * On Windows systems, we use WSAEventSelect() to associate
334 * an event handle with the network activity, and we use
335 * WaitForMultipleObjectsEx() on that handle and the standard
336 * input handle, when appropriate. Standard output is assumed
337 * to be always writeable, and standard input to be the console;
338 * this does not work well (or at all) with redirections (to
339 * pipes or files) but it should be enough for a debug tool
340 * (TODO: make something that handles redirections as well).
341 */
342
343 #ifdef _WIN32
344 fd_event = WSACreateEvent();
345 if (fd_event == WSA_INVALID_EVENT) {
346 fprintf(stderr, "ERROR: WSACreateEvent() failed with %d\n",
347 WSAGetLastError());
348 retcode = -2;
349 goto engine_exit;
350 }
351 WSAEventSelect(fd, fd_event, FD_READ | FD_WRITE | FD_CLOSE);
352 h_in = GetStdHandle(STD_INPUT_HANDLE);
353 h_out = GetStdHandle(STD_OUTPUT_HANDLE);
354 SetConsoleMode(h_in, ENABLE_ECHO_INPUT
355 | ENABLE_LINE_INPUT
356 | ENABLE_PROCESSED_INPUT
357 | ENABLE_PROCESSED_OUTPUT
358 | ENABLE_WRAP_AT_EOL_OUTPUT);
359 #else
360 /*
361 * Make sure that stdin and stdout are non-blocking.
362 */
363 fcntl(0, F_SETFL, O_NONBLOCK);
364 fcntl(1, F_SETFL, O_NONBLOCK);
365 #endif
366
367 /*
368 * Perform the loop.
369 */
370 for (;;) {
371 unsigned st;
372 int sendrec, recvrec, sendapp, recvapp;
373 #ifdef _WIN32
374 HANDLE pfd[2];
375 DWORD wt;
376 #else
377 struct pollfd pfd[3];
378 int n;
379 #endif
380 size_t u, k_fd, k_in, k_out;
381 int sendrec_ok, recvrec_ok, sendapp_ok, recvapp_ok;
382
383 /*
384 * Get current engine state.
385 */
386 st = br_ssl_engine_current_state(cc);
387 if (st == BR_SSL_CLOSED) {
388 int err;
389
390 err = br_ssl_engine_last_error(cc);
391 if (err == BR_ERR_OK) {
392 if (verbose) {
393 fprintf(stderr,
394 "SSL closed normally\n");
395 }
396 retcode = 0;
397 goto engine_exit;
398 } else {
399 fprintf(stderr, "ERROR: SSL error %d", err);
400 retcode = err;
401 if (err >= BR_ERR_SEND_FATAL_ALERT) {
402 err -= BR_ERR_SEND_FATAL_ALERT;
403 fprintf(stderr,
404 " (sent alert %d)\n", err);
405 } else if (err >= BR_ERR_RECV_FATAL_ALERT) {
406 err -= BR_ERR_RECV_FATAL_ALERT;
407 fprintf(stderr,
408 " (received alert %d)\n", err);
409 } else {
410 const char *ename;
411
412 ename = find_error_name(err, NULL);
413 if (ename == NULL) {
414 ename = "unknown";
415 }
416 fprintf(stderr, " (%s)\n", ename);
417 }
418 goto engine_exit;
419 }
420 }
421
422 /*
423 * Compute descriptors that must be polled, depending
424 * on engine state.
425 */
426 sendrec = ((st & BR_SSL_SENDREC) != 0);
427 recvrec = ((st & BR_SSL_RECVREC) != 0);
428 sendapp = ((st & BR_SSL_SENDAPP) != 0);
429 recvapp = ((st & BR_SSL_RECVAPP) != 0);
430 if (verbose && sendapp && !hsdetails) {
431 char csn[80];
432 const char *pname;
433
434 fprintf(stderr, "Handshake completed\n");
435 fprintf(stderr, " version: ");
436 switch (cc->session.version) {
437 case BR_SSL30:
438 fprintf(stderr, "SSL 3.0");
439 break;
440 case BR_TLS10:
441 fprintf(stderr, "TLS 1.0");
442 break;
443 case BR_TLS11:
444 fprintf(stderr, "TLS 1.1");
445 break;
446 case BR_TLS12:
447 fprintf(stderr, "TLS 1.2");
448 break;
449 default:
450 fprintf(stderr, "unknown (0x%04X)",
451 (unsigned)cc->session.version);
452 break;
453 }
454 fprintf(stderr, "\n");
455 get_suite_name_ext(
456 cc->session.cipher_suite, csn, sizeof csn);
457 fprintf(stderr, " cipher suite: %s\n", csn);
458 if (uses_ecdhe(cc->session.cipher_suite)) {
459 get_curve_name_ext(
460 br_ssl_engine_get_ecdhe_curve(cc),
461 csn, sizeof csn);
462 fprintf(stderr,
463 " ECDHE curve: %s\n", csn);
464 }
465 fprintf(stderr, " secure renegotiation: %s\n",
466 cc->reneg == 1 ? "no" : "yes");
467 pname = br_ssl_engine_get_selected_protocol(cc);
468 if (pname != NULL) {
469 fprintf(stderr,
470 " protocol name (ALPN): %s\n",
471 pname);
472 }
473 hsdetails = 1;
474 }
475
476 k_fd = (size_t)-1;
477 k_in = (size_t)-1;
478 k_out = (size_t)-1;
479
480 u = 0;
481 #ifdef _WIN32
482 /*
483 * If we recorded that we can send or receive data, and we
484 * want to do exactly that, then we don't wait; we just do
485 * it.
486 */
487 recvapp_ok = 0;
488 sendrec_ok = 0;
489 recvrec_ok = 0;
490 sendapp_ok = 0;
491
492 if (sendrec && can_send) {
493 sendrec_ok = 1;
494 } else if (recvrec && can_recv) {
495 recvrec_ok = 1;
496 } else if (recvapp) {
497 recvapp_ok = 1;
498 } else if (sendapp && in_avail_buffered(h_in, &bb)) {
499 sendapp_ok = 1;
500 } else {
501 /*
502 * If we cannot do I/O right away, then we must
503 * wait for some event, and try again.
504 */
505 pfd[u] = (HANDLE)fd_event;
506 k_fd = u;
507 u ++;
508 if (sendapp) {
509 pfd[u] = h_in;
510 k_in = u;
511 u ++;
512 }
513 wt = WaitForMultipleObjectsEx(u, pfd,
514 FALSE, INFINITE, FALSE);
515 if (wt == WAIT_FAILED) {
516 fprintf(stderr, "ERROR:"
517 " WaitForMultipleObjectsEx()"
518 " failed with 0x%08lX",
519 (unsigned long)GetLastError());
520 retcode = -2;
521 goto engine_exit;
522 }
523 if (wt == k_fd) {
524 WSANETWORKEVENTS e;
525
526 if (WSAEnumNetworkEvents(fd, fd_event, &e)) {
527 fprintf(stderr, "ERROR:"
528 " WSAEnumNetworkEvents()"
529 " failed with %d\n",
530 WSAGetLastError());
531 retcode = -2;
532 goto engine_exit;
533 }
534 if (e.lNetworkEvents & (FD_WRITE | FD_CLOSE)) {
535 can_send = 1;
536 }
537 if (e.lNetworkEvents & (FD_READ | FD_CLOSE)) {
538 can_recv = 1;
539 }
540 }
541 continue;
542 }
543 #else
544 if (sendrec || recvrec) {
545 pfd[u].fd = fd;
546 pfd[u].revents = 0;
547 pfd[u].events = 0;
548 if (sendrec) {
549 pfd[u].events |= POLLOUT;
550 }
551 if (recvrec) {
552 pfd[u].events |= POLLIN;
553 }
554 k_fd = u;
555 u ++;
556 }
557 if (sendapp) {
558 pfd[u].fd = 0;
559 pfd[u].revents = 0;
560 pfd[u].events = POLLIN;
561 k_in = u;
562 u ++;
563 }
564 if (recvapp) {
565 pfd[u].fd = 1;
566 pfd[u].revents = 0;
567 pfd[u].events = POLLOUT;
568 k_out = u;
569 u ++;
570 }
571 n = poll(pfd, u, -1);
572 if (n < 0) {
573 if (errno == EINTR) {
574 continue;
575 }
576 perror("ERROR: poll()");
577 retcode = -2;
578 goto engine_exit;
579 }
580 if (n == 0) {
581 continue;
582 }
583
584 /*
585 * We transform closures/errors into read+write accesses
586 * so as to force the read() or write() call that will
587 * detect the situation.
588 */
589 while (u -- > 0) {
590 if (pfd[u].revents & (POLLERR | POLLHUP)) {
591 pfd[u].revents |= POLLIN | POLLOUT;
592 }
593 }
594
595 recvapp_ok = recvapp && (pfd[k_out].revents & POLLOUT) != 0;
596 sendrec_ok = sendrec && (pfd[k_fd].revents & POLLOUT) != 0;
597 recvrec_ok = recvrec && (pfd[k_fd].revents & POLLIN) != 0;
598 sendapp_ok = sendapp && (pfd[k_in].revents & POLLIN) != 0;
599 #endif
600
601 /*
602 * We give preference to outgoing data, on stdout and on
603 * the socket.
604 */
605 if (recvapp_ok) {
606 unsigned char *buf;
607 size_t len;
608 #ifdef _WIN32
609 DWORD wlen;
610 #else
611 ssize_t wlen;
612 #endif
613
614 buf = br_ssl_engine_recvapp_buf(cc, &len);
615 #ifdef _WIN32
616 if (!WriteFile(h_out, buf, len, &wlen, NULL)) {
617 if (verbose) {
618 fprintf(stderr, "stdout closed...\n");
619 }
620 retcode = -2;
621 goto engine_exit;
622 }
623 #else
624 wlen = write(1, buf, len);
625 if (wlen <= 0) {
626 if (verbose) {
627 fprintf(stderr, "stdout closed...\n");
628 }
629 retcode = -2;
630 goto engine_exit;
631 }
632 #endif
633 br_ssl_engine_recvapp_ack(cc, wlen);
634 continue;
635 }
636 if (sendrec_ok) {
637 unsigned char *buf;
638 size_t len;
639 int wlen;
640
641 buf = br_ssl_engine_sendrec_buf(cc, &len);
642 wlen = send(fd, buf, len, 0);
643 if (wlen <= 0) {
644 #ifdef _WIN32
645 int err;
646
647 err = WSAGetLastError();
648 if (err == EWOULDBLOCK
649 || err == WSAEWOULDBLOCK)
650 {
651 can_send = 0;
652 continue;
653 }
654 #else
655 if (errno == EINTR || errno == EWOULDBLOCK) {
656 continue;
657 }
658 #endif
659 if (verbose) {
660 fprintf(stderr, "socket closed...\n");
661 }
662 retcode = -1;
663 goto engine_exit;
664 }
665 if (trace) {
666 dump_blob("Outgoing bytes", buf, wlen);
667 }
668 br_ssl_engine_sendrec_ack(cc, wlen);
669 continue;
670 }
671 if (recvrec_ok) {
672 unsigned char *buf;
673 size_t len;
674 int rlen;
675
676 buf = br_ssl_engine_recvrec_buf(cc, &len);
677 rlen = recv(fd, buf, len, 0);
678 if (rlen == 0) {
679 if (verbose) {
680 fprintf(stderr, "socket closed...\n");
681 }
682 retcode = -1;
683 goto engine_exit;
684 }
685 if (rlen < 0) {
686 #ifdef _WIN32
687 int err;
688
689 err = WSAGetLastError();
690 if (err == EWOULDBLOCK
691 || err == WSAEWOULDBLOCK)
692 {
693 can_recv = 0;
694 continue;
695 }
696 #else
697 if (errno == EINTR || errno == EWOULDBLOCK) {
698 continue;
699 }
700 #endif
701 if (verbose) {
702 fprintf(stderr, "socket broke...\n");
703 }
704 retcode = -1;
705 goto engine_exit;
706 }
707 if (trace) {
708 dump_blob("Incoming bytes", buf, rlen);
709 }
710 br_ssl_engine_recvrec_ack(cc, rlen);
711 continue;
712 }
713 if (sendapp_ok) {
714 unsigned char *buf;
715 size_t len;
716 #ifdef _WIN32
717 int rlen;
718 #else
719 ssize_t rlen;
720 #endif
721
722 buf = br_ssl_engine_sendapp_buf(cc, &len);
723 #ifdef _WIN32
724 rlen = in_read_buffered(h_in, &bb, buf, len);
725 #else
726 rlen = read(0, buf, len);
727 #endif
728 if (rlen <= 0) {
729 if (verbose) {
730 fprintf(stderr, "stdin closed...\n");
731 }
732 br_ssl_engine_close(cc);
733 } else if (!run_command(cc, buf, rlen)) {
734 br_ssl_engine_sendapp_ack(cc, rlen);
735 }
736 br_ssl_engine_flush(cc, 0);
737 continue;
738 }
739
740 /* We should never reach that point. */
741 fprintf(stderr, "ERROR: poll() misbehaves\n");
742 retcode = -2;
743 goto engine_exit;
744 }
745
746 /*
747 * Release allocated structures.
748 */
749 engine_exit:
750 #ifdef _WIN32
751 if (fd_event != WSA_INVALID_EVENT) {
752 WSACloseEvent(fd_event);
753 }
754 #endif
755 return retcode;
756 }