summaryrefslogtreecommitdiff
path: root/src/openvpn/ssl_openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/ssl_openssl.c')
-rw-r--r--src/openvpn/ssl_openssl.c293
1 files changed, 213 insertions, 80 deletions
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index b266309..a78dae9 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -5,8 +5,8 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net>
- * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com>
+ * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
+ * Copyright (C) 2010-2018 Fox Crypto B.V. <openvpn@fox-it.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -206,16 +206,73 @@ info_callback(INFO_CALLBACK_SSL_CONST SSL *s, int where, int ret)
int
tls_version_max(void)
{
-#if defined(SSL_OP_NO_TLSv1_2)
+#if defined(TLS1_3_VERSION)
+ return TLS_VER_1_3;
+#elif defined(TLS1_2_VERSION) || defined(SSL_OP_NO_TLSv1_2)
return TLS_VER_1_2;
-#elif defined(SSL_OP_NO_TLSv1_1)
+#elif defined(TLS1_1_VERSION) || defined(SSL_OP_NO_TLSv1_1)
return TLS_VER_1_1;
#else
return TLS_VER_1_0;
#endif
}
-void
+/** Convert internal version number to openssl version number */
+static int
+openssl_tls_version(int ver)
+{
+ if (ver == TLS_VER_1_0)
+ {
+ return TLS1_VERSION;
+ }
+ else if (ver == TLS_VER_1_1)
+ {
+ return TLS1_1_VERSION;
+ }
+ else if (ver == TLS_VER_1_2)
+ {
+ return TLS1_2_VERSION;
+ }
+#if defined(TLS1_3_VERSION)
+ else if (ver == TLS_VER_1_3)
+ {
+ return TLS1_3_VERSION;
+ }
+#endif
+ return 0;
+}
+
+static bool
+tls_ctx_set_tls_versions(struct tls_root_ctx *ctx, unsigned int ssl_flags)
+{
+ int tls_ver_min = openssl_tls_version(
+ (ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & SSLF_TLS_VERSION_MIN_MASK);
+ int tls_ver_max = openssl_tls_version(
+ (ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK);
+
+ if (!tls_ver_min)
+ {
+ /* Enforce at least TLS 1.0 */
+ int cur_min = SSL_CTX_get_min_proto_version(ctx->ctx);
+ tls_ver_min = cur_min < TLS1_VERSION ? TLS1_VERSION : cur_min;
+ }
+
+ if (!SSL_CTX_set_min_proto_version(ctx->ctx, tls_ver_min))
+ {
+ msg(D_TLS_ERRORS, "%s: failed to set minimum TLS version", __func__);
+ return false;
+ }
+
+ if (tls_ver_max && !SSL_CTX_set_max_proto_version(ctx->ctx, tls_ver_max))
+ {
+ msg(D_TLS_ERRORS, "%s: failed to set maximum TLS version", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+bool
tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
{
ASSERT(NULL != ctx);
@@ -223,44 +280,21 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
/* default certificate verification flags */
int flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
- /* 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;
- int tls_ver_max = TLS_VER_UNSPEC;
- const int tls_ver_min =
- (ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & SSLF_TLS_VERSION_MIN_MASK;
-
- tls_ver_max =
- (ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK;
- if (tls_ver_max <= TLS_VER_UNSPEC)
- {
- tls_ver_max = tls_version_max();
- }
-
- if (tls_ver_min > TLS_VER_1_0 || tls_ver_max < TLS_VER_1_0)
- {
- sslopt |= SSL_OP_NO_TLSv1;
- }
-#ifdef SSL_OP_NO_TLSv1_1
- if (tls_ver_min > TLS_VER_1_1 || tls_ver_max < TLS_VER_1_1)
- {
- sslopt |= SSL_OP_NO_TLSv1_1;
- }
-#endif
-#ifdef SSL_OP_NO_TLSv1_2
- if (tls_ver_min > TLS_VER_1_2 || tls_ver_max < TLS_VER_1_2)
- {
- sslopt |= SSL_OP_NO_TLSv1_2;
- }
-#endif
+ /* process SSL options */
+ long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET;
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
- sslopt |= SSL_OP_CIPHER_SERVER_PREFERENCE;
+ sslopt |= SSL_OP_CIPHER_SERVER_PREFERENCE;
#endif
#ifdef SSL_OP_NO_COMPRESSION
- /* Disable compression - flag not available in OpenSSL 0.9.8 */
- sslopt |= SSL_OP_NO_COMPRESSION;
+ /* Disable compression - flag not available in OpenSSL 0.9.8 */
+ sslopt |= SSL_OP_NO_COMPRESSION;
#endif
- SSL_CTX_set_options(ctx->ctx, sslopt);
+
+ SSL_CTX_set_options(ctx->ctx, sslopt);
+
+ if (!tls_ctx_set_tls_versions(ctx, ssl_flags))
+ {
+ return false;
}
#ifdef SSL_MODE_RELEASE_BUFFERS
@@ -283,6 +317,8 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
SSL_CTX_set_verify(ctx->ctx, flags, verify_callback);
SSL_CTX_set_info_callback(ctx->ctx, info_callback);
+
+ return true;
}
void
@@ -387,6 +423,96 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
}
void
+convert_tls13_list_to_openssl(char *openssl_ciphers, size_t len,
+ const char *ciphers)
+{
+ /*
+ * OpenSSL (and official IANA) cipher names have _ in them. We
+ * historically used names with - in them. Silently convert names
+ * with - to names with _ to support both
+ */
+ if (strlen(ciphers) >= (len - 1))
+ {
+ msg(M_FATAL,
+ "Failed to set restricted TLS 1.3 cipher list, too long (>%d).",
+ (int) (len - 1));
+ }
+
+ strncpy(openssl_ciphers, ciphers, len);
+
+ for (size_t i = 0; i < strlen(openssl_ciphers); i++)
+ {
+ if (openssl_ciphers[i] == '-')
+ {
+ openssl_ciphers[i] = '_';
+ }
+ }
+}
+
+void
+tls_ctx_restrict_ciphers_tls13(struct tls_root_ctx *ctx, const char *ciphers)
+{
+ if (ciphers == NULL)
+ {
+ /* default cipher list of OpenSSL 1.1.1 is sane, do not set own
+ * default as we do with tls-cipher */
+ return;
+ }
+
+#if (OPENSSL_VERSION_NUMBER < 0x1010100fL)
+ crypto_msg(M_WARN, "Not compiled with OpenSSL 1.1.1 or higher. "
+ "Ignoring TLS 1.3 only tls-ciphersuites '%s' setting.",
+ ciphers);
+#else
+ ASSERT(NULL != ctx);
+
+ char openssl_ciphers[4096];
+ convert_tls13_list_to_openssl(openssl_ciphers, sizeof(openssl_ciphers),
+ ciphers);
+
+ if (!SSL_CTX_set_ciphersuites(ctx->ctx, openssl_ciphers))
+ {
+ crypto_msg(M_FATAL, "Failed to set restricted TLS 1.3 cipher list: %s",
+ openssl_ciphers);
+ }
+#endif
+}
+
+void
+tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile)
+{
+#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
+ /* OpenSSL does not have certificate profiles, but a complex set of
+ * callbacks that we could try to implement to achieve something similar.
+ * For now, use OpenSSL's security levels to achieve similar (but not equal)
+ * behaviour. */
+ if (!profile || 0 == strcmp(profile, "legacy"))
+ {
+ SSL_CTX_set_security_level(ctx->ctx, 1);
+ }
+ else if (0 == strcmp(profile, "preferred"))
+ {
+ SSL_CTX_set_security_level(ctx->ctx, 2);
+ }
+ else if (0 == strcmp(profile, "suiteb"))
+ {
+ SSL_CTX_set_security_level(ctx->ctx, 3);
+ SSL_CTX_set_cipher_list(ctx->ctx, "SUITEB128");
+ }
+ else
+ {
+ msg(M_FATAL, "ERROR: Invalid cert profile: %s", profile);
+ }
+#else
+ if (profile)
+ {
+ msg(M_WARN, "WARNING: OpenSSL 1.0.1 does not support --tls-cert-profile"
+ ", ignoring user-set profile: '%s'", profile);
+ }
+#endif
+}
+
+void
tls_ctx_check_cert_time(const struct tls_root_ctx *ctx)
{
int ret;
@@ -557,7 +683,7 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
EC_KEY_free(ecdh);
#else /* ifndef OPENSSL_NO_EC */
- msg(M_DEBUG, "Your OpenSSL library was built without elliptic curve support."
+ msg(D_LOW, "Your OpenSSL library was built without elliptic curve support."
" Skipping ECDH parameter loading.");
#endif /* OPENSSL_NO_EC */
}
@@ -1098,7 +1224,7 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
X509_free(cert);
RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */
- return 1;
+ return 0;
err:
if (cert)
@@ -1113,11 +1239,11 @@ err:
{
if (rsa_meth)
{
- free(rsa_meth);
+ RSA_meth_free(rsa_meth);
}
}
crypto_msg(M_FATAL, "Cannot enable SSL external private key capability");
- return 0;
+ return 1;
}
#endif /* ifdef MANAGMENT_EXTERNAL_KEY */
@@ -1385,23 +1511,6 @@ bio_debug_oc(const char *mode, BIO *bio)
#endif /* ifdef BIO_DEBUG */
/*
- * OpenVPN's interface to SSL/TLS authentication,
- * encryption, and decryption is exclusively
- * through "memory BIOs".
- */
-static BIO *
-getbio(BIO_METHOD *type, const char *desc)
-{
- BIO *ret;
- ret = BIO_new(type);
- if (!ret)
- {
- crypto_msg(M_FATAL, "Error creating %s BIO", desc);
- }
- return ret;
-}
-
-/*
* Write to an OpenSSL BIO in non-blocking mode.
*/
static int
@@ -1542,9 +1651,9 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_
* from verify callback*/
SSL_set_ex_data(ks_ssl->ssl, mydata_index, session);
- ks_ssl->ssl_bio = getbio(BIO_f_ssl(), "ssl_bio");
- ks_ssl->ct_in = getbio(BIO_s_mem(), "ct_in");
- ks_ssl->ct_out = getbio(BIO_s_mem(), "ct_out");
+ ASSERT((ks_ssl->ssl_bio = BIO_new(BIO_f_ssl())));
+ ASSERT((ks_ssl->ct_in = BIO_new(BIO_s_mem())));
+ ASSERT((ks_ssl->ct_out = BIO_new(BIO_s_mem())));
#ifdef BIO_DEBUG
bio_debug_oc("open ssl_bio", ks_ssl->ssl_bio);
@@ -1725,13 +1834,11 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
}
void
-show_available_tls_ciphers(const char *cipher_list)
+show_available_tls_ciphers_list(const char *cipher_list,
+ const char *tls_cert_profile,
+ const bool tls13)
{
struct tls_root_ctx tls_ctx;
- SSL *ssl;
- const char *cipher_name;
- const tls_cipher_name_pair *pair;
- int priority = 0;
tls_ctx.ctx = SSL_CTX_new(SSLv23_method());
if (!tls_ctx.ctx)
@@ -1739,33 +1846,59 @@ show_available_tls_ciphers(const char *cipher_list)
crypto_msg(M_FATAL, "Cannot create SSL_CTX object");
}
- ssl = SSL_new(tls_ctx.ctx);
+#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL)
+ if (tls13)
+ {
+ SSL_CTX_set_min_proto_version(tls_ctx.ctx, TLS1_3_VERSION);
+ tls_ctx_restrict_ciphers_tls13(&tls_ctx, cipher_list);
+ }
+ else
+#endif
+ {
+ SSL_CTX_set_max_proto_version(tls_ctx.ctx, TLS1_2_VERSION);
+ tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
+ }
+
+ tls_ctx_set_cert_profile(&tls_ctx, tls_cert_profile);
+
+ SSL *ssl = SSL_new(tls_ctx.ctx);
if (!ssl)
{
crypto_msg(M_FATAL, "Cannot create SSL object");
}
- 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++)))
+#if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
+ STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl);
+#else
+ STACK_OF(SSL_CIPHER) *sk = SSL_get1_supported_ciphers(ssl);
+#endif
+ for (int i=0;i < sk_SSL_CIPHER_num(sk);i++)
{
- pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name));
+ const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, i);
- if (NULL == pair)
+ const char *cipher_name = SSL_CIPHER_get_name(c);
+
+ const tls_cipher_name_pair *pair =
+ tls_get_cipher_name_pair(cipher_name, strlen(cipher_name));
+
+ if (tls13)
+ {
+ printf("%s\n", cipher_name);
+ }
+ else if (NULL == pair)
{
/* No translation found, print warning */
- printf("%s (No IANA name known to OpenVPN, use OpenSSL name.)\n", cipher_name);
+ printf("%s (No IANA name known to OpenVPN, use OpenSSL name.)\n",
+ cipher_name);
}
else
{
printf("%s\n", pair->iana_name);
}
-
}
- printf("\n" SHOW_TLS_CIPHER_LIST_WARNING);
-
+#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL)
+ sk_SSL_CIPHER_free(sk);
+#endif
SSL_free(ssl);
SSL_CTX_free(tls_ctx.ctx);
}