diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/qnetworkreplywasmimpl.cpp | 30 | ||||
-rw-r--r-- | src/network/kernel/qauthenticator.cpp | 23 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 47 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_p.h | 7 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_symbols.cpp | 13 |
5 files changed, 102 insertions, 18 deletions
diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index 505db44522..2ee57a0860 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -308,12 +308,6 @@ void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bu downloadBuffer.append(buffer, bufferSize); emit q->readyRead(); - - if (downloadBufferCurrentSize == totalDownloadSize) { - q->setFinished(true); - emit q->readChannelFinished(); - emit q->finished(); - } } //taken from qnetworkrequest.cpp @@ -446,13 +440,25 @@ void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingData() void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch) { auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); - if (!reply || reply->state == QNetworkReplyPrivate::Aborted) - return; - QByteArray buffer(fetch->data, fetch->numBytes); - reply->dataReceived(buffer, buffer.size()); - + if (reply) { + if (reply->state != QNetworkReplyPrivate::Aborted) { + QByteArray buffer(fetch->data, fetch->numBytes); + reply->dataReceived(buffer, buffer.size()); + QByteArray statusText(fetch->statusText); + reply->setStatusCode(fetch->status, statusText); + reply->setReplyFinished(); + } + reply->m_fetch = nullptr; + } emscripten_fetch_close(fetch); - reply->m_fetch = nullptr; +} + +void QNetworkReplyWasmImplPrivate::setReplyFinished() +{ + Q_Q(QNetworkReplyWasmImpl); + q->setFinished(true); + emit q->readChannelFinished(); + emit q->finished(); } void QNetworkReplyWasmImplPrivate::setStatusCode(int status, const QByteArray &statusText) diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index 86242b011f..d9fe7bc47b 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -423,6 +423,22 @@ void QAuthenticatorPrivate::updateCredentials() } } +static bool verifyDigestMD5(const QByteArray &value) +{ + auto opts = QAuthenticatorPrivate::parseDigestAuthenticationChallenge(value); + auto it = opts.constFind("algorithm"); + if (it != opts.cend()) { + QByteArray alg = it.value(); + if (alg.size() < 3) + return false; + // Just compare the first 3 characters, that way we match other subvariants as well, such as + // "MD5-sess" + auto view = QByteArray::fromRawData(alg.data(), 3); + return view.compare("MD5", Qt::CaseInsensitive) == 0; + } + return true; // assume it's ok if algorithm is not specified +} + void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy, const QString &host) { #if !QT_CONFIG(gssapi) @@ -454,8 +470,13 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt method = Ntlm; headerVal = current.second.mid(5); } else if (method < DigestMd5 && str.startsWith("digest")) { + // Make sure the algorithm is actually MD5 before committing to it: + QByteArray fieldValue = current.second.mid(7); + if (!verifyDigestMD5(fieldValue)) + continue; + method = DigestMd5; - headerVal = current.second.mid(7); + headerVal = fieldValue; } else if (method < Negotiate && str.startsWith("negotiate")) { #if QT_CONFIG(sspi) || QT_CONFIG(gssapi) // if it's not supported then we shouldn't try to use it #if QT_CONFIG(gssapi) diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 3d3fd88c40..37fad2a68f 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -462,7 +462,7 @@ bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert, const QSharedPointer<OCSP_CERTID> guard(recreatedId, q_OCSP_CERTID_free); if (q_OCSP_id_cmp(const_cast<OCSP_CERTID *>(certId), recreatedId)) { - qDebug(lcSsl, "Certificate ID mismatch"); + qCDebug(lcSsl, "Certificate ID mismatch"); return false; } // Bingo! @@ -491,8 +491,23 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx) // during a handshake, a pointer to the SSL object is stored into the X509_STORE_CTX object // to identify the connection affected. To retrieve this pointer the X509_STORE_CTX_get_ex_data() // function can be used with the correct index." - if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()))) + if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data( + ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()))) { + + // We may be in a renegotiation, check if we are inside a call to SSL_read: + const auto tlsOffset = QSslSocketBackendPrivate::s_indexForSSLExtraData; + auto tls = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, tlsOffset)); + Q_ASSERT(tls); + if (tls->isInSslRead()) { + // We are in a renegotiation, make a note of this for later. + // We'll check that the certificate is the same as the one we got during + // the initial handshake + tls->setRenegotiated(true); + return 1; + } + errors = ErrorListPtr(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData + 1)); + } } if (!errors) { @@ -1156,7 +1171,25 @@ void QSslSocketBackendPrivate::transmit() break; } // Don't use SSL_pending(). It's very unreliable. + inSslRead = true; readBytes = q_SSL_read(ssl, buffer.reserve(bytesToRead), bytesToRead); + inSslRead = false; + if (renegotiated) { + renegotiated = false; + X509 *x509 = q_SSL_get_peer_certificate(ssl); + const auto peerCertificate = + QSslCertificatePrivate::QSslCertificate_from_X509(x509); + // Fail the renegotiate if the certificate has changed, else: continue. + if (peerCertificate != q->peerCertificate()) { + const ScopedBool bg(inSetAndEmitError, true); + setErrorAndEmit( + QAbstractSocket::RemoteHostClosedError, + QSslSocket::tr( + "TLS certificate unexpectedly changed during renegotiation!")); + q->abort(); + return; + } + } if (readBytes > 0) { #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: decrypted" << readBytes << "bytes"; @@ -1600,6 +1633,16 @@ unsigned int QSslSocketBackendPrivate::tlsPskServerCallback(const char *identity return pskLength; } +bool QSslSocketBackendPrivate::isInSslRead() const +{ + return inSslRead; +} + +void QSslSocketBackendPrivate::setRenegotiated(bool renegotiated) +{ + this->renegotiated = renegotiated; +} + #ifdef Q_OS_WIN void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert) diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index 67f267aec1..4103de23e8 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -134,6 +134,9 @@ public: bool inSetAndEmitError = false; + bool inSslRead = false; + bool renegotiated = false; + // Platform specific functions void startClientEncryption() override; void startServerEncryption() override; @@ -149,6 +152,10 @@ public: int handleNewSessionTicket(SSL *context); unsigned int tlsPskClientCallback(const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len); unsigned int tlsPskServerCallback(const char *identity, unsigned char *psk, unsigned int max_psk_len); + + bool isInSslRead() const; + void setRenegotiated(bool renegotiated); + #ifdef Q_OS_WIN void fetchCaRootForCert(const QSslCertificate &cert); void _q_caRootLoaded(QSslCertificate,QSslCertificate) override; diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index 368e25345f..e53fb279f0 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -675,7 +675,14 @@ static LoadedOpenSsl loadOpenSsl() LoadedOpenSsl result; // With OpenSSL 1.1 the names have changed to libssl-1_1 and libcrypto-1_1 for builds using - // MSVC and GCC, with architecture suffixes for non-x86 builds. + // MSVC and GCC. For 3.0 the version suffix changed again, to just '3'. + // For non-x86 builds, an architecture suffix is also appended. + +#if (OPENSSL_VERSION_NUMBER >> 28) < 3 +#define QT_OPENSSL_VERSION "1_1" +#elif OPENSSL_VERSION_MAJOR == 3 // Starting with 3.0 this define is available +#define QT_OPENSSL_VERSION "3" +#endif // > 3 intentionally left undefined #if defined(Q_PROCESSOR_X86_64) #define QT_SSL_SUFFIX "-x64" @@ -687,8 +694,8 @@ static LoadedOpenSsl loadOpenSsl() #define QT_SSL_SUFFIX #endif - tryToLoadOpenSslWin32Library(QLatin1String("libssl-1_1" QT_SSL_SUFFIX), - QLatin1String("libcrypto-1_1" QT_SSL_SUFFIX), result); + tryToLoadOpenSslWin32Library(QLatin1String("libssl-" QT_OPENSSL_VERSION QT_SSL_SUFFIX), + QLatin1String("libcrypto-" QT_OPENSSL_VERSION QT_SSL_SUFFIX), result); #undef QT_SSL_SUFFIX return result; |