• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

KDECore

kssld.cpp
Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE libraries
00003 
00004    Copyright (c) 2007, 2008, 2010 Andreas Hartmetz <ahartmetz@gmail.com>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 
00021 */
00022 
00023 #include "kssld.h"
00024 
00025 #include "ksslcertificatemanager.h"
00026 #include "kssld_adaptor.h"
00027 
00028 #include <kconfig.h>
00029 #include <kconfiggroup.h>
00030 #include <QtCore/QFile>
00031 #include <kglobal.h>
00032 #include <kstandarddirs.h>
00033 #include <kdebug.h>
00034 #include <QtCore/QDate>
00035 #include <kpluginfactory.h>
00036 #include <kpluginloader.h>
00037 
00038 
00039 
00040 K_PLUGIN_FACTORY(KSSLDFactory, registerPlugin<KSSLD>();)
00041 K_EXPORT_PLUGIN(KSSLDFactory("kssld"))
00042 //KDE_EXPORT void *__kde_do_unload; // TODO re-add support for this?
00043 
00044 
00045 class KSSLDPrivate
00046 {
00047 public:
00048     KSSLDPrivate()
00049      : config(QString::fromLatin1("ksslcertificatemanager"), KConfig::SimpleConfig)
00050     {
00051         struct strErr {
00052             const char *str;
00053             KSslError::Error err;
00054         };
00055 
00056         //hmmm, looks like these are all of the errors where it is possible to continue.
00057         const static strErr strError[] = {
00058             {"NoError", KSslError::NoError},
00059             {"UnknownError", KSslError::UnknownError},
00060             {"InvalidCertificateAuthority", KSslError::InvalidCertificateAuthorityCertificate},
00061             {"InvalidCertificate", KSslError::InvalidCertificate},
00062             {"CertificateSignatureFailed", KSslError::CertificateSignatureFailed},
00063             {"SelfSignedCertificate", KSslError::SelfSignedCertificate},
00064             {"RevokedCertificate", KSslError::RevokedCertificate},
00065             {"InvalidCertificatePurpose", KSslError::InvalidCertificatePurpose},
00066             {"RejectedCertificate", KSslError::RejectedCertificate},
00067             {"UntrustedCertificate", KSslError::UntrustedCertificate},
00068             {"ExpiredCertificate", KSslError::ExpiredCertificate},
00069             {"HostNameMismatch", KSslError::HostNameMismatch}
00070         };
00071 
00072         for (int i = 0; i < int(sizeof(strError)/sizeof(strErr)); i++) {
00073             QString s = QString::fromLatin1(strError[i].str);
00074             KSslError::Error e = strError[i].err;
00075             stringToSslError.insert(s, e);
00076             sslErrorToString.insert(e, s);
00077         }
00078     }
00079 
00080     KConfig config;
00081     QHash<QString, KSslError::Error> stringToSslError;
00082     QHash<KSslError::Error, QString> sslErrorToString;
00083 };
00084 
00085 
00086 
00087 KSSLD::KSSLD(QObject* parent, const QVariantList&)
00088  : KDEDModule(parent),
00089    d(new KSSLDPrivate())
00090 {
00091     new KSSLDAdaptor(this);
00092     pruneExpiredRules();
00093 }
00094 
00095 
00096 KSSLD::~KSSLD()
00097 {
00098     delete d;
00099 }
00100 
00101 
00102 void KSSLD::setRule(const KSslCertificateRule &rule)
00103 {
00104     if (rule.hostName().isEmpty()) {
00105         return;
00106     }
00107     KConfigGroup group = d->config.group(rule.certificate().digest().toHex());
00108 
00109     QStringList sl;
00110 
00111     QString dtString = QString::fromLatin1("ExpireUTC ");
00112     dtString.append(rule.expiryDateTime().toString(Qt::ISODate));
00113     sl.append(dtString);
00114 
00115     if (rule.isRejected()) {
00116         sl.append(QString::fromLatin1("Reject"));
00117     } else {
00118         foreach (KSslError::Error e, rule.ignoredErrors())
00119             sl.append(d->sslErrorToString.value(e));
00120     }
00121 
00122     if (!group.hasKey("CertificatePEM"))
00123         group.writeEntry("CertificatePEM", rule.certificate().toPem());
00124 #ifdef PARANOIA
00125     else
00126         if (group.readEntry("CertificatePEM") != rule.certificate().toPem())
00127             return;
00128 #endif
00129     group.writeEntry(rule.hostName(), sl);
00130     group.sync();
00131 }
00132 
00133 
00134 void KSSLD::clearRule(const KSslCertificateRule &rule)
00135 {
00136     clearRule(rule.certificate(), rule.hostName());
00137 }
00138 
00139 
00140 void KSSLD::clearRule(const QSslCertificate &cert, const QString &hostName)
00141 {
00142     KConfigGroup group = d->config.group(cert.digest().toHex());
00143     group.deleteEntry(hostName);
00144     if (group.keyList().size() < 2) {
00145         group.deleteGroup();
00146     }
00147     group.sync();
00148 }
00149 
00150 
00151 void KSSLD::pruneExpiredRules()
00152 {
00153     // expired rules are deleted when trying to load them, so we just try to load all rules.
00154     // be careful about iterating over KConfig(Group) while changing it
00155     foreach (const QString &groupName, d->config.groupList()) {
00156         QByteArray certDigest = groupName.toLatin1();
00157         foreach (const QString &key, d->config.group(groupName).keyList()) {
00158             if (key == QLatin1String("CertificatePEM")) {
00159                 continue;
00160             }
00161             KSslCertificateRule r = rule(certDigest, key);
00162         }
00163     }
00164 }
00165 
00166 
00167 // check a domain name with subdomains for well-formedness and count the dot-separated parts
00168 static QString normalizeSubdomains(const QString &hostName, int *namePartsCount)
00169 {
00170     QString ret;
00171     int partsCount = 0;
00172     bool wasPrevDot = true; // -> allow no dot at the beginning and count first name part
00173     const int length = hostName.length();
00174     for (int i = 0; i < length; i++) {
00175         const QChar c = hostName.at(i);
00176         if (c == QLatin1Char('.')) {
00177             if (wasPrevDot || (i + 1 == hostName.length())) {
00178                 // consecutive dots or a dot at the end are forbidden
00179                 partsCount = 0;
00180                 ret.clear();
00181                 break;
00182             }
00183             wasPrevDot = true;
00184         } else {
00185             if (wasPrevDot) {
00186                 partsCount++;
00187             }
00188             wasPrevDot = false;
00189         }
00190         ret.append(c);
00191     }
00192 
00193     *namePartsCount = partsCount;
00194     return ret;
00195 }
00196 
00197 
00198 KSslCertificateRule KSSLD::rule(const QSslCertificate &cert, const QString &hostName) const
00199 {
00200     const QByteArray certDigest = cert.digest().toHex();
00201     KConfigGroup group = d->config.group(certDigest);
00202 
00203     KSslCertificateRule ret(cert, hostName);
00204     bool foundHostName = false;
00205 
00206     int needlePartsCount;
00207     QString needle = normalizeSubdomains(hostName, &needlePartsCount);
00208 
00209     // Find a rule for the hostname, either...
00210     if (group.hasKey(needle)) {
00211       // directly (host, site.tld, a.site.tld etc)
00212       if (needlePartsCount >= 1) {
00213         foundHostName = true;
00214       }
00215     } else {
00216         // or with wildcards
00217         //   "tld" <- "*." and "site.tld" <- "*.tld" are not valid matches,
00218         //   "a.site.tld" <- "*.site.tld" is
00219         while (--needlePartsCount >= 2) {
00220             const int dotIndex = needle.indexOf(QLatin1Char('.'));
00221             Q_ASSERT(dotIndex > 0); // if this fails normalizeSubdomains() failed
00222             needle.remove(0, dotIndex - 1);
00223             needle[0] = QChar::fromLatin1('*');
00224             if (group.hasKey(needle)) {
00225                 foundHostName = true;
00226                 break;
00227             }
00228             needle.remove(0, 2);    // remove "*."
00229         }
00230     }
00231 
00232     if (!foundHostName) {
00233         //Don't make a rule with the failed wildcard pattern - use the original hostname.
00234         return KSslCertificateRule(cert, hostName);
00235     }
00236 
00237     //parse entry of the format "ExpireUTC <date>, Reject" or
00238     //"ExpireUTC <date>, HostNameMismatch, ExpiredCertificate, ..."
00239     QStringList sl = group.readEntry(needle, QStringList());
00240 
00241     QDateTime expiryDt;
00242     // the rule is well-formed if it contains at least the expire date and one directive
00243     if (sl.size() >= 2) {
00244         QString dtString = sl.takeFirst();
00245         if (dtString.startsWith(QLatin1String("ExpireUTC "))) {
00246             dtString.remove(0, 10/* length of "ExpireUTC " */);
00247             expiryDt = QDateTime::fromString(dtString, Qt::ISODate);
00248         }
00249     }
00250 
00251     if (!expiryDt.isValid() || expiryDt < QDateTime::currentDateTime()) {
00252         //the entry is malformed or expired so we remove it
00253         group.deleteEntry(needle);
00254         //the group is useless once only the CertificatePEM entry left
00255         if (group.keyList().size() < 2) {
00256             group.deleteGroup();
00257         }
00258         return ret;
00259     }
00260 
00261     QList<KSslError::Error> ignoredErrors;
00262     bool isRejected = false;
00263     foreach (const QString &s, sl) {
00264         if (s == QLatin1String("Reject")) {
00265             isRejected = true;
00266             ignoredErrors.clear();
00267             break;
00268         }
00269         if (!d->stringToSslError.contains(s)) {
00270             continue;
00271         }
00272         ignoredErrors.append(d->stringToSslError.value(s));
00273     }
00274 
00275     //Everything is checked and we can make ret valid
00276     ret.setExpiryDateTime(expiryDt);
00277     ret.setRejected(isRejected);
00278     ret.setIgnoredErrors(ignoredErrors);
00279     return ret;
00280 }
00281 
00282 
00283 #include "kssld.moc"
00284 #include "kssld_adaptor.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:49:32 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal