diff options
Diffstat (limited to 'src/network/ssl/qsslcontext_openssl11.cpp')
-rw-r--r-- | src/network/ssl/qsslcontext_openssl11.cpp | 104 |
1 files changed, 81 insertions, 23 deletions
diff --git a/src/network/ssl/qsslcontext_openssl11.cpp b/src/network/ssl/qsslcontext_openssl11.cpp index 708cb7bb0e..db023b7331 100644 --- a/src/network/ssl/qsslcontext_openssl11.cpp +++ b/src/network/ssl/qsslcontext_openssl11.cpp @@ -95,17 +95,34 @@ init_context: // SSL 2 is no longer supported, but chosen deliberately -> error sslContext->ctx = nullptr; unsupportedProtocol = true; + } else if (sslContext->sslConfiguration.protocol() == QSsl::SslV3) { + // SSL 3 is no longer supported, but chosen deliberately -> error + sslContext->ctx = nullptr; + unsupportedProtocol = true; } else { switch (sslContext->sslConfiguration.protocol()) { -#if QT_CONFIG(dtls) case QSsl::DtlsV1_0: case QSsl::DtlsV1_0OrLater: case QSsl::DtlsV1_2: case QSsl::DtlsV1_2OrLater: +#if QT_CONFIG(dtls) isDtls = true; sslContext->ctx = q_SSL_CTX_new(client ? q_DTLS_client_method() : q_DTLS_server_method()); - break; +#else // dtls + sslContext->ctx = nullptr; + unsupportedProtocol = true; + qCWarning(lcSsl, "DTLS protocol requested, but feature 'dtls' is disabled"); + #endif // dtls + break; + case QSsl::TlsV1_3: + case QSsl::TlsV1_3OrLater: +#if !defined(TLS1_3_VERSION) + qCWarning(lcSsl, "TLS 1.3 is not supported"); + sslContext->ctx = nullptr; + unsupportedProtocol = true; + break; +#endif // TLS1_3_VERSION default: // The ssl options will actually control the supported methods sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method()); @@ -138,11 +155,6 @@ init_context: long maxVersion = anyVersion; 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; @@ -155,12 +167,19 @@ init_context: minVersion = TLS1_2_VERSION; maxVersion = TLS1_2_VERSION; break; + case QSsl::TlsV1_3: +#ifdef TLS1_3_VERSION + minVersion = TLS1_3_VERSION; + maxVersion = TLS1_3_VERSION; +#else + // This protocol is not supported by OpenSSL 1.1 and we handle + // it as an error (see the code above). + Q_UNREACHABLE(); +#endif // TLS1_3_VERSION + break; // Ranges: case QSsl::TlsV1SslV3: case QSsl::AnyProtocol: - minVersion = SSL3_VERSION; - maxVersion = 0; - break; case QSsl::SecureProtocols: case QSsl::TlsV1_0OrLater: minVersion = TLS1_VERSION; @@ -174,7 +193,6 @@ init_context: minVersion = TLS1_2_VERSION; maxVersion = 0; break; -#if QT_CONFIG(dtls) case QSsl::DtlsV1_0: minVersion = DTLS1_VERSION; maxVersion = DTLS1_VERSION; @@ -191,12 +209,23 @@ init_context: minVersion = DTLS1_2_VERSION; maxVersion = DTLS_MAX_VERSION; break; -#endif // dtls - case QSsl::SslV2: + case QSsl::TlsV1_3OrLater: +#ifdef TLS1_3_VERSION + minVersion = TLS1_3_VERSION; + maxVersion = 0; + break; +#else // This protocol is not supported by OpenSSL 1.1 and we handle // it as an error (see the code above). Q_UNREACHABLE(); break; +#endif // TLS1_3_VERSION + case QSsl::SslV2: + case QSsl::SslV3: + // These protocols are not supported, and we handle + // them as an error (see the code above). + Q_UNREACHABLE(); + break; case QSsl::UnknownProtocol: break; } @@ -223,23 +252,52 @@ init_context: // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS); + auto filterCiphers = [](const QList<QSslCipher> &ciphers, bool selectTls13) + { + QByteArray cipherString; + bool first = true; + + for (const QSslCipher &cipher : qAsConst(ciphers)) { + const bool isTls13Cipher = cipher.protocol() == QSsl::TlsV1_3 || cipher.protocol() == QSsl::TlsV1_3OrLater; + if (selectTls13 != isTls13Cipher) + continue; + + if (first) + first = false; + else + cipherString.append(':'); + cipherString.append(cipher.name().toLatin1()); + } + return cipherString; + }; + // Initialize ciphers - QByteArray cipherString; - bool first = true; QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers(); if (ciphers.isEmpty()) ciphers = isDtls ? q_getDefaultDtlsCiphers() : QSslSocketPrivate::defaultCiphers(); - for (const QSslCipher &cipher : qAsConst(ciphers)) { - if (first) - first = false; - else - cipherString.append(':'); - cipherString.append(cipher.name().toLatin1()); + const QByteArray preTls13Ciphers = filterCiphers(ciphers, false); + + if (preTls13Ciphers.size()) { + if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, preTls13Ciphers.data())) { + sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); + sslContext->errorCode = QSslError::UnspecifiedError; + return; + } } - if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, cipherString.data())) { - sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); + const QByteArray tls13Ciphers = filterCiphers(ciphers, true); +#ifdef TLS1_3_VERSION + if (tls13Ciphers.size()) { + if (!q_SSL_CTX_set_ciphersuites(sslContext->ctx, tls13Ciphers.data())) { + sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); + sslContext->errorCode = QSslError::UnspecifiedError; + return; + } + } +#endif // TLS1_3_VERSION + if (!preTls13Ciphers.size() && !tls13Ciphers.size()) { + sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QStringLiteral("")); sslContext->errorCode = QSslError::UnspecifiedError; return; } |