Hi, On 19-01-18 19:05, Selva Nair wrote: > The patch is good except for some issues that are easy to fix: > > On Sat, Dec 30, 2017 at 6:02 AM, 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: > > I did not see this behaviour in locally built openssl 1.1, and so did > some digging.. > > Our current approach still works on stock-built openssl 1.1 (though > deprecated). > But some distros (e.g., Debian unstable) are patching openssl-1.1 to set > TLS 1.2 as the default min version. That can be over-ridden only using the > new min/max_proto_version API calls. Debian has recently backed-off on this, > but distros restricting TLS versions is something we need to cope with.
Ah, that explains why tincantech couldn't reproduce the original issue while testing! > Even otherwise directly setting the min/max values is better. And the old and > new methods do not work well together. So this change is good to have, > independent of the target OS/distro. > > Anyway, I want to use this in the cryptoapi patch: why else would anyone do > the > thankless reviewing job :) So let me thank you right here for reviewing! >> "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 >> >> Note: this patch does not cherry-pick to release/2.4 nicely. Once the one >> for master has been accepted, I'll send a backport for release/2.4. >> >> src/openvpn/openssl_compat.h | 63 ++++++++++++++++++++++++++++++++ >> src/openvpn/ssl_openssl.c | 86 >> +++++++++++++++++++++++++------------------- >> 2 files changed, 113 insertions(+), 36 deletions(-) >> >> diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h >> index 70b19aea..2a6c98d9 100644 >> --- a/src/openvpn/openssl_compat.h >> +++ b/src/openvpn/openssl_compat.h >> @@ -647,4 +647,67 @@ 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 void >> +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); >> +} >> +#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 void >> +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); >> +} >> +#endif /* SSL_CTX_set_max_proto_version */ >> + >> #endif /* OPENSSL_COMPAT_H_ */ >> diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c >> index 34c31b9d..9d5cd5ec 100644 >> --- a/src/openvpn/ssl_openssl.c >> +++ b/src/openvpn/ssl_openssl.c >> @@ -206,15 +206,56 @@ 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 >> } >> >> +/** 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 void >> +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 ? TLS_VER_1_0 : cur_min; > > That should be > > tls_ver_min = cur_min < TLS1_VERSION ? TLS1_VERSION : cur_min; Oh, darn, indeed. >> + } >> + SSL_CTX_set_min_proto_version(ctx->ctx, tls_ver_min); > > This call can potentially fail in openssl 1.1, though unlikely. As a > sane minimum is > important, we should check the return value and do something sensible with it. > Actually it does fail with the above bug and it could fail in some > other convoluted > situations. Will fix. >> + >> + if (tls_ver_max) >> + { >> + SSL_CTX_set_max_proto_version(ctx->ctx, tls_ver_max); > > This also can potentially fail. Not critical unlike the minimum value, > but still a check of the return value and a helpful error message is useful. Will fix too. >> + } >> +} >> + >> void >> tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) >> { >> @@ -223,42 +264,15 @@ 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); >> + >> + tls_ctx_set_tls_versions(ctx, ssl_flags); >> >> #ifdef SSL_MODE_RELEASE_BUFFERS >> SSL_CTX_set_mode(ctx->ctx, SSL_MODE_RELEASE_BUFFERS); >> -- > > Debian has recently (Nov 2017) back-tracked on setting 1.2 as the default > min version, so testing against the original bug report is now hard. > > But this passes my tests with custom built openssl and a recently updated > debian unstable installation (after the bug fix mentioned above). > > Finally, there is a minor issue with openssl 1.1's macros for > SSL_CTX_get_min/max_proto_version (long argument passed a NULL) but I > think we can live with the compiler warning until they fix it upstream. tincantech reported this too, so I created a pull request: https://github.com/openssl/openssl/pull/5099 v3 coming soon. Thanks, -Steffan ------------------------------------------------------------------------------ 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