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
50static void
51dump_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 */
74static int
75run_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
146typedef struct {
147	unsigned char buf[1024];
148	size_t ptr, len;
149} in_buffer;
150
151static int
152in_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 */
178static int
179in_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
237static int
238in_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 */
246int
247run_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_ctr, 0));
285		}
286		if (cc->iaes_ctrcbc != 0) {
287			fprintf(stderr, "   AES/CCM:       %s\n",
288				get_algo_name(cc->iaes_ctrcbc, 0));
289		}
290		if (cc->ides_cbcenc != 0) {
291			fprintf(stderr, "   DES/CBC (enc): %s\n",
292				get_algo_name(cc->ides_cbcenc, 0));
293		}
294		if (cc->ides_cbcdec != 0) {
295			fprintf(stderr, "   DES/CBC (dec): %s\n",
296				get_algo_name(cc->ides_cbcdec, 0));
297		}
298		if (cc->ighash != 0) {
299			fprintf(stderr, "   GHASH (GCM):   %s\n",
300				get_algo_name(cc->ighash, 0));
301		}
302		if (cc->ichacha != 0) {
303			fprintf(stderr, "   ChaCha20:      %s\n",
304				get_algo_name(cc->ichacha, 0));
305		}
306		if (cc->ipoly != 0) {
307			fprintf(stderr, "   Poly1305:      %s\n",
308				get_algo_name(cc->ipoly, 0));
309		}
310		if (cc->iec != 0) {
311			fprintf(stderr, "   EC:            %s\n",
312				get_algo_name(cc->iec, 0));
313		}
314		if (cc->iecdsa != 0) {
315			fprintf(stderr, "   ECDSA:         %s\n",
316				get_algo_name(cc->iecdsa, 0));
317		}
318		if (cc->irsavrfy != 0) {
319			fprintf(stderr, "   RSA (vrfy):    %s\n",
320				get_algo_name(cc->irsavrfy, 0));
321		}
322	}
323
324#ifdef _WIN32
325	fd_event = WSA_INVALID_EVENT;
326	can_send = 0;
327	can_recv = 0;
328	bb.ptr = bb.len = 0;
329#endif
330
331	/*
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()
335	 * call.
336	 *
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).
345	 */
346
347#ifdef _WIN32
348	fd_event = WSACreateEvent();
349	if (fd_event == WSA_INVALID_EVENT) {
350		fprintf(stderr, "ERROR: WSACreateEvent() failed with %d\n",
351			WSAGetLastError());
352		retcode = -2;
353		goto engine_exit;
354	}
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
359		| ENABLE_LINE_INPUT
360		| ENABLE_PROCESSED_INPUT
361		| ENABLE_PROCESSED_OUTPUT
362		| ENABLE_WRAP_AT_EOL_OUTPUT);
363#else
364	/*
365	 * Make sure that stdin and stdout are non-blocking.
366	 */
367	fcntl(0, F_SETFL, O_NONBLOCK);
368	fcntl(1, F_SETFL, O_NONBLOCK);
369#endif
370
371	/*
372	 * Perform the loop.
373	 */
374	for (;;) {
375		unsigned st;
376		int sendrec, recvrec, sendapp, recvapp;
377#ifdef _WIN32
378		HANDLE pfd[2];
379		DWORD wt;
380#else
381		struct pollfd pfd[3];
382		int n;
383#endif
384		size_t u, k_fd, k_in, k_out;
385		int sendrec_ok, recvrec_ok, sendapp_ok, recvapp_ok;
386
387		/*
388		 * Get current engine state.
389		 */
390		st = br_ssl_engine_current_state(cc);
391		if (st == BR_SSL_CLOSED) {
392			int err;
393
394			err = br_ssl_engine_last_error(cc);
395			if (err == BR_ERR_OK) {
396				if (verbose) {
397					fprintf(stderr,
398						"SSL closed normally\n");
399				}
400				retcode = 0;
401				goto engine_exit;
402			} else {
403				fprintf(stderr, "ERROR: SSL error %d", err);
404				retcode = err;
405				if (err >= BR_ERR_SEND_FATAL_ALERT) {
406					err -= BR_ERR_SEND_FATAL_ALERT;
407					fprintf(stderr,
408						" (sent alert %d)\n", err);
409				} else if (err >= BR_ERR_RECV_FATAL_ALERT) {
410					err -= BR_ERR_RECV_FATAL_ALERT;
411					fprintf(stderr,
412						" (received alert %d)\n", err);
413				} else {
414					const char *ename;
415
416					ename = find_error_name(err, NULL);
417					if (ename == NULL) {
418						ename = "unknown";
419					}
420					fprintf(stderr, " (%s)\n", ename);
421				}
422				goto engine_exit;
423			}
424		}
425
426		/*
427		 * Compute descriptors that must be polled, depending
428		 * on engine state.
429		 */
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) {
435			char csn[80];
436			const char *pname;
437
438			fprintf(stderr, "Handshake completed\n");
439			fprintf(stderr, "   version:               ");
440			switch (cc->session.version) {
441			case BR_SSL30:
442				fprintf(stderr, "SSL 3.0");
443				break;
444			case BR_TLS10:
445				fprintf(stderr, "TLS 1.0");
446				break;
447			case BR_TLS11:
448				fprintf(stderr, "TLS 1.1");
449				break;
450			case BR_TLS12:
451				fprintf(stderr, "TLS 1.2");
452				break;
453			default:
454				fprintf(stderr, "unknown (0x%04X)",
455					(unsigned)cc->session.version);
456				break;
457			}
458			fprintf(stderr, "\n");
459			get_suite_name_ext(
460				cc->session.cipher_suite, csn, sizeof csn);
461			fprintf(stderr, "   cipher suite:          %s\n", csn);
462			if (uses_ecdhe(cc->session.cipher_suite)) {
463				get_curve_name_ext(
464					br_ssl_engine_get_ecdhe_curve(cc),
465					csn, sizeof csn);
466				fprintf(stderr,
467					"   ECDHE curve:           %s\n", csn);
468			}
469			fprintf(stderr, "   secure renegotiation:  %s\n",
470				cc->reneg == 1 ? "no" : "yes");
471			pname = br_ssl_engine_get_selected_protocol(cc);
472			if (pname != NULL) {
473				fprintf(stderr,
474					"   protocol name (ALPN):  %s\n",
475					pname);
476			}
477			hsdetails = 1;
478		}
479
480		k_fd = (size_t)-1;
481		k_in = (size_t)-1;
482		k_out = (size_t)-1;
483
484		u = 0;
485#ifdef _WIN32
486		/*
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
489		 * it.
490		 */
491		recvapp_ok = 0;
492		sendrec_ok = 0;
493		recvrec_ok = 0;
494		sendapp_ok = 0;
495
496		if (sendrec && can_send) {
497			sendrec_ok = 1;
498		} else if (recvrec && can_recv) {
499			recvrec_ok = 1;
500		} else if (recvapp) {
501			recvapp_ok = 1;
502		} else if (sendapp && in_avail_buffered(h_in, &bb)) {
503			sendapp_ok = 1;
504		} else {
505			/*
506			 * If we cannot do I/O right away, then we must
507			 * wait for some event, and try again.
508			 */
509			pfd[u] = (HANDLE)fd_event;
510			k_fd = u;
511			u ++;
512			if (sendapp) {
513				pfd[u] = h_in;
514				k_in = u;
515				u ++;
516			}
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());
524				retcode = -2;
525				goto engine_exit;
526			}
527			if (wt == k_fd) {
528				WSANETWORKEVENTS e;
529
530				if (WSAEnumNetworkEvents(fd, fd_event, &e)) {
531					fprintf(stderr, "ERROR:"
532						" WSAEnumNetworkEvents()"
533						" failed with %d\n",
534						WSAGetLastError());
535					retcode = -2;
536					goto engine_exit;
537				}
538				if (e.lNetworkEvents & (FD_WRITE | FD_CLOSE)) {
539					can_send = 1;
540				}
541				if (e.lNetworkEvents & (FD_READ | FD_CLOSE)) {
542					can_recv = 1;
543				}
544			}
545			continue;
546		}
547#else
548		if (sendrec || recvrec) {
549			pfd[u].fd = fd;
550			pfd[u].revents = 0;
551			pfd[u].events = 0;
552			if (sendrec) {
553				pfd[u].events |= POLLOUT;
554			}
555			if (recvrec) {
556				pfd[u].events |= POLLIN;
557			}
558			k_fd = u;
559			u ++;
560		}
561		if (sendapp) {
562			pfd[u].fd = 0;
563			pfd[u].revents = 0;
564			pfd[u].events = POLLIN;
565			k_in = u;
566			u ++;
567		}
568		if (recvapp) {
569			pfd[u].fd = 1;
570			pfd[u].revents = 0;
571			pfd[u].events = POLLOUT;
572			k_out = u;
573			u ++;
574		}
575		n = poll(pfd, u, -1);
576		if (n < 0) {
577			if (errno == EINTR) {
578				continue;
579			}
580			perror("ERROR: poll()");
581			retcode = -2;
582			goto engine_exit;
583		}
584		if (n == 0) {
585			continue;
586		}
587
588		/*
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.
592		 */
593		while (u -- > 0) {
594			if (pfd[u].revents & (POLLERR | POLLHUP)) {
595				pfd[u].revents |= POLLIN | POLLOUT;
596			}
597		}
598
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;
603#endif
604
605		/*
606		 * We give preference to outgoing data, on stdout and on
607		 * the socket.
608		 */
609		if (recvapp_ok) {
610			unsigned char *buf;
611			size_t len;
612#ifdef _WIN32
613			DWORD wlen;
614#else
615			ssize_t wlen;
616#endif
617
618			buf = br_ssl_engine_recvapp_buf(cc, &len);
619#ifdef _WIN32
620			if (!WriteFile(h_out, buf, len, &wlen, NULL)) {
621				if (verbose) {
622					fprintf(stderr, "stdout closed...\n");
623				}
624				retcode = -2;
625				goto engine_exit;
626			}
627#else
628			wlen = write(1, buf, len);
629			if (wlen <= 0) {
630				if (verbose) {
631					fprintf(stderr, "stdout closed...\n");
632				}
633				retcode = -2;
634				goto engine_exit;
635			}
636#endif
637			br_ssl_engine_recvapp_ack(cc, wlen);
638			continue;
639		}
640		if (sendrec_ok) {
641			unsigned char *buf;
642			size_t len;
643			int wlen;
644
645			buf = br_ssl_engine_sendrec_buf(cc, &len);
646			wlen = send(fd, buf, len, 0);
647			if (wlen <= 0) {
648#ifdef _WIN32
649				int err;
650
651				err = WSAGetLastError();
652				if (err == EWOULDBLOCK
653					|| err == WSAEWOULDBLOCK)
654				{
655					can_send = 0;
656					continue;
657				}
658#else
659				if (errno == EINTR || errno == EWOULDBLOCK) {
660					continue;
661				}
662#endif
663				if (verbose) {
664					fprintf(stderr, "socket closed...\n");
665				}
666				retcode = -1;
667				goto engine_exit;
668			}
669			if (trace) {
670				dump_blob("Outgoing bytes", buf, wlen);
671			}
672			br_ssl_engine_sendrec_ack(cc, wlen);
673			continue;
674		}
675		if (recvrec_ok) {
676			unsigned char *buf;
677			size_t len;
678			int rlen;
679
680			buf = br_ssl_engine_recvrec_buf(cc, &len);
681			rlen = recv(fd, buf, len, 0);
682			if (rlen == 0) {
683				if (verbose) {
684					fprintf(stderr, "socket closed...\n");
685				}
686				retcode = -1;
687				goto engine_exit;
688			}
689			if (rlen < 0) {
690#ifdef _WIN32
691				int err;
692
693				err = WSAGetLastError();
694				if (err == EWOULDBLOCK
695					|| err == WSAEWOULDBLOCK)
696				{
697					can_recv = 0;
698					continue;
699				}
700#else
701				if (errno == EINTR || errno == EWOULDBLOCK) {
702					continue;
703				}
704#endif
705				if (verbose) {
706					fprintf(stderr, "socket broke...\n");
707				}
708				retcode = -1;
709				goto engine_exit;
710			}
711			if (trace) {
712				dump_blob("Incoming bytes", buf, rlen);
713			}
714			br_ssl_engine_recvrec_ack(cc, rlen);
715			continue;
716		}
717		if (sendapp_ok) {
718			unsigned char *buf;
719			size_t len;
720#ifdef _WIN32
721			int rlen;
722#else
723			ssize_t rlen;
724#endif
725
726			buf = br_ssl_engine_sendapp_buf(cc, &len);
727#ifdef _WIN32
728			rlen = in_read_buffered(h_in, &bb, buf, len);
729#else
730			rlen = read(0, buf, len);
731#endif
732			if (rlen <= 0) {
733				if (verbose) {
734					fprintf(stderr, "stdin closed...\n");
735				}
736				br_ssl_engine_close(cc);
737			} else if (!run_command(cc, buf, rlen)) {
738				br_ssl_engine_sendapp_ack(cc, rlen);
739			}
740			br_ssl_engine_flush(cc, 0);
741			continue;
742		}
743
744		/* We should never reach that point. */
745		fprintf(stderr, "ERROR: poll() misbehaves\n");
746		retcode = -2;
747		goto engine_exit;
748	}
749
750	/*
751	 * Release allocated structures.
752	 */
753engine_exit:
754#ifdef _WIN32
755	if (fd_event != WSA_INVALID_EVENT) {
756		WSACloseEvent(fd_event);
757	}
758#endif
759	return retcode;
760}
761