1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
Origin: https://projects.kde.org/projects/kde/kdelibs/repository/revisions/3735e2ee
Description: Harden SSL verification against poisoned DNS attacks
... in the case of certificates that are issued against an IP address rather
than a hostname.
Patch by Tomas Hoger / Red Hat Security Response Team, reviewed by Jeff
Mitchell and Richard Moore.
--- a/kio/kio/tcpslavebase.cpp
+++ b/kio/kio/tcpslavebase.cpp
@@ -534,23 +534,34 @@ TCPSlaveBase::SslResult TCPSlaveBase::startTLSInternal(uint v_)
// domain<->certificate matching here.
d->sslErrors = d->socket.sslErrors();
QSslCertificate peerCert = d->socket.peerCertificateChain().first();
- QStringList domainPatterns(peerCert.subjectInfo(QSslCertificate::CommonName));
- domainPatterns += peerCert.alternateSubjectNames().values(QSsl::DnsEntry);
QMutableListIterator<KSslError> it(d->sslErrors);
while (it.hasNext()) {
// As of 4.4.0 Qt does not assign a certificate to the QSslError it emits
// *in the case of HostNameMismatch*. A HostNameMismatch, however, will always
// be an error of the peer certificate so we just don't check the error's
// certificate().
- if (it.next().error() != KSslError::HostNameMismatch) {
- continue;
+
+ // Remove all HostNameMismatch, we have to redo name checking later.
+ if (it.next().error() == KSslError::HostNameMismatch) {
+ it.remove();
}
- foreach (const QString &dp, domainPatterns) {
- if (isMatchingHostname(dp,d->host)) {
- it.remove();
- }
+ }
+ // Redo name checking here and (re-)insert HostNameMismatch to sslErrors if
+ // host name does not match any of the names in server certificate.
+ // QSslSocket may not report HostNameMismatch error, when server
+ // certificate was issued for the IP we are connecting to.
+ QStringList domainPatterns(peerCert.subjectInfo(QSslCertificate::CommonName));
+ domainPatterns += peerCert.alternateSubjectNames().values(QSsl::DnsEntry);
+ bool names_match = false;
+ foreach (const QString &dp, domainPatterns) {
+ if (isMatchingHostname(dp,d->host)) {
+ names_match = true;
+ break;
}
}
+ if (!names_match) {
+ d->sslErrors.insert(0, KSslError(KSslError::HostNameMismatch, peerCert));
+ }
// The app side needs the metadata now for the SSL error dialog (if any) but
// the same metadata will be needed later, too. When "later" arrives the slave
|