File 551bfa12-ssl-wildcards.diff of Package kdelibs4

diff --git a/kio/kio/tcpslavebase.cpp b/kio/kio/tcpslavebase.cpp
index 84c9b82..8d66863 100644
--- a/kio/kio/tcpslavebase.cpp
+++ b/kio/kio/tcpslavebase.cpp
@@ -4,6 +4,7 @@
  * Copyright (C) 2001 Dawit Alemayehu <adawit@kde.org>
  * Copyright (C) 2007,2008 Andreas Hartmetz <ahartmetz@gmail.com>
  * Copyright (C) 2008 Roland Harnau <tau@gmx.eu>
+ * Copyright (C) 2010 Richard Moore <rich@kde.org>
  *
  * This file is part of the KDE project
  *
@@ -438,6 +439,49 @@ bool TCPSlaveBase::startSsl()
     return startTLSInternal(KTcpSocket::TlsV1) & ResultOk;
 }
 
+// Find out if a hostname matches an SSL certificate's Common Name (including wildcards)
+static bool isMatchingHostname(const QString &cnIn, const QString &hostnameIn)
+{
+    const QString cn = cnIn.toLower();
+    const QString hostname = hostnameIn.toLower();
+
+    const int wildcard = cn.indexOf(QLatin1Char('*'));
+
+    // Check this is a wildcard cert, if not then just compare the strings
+    if (wildcard < 0)
+        return cn == hostname;
+
+    const int firstCnDot = cn.indexOf(QLatin1Char('.'));
+    const int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1);
+
+    // Check at least 3 components
+    if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length()))
+        return false;
+
+    // Check * is last character of 1st component (ie. there's a following .)
+    if (wildcard+1 != firstCnDot)
+        return false;
+
+    // Check only one star
+    if (cn.lastIndexOf(QLatin1Char('*')) != wildcard)
+        return false;
+
+    // Check characters preceding * (if any) match
+    if (wildcard && (hostname.leftRef(wildcard) != cn.leftRef(wildcard)))
+        return false;
+
+    // Check characters following first . match
+    if (hostname.midRef(hostname.indexOf(QLatin1Char('.'))) != cn.midRef(firstCnDot))
+        return false;
+
+    // Check if the hostname is an IP address, if so then wildcards are not allowed
+    QHostAddress addr(hostname);
+    if (!addr.isNull())
+        return false;
+
+    // Ok, I guess this was a wildcard CN and the hostname matches.
+    return true;
+}
 
 TCPSlaveBase::SslResult TCPSlaveBase::startTLSInternal(uint v_)
 {
@@ -492,25 +536,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);
-    QRegExp domainMatcher(QString(), Qt::CaseInsensitive, QRegExp::Wildcard);
     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) {
-            domainMatcher.setPattern(dp);
-            if (domainMatcher.exactMatch(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
openSUSE Build Service is sponsored by