diff options
author | Alberto Gonzalez Iniesta <agi@inittab.org> | 2014-04-16 17:32:08 +0200 |
---|---|---|
committer | Alberto Gonzalez Iniesta <agi@inittab.org> | 2014-04-16 17:32:08 +0200 |
commit | 0af7f64094c65cba7ee45bd2679e6826bcf598cb (patch) | |
tree | 43702d27f33b48a461e3f84d1931b89aa3070d4f /src | |
parent | 70b71e008cc968ee53d6b8af9f7a006f13c27e2a (diff) |
Imported Upstream version 2.3.3upstream/2.3.3
Diffstat (limited to 'src')
-rw-r--r-- | src/openvpn/buffer.c | 29 | ||||
-rw-r--r-- | src/openvpn/init.c | 4 | ||||
-rw-r--r-- | src/openvpn/misc.c | 27 | ||||
-rw-r--r-- | src/openvpn/openvpn.c | 2 | ||||
-rw-r--r-- | src/openvpn/options.c | 206 | ||||
-rw-r--r-- | src/openvpn/options.h | 3 | ||||
-rw-r--r-- | src/openvpn/pkcs11_openssl.c | 14 | ||||
-rw-r--r-- | src/openvpn/plugin.c | 5 | ||||
-rw-r--r-- | src/openvpn/push.c | 4 | ||||
-rw-r--r-- | src/openvpn/route.c | 131 | ||||
-rw-r--r-- | src/openvpn/route.h | 10 | ||||
-rw-r--r-- | src/openvpn/socket.c | 14 | ||||
-rw-r--r-- | src/openvpn/ssl.c | 69 | ||||
-rw-r--r-- | src/openvpn/ssl_backend.h | 66 | ||||
-rw-r--r-- | src/openvpn/ssl_common.h | 4 | ||||
-rw-r--r-- | src/openvpn/ssl_openssl.c | 143 | ||||
-rw-r--r-- | src/openvpn/ssl_openssl.h | 12 | ||||
-rw-r--r-- | src/openvpn/ssl_polarssl.c | 242 | ||||
-rw-r--r-- | src/openvpn/ssl_polarssl.h | 5 | ||||
-rw-r--r-- | src/openvpn/ssl_verify.c | 2 | ||||
-rw-r--r-- | src/openvpn/syshead.h | 2 | ||||
-rw-r--r-- | src/openvpn/tun.c | 361 | ||||
-rw-r--r-- | src/openvpn/tun.h | 3 | ||||
-rw-r--r-- | src/openvpn/win32.c | 34 |
24 files changed, 1013 insertions, 379 deletions
diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 56d14b1..fb3b52d 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -327,19 +327,28 @@ gc_malloc (size_t size, bool clear, struct gc_arena *a) #endif { void *ret; - struct gc_entry *e; - ASSERT (NULL != a); - + if (a) + { + struct gc_entry *e; #ifdef DMALLOC - e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry)); + e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry)); #else - e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry)); + e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry)); #endif - check_malloc_return (e); - ret = (char *) e + sizeof (struct gc_entry); - e->next = a->list; - a->list = e; - + check_malloc_return (e); + ret = (char *) e + sizeof (struct gc_entry); + e->next = a->list; + a->list = e; + } + else + { +#ifdef DMALLOC + ret = openvpn_dmalloc (file, line, size); +#else + ret = malloc (size); +#endif + check_malloc_return (ret); + } #ifndef ZERO_BUFFER_ON_ALLOC if (clear) #endif diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 2420216..52d370b 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -866,7 +866,7 @@ print_openssl_info (const struct options *options) show_available_engines (); #ifdef ENABLE_SSL if (options->show_tls_ciphers) - show_available_tls_ciphers (); + show_available_tls_ciphers (options->cipher_list); #endif return true; } @@ -2973,7 +2973,7 @@ do_close_ifconfig_pool_persist (struct context *c) static void do_inherit_env (struct context *c, const struct env_set *src) { - c->c2.es = env_set_create (&c->c2.gc); + c->c2.es = env_set_create (NULL); c->c2.es_owned = true; env_set_inherit (c->c2.es, src); } diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index fa327f8..56a01a6 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -934,32 +934,23 @@ create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc } /* - * Add a random string to first DNS label of hostname to prevent DNS caching. + * Prepend a random string to hostname to prevent DNS caching. * For example, foo.bar.gov would be modified to <random-chars>.foo.bar.gov. - * Of course, this requires explicit support in the DNS server. + * Of course, this requires explicit support in the DNS server (wildcard). */ const char * hostname_randomize(const char *hostname, struct gc_arena *gc) { # define n_rnd_bytes 6 - char *hst = string_alloc(hostname, gc); - char *dot = strchr(hst, '.'); + uint8_t rnd_bytes[n_rnd_bytes]; + const char *rnd_str; + struct buffer hname = alloc_buf_gc (strlen(hostname)+sizeof(rnd_bytes)*2+4, gc); - if (dot) - { - uint8_t rnd_bytes[n_rnd_bytes]; - const char *rnd_str; - struct buffer hname = alloc_buf_gc (strlen(hostname)+sizeof(rnd_bytes)*2+4, gc); - - *dot++ = '\0'; - prng_bytes (rnd_bytes, sizeof (rnd_bytes)); - rnd_str = format_hex_ex (rnd_bytes, sizeof (rnd_bytes), 40, 0, NULL, gc); - buf_printf(&hname, "%s-0x%s.%s", hst, rnd_str, dot); - return BSTR(&hname); - } - else - return hostname; + prng_bytes (rnd_bytes, sizeof (rnd_bytes)); + rnd_str = format_hex_ex (rnd_bytes, sizeof (rnd_bytes), 40, 0, NULL, gc); + buf_printf(&hname, "%s.%s", rnd_str, hostname); + return BSTR(&hname); # undef n_rnd_bytes } diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 104c9e9..5125eae 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -171,7 +171,7 @@ openvpn_main (int argc, char *argv[]) gc_init (&c.gc); /* initialize environmental variable store */ - c.es = env_set_create (&c.gc); + c.es = env_set_create (NULL); #ifdef WIN32 set_win_sys_path_via_env (c.es); #endif diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 23af272..7741dbf 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5,10 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> - * - * Additions for eurephia plugin done by: - * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2009 + * Copyright (C) 2002-2013 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -100,9 +98,6 @@ const char title_string[] = #ifdef ENABLE_PKCS11 " [PKCS11]" #endif -#ifdef ENABLE_EUREPHIA - " [eurephia]" -#endif #if ENABLE_IP_PKTINFO " [MH]" #endif @@ -248,6 +243,8 @@ static const char usage_message[] = "--setenv name value : Set a custom environmental variable to pass to script.\n" "--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n" " directives for future OpenVPN versions to be ignored.\n" + "--ignore-unkown-option opt1 opt2 ...: Relax config file syntax. Allow\n" + " these options to be ignored when unknown\n" "--script-security level: Where level can be:\n" " 0 -- strictly no calling of external programs\n" " 1 -- (default) only call built-ins such as ifconfig\n" @@ -572,6 +569,9 @@ static const char usage_message[] = " by a Certificate Authority in --ca file.\n" "--extra-certs file : one or more PEM certs that complete the cert chain.\n" "--key file : Local private key in .pem format.\n" + "--tls-version-min <version> ['or-highest'] : sets the minimum TLS version we\n" + " will accept from the peer. If version is unrecognized and 'or-highest'\n" + " is specified, require max TLS version supported by SSL implementation.\n" #ifndef ENABLE_CRYPTO_POLARSSL "--pkcs12 file : PKCS#12 file containing local private key, local certificate\n" " and optionally the root CA certificate.\n" @@ -1979,6 +1979,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #ifdef ENABLE_HTTP_PROXY if ((ce->http_proxy_options) && ce->proto != PROTO_TCPv4_CLIENT) msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)"); + if ((ce->http_proxy_options) && !ce->http_proxy_options->server) + msg (M_USAGE, "--http-proxy not specified but other http proxy options present"); #endif #if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_SOCKS) @@ -2603,6 +2605,44 @@ check_file_access(const int type, const char *file, const int mode, const char * return (errcode != 0 ? true : false); } +/* A wrapper for check_file_access() which also takes a chroot directory. + * If chroot is NULL, behaviour is exactly the same as calling check_file_access() directly, + * otherwise it will look for the file inside the given chroot directory instead. + */ +static bool +check_file_access_chroot(const char *chroot, const int type, const char *file, const int mode, const char *opt) +{ + bool ret = false; + + /* If no file configured, no errors to look for */ + if (!file) + return false; + + /* If chroot is set, look for the file/directory inside the chroot */ + if( chroot ) + { + struct gc_arena gc = gc_new(); + struct buffer chroot_file; + int len = 0; + + /* Build up a new full path including chroot directory */ + len = strlen(chroot) + strlen(PATH_SEPARATOR_STR) + strlen(file) + 1; + chroot_file = alloc_buf_gc(len, &gc); + buf_printf(&chroot_file, "%s%s%s", chroot, PATH_SEPARATOR_STR, file); + ASSERT (chroot_file.len > 0); + + ret = check_file_access(type, BSTR(&chroot_file), mode, opt); + gc_free(&gc); + } + else + { + /* No chroot in play, just call core file check function */ + ret = check_file_access(type, file, mode, opt); + } + return ret; +} + + /* * Verifies that the path in the "command" that comes after certain script options (e.g., --up) is a * valid file with appropriate permissions. @@ -2620,7 +2660,7 @@ check_file_access(const int type, const char *file, const int mode, const char * * check_file_access() arguments. */ static bool -check_cmd_access(const char *command, const char *opt) +check_cmd_access(const char *command, const char *opt, const char *chroot) { struct argv argv; bool return_code; @@ -2639,7 +2679,7 @@ check_cmd_access(const char *command, const char *opt) * only requires X_OK to function on Unix - a scenario not unlikely to * be seen on suid binaries. */ - return_code = check_file_access(CHKACC_FILE, argv.argv[0], X_OK, opt); + return_code = check_file_access_chroot(chroot, CHKACC_FILE, argv.argv[0], X_OK, opt); else { msg (M_NOPREFIX|M_OPTERR, "%s fails with '%s': No path to executable.", @@ -2665,7 +2705,7 @@ options_postprocess_filechecks (struct options *options) #ifdef ENABLE_SSL errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->dh_file, R_OK, "--dh"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->ca_file, R_OK, "--ca"); - errs |= check_file_access (CHKACC_FILE, options->ca_path, R_OK, "--capath"); + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->ca_path, R_OK, "--capath"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->cert_file, R_OK, "--cert"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK, "--extra-certs"); @@ -2678,10 +2718,10 @@ options_postprocess_filechecks (struct options *options) "--pkcs12"); if (options->ssl_flags & SSLF_CRL_VERIFY_DIR) - errs |= check_file_access (CHKACC_FILE, options->crl_file, R_OK|X_OK, + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK|X_OK, "--crl-verify directory"); else - errs |= check_file_access (CHKACC_FILE, options->crl_file, R_OK, + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK, "--crl-verify"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->tls_auth_file, R_OK, @@ -2723,13 +2763,13 @@ options_postprocess_filechecks (struct options *options) /* ** Config related ** */ #ifdef ENABLE_SSL - errs |= check_file_access (CHKACC_FILE, options->tls_export_cert, + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tls_export_cert, R_OK|W_OK|X_OK, "--tls-export-cert"); #endif /* ENABLE_SSL */ #if P2MP_SERVER - errs |= check_file_access (CHKACC_FILE, options->client_config_dir, + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->client_config_dir, R_OK|X_OK, "--client-config-dir"); - errs |= check_file_access (CHKACC_FILE, options->tmp_dir, + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tmp_dir, R_OK|W_OK|X_OK, "Temporary directory (--tmp-dir)"); #endif /* P2MP_SERVER */ @@ -2829,6 +2869,7 @@ pre_pull_restore (struct options *o) } o->push_continuation = 0; + o->push_option_types_found = 0; } #endif @@ -3806,7 +3847,7 @@ read_config_string (const char *prefix, { bypass_doubledash (&p[0]); check_inline_file_via_buf (&multiline, p, &options->gc); - add_option (options, p, NULL, line_num, 0, msglevel, permission_mask, option_types_found, es); + add_option (options, p, prefix, line_num, 0, msglevel, permission_mask, option_types_found, es); } CLEAR (p); } @@ -3926,27 +3967,43 @@ void options_string_import (struct options *options, #if P2MP -#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, (mask), permission_mask, option_types_found, msglevel)) goto err; } +#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, line, (mask), permission_mask, option_types_found, msglevel, options)) goto err; } static bool verify_permission (const char *name, const char* file, + int line, const unsigned int type, const unsigned int allowed, unsigned int *found, - const int msglevel) + const int msglevel, + struct options* options) { if (!(type & allowed)) { msg (msglevel, "option '%s' cannot be used in this context (%s)", name, file); return false; } - else + + if (found) + *found |= type; + +#ifndef ENABLE_SMALL + /* Check if this options is allowed in connection block, + * but we are currently not in a connection block + * Parsing a connection block uses a temporary options struct without + * connection_list + */ + + if ((type & OPT_P_CONNECTION) && options->connection_list) { - if (found) - *found |= type; - return true; + if (file) + msg (M_WARN, "Option '%s' in %s:%d is ignored by previous <connection> blocks ", name, file, line); + else + msg (M_WARN, "Option '%s' is ignored by previous <connection> blocks", name); } +#endif + return true; } #else @@ -3996,7 +4053,8 @@ static void set_user_script (struct options *options, const char **script, const char *new_script, - const char *type) + const char *type, + bool in_chroot) { if (*script) { msg (M_WARN, "Multiple --%s scripts defined. " @@ -4011,8 +4069,9 @@ set_user_script (struct options *options, openvpn_snprintf (script_name, sizeof(script_name), "--%s script", type); - if (check_cmd_access (*script, script_name)) + if (check_cmd_access (*script, script_name, (in_chroot ? options->chroot_dir : NULL))) msg (M_USAGE, "Please correct this error."); + } #endif } @@ -4033,7 +4092,18 @@ add_option (struct options *options, const bool pull_mode = BOOL_CAST (permission_mask & OPT_P_PULL_MODE); int msglevel_fc = msglevel_forward_compatible (options, msglevel); - ASSERT (MAX_PARMS >= 5); + ASSERT (MAX_PARMS >= 7); + + /* + * If directive begins with "setenv opt" prefix, don't raise an error if + * directive is unrecognized. + */ + if (streq (p[0], "setenv") && p[1] && streq (p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE)) + { + p += 2; + msglevel_fc = M_WARN; + } + if (!file) { file = "[CMD-LINE]"; @@ -4394,6 +4464,43 @@ add_option (struct options *options, uninit_options (&sub); } } + else if (streq (p[0], "ignore-unknown-option") && p[1]) + { + int i; + int j; + int numignored=0; + const char **ignore; + + VERIFY_PERMISSION (OPT_P_GENERAL); + /* Find out how many options to be ignored */ + for (i=1;p[i];i++) + numignored++; + + /* add number of options already ignored */ + for (i=0;options->ignore_unknown_option && + options->ignore_unknown_option[i]; i++) + numignored++; + + /* Allocate array */ + ALLOC_ARRAY_GC (ignore, const char*, numignored+1, &options->gc); + for (i=0;options->ignore_unknown_option && + options->ignore_unknown_option[i]; i++) + ignore[i]=options->ignore_unknown_option[i]; + + options->ignore_unknown_option=ignore; + + for (j=1;p[j];j++) + { + /* Allow the user to specify ignore-unknown-option --opt too */ + if (p[j][0]=='-' && p[j][1]=='-') + options->ignore_unknown_option[i] = (p[j]+2); + else + options->ignore_unknown_option[i] = p[j]; + i++; + } + + options->ignore_unknown_option[i] = NULL; + } else if (streq (p[0], "remote-ip-hint") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -4482,7 +4589,7 @@ add_option (struct options *options, set_user_script (options, &options->ipchange, string_substitute (p[1], ',', ' ', &options->gc), - "ipchange"); + "ipchange", true); } else if (streq (p[0], "float")) { @@ -4528,14 +4635,14 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - set_user_script (options, &options->up_script, p[1], "up"); + set_user_script (options, &options->up_script, p[1], "up", false); } else if (streq (p[0], "down") && p[1]) { VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - set_user_script (options, &options->down_script, p[1], "down"); + set_user_script (options, &options->down_script, p[1], "down", true); } else if (streq (p[0], "down-pre")) { @@ -5216,7 +5323,7 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - set_user_script (options, &options->route_script, p[1], "route-up"); + set_user_script (options, &options->route_script, p[1], "route-up", false); } else if (streq (p[0], "route-pre-down") && p[1]) { @@ -5226,7 +5333,7 @@ add_option (struct options *options, set_user_script (options, &options->route_predown_script, p[1], - "route-pre-down"); + "route-pre-down", true); } else if (streq (p[0], "route-noexec")) { @@ -5595,7 +5702,7 @@ add_option (struct options *options, } set_user_script (options, &options->auth_user_pass_verify_script, - p[1], "auth-user-pass-verify"); + p[1], "auth-user-pass-verify", true); } else if (streq (p[0], "client-connect") && p[1]) { @@ -5603,7 +5710,7 @@ add_option (struct options *options, if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; set_user_script (options, &options->client_connect_script, - p[1], "client-connect"); + p[1], "client-connect", true); } else if (streq (p[0], "client-disconnect") && p[1]) { @@ -5611,7 +5718,7 @@ add_option (struct options *options, if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; set_user_script (options, &options->client_disconnect_script, - p[1], "client-disconnect"); + p[1], "client-disconnect", true); } else if (streq (p[0], "learn-address") && p[1]) { @@ -5619,7 +5726,7 @@ add_option (struct options *options, if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; set_user_script (options, &options->learn_address_script, - p[1], "learn-address"); + p[1], "learn-address", true); } else if (streq (p[0], "tmp-dir") && p[1]) { @@ -6438,6 +6545,19 @@ add_option (struct options *options, options->priv_key_file_inline = p[2]; } } + else if (streq (p[0], "tls-version-min") && p[1]) + { + int ver; + VERIFY_PERMISSION (OPT_P_GENERAL); + ver = tls_version_min_parse(p[1], p[2]); + if (ver == TLS_VER_BAD) + { + msg (msglevel, "unknown tls-version-min parameter: %s", p[1]); + goto err; + } + options->ssl_flags &= ~(SSLF_TLS_VERSION_MASK << SSLF_TLS_VERSION_SHIFT); + options->ssl_flags |= (ver << SSLF_TLS_VERSION_SHIFT); + } #ifndef ENABLE_CRYPTO_POLARSSL else if (streq (p[0], "pkcs12") && p[1]) { @@ -6509,7 +6629,7 @@ add_option (struct options *options, goto err; set_user_script (options, &options->tls_verify, string_substitute (p[1], ',', ' ', &options->gc), - "tls-verify"); + "tls-verify", true); } #ifndef ENABLE_CRYPTO_POLARSSL else if (streq (p[0], "tls-export-cert") && p[1]) @@ -6823,10 +6943,22 @@ add_option (struct options *options, #endif else { + int i; + int msglevel= msglevel_fc; + /* Check if an option is in --ignore-unknown-option and + set warning level to non fatal */ + for(i=0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++) + { + if (streq(p[0], options->ignore_unknown_option[i])) + { + msglevel = M_WARN; + break; + } + } if (file) - msg (msglevel_fc, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION); + msg (msglevel, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION); else - msg (msglevel_fc, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION); + msg (msglevel, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION); } err: gc_free (&gc); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index f80532c..8cbb85a 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -186,6 +186,8 @@ struct options /* enable forward compatibility for post-2.1 features */ bool forward_compatible; + /* list of options that should be ignored even if unkown */ + const char ** ignore_unknown_option; /* persist parms */ bool persist_config; @@ -458,6 +460,7 @@ struct options bool client; bool pull; /* client pull of config options from server */ int push_continuation; + unsigned int push_option_types_found; const char *auth_user_pass_file; struct options_pre_pull *pre_pull; diff --git a/src/openvpn/pkcs11_openssl.c b/src/openvpn/pkcs11_openssl.c index af843b7..87eb166 100644 --- a/src/openvpn/pkcs11_openssl.c +++ b/src/openvpn/pkcs11_openssl.c @@ -49,7 +49,7 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, int ret = 1; X509 *x509 = NULL; - RSA *rsa = NULL; + EVP_PKEY *evp = NULL; pkcs11h_openssl_session_t openssl_session = NULL; if ((openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL) @@ -63,9 +63,9 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, */ certificate = NULL; - if ((rsa = pkcs11h_openssl_session_getRSA (openssl_session)) == NULL) + if ((evp = pkcs11h_openssl_session_getEVP (openssl_session)) == NULL) { - msg (M_WARN, "PKCS#11: Unable get rsa object"); + msg (M_WARN, "PKCS#11: Unable get evp object"); goto cleanup; } @@ -75,7 +75,7 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, goto cleanup; } - if (!SSL_CTX_use_RSAPrivateKey (ssl_ctx->ctx, rsa)) + if (!SSL_CTX_use_PrivateKey (ssl_ctx->ctx, evp)) { msg (M_WARN, "PKCS#11: Cannot set private key for openssl"); goto cleanup; @@ -108,10 +108,10 @@ cleanup: x509 = NULL; } - if (rsa != NULL) + if (evp != NULL) { - RSA_free (rsa); - rsa = NULL; + EVP_PKEY_free (evp); + evp = NULL; } if (openssl_session != NULL) diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index c96c121..0948f23 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -40,8 +40,8 @@ #include "error.h" #include "misc.h" #include "plugin.h" +#include "ssl_backend.h" #include "win32.h" - #include "memdbg.h" #define PLUGIN_SYMBOL_REQUIRED (1<<0) @@ -374,7 +374,8 @@ plugin_open_item (struct plugin *p, struct openvpn_plugin_args_open_in args = { p->plugin_type_mask, (const char ** const) o->argv, (const char ** const) envp, - &callbacks }; + &callbacks, + SSLAPI }; struct openvpn_plugin_args_open_return retargs; CLEAR(retargs); diff --git a/src/openvpn/push.c b/src/openvpn/push.c index be50bef..11505cb 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -202,8 +202,10 @@ incoming_push_message (struct context *c, const struct buffer *buffer) msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) { + c->options.push_option_types_found |= option_types_found; + if (status == PUSH_MSG_REPLY) - do_up (c, true, option_types_found); /* delay bringing tun/tap up until --push parms received from remote */ + do_up (c, true, c->options.push_option_types_found ); /* delay bringing tun/tap up until --push parms received from remote */ event_timeout_clear (&c->c2.push_request_interval); } diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 044e6ac..6333ee7 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -49,7 +49,7 @@ #define METRIC_NOT_USED ((DWORD)-1) #endif -static void delete_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es); +static void delete_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es); static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags); @@ -150,7 +150,7 @@ struct route_list * new_route_list (const int max_routes, struct gc_arena *a) { struct route_list *ret; - ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route, max_routes, a); + ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route_ipv4, max_routes, a); ret->capacity = max_routes; return ret; } @@ -165,7 +165,7 @@ new_route_ipv6_list (const int max_routes, struct gc_arena *a) } static const char * -route_string (const struct route *r, struct gc_arena *gc) +route_string (const struct route_ipv4 *r, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (256, gc); buf_printf (&out, "ROUTE network %s netmask %s gateway %s", @@ -267,7 +267,7 @@ is_special_addr (const char *addr_str) } static bool -init_route (struct route *r, +init_route (struct route_ipv4 *r, struct addrinfo **network_list, const struct route_option *ro, const struct route_list *rl) @@ -484,7 +484,7 @@ void clear_route_list (struct route_list *rl) { const int capacity = rl->capacity; - const size_t rl_size = array_mult_safe (sizeof(struct route), capacity, sizeof(struct route_list)); + const size_t rl_size = array_mult_safe (sizeof(struct route_ipv4), capacity, sizeof(struct route_list)); memset(rl, 0, rl_size); rl->capacity = capacity; } @@ -519,7 +519,7 @@ add_block_local_item (struct route_list *rl, && rl->rgi.gateway.netmask < 0xFFFFFFFF && (rl->n)+2 <= rl->capacity) { - struct route r; + struct route_ipv4 r; unsigned int l2; /* split a route into two smaller blocking routes, and direct them to target */ @@ -649,7 +649,7 @@ init_route_list (struct route_list *rl, for (i = 0; i < opt->n; ++i) { struct addrinfo* netlist; - struct route r; + struct route_ipv4 r; if (!init_route (&r, &netlist, @@ -760,7 +760,7 @@ add_route3 (in_addr_t network, const struct route_gateway_info *rgi, const struct env_set *es) { - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED; r.network = network; @@ -778,7 +778,7 @@ del_route3 (in_addr_t network, const struct route_gateway_info *rgi, const struct env_set *es) { - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED|RT_ADDED; r.network = network; @@ -1028,7 +1028,7 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun for (i = 0; i < rl->n; ++i) { - struct route *r = &rl->routes[i]; + struct route_ipv4 *r = &rl->routes[i]; check_subnet_conflict (r->network, r->netmask, "route"); if (flags & ROUTE_DELETE_FIRST) delete_route (r, tt, flags, &rl->rgi, es); @@ -1060,7 +1060,7 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6, int i; for (i = rl->n - 1; i >= 0; --i) { - struct route * r = &rl->routes[i]; + struct route_ipv4 * r = &rl->routes[i]; delete_route (r, tt, flags, &rl->rgi, es); } rl->iflags &= ~RL_ROUTES_ADDED; @@ -1154,7 +1154,7 @@ print_default_gateway(const int msglevel, const struct route_gateway_info *rgi) #endif static void -print_route (const struct route *r, int level) +print_route (const struct route_ipv4 *r, int level) { struct gc_arena gc = gc_new (); if (r->flags & RT_DEFINED) @@ -1171,7 +1171,7 @@ print_routes (const struct route_list *rl, int level) } static void -setenv_route (struct env_set *es, const struct route *r, int i) +setenv_route (struct env_set *es, const struct route_ipv4 *r, int i) { struct gc_arena gc = gc_new (); if (r->flags & RT_DEFINED) @@ -1288,7 +1288,7 @@ is_on_link (const int is_local_route, const unsigned int flags, const struct rou } void -add_route (struct route *r, +add_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, /* may be NULL */ @@ -1728,7 +1728,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla } static void -delete_route (struct route *r, +delete_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, @@ -2232,7 +2232,7 @@ get_default_gateway (struct route_gateway_info *rgi) } static DWORD -windows_route_find_if_index (const struct route *r, const struct tuntap *tt) +windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt) { struct gc_arena gc = gc_new (); DWORD ret = TUN_ADAPTER_INDEX_INVALID; @@ -2277,7 +2277,7 @@ windows_route_find_if_index (const struct route *r, const struct tuntap *tt) } bool -add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index) +add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index) { struct gc_arena gc = gc_new (); bool ret = false; @@ -2351,7 +2351,7 @@ add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_i } bool -del_route_ipapi (const struct route *r, const struct tuntap *tt) +del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt) { struct gc_arena gc = gc_new (); bool ret = false; @@ -2597,53 +2597,7 @@ get_default_gateway (struct route_gateway_info *rgi) #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> - -/* all of this is taken from <net/route.h> in FreeBSD */ -#define RTA_DST 0x1 -#define RTA_GATEWAY 0x2 -#define RTA_NETMASK 0x4 - -#define RTM_GET 0x4 -#define RTM_VERSION 5 - -#define RTF_UP 0x1 -#define RTF_GATEWAY 0x2 - -/* - * These numbers are used by reliable protocols for determining - * retransmission behavior and are included in the routing structure. - */ -struct rt_metrics { - u_long rmx_locks; /* Kernel must leave these values alone */ - u_long rmx_mtu; /* MTU for this path */ - u_long rmx_hopcount; /* max hops expected */ - u_long rmx_expire; /* lifetime for route, e.g. redirect */ - u_long rmx_recvpipe; /* inbound delay-bandwidth product */ - u_long rmx_sendpipe; /* outbound delay-bandwidth product */ - u_long rmx_ssthresh; /* outbound gateway buffer limit */ - u_long rmx_rtt; /* estimated round trip time */ - u_long rmx_rttvar; /* estimated rtt variance */ - u_long rmx_pksent; /* packets sent using this route */ - u_long rmx_filler[4]; /* will be used for T/TCP later */ -}; - -/* - * Structures for routing messages. - */ -struct rt_msghdr { - u_short rtm_msglen; /* to skip over non-understood messages */ - u_char rtm_version; /* future binary compatibility */ - u_char rtm_type; /* message type */ - u_short rtm_index; /* index for associated ifp */ - int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ - int rtm_addrs; /* bitmask identifying sockaddrs in msg */ - pid_t rtm_pid; /* identify sender */ - int rtm_seq; /* for sender to identify action */ - int rtm_errno; /* why failed */ - int rtm_use; /* from rtentry */ - u_long rtm_inits; /* which metrics we are initializing */ - struct rt_metrics rtm_rmx; /* metrics themselves */ -}; +#include <net/route.h> struct { struct rt_msghdr m_rtm; @@ -2963,52 +2917,7 @@ get_default_gateway (struct route_gateway_info *rgi) #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> - -/* all of this is taken from <net/route.h> in OpenBSD 3.6 */ -#define RTA_DST 0x1 /* destination sockaddr present */ -#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ -#define RTA_NETMASK 0x4 /* netmask sockaddr present */ - -#define RTM_GET 0x4 /* Report Metrics */ - -#define RTM_VERSION 3 /* Up the ante and ignore older versions */ - -#define RTF_UP 0x1 /* route usable */ -#define RTF_GATEWAY 0x2 /* destination is a gateway */ - -/* - * Huge version for userland compatibility. - */ -struct rt_metrics { - u_long rmx_locks; /* Kernel must leave these values alone */ - u_long rmx_mtu; /* MTU for this path */ - u_long rmx_hopcount; /* max hops expected */ - u_long rmx_expire; /* lifetime for route, e.g. redirect */ - u_long rmx_recvpipe; /* inbound delay-bandwidth product */ - u_long rmx_sendpipe; /* outbound delay-bandwidth product */ - u_long rmx_ssthresh; /* outbound gateway buffer limit */ - u_long rmx_rtt; /* estimated round trip time */ - u_long rmx_rttvar; /* estimated rtt variance */ - u_long rmx_pksent; /* packets sent using this route */ -}; - -/* - * Structures for routing messages. - */ -struct rt_msghdr { - u_short rtm_msglen; /* to skip over non-understood messages */ - u_char rtm_version; /* future binary compatibility */ - u_char rtm_type; /* message type */ - u_short rtm_index; /* index for associated ifp */ - int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ - int rtm_addrs; /* bitmask identifying sockaddrs in msg */ - pid_t rtm_pid; /* identify sender */ - int rtm_seq; /* for sender to identify action */ - int rtm_errno; /* why failed */ - int rtm_use; /* from rtentry */ - u_long rtm_inits; /* which metrics we are initializing */ - struct rt_metrics rtm_rmx; /* metrics themselves */ -}; +#include <net/route.h> struct { struct rt_msghdr m_rtm; diff --git a/src/openvpn/route.h b/src/openvpn/route.h index a40de32..fe9b461 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -110,7 +110,7 @@ struct route_ipv6_option_list { struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE]; }; -struct route { +struct route_ipv4 { # define RT_DEFINED (1<<0) # define RT_ADDED (1<<1) # define RT_METRIC_DEFINED (1<<2) @@ -190,7 +190,7 @@ struct route_list { unsigned int flags; /* RG_x flags */ int capacity; int n; - struct route routes[EMPTY_ARRAY_SIZE]; + struct route_ipv4 routes[EMPTY_ARRAY_SIZE]; }; #if P2MP @@ -223,7 +223,7 @@ struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_are void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); -void add_route (struct route *r, +void add_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, @@ -301,8 +301,8 @@ void print_routes (const struct route_list *rl, int level); void show_routes (int msglev); bool test_routes (const struct route_list *rl, const struct tuntap *tt); -bool add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index); -bool del_route_ipapi (const struct route *r, const struct tuntap *tt); +bool add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index); +bool del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt); #else static inline bool test_routes (const struct route_list *rl, const struct tuntap *tt) { return true; } diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 85f783a..708903c 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -208,18 +208,20 @@ openvpn_getaddrinfo (unsigned int flags, get_signal (signal_received); if (*signal_received) /* were we interrupted by a signal? */ { - if (0 == status) { - ASSERT(res); - freeaddrinfo(*res); - res = NULL; - } if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ { msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); *signal_received = 0; } else - goto done; + { + if (0 == status) { + ASSERT(res); + freeaddrinfo(*res); + res = NULL; + } + goto done; + } } } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 8b864c8..800fcba 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -7,10 +7,7 @@ * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> - * - * Additions for eurephia plugin done by: - * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2008-2009 - * + * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -141,8 +138,6 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { {"DHE-DSS-CAMELLIA128-SHA", "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA"}, {"DHE-DSS-CAMELLIA256-SHA256", "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256"}, {"DHE-DSS-CAMELLIA256-SHA", "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA"}, - {"DHE-DSS-DES-CBC3-SHA", "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA"}, - {"DHE-DSS-DES-CBC-SHA", "TLS-DHE-DSS-WITH-DES-CBC-SHA"}, {"DHE-DSS-SEED-SHA", "TLS-DHE-DSS-WITH-SEED-CBC-SHA"}, {"DHE-RSA-AES128-GCM-SHA256", "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256"}, {"DHE-RSA-AES128-SHA256", "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256"}, @@ -154,8 +149,6 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { {"DHE-RSA-CAMELLIA128-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA"}, {"DHE-RSA-CAMELLIA256-SHA256", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"}, {"DHE-RSA-CAMELLIA256-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA"}, - {"DHE-RSA-DES-CBC3-SHA", "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA"}, - {"DHE-RSA-DES-CBC-SHA", "TLS-DHE-RSA-WITH-DES-CBC-SHA"}, {"DHE-RSA-SEED-SHA", "TLS-DHE-RSA-WITH-SEED-CBC-SHA"}, {"DH-RSA-SEED-SHA", "TLS-DH-RSA-WITH-SEED-CBC-SHA"}, {"ECDH-ECDSA-AES128-GCM-SHA256", "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256"}, @@ -242,6 +235,19 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { {"SRP-RSA-3DES-EDE-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-3DES-EDE-CBC-SHA"}, {"SRP-RSA-AES-128-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-128-CBC-SHA"}, {"SRP-RSA-AES-256-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-256-CBC-SHA"}, +#ifdef ENABLE_CRYPTO_OPENSSL + {"DEFAULT", "DEFAULT"}, + {"ALL", "ALL"}, + {"HIGH", "HIGH"}, + {"MEDIUM", "MEDIUM"}, + {"LOW", "LOW"}, + {"ECDH", "ECDH"}, + {"ECDSA", "ECDSA"}, + {"EDH", "EDH"}, + {"EXP", "EXP"}, + {"RSA", "RSA"}, + {"SRP", "SRP"}, +#endif {NULL, NULL} }; @@ -447,6 +453,27 @@ ssl_put_auth_challenge (const char *cr_str) #endif /* + * Parse a TLS version string, returning a TLS_VER_x constant. + * If version string is not recognized and extra == "or-highest", + * return tls_version_max(). + */ +int +tls_version_min_parse(const char *vstr, const char *extra) +{ + const int max_version = tls_version_max(); + if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version) + return TLS_VER_1_0; + else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version) + return TLS_VER_1_1; + else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version) + return TLS_VER_1_2; + else if (extra && !strcmp(extra, "or-highest")) + return max_version; + else + return TLS_VER_BAD; +} + +/* * Initialize SSL context. * All files are in PEM format. */ @@ -495,12 +522,8 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) #ifdef MANAGMENT_EXTERNAL_KEY else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file) { - openvpn_x509_cert_t *my_cert = NULL; - tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline, - &my_cert); - tls_ctx_use_external_private_key(new_ctx, my_cert); - - tls_ctx_free_cert_file(my_cert); + tls_ctx_use_external_private_key(new_ctx, options->cert_file, + options->cert_file_inline); } #endif else @@ -508,7 +531,7 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) /* Load Certificate */ if (options->cert_file) { - tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline, NULL); + tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline); } /* Load Private Key */ @@ -1813,15 +1836,17 @@ push_peer_info(struct buffer *buf, struct tls_session *session) get_default_gateway (&rgi); if (rgi.flags & RGI_HWADDR_DEFINED) buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc)); + } - /* push env vars that begin with UV_ */ - for (e=es->list; e != NULL; e=e->next) + /* push env vars that begin with UV_ and IV_GUI_VER */ + for (e=es->list; e != NULL; e=e->next) + { + if (e->string) { - if (e->string) - { - if (!strncmp(e->string, "UV_", 3) && buf_safe(&out, strlen(e->string)+1)) - buf_printf (&out, "%s\n", e->string); - } + if (((strncmp(e->string, "UV_", 3)==0 && session->opt->push_peer_info_detail >= 2) + || (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0)) + && buf_safe(&out, strlen(e->string)+1)) + buf_printf (&out, "%s\n", e->string); } } diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index f61580c..54383fe 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -36,12 +36,23 @@ #ifdef ENABLE_CRYPTO_OPENSSL #include "ssl_openssl.h" #include "ssl_verify_openssl.h" +#define SSLAPI SSLAPI_OPENSSL #endif #ifdef ENABLE_CRYPTO_POLARSSL #include "ssl_polarssl.h" #include "ssl_verify_polarssl.h" +#define SSLAPI SSLAPI_POLARSSL #endif +/* Ensure that SSLAPI got a sane value if SSL is disabled or unknown */ +#ifndef SSLAPI +#define SSLAPI SSLAPI_NONE +#endif + +/** + * prototype for struct tls_session from ssl_common.h + */ +struct tls_session; /** * Get a tls_cipher_name_pair containing OpenSSL and IANA names for supplied TLS cipher name @@ -90,6 +101,29 @@ void tls_free_lib(); void tls_clear_error(); /** + * Parse a TLS version specifier + * + * @param vstr The TLS version string + * @param extra An optional extra parameter, may be NULL + * + * @return One of the TLS_VER_x constants or TLS_VER_BAD + * if a parse error should be flagged. + */ +#define TLS_VER_BAD -1 +#define TLS_VER_1_0 0 /* default */ +#define TLS_VER_1_1 1 +#define TLS_VER_1_2 2 +int tls_version_min_parse(const char *vstr, const char *extra); + +/** + * Return the maximum TLS version (as a TLS_VER_x constant) + * supported by current SSL implementation + * + * @return One of the TLS_VER_x constants (but not TLS_VER_BAD). + */ +int tls_version_max(void); + +/** * Initialise a library-specific TLS context for a server. * * @param ctx TLS context to initialise @@ -181,27 +215,13 @@ void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert * Load certificate file into the given TLS context. If the given certificate * file contains a certificate chain, load the whole chain. * - * If the x509 parameter is not NULL, the certificate will be returned in it. - * * @param ctx TLS context to use * @param cert_file The file name to load the certificate from, or * "[[INLINE]]" in the case of inline files. * @param cert_file_inline A string containing the certificate - * @param x509 An optional certificate, if x509 is NULL, - * do nothing, if x509 is not NULL, *x509 will be - * allocated and filled with the loaded certificate. - * *x509 must be NULL. */ void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, openvpn_x509_cert_t **x509 - ); - -/** - * Free the given certificate - * - * @param x509 certificate to free - */ -void tls_ctx_free_cert_file (openvpn_x509_cert_t *x509); + const char *cert_file_inline); /** * Load private key file into the given TLS context. @@ -221,17 +241,19 @@ int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, #ifdef MANAGMENT_EXTERNAL_KEY /** - * Tell the management interface to load the external private key matching - * the given certificate. + * Tell the management interface to load the given certificate and the external + * private key matching the given certificate. * * @param ctx TLS context to use - * @param cert The certificate file to load the private key for + * @param cert_file The file name to load the certificate from, or * "[[INLINE]]" in the case of inline files. + * @param cert_file_inline A string containing the certificate * * @return 1 if an error occurred, 0 if parsing was * successful. */ -int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert); +int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline); #endif @@ -291,7 +313,7 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx); * @param session The session associated with the given key_state */ void key_state_ssl_init(struct key_state_ssl *ks_ssl, - const struct tls_root_ctx *ssl_ctx, bool is_server, void *session); + const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session); /** * Free the SSL channel part of the given key state. @@ -432,8 +454,10 @@ void print_details (struct key_state_ssl * ks_ssl, const char *prefix); /* * Show the TLS ciphers that are available for us to use in the OpenSSL * library. + * + * @param - list of allowed TLS cipher, or NULL. */ -void show_available_tls_ciphers (); +void show_available_tls_ciphers (const char *tls_ciphers); /* * The OpenSSL library has a notion of preference in TLS ciphers. Higher diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 0d818ab..66b6492 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -285,12 +285,14 @@ struct tls_options struct env_set *es; const struct plugin_list *plugins; - /* configuration file boolean options */ + /* configuration file SSL-related boolean and low-permutation options */ # define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0) # define SSLF_USERNAME_AS_COMMON_NAME (1<<1) # define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2) # define SSLF_OPT_VERIFY (1<<4) # define SSLF_CRL_VERIFY_DIR (1<<5) +# define SSLF_TLS_VERSION_SHIFT 6 +# define SSLF_TLS_VERSION_MASK 0xF /* (uses bit positions 6 to 9) */ unsigned int ssl_flags; #ifdef MANAGEMENT_DEF_AUTH diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 79cc056..5689e7c 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -103,8 +103,17 @@ tmp_rsa_cb (SSL * s, int is_export, int keylength) static RSA *rsa_tmp = NULL; if (rsa_tmp == NULL) { + int ret = -1; + BIGNUM *bn = BN_new(); + rsa_tmp = RSA_new(); + msg (D_HANDSHAKE, "Generating temp (%d bit) RSA key", keylength); - rsa_tmp = RSA_generate_key (keylength, RSA_F4, NULL, NULL); + + if(!bn || !BN_set_word(bn, RSA_F4) || + !RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL)) + msg(M_SSLERR, "Failed to generate temp RSA key"); + + if (bn) BN_free( bn ); } return (rsa_tmp); } @@ -114,10 +123,10 @@ tls_ctx_server_new(struct tls_root_ctx *ctx) { ASSERT(NULL != ctx); - ctx->ctx = SSL_CTX_new (TLSv1_server_method ()); + ctx->ctx = SSL_CTX_new (SSLv23_server_method ()); if (ctx->ctx == NULL) - msg (M_SSLERR, "SSL_CTX_new TLSv1_server_method"); + msg (M_SSLERR, "SSL_CTX_new SSLv23_server_method"); SSL_CTX_set_tmp_rsa_callback (ctx->ctx, tmp_rsa_cb); } @@ -127,10 +136,10 @@ tls_ctx_client_new(struct tls_root_ctx *ctx) { ASSERT(NULL != ctx); - ctx->ctx = SSL_CTX_new (TLSv1_client_method ()); + ctx->ctx = SSL_CTX_new (SSLv23_client_method ()); if (ctx->ctx == NULL) - msg (M_SSLERR, "SSL_CTX_new TLSv1_client_method"); + msg (M_SSLERR, "SSL_CTX_new SSLv23_client_method"); } void @@ -174,13 +183,46 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret) } } +/* + * Return maximum TLS version supported by local OpenSSL library. + * Assume that presence of SSL_OP_NO_TLSvX macro indicates that + * TLSvX is supported. + */ +int +tls_version_max(void) +{ +#if defined(SSL_OP_NO_TLSv1_2) + return TLS_VER_1_2; +#elif defined(SSL_OP_NO_TLSv1_1) + return TLS_VER_1_1; +#else + return TLS_VER_1_0; +#endif +} + void tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) { ASSERT(NULL != ctx); + /* process SSL options including minimum TLS version we will accept from peer */ + { + long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + const int tls_version_min = (ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK; + if (tls_version_min > TLS_VER_1_0) + sslopt |= SSL_OP_NO_TLSv1; +#ifdef SSL_OP_NO_TLSv1_1 + if (tls_version_min > TLS_VER_1_1) + sslopt |= SSL_OP_NO_TLSv1_1; +#endif +#ifdef SSL_OP_NO_TLSv1_2 + if (tls_version_min > TLS_VER_1_2) + sslopt |= SSL_OP_NO_TLSv1_2; +#endif + SSL_CTX_set_options (ctx->ctx, sslopt); + } + SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF); - SSL_CTX_set_options (ctx->ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback); /* Require peer certificate verification */ @@ -380,16 +422,34 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, /* Set Certificate Verification chain */ if (load_ca_file) { + /* Add CAs from PKCS12 to the cert store and mark them as trusted. + * They're also used to fill in the chain of intermediate certs as + * necessary. + */ if (ca && sk_X509_num(ca)) { for (i = 0; i < sk_X509_num(ca); i++) { - if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) + if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)"); if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); } } + } else { + /* If trusted CA certs were loaded from a PEM file, and we ignore the + * ones in PKCS12, do load PKCS12-provided certs to the client extra + * certs chain just in case they include intermediate CAs needed to + * prove my identity to the other end. This does not make them trusted. + */ + if (ca && sk_X509_num(ca)) + { + for (i = 0; i < sk_X509_num(ca); i++) + { + if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i))) + msg (M_SSLERR, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)"); + } + } } return 0; } @@ -423,9 +483,10 @@ tls_ctx_add_extra_certs (struct tls_root_ctx *ctx, BIO *bio) } } -void -tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, X509 **x509 +/* Like tls_ctx_load_cert, but returns a copy of the certificate in **X509 */ +static void +tls_ctx_load_cert_file_and_copy (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline, X509 **x509 ) { BIO *in = NULL; @@ -480,6 +541,13 @@ end: } void +tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, + const char *cert_file_inline) +{ + tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, NULL); +} + +void tls_ctx_free_cert_file (X509 *x509) { X509_free(x509); @@ -616,15 +684,19 @@ rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i } int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert) +tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) { RSA *rsa = NULL; RSA *pub_rsa; RSA_METHOD *rsa_meth; + X509 *cert = NULL; ASSERT (NULL != ctx); ASSERT (NULL != cert); + tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, &cert); + /* allocate custom RSA method object */ ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD); rsa_meth->name = "OpenVPN external private key RSA Method"; @@ -659,10 +731,13 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert) if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa)) goto err; + X509_free(cert); RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ return 1; err: + if (cert) + X509_free(cert); if (rsa) RSA_free(rsa); else @@ -694,7 +769,7 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, X509_STORE *store = NULL; X509_NAME *xn = NULL; BIO *in = NULL; - int i, added = 0; + int i, added = 0, prev = 0; ASSERT(NULL != ctx); @@ -721,6 +796,11 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, if (info->crl) X509_STORE_add_crl (store, info->crl); + if (tls_server && !info->x509) + { + msg (M_SSLERR, "X509 name was missing in TLS mode"); + } + if (info->x509) { X509_STORE_add_cert (store, info->x509); @@ -750,6 +830,15 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, sk_X509_NAME_push (cert_names, xn); } } + + if (tls_server) { + int cnum = sk_X509_NAME_num (cert_names); + if (cnum != (prev + 1)) { + msg (M_WARN, "Cannot load CA certificate file %s (entry %d did not validate)", np(ca_file), added); + } + prev = cnum; + } + } sk_X509_INFO_pop_free (info_stack, X509_INFO_free); } @@ -757,8 +846,15 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, if (tls_server) SSL_CTX_set_client_CA_list (ctx->ctx, cert_names); - if (!added || (tls_server && sk_X509_NAME_num (cert_names) != added)) - msg (M_SSLERR, "Cannot load CA certificate file %s", np(ca_file)); + if (!added) + msg (M_SSLERR, "Cannot load CA certificate file %s (no entries were read)", np(ca_file)); + + if (tls_server) { + int cnum = sk_X509_NAME_num (cert_names); + if (cnum != added) + msg (M_SSLERR, "Cannot load CA certificate file %s (only %d of %d entries were valid X509 names)", np(ca_file), cnum, added); + } + if (in) BIO_free (in); } @@ -1015,7 +1111,7 @@ bio_read (BIO *bio, struct buffer *buf, int maxlen, const char *desc) } void -key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, void *session) +key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) { ASSERT(NULL != ssl_ctx); ASSERT(ks_ssl); @@ -1188,23 +1284,26 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix) } void -show_available_tls_ciphers () +show_available_tls_ciphers (const char *cipher_list) { - SSL_CTX *ctx; + struct tls_root_ctx tls_ctx; SSL *ssl; const char *cipher_name; const char *print_name; const tls_cipher_name_pair *pair; int priority = 0; - ctx = SSL_CTX_new (TLSv1_method ()); - if (!ctx) + tls_ctx.ctx = SSL_CTX_new (SSLv23_method ()); + if (!tls_ctx.ctx) msg (M_SSLERR, "Cannot create SSL_CTX object"); - ssl = SSL_new (ctx); + ssl = SSL_new (tls_ctx.ctx); if (!ssl) msg (M_SSLERR, "Cannot create SSL object"); + if (cipher_list) + tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); + printf ("Available TLS Ciphers,\n"); printf ("listed in order of preference:\n\n"); while ((cipher_name = SSL_get_cipher_list (ssl, priority++))) @@ -1222,7 +1321,7 @@ show_available_tls_ciphers () printf ("\n"); SSL_free (ssl); - SSL_CTX_free (ctx); + SSL_CTX_free (tls_ctx.ctx); } void @@ -1232,7 +1331,7 @@ get_highest_preference_tls_cipher (char *buf, int size) SSL *ssl; const char *cipher_name; - ctx = SSL_CTX_new (TLSv1_method ()); + ctx = SSL_CTX_new (SSLv23_method ()); if (!ctx) msg (M_SSLERR, "Cannot create SSL_CTX object"); ssl = SSL_new (ctx); diff --git a/src/openvpn/ssl_openssl.h b/src/openvpn/ssl_openssl.h index fc2052c..73a6c49 100644 --- a/src/openvpn/ssl_openssl.h +++ b/src/openvpn/ssl_openssl.h @@ -33,6 +33,18 @@ #include <openssl/ssl.h> /** + * SSL_OP_NO_TICKET tells OpenSSL to disable "stateless session resumption", + * as this is something we do not want nor need, but could potentially be + * used for a future attack. For compatibility reasons, in the 2.3.x + * series, we keep building if the OpenSSL version is too old to support + * this. 2.4 requires it and will fail configure if not present. + */ +#ifndef SSL_OP_NO_TICKET +# define SSL_OP_NO_TICKET 0 +#endif + + +/** * Structure that wraps the TLS context. Contents differ depending on the * SSL library used. */ diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index 2b5b37b..551c352 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -7,6 +7,7 @@ * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2006-2010, Brainspark B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -121,6 +122,10 @@ tls_ctx_free(struct tls_root_ctx *ctx) free(ctx->priv_key_pkcs11); } #endif +#if defined(MANAGMENT_EXTERNAL_KEY) + if (ctx->external_key != NULL) + free(ctx->external_key); +#endif if (ctx->allowed_ciphers) free(ctx->allowed_ciphers); @@ -237,13 +242,10 @@ tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, - openvpn_x509_cert_t **x509 + const char *cert_file_inline ) { ASSERT(NULL != ctx); - if (NULL != x509) - ASSERT(NULL == *x509); if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_file_inline) { @@ -256,16 +258,6 @@ tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, if (0 != x509parse_crtfile(ctx->crt_chain, cert_file)) msg (M_FATAL, "Cannot load certificate file %s", cert_file); } - if (x509) - { - *x509 = ctx->crt_chain; - } -} - -void -tls_ctx_free_cert_file (openvpn_x509_cert_t *x509) -{ - x509_free(x509); } int @@ -322,13 +314,156 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, #ifdef MANAGMENT_EXTERNAL_KEY + +struct external_context { + size_t signature_length; +}; + int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert) +tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) { - msg(M_FATAL, "Use of management external keys not yet supported for PolarSSL."); - return false; + ASSERT(NULL != ctx); + + tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline); + + if (ctx->crt_chain == NULL) + return 0; + + /* Most of the initialization happens in key_state_ssl_init() */ + ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context); + ctx->external_key->signature_length = ctx->crt_chain->rsa.len; + + return 1; } +static inline int external_pkcs1_sign( void *ctx_voidptr, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode, + int hash_id, unsigned int hashlen, const unsigned char *hash, + unsigned char *sig ) +{ + struct external_context * const ctx = ctx_voidptr; + char *in_b64 = NULL; + char *out_b64 = NULL; + int rv; + unsigned char * const p = sig; + size_t asn_len; + + ASSERT(NULL != ctx); + + if (RSA_PRIVATE != mode) + { + rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA; + goto done; + } + + /* + * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW, + * but TLSv1.2 needs the full suite of hashes. + * + * This code has been taken from PolarSSL pkcs11_sign(), under the GPLv2.0+. + */ + switch( hash_id ) + { + case SIG_RSA_RAW: + asn_len = 0; + memcpy( p, hash, hashlen ); + break; + + case SIG_RSA_MD2: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 2; break; + + case SIG_RSA_MD4: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 4; break; + + case SIG_RSA_MD5: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 5; break; + + case SIG_RSA_SHA1: + asn_len = OID_SIZE(ASN1_HASH_SHA1); + memcpy( p, ASN1_HASH_SHA1, asn_len ); + memcpy( p + 15, hash, hashlen ); + break; + + case SIG_RSA_SHA224: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 4; p[18] += hashlen; break; + + case SIG_RSA_SHA256: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 1; p[18] += hashlen; break; + + case SIG_RSA_SHA384: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 2; p[18] += hashlen; break; + + case SIG_RSA_SHA512: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 3; p[18] += hashlen; break; + + /* End of copy */ + default: + rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA; + goto done; + } + + /* convert 'from' to base64 */ + if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0) + { + rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA; + goto done; + } + + /* call MI for signature */ + if (management) + out_b64 = management_query_rsa_sig (management, in_b64); + if (!out_b64) + { + rv = POLARSSL_ERR_RSA_PRIVATE_FAILED; + goto done; + } + + /* decode base64 signature to binary and verify length */ + if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) != + ctx->signature_length ) + { + rv = POLARSSL_ERR_RSA_PRIVATE_FAILED; + goto done; + } + + rv = 0; + + done: + if (in_b64) + free (in_b64); + if (out_b64) + free (out_b64); + return rv; +} + +static inline size_t external_key_len(void *vctx) +{ + struct external_context * const ctx = vctx; + + return ctx->signature_length; +} #endif void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, @@ -501,8 +636,20 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx) } } +int +tls_version_max(void) +{ +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3) + return TLS_VER_1_2; +#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2) + return TLS_VER_1_1; +#else + return TLS_VER_1_0; +#endif +} + void key_state_ssl_init(struct key_state_ssl *ks_ssl, - const struct tls_root_ctx *ssl_ctx, bool is_server, void *session) + const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) { ASSERT(NULL != ssl_ctx); ASSERT(ks_ssl); @@ -530,14 +677,61 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, ssl_pkcs11_key_len ); else #endif +#if defined(MANAGMENT_EXTERNAL_KEY) + if (ssl_ctx->external_key != NULL) + ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain, + ssl_ctx->external_key, NULL, external_pkcs1_sign, + external_key_len ); + else +#endif ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key ); /* Initialise SSL verification */ - ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED); - ssl_set_verify (ks_ssl->ctx, verify_callback, session); +#if P2MP_SERVER + if (session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) + { + msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " + "--client-cert-not-required may accept clients which do not present " + "a certificate"); + } + else +#endif + { + ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED); + ssl_set_verify (ks_ssl->ctx, verify_callback, session); + } + /* TODO: PolarSSL does not currently support sending the CA chain to the client */ ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL ); + /* Initialize minimum TLS version */ + { + const int tls_version_min = (session->opt->ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK; + int polar_major; + int polar_minor; + switch (tls_version_min) + { + case TLS_VER_1_0: + default: + polar_major = SSL_MAJOR_VERSION_3; + polar_minor = SSL_MINOR_VERSION_1; + break; +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2) + case TLS_VER_1_1: + polar_major = SSL_MAJOR_VERSION_3; + polar_minor = SSL_MINOR_VERSION_2; + break; +#endif +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3) + case TLS_VER_1_2: + polar_major = SSL_MAJOR_VERSION_3; + polar_minor = SSL_MINOR_VERSION_3; + break; +#endif + } + ssl_set_min_version(ks_ssl->ctx, polar_major, polar_minor); + } + /* Initialise BIOs */ ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer); ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer); @@ -839,10 +1033,16 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix) } void -show_available_tls_ciphers () +show_available_tls_ciphers (const char *cipher_list) { + struct tls_root_ctx tls_ctx; const int *ciphers = ssl_list_ciphersuites(); + if (cipher_list) { + tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); + ciphers = tls_ctx.allowed_ciphers; + } + #ifndef ENABLE_SMALL printf ("Available TLS Ciphers,\n"); printf ("listed in order of preference:\n\n"); diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_polarssl.h index da93699..fc9aa78 100644 --- a/src/openvpn/ssl_polarssl.h +++ b/src/openvpn/ssl_polarssl.h @@ -30,6 +30,8 @@ #ifndef SSL_POLARSSL_H_ #define SSL_POLARSSL_H_ +#include "syshead.h" + #include <polarssl/ssl.h> #if defined(ENABLE_PKCS11) @@ -68,6 +70,9 @@ struct tls_root_ctx { #if defined(ENABLE_PKCS11) pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ #endif +#ifdef MANAGMENT_EXTERNAL_KEY + struct external_context *external_key; /**< Management external key */ +#endif int * allowed_ciphers; /**< List of allowed ciphers for this connection */ }; diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index e651a8e..0670f2a 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -425,7 +425,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert setenv_str (es, envname, common_name); #endif -#ifdef ENABLE_EUREPHIA /* export X509 cert SHA1 fingerprint */ { unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc); @@ -434,7 +433,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1, ":", &gc)); } -#endif /* export serial number as environmental variable */ serial = x509_get_serial(peer_cert, &gc); diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 4db29cc..7a7d53a 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -546,7 +546,7 @@ socket_defined (const socket_descriptor_t sd) /* * Enable external private key */ -#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL) && !defined(ENABLE_CRYPTO_POLARSSL) +#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL) #define MANAGMENT_EXTERNAL_KEY #endif diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index a361233..976cc52 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -73,6 +73,12 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co #include <stropts.h> #endif +#if defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H +#include <sys/kern_control.h> +#include <net/if_utun.h> +#include <sys/sys_domain.h> +#endif + static void clear_tuntap (struct tuntap *tuntap); bool @@ -867,7 +873,7 @@ do_ifconfig (struct tuntap *tt, if (!tun && tt->topology == TOP_SUBNET) { /* Add a network route for the local tun interface */ - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED | RT_METRIC_DEFINED; r.network = tt->local & tt->remote_netmask; @@ -1064,7 +1070,7 @@ do_ifconfig (struct tuntap *tt, /* Add a network route for the local tun interface */ if (!tun && tt->topology == TOP_SUBNET) { - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED; r.network = tt->local & tt->remote_netmask; @@ -1130,7 +1136,7 @@ do_ifconfig (struct tuntap *tt, /* Add a network route for the local tun interface */ if (!tun && tt->topology == TOP_SUBNET) { - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED; r.network = tt->local & tt->remote_netmask; @@ -1248,6 +1254,87 @@ open_null (struct tuntap *tt) tt->actual_name = string_alloc ("null", NULL); } + +#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H) + +/* + * OpenBSD and Mac OS X when using utun + * have a slightly incompatible TUN device from + * the rest of the world, in that it prepends a + * uint32 to the beginning of the IP header + * to designate the protocol (why not just + * look at the version field in the IP header to + * determine v4 or v6?). + * + * We strip off this field on reads and + * put it back on writes. + * + * I have not tested TAP devices on OpenBSD, + * but I have conditionalized the special + * TUN handling code described above to + * go away for TAP devices. + */ + +#include <netinet/ip.h> +#include <sys/uio.h> + +static inline int +header_modify_read_write_return (int len) +{ + if (len > 0) + return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; + else + return len; +} + +int +write_tun_header (struct tuntap* tt, uint8_t *buf, int len) +{ + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + struct ip *iph; + + iph = (struct ip *) buf; + + if (tt->ipv6 && iph->ip_v == 6) + type = htonl (AF_INET6); + else + type = htonl (AF_INET); + + iv[0].iov_base = &type; + iv[0].iov_len = sizeof (type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return header_modify_read_write_return (writev (tt->fd, iv, 2)); + } + else + return write (tt->fd, buf, len); +} + +int +read_tun_header (struct tuntap* tt, uint8_t *buf, int len) +{ + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + + iv[0].iov_base = &type; + iv[0].iov_len = sizeof (type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return header_modify_read_write_return (readv (tt->fd, iv, 2)); + } + else + return read (tt->fd, buf, len); +} +#endif + + #ifndef WIN32 static void open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, @@ -1972,23 +2059,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) #elif defined(TARGET_OPENBSD) -/* - * OpenBSD has a slightly incompatible TUN device from - * the rest of the world, in that it prepends a - * uint32 to the beginning of the IP header - * to designate the protocol (why not just - * look at the version field in the IP header to - * determine v4 or v6?). - * - * We strip off this field on reads and - * put it back on writes. - * - * I have not tested TAP devices on OpenBSD, - * but I have conditionalized the special - * TUN handling code described above to - * go away for TAP devices. - */ - void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { @@ -2055,59 +2125,16 @@ close_tun (struct tuntap* tt) } } -static inline int -openbsd_modify_read_write_return (int len) -{ - if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; - else - return len; -} - int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - struct ip *iph; - - iph = (struct ip *) buf; - - if (tt->ipv6 && iph->ip_v == 6) - type = htonl (AF_INET6); - else - type = htonl (AF_INET); - - iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return openbsd_modify_read_write_return (writev (tt->fd, iv, 2)); - } - else - return write (tt->fd, buf, len); + return write_tun_header (tt, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun (struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - - iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return openbsd_modify_read_write_return (readv (tt->fd, iv, 2)); - } - else - return read (tt->fd, buf, len); + return read_tun_header (tt, buf, len); } #elif defined(TARGET_NETBSD) @@ -2467,10 +2494,177 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) * pointing to lo0. Need to unconfigure... (observed on 10.5) */ +/* + * utun is the native Darwin tun driver present since at least 10.7 + * Thanks goes to Jonathan Levin for providing an example how to utun + * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c) + */ + +#ifdef HAVE_NET_IF_UTUN_H + +/* Helper functions that tries to open utun device + return -2 on early initialization failures (utun not supported + at all (old OS X) and -1 on initlization failure of utun + device (utun works but utunX is already used */ +static +int utun_open_helper (struct ctl_info ctlInfo, int utunnum) +{ + struct sockaddr_ctl sc; + int fd; + + fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + + if (fd < 0) + { + msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)", + strerror (errno)); + return -2; + } + + if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) + { + close (fd); + msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)", + strerror (errno)); + return -2; + } + + + sc.sc_id = ctlInfo.ctl_id; + sc.sc_len = sizeof(sc); + sc.sc_family = AF_SYSTEM; + sc.ss_sysaddr = AF_SYS_CONTROL; + + sc.sc_unit = utunnum+1; + + + /* If the connect is successful, a utun%d device will be created, where "%d" + * is (sc.sc_unit - 1) */ + + if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) + { + msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)", + strerror (errno)); + close(fd); + return -1; + } + + set_nonblock (fd); + set_cloexec (fd); /* don't pass fd to scripts */ + + return fd; +} + +void +open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +{ + struct ctl_info ctlInfo; + int fd; + char utunname[20]; + int utunnum =-1; + socklen_t utunname_len = sizeof(utunname); + + /* dev_node is simply utun, do the normal dynamic utun + * otherwise try to parse the utun number */ + if (dev_node && !strcmp ("utun", dev_node)==0) + { + if (!sscanf (dev_node, "utun%d", &utunnum)==1) + msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'" + "to use a utun device number X", dev_node); + } + + + + CLEAR (ctlInfo); + if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= + sizeof(ctlInfo.ctl_name)) + { + msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long"); + } + + /* try to open first available utun device if no specific utun is requested */ + if (utunnum == -1) + { + for (utunnum=0; utunnum<255; utunnum++) + { + fd = utun_open_helper (ctlInfo, utunnum); + /* Break if the fd is valid, + * or if early initalization failed (-2) */ + if (fd !=-1) + break; + } + } + else + { + fd = utun_open_helper (ctlInfo, utunnum); + } + + /* opening an utun device failed */ + tt->fd = fd; + + if (fd < 0) + return; + + /* Retrieve the assigned interface name. */ + if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len)) + msg (M_ERR | M_ERRNO, "Error retrieving utun interface name"); + + tt->actual_name = string_alloc (utunname, NULL); + + msg (M_INFO, "Opened utun device %s", utunname); + tt->is_utun = true; +} + +#endif + void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, true, tt); +#ifdef HAVE_NET_IF_UTUN_H + /* If dev_node does not start start with utun assume regular tun/tap */ + if ((!dev_node && tt->type==DEV_TYPE_TUN) || + (dev_node && !strncmp (dev_node, "utun", 4))) + { + + /* Check if user has specific dev_type tap and forced utun with + dev-node utun */ + if (tt->type!=DEV_TYPE_TUN) + msg (M_FATAL, "Cannot use utun devices with --dev-type %s", + dev_type_string (dev, dev_type)); + + /* Try utun first and fall back to normal tun if utun fails + and dev_node is not specified */ + open_darwin_utun(dev, dev_type, dev_node, tt); + + if (!tt->is_utun) + { + if (!dev_node) + { + /* No explicit utun and utun failed, try the generic way) */ + msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device"); + open_tun_generic (dev, dev_type, NULL, true, true, tt); + } + else + { + /* Specific utun device or generic utun request with no tun + fall back failed, consider this a fatal failure */ + msg (M_FATAL, "Cannot open utun device"); + } + } + } + else +#endif + { + + /* Use plain dev-node tun to select /dev/tun style + * Unset dev_node variable prior to passing to open_tun_generic to + * let open_tun_generic pick the first available tun device */ + + if (dev_node && strcmp (dev_node, "tun")==0) + dev_node=NULL; + + open_tun_generic (dev, dev_type, dev_node, true, true, tt); + } } void @@ -2503,13 +2697,23 @@ close_tun (struct tuntap* tt) int write_tun (struct tuntap* tt, uint8_t *buf, int len) { - return write (tt->fd, buf, len); +#ifdef HAVE_NET_IF_UTUN_H + if (tt->is_utun) + return write_tun_header (tt, buf, len); + else +#endif + return write (tt->fd, buf, len); } int read_tun (struct tuntap* tt, uint8_t *buf, int len) { - return read (tt->fd, buf, len); +#ifdef HAVE_NET_IF_UTUN_H + if (tt->is_utun) + return read_tun_header (tt, buf, len); + else +#endif + return read (tt->fd, buf, len); } #elif defined(WIN32) @@ -2854,9 +3058,9 @@ get_panel_reg (struct gc_arena *gc) char enum_name[256]; char connection_string[256]; HKEY connection_key; - char name_data[256]; + WCHAR name_data[256]; DWORD name_type; - const char name_string[] = "Name"; + const WCHAR name_string[] = L"Name"; len = sizeof (enum_name); status = RegEnumKeyEx( @@ -2890,12 +3094,12 @@ get_panel_reg (struct gc_arena *gc) else { len = sizeof (name_data); - status = RegQueryValueEx( + status = RegQueryValueExW( connection_key, name_string, NULL, &name_type, - name_data, + (LPBYTE) name_data, &len); if (status != ERROR_SUCCESS || name_type != REG_SZ) @@ -2903,10 +3107,15 @@ get_panel_reg (struct gc_arena *gc) NETWORK_CONNECTIONS_KEY, connection_string, name_string); else { + int n; + LPSTR name; struct panel_reg *reg; ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); - reg->name = string_alloc (name_data, gc); + n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL); + name = gc_malloc (n, false, gc); + WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL); + reg->name = name; reg->guid = string_alloc (enum_name, gc); /* link into return list */ @@ -3116,7 +3325,7 @@ static void at_least_one_tap_win (const struct tap_reg *tap_reg) { if (!tap_reg) - msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> " PACKAGE_NAME " -> Add a new TAP-Windows virtual ethernet adapter."); + msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> TAP-Windows -> Utilities -> Add a new TAP-Windows virtual ethernet adapter."); } /* diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index c3fc62e..085d6a3 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -181,6 +181,9 @@ struct tuntap int ip_fd; #endif +#ifdef HAVE_NET_IF_UTUN_H + bool is_utun; +#endif /* used for printing status info only */ unsigned int rwflags_debug; diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 178e2c3..13fd881 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -996,19 +996,27 @@ set_win_sys_path_via_env (struct env_set *es) const char * win_get_tempdir() { - static char buf[MAX_PATH]; - char *tmpdir = buf; - - CLEAR(buf); - - if (!GetTempPath(sizeof(buf),buf)) { - /* Warn if we can't find a valid temporary directory, which should - * be unlikely. - */ - msg (M_WARN, "Could not find a suitable temporary directory." - " (GetTempPath() failed). Consider to use --tmp-dir"); - tmpdir = NULL; - } + static char tmpdir[MAX_PATH]; + WCHAR wtmpdir[MAX_PATH]; + + if (!GetTempPathW(_countof(wtmpdir), wtmpdir)) + { + /* Warn if we can't find a valid temporary directory, which should + * be unlikely. + */ + msg (M_WARN, "Could not find a suitable temporary directory." + " (GetTempPath() failed). Consider using --tmp-dir"); + return NULL; + } + + if (WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, NULL, 0, NULL, NULL) > sizeof (tmpdir)) + { + msg (M_WARN, "Could not get temporary directory. Path is too long." + " Consider using --tmp-dir"); + return NULL; + } + + WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL); return tmpdir; } #endif |