[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    branches/KDE/4.2/kdelibs/kio/kio
From:       Roland Harnau <truthandprogress () googlemail ! com>
Date:       2009-02-26 13:44:48
Message-ID: 1235655888.959334.5577.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 932373 by rharnau:

Make Konqueror show correct information about whether a SSL certificate is
trusted in its SSL Information dialog. For this the matching of host name \
and certificate has do be done before the meta data is sent.

BUG: 182805

 M  +80 -79    tcpslavebase.cpp  


--- branches/KDE/4.2/kdelibs/kio/kio/tcpslavebase.cpp #932372:932373
@@ -103,6 +103,8 @@
 class TCPSlaveBase::TcpSlaveBasePrivate
 {
 public:
+    TcpSlaveBasePrivate(TCPSlaveBase* qq) : q(qq) {}
+
     QList<KSslError> nonIgnorableErrors(const QList<KSslError> &/*e*/) \
const  {
         QList<KSslError> ret;
@@ -110,6 +112,55 @@
         return ret;
     }
 
+    void prepareSslRelatedMetaData()
+    {
+        KSslCipher cipher = socket.sessionCipher();
+        q->setMetaData("ssl_protocol_version", \
socket.negotiatedSslVersionName()); +        QString sslCipher = \
cipher.encryptionMethod() + '\n'; +        sslCipher += \
cipher.authenticationMethod() + '\n'; +        sslCipher += \
cipher.keyExchangeMethod() + '\n'; +        sslCipher += \
cipher.digestMethod(); +        q->setMetaData("ssl_cipher", sslCipher);
+        q->setMetaData("ssl_cipher_used_bits", \
QString::number(cipher.usedBits())); +        \
q->setMetaData("ssl_cipher_bits", QString::number(cipher.supportedBits())); \
+        q->setMetaData("ssl_peer_ip", ip); +
+        // try to fill in the blanks, i.e. missing certificates, and just \
assume that +        // those belong to the peer (==website or similar) \
certificate. +        for (int i = 0; i < sslErrors.count(); i++) {
+            if (sslErrors[i].certificate().isNull()) {
+                sslErrors[i] = KSslError(sslErrors[i].error(),
+                                        socket.peerCertificateChain()[0]);
+            }
+        }
+
+        QString errorStr;
+        // encode the two-dimensional numeric error list using '\n' and \
'\t' as outer and inner separators +        foreach (const QSslCertificate \
&cert, socket.peerCertificateChain()) { +            foreach (const \
KSslError &error, sslErrors) { +                if (error.certificate() == \
cert) { +                    errorStr += \
QString::number(static_cast<int>(error.error())) + '\t'; +                }
+            }
+            if (errorStr.endsWith('\t')) {
+                errorStr.chop(1);
+            }
+            errorStr += '\n';
+        }
+        errorStr.chop(1);
+        q->setMetaData("ssl_cert_errors", errorStr);
+
+        QString peerCertChain;
+        foreach (const QSslCertificate &cert, \
socket.peerCertificateChain()) { +            \
peerCertChain.append(cert.toPem()); +            \
peerCertChain.append('\x01'); +        }
+        peerCertChain.chop(1);
+        q->setMetaData("ssl_peer_chain", peerCertChain);
+    }
+
+    TCPSlaveBase* q;
+
     int timeout;
     bool isBlocking;
 
@@ -125,6 +176,7 @@
     bool autoSSL;
     bool sslNoUi; // If true, we just drop the connection silently
                   // if SSL certificate check fails in some way.
+    QList<KSslError> sslErrors;
 };
 
 
@@ -140,7 +192,7 @@
                            const QByteArray &appSocket,
                            bool autoSSL)
  : SlaveBase(protocol, poolSocket, appSocket),
-   d(new TcpSlaveBasePrivate)
+   d(new TcpSlaveBasePrivate(this))
 {
     d->timeout = KProtocolManager::connectTimeout();
     d->isBlocking = true;
@@ -441,50 +493,31 @@
                  << " supportedBits:" << cipher.supportedBits()
                  << " usedBits:" << cipher.usedBits();
 
-    setMetaData("ssl_protocol_version", \
                d->socket.negotiatedSslVersionName());
-    QString sslCipher = cipher.encryptionMethod() + '\n';
-    sslCipher += cipher.authenticationMethod() + '\n';
-    sslCipher += cipher.keyExchangeMethod() + '\n';
-    sslCipher += cipher.digestMethod();
-    setMetaData("ssl_cipher", sslCipher);
-    setMetaData("ssl_cipher_used_bits", \
                QString::number(cipher.usedBits()));
-    setMetaData("ssl_cipher_bits", \
                QString::number(cipher.supportedBits()));
-    setMetaData("ssl_peer_ip", d->ip);
-
-    // try to fill in the blanks, i.e. missing certificates, and just \
                assume that
-    // those belong to the peer (==website or similar) certificate.
-    QList<KSslError> sslErrors = d->socket.sslErrors();
-    for (int i = 0; i < sslErrors.count(); i++) {
-        if (sslErrors[i].certificate().isNull()) {
-            sslErrors[i] = KSslError(sslErrors[i].error(),
-                                     d->socket.peerCertificateChain()[0]);
+    // Since we connect by IP (cf. KIO::HostInfo) the SSL code will not \
recognize +    // that the site certificate belongs to the domain. We \
therefore do the +    // 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;
         }
-    }
-
-    QString errorStr;
-    // encode the two-dimensional numeric error list using '\n' and '\t' \
                as outer and inner separators
-    foreach (const QSslCertificate &cert, \
                d->socket.peerCertificateChain()) {                         \
                
-        foreach (const KSslError &error, sslErrors) {
-            if (error.certificate() == cert) {
-                errorStr += \
QString::number(static_cast<int>(error.error())) + '\t'; +        foreach \
(const QString &dp, domainPatterns) { +            \
domainMatcher.setPattern(dp); +            if \
(domainMatcher.exactMatch(d->host)) { +                it.remove();
             }
         }
-        if (errorStr.endsWith('\t')) {
-            errorStr.chop(1);
-        }
-        errorStr += '\n';
     }
-    errorStr.chop(1);
-    setMetaData("ssl_cert_errors", errorStr);
 
-    QString peerCertChain;
-    foreach (const QSslCertificate &cert, \
                d->socket.peerCertificateChain()) {
-        peerCertChain.append(cert.toPem());
-        peerCertChain.append('\x01');
-    }
-    peerCertChain.chop(1);
-    setMetaData("ssl_peer_chain", peerCertChain);
-
     // 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
     // may actually be connected to a different application that doesn't \
know @@ -493,6 +526,7 @@
     // from here, for example. And Konqi will be the second application to \
connect  // to the slave.
     // Therefore we choose to have our metadata and send it, too :)
+    d->prepareSslRelatedMetaData();
     sendAndKeepMetaData();
 
     SslResult rc = verifyServerCertificate();
@@ -529,7 +563,6 @@
     return rc;
 }
 
-
 void TCPSlaveBase::selectClientCertificate()
 {
 #if 0 //hehe
@@ -701,50 +734,19 @@
 #endif
 }
 
-
 TCPSlaveBase::SslResult TCPSlaveBase::verifyServerCertificate()
 {
     d->sslNoUi = hasMetaData("ssl_no_ui") && (metaData("ssl_no_ui") != \
"FALSE");  
-    QList<KSslError> se = d->socket.sslErrors();
-    if (se.isEmpty())
+    if (d->sslErrors.isEmpty())
         return ResultOk;
-
-    // Since we connect by IP (cf. KIO::HostInfo) the SSL code will not \
                recognize
-    // that the site certificate belongs to the domain. We therefore do \
                the
-    // domain<->certificate matching here.
-
-    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(se);
-    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;
-        }
-        foreach (const QString &dp, domainPatterns) {
-            domainMatcher.setPattern(dp);
-            if (domainMatcher.exactMatch(d->host)) {
-                it.remove();
-            }
-        }
-    }
-
-    if (se.isEmpty())
-        return ResultOk;
-
     if (d->sslNoUi)
         return ResultFailed;
 
     QString message = i18n("The server failed the authenticity check \
(%1).\n\n",  d->host);
 
-    foreach (const KSslError &err, se) {
+    foreach (const KSslError &err, d->sslErrors) {
         //### use our own wording that is "closer to the user"
         message.append(err.errorString());
         message.append('\n');
@@ -753,7 +755,6 @@
     //### Consider that hostname mismatch and e.g. an expired certificate \
                are very different.
     //    Maybe there should be no option to acceptForever a cert with bad \
hostname.  
-
     /* We need a list of ignorable errors. I don't think it makes sense to \
                ignore
        malformed certificates, for example, as other environments probably \
                don't do
        that either. It would be similar to a compiler trying to correct \
syntax errors. @@ -768,15 +769,15 @@
     KSslCertificateRule rule = \
cm->rule(d->socket.peerCertificateChain().first(), d->host);  
     //TODO put nonIgnorableErrors into the cert manager
-    QList<KSslError> fatalErrors = d->nonIgnorableErrors(se);
+    QList<KSslError> fatalErrors = d->nonIgnorableErrors(d->sslErrors);
     if (!fatalErrors.isEmpty()) {
         //TODO message "sorry, fatal error, you can't override it"
         return ResultFailed;
     }
 
     //throw out previously seen errors that are supposed to be ignored.
-    se = rule.filterErrors(se);
-    if (se.isEmpty()) {
+    QList<KSslError> remainingErrors = rule.filterErrors(d->sslErrors);
+    if (remainingErrors.isEmpty()) {
         kDebug(7029) << "Error list empty after removing errors to be \
ignored. Continuing.";  return ResultOk | ResultOverridden;
     }
@@ -820,7 +821,7 @@
     //rule = KSslCertificateRule(d->socket.peerCertificateChain().first(), \
whatever);  
     rule.setExpiryDateTime(ruleExpiry);
-    rule.setIgnoredErrors(se);
+    rule.setIgnoredErrors(remainingErrors);
     cm->setRule(rule);
 
     return ResultOk | ResultOverridden;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic