Hello,

I've written some code which basically allows to emulate the behavior of starttls-enabled clients and servers via nc(1). I mainly use it for debugging purposes since it is more generic than openssl s_client -starttls. However, the solution is probably ugly since I'm not very proficient in writing code.

Best regards
Andreas
Index: netcat.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/netcat.c,v
retrieving revision 1.150
diff -u -p -u -r1.150 netcat.c
--- netcat.c	4 Jan 2016 02:18:31 -0000	1.150
+++ netcat.c	4 Jan 2016 15:41:10 -0000
@@ -71,6 +71,7 @@
 #define TLS_NOVERIFY	(1 << 2)
 #define TLS_NONAME	(1 << 3)
 #define TLS_CCERT	(1 << 4)
+#define TLS_STARTTLS	(1 << 5)
 
 /* Command Line Options */
 int	dflag;					/* detached, no stdin */
@@ -95,6 +96,7 @@ int	Oflag;					/* TCP send buffer size *
 int	Sflag;					/* TCP MD5 signature option */
 int	Tflag = -1;				/* IP Type of Service */
 int	rtableid = -1;
+char	*host;
 
 int	usetls;					/* use TLS */
 char    *Cflag;					/* Public cert file */
@@ -110,12 +112,15 @@ uint8_t *privkey;
 size_t  privkeylen;
 uint8_t *pubcert;
 size_t  pubcertlen;
+struct	tls_config *tls_cfg;
 
 int timeout = -1;
 int family = AF_UNSPEC;
 char *portlist[PORT_MAX+1];
 char *unix_dg_tmp_socket;
 
+volatile sig_atomic_t seenint;			/* set when we receive SIGINT */
+
 void	atelnet(int, unsigned char *, unsigned int);
 void	build_ports(char *);
 void	help(void);
@@ -140,12 +145,13 @@ ssize_t drainbuf(int, unsigned char *, s
 ssize_t fillbuf(int, unsigned char *, size_t *, struct tls *);
 void	tls_setup_client(struct tls *, int, char *);
 struct tls *tls_setup_server(struct tls *, int, char *);
+void	onsigint(int);
 
 int
 main(int argc, char *argv[])
 {
 	int ch, s, ret, socksv;
-	char *host, *uport;
+	char *uport;
 	struct addrinfo hints;
 	struct servent *sv;
 	socklen_t len;
@@ -154,9 +160,10 @@ main(int argc, char *argv[])
 	const char *errstr, *proxyhost = "", *proxyport = NULL;
 	struct addrinfo proxyhints;
 	char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
-	struct tls_config *tls_cfg = NULL;
 	struct tls *tls_ctx = NULL;
 
+	seenint = 0;		
+	tls_cfg = NULL;
 	ret = 1;
 	s = 0;
 	socksv = 5;
@@ -474,7 +481,7 @@ main(int argc, char *argv[])
 				s = unix_listen(host);
 		}
 
-		if (usetls) {
+		if (usetls && !(TLSopt & TLS_STARTTLS)) {
 			tls_config_verify_client_optional(tls_cfg);
 			if ((tls_ctx = tls_server()) == NULL)
 				errx(1, "tls server creation failed");
@@ -529,10 +536,16 @@ main(int argc, char *argv[])
 				}
 				if (vflag)
 					report_connect((struct sockaddr *)&cliaddr, len);
-				if ((usetls) &&
-				    (tls_cctx = tls_setup_server(tls_ctx, connfd, host)))
-					readwrite(connfd, tls_cctx);
-				if (!usetls)
+				if (usetls) {
+					if (TLSopt & TLS_STARTTLS) {
+						/* install SIGINT handler which is
+						   the delayed trigger for TLS */
+						(void)signal(SIGINT, onsigint);
+						readwrite(connfd, tls_ctx);
+					}
+					else if (tls_cctx = tls_setup_server(tls_ctx, connfd, host))
+						readwrite(connfd, tls_cctx);
+				} else
 					readwrite(connfd, NULL);
 				if (tls_cctx) {
 					int i;
@@ -580,7 +593,7 @@ main(int argc, char *argv[])
 			if (s)
 				close(s);
 
-			if (usetls) {
+			if (usetls && !(TLSopt & TLS_STARTTLS)) {
 				if ((tls_ctx = tls_client()) == NULL)
 					errx(1, "tls client creation failed");
 				if (tls_configure(tls_ctx, tls_cfg) == -1)
@@ -625,8 +638,14 @@ main(int argc, char *argv[])
 			if (Fflag)
 				fdpass(s);
 			else {
-				if (usetls)
-					tls_setup_client(tls_ctx, s, host);
+				if (usetls) {
+					if (TLSopt & TLS_STARTTLS)
+						/* install SIGINT handler which is
+						   the delayed trigger for TLS */
+						(void)signal(SIGINT, onsigint);
+					else
+						tls_setup_client(tls_ctx, s, host);
+				}
 				if (!zflag)
 					readwrite(s, tls_ctx);
 				if (tls_ctx) {
@@ -1003,6 +1022,37 @@ readwrite(int net_fd, struct tls *tls_ct
 		/* poll */
 		num_fds = poll(pfd, 4, timeout);
 
+		/* received SIGINT triggers TLS handshake */
+		if (seenint) {
+			/* restore default SIGINT handler */
+			(void)signal(SIGINT, SIG_DFL);
+
+			if (tls_ctx != NULL)
+				continue;
+
+			if (lflag) {
+				tls_config_verify_client_optional(tls_cfg);
+				if ((tls_ctx = tls_server()) == NULL)
+					errx(1, "tls server creation failed");
+				if (tls_configure(tls_ctx, tls_cfg) == -1)
+					errx(1, "tls configuration failed (%s)",
+					    tls_error(tls_ctx));
+				if (!(tls_ctx = tls_setup_server(tls_ctx, net_fd,
+					host)))
+					    return;
+			} else {
+				if ((tls_ctx = tls_client()) == NULL)
+					errx(1, "tls client creation failed");
+				if (tls_configure(tls_ctx, tls_cfg) == -1)
+					errx(1, "tls configuration failed (%s)",
+					    tls_error(tls_ctx));
+				tls_setup_client(tls_ctx, net_fd, host);
+			}
+
+			seenint = 0;
+			continue;
+		}
+
 		/* treat poll errors */
 		if (num_fds == -1) {
 			close(net_fd);
@@ -1451,6 +1501,7 @@ map_tls(char *s, int *val)
 		{ "noverify",		TLS_NOVERIFY },
 		{ "noname",		TLS_NONAME },
 		{ "clientcert",		TLS_CCERT},
+		{ "starttls",		TLS_STARTTLS},
 		{ NULL,			-1 },
 	};
 
@@ -1510,6 +1561,12 @@ report_connect(const struct sockaddr *sa
 	fprintf(stderr,
 	    "Connection from %s %s "
 	    "received!\n", remote_host, remote_port);
+}
+
+void
+onsigint(int sig)
+{
+	seenint = 1;
 }
 
 void
Index: nc.1
===================================================================
RCS file: /cvs/src/usr.bin/nc/nc.1,v
retrieving revision 1.71
diff -u -p -u -r1.71 nc.1
--- nc.1	25 Sep 2015 14:56:33 -0000	1.71
+++ nc.1	4 Jan 2016 15:41:10 -0000
@@ -222,9 +222,11 @@ which allows legacy TLS protocols;
 .Ar noverify ,
 which disables certificate verification;
 .Ar noname ,
-which disables certificate name checking; or
+which disables certificate name checking;
 .Ar clientcert ,
-which requires a client certificate on incoming connections.
+which requires a client certificate on incoming connections; or
+.Ar starttls ,
+which delays the use of TLS until a SIGINT (Ctrl-c) has been received.
 It is illegal to specify TLS options if not using TLS.
 .Pp
 For IPv4 TOS value

Reply via email to