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