Add support for SSL/TLS server certificate validation, enabled by
authorjca <jca@openbsd.org>
Tue, 24 Dec 2013 13:00:59 +0000 (13:00 +0000)
committerjca <jca@openbsd.org>
Tue, 24 Dec 2013 13:00:59 +0000 (13:00 +0000)
default.  See the documentation for the `-S' switch.  This also allows
setting the preferred ciphers for the communication.  Documentation bits
ok'ed by jmc@, ok beck@ sthen@.

usr.bin/ftp/fetch.c
usr.bin/ftp/ftp.1
usr.bin/ftp/ftp_var.h
usr.bin/ftp/main.c

index 752d6f5..b88be00 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: fetch.c,v 1.111 2013/11/13 20:41:10 deraadt Exp $     */
+/*     $OpenBSD: fetch.c,v 1.112 2013/12/24 13:00:59 jca Exp $ */
 /*     $NetBSD: fetch.c,v 1.14 1997/08/18 10:20:20 lukem Exp $ */
 
 /*-
@@ -606,8 +606,27 @@ again:
                SSL_load_error_strings();
                SSLeay_add_ssl_algorithms();
                ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+               if (ssl_ctx == NULL) {
+                       ERR_print_errors_fp(ttyout);
+                       goto cleanup_url_get;
+               }
+               if (ssl_verify) {
+                       if (ssl_ca_file == NULL && ssl_ca_path == NULL)
+                               ssl_ca_file = _PATH_SSL_CAFILE;
+                       if (SSL_CTX_load_verify_locations(ssl_ctx,
+                           ssl_ca_file, ssl_ca_path) != 1) {
+                               ERR_print_errors_fp(ttyout);
+                               goto cleanup_url_get;
+                       }
+                       SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
+                       if (ssl_verify_depth != -1)
+                               SSL_CTX_set_verify_depth(ssl_ctx,
+                                   ssl_verify_depth);
+               }
+               if (ssl_ciphers != NULL)
+                       SSL_CTX_set_cipher_list(ssl_ctx, ssl_ciphers);
                ssl = SSL_new(ssl_ctx);
-               if (ssl == NULL || ssl_ctx == NULL) {
+               if (ssl == NULL) {
                        ERR_print_errors_fp(ttyout);
                        goto cleanup_url_get;
                }
index ab5406b..2cf1b62 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ftp.1,v 1.88 2013/04/28 18:03:40 lteo Exp $
+.\"    $OpenBSD: ftp.1,v 1.89 2013/12/24 13:00:59 jca Exp $
 .\"    $NetBSD: ftp.1,v 1.22 1997/08/18 10:20:22 lukem Exp $
 .\"
 .\" Copyright (c) 1985, 1989, 1990, 1993
@@ -30,7 +30,7 @@
 .\"
 .\"    @(#)ftp.1       8.3 (Berkeley) 10/9/94
 .\"
-.Dd $Mdocdate: April 28 2013 $
+.Dd $Mdocdate: December 24 2013 $
 .Dt FTP 1
 .Os
 .Sh NAME
@@ -59,6 +59,7 @@
 .Op Fl C
 .Op Fl c Ar cookie
 .Op Fl o Ar output
+.Op Fl S Ar ssl_options
 .Op Fl s Ar srcaddr
 .Sm off
 .No http[s]:// Oo Ar user : password No @
@@ -216,6 +217,43 @@ if the server does not support passive connections.
 .It Fl r Ar seconds
 Retry to connect if failed, pausing for number of
 .Ar seconds .
+.It Fl S Ar ssl_options
+SSL/TLS options to use with HTTPS transfers.
+The following settings are available:
+.Bl -tag -width Ds
+.It Cm cafile Ns = Ns Ar /path/to/cert.pem
+PEM encoded file containing CA certificates used for certificate
+validation.
+.It Cm capath Ns = Ns Ar /path/to/certs/
+Directory containing PEM encoded CA certificates used for certificate
+validation.
+Such a directory can be prepared using the c_rehash OpenSSL utility.
+.It Cm ciphers Ns = Ns Ar cipher_list
+Specify the list of ciphers that will be used by
+.Nm .
+See the
+.Xr openssl 1
+.Cm ciphers
+subcommand.
+.It Cm depth Ns = Ns Ar max_depth
+Maximum depth of the certificate chain allowed when performing
+validation.
+.It Cm do
+Perform server certificate validation.
+.It Cm dont
+Don't perform server certificate validation.
+.El
+.Pp
+By default, server certificate validation is performed, and if it fails
+.Nm
+will abort.
+If no
+.Cm cafile
+or
+.Cm capath
+setting is provided,
+.Pa /etc/ssl/cert.pem
+will be used.
 .It Fl s Ar srcaddr
 Use
 .Ar srcaddr
index 3ec6962..f68f547 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ftp_var.h,v 1.32 2012/04/30 13:41:26 haesbaert Exp $  */
+/*     $OpenBSD: ftp_var.h,v 1.33 2013/12/24 13:00:59 jca Exp $        */
 /*     $NetBSD: ftp_var.h,v 1.18 1997/08/18 10:20:25 lukem Exp $       */
 
 /*
@@ -229,3 +229,14 @@ char macbuf[4096];
 FILE   *ttyout;                /* stdout or stderr, depending on interactive */
 
 extern struct cmd cmdtab[];
+
+#ifndef SMALL
+extern char    *ssl_ciphers;
+extern char    *ssl_ca_file;
+extern char    *ssl_ca_path;
+extern int      ssl_verify;
+extern int      ssl_verify_depth;
+# ifndef       _PATH_SSL_CAFILE
+#  define      _PATH_SSL_CAFILE "/etc/ssl/cert.pem"
+# endif
+#endif /* !SMALL */
index 492eb2b..ecaf06a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: main.c,v 1.85 2012/08/26 02:16:02 lteo Exp $  */
+/*     $OpenBSD: main.c,v 1.86 2013/12/24 13:00:59 jca Exp $   */
 /*     $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $  */
 
 /*
@@ -67,6 +67,7 @@
 
 #include <ctype.h>
 #include <err.h>
+#include <limits.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <stdio.h>
 #include "ftp_var.h"
 #include "cmds.h"
 
+#ifndef SMALL
+char * const ssl_verify_opts[] = {
+#define SSL_CAFILE     0
+       "cafile",
+#define SSL_CAPATH     1
+       "capath",
+#define SSL_CIPHERS    2
+       "ciphers",
+#define SSL_DONTVERIFY 3
+       "dont",
+#define SSL_DOVERIFY   4
+       "do",
+#define SSL_VERIFYDEPTH        5
+       "depth",
+       NULL
+};
+char   *ssl_ciphers;
+int     ssl_verify = 1;
+int     ssl_verify_depth = -1;
+char   *ssl_ca_file;
+char   *ssl_ca_path;
+#endif /* !SMALL */
+
 int family = PF_UNSPEC;
 int pipeout;
 
@@ -175,7 +199,8 @@ main(volatile int argc, char *argv[])
        cookiefile = getenv("http_cookies");
 #endif /* !SMALL */
 
-       while ((ch = getopt(argc, argv, "46AaCc:dEegik:mno:pP:r:s:tvV")) != -1) {
+       while ((ch = getopt(argc, argv,
+                   "46AaCc:dEegik:mno:pP:r:S:s:tvV")) != -1) {
                switch (ch) {
                case '4':
                        family = PF_INET;
@@ -276,6 +301,53 @@ main(volatile int argc, char *argv[])
                        }
                        break;
 
+               case 'S':
+#ifndef SMALL
+                       cp = optarg;
+                       while (*cp) {
+                               char    *str;
+                               switch (getsubopt(&cp, ssl_verify_opts, &str)) {
+                               case SSL_CAFILE:
+                                       if (str == NULL)
+                                               errx(1, "missing CA file");
+                                       ssl_ca_file = str;
+                                       break;
+                               case SSL_CAPATH:
+                                       if (str == NULL)
+                                               errx(1, "missing CA directory"
+                                                   " path");
+                                       ssl_ca_path = str;
+                                       break;
+                               case SSL_CIPHERS:
+                                       if (str == NULL)
+                                               errx(1, "missing cipher list");
+                                       ssl_ciphers = str;
+                                       break;
+                               case SSL_DONTVERIFY:
+                                       ssl_verify = 0;
+                                       break;
+                               case SSL_DOVERIFY:
+                                       ssl_verify = 1;
+                                       break;
+                               case SSL_VERIFYDEPTH:
+                                       if (str == NULL)
+                                               errx(1, "missing depth");
+                                       ssl_verify_depth = strtonum(str, 0,
+                                           INT_MAX, &errstr);
+                                       if (errstr)
+                                               errx(1, "certificate "
+                                                   "validation depth is %s",
+                                                   errstr);
+                                       break;
+                               default:
+                                       errx(1, "unknown -S suboption `%s'",
+                                           suboptarg ? suboptarg : "");
+                                       /* NOTREACHED */
+                               }
+                       }
+#endif
+                       break;
+
                case 's':
 #ifndef SMALL
                        srcaddr = optarg;
@@ -775,6 +847,7 @@ usage(void)
 #endif /* !SMALL */
            "[-o output] "
 #ifndef SMALL
+           "[-S ssl_options] "
            "[-s srcaddr]\n"
            "           "
 #endif /* !SMALL */