summaryrefslogtreecommitdiffstats
path: root/src/network/ssl/qsslsocket_openssl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/ssl/qsslsocket_openssl.cpp')
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp47
1 files changed, 45 insertions, 2 deletions
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)