Allow TLS ciphers and protocols to be specified for nc(1).
authorjsing <jsing@openbsd.org>
Tue, 28 Nov 2017 16:59:10 +0000 (16:59 +0000)
committerjsing <jsing@openbsd.org>
Tue, 28 Nov 2017 16:59:10 +0000 (16:59 +0000)
Replace the "tlscompat" and "tlsall" options with "cipher" and "protocol"
options that are key/value pairs. This allows the user to specify ciphers
and protocols in a form that are accepted by tls_config_set_ciphers() and
tls_config_set_protocols() respectively.

ok beck@

(also ok jmc@ for a previous revision of the man page).

usr.bin/nc/nc.1
usr.bin/nc/netcat.c

index bb3a8f7..e10d385 100644 (file)
@@ -1,4 +1,4 @@
-.\"     $OpenBSD: nc.1,v 1.87 2017/07/15 18:11:47 jmc Exp $
+.\"     $OpenBSD: nc.1,v 1.88 2017/11/28 16:59:10 jsing 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: July 15 2017 $
+.Dd $Mdocdate: November 28 2017 $
 .Dt NC 1
 .Os
 .Sh NAME
@@ -233,10 +233,6 @@ Change IPv4 TOS value or TLS options.
 For TLS options
 .Ar keyword
 may be one of:
-.Ar tlsall ,
-which allows the use of all supported TLS protocols and ciphers;
-.Ar tlscompat ,
-which allows the use of all supported TLS protocols and "compat" ciphers;
 .Ar noverify ,
 which disables certificate verification;
 .Ar noname ,
@@ -246,6 +242,15 @@ which requires a client certificate on incoming connections; or
 .Ar muststaple ,
 which requires the peer to provide a valid stapled OCSP response
 with the handshake.
+The following TLS options specify a value in the form of a key=value pair:
+.Ar ciphers ,
+which allows the supported TLS ciphers to be specified (see
+.Xr tls_config_set_ciphers 3
+for further details);
+.Ar protocols ,
+which allows the supported TLS protocols to be specified (see
+.Xr tls_config_parse_protocols 3
+for further details).
 It is illegal to specify TLS options if not using TLS.
 .Pp
 For IPv4 TOS value
@@ -497,10 +502,15 @@ 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.example.com, and negotiate TLS with
+any supported TLS protocol version and "compat" ciphers:
+.Pp
+.Dl $ nc -cv -T protocols=all -T ciphers=compat www.example.com 443
+.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.
+Check for a different name in the certificate for validation:
 .Pp
-.Dl $  nc -v -c -e adsf.au.doubleclick.net www.google.ca 443
+.Dl $ nc -cv -e adsf.au.doubleclick.net www.google.ca 443
 .Pp
 Open a UDP connection to port 53 of host.example.com:
 .Pp
index f8bd8fa..867927d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: netcat.c,v 1.188 2017/10/24 17:49:35 bluhm Exp $ */
+/* $OpenBSD: netcat.c,v 1.189 2017/11/28 16:59:10 jsing Exp $ */
 /*
  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
  * Copyright (c) 2015 Bob Beck.  All rights reserved.
 #define BUFSIZE                16384
 #define DEFAULT_CA_FILE        "/etc/ssl/cert.pem"
 
-#define TLS_ALL        (1 << 1)
-#define TLS_NOVERIFY   (1 << 2)
-#define TLS_NONAME     (1 << 3)
-#define TLS_CCERT      (1 << 4)
-#define TLS_MUSTSTAPLE (1 << 5)
-#define TLS_COMPAT     (1 << 6)
+#define TLS_NOVERIFY   (1 << 1)
+#define TLS_NONAME     (1 << 2)
+#define TLS_CCERT      (1 << 3)
+#define TLS_MUSTSTAPLE (1 << 4)
 
 /* Command Line Options */
 int    dflag;                                  /* detached, no stdin */
@@ -108,6 +106,8 @@ int tls_cachanged;                          /* Using non-default CA file */
 int     TLSopt;                                        /* TLS options */
 char   *tls_expectname;                        /* required name in peer cert */
 char   *tls_expecthash;                        /* required hash of peer cert */
+char   *tls_ciphers;                           /* TLS ciphers */
+char   *tls_protocols;                         /* TLS protocols */
 FILE   *Zflag;                                 /* file to save peer cert */
 
 int recvcount, recvlimit;
@@ -135,8 +135,8 @@ int unix_bind(char *, int);
 int    unix_connect(char *);
 int    unix_listen(char *);
 void   set_common_sockopts(int, int);
-int    map_tos(char *, int *);
-int    map_tls(char *, int *);
+int    process_tos_opt(char *, int *);
+int    process_tls_opt(char *, int *);
 void   save_peer_cert(struct tls *_tls_ctx, FILE *_fp);
 void   report_connect(const struct sockaddr *, socklen_t, char *);
 void   report_tls(struct tls *tls_ctx, char * host);
@@ -161,6 +161,7 @@ main(int argc, char *argv[])
        char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
        struct tls_config *tls_cfg = NULL;
        struct tls *tls_ctx = NULL;
+       uint32_t protocols;
 
        ret = 1;
        socksv = 5;
@@ -324,9 +325,9 @@ main(int argc, char *argv[])
                case 'T':
                        errstr = NULL;
                        errno = 0;
-                       if (map_tos(optarg, &Tflag))
+                       if (process_tls_opt(optarg, &TLSopt))
                                break;
-                       if (map_tls(optarg, &TLSopt))
+                       if (process_tos_opt(optarg, &Tflag))
                                break;
                        if (strlen(optarg) > 1 && optarg[0] == '0' &&
                            optarg[1] == 'x')
@@ -402,8 +403,6 @@ main(int argc, char *argv[])
                errx(1, "cannot use -c and -F");
        if (TLSopt && !usetls)
                errx(1, "you must specify -c to use TLS options");
-       if ((TLSopt & (TLS_ALL|TLS_COMPAT)) == (TLS_ALL|TLS_COMPAT))
-               errx(1, "cannot use -T tlsall and -T tlscompat");
        if (Cflag && !usetls)
                errx(1, "you must specify -c to use -C");
        if (Kflag && !usetls)
@@ -497,14 +496,12 @@ main(int argc, char *argv[])
                        errx(1, "%s", tls_config_error(tls_cfg));
                if (oflag && tls_config_set_ocsp_staple_file(tls_cfg, oflag) == -1)
                        errx(1, "%s", tls_config_error(tls_cfg));
-               if (TLSopt & (TLS_ALL|TLS_COMPAT)) {
-                       if (tls_config_set_protocols(tls_cfg,
-                           TLS_PROTOCOLS_ALL) != 0)
-                               errx(1, "%s", tls_config_error(tls_cfg));
-                       if (tls_config_set_ciphers(tls_cfg,
-                           (TLSopt & TLS_ALL) ? "all" : "compat") != 0)
-                               errx(1, "%s", tls_config_error(tls_cfg));
-               }
+               if (tls_config_parse_protocols(&protocols, tls_protocols) == -1)
+                       errx(1, "invalid TLS protocols `%s'", tls_protocols);
+               if (tls_config_set_protocols(tls_cfg, protocols) == -1)
+                       errx(1, "%s", tls_config_error(tls_cfg));
+               if (tls_config_set_ciphers(tls_cfg, tls_ciphers) == -1)
+                       errx(1, "%s", tls_config_error(tls_cfg));
                if (!lflag && (TLSopt & TLS_CCERT))
                        errx(1, "clientcert is only valid with -l");
                if (TLSopt & TLS_NONAME)
@@ -1509,7 +1506,7 @@ set_common_sockopts(int s, int af)
 }
 
 int
-map_tos(char *s, int *val)
+process_tos_opt(char *s, int *val)
 {
        /* DiffServ Codepoints and other TOS mappings */
        const struct toskeywords {
@@ -1557,24 +1554,41 @@ map_tos(char *s, int *val)
 }
 
 int
-map_tls(char *s, int *val)
+process_tls_opt(char *s, int *flags)
 {
+       size_t len;
+       char *v;
+
        const struct tlskeywords {
                const char      *keyword;
-               int              val;
+               int              flag;
+               char            **value;
        } *t, tlskeywords[] = {
-               { "tlsall",             TLS_ALL },
-               { "noverify",           TLS_NOVERIFY },
-               { "noname",             TLS_NONAME },
-               { "clientcert",         TLS_CCERT},
-               { "muststaple",         TLS_MUSTSTAPLE},
-               { "tlscompat",          TLS_COMPAT },
-               { NULL,                 -1 },
+               { "ciphers",            -1,                     &tls_ciphers },
+               { "clientcert",         TLS_CCERT,              NULL },
+               { "muststaple",         TLS_MUSTSTAPLE,         NULL },
+               { "noverify",           TLS_NOVERIFY,           NULL },
+               { "noname",             TLS_NONAME,             NULL },
+               { "protocols",          -1,                     &tls_protocols },
+               { NULL,                 -1,                     NULL },
        };
 
+       len = strlen(s);
+       if ((v = strchr(s, '=')) != NULL) {
+               len = v - s;
+               v++;
+       }
+
        for (t = tlskeywords; t->keyword != NULL; t++) {
-               if (strcmp(s, t->keyword) == 0) {
-                       *val |= t->val;
+               if (strlen(t->keyword) == len &&
+                   strncmp(s, t->keyword, len) == 0) {
+                       if (t->value != NULL) {
+                               if (v == NULL)
+                                       errx(1, "invalid tls value `%s'", s);
+                               *t->value = v;
+                       } else {
+                               *flags |= t->flag;
+                       }
                        return 1;
                }
        }