diff options
Diffstat (limited to 'kio/kssl/ksslpeerinfo.cc')
-rw-r--r-- | kio/kssl/ksslpeerinfo.cc | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/kio/kssl/ksslpeerinfo.cc b/kio/kssl/ksslpeerinfo.cc new file mode 100644 index 000000000..8be542425 --- /dev/null +++ b/kio/kssl/ksslpeerinfo.cc @@ -0,0 +1,171 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2000-2003 George Staikos <staikos@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qregexp.h> + +#include "ksslpeerinfo.h" +#include <kdebug.h> + +#include <ksockaddr.h> +#include <kextsock.h> +#include <netsupp.h> +#ifndef Q_WS_WIN //TODO kresolver not ported +#include "kresolver.h" +#endif + +#include "ksslx509map.h" + +class KSSLPeerInfoPrivate { +public: + KSSLPeerInfoPrivate() {} + ~KSSLPeerInfoPrivate() { } + QString peerHost; +}; + + + +KSSLPeerInfo::KSSLPeerInfo() { + d = new KSSLPeerInfoPrivate; +} + +KSSLPeerInfo::~KSSLPeerInfo() { + delete d; +} + +KSSLCertificate& KSSLPeerInfo::getPeerCertificate() { + return m_cert; +} + +void KSSLPeerInfo::setPeerHost(QString realHost) { + d->peerHost = realHost.stripWhiteSpace(); + while(d->peerHost.endsWith(".")) + d->peerHost.truncate(d->peerHost.length()-1); + +#ifdef Q_WS_WIN //TODO kresolver not ported + d->peerHost = d->peerHost.lower(); +#else + d->peerHost = QString::fromLatin1(KNetwork::KResolver::domainToAscii(d->peerHost)); +#endif +} + +bool KSSLPeerInfo::certMatchesAddress() { +#ifdef KSSL_HAVE_SSL + KSSLX509Map certinfo(m_cert.getSubject()); + QStringList cns = QStringList::split(QRegExp("[ \n\r]"), certinfo.getValue("CN")); + cns += m_cert.subjAltNames(); + + for (QStringList::Iterator cn = cns.begin(); cn != cns.end(); ++cn) { + if (cnMatchesAddress((*cn).stripWhiteSpace().lower())) + return true; + } + +#endif + + return false; +} + + +bool KSSLPeerInfo::cnMatchesAddress(QString cn) { +#ifdef KSSL_HAVE_SSL + QRegExp rx; + + kdDebug(7029) << "Matching CN=[" << cn << "] to [" + << d->peerHost << "]" << endl; + + // Check for invalid characters + if (QRegExp("[^a-zA-Z0-9\\.\\*\\-]").search(cn) >= 0) { + kdDebug(7029) << "CN contains invalid characters! Failing." << endl; + return false; + } + + // Domains can legally end with '.'s. We don't need them though. + while(cn.endsWith(".")) + cn.truncate(cn.length()-1); + + // Do not let empty CN's get by!! + if (cn.isEmpty()) + return false; + + // Check for IPv4 address + rx.setPattern("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"); + if (rx.exactMatch(d->peerHost)) + return d->peerHost == cn; + + // Check for IPv6 address here... + rx.setPattern("^\\[.*\\]$"); + if (rx.exactMatch(d->peerHost)) + return d->peerHost == cn; + + if (cn.contains('*')) { + // First make sure that there are at least two valid parts + // after the wildcard (*). + QStringList parts = QStringList::split('.', cn, false); + + while (parts.count() > 2) + parts.remove(parts.begin()); + + if (parts.count() != 2) { + return false; // we don't allow *.root - that's bad + } + + if (parts[0].contains('*') || parts[1].contains('*')) { + return false; + } + + // RFC2818 says that *.example.com should match against + // foo.example.com but not bar.foo.example.com + // (ie. they must have the same number of parts) + if (QRegExp(cn, false, true).exactMatch(d->peerHost) && + QStringList::split('.', cn, false).count() == + QStringList::split('.', d->peerHost, false).count()) + return true; + + // *.example.com must match example.com also. Sigh.. + if (cn.startsWith("*.")) { + QString chopped = cn.mid(2); + if (chopped == d->peerHost) { + return true; + } + } + return false; + } + + // We must have an exact match in this case (insensitive though) + // (note we already did .lower()) + if (cn == d->peerHost) + return true; +#endif + return false; +} + + +void KSSLPeerInfo::reset() { + d->peerHost = QString::null; +} + + +const QString& KSSLPeerInfo::peerHost() const { + return d->peerHost; +} + |