00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #include <qtimer.h>
00028
00029 #include "kssld.h"
00030 #include <kconfig.h>
00031 #include <ksimpleconfig.h>
00032 #include <ksslcertchain.h>
00033 #include <ksslcertificate.h>
00034 #include <ksslx509map.h>
00035 #include <qptrlist.h>
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 #include <stdlib.h>
00039 #include <pwd.h>
00040 #include <unistd.h>
00041 #include <qfile.h>
00042 #include <qsortedlist.h>
00043 #include <kglobal.h>
00044 #include <kstandarddirs.h>
00045 #include <kdebug.h>
00046 #include <qdatetime.h>
00047
00048 #include <kmdcodec.h>
00049 #include <kopenssl.h>
00050
00051
00052
00053 extern "C" {
00054 KDEDModule *create_kssld(const QCString &name) {
00055 return new KSSLD(name);
00056 }
00057
00058 void *__kde_do_unload;
00059 }
00060
00061
00062 KSSLD::KSSLD(const QCString &name) : KDEDModule(name)
00063 {
00064
00065 cfg = new KSimpleConfig("ksslpolicies", false);
00066 KGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl");
00067 caVerifyUpdate();
00068 cacheLoadDefaultPolicies();
00069 certList.setAutoDelete(false);
00070 kossl = KOSSL::self();
00071
00072
00073 }
00074
00075
00076 KSSLD::~KSSLD()
00077 {
00078
00079 cacheClearList();
00080 delete cfg;
00081
00082
00083 }
00084
00085
00086
00087
00088
00089 class KSSLCNode {
00090 public:
00091 KSSLCertificate *cert;
00092 KSSLCertificateCache::KSSLCertificatePolicy policy;
00093 bool permanent;
00094 QDateTime expires;
00095 QStringList hosts;
00096 KSSLCNode() { cert = 0L;
00097 policy = KSSLCertificateCache::Unknown;
00098 permanent = true;
00099 }
00100 ~KSSLCNode() { if (cert) delete cert; }
00101 };
00102
00103
00104
00105 void KSSLD::cacheSaveToDisk() {
00106 KSSLCNode *node;
00107
00108 for (node = certList.first(); node; node = certList.next()) {
00109 if (node->permanent ||
00110 node->expires > QDateTime::currentDateTime()) {
00111
00112
00113
00114 cfg->setGroup(node->cert->getSubject());
00115 cfg->writeEntry("Certificate", node->cert->toString());
00116 cfg->writeEntry("Policy", node->policy);
00117 cfg->writeEntry("Expires", node->expires);
00118 cfg->writeEntry("Permanent", node->permanent);
00119 cfg->writeEntry("Hosts", node->hosts);
00120
00121
00122 QStringList qsl;
00123 QPtrList<KSSLCertificate> cl =
00124 node->cert->chain().getChain();
00125 for (KSSLCertificate *c = cl.first();
00126 c != 0;
00127 c = cl.next()) {
00128
00129
00130 qsl << c->toString();
00131 }
00132
00133 cl.setAutoDelete(true);
00134 cfg->writeEntry("Chain", qsl);
00135 }
00136 }
00137
00138 cfg->sync();
00139
00140
00141 QString cfgName(KGlobal::dirs()->findResource("config", "ksslpolicies"));
00142
00143 if (!cfgName.isEmpty()) {
00144 ::chmod(QFile::encodeName(cfgName), 0600);
00145 }
00146 }
00147
00148
00149 void KSSLD::cacheReload() {
00150 cacheClearList();
00151 delete cfg;
00152 cfg = new KSimpleConfig("ksslpolicies", false);
00153 cacheLoadDefaultPolicies();
00154 }
00155
00156
00157 void KSSLD::cacheClearList() {
00158 KSSLCNode *node;
00159
00160 for (node = certList.first(); node; node = certList.next()) {
00161 certList.remove(node);
00162 delete node;
00163 }
00164
00165 skEmail.clear();
00166 skMD5Digest.clear();
00167 }
00168
00169
00170 void KSSLD::cacheLoadDefaultPolicies() {
00171 QStringList groups = cfg->groupList();
00172
00173 for (QStringList::Iterator i = groups.begin();
00174 i != groups.end();
00175 ++i) {
00176 if ((*i).length() == 0) {
00177 continue;
00178 }
00179
00180 cfg->setGroup(*i);
00181
00182
00183 if (!cfg->readBoolEntry("Permanent") &&
00184 cfg->readDateTimeEntry("Expires") <
00185 QDateTime::currentDateTime()) {
00186 cfg->deleteGroup(*i);
00187 continue;
00188 }
00189
00190 QCString encodedCert;
00191 KSSLCertificate *newCert;
00192
00193 encodedCert = cfg->readEntry("Certificate").local8Bit();
00194 newCert = KSSLCertificate::fromString(encodedCert);
00195
00196 if (!newCert) {
00197 continue;
00198 }
00199
00200 KSSLCNode *n = new KSSLCNode;
00201 n->cert = newCert;
00202 n->policy = (KSSLCertificateCache::KSSLCertificatePolicy) cfg->readNumEntry("Policy");
00203 n->permanent = cfg->readBoolEntry("Permanent");
00204 n->expires = cfg->readDateTimeEntry("Expires");
00205 n->hosts = cfg->readListEntry("Hosts");
00206 newCert->chain().setChain(cfg->readListEntry("Chain"));
00207 certList.append(n);
00208 searchAddCert(newCert);
00209 }
00210 }
00211
00212
00213 void KSSLD::cacheAddCertificate(KSSLCertificate cert,
00214 KSSLCertificateCache::KSSLCertificatePolicy policy,
00215 bool permanent) {
00216 KSSLCNode *node;
00217
00218 for (node = certList.first(); node; node = certList.next()) {
00219 if (cert == *(node->cert)) {
00220 node->policy = policy;
00221 node->permanent = permanent;
00222
00223 if (!permanent) {
00224 node->expires = QDateTime::currentDateTime();
00225
00226 node->expires = node->expires.addSecs(3600);
00227 }
00228
00229 cacheSaveToDisk();
00230 return;
00231 }
00232 }
00233
00234 KSSLCNode *n = new KSSLCNode;
00235 n->cert = cert.replicate();
00236 n->policy = policy;
00237 n->permanent = permanent;
00238
00239 cacheRemoveBySubject(n->cert->getSubject());
00240 certList.prepend(n);
00241
00242 if (!permanent) {
00243 n->expires = QDateTime::currentDateTime();
00244 n->expires = n->expires.addSecs(3600);
00245 }
00246
00247 searchAddCert(n->cert);
00248 cacheSaveToDisk();
00249 }
00250
00251
00252 KSSLCertificateCache::KSSLCertificatePolicy KSSLD::cacheGetPolicyByCN(QString cn) {
00253 KSSLCNode *node;
00254
00255 for (node = certList.first(); node; node = certList.next()) {
00256 if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
00257 if (!node->permanent &&
00258 node->expires < QDateTime::currentDateTime()) {
00259 certList.remove(node);
00260 cfg->deleteGroup(node->cert->getSubject());
00261 delete node;
00262 continue;
00263 }
00264
00265 certList.remove(node);
00266 certList.prepend(node);
00267 cacheSaveToDisk();
00268 return node->policy;
00269 }
00270 }
00271
00272 cacheSaveToDisk();
00273
00274 return KSSLCertificateCache::Unknown;
00275 }
00276
00277
00278 KSSLCertificateCache::KSSLCertificatePolicy KSSLD::cacheGetPolicyByCertificate(KSSLCertificate cert) {
00279 KSSLCNode *node;
00280
00281 for (node = certList.first(); node; node = certList.next()) {
00282 if (cert == *(node->cert)) {
00283 if (!node->permanent &&
00284 node->expires < QDateTime::currentDateTime()) {
00285 certList.remove(node);
00286 cfg->deleteGroup(node->cert->getSubject());
00287 delete node;
00288 cacheSaveToDisk();
00289 return KSSLCertificateCache::Unknown;
00290 }
00291
00292 certList.remove(node);
00293 certList.prepend(node);
00294 return node->policy;
00295 }
00296 }
00297
00298 return KSSLCertificateCache::Unknown;
00299 }
00300
00301
00302 bool KSSLD::cacheSeenCN(QString cn) {
00303 KSSLCNode *node;
00304
00305 for (node = certList.first(); node; node = certList.next()) {
00306 if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
00307 if (!node->permanent &&
00308 node->expires < QDateTime::currentDateTime()) {
00309 certList.remove(node);
00310 cfg->deleteGroup(node->cert->getSubject());
00311 delete node;
00312 cacheSaveToDisk();
00313 continue;
00314 }
00315
00316 certList.remove(node);
00317 certList.prepend(node);
00318 return true;
00319 }
00320 }
00321
00322 return false;
00323 }
00324
00325
00326 bool KSSLD::cacheSeenCertificate(KSSLCertificate cert) {
00327 KSSLCNode *node;
00328
00329 for (node = certList.first(); node; node = certList.next()) {
00330 if (cert == *(node->cert)) {
00331 if (!node->permanent &&
00332 node->expires < QDateTime::currentDateTime()) {
00333 certList.remove(node);
00334 cfg->deleteGroup(node->cert->getSubject());
00335 delete node;
00336 cacheSaveToDisk();
00337 return false;
00338 }
00339
00340 certList.remove(node);
00341 certList.prepend(node);
00342 return true;
00343 }
00344 }
00345
00346 return false;
00347 }
00348
00349
00350 bool KSSLD::cacheIsPermanent(KSSLCertificate cert) {
00351 KSSLCNode *node;
00352
00353 for (node = certList.first(); node; node = certList.next()) {
00354 if (cert == *(node->cert)) {
00355 if (!node->permanent && node->expires <
00356 QDateTime::currentDateTime()) {
00357 certList.remove(node);
00358 cfg->deleteGroup(node->cert->getSubject());
00359 delete node;
00360 cacheSaveToDisk();
00361 return false;
00362 }
00363
00364 certList.remove(node);
00365 certList.prepend(node);
00366 return node->permanent;
00367 }
00368 }
00369
00370 return false;
00371 }
00372
00373
00374 bool KSSLD::cacheRemoveBySubject(QString subject) {
00375 KSSLCNode *node;
00376 bool gotOne = false;
00377
00378 for (node = certList.first(); node; node = certList.next()) {
00379 if (node->cert->getSubject() == subject) {
00380 certList.remove(node);
00381 cfg->deleteGroup(node->cert->getSubject());
00382 searchRemoveCert(node->cert);
00383 delete node;
00384 gotOne = true;
00385 }
00386 }
00387
00388 cacheSaveToDisk();
00389
00390 return gotOne;
00391 }
00392
00393
00394 bool KSSLD::cacheRemoveByCN(QString cn) {
00395 KSSLCNode *node;
00396 bool gotOne = false;
00397
00398 for (node = certList.first(); node; node = certList.next()) {
00399 if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
00400 certList.remove(node);
00401 cfg->deleteGroup(node->cert->getSubject());
00402 searchRemoveCert(node->cert);
00403 delete node;
00404 gotOne = true;
00405 }
00406 }
00407
00408 cacheSaveToDisk();
00409
00410 return gotOne;
00411 }
00412
00413
00414 bool KSSLD::cacheRemoveByCertificate(KSSLCertificate cert) {
00415 KSSLCNode *node;
00416
00417 for (node = certList.first(); node; node = certList.next()) {
00418 if (cert == *(node->cert)) {
00419 certList.remove(node);
00420 cfg->deleteGroup(node->cert->getSubject());
00421 searchRemoveCert(node->cert);
00422 delete node;
00423 cacheSaveToDisk();
00424 return true;
00425 }
00426 }
00427
00428 return false;
00429 }
00430
00431
00432 bool KSSLD::cacheModifyByCN(QString cn,
00433 KSSLCertificateCache::KSSLCertificatePolicy policy, bool permanent,
00434 QDateTime expires) {
00435 KSSLCNode *node;
00436
00437 for (node = certList.first(); node; node = certList.next()) {
00438 if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
00439 node->permanent = permanent;
00440 node->expires = expires;
00441 node->policy = policy;
00442 certList.remove(node);
00443 certList.prepend(node);
00444 cacheSaveToDisk();
00445 return true;
00446 }
00447 }
00448
00449 return false;
00450 }
00451
00452
00453 bool KSSLD::cacheModifyByCertificate(KSSLCertificate cert,
00454 KSSLCertificateCache::KSSLCertificatePolicy policy,
00455 bool permanent,
00456 QDateTime expires) {
00457 KSSLCNode *node;
00458
00459 for (node = certList.first(); node; node = certList.next()) {
00460 if (cert == *(node->cert)) {
00461 node->permanent = permanent;
00462 node->expires = expires;
00463 node->policy = policy;
00464 certList.remove(node);
00465 certList.prepend(node);
00466 cacheSaveToDisk();
00467 return true;
00468 }
00469 }
00470
00471 return false;
00472 }
00473
00474
00475 QStringList KSSLD::cacheGetHostList(KSSLCertificate cert) {
00476 KSSLCNode *node;
00477
00478 for (node = certList.first(); node; node = certList.next()) {
00479 if (cert == *(node->cert)) {
00480 if (!node->permanent && node->expires <
00481 QDateTime::currentDateTime()) {
00482 certList.remove(node);
00483 cfg->deleteGroup(node->cert->getSubject());
00484 searchRemoveCert(node->cert);
00485 delete node;
00486 cacheSaveToDisk();
00487 return QStringList();
00488 }
00489
00490 certList.remove(node);
00491 certList.prepend(node);
00492 return node->hosts;
00493 }
00494 }
00495
00496 return QStringList();
00497 }
00498
00499
00500 bool KSSLD::cacheAddHost(KSSLCertificate cert, QString host) {
00501 KSSLCNode *node;
00502
00503 if (host.isEmpty())
00504 return true;
00505
00506 for (node = certList.first(); node; node = certList.next()) {
00507 if (cert == *(node->cert)) {
00508 if (!node->permanent && node->expires <
00509 QDateTime::currentDateTime()) {
00510 certList.remove(node);
00511 cfg->deleteGroup(node->cert->getSubject());
00512 searchRemoveCert(node->cert);
00513 delete node;
00514 cacheSaveToDisk();
00515 return false;
00516 }
00517
00518 if (!node->hosts.contains(host)) {
00519 node->hosts << host;
00520 }
00521
00522 certList.remove(node);
00523 certList.prepend(node);
00524 cacheSaveToDisk();
00525 return true;
00526 }
00527 }
00528
00529 return false;
00530 }
00531
00532
00533 bool KSSLD::cacheRemoveHost(KSSLCertificate cert, QString host) {
00534 KSSLCNode *node;
00535
00536 for (node = certList.first(); node; node = certList.next()) {
00537 if (cert == *(node->cert)) {
00538 if (!node->permanent && node->expires <
00539 QDateTime::currentDateTime()) {
00540 certList.remove(node);
00541 cfg->deleteGroup(node->cert->getSubject());
00542 searchRemoveCert(node->cert);
00543 delete node;
00544 cacheSaveToDisk();
00545 return false;
00546 }
00547 node->hosts.remove(host);
00548 certList.remove(node);
00549 certList.prepend(node);
00550 cacheSaveToDisk();
00551 return true;
00552 }
00553 }
00554
00555 return false;
00556 }
00557
00558
00559
00560
00562
00563 void KSSLD::caVerifyUpdate() {
00564 QString path = KGlobal::dirs()->saveLocation("kssl") + "/ca-bundle.crt";
00565 if (!QFile::exists(path))
00566 return;
00567
00568 cfg->setGroup(QString::null);
00569 Q_UINT32 newStamp = KGlobal::dirs()->calcResourceHash("config", "ksslcalist", true);
00570 Q_UINT32 oldStamp = cfg->readUnsignedNumEntry("ksslcalistStamp");
00571 if (oldStamp != newStamp)
00572 {
00573 caRegenerate();
00574 cfg->writeEntry("ksslcalistStamp", newStamp);
00575 cfg->sync();
00576 }
00577 }
00578
00579 bool KSSLD::caRegenerate() {
00580 QString path = KGlobal::dirs()->saveLocation("kssl") + "/ca-bundle.crt";
00581
00582 QFile out(path);
00583
00584 if (!out.open(IO_WriteOnly))
00585 return false;
00586
00587 KConfig cfg("ksslcalist", true, false);
00588
00589 QStringList x = cfg.groupList();
00590
00591 for (QStringList::Iterator i = x.begin();
00592 i != x.end();
00593 ++i) {
00594 if ((*i).isEmpty() || *i == "<default>") continue;
00595
00596 cfg.setGroup(*i);
00597
00598 if (!cfg.readBoolEntry("site", false)) continue;
00599
00600 QString cert = cfg.readEntry("x509", "");
00601 if (cert.length() <= 0) continue;
00602
00603 unsigned int xx = cert.length() - 1;
00604 for (unsigned int j = 0; j < xx/64; j++) {
00605 cert.insert(64*(j+1)+j, '\n');
00606 }
00607 out.writeBlock("-----BEGIN CERTIFICATE-----\n", 28);
00608 out.writeBlock(cert.latin1(), cert.length());
00609 out.writeBlock("\n-----END CERTIFICATE-----\n\n", 28);
00610 out.flush();
00611 }
00612
00613 return true;
00614 }
00615
00616
00617
00618 bool KSSLD::caAdd(QString certificate, bool ssl, bool email, bool code) {
00619 KSSLCertificate *x = KSSLCertificate::fromString(certificate.local8Bit());
00620
00621 if (!x) return false;
00622
00623 KConfig cfg("ksslcalist", false, false);
00624
00625 cfg.setGroup(x->getSubject());
00626 cfg.writeEntry("x509", certificate);
00627 cfg.writeEntry("site", ssl);
00628 cfg.writeEntry("email", email);
00629 cfg.writeEntry("code", code);
00630
00631 cfg.sync();
00632 delete x;
00633
00634 return true;
00635 }
00636
00637
00638 QStringList KSSLD::caList() {
00639 QStringList x;
00640 KConfig cfg("ksslcalist", true, false);
00641
00642 x = cfg.groupList();
00643 x.remove("<default>");
00644
00645 return x;
00646 }
00647
00648
00649 bool KSSLD::caUseForSSL(QString subject) {
00650 KConfig cfg("ksslcalist", true, false);
00651
00652 if (!cfg.hasGroup(subject))
00653 return false;
00654
00655 cfg.setGroup(subject);
00656 return cfg.readBoolEntry("site", false);
00657 }
00658
00659
00660
00661 bool KSSLD::caUseForEmail(QString subject) {
00662 KConfig cfg("ksslcalist", true, false);
00663
00664 if (!cfg.hasGroup(subject))
00665 return false;
00666
00667 cfg.setGroup(subject);
00668 return cfg.readBoolEntry("email", false);
00669 }
00670
00671
00672
00673 bool KSSLD::caUseForCode(QString subject) {
00674 KConfig cfg("ksslcalist", true, false);
00675
00676 if (!cfg.hasGroup(subject))
00677 return false;
00678
00679 cfg.setGroup(subject);
00680 return cfg.readBoolEntry("code", false);
00681 }
00682
00683
00684 bool KSSLD::caRemove(QString subject) {
00685 KConfig cfg("ksslcalist", false, false);
00686 if (!cfg.hasGroup(subject))
00687 return false;
00688
00689 cfg.deleteGroup(subject);
00690 cfg.sync();
00691
00692 return true;
00693 }
00694
00695
00696 QString KSSLD::caGetCert(QString subject) {
00697 KConfig cfg("ksslcalist", true, false);
00698 if (!cfg.hasGroup(subject))
00699 return QString::null;
00700
00701 cfg.setGroup(subject);
00702
00703 return cfg.readEntry("x509", QString::null);
00704 }
00705
00706
00707 bool KSSLD::caSetUse(QString subject, bool ssl, bool email, bool code) {
00708 KConfig cfg("ksslcalist", false, false);
00709 if (!cfg.hasGroup(subject))
00710 return false;
00711
00712 cfg.setGroup(subject);
00713
00714 cfg.writeEntry("site", ssl);
00715 cfg.writeEntry("email", email);
00716 cfg.writeEntry("code", code);
00717 cfg.sync();
00718
00719 return true;
00720 }
00721
00723
00724 void KSSLD::searchAddCert(KSSLCertificate *cert) {
00725 skMD5Digest.insert(cert->getMD5DigestText(), cert, true);
00726
00727 QStringList mails;
00728 cert->getEmails(mails);
00729 for(QStringList::const_iterator iter = mails.begin(); iter != mails.end(); iter++) {
00730 QString email = static_cast<const QString &>(*iter).lower();
00731 QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(email);
00732
00733 if (it == skEmail.end())
00734 it = skEmail.insert(email, QPtrVector<KSSLCertificate>());
00735
00736 QPtrVector<KSSLCertificate> &elem = *it;
00737
00738 if (elem.findRef(cert) == -1) {
00739 unsigned int n = 0;
00740 for(; n < elem.size(); n++) {
00741 if (!elem.at(n)) {
00742 elem.insert(n, cert);
00743 break;
00744 }
00745 }
00746 if (n == elem.size()) {
00747 elem.resize(n+1);
00748 elem.insert(n, cert);
00749 }
00750 }
00751 }
00752 }
00753
00754
00755 void KSSLD::searchRemoveCert(KSSLCertificate *cert) {
00756 skMD5Digest.remove(cert->getMD5DigestText());
00757
00758 QStringList mails;
00759 cert->getEmails(mails);
00760 for(QStringList::const_iterator iter = mails.begin(); iter != mails.end(); iter++) {
00761 QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(static_cast<const QString &>(*iter).lower());
00762
00763 if (it == skEmail.end())
00764 break;
00765
00766 QPtrVector<KSSLCertificate> &elem = *it;
00767
00768 int n = elem.findRef(cert);
00769 if (n != -1)
00770 elem.remove(n);
00771 }
00772 }
00773
00774
00775 QStringList KSSLD::getKDEKeyByEmail(const QString &email) {
00776 QStringList rc;
00777 QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(email.lower());
00778
00779 kdDebug() << "GETKDEKey " << email.latin1() << endl;
00780
00781 if (it == skEmail.end())
00782 return rc;
00783
00784 QPtrVector<KSSLCertificate> &elem = *it;
00785 for (unsigned int n = 0; n < elem.size(); n++) {
00786 KSSLCertificate *cert = elem.at(n);
00787 if (cert) {
00788 rc.append(cert->getKDEKey());
00789 }
00790 }
00791
00792 kdDebug() << "ergebnisse: " << rc.size() << " " << elem.size() << endl;
00793 return rc;
00794 }
00795
00796
00797 KSSLCertificate KSSLD::getCertByMD5Digest(const QString &key) {
00798 QMap<QString, KSSLCertificate *>::iterator iter = skMD5Digest.find(key);
00799
00800 kdDebug() << "Searching cert for " << key.latin1() << endl;
00801
00802 if (iter != skMD5Digest.end())
00803 return **iter;
00804
00805 KSSLCertificate rc;
00806 kdDebug() << "Not found: " << rc.toString().latin1() << endl;
00807 return rc;
00808 }
00809
00810
00812
00813
00814
00815
00816
00818
00819 #include "kssld.moc"
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864