From 655845108ca221b709c435b004a3cf8f2b3d78fd Mon Sep 17 00:00:00 2001 From: Stephen Kent Date: Thu, 18 Aug 2016 10:26:41 -0700 Subject: [PATCH] Add an option to provide a CA cert for server certificate verification Enable this option with -C/--cacert --- cmdline.c | 18 ++++++++++++++++-- cmdline.h | 2 ++ docs/proxytunnel.1.adoc | 5 +++++ ptstream.c | 20 ++++++++++++++++++-- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/cmdline.c b/cmdline.c index 9d15e57..518d216 100644 --- a/cmdline.c +++ b/cmdline.c @@ -66,6 +66,7 @@ void cmdline_parser_print_help (void) { "Additional options for specific features:\n" #ifdef USE_SSL " -z, --no-check-certficate Don't verify server SSL certificate\n" +" -C, --cacert=STRING Path to trusted CA certificate or directory\n" #endif " -F, --passfile=STRING File with credentials for proxy authentication\n" " -P, --proxyauth=STRING Proxy auth credentials user:pass combination\n" @@ -140,6 +141,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->proctitle_given = 0; args_info->enforcetls1_given = 0; args_info->host_given = 0; + args_info->cacert_given = 0; /* No... we can't make this a function... -- Maniac */ #define clear_args() \ @@ -169,6 +171,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->enforcetls1_flag = 0; \ args_info->host_arg = NULL; \ args_info->no_check_cert_flag = 0; \ + args_info->cacert_arg = NULL; \ } clear_args(); @@ -214,12 +217,13 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar { "encrypt-remproxy",0,NULL, 'X' }, { "no-ssl3", 0, NULL, 'T' }, { "no-check-certificate",0,NULL,'z' }, + { "cacert", 1, NULL, 'C' }, { NULL, 0, NULL, 0 } }; - c = getopt_long (argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXqLo:Tz", long_options, &option_index); + c = getopt_long (argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXqLo:TzC:", long_options, &option_index); #else - c = getopt( argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXqLo:Tz" ); + c = getopt( argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXqLo:TzC:" ); #endif if (c == -1) @@ -442,6 +446,16 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar message("Server SSL certificate verification disabled\n"); break; + case 'C': /* Trusted CA certificate (or directory) for server SSL certificate verification */ + if (args_info->cacert_given) { + fprintf (stderr, "%s: `--cacert' (`-C') option given more than once\n", PACKAGE); + clear_args (); + exit(1); + } + args_info->cacert_given = 1; + args_info->cacert_arg = gengetopt_strdup (optarg); + break; + case 0: /* Long option with no short option */ case '?': /* Invalid option. */ diff --git a/cmdline.h b/cmdline.h index c1eef43..cd85191 100644 --- a/cmdline.h +++ b/cmdline.h @@ -52,6 +52,7 @@ struct gengetopt_args_info { int enforcetls1_flag; /* Override default and enforce TLSv1 */ char *host_arg; /* Optional Host Header */ int no_check_cert_flag; /* Turn off server SSL certificate verification (default=on) */ + char *cacert_arg; /* Trusted CA certificate (or directory) for server SSL certificate verification */ int help_given; /* Whether help was given. */ int version_given; /* Whether version was given. */ int user_given; /* Whether user was given. */ @@ -77,6 +78,7 @@ struct gengetopt_args_info { int proctitle_given; /* Whether to override process title */ int enforcetls1_given; /* Wheter to enforce TLSv1 */ int host_given; /* Wheter we override the Host Header */ + int cacert_given; /* Whether cacert was given */ }; int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *args_info ); diff --git a/docs/proxytunnel.1.adoc b/docs/proxytunnel.1.adoc index 6740412..a884207 100644 --- a/docs/proxytunnel.1.adoc +++ b/docs/proxytunnel.1.adoc @@ -58,6 +58,11 @@ also be used for other proxy-traversing purposes like proxy bouncing. is checked against the server certificate's subject alternative names if any are present, or common name if there are no subject alternative names. +*-C*, *--cacert*=_filename/directory_:: + Specify a CA certificate file (or directory containing CA certificate(s)) + to trust when verifying a server SSL certificate. If a directory is provided, + it must be prepared with OpenSSL's c_rehash tool. (default: /etc/ssl/certs) + *-F*, *--passfile*=_filename_:: Use _filename_ for reading username and password for HTTPS proxy authentication, the file uses the same format as .wgetrc and can be shared diff --git a/ptstream.c b/ptstream.c index 491c562..88d9e1f 100644 --- a/ptstream.c +++ b/ptstream.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "proxytunnel.h" @@ -241,6 +242,9 @@ int stream_enable_ssl(PTSTREAM *pts, const char *proxy_arg) { long ssl_options = 0; X509* cert = NULL; + int status; + struct stat st_buf; + const char *ca_file = NULL; const char *ca_dir = "/etc/ssl/certs/"; /* Default cert directory if none given */ long vresult; char *peer_host = NULL; @@ -263,8 +267,20 @@ int stream_enable_ssl(PTSTREAM *pts, const char *proxy_arg) { SSL_CTX_set_options (ctx, ssl_options); if ( !args_info.no_check_cert_flag ) { - if (!SSL_CTX_load_verify_locations(ctx, NULL, ca_dir)) { - message("Error loading certificates from %s\n", ca_dir); + if ( args_info.cacert_given ) { + if ((status = stat(args_info.cacert_arg, &st_buf)) != 0) { + message("Error reading certificate path %s\n", args_info.cacert_arg); + goto fail; + } + if (S_ISDIR(st_buf.st_mode)) { + ca_dir = args_info.cacert_arg; + } else { + ca_dir = NULL; + ca_file = args_info.cacert_arg; + } + } + if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_dir)) { + message("Error loading certificate(s) from %s\n", args_info.cacert_arg); goto fail; } }