diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2015-09-11 21:07:02 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2015-09-11 21:07:02 +0000 |
commit | a293cb8c92c2fa66da8e9a6c8f5d36444669997c (patch) | |
tree | 938c360e8cefbf3d6345d94e2d100b26346316bc /usr.bin/nc | |
parent | c93d4e666326faa1abb0c23a01d500759685cf8a (diff) |
Add TLS suppport to nc. Provides a useful little test and script tool.
ok jsing@ bluhm@
Diffstat (limited to 'usr.bin/nc')
-rw-r--r-- | usr.bin/nc/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/nc/nc.1 | 51 | ||||
-rw-r--r-- | usr.bin/nc/netcat.c | 336 |
3 files changed, 346 insertions, 45 deletions
diff --git a/usr.bin/nc/Makefile b/usr.bin/nc/Makefile index 150f8295bde..5f20c40cf75 100644 --- a/usr.bin/nc/Makefile +++ b/usr.bin/nc/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.6 2001/09/02 18:45:41 jakob Exp $ +# $OpenBSD: Makefile,v 1.7 2015/09/11 21:07:01 beck Exp $ PROG= nc SRCS= netcat.c atomicio.c socks.c +LDADD+= -ltls -lssl -lcrypto +DPADD+= ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} .include <bsd.prog.mk> diff --git a/usr.bin/nc/nc.1 b/usr.bin/nc/nc.1 index d83cb5ca8d4..8cb96e8734f 100644 --- a/usr.bin/nc/nc.1 +++ b/usr.bin/nc/nc.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: nc.1,v 1.68 2015/03/26 10:35:04 tobias Exp $ +.\" $OpenBSD: nc.1,v 1.69 2015/09/11 21:07:01 beck Exp $ .\" .\" Copyright (c) 1996 David Sacerdote .\" All rights reserved. @@ -25,7 +25,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: March 26 2015 $ +.Dd $Mdocdate: September 11 2015 $ .Dt NC 1 .Os .Sh NAME @@ -41,7 +41,7 @@ .Op Fl P Ar proxy_username .Op Fl p Ar source_port .Op Fl s Ar source -.Op Fl T Ar toskeyword +.Op Fl T Ar keyword .Op Fl V Ar rtable .Op Fl w Ar timeout .Op Fl X Ar proxy_protocol @@ -98,10 +98,18 @@ to use IPv4 addresses only. Forces .Nm to use IPv6 addresses only. +.It Fl C Ar certificate_filename +Specifies the filename from which the public key part of the TLS +certificate is loaded, in PEM format. May only be used with TLS. +.It Fl c +If using a TCP socket to connect or listen, use TLS. Illegal if not using TCP sockets. .It Fl D Enable debugging on the socket. .It Fl d Do not attempt to read from stdin. +.It Fl e Ar name +specify the name that must be present in the peer certificate when using TLS. +Illegal if not using TLS. .It Fl F Pass the first connected socket using .Xr sendmsg 2 @@ -117,6 +125,11 @@ using the .Xr ssh_config 5 .Cm ProxyUseFdpass option). +.It Fl H Ar hash_string +Specifies the required hash string of the peer certificate when using TLS. +The string format required is that used by +.Xr tls_peer_cert_hash 3 . +Illegal if not using TLS, and may not be used with -T noverify. .It Fl h Prints out .Nm @@ -126,6 +139,9 @@ Specifies the size of the TCP receive buffer. .It Fl i Ar interval Specifies a delay time interval between lines of text sent and received. Also causes a delay time between connections to multiple ports. +.It Fl K Ar key_filename +Specifies the filename from which the private key +is loaded in PEM format. May only be used with TLS. .It Fl k Forces .Nm @@ -172,6 +188,11 @@ should use, subject to privilege restrictions and availability. It is an error to use this option in conjunction with the .Fl l option. +.It Fl R Ar CA_filename +Specifies the filename from which the root CA bundle for Certificate +verification is loaded in pem format. Illegal if not using TLS. +Default value is +.Pa /etc/ssl/cert.pem . .It Fl r Specifies that source and/or destination ports should be chosen randomly instead of sequentially within a range or in the order that the system @@ -187,9 +208,22 @@ to create and use so that datagrams can be received. It is an error to use this option in conjunction with the .Fl l option. -.It Fl T Ar toskeyword -Change IPv4 TOS value. -.Ar toskeyword +.It Fl T Ar keyword +Change IPv4 TOS value or TLS options. +For TLS options +.Ar keyword +may be one of +.Ar tlslegacy , +which allows legacy TLS protocols, +.Ar noverify , +which disables certificate verification +.Ar noname , +which disables certificate name checking, or +.Ar clientcert, +which requires a client certificate on incoming connections . +It is illegal to specify TLS options if not using TLS. +For IPv4 TOS value +.Ar keyword may be one of .Ar critical , .Ar inetcontrol , @@ -429,6 +463,11 @@ the source port, with a timeout of 5 seconds: .Pp .Dl $ nc -p 31337 -w 5 host.example.com 42 .Pp +Open a TCP connection to port 443 of www.google.ca, and negotiate +TLS. Check for a different name in the certificate for validation. +.Pp +.Dl $ nc -v -c -e adsf.au.doubleclick.net www.google.ca 443 +.Pp Open a UDP connection to port 53 of host.example.com: .Pp .Dl $ nc -u host.example.com 53 diff --git a/usr.bin/nc/netcat.c b/usr.bin/nc/netcat.c index ce613cd75d8..3909f708171 100644 --- a/usr.bin/nc/netcat.c +++ b/usr.bin/nc/netcat.c @@ -1,6 +1,7 @@ -/* $OpenBSD: netcat.c,v 1.132 2015/09/08 17:28:47 bluhm Exp $ */ +/* $OpenBSD: netcat.c,v 1.133 2015/09/11 21:07:01 beck Exp $ */ /* * Copyright (c) 2001 Eric Jackson <ericj@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,12 @@ #define POLL_NETIN 2 #define POLL_STDOUT 3 #define BUFSIZE 16384 +#define DEFAULT_CA_FILE "/etc/ssl/cert.pem" + +#define TLS_LEGACY (1 << 1) +#define TLS_NOVERIFY (1 << 2) +#define TLS_NONAME (1 << 3) +#define TLS_CCERT (1 << 4) /* Command Line Options */ int dflag; /* detached, no stdin */ @@ -95,6 +103,16 @@ int Sflag; /* TCP MD5 signature option */ 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 tls_cachanged; /* Using non-default CA file */ +int TLSopt; /* TLS options */ +char *tls_expectname; /* required name in peer cert */ +char *tls_peerhash; /* hash of peer cert */ +char *tls_expecthash; /* required hash of peer cert */ + int timeout = -1; int family = AF_UNSPEC; char *portlist[PORT_MAX+1]; @@ -104,7 +122,7 @@ void atelnet(int, unsigned char *, unsigned int); 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); @@ -116,10 +134,14 @@ int unix_connect(char *); int unix_listen(char *); void set_common_sockopts(int, int); int map_tos(char *, int *); +int map_tls(char *, int *); void report_connect(const struct sockaddr *, socklen_t); +void report_tls(struct tls * tls_ctx, char * host, char *tls_expectname); 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 *); +void tls_setup_client(struct tls *, int, char *); +struct tls * tls_setup_server(struct tls *, int, char *); int main(int argc, char *argv[]) @@ -134,6 +156,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 *tls_cfg = NULL; + struct tls *tls_ctx = NULL; ret = 1; s = 0; @@ -145,7 +169,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) { + "46C:cDde:FH:hI:i:K:klNnO:P:p:R:rSs:T:tUuV:vw:X:x:z")) != -1) { switch (ch) { case '4': family = AF_INET; @@ -166,12 +190,24 @@ main(int argc, char *argv[]) else errx(1, "unsupported proxy protocol"); break; + case 'C': + Cflag = optarg; + break; + case 'c': + usetls = 1; + break; case 'd': dflag = 1; break; + case 'e': + tls_expectname = optarg; + break; case 'F': Fflag = 1; break; + case 'H': + tls_expecthash = optarg; + break; case 'h': help(); break; @@ -180,6 +216,9 @@ main(int argc, char *argv[]) if (errstr) errx(1, "interval %s: %s", errstr, optarg); break; + case 'K': + Kflag = optarg; + break; case 'k': kflag = 1; break; @@ -198,6 +237,10 @@ main(int argc, char *argv[]) case 'p': pflag = optarg; break; + case 'R': + tls_cachanged = 1; + Rflag = optarg; + break; case 'r': rflag = 1; break; @@ -256,6 +299,8 @@ main(int argc, char *argv[]) errno = 0; if (map_tos(optarg, &Tflag)) break; + if (map_tls(optarg, &TLSopt)) + break; if (strlen(optarg) > 1 && optarg[0] == '0' && optarg[1] == 'x') Tflag = (int)strtol(optarg, NULL, 16); @@ -263,7 +308,7 @@ main(int argc, char *argv[]) Tflag = (int)strtonum(optarg, 0, 255, &errstr); if (Tflag < 0 || Tflag > 255 || errstr || errno) - errx(1, "illegal tos value %s", optarg); + errx(1, "illegal tos/tls value %s", optarg); break; default: usage(1); @@ -295,6 +340,22 @@ main(int argc, char *argv[]) errx(1, "cannot use -z and -l"); if (!lflag && kflag) errx(1, "must use -l with -k"); + if (uflag && usetls) + errx(1, "cannot use -c and -u"); + if ((family == AF_UNIX) && usetls) + errx(1, "cannot use -c and -U"); + if (TLSopt && !usetls) + errx(1, "you must specify -c to use TLS options"); + if (Cflag && !usetls) + errx(1, "you must specify -c to use -C"); + if (Kflag && !usetls) + errx(1, "you must specify -c to use -K"); + if (tls_cachanged && !usetls) + errx(1, "you must specify -c to use -R"); + if (tls_expecthash && !usetls) + errx(1, "you must specify -c to use -H"); + if (tls_expectname && !usetls) + errx(1, "you must specify -c to use -e"); /* Get name of temporary socket for unix datagram client */ if ((family == AF_UNIX) && uflag && !lflag) { @@ -347,7 +408,34 @@ main(int argc, char *argv[]) proxyhints.ai_flags |= AI_NUMERICHOST; } + if (usetls) { + if (tls_init() == -1) + errx(1, "unable to initialize TLS"); + if ((tls_cfg = tls_config_new()) == NULL) + errx(1, "unable to allocate TLS config"); + if (Cflag && (tls_config_set_cert_file(tls_cfg, Cflag) == -1)) + errx(1, "unable to set TLS certificate file %s", Cflag); + if (Kflag && (tls_config_set_key_file(tls_cfg, Kflag) == -1)) + errx(1, "unable to set TLS key file %s", Kflag); + if (Rflag && (tls_config_set_ca_file(tls_cfg, Rflag) == -1)) + errx(1, "unable to set root CA file %s", Rflag); + if (TLSopt & TLS_LEGACY) { + tls_config_set_protocols(tls_cfg, TLS_PROTOCOLS_ALL); + tls_config_set_ciphers(tls_cfg, "legacy"); + } + if (!lflag && (TLSopt & TLS_CCERT)) + errx(1, "clientcert is only valid with -l"); + if (TLSopt & TLS_NONAME) + tls_config_insecure_noverifyname(tls_cfg); + if (TLSopt & TLS_NOVERIFY) { + if (tls_expecthash != NULL) + errx(1, "-H and -T noverify may not be used" + "together"); + tls_config_insecure_noverifycert(tls_cfg); + } + } if (lflag) { + struct tls *tls_cctx = NULL; int connfd; ret = 0; @@ -358,6 +446,14 @@ main(int argc, char *argv[]) s = unix_listen(host); } + if (usetls) { + 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)); + } /* Allow only one connection at a time, but stay alive. */ for (;;) { if (family != AF_UNIX) @@ -369,7 +465,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,7 +490,7 @@ main(int argc, char *argv[]) if (vflag) report_connect((struct sockaddr *)&z, len); - readwrite(s); + readwrite(s, NULL); } else { len = sizeof(cliaddr); connfd = accept4(s, (struct sockaddr *)&cliaddr, @@ -405,11 +501,23 @@ main(int argc, char *argv[]) } if (vflag) report_connect((struct sockaddr *)&cliaddr, len); - - readwrite(connfd); + if ((usetls) && + (tls_cctx = tls_setup_server(tls_ctx, connfd, + host))) + readwrite(connfd, tls_cctx); + if (!usetls) + readwrite(connfd, NULL); + if (tls_cctx) { + int i; + do { + i = tls_close(tls_cctx); + } while (i == TLS_WANT_POLLIN || + i == TLS_WANT_POLLOUT); + tls_free(tls_cctx); + tls_cctx = NULL; + } close(connfd); } - if (family != AF_UNIX) close(s); else if (uflag) { @@ -424,7 +532,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; @@ -444,6 +552,13 @@ main(int argc, char *argv[]) if (s) close(s); + if (usetls) { + 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)); + } if (xflag) s = socks_connect(host, portlist[i], hints, proxyhost, proxyport, proxyhints, socksv, @@ -481,14 +596,30 @@ main(int argc, char *argv[]) } if (Fflag) fdpass(s); - else if (!zflag) - readwrite(s); + else { + if (usetls) + tls_setup_client(tls_ctx, s, host); + if (!zflag) + readwrite(s, tls_ctx); + if (tls_ctx) { + int j; + do { + j = tls_close(tls_ctx); + } while (j == TLS_WANT_POLLIN || + j == TLS_WANT_POLLOUT); + tls_free(tls_ctx); + tls_ctx = NULL; + } + } } } if (s) close(s); + free(tls_peerhash); + tls_config_free(tls_cfg); + exit(ret); } @@ -524,6 +655,67 @@ unix_bind(char *path) return (s); } +void +tls_setup_client(struct tls *tls_ctx, int s, char *host) + +{ + int i; + if (tls_connect_socket(tls_ctx, s, + tls_expectname ? tls_expectname : host) == -1) { + errx(1, "tls connection failed (%s)", + tls_error(tls_ctx)); + } + do { + if ((i = tls_handshake(tls_ctx)) == -1) + errx(1, "tls handshake failed (%s)", + tls_error(tls_ctx)); + } while (i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); + if (tls_peer_cert_hash(tls_ctx, &tls_peerhash) == -1) + errx(1, "hash of peer certificate failed"); + if (vflag) + report_tls(tls_ctx, host, tls_expectname); + if (tls_expecthash && tls_peerhash && + strcmp(tls_expecthash, tls_peerhash) != 0) + errx(1, "peer certificate is not %s", tls_expecthash); +} +struct tls * +tls_setup_server(struct tls *tls_ctx, int connfd, char *host) +{ + struct tls *tls_cctx; + if (tls_accept_socket(tls_ctx, &tls_cctx, + connfd) == -1) { + warnx("tls accept failed (%s)", + tls_error(tls_ctx)); + tls_cctx = NULL; + } else { + int i; + do { + if ((i = tls_handshake(tls_cctx)) == -1) + warnx("tls handshake failed (%s)", + tls_error(tls_cctx)); + } while(i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); + } + if (tls_cctx) { + int gotcert = tls_peer_cert_provided(tls_cctx); + if (gotcert && tls_peer_cert_hash(tls_cctx, &tls_peerhash) == -1) + warn("hash of peer certificate failed"); + if (vflag && gotcert) + report_tls(tls_cctx, host, tls_expectname); + if ((TLSopt & TLS_CCERT) && !gotcert) + warnx("No client certificate provided"); + else if (gotcert && tls_peerhash && tls_expecthash && + strcmp(tls_expecthash, tls_peerhash) != 0) + warnx("peer certificate is not %s", tls_expecthash); + else if (gotcert && tls_expectname && + (! tls_peer_cert_contains_name(tls_cctx, tls_expectname))) + warnx("name (%s) not found in client cert", + tls_expectname); + else { + return tls_cctx; + } + } + return NULL; +} /* * unix_connect() * Returns a socket connected to a local unix socket. Returns -1 on failure. @@ -731,7 +923,7 @@ local_listen(char *host, char *port, struct addrinfo hints) * Loop that polls on the network file descriptor and stdin. */ void -readwrite(int net_fd) +readwrite(int net_fd, struct tls *tls_ctx) { struct pollfd pfd[4]; int stdin_fd = STDIN_FILENO; @@ -839,9 +1031,12 @@ 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); - /* error or eof on stdin - remove from pfd */ - if (ret == 0 || ret == -1) + &stdinbufpos, NULL); + if (ret == TLS_WANT_POLLIN) + pfd[POLL_STDIN].events = POLLIN; + else if (ret == TLS_WANT_POLLOUT) + pfd[POLL_STDIN].events = POLLOUT; + else if (ret == 0 || ret == -1) pfd[POLL_STDIN].fd = -1; /* read something - poll net out */ if (stdinbufpos > 0) @@ -853,8 +1048,12 @@ 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); - if (ret == -1) + &stdinbufpos, tls_ctx); + if (ret == TLS_WANT_POLLIN) + pfd[POLL_NETOUT].events = POLLIN; + else if (ret == TLS_WANT_POLLOUT) + pfd[POLL_NETOUT].events = POLLOUT; + else if (ret == -1) pfd[POLL_NETOUT].fd = -1; /* buffer empty - remove self from polling */ if (stdinbufpos == 0) @@ -866,8 +1065,12 @@ 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); - if (ret == -1) + &netinbufpos, tls_ctx); + if (ret == TLS_WANT_POLLIN) + pfd[POLL_NETIN].events = POLLIN; + else if (ret == TLS_WANT_POLLOUT) + pfd[POLL_NETIN].events = POLLOUT; + else if (ret == -1) pfd[POLL_NETIN].fd = -1; /* eof on net in - remove from pfd */ if (ret == 0) { @@ -888,8 +1091,12 @@ 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); - if (ret == -1) + &netinbufpos, NULL); + if (ret == TLS_WANT_POLLIN) + pfd[POLL_STDOUT].events = POLLIN; + else if (ret == TLS_WANT_POLLOUT) + pfd[POLL_STDOUT].events = POLLOUT; + else if (ret == -1) pfd[POLL_STDOUT].fd = -1; /* buffer empty - remove self from polling */ if (netinbufpos == 0) @@ -913,15 +1120,19 @@ 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; - n = write(fd, buf, *bufpos); - /* don't treat EAGAIN, EINTR as error */ - if (n == -1 && (errno == EAGAIN || errno == EINTR)) - n = -2; + if (tls) + n = tls_write(tls, buf, *bufpos); + else { + n = write(fd, buf, *bufpos); + /* don't treat EAGAIN, EINTR as error */ + if (n == -1 && (errno == EAGAIN || errno == EINTR)) + n = TLS_WANT_POLLOUT; + } if (n <= 0) return n; /* adjust buffer */ @@ -934,15 +1145,19 @@ drainbuf(int fd, unsigned char *buf, size_t *bufpos) 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; - n = read(fd, buf + *bufpos, num); - /* don't treat EAGAIN, EINTR as error */ - if (n == -1 && (errno == EAGAIN || errno == EINTR)) - n = -2; + if (tls) + n = tls_read(tls, buf + *bufpos, num); + else { + n = read(fd, buf + *bufpos, num); + /* don't treat EAGAIN, EINTR as error */ + if (n == -1 && (errno == EAGAIN || errno == EINTR)) + n = TLS_WANT_POLLIN; + } if (n <= 0) return n; *bufpos += n; @@ -1209,6 +1424,49 @@ map_tos(char *s, int *val) return (0); } +int +map_tls(char *s, int *val) +{ + const struct tlskeywords { + const char *keyword; + int val; + } *t, tlskeywords[] = { + { "tlslegacy", TLS_LEGACY }, + { "noverify", TLS_NOVERIFY }, + { "noname", TLS_NONAME }, + { "clientcert", TLS_CCERT}, + { NULL, -1 }, + }; + + for (t = tlskeywords; t->keyword != NULL; t++) { + if (strcmp(s, t->keyword) == 0) { + *val |= t->val; + return (1); + } + } + return (0); +} + +void +report_tls(struct tls * tls_ctx, char * host, char *tls_expectname) +{ + char *subject = NULL, *issuer = NULL; + if (tls_peer_cert_subject(tls_ctx, &subject) == -1) + errx(1, "unable to get certificate subject"); + if (tls_peer_cert_issuer(tls_ctx, &issuer) == -1) + errx(1, "unable to get certificate issuer"); + fprintf(stderr, "TLS handshake completed with %s\n", host); + fprintf(stderr, "Peer name %s\n", + tls_expectname ? tls_expectname : host); + if (subject) + fprintf(stderr, "Subject: %s\n", subject); + if (issuer) + fprintf(stderr, "Issuer: %s\n", issuer); + if (tls_peerhash) + fprintf(stderr, "Cert Hash: %s\n", tls_peerhash); + free(subject); + free(issuer); +} void report_connect(const struct sockaddr *sa, socklen_t salen) { @@ -1276,10 +1534,12 @@ void usage(int ret) { fprintf(stderr, - "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" - "\t [-P proxy_username] [-p source_port] [-s source] [-T toskeyword]\n" - "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" - "\t [-x proxy_address[:port]] [destination] [port]\n"); + "usage: nc [-46cDdFhklNnrStUuvz] [-C certfile] [-e name] \n" + "\t [-I length] [-i interval] [-H hash] [-K keyfile] [-O length]\n" + "\t [-P proxy_username] [-p source_port] [-R cafile] [-s source]\n" + "\t [-T tls|toskeyword] [-V rtable] [-w timeout]\n" + "\t [-X proxy_protocol] [-x proxy_address[:port]]\n" + "\t [destination] [port]\n"); if (ret) exit(1); } |