Skip to content

Commit 03a5599

Browse files
committed
TLS version negotiation
Updated the TLS negotiation logic to adaptively try to connect using the highest TLS version supported by both client and server. Previously, OpenVPN (when linked with OpenSSL) would always connect using TLS 1.0. Also added tls-version-min directive to force a higher TLS version than 1.0: tls-version-min <version> ['or-highest'] -- sets the minimum TLS version we will accept from the peer. Examples for version include "1.0" (default), "1.1", or "1.2". If 'or-highest' is specified and version is not recognized, we will only accept the highest TLS version supported by the local SSL implementation. Examples: tls-version-min 1.1 -- fail the connection unless peer can connect at TLS 1.1 or higher. tls-version-min 1.2 or-highest -- require that the peer connect at TLS 1.2 or higher, however if the local SSL implementation doesn't support TLS 1.2 (as it wouldn't if linked with an older version of OpenSSL), reduce the minimum required version to the highest version supported by the local SSL implementation (such as TLS 1.0). This is intended to allow client configurations to target higher TLS versions that are supported on the server, even if some older clients don't support these versions yet.
1 parent 1a13dd2 commit 03a5599

File tree

7 files changed

+152
-4
lines changed

7 files changed

+152
-4
lines changed

doc/openvpn.8

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4235,6 +4235,15 @@ when you built your peer's certificate (see
42354235
above).
42364236
.\"*********************************************************
42374237
.TP
4238+
.B \-\-tls-version-min version ['or-highest']
4239+
Sets the minimum
4240+
TLS version we will accept from the peer (default is "1.0").
4241+
Examples for version
4242+
include "1.0", "1.1", or "1.2". If 'or-highest' is specified
4243+
and version is not recognized, we will only accept the highest TLS
4244+
version supported by the local SSL implementation.
4245+
.\"*********************************************************
4246+
.TP
42384247
.B \-\-pkcs12 file
42394248
Specify a PKCS #12 file containing local private key,
42404249
local certificate, and root CA certificate.

src/openvpn/options.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,9 @@ static const char usage_message[] =
582582
" by a Certificate Authority in --ca file.\n"
583583
"--extra-certs file : one or more PEM certs that complete the cert chain.\n"
584584
"--key file : Local private key in .pem format.\n"
585+
"--tls-version-min <version> ['or-highest'] : sets the minimum TLS version we\n"
586+
" will accept from the peer. If version is unrecognized and 'or-highest'\n"
587+
" is specified, require max TLS version supported by SSL implementation.\n"
585588
#ifndef ENABLE_CRYPTO_POLARSSL
586589
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
587590
" and optionally the root CA certificate.\n"
@@ -6511,6 +6514,19 @@ add_option (struct options *options,
65116514
options->priv_key_file_inline = p[2];
65126515
}
65136516
}
6517+
else if (streq (p[0], "tls-version-min") && p[1])
6518+
{
6519+
int ver;
6520+
VERIFY_PERMISSION (OPT_P_GENERAL);
6521+
ver = tls_version_min_parse(p[1], p[2]);
6522+
if (ver == TLS_VER_BAD)
6523+
{
6524+
msg (msglevel, "unknown tls-version-min parameter: %s", p[1]);
6525+
goto err;
6526+
}
6527+
options->ssl_flags &= ~(SSLF_TLS_VERSION_MASK << SSLF_TLS_VERSION_SHIFT);
6528+
options->ssl_flags |= (ver << SSLF_TLS_VERSION_SHIFT);
6529+
}
65146530
#ifndef ENABLE_CRYPTO_POLARSSL
65156531
else if (streq (p[0], "pkcs12") && p[1])
65166532
{

src/openvpn/ssl.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,27 @@ ssl_put_auth_challenge (const char *cr_str)
446446

447447
#endif
448448

449+
/*
450+
* Parse a TLS version string, returning a TLS_VER_x constant.
451+
* If version string is not recognized and extra == "or-highest",
452+
* return tls_version_max().
453+
*/
454+
int
455+
tls_version_min_parse(const char *vstr, const char *extra)
456+
{
457+
const int max_version = tls_version_max();
458+
if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version)
459+
return TLS_VER_1_0;
460+
else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version)
461+
return TLS_VER_1_1;
462+
else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version)
463+
return TLS_VER_1_2;
464+
else if (extra && !strcmp(extra, "or-highest"))
465+
return max_version;
466+
else
467+
return TLS_VER_BAD;
468+
}
469+
449470
/*
450471
* Initialize SSL context.
451472
* All files are in PEM format.

src/openvpn/ssl_backend.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,29 @@ void tls_free_lib();
9393
*/
9494
void tls_clear_error();
9595

96+
/**
97+
* Parse a TLS version specifier
98+
*
99+
* @param vstr The TLS version string
100+
* @param extra An optional extra parameter, may be NULL
101+
*
102+
* @return One of the TLS_VER_x constants or TLS_VER_BAD
103+
* if a parse error should be flagged.
104+
*/
105+
#define TLS_VER_BAD -1
106+
#define TLS_VER_1_0 0 /* default */
107+
#define TLS_VER_1_1 1
108+
#define TLS_VER_1_2 2
109+
int tls_version_min_parse(const char *vstr, const char *extra);
110+
111+
/**
112+
* Return the maximum TLS version (as a TLS_VER_x constant)
113+
* supported by current SSL implementation
114+
*
115+
* @return One of the TLS_VER_x constants (but not TLS_VER_BAD).
116+
*/
117+
int tls_version_max(void);
118+
96119
/**
97120
* Initialise a library-specific TLS context for a server.
98121
*

src/openvpn/ssl_common.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,12 +290,14 @@ struct tls_options
290290
struct compress_options comp_options;
291291
#endif
292292

293-
/* configuration file boolean options */
293+
/* configuration file SSL-related boolean and low-permutation options */
294294
# define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0)
295295
# define SSLF_USERNAME_AS_COMMON_NAME (1<<1)
296296
# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2)
297297
# define SSLF_OPT_VERIFY (1<<4)
298298
# define SSLF_CRL_VERIFY_DIR (1<<5)
299+
# define SSLF_TLS_VERSION_SHIFT 6
300+
# define SSLF_TLS_VERSION_MASK 0xF /* (uses bit positions 6 to 9) */
299301
unsigned int ssl_flags;
300302

301303
#ifdef MANAGEMENT_DEF_AUTH

src/openvpn/ssl_openssl.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ tls_ctx_server_new(struct tls_root_ctx *ctx)
114114
{
115115
ASSERT(NULL != ctx);
116116

117-
ctx->ctx = SSL_CTX_new (TLSv1_server_method ());
117+
ctx->ctx = SSL_CTX_new (SSLv23_server_method ());
118118

119119
if (ctx->ctx == NULL)
120120
msg (M_SSLERR, "SSL_CTX_new TLSv1_server_method");
@@ -127,7 +127,7 @@ tls_ctx_client_new(struct tls_root_ctx *ctx)
127127
{
128128
ASSERT(NULL != ctx);
129129

130-
ctx->ctx = SSL_CTX_new (TLSv1_client_method ());
130+
ctx->ctx = SSL_CTX_new (SSLv23_client_method ());
131131

132132
if (ctx->ctx == NULL)
133133
msg (M_SSLERR, "SSL_CTX_new TLSv1_client_method");
@@ -174,13 +174,48 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret)
174174
}
175175
}
176176

177+
/*
178+
* Return maximum TLS version supported by local OpenSSL library.
179+
* Assume that presence of SSL_OP_NO_TLSvX macro indicates that
180+
* TLSvX is supported.
181+
*/
182+
int
183+
tls_version_max(void)
184+
{
185+
#if defined(SSL_OP_NO_TLSv1_2)
186+
return TLS_VER_1_2;
187+
#elif defined(SSL_OP_NO_TLSv1_1)
188+
return TLS_VER_1_1;
189+
#else
190+
return TLS_VER_1_0;
191+
#endif
192+
}
193+
177194
void
178195
tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
179196
{
180197
ASSERT(NULL != ctx);
181198

199+
/* process SSL options including minimum TLS version we will accept from peer */
200+
{
201+
long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
202+
const int tls_version_min = (ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK;
203+
#ifdef SSL_OP_NO_TLSv1
204+
if (tls_version_min > TLS_VER_1_0)
205+
sslopt |= SSL_OP_NO_TLSv1;
206+
#endif
207+
#ifdef SSL_OP_NO_TLSv1_1
208+
if (tls_version_min > TLS_VER_1_1)
209+
sslopt |= SSL_OP_NO_TLSv1_1;
210+
#endif
211+
#ifdef SSL_OP_NO_TLSv1_2
212+
if (tls_version_min > TLS_VER_1_2)
213+
sslopt |= SSL_OP_NO_TLSv1_2;
214+
#endif
215+
SSL_CTX_set_options (ctx->ctx, sslopt);
216+
}
217+
182218
SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF);
183-
SSL_CTX_set_options (ctx->ctx, SSL_OP_SINGLE_DH_USE);
184219
SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback);
185220

186221
/* Require peer certificate verification */

src/openvpn/ssl_polarssl.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,18 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
501501
}
502502
}
503503

504+
int
505+
tls_version_max(void)
506+
{
507+
#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3)
508+
return TLS_VER_1_2;
509+
#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
510+
return TLS_VER_1_1;
511+
#else
512+
return TLS_VER_1_0;
513+
#endif
514+
}
515+
504516
void key_state_ssl_init(struct key_state_ssl *ks_ssl,
505517
const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session)
506518
{
@@ -550,6 +562,36 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
550562
/* TODO: PolarSSL does not currently support sending the CA chain to the client */
551563
ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL );
552564

565+
/* Initialize minimum TLS version */
566+
{
567+
const int tls_version_min = (session->opt->ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK;
568+
int polar_major;
569+
int polar_minor;
570+
switch (tls_version_min)
571+
{
572+
#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_1)
573+
case TLS_VER_1_0:
574+
default:
575+
polar_major = SSL_MAJOR_VERSION_3;
576+
polar_minor = SSL_MINOR_VERSION_1;
577+
break;
578+
#endif
579+
#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
580+
case TLS_VER_1_1:
581+
polar_major = SSL_MAJOR_VERSION_3;
582+
polar_minor = SSL_MINOR_VERSION_2;
583+
break;
584+
#endif
585+
#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3)
586+
case TLS_VER_1_2:
587+
polar_major = SSL_MAJOR_VERSION_3;
588+
polar_minor = SSL_MINOR_VERSION_3;
589+
break;
590+
#endif
591+
}
592+
ssl_set_min_version(ks_ssl->ctx, polar_major, polar_minor);
593+
}
594+
553595
/* Initialise BIOs */
554596
ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer);
555597
ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer);

0 commit comments

Comments
 (0)