diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index 85d1a99c45..51779dec33 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -117,7 +117,7 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl"); Describes the protocol of the cipher. \value SslV3 SSLv3. When using the WinRT backend this option will also enable TLSv1.0 - \value SslV2 SSLv2 + \value SslV2 SSLv2. Note, SSLv2 support was removed in OpenSSL 1.1. \value TlsV1_0 TLSv1.0 \value TlsV1_0OrLater TLSv1.0 and later versions. This option is not available when using the WinRT backend due to platform limitations. \value TlsV1 Obsolete, means the same as TlsV1_0 @@ -126,8 +126,8 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl"); \value TlsV1_2 TLSv1.2. When using the WinRT backend this option will also enable TLSv1.0 and TLSv1.1. \value TlsV1_2OrLater TLSv1.2 and later versions. This option is not available when using the WinRT backend due to platform limitations. \value UnknownProtocol The cipher's protocol cannot be determined. - \value AnyProtocol The socket understands SSLv2, SSLv3, and TLSv1.0. This - value is used by QSslSocket only. + \value AnyProtocol The socket understands SSLv2, SSLv3, TLSv1.0 and all + supported later versions of TLS. This value is used by QSslSocket only. \value TlsV1SslV3 On the client side, this will send a TLS 1.0 Client Hello, enabling TLSv1_0 and SSLv3 connections. On the server side, this will enable both SSLv3 and TLSv1_0 connections. diff --git a/src/network/ssl/qsslcontext_openssl11.cpp b/src/network/ssl/qsslcontext_openssl11.cpp index 7be7be46b8..5c68ed41db 100644 --- a/src/network/ssl/qsslcontext_openssl11.cpp +++ b/src/network/ssl/qsslcontext_openssl11.cpp @@ -100,6 +100,68 @@ init_context: return; } + long minVersion = TLS_ANY_VERSION; + long maxVersion = TLS_ANY_VERSION; + switch (sslContext->sslConfiguration.protocol()) { + // The single-protocol versions first: + case QSsl::SslV3: + minVersion = SSL3_VERSION; + maxVersion = SSL3_VERSION; + break; + case QSsl::TlsV1_0: + minVersion = TLS1_VERSION; + maxVersion = TLS1_VERSION; + break; + case QSsl::TlsV1_1: + minVersion = TLS1_1_VERSION; + maxVersion = TLS1_1_VERSION; + break; + case QSsl::TlsV1_2: + minVersion = TLS1_2_VERSION; + maxVersion = TLS1_2_VERSION; + break; + // Ranges: + case QSsl::TlsV1SslV3: + case QSsl::AnyProtocol: + minVersion = SSL3_VERSION; + maxVersion = TLS_MAX_VERSION; + break; + case QSsl::SecureProtocols: + case QSsl::TlsV1_0OrLater: + minVersion = TLS1_VERSION; + maxVersion = TLS_MAX_VERSION; + break; + case QSsl::TlsV1_1OrLater: + minVersion = TLS1_1_VERSION; + maxVersion = TLS_MAX_VERSION; + break; + case QSsl::TlsV1_2OrLater: + minVersion = TLS1_2_VERSION; + maxVersion = TLS_MAX_VERSION; + break; + case QSsl::SslV2: + // This protocol is not supported by OpenSSL 1.1 and we handle + // it as an error (see the code above). + Q_UNREACHABLE(); + break; + case QSsl::UnknownProtocol: + break; + } + + if (minVersion != TLS_ANY_VERSION + && !q_SSL_CTX_set_min_proto_version(sslContext->ctx, minVersion)) { + sslContext->errorStr = QSslSocket::tr("Error while setting the minimal protocol version"); + sslContext->errorCode = QSslError::UnspecifiedError; + return; + } + + if (maxVersion != TLS_ANY_VERSION + && !q_SSL_CTX_set_max_proto_version(sslContext->ctx, maxVersion)) { + sslContext->errorStr = QSslSocket::tr("Error while setting the maximum protocol version"); + sslContext->errorCode = QSslError::UnspecifiedError; + return; + } + // Enable bug workarounds. long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions); q_SSL_CTX_set_options(sslContext->ctx, options); diff --git a/src/network/ssl/qsslsocket_openssl11_symbols_p.h b/src/network/ssl/qsslsocket_openssl11_symbols_p.h index 2980b3d23e..ac8d46ce6d 100644 --- a/src/network/ssl/qsslsocket_openssl11_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl11_symbols_p.h @@ -129,4 +129,10 @@ const char *q_OpenSSL_version(int type); unsigned long q_SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session); +#define q_SSL_CTX_set_min_proto_version(ctx, version) \ + q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, nullptr) + +#define q_SSL_CTX_set_max_proto_version(ctx, version) \ + q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, nullptr) + #endif diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index 1332b369e7..bb01116240 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -1188,13 +1188,7 @@ void tst_QSslSocket::protocolServerSide_data() #if !defined(OPENSSL_NO_SSL2) // OpenSSL 1.1 has removed SSL2 support. But there is no OPENSSL_NO_SSL2 macro ... #define OPENSSL_NO_SSL2 -#endif - // A client using our OpenSSL1.1 backend will negotiate up from TLS 1.0 or 1.1 - // to TLS 1.2 if the server asks for it, where our older backend fails to compromise. - // So some tests that fail for the old pass with the new. - const bool willUseTLS12 = true; -#else - const bool willUseTLS12 = false; +#endif // OPENSSL_NO_SSL2 #endif // opensslv11 #if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) @@ -1290,7 +1284,7 @@ void tst_QSslSocket::protocolServerSide_data() QTest::newRow("tls1.1orlater-ssl3") << QSsl::TlsV1_1OrLater << QSsl::SslV3 << false; #endif - QTest::newRow("tls1.1orlater-tls1.0") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_0 << willUseTLS12; + QTest::newRow("tls1.1orlater-tls1.0") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_0 << false; QTest::newRow("tls1.1orlater-tls1.1") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_1 << true; QTest::newRow("tls1.1orlater-tls1.2") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_2 << true; @@ -1300,8 +1294,8 @@ void tst_QSslSocket::protocolServerSide_data() #if !defined(OPENSSL_NO_SSL3) QTest::newRow("tls1.2orlater-ssl3") << QSsl::TlsV1_2OrLater << QSsl::SslV3 << false; #endif - QTest::newRow("tls1.2orlater-tls1.0") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_0 << willUseTLS12; - QTest::newRow("tls1.2orlater-tls1.1") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_1 << willUseTLS12; + QTest::newRow("tls1.2orlater-tls1.0") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_0 << false; + QTest::newRow("tls1.2orlater-tls1.1") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_1 << false; QTest::newRow("tls1.2orlater-tls1.2") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_2 << true; QTest::newRow("any-tls1.0") << QSsl::AnyProtocol << QSsl::TlsV1_0 << true;