diff options
Diffstat (limited to 'kio/misc/kssld')
-rw-r--r-- | kio/misc/kssld/Makefile.am | 33 | ||||
-rw-r--r-- | kio/misc/kssld/kssld.cpp | 1027 | ||||
-rw-r--r-- | kio/misc/kssld/kssld.desktop | 156 | ||||
-rw-r--r-- | kio/misc/kssld/kssld.h | 154 |
4 files changed, 1370 insertions, 0 deletions
diff --git a/kio/misc/kssld/Makefile.am b/kio/misc/kssld/Makefile.am new file mode 100644 index 000000000..63252f46c --- /dev/null +++ b/kio/misc/kssld/Makefile.am @@ -0,0 +1,33 @@ +# This file is part of the KDE libraries +# Copyright (C) 2001 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. + +INCLUDES= -I$(srcdir)/.. -I$(top_srcdir) $(SSL_INCLUDES) -I$(top_srcdir)/kio/kssl -I$(top_builddir)/kio/kssl $(all_includes) + +kde_module_LTLIBRARIES = kded_kssld.la + +kded_kssld_la_LDFLAGS = $(all_libraries) -module -avoid-version +kded_kssld_la_LIBADD = $(LIB_KIO) $(LIB_KDED) +kded_kssld_la_SOURCES = kssld.cpp kssld.skel + +METASOURCES = AUTO + +noinst_HEADERS = kssld.h + +services_DATA = kssld.desktop +servicesdir = $(kde_servicesdir)/kded + diff --git a/kio/misc/kssld/kssld.cpp b/kio/misc/kssld/kssld.cpp new file mode 100644 index 000000000..ff96681e2 --- /dev/null +++ b/kio/misc/kssld/kssld.cpp @@ -0,0 +1,1027 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2001-2005 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 <qtimer.h> + +#include "kssld.h" +#include <kconfig.h> +#include <ksimpleconfig.h> +#include <ksslcertchain.h> +#include <ksslcertificate.h> +#include <ksslcertificatehome.h> +#include <ksslpkcs12.h> +#include <ksslx509map.h> +#include <qptrlist.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <pwd.h> +#include <unistd.h> +#include <qfile.h> +#include <qsortedlist.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <qdatetime.h> + +#include <kmdcodec.h> +#include <kopenssl.h> + +// See design notes at end + +extern "C" { + KDE_EXPORT KDEDModule *create_kssld(const QCString &name) { + return new KSSLD(name); + } + + KDE_EXPORT void *__kde_do_unload; +} + + +static void updatePoliciesConfig(KConfig *cfg) { + QStringList groups = cfg->groupList(); + + for (QStringList::Iterator i = groups.begin(); i != groups.end(); ++i) { + if ((*i).isEmpty() || *i == "General") { + continue; + } + + cfg->setGroup(*i); + + // remove it if it has expired + if (!cfg->readBoolEntry("Permanent") && cfg->readDateTimeEntry("Expires") < QDateTime::currentDateTime()) { + cfg->deleteGroup(*i); + continue; + } + + QString encodedCertStr = cfg->readEntry("Certificate"); + QCString encodedCert = encodedCertStr.local8Bit(); + KSSLCertificate *newCert = KSSLCertificate::fromString(encodedCert); + if (!newCert) { + cfg->deleteGroup(*i); + continue; + } + + KSSLCertificateCache::KSSLCertificatePolicy policy = (KSSLCertificateCache::KSSLCertificatePolicy) cfg->readNumEntry("Policy"); + bool permanent = cfg->readBoolEntry("Permanent"); + QDateTime expires = cfg->readDateTimeEntry("Expires"); + QStringList hosts = cfg->readListEntry("Hosts"); + QStringList chain = cfg->readListEntry("Chain"); + cfg->deleteGroup(*i); + + cfg->setGroup(newCert->getMD5Digest()); + cfg->writeEntry("Certificate", encodedCertStr); + cfg->writeEntry("Policy", policy); + cfg->writeEntry("Permanent", permanent); + cfg->writeEntry("Expires", expires); + cfg->writeEntry("Hosts", hosts); + cfg->writeEntry("Chain", chain); + delete newCert; + } + + cfg->setGroup("General"); + cfg->writeEntry("policies version", 2); + + cfg->sync(); +} + + +KSSLD::KSSLD(const QCString &name) : KDEDModule(name) +{ +// ----------------------- FOR THE CACHE ------------------------------------ + cfg = new KSimpleConfig("ksslpolicies", false); + cfg->setGroup("General"); + if (2 != cfg->readNumEntry("policies version", 0)) { + ::updatePoliciesConfig(cfg); + } + KGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl"); + caVerifyUpdate(); + cacheLoadDefaultPolicies(); + certList.setAutoDelete(false); + kossl = KOSSL::self(); + +// ----------------------- FOR THE HOME ------------------------------------- +} + + +KSSLD::~KSSLD() +{ +// ----------------------- FOR THE CACHE ------------------------------------ + cacheClearList(); + delete cfg; + +// ----------------------- FOR THE HOME ------------------------------------- +} + + + + +// A node in the cache +class KSSLCNode { + public: + KSSLCertificate *cert; + KSSLCertificateCache::KSSLCertificatePolicy policy; + bool permanent; + QDateTime expires; + QStringList hosts; + KSSLCNode() { cert = 0L; + policy = KSSLCertificateCache::Unknown; + permanent = true; + } + ~KSSLCNode() { delete cert; } +}; + + + +void KSSLD::cacheSaveToDisk() { +KSSLCNode *node; + + cfg->setGroup("General"); + cfg->writeEntry("policies version", 2); + + for (node = certList.first(); node; node = certList.next()) { + if (node->permanent || + node->expires > QDateTime::currentDateTime()) { + // First convert to a binary format and then write the + // kconfig entry write the (CN, policy, cert) to + // KSimpleConfig + cfg->setGroup(node->cert->getMD5Digest()); + cfg->writeEntry("Certificate", node->cert->toString()); + cfg->writeEntry("Policy", node->policy); + cfg->writeEntry("Expires", node->expires); + cfg->writeEntry("Permanent", node->permanent); + cfg->writeEntry("Hosts", node->hosts); + + // Also write the chain + QStringList qsl; + QPtrList<KSSLCertificate> cl = + node->cert->chain().getChain(); + for (KSSLCertificate *c = cl.first(); + c != 0; + c = cl.next()) { + //kdDebug() << "Certificate in chain: " + // << c->toString() << endl; + qsl << c->toString(); + } + + cl.setAutoDelete(true); + cfg->writeEntry("Chain", qsl); + } + } + + cfg->sync(); + + // insure proper permissions -- contains sensitive data + QString cfgName(KGlobal::dirs()->findResource("config", "ksslpolicies")); + + if (!cfgName.isEmpty()) { + ::chmod(QFile::encodeName(cfgName), 0600); + } +} + + +void KSSLD::cacheReload() { + cacheClearList(); + delete cfg; + cfg = new KSimpleConfig("ksslpolicies", false); + cacheLoadDefaultPolicies(); +} + + +void KSSLD::cacheClearList() { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + certList.remove(node); + delete node; + } + + skEmail.clear(); + skMD5Digest.clear(); +} + + +void KSSLD::cacheLoadDefaultPolicies() { +QStringList groups = cfg->groupList(); + + for (QStringList::Iterator i = groups.begin(); + i != groups.end(); + ++i) { + if ((*i).isEmpty() || *i == "General") { + continue; + } + + cfg->setGroup(*i); + + // remove it if it has expired + if (!cfg->readBoolEntry("Permanent") && + cfg->readDateTimeEntry("Expires") < + QDateTime::currentDateTime()) { + cfg->deleteGroup(*i); + continue; + } + + QCString encodedCert; + KSSLCertificate *newCert; + + encodedCert = cfg->readEntry("Certificate").local8Bit(); + newCert = KSSLCertificate::fromString(encodedCert); + + if (!newCert) { + continue; + } + + KSSLCNode *n = new KSSLCNode; + n->cert = newCert; + n->policy = (KSSLCertificateCache::KSSLCertificatePolicy) cfg->readNumEntry("Policy"); + n->permanent = cfg->readBoolEntry("Permanent"); + n->expires = cfg->readDateTimeEntry("Expires"); + n->hosts = cfg->readListEntry("Hosts"); + newCert->chain().setCertChain(cfg->readListEntry("Chain")); + certList.append(n); + searchAddCert(newCert); + } +} + + +void KSSLD::cacheAddCertificate(KSSLCertificate cert, + KSSLCertificateCache::KSSLCertificatePolicy policy, + bool permanent) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + node->policy = policy; + node->permanent = permanent; + + if (!permanent) { + node->expires = QDateTime::currentDateTime(); + // FIXME: make this configurable + node->expires = node->expires.addSecs(3600); + } + + cacheSaveToDisk(); + return; + } + } + + KSSLCNode *n = new KSSLCNode; + n->cert = cert.replicate(); + n->policy = policy; + n->permanent = permanent; + // remove the old one + cacheRemoveByCertificate(*(n->cert)); + certList.prepend(n); + + if (!permanent) { + n->expires = QDateTime::currentDateTime(); + n->expires = n->expires.addSecs(3600); + } + + searchAddCert(n->cert); + cacheSaveToDisk(); +} + + +KSSLCertificateCache::KSSLCertificatePolicy KSSLD::cacheGetPolicyByCN(QString cn) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) { + if (!node->permanent && + node->expires < QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + delete node; + continue; + } + + certList.remove(node); + certList.prepend(node); + cacheSaveToDisk(); + return node->policy; + } + } + + cacheSaveToDisk(); + +return KSSLCertificateCache::Unknown; +} + + +KSSLCertificateCache::KSSLCertificatePolicy KSSLD::cacheGetPolicyByCertificate(KSSLCertificate cert) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + if (!node->permanent && + node->expires < QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + delete node; + cacheSaveToDisk(); + return KSSLCertificateCache::Unknown; + } + + certList.remove(node); + certList.prepend(node); + return node->policy; + } + } + +return KSSLCertificateCache::Unknown; +} + + +bool KSSLD::cacheSeenCN(QString cn) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) { + if (!node->permanent && + node->expires < QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + delete node; + cacheSaveToDisk(); + continue; + } + + certList.remove(node); + certList.prepend(node); + return true; + } + } + +return false; +} + + +bool KSSLD::cacheSeenCertificate(KSSLCertificate cert) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + if (!node->permanent && + node->expires < QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + delete node; + cacheSaveToDisk(); + return false; + } + + certList.remove(node); + certList.prepend(node); + return true; + } + } + +return false; +} + + +bool KSSLD::cacheIsPermanent(KSSLCertificate cert) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + if (!node->permanent && node->expires < + QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + delete node; + cacheSaveToDisk(); + return false; + } + + certList.remove(node); + certList.prepend(node); + return node->permanent; + } + } + +return false; +} + + +bool KSSLD::cacheRemoveBySubject(QString subject) { +KSSLCNode *node; +bool gotOne = false; + + for (node = certList.first(); node; node = certList.next()) { + if (node->cert->getSubject() == subject) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + searchRemoveCert(node->cert); + delete node; + gotOne = true; + } + } + + cacheSaveToDisk(); + +return gotOne; +} + + +bool KSSLD::cacheRemoveByCN(QString cn) { +KSSLCNode *node; +bool gotOne = false; + + for (node = certList.first(); node; node = certList.next()) { + if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + searchRemoveCert(node->cert); + delete node; + gotOne = true; + } + } + + cacheSaveToDisk(); + +return gotOne; +} + + +bool KSSLD::cacheRemoveByCertificate(KSSLCertificate cert) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + searchRemoveCert(node->cert); + delete node; + cacheSaveToDisk(); + return true; + } + } + +return false; +} + + +bool KSSLD::cacheModifyByCN(QString cn, + KSSLCertificateCache::KSSLCertificatePolicy policy, bool permanent, + QDateTime expires) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) { + node->permanent = permanent; + node->expires = expires; + node->policy = policy; + certList.remove(node); + certList.prepend(node); + cacheSaveToDisk(); + return true; + } + } + +return false; +} + + +bool KSSLD::cacheModifyByCertificate(KSSLCertificate cert, + KSSLCertificateCache::KSSLCertificatePolicy policy, + bool permanent, + QDateTime expires) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + node->permanent = permanent; + node->expires = expires; + node->policy = policy; + certList.remove(node); + certList.prepend(node); + cacheSaveToDisk(); + return true; + } + } + +return false; +} + + +QStringList KSSLD::cacheGetHostList(KSSLCertificate cert) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + if (!node->permanent && node->expires < + QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + searchRemoveCert(node->cert); + delete node; + cacheSaveToDisk(); + return QStringList(); + } + + certList.remove(node); + certList.prepend(node); + return node->hosts; + } + } + +return QStringList(); +} + + +bool KSSLD::cacheAddHost(KSSLCertificate cert, QString host) { +KSSLCNode *node; + + if (host.isEmpty()) + return true; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + if (!node->permanent && node->expires < + QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + searchRemoveCert(node->cert); + delete node; + cacheSaveToDisk(); + return false; + } + + if (!node->hosts.contains(host)) { + node->hosts << host; + } + + certList.remove(node); + certList.prepend(node); + cacheSaveToDisk(); + return true; + } + } + +return false; +} + + +bool KSSLD::cacheRemoveHost(KSSLCertificate cert, QString host) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + if (!node->permanent && node->expires < + QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + searchRemoveCert(node->cert); + delete node; + cacheSaveToDisk(); + return false; + } + node->hosts.remove(host); + certList.remove(node); + certList.prepend(node); + cacheSaveToDisk(); + return true; + } + } + +return false; +} + + + + +/////////////////////////////////////////////////////////////////////////// + +void KSSLD::caVerifyUpdate() { + QString path = KGlobal::dirs()->saveLocation("kssl") + "/ca-bundle.crt"; + if (!QFile::exists(path)) + return; + + cfg->setGroup(QString::null); + Q_UINT32 newStamp = KGlobal::dirs()->calcResourceHash("config", "ksslcalist", true); + Q_UINT32 oldStamp = cfg->readUnsignedNumEntry("ksslcalistStamp"); + if (oldStamp != newStamp) + { + caRegenerate(); + cfg->writeEntry("ksslcalistStamp", newStamp); + cfg->sync(); + } +} + +bool KSSLD::caRegenerate() { +QString path = KGlobal::dirs()->saveLocation("kssl") + "/ca-bundle.crt"; + +QFile out(path); + + if (!out.open(IO_WriteOnly)) + return false; + +KConfig cfg("ksslcalist", true, false); + +QStringList x = cfg.groupList(); + + for (QStringList::Iterator i = x.begin(); + i != x.end(); + ++i) { + if ((*i).isEmpty() || *i == "<default>") continue; + + cfg.setGroup(*i); + + if (!cfg.readBoolEntry("site", false)) continue; + + QString cert = cfg.readEntry("x509", ""); + if (cert.length() <= 0) continue; + + unsigned int xx = cert.length() - 1; + for (unsigned int j = 0; j < xx/64; j++) { + cert.insert(64*(j+1)+j, '\n'); + } + out.writeBlock("-----BEGIN CERTIFICATE-----\n", 28); + out.writeBlock(cert.latin1(), cert.length()); + out.writeBlock("\n-----END CERTIFICATE-----\n\n", 28); + out.flush(); + } + +return true; +} + + + +bool KSSLD::caAdd(QString certificate, bool ssl, bool email, bool code) { +KSSLCertificate *x = KSSLCertificate::fromString(certificate.local8Bit()); + + if (!x) return false; + +KConfig cfg("ksslcalist", false, false); + + cfg.setGroup(x->getSubject()); + cfg.writeEntry("x509", certificate); + cfg.writeEntry("site", ssl); + cfg.writeEntry("email", email); + cfg.writeEntry("code", code); + + cfg.sync(); + delete x; + +return true; +} + + +/** + * @internal + * Returns a list of certificates as QStrings read from the given file + */ +static QStringList caReadCerticatesFromFile(QString filename) { + + QStringList certificates; + QString certificate, temp; + QFile file(filename); + + if (!file.open(IO_ReadOnly)) + return certificates; + + while (!file.atEnd()) { + file.readLine(temp, 999); + if (temp.startsWith("-----BEGIN CERTIFICATE-----")) { + certificate = QString::null; + continue; + } + + if (temp.startsWith("-----END CERTIFICATE-----")) { + certificates.append(certificate); + certificate = QString::null; + continue; + } + + certificate += temp.stripWhiteSpace(); + } + + file.close(); + + return certificates; +} + +bool KSSLD::caAddFromFile(QString filename, bool ssl, bool email, bool code) { + + QStringList certificates; + certificates = caReadCerticatesFromFile(filename); + if (certificates.isEmpty()) + return false; + + bool ok = true; + + for (QStringList::Iterator it = certificates.begin(); + it != certificates.end(); ++it ) { + ok &= caAdd(*it, ssl, email, code); + } + + return ok; +} + +bool KSSLD::caRemoveFromFile(QString filename) { + + QStringList certificates; + certificates = caReadCerticatesFromFile(filename); + if (certificates.isEmpty()) + return false; + + bool ok = true; + + for (QStringList::Iterator it = certificates.begin(); + it != certificates.end(); ++it ) { + QString certificate = *it; + KSSLCertificate *x = KSSLCertificate::fromString(certificate.local8Bit()); + ok &= x && caRemove(x->getSubject()); + delete x; + } + + return ok; +} + + +QStringList KSSLD::caList() { +QStringList x; +KConfig cfg("ksslcalist", true, false); + + x = cfg.groupList(); + x.remove("<default>"); + +return x; +} + + +bool KSSLD::caUseForSSL(QString subject) { +KConfig cfg("ksslcalist", true, false); + + if (!cfg.hasGroup(subject)) + return false; + + cfg.setGroup(subject); +return cfg.readBoolEntry("site", false); +} + + + +bool KSSLD::caUseForEmail(QString subject) { +KConfig cfg("ksslcalist", true, false); + + if (!cfg.hasGroup(subject)) + return false; + + cfg.setGroup(subject); +return cfg.readBoolEntry("email", false); +} + + + +bool KSSLD::caUseForCode(QString subject) { +KConfig cfg("ksslcalist", true, false); + + if (!cfg.hasGroup(subject)) + return false; + + cfg.setGroup(subject); +return cfg.readBoolEntry("code", false); +} + + +bool KSSLD::caRemove(QString subject) { +KConfig cfg("ksslcalist", false, false); + if (!cfg.hasGroup(subject)) + return false; + + cfg.deleteGroup(subject); + cfg.sync(); + +return true; +} + + +QString KSSLD::caGetCert(QString subject) { +KConfig cfg("ksslcalist", true, false); + if (!cfg.hasGroup(subject)) + return QString::null; + + cfg.setGroup(subject); + +return cfg.readEntry("x509", QString::null); +} + + +bool KSSLD::caSetUse(QString subject, bool ssl, bool email, bool code) { +KConfig cfg("ksslcalist", false, false); + if (!cfg.hasGroup(subject)) + return false; + + cfg.setGroup(subject); + + cfg.writeEntry("site", ssl); + cfg.writeEntry("email", email); + cfg.writeEntry("code", code); + cfg.sync(); + +return true; +} + +/////////////////////////////////////////////////////////////////////////// + +void KSSLD::searchAddCert(KSSLCertificate *cert) { + skMD5Digest.insert(cert->getMD5Digest(), cert, true); + + QStringList mails; + cert->getEmails(mails); + for(QStringList::const_iterator iter = mails.begin(); iter != mails.end(); ++iter) { + QString email = static_cast<const QString &>(*iter).lower(); + QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(email); + + if (it == skEmail.end()) + it = skEmail.insert(email, QPtrVector<KSSLCertificate>()); + + QPtrVector<KSSLCertificate> &elem = *it; + + if (elem.findRef(cert) == -1) { + unsigned int n = 0; + for(; n < elem.size(); n++) { + if (!elem.at(n)) { + elem.insert(n, cert); + break; + } + } + if (n == elem.size()) { + elem.resize(n+1); + elem.insert(n, cert); + } + } + } +} + + +void KSSLD::searchRemoveCert(KSSLCertificate *cert) { + skMD5Digest.remove(cert->getMD5Digest()); + + QStringList mails; + cert->getEmails(mails); + for(QStringList::const_iterator iter = mails.begin(); iter != mails.end(); ++iter) { + QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(static_cast<const QString &>(*iter).lower()); + + if (it == skEmail.end()) + break; + + QPtrVector<KSSLCertificate> &elem = *it; + + int n = elem.findRef(cert); + if (n != -1) + elem.remove(n); + } +} + + +QStringList KSSLD::getKDEKeyByEmail(const QString &email) { + QStringList rc; + QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(email.lower()); + + kdDebug() << "GETKDEKey " << email.latin1() << endl; + + if (it == skEmail.end()) + return rc; + + QPtrVector<KSSLCertificate> &elem = *it; + for (unsigned int n = 0; n < elem.size(); n++) { + KSSLCertificate *cert = elem.at(n); + if (cert) { + rc.append(cert->getKDEKey()); + } + } + + kdDebug() << "ergebnisse: " << rc.size() << " " << elem.size() << endl; + return rc; +} + + +KSSLCertificate KSSLD::getCertByMD5Digest(const QString &key) { + QMap<QString, KSSLCertificate *>::iterator iter = skMD5Digest.find(key); + + kdDebug() << "Searching cert for " << key.latin1() << endl; + + if (iter != skMD5Digest.end()) + return **iter; + + KSSLCertificate rc; // FIXME: Better way to return a not found condition? + kdDebug() << "Not found: " << rc.toString().latin1() << endl; + return rc; +} + + +/////////////////////////////////////////////////////////////////////////// + +// +// Certificate Home methods +// + +QStringList KSSLD::getHomeCertificateList() { + return KSSLCertificateHome::getCertificateList(); +} + +bool KSSLD::addHomeCertificateFile(QString filename, QString password, bool storePass) { + return KSSLCertificateHome::addCertificate(filename, password, storePass); +} + +bool KSSLD::addHomeCertificatePKCS12(QString base64cert, QString passToStore) { + bool ok; + KSSLPKCS12 *pkcs12 = KSSLPKCS12::fromString(base64cert, passToStore); + ok = KSSLCertificateHome::addCertificate(pkcs12, passToStore); + delete pkcs12; + return ok; +} + +bool KSSLD::deleteHomeCertificateByFile(QString filename, QString password) { + return KSSLCertificateHome::deleteCertificate(filename, password); +} + +bool KSSLD::deleteHomeCertificateByPKCS12(QString base64cert, QString password) { + bool ok; + KSSLPKCS12 *pkcs12 = KSSLPKCS12::fromString(base64cert, password); + ok = KSSLCertificateHome::deleteCertificate(pkcs12); + delete pkcs12; + return ok; +} + +bool KSSLD::deleteHomeCertificateByName(QString name) { + return KSSLCertificateHome::deleteCertificateByName(name); +} + + + +/////////////////////////////////////////////////////////////////////////// + +#include "kssld.moc" + + +/* + + DESIGN - KSSLCertificateCache + ------ + + This is the first implementation and I think this cache actually needs + experimentation to determine which implementation works best. My current + options are: + + (1) Store copies of the X509 certificates in a QPtrList using a self + organizing heuristic as described by Munro and Suwanda. + (2) Store copies of the X509 certificates in a tree structure, perhaps + a redblack tree, avl tree, or even just a simple binary tree. + (3) Store the CN's in a tree or list and use them as a hash to retrieve + the X509 certificates. + (4) Create "nodes" containing the X509 certificate and place them in + two structures concurrently, one organized by CN, the other by + X509 serial number. + + This implementation uses (1). (4) is definitely attractive, but I don't + think it will be necessary to go so crazy with performance, and perhaps + end up performing poorly in situations where there are very few entries in + the cache (which is most likely the case most of the time). The style of + heuristic is move-to-front, not swap-forward. This seems to make more + sense because the typical user will hit a site at least a few times in a + row before moving to a new one. + + What I worry about most with respect to performance is that cryptographic + routines are expensive and if we have to perform them on each X509 + certificate until the right one is found, we will perform poorly. + + All in all, this code is actually quite crucial for performance on SSL + website, especially those with many image files loaded via SSL. If a + site loads 15 images, we will have to run through this code 15 times. + A heuristic for self organization will make each successive lookup faster. + Sounds good, doesn't it? + + DO NOT ATTEMPT TO GUESS WHICH CERTIFICATES ARE ACCEPTIBLE IN YOUR CODE!! + ALWAYS USE THE CACHE. IT MAY CHECK THINGS THAT YOU DON'T THINK OF, AND + ALSO IF THERE IS A BUG IN THE CHECKING CODE, IF IT IS ALL CONTAINED IN + THIS LIBRARY, A MINOR FIX WILL FIX ALL APPLICATIONS. + */ + diff --git a/kio/misc/kssld/kssld.desktop b/kio/misc/kssld/kssld.desktop new file mode 100644 index 000000000..bbabf17a1 --- /dev/null +++ b/kio/misc/kssld/kssld.desktop @@ -0,0 +1,156 @@ +[Desktop Entry] +Type=Service +ServiceTypes=KDEDModule +X-KDE-ModuleType=Library +X-KDE-Library=kssld +X-KDE-FactoryName=kssld +X-KDE-Kded-autoload=false +X-KDE-Kded-load-on-demand=true +Name=KSSL Daemon Module +Name[af]=Kssl Bediener Module +Name[ar]=وحدة مراقب KSSL +Name[az]=KSSL Demon Modulu +Name[be]=Модуль сервіса KSSL +Name[bg]=Демон KSSL +Name[bn]=KSSL ডিমন মডিউল +Name[br]=Mollad an diaoul KSSL +Name[ca]=Mòdul del dimoni KSSL +Name[cs]=Modul démona KSSL +Name[csb]=KSSL +Name[cy]=Modiwl Daemon KSSL +Name[da]=KSSL Dæmonmodul +Name[de]=SSL-Dienst +Name[el]=Άρθρωμα δαίμονα KSSL +Name[eo]=SSL-demono-modulo +Name[es]=Módulo de demonio KSSL +Name[et]=KSSL deemoni moodul +Name[eu]=KSSL daemon modulua +Name[fa]=پیمانۀ شبح KSSL +Name[fi]=KSSL-palvelinmoduuli +Name[fr]=Module démon KSSL +Name[ga]=Modúl Deamhain KSSL +Name[gl]=Módulo do Demo KSSL +Name[he]=מודול תהליך הרקע של SSL +Name[hi]=KSSL ङेमन घटक +Name[hr]=Modul KSSL demona +Name[hu]=KSSL szolgáltatásmodul +Name[id]=Modul Daemon KSSL +Name[is]=KSSL þjónseining +Name[it]=Modulo demone KSSL +Name[ja]=KSSL デーモンモジュール +Name[ka]=KSSL გუშაგის მოდული +Name[kk]=KSSL қызметтің модулі +Name[km]=ម៉ូឌុល Daemon KSSL +Name[ko]=KSSL 데몬 모듈 +Name[lb]=KSSL-Dämonmodul +Name[lt]=KSSL tarnybos modulis +Name[lv]=KSSL Dēmona Modulis +Name[mn]=KSSL Daemon Modul +Name[ms]=Modul Daemon KSSL +Name[mt]=Modulu daemon KSSL +Name[nb]=KSSL nisse-modul +Name[nds]=KSSL-Dämoon +Name[ne]=KSSL डेइमन मोड्युल +Name[nl]=KSSL daemon-module +Name[nn]=KSSL-nissemodul +Name[nso]=Seripa sa Daemon ya KSSL +Name[pa]=KSSL ਡਾਇਮੋਨ ਮੈਡੀਊਲ +Name[pl]=KSSL +Name[pt]=Módulo do Servidor de KSSL +Name[pt_BR]=Módulo do Serviço do KSSL +Name[ro]=Modul demon KSSL +Name[ru]=Служба KSSL +Name[rw]=Igice Dayimoni KSSL +Name[se]=KSSL-bálvámoduvla +Name[sk]=Modul démona KSSL +Name[sl]=Strežniški modul KSSL +Name[sq]=Demoni për Modulin KSSL +Name[sr]=KSSL демон модул +Name[sr@Latn]=KSSL demon modul +Name[sv]=KSSL-demonmodul +Name[ta]=KSSL டெமான் பகுதி +Name[te]=కెఎస్ ఎస్ ఎల్ సూత్రధారి మాడ్యూల్ +Name[tg]=Модули Демон KSSL +Name[th]=โมดูลเดมอน KSSL +Name[tr]=KSSL Program Modülü +Name[tt]=KSSL Xezmäteneñ Modulı +Name[uk]=Модуль демону KSSL +Name[uz]=KSSL xizmatining moduli +Name[uz@cyrillic]=KSSL хизматининг модули +Name[ven]=Modulu wa Daemon wa KSSL +Name[vi]=Mô-đun trình nền KSSL +Name[xh]=Isicatshulwa se KSSL Daemon +Name[zh_CN]=KSSL 守护进程模块 +Name[zh_HK]=KSSL 伺服程式模組 +Name[zh_TW]=KSSL 伺服程式模組 +Name[zu]=Ingxenye ye-daemon ye-KSSL +Comment=KSSL daemon module for KDED +Comment[af]=KSSL bediener module vir KDED +Comment[be]=Модуль сервіса KSSL для KDED +Comment[bg]=Модул демон за KSSL за KDED +Comment[bn]=KDED-র জন্য KSSL ডিমন মডিউল +Comment[br]=Mollad an diaoul KSSL evit KDED +Comment[bs]=KSSL Daemon Module za KDED +Comment[ca]=Mòdul del dimoni KSSL per a KDED +Comment[cs]=Modul démona KSSL pro KDED +Comment[csb]=Ùsłëżnota SSL w KDED +Comment[da]=KSSL Dæmonmodul for KDED +Comment[de]=Unterstützung für SSL-Verschlüsselung in KDE +Comment[el]=Άρθρωμα δαίμονα KSSL για το KDED +Comment[eo]=SSL-demono-modulo por KDED +Comment[es]=Módulo de demonio KSSL para KDED +Comment[et]=KDED KSSL deemoni moodul +Comment[eu]=KSSL daemon modulua KDEDrako +Comment[fa]=پیمانۀ شبح KSSL برای KDED +Comment[fi]=KSSL-palvelinmoduuli KDED:lle +Comment[fr]=Module démon KSSL pour KDED +Comment[fy]=KSSL daemon module foar KDED +Comment[ga]=Modúl deamhain KSSL le haghaidh KDED +Comment[gl]=Módulo do Demo KSSL para KDED +Comment[he]=מודול תהליך רקע של SSL עבור KDED +Comment[hi]=केडीईडी के लिए केएसएसएल डेमन मॉड्यूल +Comment[hr]=KSSL demon modul za KDED +Comment[hu]=KSSL szolgáltatásmodul a KDED-hez +Comment[id]=Modul daemon KSSL untuk KDED +Comment[is]=KSSL þjónseining fyrir KDED +Comment[it]=Modulo demone KSSL per KDED +Comment[ja]=KDED 用 の KSSL デーモンモジュール +Comment[ka]=KSSL გუშაგის მოდული KDED-სთვის +Comment[kk]=KDED KSSL куәліктерді басқару қызметтің модулі +Comment[km]=ម៉ូឌុល daemon KSSL សម្រាប់ KDED +Comment[lb]=KSSL-Dämonmodul fir KDED +Comment[lt]=KSSL tarnybos modulis, skirtas KDED +Comment[lv]=KSSL Dēmona Modulis priekš KDED +Comment[mk]=KSSL даемон модул за KDED +Comment[ms]=Modul Daemon KSSL untuk KDED +Comment[nb]=KSSL nissemodul for KDED +Comment[nds]=KSSL-Dämoonmoduul för KDED +Comment[ne]=KDED का लागि डेइमन मोड्युल KSSL +Comment[nl]=KSSL daemon-module voor KDED +Comment[nn]=KSSL-nissemodul for KDED +Comment[pa]=KDED ਲਈ KSSL ਪੇਸ਼ਕਾਰੀ +Comment[pl]=Obsługa SSL w KDED +Comment[pt]=Módulo servidor de KSSL para o KDED +Comment[pt_BR]=Módulo de serviço KSSL para o KDE +Comment[ro]=Modul demon KSSL pentru KDED +Comment[ru]=Управление сертификатами SSL +Comment[rw]=Igice cya dayimoni KSSL cya KDED +Comment[se]=KDED:a KSSL-bálvámoduvla +Comment[sk]=Modul démona KSSL pre KDED +Comment[sl]=Strežniški modul KSSL za KDED +Comment[sr]=KSSL демон модул за KDED +Comment[sr@Latn]=KSSL demon modul za KDED +Comment[sv]=KSSL-demonmodul för KDED +Comment[ta]=KDEDக்கான KSSL டெமான் பகுதி +Comment[te]=కెడిఈడి కొరకు కెఎస్ ఎస్ ఎల్ సూత్రధారి మాడ్యూల్ +Comment[tg]=Модули Демон KSSL брои KDED +Comment[th]=โมดูลเดมอน KSSL สำหรับ KDED +Comment[tr]=KDED için KSSL program biirmi +Comment[tt]=KDED öçen KSSL xezmät +Comment[uk]=Модуль демону KSSL для KDED +Comment[uz]=KDED uchun KSSL xizmatining moduli +Comment[uz@cyrillic]=KDED учун KSSL хизматининг модули +Comment[vi]=Mô-đun trình nền KSSL cho KDED. +Comment[zh_CN]=KDED 的 KSSL 守护进程模块 +Comment[zh_HK]=KDED 使用的 SSL 伺服程式模組 +Comment[zh_TW]=KDED 使用的 KSSL 伺服程式模組 diff --git a/kio/misc/kssld/kssld.h b/kio/misc/kssld/kssld.h new file mode 100644 index 000000000..94cbe3972 --- /dev/null +++ b/kio/misc/kssld/kssld.h @@ -0,0 +1,154 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2001-2005 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. + +*/ +#ifndef __KSSLD_H__ +#define __KSSLD_H__ + +#include <kded/kdedmodule.h> +#include <ksslcertificate.h> +#include <ksslcertificatecache.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvaluelist.h> +#include <qmap.h> +#include <qptrvector.h> + + +class KSimpleConfig; +class KSSLCNode; +class KOpenSSLProxy; + +class KSSLD : public KDEDModule +{ + Q_OBJECT + K_DCOP + +public: + + KSSLD(const QCString &name); + + virtual ~KSSLD(); + +k_dcop: + // + // Certificate Cache methods + // + void cacheAddCertificate(KSSLCertificate cert, + KSSLCertificateCache::KSSLCertificatePolicy policy, + bool permanent = true); + KSSLCertificateCache::KSSLCertificatePolicy cacheGetPolicyByCN(QString cn); + + KSSLCertificateCache::KSSLCertificatePolicy cacheGetPolicyByCertificate(KSSLCertificate cert); + + bool cacheSeenCN(QString cn); + bool cacheSeenCertificate(KSSLCertificate cert); + + bool cacheRemoveByCN(QString cn); + bool cacheRemoveBySubject(QString subject); + bool cacheRemoveByCertificate(KSSLCertificate cert); + + bool cacheIsPermanent(KSSLCertificate cert); + + void cacheReload(); + + bool cacheModifyByCN(QString cn, + KSSLCertificateCache::KSSLCertificatePolicy policy, + bool permanent, + QDateTime expires); + + bool cacheModifyByCertificate(KSSLCertificate cert, + KSSLCertificateCache::KSSLCertificatePolicy policy, + bool permanent, + QDateTime expires); + + QStringList cacheGetHostList(KSSLCertificate cert); + + bool cacheAddHost(KSSLCertificate cert, QString host); + + bool cacheRemoveHost(KSSLCertificate cert, QString host); + + /* Certificate Authorities */ + void caVerifyUpdate(); + bool caRegenerate(); + + QStringList caList(); + + bool caUseForSSL(QString subject); + + bool caUseForEmail(QString subject); + + bool caUseForCode(QString subject); + + bool caAdd(QString certificate, bool ssl, bool email, bool code); + + bool caAddFromFile(QString filename, bool ssl, bool email, bool code); + + bool caRemove(QString subject); + + bool caRemoveFromFile(QString filename); + + QString caGetCert(QString subject); + + bool caSetUse(QString subject, bool ssl, bool email, bool code); + + QStringList getKDEKeyByEmail(const QString &email); + + KSSLCertificate getCertByMD5Digest(const QString &key); + + // + // Certificate Home methods + // + + QStringList getHomeCertificateList(); + + bool addHomeCertificateFile(QString filename, QString password, bool storePass /*=false*/); + + bool addHomeCertificatePKCS12(QString base64cert, QString passToStore); + + bool deleteHomeCertificateByFile(QString filename, QString password); + + bool deleteHomeCertificateByPKCS12(QString base64cert, QString password); + + bool deleteHomeCertificateByName(QString name); + +private: + + void cacheClearList(); + void cacheSaveToDisk(); + void cacheLoadDefaultPolicies(); + + // for the cache portion: + KSimpleConfig *cfg; + QPtrList<KSSLCNode> certList; + + // Our pointer to OpenSSL + KOpenSSLProxy *kossl; + + // + void searchAddCert(KSSLCertificate *cert); + void searchRemoveCert(KSSLCertificate *cert); + + QMap<QString, QPtrVector<KSSLCertificate> > skEmail; + QMap<QString, KSSLCertificate *> skMD5Digest; +}; + + +#endif |