diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 70893afcde..d8f291b9c7 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -232,6 +232,40 @@ static int q_X509Callback(int ok, X509_STORE_CTX *ctx) return 1; } +long QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions) +{ + long options; + if (protocol == QSsl::TlsV1SslV3 || protocol == QSsl::SecureProtocols) + options = SSL_OP_ALL|SSL_OP_NO_SSLv2; + else + options = SSL_OP_ALL; + + // This option is disabled by default, so we need to be able to clear it + if (sslOptions & QSsl::SslOptionDisableEmptyFragments) + options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + else + options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + +#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION + // This option is disabled by default, so we need to be able to clear it + if (sslOptions & QSsl::SslOptionDisableLegacyRenegotiation) + options &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; + else + options |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; +#endif + +#ifdef SSL_OP_NO_TICKET + if (sslOptions & QSsl::SslOptionDisableSessionTickets) + options |= SSL_OP_NO_TICKET; +#endif +#ifdef SSL_OP_NO_COMPRESSION + if (sslOptions & QSsl::SslOptionDisableCompression) + options |= SSL_OP_NO_COMPRESSION; +#endif + + return options; +} + bool QSslSocketBackendPrivate::initSslContext() { Q_Q(QSslSocket); @@ -275,35 +309,7 @@ init_context: } // Enable bug workarounds. - long options; - if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols) - options = SSL_OP_ALL|SSL_OP_NO_SSLv2; - else - options = SSL_OP_ALL; - - // This option is disabled by default, so we need to be able to clear it - if (configuration.sslOptions & QSsl::SslOptionDisableEmptyFragments) - options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; - else - options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; - -#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION - // This option is disabled by default, so we need to be able to clear it - if (configuration.sslOptions & QSsl::SslOptionDisableLegacyRenegotiation) - options &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; - else - options |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; -#endif - -#ifdef SSL_OP_NO_TICKET - if (configuration.sslOptions & QSsl::SslOptionDisableSessionTickets) - options |= SSL_OP_NO_TICKET; -#endif -#ifdef SSL_OP_NO_COMPRESSION - if (configuration.sslOptions & QSsl::SslOptionDisableCompression) - options |= SSL_OP_NO_COMPRESSION; -#endif - + long options = setupOpenSslOptions(configuration.protocol, configuration.sslOptions); q_SSL_CTX_set_options(ctx, options); // Initialize ciphers diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index c4b9018db7..ef00b0998d 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -118,6 +118,7 @@ public: void disconnected(); QSslCipher sessionCipher() const; + Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions); static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher); static QList STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509); static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName); diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index d9ea400d0a..27bfeb7933 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -192,6 +192,7 @@ private slots: void blacklistedCertificates(); void setEmptyDefaultConfiguration(); void versionAccessors(); + void sslOptions(); static void exitLoop() { @@ -2052,6 +2053,48 @@ void tst_QSslSocket::versionAccessors() qDebug() << QString::number(QSslSocket::sslLibraryVersionNumber(), 16); } +void tst_QSslSocket::sslOptions() +{ + if (!QSslSocket::supportsSsl()) + return; + + QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, + QSsl::SslOptionDisableEmptyFragments + |QSsl::SslOptionDisableLegacyRenegotiation), + long(SSL_OP_ALL|SSL_OP_NO_SSLv2)); + +#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION + QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, + QSsl::SslOptionDisableEmptyFragments), + long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))); +#endif + +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, + QSsl::SslOptionDisableLegacyRenegotiation), + long((SSL_OP_ALL|SSL_OP_NO_SSLv2) & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)); +#endif + +#ifdef SSL_OP_NO_TICKET + QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, + QSsl::SslOptionDisableEmptyFragments + |QSsl::SslOptionDisableLegacyRenegotiation + |QSsl::SslOptionDisableSessionTickets), + long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET))); +#endif + +#ifdef SSL_OP_NO_TICKET +#ifdef SSL_OP_NO_COMPRESSION + QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, + QSsl::SslOptionDisableEmptyFragments + |QSsl::SslOptionDisableLegacyRenegotiation + |QSsl::SslOptionDisableSessionTickets + |QSsl::SslOptionDisableCompression), + long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET|SSL_OP_NO_COMPRESSION))); +#endif +#endif +} + #endif // QT_NO_OPENSSL QTEST_MAIN(tst_QSslSocket)