I doodled this into netcat last night, because I got tired of typing openssl 
s_client                       
and s_server when testing things.. Still scripts nicely.                        
                            
                                                                                
                            
-Bob                                                                            
                            
        
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.bin/nc/Makefile,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 Makefile
--- Makefile    2 Sep 2001 18:45:41 -0000       1.6
+++ Makefile    5 Sep 2015 16:03:45 -0000
@@ -2,5 +2,7 @@
 
 PROG=  nc
 SRCS=  netcat.c atomicio.c socks.c
+LDADD+= -ltls -lssl -lcrypto
+DPADD+=  ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
 
 .include <bsd.prog.mk>
Index: nc.1
===================================================================
RCS file: /cvs/src/usr.bin/nc/nc.1,v
retrieving revision 1.68
diff -u -p -u -p -r1.68 nc.1
--- nc.1        26 Mar 2015 10:35:04 -0000      1.68
+++ nc.1        5 Sep 2015 16:03:45 -0000
@@ -102,6 +102,17 @@ to use IPv6 addresses only.
 Enable debugging on the socket.
 .It Fl d
 Do not attempt to read from stdin.
+.It Fl c
+If using a tcp socket to connect or listen, use TLS.  This option
+takes optional numeric argument that can be used to make the TLS
+connection less secure. specifying 1 disables certificate validity
+verification, specifying 2 disables the verification of the
+certificate name against the hostname, and 3 disables all certificate
+verification.
+.It Fl C Ar certificate_filename
+Specifies the filename from which the public part of the TLS
+certificate is loaded, in pem format. Has no effect when TLS is not
+used.
 .It Fl F
 Pass the first connected socket using
 .Xr sendmsg 2
@@ -132,6 +143,9 @@ Forces
 to stay listening for another connection after its current connection
 is completed.
 It is an error to use this option without the
+.It Fl K Ar key_filename
+Specifies the filename from which the private key for the TLS certificate
+is loaded in pem format. Has no effect when TLS is not used.
 .Fl l
 option.
 When used together with the
@@ -176,6 +190,11 @@ option.
 Specifies that source and/or destination ports should be chosen randomly
 instead of sequentially within a range or in the order that the system
 assigns them.
+.It Fl R Ar CA_filename
+Specifies the filename from which the root CA bundle for Certificate 
+verification is loaded in pem format. Has no effect when TLS is not used.
+Default value is 
+.Pa /etc/ssl/cert.pem .
 .It Fl S
 Enables the RFC 2385 TCP MD5 signature option.
 .It Fl s Ar source
Index: netcat.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/netcat.c,v
retrieving revision 1.129
diff -u -p -u -p -r1.129 netcat.c
--- netcat.c    26 Mar 2015 21:22:50 -0000      1.129
+++ netcat.c    5 Sep 2015 16:03:45 -0000
@@ -1,6 +1,7 @@
 /* $OpenBSD: netcat.c,v 1.129 2015/03/26 21:22:50 tobias Exp $ */
 /*
  * Copyright (c) 2001 Eric Jackson <er...@monkey.org>
+ * Copyright (c) 2015 Bob Beck.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -54,6 +55,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <tls.h>
 #include "atomicio.h"
 
 #ifndef SUN_LEN
@@ -70,6 +72,7 @@
 #define POLL_NETIN 2
 #define POLL_STDOUT 3
 #define BUFSIZE 16384
+#define DEFAULT_CA_FILE "/etc/ssl/cert.pem"
 
 /* Command Line Options */
 int    dflag;                                  /* detached, no stdin */
@@ -95,6 +98,12 @@ int  Sflag;                                  /* TCP MD5 
signature opti
 int    Tflag = -1;                             /* IP Type of Service */
 int    rtableid = -1;
 
+int    usetls;                                 /* use TLS */
+char    *Cflag;                                        /* Public cert file */
+char    *Kflag;                                        /* Private key file */
+char    *Rflag = DEFAULT_CA_FILE;              /* Root CA file */
+int     insecure;                              /* Insecure Mode */
+
 int timeout = -1;
 int family = AF_UNSPEC;
 char *portlist[PORT_MAX+1];
@@ -104,7 +113,7 @@ void        atelnet(int, unsigned char *, unsig
 void   build_ports(char *);
 void   help(void);
 int    local_listen(char *, char *, struct addrinfo);
-void   readwrite(int);
+void   readwrite(int, struct tls *);
 void   fdpass(int nfd) __attribute__((noreturn));
 int    remote_connect(const char *, const char *, struct addrinfo);
 int    timeout_connect(int, const struct sockaddr *, socklen_t);
@@ -118,8 +127,8 @@ void        set_common_sockopts(int, int);
 int    map_tos(char *, int *);
 void   report_connect(const struct sockaddr *, socklen_t);
 void   usage(int);
-ssize_t drainbuf(int, unsigned char *, size_t *);
-ssize_t fillbuf(int, unsigned char *, size_t *);
+ssize_t drainbuf(int, unsigned char *, size_t *, struct tls *);
+ssize_t fillbuf(int, unsigned char *, size_t *, struct tls *);
 
 int
 main(int argc, char *argv[])
@@ -134,6 +143,8 @@ 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 *tlsc = NULL;
+       struct tls *ctx = NULL;
 
        ret = 1;
        s = 0;
@@ -145,7 +156,7 @@ main(int argc, char *argv[])
        signal(SIGPIPE, SIG_IGN);
 
        while ((ch = getopt(argc, argv,
-           "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
+           "46Dc::C:dFhI:i:kK:lNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
                switch (ch) {
                case '4':
                        family = AF_INET;
@@ -166,6 +177,14 @@ main(int argc, char *argv[])
                        else
                                errx(1, "unsupported proxy protocol");
                        break;
+               case 'c':
+                       usetls = 1;
+                       if (optarg != NULL) {
+                               insecure = strtonum(optarg, 0, 3, &errstr);
+                               if (errstr)
+                                       errx(1, "insecure %s: %s", errstr, 
optarg);
+                       }
+                       break;
                case 'd':
                        dflag = 1;
                        break;
@@ -183,6 +202,9 @@ main(int argc, char *argv[])
                case 'k':
                        kflag = 1;
                        break;
+               case 'K':
+                       Kflag = optarg;
+                       break;
                case 'l':
                        lflag = 1;
                        break;
@@ -195,12 +217,18 @@ main(int argc, char *argv[])
                case 'P':
                        Pflag = optarg;
                        break;
+               case 'C':
+                       Cflag = optarg;
+                       break;
                case 'p':
                        pflag = optarg;
                        break;
                case 'r':
                        rflag = 1;
                        break;
+               case 'R':
+                       Rflag = optarg;
+                       break;
                case 's':
                        sflag = optarg;
                        break;
@@ -347,6 +375,33 @@ main(int argc, char *argv[])
                        proxyhints.ai_flags |= AI_NUMERICHOST;
        }
 
+       if (usetls) {
+               if (tls_init() == -1)
+                       errx(1, "unable to initialize tls");
+               if ((tlsc = tls_config_new()) == NULL)
+                       errx(1, "unable allocate tls config");
+               if (Cflag && (tls_config_set_cert_file(tlsc, Cflag) == -1))
+                       errx(1, "unable to set TLS certificate file %s", Cflag);
+               if (Kflag && (tls_config_set_key_file(tlsc, Kflag) == -1))
+                       errx(1, "unable to set TLS key file %s", Kflag);
+               if (Rflag && (tls_config_set_ca_file(tlsc, Rflag) == -1))
+                       errx(1, "unable to set Root CA file %s", Rflag);
+               switch (insecure) {
+               case 1:
+                       tls_config_insecure_noverifyname(tlsc);
+                       break;
+               case 2:
+                       tls_config_insecure_noverifycert(tlsc);
+                       break;
+               case 3:
+                       tls_config_insecure_noverifyname(tlsc);
+                       tls_config_insecure_noverifycert(tlsc);
+                       break;
+               default:
+                       break;
+               }
+       }
+
        if (lflag) {
                int connfd;
                ret = 0;
@@ -369,7 +424,7 @@ main(int argc, char *argv[])
                         * receive datagrams from multiple socket pairs.
                         */
                        if (uflag && kflag)
-                               readwrite(s);
+                               readwrite(s, NULL);
                        /*
                         * For UDP and not -k, we will use recvfrom() initially
                         * to wait for a caller, then use the regular functions
@@ -394,8 +449,9 @@ main(int argc, char *argv[])
                                if (vflag)
                                        report_connect((struct sockaddr *)&z, 
len);
 
-                               readwrite(s);
+                               readwrite(s, NULL);
                        } else {
+                               struct tls *cctx = NULL;
                                len = sizeof(cliaddr);
                                connfd = accept(s, (struct sockaddr *)&cliaddr,
                                    &len);
@@ -405,11 +461,44 @@ main(int argc, char *argv[])
                                }
                                if (vflag)
                                        report_connect((struct sockaddr 
*)&cliaddr, len);
-
-                               readwrite(connfd);
+                               if (usetls) {
+                                       int i;
+                                       if ((ctx = tls_server()) == NULL)
+                                               errx(1, "tls client creation 
failed");
+                                       if (tls_configure(ctx, tlsc) == -1)
+                                               errx(1, "tls configuration 
failed (%s)",
+                                                   tls_error(ctx));
+                                       do {
+                                               i = tls_accept_socket(ctx, 
&cctx, connfd);
+                                               if (i == -1) {
+                                                       warn ("tls connection 
failed (%s)",
+                                                           tls_error(ctx));
+                                                       cctx = NULL;
+                                               }
+                                       } while (i == TLS_READ_AGAIN || i == 
TLS_WRITE_AGAIN);
+                               }
+                               if (usetls && cctx)
+                                       readwrite(connfd, cctx);
+                               if (!usetls)
+                                       readwrite(connfd, NULL);
+                               if (ctx) {
+                                       int i;
+                                       do {
+                                               i = tls_close(ctx);
+                                       } while (i == TLS_READ_AGAIN || i == 
TLS_WRITE_AGAIN);
+                                       tls_free(ctx);
+                                       ctx = NULL;
+                               }
+                               if (cctx) {
+                                       int i;
+                                       do {
+                                               i = tls_close(cctx);
+                                       } while (i == TLS_READ_AGAIN || i == 
TLS_WRITE_AGAIN);
+                                       tls_free(cctx);
+                                       cctx = NULL;
+                               }
                                close(connfd);
                        }
-
                        if (family != AF_UNIX)
                                close(s);
                        else if (uflag) {
@@ -424,7 +513,7 @@ main(int argc, char *argv[])
                ret = 0;
 
                if ((s = unix_connect(host)) > 0 && !zflag) {
-                       readwrite(s);
+                       readwrite(s, NULL);
                        close(s);
                } else
                        ret = 1;
@@ -481,14 +570,34 @@ main(int argc, char *argv[])
                        }
                        if (Fflag)
                                fdpass(s);
-                       else if (!zflag)
-                               readwrite(s);
+                       else {
+                               if (usetls) {
+                                       if ((ctx = tls_client()) == NULL)
+                                               errx(1, "tls client creation 
failed");
+                                       if (tls_configure(ctx, tlsc) == -1)
+                                               errx(1, "tls configuration 
failed");
+                                       if (tls_connect_socket(ctx, s, host) == 
-1)
+                                               errx(1, "tls connection failed 
(%s)", tls_error(ctx));
+                               }
+                               if (!zflag)
+                                       readwrite(s, ctx);
+                               if (ctx) {
+                                       int i;
+                                       do {
+                                               i = tls_close(ctx);
+                                       } while (i == TLS_READ_AGAIN || i == 
TLS_WRITE_AGAIN);
+                                       tls_free(ctx);
+                                       ctx = NULL;
+                               }
+                       }
                }
        }
 
        if (s)
                close(s);
 
+       tls_config_free(tlsc);
+
        exit(ret);
 }
 
@@ -608,7 +717,7 @@ remote_connect(const char *host, const c
 
                        /* try SO_BINDANY, but don't insist */
                        setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on));
-                       memset(&ahints, 0, sizeof(struct addrinfo));
+                       memset(&ahints, 0, sizeof(struct addrinfo));
                        ahints.ai_family = res0->ai_family;
                        ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
                        ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
@@ -740,7 +849,7 @@ local_listen(char *host, char *port, str
  * Loop that polls on the network file descriptor and stdin.
  */
 void
-readwrite(int net_fd)
+readwrite(int net_fd, struct tls *ctx)
 {
        struct pollfd pfd[4];
        int stdin_fd = STDIN_FILENO;
@@ -772,6 +881,7 @@ readwrite(int net_fd)
        pfd[POLL_STDOUT].fd = stdout_fd;
        pfd[POLL_STDOUT].events = 0;
 
+
        while (1) {
                /* both inputs are gone, buffers are empty, we are done */
                if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1
@@ -848,7 +958,7 @@ readwrite(int net_fd)
                /* try to read from stdin */
                if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
                        ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
-                           &stdinbufpos);
+                           &stdinbufpos, NULL);
                        /* error or eof on stdin - remove from pfd */
                        if (ret == 0 || ret == -1)
                                pfd[POLL_STDIN].fd = -1;
@@ -862,7 +972,7 @@ readwrite(int net_fd)
                /* try to write to network */
                if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
                        ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
-                           &stdinbufpos);
+                           &stdinbufpos, ctx);
                        if (ret == -1)
                                pfd[POLL_NETOUT].fd = -1;
                        /* buffer empty - remove self from polling */
@@ -875,7 +985,7 @@ readwrite(int net_fd)
                /* try to read from network */
                if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
                        ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
-                           &netinbufpos);
+                           &netinbufpos, ctx);
                        if (ret == -1)
                                pfd[POLL_NETIN].fd = -1;
                        /* eof on net in - remove from pfd */
@@ -897,7 +1007,7 @@ readwrite(int net_fd)
                /* try to write to stdout */
                if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
                        ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
-                           &netinbufpos);
+                           &netinbufpos, NULL);
                        if (ret == -1)
                                pfd[POLL_STDOUT].fd = -1;
                        /* buffer empty - remove self from polling */
@@ -922,17 +1032,27 @@ readwrite(int net_fd)
 }
 
 ssize_t
-drainbuf(int fd, unsigned char *buf, size_t *bufpos)
+drainbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
 {
        ssize_t n;
        ssize_t adjust;
+       size_t t;
 
-       n = write(fd, buf, *bufpos);
-       /* don't treat EAGAIN, EINTR as error */
-       if (n == -1 && (errno == EAGAIN || errno == EINTR))
-               n = -2;
-       if (n <= 0)
-               return n;
+       if (tls) {
+               n = tls_write(tls, buf, *bufpos, &t);
+               if (n == TLS_READ_AGAIN || n == TLS_WRITE_AGAIN)
+                       n = -2;
+               if (n < 0)
+                       return n;
+               n = t;
+       } else {
+               n = write(fd, buf, *bufpos);
+               /* don't treat EAGAIN, EINTR as error */
+               if (n == -1 && (errno == EAGAIN || errno == EINTR))
+                       n = -2;
+               if (n <= 0)
+                       return n;
+       }
        /* adjust buffer */
        adjust = *bufpos - n;
        if (adjust > 0)
@@ -943,17 +1063,27 @@ drainbuf(int fd, unsigned char *buf, siz
 
 
 ssize_t
-fillbuf(int fd, unsigned char *buf, size_t *bufpos)
+fillbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
 {
        size_t num = BUFSIZE - *bufpos;
        ssize_t n;
+       size_t t;
 
-       n = read(fd, buf + *bufpos, num);
-       /* don't treat EAGAIN, EINTR as error */
-       if (n == -1 && (errno == EAGAIN || errno == EINTR))
-               n = -2;
-       if (n <= 0)
-               return n;
+       if (tls) {
+               n = tls_read(tls, buf + *bufpos, num, &t);
+               if (n == TLS_READ_AGAIN || n == TLS_WRITE_AGAIN)
+                       n = -2;
+               if (n < 0)
+                       return n;
+               n = t;
+       } else {
+               n = read(fd, buf + *bufpos, num);
+               /* don't treat EAGAIN, EINTR as error */
+               if (n == -1 && (errno == EAGAIN || errno == EINTR))
+                       n = -2;
+               if (n <= 0)
+                       return n;
+       }
        *bufpos += n;
        return n;
 }

Reply via email to