[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