2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
35 #include <sys/types.h>
36 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
45 #define INVALID_SOCKET (-1)
51 dump_blob(const char *name, const void *data, size_t len)
53 const unsigned char *buf;
57 fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len);
58 for (u = 0; u < len; u ++) {
60 fprintf(stderr, "\n%08lX ", (unsigned long)u);
61 } else if ((u & 7) == 0) {
64 fprintf(stderr, " %02x", buf[u]);
66 fprintf(stderr, "\n");
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.
75 run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len)
78 * A single static slot for saving session parameters.
80 static br_ssl_session_parameters slot;
81 static int slot_used = 0;
85 if (len < 2 || len > 3) {
88 if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) {
91 if (len == 2 && buf[1] != '\n') {
96 fprintf(stderr, "closing...\n");
97 br_ssl_engine_close(cc);
100 if (br_ssl_engine_renegotiate(cc)) {
101 fprintf(stderr, "renegotiating...\n");
103 fprintf(stderr, "not renegotiating.\n");
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
114 fprintf(stderr, "forgetting session...\n");
115 br_ssl_client_forget_session((br_ssl_client_context *)cc);
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]);
124 fprintf(stderr, "\n");
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]);
134 fprintf(stderr, "\n");
135 br_ssl_engine_set_session_parameters(cc, &slot);
147 unsigned char buf[1024];
152 in_return_bytes(in_buffer *bb, unsigned char *buf, size_t len)
154 if (bb->ptr < bb->len) {
160 clen = bb->len - bb->ptr;
164 memcpy(buf, bb->buf + bb->ptr, clen);
166 if (bb->ptr == bb->len) {
167 bb->ptr = bb->len = 0;
175 * A buffered version of in_read(), using a buffer to return only
176 * full lines when feasible.
179 in_read_buffered(HANDLE h_in, in_buffer *bb, unsigned char *buf, size_t len)
186 n = in_return_bytes(bb, buf, len);
194 if (!PeekConsoleInput(h_in, &inrec, 1, &v)) {
195 fprintf(stderr, "ERROR: PeekConsoleInput()"
196 " failed with 0x%08lX\n",
197 (unsigned long)GetLastError());
203 if (!ReadConsoleInput(h_in, &inrec, 1, &v)) {
204 fprintf(stderr, "ERROR: ReadConsoleInput()"
205 " failed with 0x%08lX\n",
206 (unsigned long)GetLastError());
212 if (inrec.EventType == KEY_EVENT
213 && inrec.Event.KeyEvent.bKeyDown)
217 c = inrec.Event.KeyEvent.uChar.AsciiChar;
218 if (c == '\n' || c == '\r' || c == '\t'
219 || (c >= 32 && c != 127))
224 bb->buf[bb->ptr ++] = (unsigned char)c;
228 if (bb->len == sizeof bb->buf || c == '\n') {
230 return in_return_bytes(bb, buf, len);
238 in_avail_buffered(HANDLE h_in, in_buffer *bb)
240 return in_read_buffered(h_in, bb, NULL, 1);
247 run_ssl_engine(br_ssl_engine_context *cc, unsigned long fd, unsigned flags)
255 int can_send, can_recv;
262 verbose = (flags & RUN_ENGINE_VERBOSE) != 0;
263 trace = (flags & RUN_ENGINE_TRACE) != 0;
266 * Print algorithm details.
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));
278 if (cc->iaes_cbcdec != 0) {
279 fprintf(stderr, " AES/CBC (dec): %s\n",
280 get_algo_name(cc->iaes_cbcdec, 0));
282 if (cc->iaes_ctr != 0) {
283 fprintf(stderr, " AES/CTR: %s\n",
284 get_algo_name(cc->iaes_cbcdec, 0));
286 if (cc->iaes_ctrcbc != 0) {
287 fprintf(stderr, " AES/CCM: %s\n",
288 get_algo_name(cc->iaes_ctrcbc, 0));
290 if (cc->ides_cbcenc != 0) {
291 fprintf(stderr, " DES/CBC (enc): %s\n",
292 get_algo_name(cc->ides_cbcenc, 0));
294 if (cc->ides_cbcdec != 0) {
295 fprintf(stderr, " DES/CBC (dec): %s\n",
296 get_algo_name(cc->ides_cbcdec, 0));
298 if (cc->ighash != 0) {
299 fprintf(stderr, " GHASH (GCM): %s\n",
300 get_algo_name(cc->ighash, 0));
302 if (cc->ichacha != 0) {
303 fprintf(stderr, " ChaCha20: %s\n",
304 get_algo_name(cc->ichacha, 0));
306 if (cc->ipoly != 0) {
307 fprintf(stderr, " Poly1305: %s\n",
308 get_algo_name(cc->ipoly, 0));
311 fprintf(stderr, " EC: %s\n",
312 get_algo_name(cc->iec, 0));
314 if (cc->iecdsa != 0) {
315 fprintf(stderr, " ECDSA: %s\n",
316 get_algo_name(cc->iecdsa, 0));
318 if (cc->irsavrfy != 0) {
319 fprintf(stderr, " RSA (vrfy): %s\n",
320 get_algo_name(cc->irsavrfy, 0));
325 fd_event = WSA_INVALID_EVENT;
332 * On Unix systems, we need to follow three descriptors:
333 * standard input (0), standard output (1), and the socket
334 * itself (for both read and write). This is done with a poll()
337 * On Windows systems, we use WSAEventSelect() to associate
338 * an event handle with the network activity, and we use
339 * WaitForMultipleObjectsEx() on that handle and the standard
340 * input handle, when appropriate. Standard output is assumed
341 * to be always writeable, and standard input to be the console;
342 * this does not work well (or at all) with redirections (to
343 * pipes or files) but it should be enough for a debug tool
344 * (TODO: make something that handles redirections as well).
348 fd_event = WSACreateEvent();
349 if (fd_event == WSA_INVALID_EVENT) {
350 fprintf(stderr, "ERROR: WSACreateEvent() failed with %d\n",
355 WSAEventSelect(fd, fd_event, FD_READ | FD_WRITE | FD_CLOSE);
356 h_in = GetStdHandle(STD_INPUT_HANDLE);
357 h_out = GetStdHandle(STD_OUTPUT_HANDLE);
358 SetConsoleMode(h_in, ENABLE_ECHO_INPUT
360 | ENABLE_PROCESSED_INPUT
361 | ENABLE_PROCESSED_OUTPUT
362 | ENABLE_WRAP_AT_EOL_OUTPUT);
365 * Make sure that stdin and stdout are non-blocking.
367 fcntl(0, F_SETFL, O_NONBLOCK);
368 fcntl(1, F_SETFL, O_NONBLOCK);
376 int sendrec, recvrec, sendapp, recvapp;
381 struct pollfd pfd[3];
384 size_t u, k_fd, k_in, k_out;
385 int sendrec_ok, recvrec_ok, sendapp_ok, recvapp_ok;
388 * Get current engine state.
390 st = br_ssl_engine_current_state(cc);
391 if (st == BR_SSL_CLOSED) {
394 err = br_ssl_engine_last_error(cc);
395 if (err == BR_ERR_OK) {
398 "SSL closed normally\n");
403 fprintf(stderr, "ERROR: SSL error %d", err);
405 if (err >= BR_ERR_SEND_FATAL_ALERT) {
406 err -= BR_ERR_SEND_FATAL_ALERT;
408 " (sent alert %d)\n", err);
409 } else if (err >= BR_ERR_RECV_FATAL_ALERT) {
410 err -= BR_ERR_RECV_FATAL_ALERT;
412 " (received alert %d)\n", err);
416 ename = find_error_name(err, NULL);
420 fprintf(stderr, " (%s)\n", ename);
427 * Compute descriptors that must be polled, depending
430 sendrec = ((st & BR_SSL_SENDREC) != 0);
431 recvrec = ((st & BR_SSL_RECVREC) != 0);
432 sendapp = ((st & BR_SSL_SENDAPP) != 0);
433 recvapp = ((st & BR_SSL_RECVAPP) != 0);
434 if (verbose && sendapp && !hsdetails) {
438 fprintf(stderr, "Handshake completed\n");
439 fprintf(stderr, " version: ");
440 switch (cc->session.version) {
442 fprintf(stderr, "SSL 3.0");
445 fprintf(stderr, "TLS 1.0");
448 fprintf(stderr, "TLS 1.1");
451 fprintf(stderr, "TLS 1.2");
454 fprintf(stderr, "unknown (0x%04X)",
455 (unsigned)cc->session.version);
458 fprintf(stderr, "\n");
460 cc->session.cipher_suite, csn, sizeof csn);
461 fprintf(stderr, " cipher suite: %s\n", csn);
462 if (uses_ecdhe(cc->session.cipher_suite)) {
464 br_ssl_engine_get_ecdhe_curve(cc),
467 " ECDHE curve: %s\n", csn);
469 fprintf(stderr, " secure renegotiation: %s\n",
470 cc->reneg == 1 ? "no" : "yes");
471 pname = br_ssl_engine_get_selected_protocol(cc);
474 " protocol name (ALPN): %s\n",
487 * If we recorded that we can send or receive data, and we
488 * want to do exactly that, then we don't wait; we just do
496 if (sendrec && can_send) {
498 } else if (recvrec && can_recv) {
500 } else if (recvapp) {
502 } else if (sendapp && in_avail_buffered(h_in, &bb)) {
506 * If we cannot do I/O right away, then we must
507 * wait for some event, and try again.
509 pfd[u] = (HANDLE)fd_event;
517 wt = WaitForMultipleObjectsEx(u, pfd,
518 FALSE, INFINITE, FALSE);
519 if (wt == WAIT_FAILED) {
520 fprintf(stderr, "ERROR:"
521 " WaitForMultipleObjectsEx()"
522 " failed with 0x%08lX",
523 (unsigned long)GetLastError());
530 if (WSAEnumNetworkEvents(fd, fd_event, &e)) {
531 fprintf(stderr, "ERROR:"
532 " WSAEnumNetworkEvents()"
538 if (e.lNetworkEvents & (FD_WRITE | FD_CLOSE)) {
541 if (e.lNetworkEvents & (FD_READ | FD_CLOSE)) {
548 if (sendrec || recvrec) {
553 pfd[u].events |= POLLOUT;
556 pfd[u].events |= POLLIN;
564 pfd[u].events = POLLIN;
571 pfd[u].events = POLLOUT;
575 n = poll(pfd, u, -1);
577 if (errno == EINTR) {
580 perror("ERROR: poll()");
589 * We transform closures/errors into read+write accesses
590 * so as to force the read() or write() call that will
591 * detect the situation.
594 if (pfd[u].revents & (POLLERR | POLLHUP)) {
595 pfd[u].revents |= POLLIN | POLLOUT;
599 recvapp_ok = recvapp && (pfd[k_out].revents & POLLOUT) != 0;
600 sendrec_ok = sendrec && (pfd[k_fd].revents & POLLOUT) != 0;
601 recvrec_ok = recvrec && (pfd[k_fd].revents & POLLIN) != 0;
602 sendapp_ok = sendapp && (pfd[k_in].revents & POLLIN) != 0;
606 * We give preference to outgoing data, on stdout and on
618 buf = br_ssl_engine_recvapp_buf(cc, &len);
620 if (!WriteFile(h_out, buf, len, &wlen, NULL)) {
622 fprintf(stderr, "stdout closed...\n");
628 wlen = write(1, buf, len);
631 fprintf(stderr, "stdout closed...\n");
637 br_ssl_engine_recvapp_ack(cc, wlen);
645 buf = br_ssl_engine_sendrec_buf(cc, &len);
646 wlen = send(fd, buf, len, 0);
651 err = WSAGetLastError();
652 if (err == EWOULDBLOCK
653 || err == WSAEWOULDBLOCK)
659 if (errno == EINTR || errno == EWOULDBLOCK) {
664 fprintf(stderr, "socket closed...\n");
670 dump_blob("Outgoing bytes", buf, wlen);
672 br_ssl_engine_sendrec_ack(cc, wlen);
680 buf = br_ssl_engine_recvrec_buf(cc, &len);
681 rlen = recv(fd, buf, len, 0);
684 fprintf(stderr, "socket closed...\n");
693 err = WSAGetLastError();
694 if (err == EWOULDBLOCK
695 || err == WSAEWOULDBLOCK)
701 if (errno == EINTR || errno == EWOULDBLOCK) {
706 fprintf(stderr, "socket broke...\n");
712 dump_blob("Incoming bytes", buf, rlen);
714 br_ssl_engine_recvrec_ack(cc, rlen);
726 buf = br_ssl_engine_sendapp_buf(cc, &len);
728 rlen = in_read_buffered(h_in, &bb, buf, len);
730 rlen = read(0, buf, len);
734 fprintf(stderr, "stdin closed...\n");
736 br_ssl_engine_close(cc);
737 } else if (!run_command(cc, buf, rlen)) {
738 br_ssl_engine_sendapp_ack(cc, rlen);
740 br_ssl_engine_flush(cc, 0);
744 /* We should never reach that point. */
745 fprintf(stderr, "ERROR: poll() misbehaves\n");
751 * Release allocated structures.
755 if (fd_event != WSA_INVALID_EVENT) {
756 WSACloseEvent(fd_event);