ftp(1) SSL/TLS server certificate validation

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

ftp(1) SSL/TLS server certificate validation

Jeremie Courreges-Anglas-2

All the code is under #ifndef SMALL, except for the getopt(3) goo; I saw
no size increase in the on-disk file, and build-checked that the
ramdisks still fit on i386.

Validation error messages straight from OpenSSL.

ok?

Index: fetch.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/fetch.c,v
retrieving revision 1.111
diff -u -p -r1.111 fetch.c
--- fetch.c 13 Nov 2013 20:41:10 -0000 1.111
+++ fetch.c 19 Dec 2013 23:25:41 -0000
@@ -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: ftp.1
===================================================================
RCS file: /cvs/src/usr.bin/ftp/ftp.1,v
retrieving revision 1.88
diff -u -p -r1.88 ftp.1
--- ftp.1 28 Apr 2013 18:03:40 -0000 1.88
+++ ftp.1 19 Dec 2013 23:41:16 -0000
@@ -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 c
 .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: ftp_var.h
===================================================================
RCS file: /cvs/src/usr.bin/ftp/ftp_var.h,v
retrieving revision 1.32
diff -u -p -r1.32 ftp_var.h
--- ftp_var.h 30 Apr 2012 13:41:26 -0000 1.32
+++ ftp_var.h 17 Dec 2013 10:59:48 -0000
@@ -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: main.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/main.c,v
retrieving revision 1.85
diff -u -p -r1.85 main.c
--- main.c 26 Aug 2012 02:16:02 -0000 1.85
+++ main.c 19 Dec 2013 23:49:50 -0000
@@ -67,6 +67,7 @@
 
 #include <ctype.h>
 #include <err.h>
+#include <limits.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <stdio.h>
@@ -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 */


--
jca | PGP: 0x06A11494 / 61DB D9A0 00A4 67CF 2A90  8961 6191 8FBF 06A1 1494