Hi,
Thanks for last and final v4 :)
On Fri, Jan 19, 2018 at 4:27 PM, Steffan Karger <stef...@karger.me> wrote:
> As described in <80e6b449-c536-dc87-7215-3693872bc...@birkenwald.de> on
> the openvpn-devel mailing list, --tls-version-min no longer works with
> OpenSSL 1.1. Kurt Roeckx posted in a debian bug report:
>
> "This is marked as important because if you switch to openssl 1.1.0
> the defaults minimum version in Debian is currently TLS 1.2 and
> you can't override it with the options that you're currently using
> (and are deprecated)."
>
> This patch is loosely based on the original patch by Kurt, but solves the
> issue by adding functions to openssl-compat.h, like we also did for all
> other openssl 1.1. breakage. This results in not having to add more ifdefs
> in ssl_openssl.c and thus cleaner code.
>
> Signed-off-by: Steffan Karger <stef...@karger.me>
> ---
> v2: fix define name, obey system lib default minimum version
> v3: add error handling, fix bug in setting default minimum
> v4: also update compat layer for v3 changes
>
> src/openvpn/openssl_compat.h | 67 +++++++++++++++++++++++++++++
> src/openvpn/ssl.c | 5 ++-
> src/openvpn/ssl_backend.h | 4 +-
> src/openvpn/ssl_mbedtls.c | 3 +-
> src/openvpn/ssl_openssl.c | 100 +++++++++++++++++++++++++++---
> -------------
> 5 files changed, 140 insertions(+), 39 deletions(-)
>
> diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
> index 05ec4e95..9f1e92a1 100644
> --- a/src/openvpn/openssl_compat.h
> +++ b/src/openvpn/openssl_compat.h
> @@ -661,4 +661,71 @@ EC_GROUP_order_bits(const EC_GROUP *group)
> #define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT
> RSA_F_RSA_EAY_PRIVATE_ENCRYPT
> #endif
>
> +#ifndef SSL_CTX_get_min_proto_version
> +/** Dummy SSL_CTX_get_min_proto_version for OpenSSL < 1.1 (not really
> needed) */
> +static inline int
> +SSL_CTX_get_min_proto_version(SSL_CTX *ctx)
> +{
> + return 0;
> +}
> +#endif /* SSL_CTX_get_min_proto_version */
> +
> +#ifndef SSL_CTX_set_min_proto_version
> +/** Mimics SSL_CTX_set_min_proto_version for OpenSSL < 1.1 */
> +static inline int
> +SSL_CTX_set_min_proto_version(SSL_CTX *ctx, long tls_ver_min)
> +{
> + long sslopt = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; /* Never do < TLS
> 1.0 */
> +
> + if (tls_ver_min > TLS1_VERSION)
> + {
> + sslopt |= SSL_OP_NO_TLSv1;
> + }
> +#ifdef SSL_OP_NO_TLSv1_1
> + if (tls_ver_min > TLS1_1_VERSION)
> + {
> + sslopt |= SSL_OP_NO_TLSv1_1;
> + }
> +#endif
> +#ifdef SSL_OP_NO_TLSv1_2
> + if (tls_ver_min > TLS1_2_VERSION)
> + {
> + sslopt |= SSL_OP_NO_TLSv1_2;
> + }
> +#endif
> + SSL_CTX_set_options(ctx, sslopt);
> +
> + return 1;
> +}
> +#endif /* SSL_CTX_set_min_proto_version */
> +
> +#ifndef SSL_CTX_set_max_proto_version
> +/** Mimics SSL_CTX_set_max_proto_version for OpenSSL < 1.1 */
> +static inline int
> +SSL_CTX_set_max_proto_version(SSL_CTX *ctx, long tls_ver_max)
> +{
> + long sslopt = 0;
> +
> + if (tls_ver_max < TLS1_VERSION)
> + {
> + sslopt |= SSL_OP_NO_TLSv1;
> + }
> +#ifdef SSL_OP_NO_TLSv1_1
> + if (tls_ver_max < TLS1_1_VERSION)
> + {
> + sslopt |= SSL_OP_NO_TLSv1_1;
> + }
> +#endif
> +#ifdef SSL_OP_NO_TLSv1_2
> + if (tls_ver_max < TLS1_2_VERSION)
> + {
> + sslopt |= SSL_OP_NO_TLSv1_2;
> + }
> +#endif
> + SSL_CTX_set_options(ctx, sslopt);
> +
> + return 1;
> +}
> +#endif /* SSL_CTX_set_max_proto_version */
> +
> #endif /* OPENSSL_COMPAT_H_ */
> diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
> index 7b428455..6c27050f 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -622,7 +622,10 @@ init_ssl(const struct options *options, struct
> tls_root_ctx *new_ctx)
> * cipher restrictions before loading certificates */
> tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
>
> - tls_ctx_set_options(new_ctx, options->ssl_flags);
> + if (!tls_ctx_set_options(new_ctx, options->ssl_flags))
> + {
> + goto err;
> + }
>
> if (options->pkcs12_file)
> {
> diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
> index 7cf5d830..444fb2f9 100644
> --- a/src/openvpn/ssl_backend.h
> +++ b/src/openvpn/ssl_backend.h
> @@ -162,8 +162,10 @@ bool tls_ctx_initialised(struct tls_root_ctx *ctx);
> *
> * @param ctx TLS context to set options on
> * @param ssl_flags SSL flags to set
> + *
> + * @return true on success, false otherwise.
> */
> -void tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int
> ssl_flags);
> +bool tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int
> ssl_flags);
>
> /**
> * Restrict the list of ciphers that can be used within the TLS context.
> diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c
> index 8ac52d55..d503162a 100644
> --- a/src/openvpn/ssl_mbedtls.c
> +++ b/src/openvpn/ssl_mbedtls.c
> @@ -206,9 +206,10 @@ key_state_export_keying_material(struct
> key_state_ssl *ssl,
> {
> }
>
> -void
> +bool
> tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
> {
> + return true;
> }
>
> static const char *
> diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
> index 86318d4c..50d68280 100644
> --- a/src/openvpn/ssl_openssl.c
> +++ b/src/openvpn/ssl_openssl.c
> @@ -206,16 +206,65 @@ 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_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;
> + }
> + 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,41 +272,18 @@ 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
> - sslopt |= SSL_OP_NO_COMPRESSION;
> - SSL_CTX_set_options(ctx->ctx, sslopt);
> + sslopt |= SSL_OP_NO_COMPRESSION;
> +
> + SSL_CTX_set_options(ctx->ctx, sslopt);
> +
> + if (!tls_ctx_set_tls_versions(ctx, ssl_flags))
> + {
> + return false;
> }
>
> #ifdef SSL_MODE_RELEASE_BUFFERS
> @@ -280,6 +306,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;
> }
>
Now I can tease patchwork by
Acked-by: Selva Nair <selva.n...@gmail.com>
Reviewed-by: Selva Nair <selva.n...@gmail.com>
Tested-by: Selva Nair <selva.n...@gmail.com>
Selva
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel