summaryrefslogtreecommitdiffstats
path: root/src/network/ssl/qsslconfiguration.cpp
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2019-10-30 11:49:07 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2019-12-03 18:06:02 +0100
commite5438e8ded27eb6f7f0e85704d6843069296c698 (patch)
tree5880a4534ffdf7aad181d35522c0d326536e1ad3 /src/network/ssl/qsslconfiguration.cpp
parent4c89005ebed79bb6ba871c407e6b8c2f8d982abf (diff)
QSslSocket (OpenSSL) improve alert messages handling
1. Add a new verification callback. This gives an option to report errors directly from this callback (by emitting handshakeInterruptedOnError()). This allows an application to explain to its peer why the handshake was interrupted (by sending a corresponding alert message). 2. This also means we want to notice such alerts (in Qt, from the application's point of view, they are mostly informational only, no interaction is required). So we also introduce a new 'info callback', that can notice alert messages read or written. We also introduce two new enums describing the level and type of an alert message. QSslSocket gets three new signals (for incoming/outgoing alerts and verification errors found early). 3. In case we requested a certificate, but the peer provided none, we would previously abruptly close the connection without a proper alert message (and such a situation is not handled by any verification callbacks, since there is no certificate(s) to verify essentially). So we now introduce a new verification option that maps to what OpenSSL calls 'SSL_VERIFY_FAIL_IF_NO_PEER_CERT'. This way, the proper alert will be generated. Fixes: QTBUG-68419 Change-Id: I5d1e9298b4040a2d4f867f5b1a3567a2253927b8 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/network/ssl/qsslconfiguration.cpp')
-rw-r--r--src/network/ssl/qsslconfiguration.cpp91
1 files changed, 89 insertions, 2 deletions
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 738c8d4ac5..b6199a2b16 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -222,7 +222,9 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
d->nextNegotiatedProtocol == other.d->nextNegotiatedProtocol &&
d->nextProtocolNegotiationStatus == other.d->nextProtocolNegotiationStatus &&
d->dtlsCookieEnabled == other.d->dtlsCookieEnabled &&
- d->ocspStaplingEnabled == other.d->ocspStaplingEnabled;
+ d->ocspStaplingEnabled == other.d->ocspStaplingEnabled &&
+ d->reportFromCallback == other.d->reportFromCallback &&
+ d->missingCertIsFatal == other.d->missingCertIsFatal;
}
/*!
@@ -267,7 +269,9 @@ bool QSslConfiguration::isNull() const
d->nextAllowedProtocols.isEmpty() &&
d->nextNegotiatedProtocol.isNull() &&
d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone &&
- d->ocspStaplingEnabled == false);
+ d->ocspStaplingEnabled == false &&
+ d->reportFromCallback == false &&
+ d->missingCertIsFatal == false);
}
/*!
@@ -1190,6 +1194,89 @@ bool QSslConfiguration::ocspStaplingEnabled() const
return d->ocspStaplingEnabled;
}
+/*!
+ \since 6.0
+
+ Returns true if a verification callback will emit QSslSocket::handshakeInterruptedOnError()
+ early, before concluding the handshake.
+
+ \note This function always returns false for all backends but OpenSSL.
+
+ \sa setHandshakeMustInterruptOnError(), QSslSocket::handshakeInterruptedOnError(), QSslSocket::continueInterruptedHandshake()
+*/
+bool QSslConfiguration::handshakeMustInterruptOnError() const
+{
+ return d->reportFromCallback;
+}
+
+/*!
+ \since 6.0
+
+ If \a interrupt is true and the underlying backend supports this option,
+ errors found during certificate verification are reported immediately
+ by emitting QSslSocket::handshakeInterruptedOnError(). This allows
+ to stop the unfinished handshake and send a proper alert message to
+ a peer. No special action is required from the application in this case.
+ QSslSocket will close the connection after sending the alert message.
+ If the application after inspecting the error wants to continue the
+ handshake, it must call QSslSocket::continueInterruptedHandshake()
+ from its slot function. The signal-slot connection must be direct.
+
+ \note When interrupting handshake is enabled, errors that would otherwise
+ be reported by QSslSocket::peerVerifyError() are instead only reported by
+ QSslSocket::handshakeInterruptedOnError().
+ \note Even if the handshake was continued, these errors will be
+ reported when emitting QSslSocket::sslErrors() signal (and thus must
+ be ignored in the corresponding function slot).
+
+ \sa handshakeMustInterruptOnError(), QSslSocket::handshakeInterruptedOnError(), QSslSocket::continueInterruptedHandshake()
+*/
+void QSslConfiguration::setHandshakeMustInterruptOnError(bool interrupt)
+{
+#if QT_CONFIG(openssl)
+ d->reportFromCallback = interrupt;
+#else
+ qCWarning(lcSsl, "This operation requires OpenSSL as TLS backend");
+#endif
+}
+
+/*!
+ \since 6.0
+
+ Returns true if errors with code QSslError::NoPeerCertificate
+ cannot be ignored.
+
+ \note Always returns false for all TLS backends but OpenSSL.
+
+ \sa QSslSocket::ignoreSslErrors(), setMissingCertificateIsFatal()
+*/
+bool QSslConfiguration::missingCertificateIsFatal() const
+{
+ return d->missingCertIsFatal;
+}
+
+/*!
+ \since 6.0
+
+ If \a cannotRecover is true, and verification mode in use is
+ QSslSocket::VerifyPeer or QSslSocket::AutoVerifyPeer (for a
+ client-side socket), the missing peer's certificate would be
+ treated as an unrecoverable error that cannot be ignored. A proper
+ alert message will be sent to the peer before closing the connection.
+
+ \note Only available if Qt was configured and built with OpenSSL backend.
+
+ \sa QSslSocket::ignoreSslErrors(), QSslSocket::PeerVerifyMode, missingCertificateIsFatal()
+*/
+void QSslConfiguration::setMissingCertificateIsFatal(bool cannotRecover)
+{
+#if QT_CONFIG(openssl)
+ d->missingCertIsFatal = cannotRecover;
+#else
+ qCWarning(lcSsl, "Handling a missing certificate as a fatal error requires an OpenSSL backend");
+#endif // openssl
+}
+
/*! \internal
*/
bool QSslConfigurationPrivate::peerSessionWasShared(const QSslConfiguration &configuration) {