From 4be470b4a09962192ad69156f16628dc4cf12ac3 Mon Sep 17 00:00:00 2001 From: jca Date: Tue, 24 Dec 2013 13:00:59 +0000 Subject: [PATCH] Add support for SSL/TLS server certificate validation, enabled by 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 | 23 +++++++++++-- usr.bin/ftp/ftp.1 | 42 +++++++++++++++++++++-- usr.bin/ftp/ftp_var.h | 13 +++++++- usr.bin/ftp/main.c | 77 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 148 insertions(+), 7 deletions(-) diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c index 752d6f55663..b88be007762 100644 --- a/usr.bin/ftp/fetch.c +++ b/usr.bin/ftp/fetch.c @@ -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; } diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1 index ab5406b2e1f..2cf1b625d0f 100644 --- a/usr.bin/ftp/ftp.1 +++ b/usr.bin/ftp/ftp.1 @@ -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 diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h index 3ec69627b67..f68f547bf9a 100644 --- a/usr.bin/ftp/ftp_var.h +++ b/usr.bin/ftp/ftp_var.h @@ -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 */ diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c index 492eb2bfc9c..ecaf06adca8 100644 --- a/usr.bin/ftp/main.c +++ b/usr.bin/ftp/main.c @@ -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 #include +#include #include #include #include @@ -78,6 +79,29 @@ #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 */ -- 2.20.1