• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/kssl
 

tdeio/kssl

ksslcertificate.cc
00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) 2000-2003 George Staikos <staikos@kde.org>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025 
00026 
00027 
00028 #include <unistd.h>
00029 #include <tqstring.h>
00030 #include <tqstringlist.h>
00031 #include <tqfile.h>
00032 
00033 #include "kssldefs.h"
00034 #include "ksslcertificate.h"
00035 #include "ksslcertchain.h"
00036 #include "ksslutils.h"
00037 
00038 #include <kstandarddirs.h>
00039 #include <kmdcodec.h>
00040 #include <tdelocale.h>
00041 #include <tqdatetime.h>
00042 #include <tdetempfile.h>
00043 
00044 #include <sys/types.h>
00045 
00046 #ifdef HAVE_SYS_STAT_H
00047 #include <sys/stat.h>
00048 #endif
00049 
00050 // this hack provided by Malte Starostik to avoid glibc/openssl bug
00051 // on some systems
00052 #ifdef KSSL_HAVE_SSL
00053 #define crypt _openssl_crypt
00054 #include <openssl/ssl.h>
00055 #include <openssl/x509.h>
00056 #include <openssl/x509v3.h>
00057 #include <openssl/x509_vfy.h>
00058 #include <openssl/pem.h>
00059 #undef crypt
00060 #endif
00061 
00062 #include <kopenssl.h>
00063 #include <tqcstring.h>
00064 #include <kdebug.h>
00065 #include "ksslx509v3.h"
00066 
00067 
00068 
00069 static char hv[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
00070 
00071 
00072 class KSSLCertificatePrivate {
00073 public:
00074     KSSLCertificatePrivate() {
00075         kossl = KOSSL::self();
00076         _lastPurpose = KSSLCertificate::None;
00077     }
00078 
00079     ~KSSLCertificatePrivate() {
00080     }
00081 
00082     KSSLCertificate::KSSLValidation m_stateCache;
00083     bool m_stateCached;
00084     #ifdef KSSL_HAVE_SSL
00085         X509 *m_cert;
00086         X509_CRL *m_cert_crl;
00087     #endif
00088     KOSSL *kossl;
00089     KSSLCertChain _chain;
00090     KSSLX509V3 _extensions;
00091     KSSLCertificate::KSSLPurpose _lastPurpose;
00092 };
00093 
00094 KSSLCertificate::KSSLCertificate() {
00095     d = new KSSLCertificatePrivate;
00096     d->m_stateCached = false;
00097     TDEGlobal::dirs()->addResourceType("kssl", TDEStandardDirs::kde_default("data") + "kssl");
00098     #ifdef KSSL_HAVE_SSL
00099         d->m_cert = NULL;
00100         d->m_cert_crl = NULL;
00101     #endif
00102 }
00103 
00104 
00105 KSSLCertificate::KSSLCertificate(const KSSLCertificate& x) {
00106     d = new KSSLCertificatePrivate;
00107     d->m_stateCached = false;
00108     TDEGlobal::dirs()->addResourceType("kssl", TDEStandardDirs::kde_default("data") + "kssl");
00109     #ifdef KSSL_HAVE_SSL
00110         d->m_cert = NULL;
00111         d->m_cert_crl = NULL;
00112         setCert(KOSSL::self()->X509_dup(const_cast<KSSLCertificate&>(x).getCert()));
00113         KSSLCertChain *c = x.d->_chain.replicate();
00114         setChain(c->rawChain());
00115         delete c;
00116     #endif
00117 }
00118 
00119 
00120 
00121 KSSLCertificate::~KSSLCertificate() {
00122 #ifdef KSSL_HAVE_SSL
00123     if (d->m_cert) {
00124         d->kossl->X509_free(d->m_cert);
00125     }
00126     if (d->m_cert_crl) {
00127         d->kossl->X509_CRL_free(d->m_cert_crl);
00128     }
00129 #endif
00130     delete d;
00131 }
00132 
00133 
00134 KSSLCertChain& KSSLCertificate::chain() {
00135     return d->_chain;
00136 }
00137 
00138 
00139 KSSLCertificate *KSSLCertificate::fromX509(X509 *x5) {
00140 KSSLCertificate *n = NULL;
00141 #ifdef KSSL_HAVE_SSL
00142     if (x5) {
00143         n = new KSSLCertificate;
00144         n->setCert(KOSSL::self()->X509_dup(x5));
00145     }
00146 #endif
00147 return n;
00148 }
00149 
00150 
00151 KSSLCertificate *KSSLCertificate::fromString(TQCString cert) {
00152 KSSLCertificate *n = NULL;
00153 #ifdef KSSL_HAVE_SSL
00154     if (cert.length() == 0)
00155         return NULL;
00156 
00157     TQByteArray qba, qbb = cert.copy();
00158     KCodecs::base64Decode(qbb, qba);
00159     unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
00160     X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size());
00161     if (!x5c) {
00162         return NULL;
00163     }
00164 
00165     n = new KSSLCertificate;
00166     n->setCert(x5c);
00167 #endif
00168 return n;
00169 }
00170 
00171 KSSLCertificate *KSSLCertificate::crlFromString(TQCString cert) {
00172 KSSLCertificate *n = NULL;
00173 #ifdef KSSL_HAVE_SSL
00174     if (cert.length() == 0)
00175         return NULL;
00176 
00177     TQByteArray qba, qbb = cert.copy();
00178     KCodecs::base64Decode(qbb, qba);
00179     unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
00180     X509_CRL *x5c = KOSSL::self()->d2i_X509_CRL(NULL, &qbap, qba.size());
00181     if (!x5c) {
00182         return NULL;
00183     }
00184 
00185     n = new KSSLCertificate;
00186     n->setCRL(x5c);
00187 #endif
00188 return n;
00189 }
00190 
00191 
00192 
00193 TQString KSSLCertificate::getSubject() const {
00194 TQString rc = "";
00195 
00196 #ifdef KSSL_HAVE_SSL
00197     char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_subject_name(d->m_cert), 0, 0);
00198     if (!t)
00199         return rc;
00200     rc = t;
00201     d->kossl->CRYPTO_free(t);
00202 #endif
00203 return rc;
00204 }
00205 
00206 
00207 TQString KSSLCertificate::getSerialNumber() const {
00208 TQString rc = "";
00209 
00210 #ifdef KSSL_HAVE_SSL
00211     ASN1_INTEGER *aint = d->kossl->X509_get_serialNumber(d->m_cert);
00212     if (aint) {
00213         rc = ASN1_INTEGER_QString(aint);
00214         // d->kossl->ASN1_INTEGER_free(aint);   this makes the sig test fail
00215     }
00216 #endif
00217 return rc;
00218 }
00219 
00220 
00221 TQString KSSLCertificate::getSignatureText() const {
00222 TQString rc = "";
00223 
00224 #ifdef KSSL_HAVE_SSL
00225 char *s;
00226 int n, i;
00227 
00228     const ASN1_BIT_STRING *signature = 0L;
00229     const X509_ALGOR *sig_alg = 0L;
00230     d->kossl->X509_get0_signature(&signature, &sig_alg, d->m_cert);
00231     i = d->kossl->OBJ_obj2nid(sig_alg->algorithm);
00232     rc = i18n("Signature Algorithm: ");
00233     rc += (i == NID_undef)?i18n("Unknown"):TQString(d->kossl->OBJ_nid2ln(i));
00234 
00235     rc += "\n";
00236     rc += i18n("Signature Contents:");
00237     n = signature->length;
00238     s = (char *)signature->data;
00239     for (i = 0; i < n; i++) {
00240         if (i%20 != 0) rc += ":";
00241         else rc += "\n";
00242         rc.append(hv[(s[i]&0xf0)>>4]);
00243         rc.append(hv[s[i]&0x0f]);
00244     }
00245 
00246 #endif
00247 
00248 return rc;
00249 }
00250 
00251 
00252 void KSSLCertificate::getEmails(TQStringList &to) const {
00253     to.clear();
00254 #ifdef KSSL_HAVE_SSL
00255     if (!d->m_cert)
00256         return;
00257     
00258     STACK *s = d->kossl->X509_get1_email(d->m_cert);
00259     if (s) {
00260         for(int n=0; n < d->kossl->OPENSSL_sk_num(s); n++) {
00261             to.append(d->kossl->OPENSSL_sk_value(s,n));
00262         }
00263         d->kossl->X509_email_free(s);
00264     }
00265 #endif  
00266 }   
00267 
00268 
00269 TQString KSSLCertificate::getKDEKey() const {
00270     return getSubject() + " (" + getMD5DigestText() + ")";
00271 }
00272 
00273 
00274 TQString KSSLCertificate::getMD5DigestFromKDEKey(const TQString &k) {
00275     TQString rc;
00276     int pos = k.findRev('(');
00277     if (pos != -1) {
00278         unsigned int len = k.length();
00279         if (k.at(len-1) == ')') {
00280             rc = k.mid(pos+1, len-pos-2);
00281         }
00282     }
00283     return rc;
00284 }
00285 
00286 
00287 TQString KSSLCertificate::getMD5DigestText() const {
00288 TQString rc = "";
00289 
00290 #ifdef KSSL_HAVE_SSL
00291     unsigned int n;
00292     unsigned char md[EVP_MAX_MD_SIZE];
00293 
00294     if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) {
00295         return rc;
00296     }
00297 
00298     for (unsigned int j = 0; j < n; j++) {
00299         if (j > 0)
00300             rc += ":";
00301         rc.append(hv[(md[j]&0xf0)>>4]);
00302         rc.append(hv[md[j]&0x0f]);
00303     }
00304 
00305 #endif
00306 
00307 return rc;
00308 }
00309 
00310 
00311 
00312 TQString KSSLCertificate::getMD5Digest() const {
00313 TQString rc = "";
00314 
00315 #ifdef KSSL_HAVE_SSL
00316     unsigned int n;
00317     unsigned char md[EVP_MAX_MD_SIZE];
00318 
00319     if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) {
00320         return rc;
00321     }
00322 
00323     for (unsigned int j = 0; j < n; j++) {
00324         rc.append(hv[(md[j]&0xf0)>>4]);
00325         rc.append(hv[md[j]&0x0f]);
00326     }
00327 
00328 #endif
00329 
00330 return rc;
00331 }
00332 
00333 
00334 
00335 TQString KSSLCertificate::getKeyType() const {
00336 TQString rc = "";
00337 
00338 #ifdef KSSL_HAVE_SSL
00339     EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert);
00340     if (pkey) {
00341         #ifndef NO_RSA
00342             if (d->kossl->EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA)
00343                 rc = "RSA";
00344             else
00345         #endif
00346         #ifndef NO_DSA
00347             if (d->kossl->EVP_PKEY_base_id(pkey) == EVP_PKEY_DSA)
00348                 rc = "DSA";
00349             else
00350         #endif
00351                 rc = "Unknown";
00352         d->kossl->EVP_PKEY_free(pkey);
00353     }
00354 #endif
00355 
00356 return rc;
00357 }
00358 
00359 
00360 
00361 TQString KSSLCertificate::getPublicKeyText() const {
00362 TQString rc = "";
00363 char *x = NULL;
00364 
00365 #ifdef KSSL_HAVE_SSL
00366     EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert);
00367     if (pkey) {
00368         rc = i18n("Unknown", "Unknown key algorithm");
00369         #ifndef NO_RSA
00370             if (d->kossl->EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
00371                 rc = i18n("Key type: RSA (%1 bit)") + "\n";
00372 
00373                 RSA *pkey_rsa = d->kossl->EVP_PKEY_get0_RSA(pkey);
00374                 const BIGNUM *bn_n = 0L;
00375                 const BIGNUM *bn_e = 0L;
00376                 d->kossl->RSA_get0_key(pkey_rsa, &bn_n, &bn_e, NULL);
00377                 x = d->kossl->BN_bn2hex(bn_n);
00378                 rc += i18n("Modulus: ");
00379                 rc = rc.arg(strlen(x)*4);
00380                 for (unsigned int i = 0; i < strlen(x); i++) {
00381                     if (i%40 != 0 && i%2 == 0)
00382                         rc += ":";
00383                     else if (i%40 == 0)
00384                         rc += "\n";
00385                     rc += x[i];
00386                 }
00387                 rc += "\n";
00388                 d->kossl->CRYPTO_free(x);
00389 
00390                 x = d->kossl->BN_bn2hex(bn_e);
00391                 rc += i18n("Exponent: 0x") + x + "\n";
00392                 d->kossl->CRYPTO_free(x);
00393             }
00394         #endif
00395         #ifndef NO_DSA
00396             if (d->kossl->EVP_PKEY_base_id(pkey) == EVP_PKEY_DSA) {
00397                 rc = i18n("Key type: DSA (%1 bit)") + "\n";
00398 
00399                 DSA *pkey_dsa = d->kossl->EVP_PKEY_get0_DSA(pkey);
00400                 const BIGNUM *bn_p = 0L;
00401                 const BIGNUM *bn_q = 0L;
00402                 const BIGNUM *bn_g = 0L;
00403                 const BIGNUM *bn_pub_key = 0L;
00404                 d->kossl->DSA_get0_pqg(pkey_dsa, &bn_p, &bn_q, &bn_g);
00405                 d->kossl->DSA_get0_key(pkey_dsa, &bn_pub_key, NULL);
00406 
00407                 x = d->kossl->BN_bn2hex(bn_p);
00408                 rc += i18n("Prime: ");
00409                 // hack - this may not be always accurate
00410                 rc = rc.arg(strlen(x)*4) ;
00411                 for (unsigned int i = 0; i < strlen(x); i++) {
00412                     if (i%40 != 0 && i%2 == 0)
00413                         rc += ":";
00414                     else if (i%40 == 0)
00415                         rc += "\n";
00416                     rc += x[i];
00417                 }
00418                 rc += "\n";
00419                 d->kossl->CRYPTO_free(x);
00420 
00421                 x = d->kossl->BN_bn2hex(bn_q);
00422                 rc += i18n("160 bit prime factor: ");
00423                 for (unsigned int i = 0; i < strlen(x); i++) {
00424                     if (i%40 != 0 && i%2 == 0)
00425                         rc += ":";
00426                     else if (i%40 == 0)
00427                         rc += "\n";
00428                     rc += x[i];
00429                 }
00430                 rc += "\n";
00431                 d->kossl->CRYPTO_free(x);
00432     
00433                 x = d->kossl->BN_bn2hex(bn_g);
00434                 rc += TQString("g: ");
00435                 for (unsigned int i = 0; i < strlen(x); i++) {
00436                     if (i%40 != 0 && i%2 == 0)
00437                         rc += ":";
00438                     else if (i%40 == 0)
00439                         rc += "\n";
00440                     rc += x[i];
00441                 }
00442                 rc += "\n";
00443                 d->kossl->CRYPTO_free(x);
00444     
00445                 x = d->kossl->BN_bn2hex(bn_pub_key);
00446                 rc += i18n("Public key: ");
00447                 for (unsigned int i = 0; i < strlen(x); i++) {
00448                     if (i%40 != 0 && i%2 == 0)
00449                         rc += ":";
00450                     else if (i%40 == 0)
00451                         rc += "\n";
00452                     rc += x[i];
00453                 }
00454                 rc += "\n";
00455                 d->kossl->CRYPTO_free(x);
00456             }
00457         #endif
00458         d->kossl->EVP_PKEY_free(pkey);
00459     }
00460 #endif
00461 
00462 return rc;
00463 }
00464 
00465 
00466 
00467 TQString KSSLCertificate::getIssuer() const {
00468 TQString rc = "";
00469 
00470 #ifdef KSSL_HAVE_SSL
00471     char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_issuer_name(d->m_cert), 0, 0);
00472 
00473     if (!t)
00474         return rc;
00475 
00476     rc = t;
00477     d->kossl->CRYPTO_free(t);
00478 #endif
00479 
00480 return rc;
00481 }
00482 
00483 void KSSLCertificate::setChain(void *c) {
00484 #ifdef KSSL_HAVE_SSL
00485     d->_chain.setChain(c);
00486 #endif
00487     d->m_stateCached = false;
00488     d->m_stateCache = KSSLCertificate::Unknown;
00489 }
00490 
00491 void KSSLCertificate::setCert(X509 *c) {
00492 #ifdef KSSL_HAVE_SSL
00493 d->m_cert = c;
00494 if (c) {
00495     d->_extensions.flags = 0;
00496     d->kossl->X509_check_purpose(c, -1, 0);    // setup the fields (!!)
00497 
00498 #if 0
00499     kdDebug(7029) << "---------------- Certificate ------------------" 
00500               << endl;
00501     kdDebug(7029) << getSubject() << endl;
00502 #endif
00503 
00504     for (int j = 0; j < d->kossl->X509_PURPOSE_get_count(); j++) {
00505         X509_PURPOSE *ptmp = d->kossl->X509_PURPOSE_get0(j);
00506         int id = d->kossl->X509_PURPOSE_get_id(ptmp);
00507         for (int ca = 0; ca < 2; ca++) {
00508             int idret = d->kossl->X509_check_purpose(c, id, ca);
00509             if (idret == 1 || idret == 2) {   // have it
00510 //              kdDebug() << "PURPOSE: " << id << (ca?" CA":"") << endl;
00511                 if (!ca)
00512                     d->_extensions.flags |= (1L <<(id-1));
00513                 else d->_extensions.flags |= (1L <<(16+id-1));
00514             } else {
00515                 if (!ca)
00516                     d->_extensions.flags &= ~(1L <<(id-1));
00517                 else d->_extensions.flags &= ~(1L <<(16+id-1));
00518             }
00519         }
00520     }
00521 
00522 #if 0
00523     kdDebug(7029) << "flags: " << TQString::number(c->ex_flags, 2)
00524               << "\nkeyusage: " << TQString::number(c->ex_kusage, 2)
00525               << "\nxkeyusage: " << TQString::number(c->ex_xkusage, 2)
00526               << "\nnscert: " << TQString::number(c->ex_nscert, 2)
00527               << endl;
00528     if (c->ex_flags & EXFLAG_KUSAGE)
00529         kdDebug(7029) << "     --- Key Usage extensions found" << endl;
00530         else kdDebug(7029) << "     --- Key Usage extensions NOT found" << endl;
00531 
00532     if (c->ex_flags & EXFLAG_XKUSAGE)
00533         kdDebug(7029) << "     --- Extended key usage extensions found" << endl;
00534         else kdDebug(7029) << "     --- Extended key usage extensions NOT found" << endl;
00535 
00536     if (c->ex_flags & EXFLAG_NSCERT)
00537         kdDebug(7029) << "     --- NS extensions found" << endl;
00538         else kdDebug(7029) << "     --- NS extensions NOT found" << endl;
00539 
00540         if (d->_extensions.certTypeSSLCA())
00541                 kdDebug(7029) << "NOTE: this is an SSL CA file." << endl;
00542         else kdDebug(7029) << "NOTE: this is NOT an SSL CA file." << endl;
00543 
00544         if (d->_extensions.certTypeEmailCA())
00545                 kdDebug(7029) << "NOTE: this is an EMAIL CA file." << endl;
00546         else kdDebug(7029) << "NOTE: this is NOT an EMAIL CA file." << endl;
00547 
00548         if (d->_extensions.certTypeCodeCA())
00549                 kdDebug(7029) << "NOTE: this is a CODE CA file." << endl;
00550         else kdDebug(7029) << "NOTE: this is NOT a CODE CA file." << endl;
00551 
00552         if (d->_extensions.certTypeSSLClient())
00553                 kdDebug(7029) << "NOTE: this is an SSL client." << endl;
00554         else kdDebug(7029) << "NOTE: this is NOT an SSL client." << endl;
00555 
00556         if (d->_extensions.certTypeSSLServer())
00557                 kdDebug(7029) << "NOTE: this is an SSL server." << endl;
00558         else kdDebug(7029) << "NOTE: this is NOT an SSL server." << endl;
00559 
00560         if (d->_extensions.certTypeNSSSLServer())
00561                 kdDebug(7029) << "NOTE: this is a NETSCAPE SSL server." << endl;
00562         else kdDebug(7029) << "NOTE: this is NOT a NETSCAPE SSL server." << endl;
00563 
00564         if (d->_extensions.certTypeSMIME())
00565                 kdDebug(7029) << "NOTE: this is an SMIME certificate." << endl;
00566         else kdDebug(7029) << "NOTE: this is NOT an SMIME certificate." << endl;
00567 
00568         if (d->_extensions.certTypeSMIMEEncrypt())
00569                 kdDebug(7029) << "NOTE: this is an SMIME encrypt cert." << endl;
00570         else kdDebug(7029) << "NOTE: this is NOT an SMIME encrypt cert." << endl;
00571 
00572         if (d->_extensions.certTypeSMIMESign())
00573                 kdDebug(7029) << "NOTE: this is an SMIME sign cert." << endl;
00574         else kdDebug(7029) << "NOTE: this is NOT an SMIME sign cert." << endl;
00575 
00576         if (d->_extensions.certTypeCRLSign())
00577                 kdDebug(7029) << "NOTE: this is a CRL signer." << endl;
00578         else kdDebug(7029) << "NOTE: this is NOT a CRL signer." << endl;
00579 
00580     kdDebug(7029) << "-----------------------------------------------" 
00581               << endl;
00582 #endif
00583 }
00584 #endif
00585 d->m_stateCached = false;
00586 d->m_stateCache = KSSLCertificate::Unknown;
00587 }
00588 
00589 void KSSLCertificate::setCRL(X509_CRL *c) {
00590 #ifdef KSSL_HAVE_SSL
00591 d->m_cert_crl = c;
00592 if (c) {
00593     d->_extensions.flags = 0;
00594 }
00595 #endif
00596 d->m_stateCached = false;
00597 d->m_stateCache = KSSLCertificate::Unknown;
00598 }
00599 
00600 X509 *KSSLCertificate::getCert() {
00601 #ifdef KSSL_HAVE_SSL
00602     return d->m_cert;
00603 #endif
00604 return 0;
00605 }
00606 
00607 // pull in the callback.  It's common across multiple files but we want
00608 // it to be hidden.
00609 
00610 #include "ksslcallback.c"
00611 
00612 
00613 bool KSSLCertificate::isValid(KSSLCertificate::KSSLPurpose p) {
00614     return (validate(p) == KSSLCertificate::Ok);
00615 }
00616 
00617 
00618 bool KSSLCertificate::isValid() {
00619     return isValid(KSSLCertificate::SSLServer);
00620 }
00621 
00622 
00623 int KSSLCertificate::purposeToOpenSSL(KSSLCertificate::KSSLPurpose p) const {
00624 int rc = 0;
00625 #ifdef KSSL_HAVE_SSL
00626     if (p == KSSLCertificate::SSLServer) {
00627         rc = X509_PURPOSE_SSL_SERVER;
00628     } else if (p == KSSLCertificate::SSLClient) {
00629         rc = X509_PURPOSE_SSL_CLIENT;
00630     } else if (p == KSSLCertificate::SMIMEEncrypt) {
00631         rc = X509_PURPOSE_SMIME_ENCRYPT;
00632     } else if (p == KSSLCertificate::SMIMESign) {
00633         rc = X509_PURPOSE_SMIME_SIGN;
00634     } else if (p == KSSLCertificate::Any) {
00635         rc = X509_PURPOSE_ANY;
00636     }
00637 #endif
00638 return rc;  
00639 }
00640 
00641 
00642 // For backward compatibility
00643 KSSLCertificate::KSSLValidation KSSLCertificate::validate() {
00644     return validate(KSSLCertificate::SSLServer);
00645 }
00646 
00647 KSSLCertificate::KSSLValidation KSSLCertificate::validate(KSSLCertificate::KSSLPurpose purpose)
00648 {
00649     KSSLValidationList result = validateVerbose(purpose);
00650     if (result.isEmpty())
00651         return KSSLCertificate::Ok;
00652     else
00653         return result.first();
00654 } 
00655 
00656 //
00657 // See apps/verify.c in OpenSSL for the source of most of this logic.
00658 //
00659 
00660 // CRL files?  we don't do that yet
00661 KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose) 
00662 {
00663     return validateVerbose(purpose, 0);
00664 }
00665 
00666 KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose, KSSLCertificate *ca)
00667 {
00668     KSSLValidationList errors;
00669     if (ca || (d->_lastPurpose != purpose)) {
00670         d->m_stateCached = false;
00671     }
00672 
00673     if (!d->m_stateCached)
00674         d->_lastPurpose = purpose;
00675 
00676 #ifdef KSSL_HAVE_SSL
00677     X509_STORE *certStore;
00678     X509_LOOKUP *certLookup;
00679     X509_STORE_CTX *certStoreCTX;
00680 
00681     if (!d->m_cert)
00682     {
00683         errors << KSSLCertificate::Unknown;
00684         return errors;
00685     }
00686 
00687     if (d->m_stateCached) {
00688         errors << d->m_stateCache;
00689         return errors;
00690     }
00691 
00692     TQStringList qsl = TDEGlobal::dirs()->resourceDirs("kssl");
00693 
00694     if (qsl.isEmpty()) {
00695         errors << KSSLCertificate::NoCARoot;
00696         return errors;
00697     }
00698 
00699     KSSLCertificate::KSSLValidation ksslv = Unknown;
00700 
00701     for (TQStringList::Iterator j = qsl.begin(); j != qsl.end(); ++j) {
00702         struct stat sb;
00703         TQString _j = (*j) + "ca-bundle.crt";
00704         if (-1 == stat(_j.ascii(), &sb)) {
00705             continue;
00706         }
00707 
00708         certStore = d->kossl->X509_STORE_new();
00709         if (!certStore) {
00710             errors << KSSLCertificate::Unknown;
00711             return errors;
00712         }
00713 
00714         d->kossl->X509_STORE_set_verify_cb(certStore, X509Callback);
00715 
00716         certLookup = d->kossl->X509_STORE_add_lookup(certStore, d->kossl->X509_LOOKUP_file());
00717         if (!certLookup) {
00718             ksslv = KSSLCertificate::Unknown;
00719             d->kossl->X509_STORE_free(certStore);
00720             continue;
00721         }
00722 
00723         if (!d->kossl->X509_LOOKUP_load_file(certLookup, _j.ascii(), X509_FILETYPE_PEM)) {
00724             // error accessing directory and loading pems
00725             kdDebug(7029) << "KSSL couldn't read CA root: " 
00726                     << _j << endl;
00727             ksslv = KSSLCertificate::ErrorReadingRoot;
00728             d->kossl->X509_STORE_free(certStore);
00729             continue;
00730         }
00731 
00732         // This is the checking code
00733         certStoreCTX = d->kossl->X509_STORE_CTX_new();
00734 
00735         // this is a bad error - could mean no free memory.
00736         // This may be the wrong thing to do here
00737         if (!certStoreCTX) {
00738             kdDebug(7029) << "KSSL couldn't create an X509 store context." << endl;
00739             d->kossl->X509_STORE_free(certStore);
00740             continue;
00741         }
00742 
00743         d->kossl->X509_STORE_CTX_init(certStoreCTX, certStore, d->m_cert, NULL);
00744         if (d->_chain.isValid()) {
00745             d->kossl->X509_STORE_CTX_set0_untrusted(certStoreCTX, (STACK_OF(X509)*)d->_chain.rawChain());
00746         }
00747 
00748         //kdDebug(7029) << "KSSL setting CRL.............." << endl;
00749         // int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
00750 
00751         d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX, purposeToOpenSSL(purpose));
00752 
00753         KSSL_X509CallBack_ca = ca ? ca->d->m_cert : 0;
00754         KSSL_X509CallBack_ca_found = false;
00755 
00756         d->kossl->X509_STORE_CTX_set_error(certStoreCTX, X509_V_OK);
00757         d->kossl->X509_verify_cert(certStoreCTX);
00758         int errcode = d->kossl->X509_STORE_CTX_get_error(certStoreCTX);
00759         if (ca && !KSSL_X509CallBack_ca_found) {
00760             ksslv = KSSLCertificate::Irrelevant;
00761         } else {
00762             ksslv = processError(errcode);
00763         }
00764         // For servers, we can try NS_SSL_SERVER too
00765         if (    (ksslv != KSSLCertificate::Ok) &&
00766             (ksslv != KSSLCertificate::Irrelevant) &&
00767             purpose == KSSLCertificate::SSLServer) {
00768             d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX,
00769                         X509_PURPOSE_NS_SSL_SERVER);
00770 
00771             d->kossl->X509_STORE_CTX_set_error(certStoreCTX, X509_V_OK);
00772             d->kossl->X509_verify_cert(certStoreCTX);
00773             errcode = d->kossl->X509_STORE_CTX_get_error(certStoreCTX);
00774             ksslv = processError(errcode);
00775         }
00776         d->kossl->X509_STORE_CTX_free(certStoreCTX);
00777         d->kossl->X509_STORE_free(certStore);
00778         // end of checking code
00779         //
00780 
00781         //kdDebug(7029) << "KSSL Validation procedure RC: " 
00782         //      << rc << endl;
00783         //kdDebug(7029) << "KSSL Validation procedure errcode: "
00784         //      << errcode << endl;
00785         //kdDebug(7029) << "KSSL Validation procedure RESULTS: "
00786         //      << ksslv << endl;
00787 
00788         if (ksslv != NoCARoot && ksslv != InvalidCA) {
00789             d->m_stateCached = true;
00790             d->m_stateCache = ksslv;
00791         }
00792         break;
00793     }
00794     
00795     if (ksslv != KSSLCertificate::Ok)
00796         errors << ksslv;
00797 #else
00798     errors << KSSLCertificate::NoSSL;
00799 #endif
00800     return errors;
00801 }
00802 
00803 
00804 
00805 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate() {
00806     return revalidate(KSSLCertificate::SSLServer);
00807 }
00808 
00809 
00810 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate(KSSLCertificate::KSSLPurpose p) {
00811     d->m_stateCached = false;
00812     return validate(p);
00813 }
00814 
00815 
00816 KSSLCertificate::KSSLValidation KSSLCertificate::processError(int ec) {
00817 KSSLCertificate::KSSLValidation rc;
00818 
00819 rc = KSSLCertificate::Unknown;
00820 #ifdef KSSL_HAVE_SSL
00821     switch (ec) {
00822     case X509_V_OK:       // OK
00823         rc = KSSLCertificate::Ok;
00824     break;
00825 
00826 
00827     case X509_V_ERR_CERT_REJECTED:
00828         rc = KSSLCertificate::Rejected;
00829     break;
00830 
00831 
00832     case X509_V_ERR_CERT_UNTRUSTED:
00833         rc = KSSLCertificate::Untrusted;
00834     break;
00835 
00836 
00837     case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
00838     case X509_V_ERR_CERT_SIGNATURE_FAILURE:
00839     case X509_V_ERR_CRL_SIGNATURE_FAILURE:
00840     case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
00841     case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
00842         rc = KSSLCertificate::SignatureFailed;
00843     break;
00844 
00845     case X509_V_ERR_INVALID_CA:
00846     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
00847     case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
00848     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
00849         rc = KSSLCertificate::InvalidCA;
00850     break;
00851 
00852 
00853     case X509_V_ERR_INVALID_PURPOSE:
00854         rc = KSSLCertificate::InvalidPurpose;
00855     break;
00856 
00857 
00858     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
00859         rc = KSSLCertificate::SelfSigned;
00860     break;
00861 
00862     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
00863         rc = KSSLCertificate::SelfSignedChain;
00864     break;
00865 
00866     case X509_V_ERR_CERT_REVOKED:
00867         rc = KSSLCertificate::Revoked;
00868     break;
00869 
00870     case X509_V_ERR_PATH_LENGTH_EXCEEDED:
00871         rc = KSSLCertificate::PathLengthExceeded;
00872     break;
00873 
00874     case X509_V_ERR_CERT_NOT_YET_VALID:
00875     case X509_V_ERR_CERT_HAS_EXPIRED:
00876     case X509_V_ERR_CRL_NOT_YET_VALID:
00877     case X509_V_ERR_CRL_HAS_EXPIRED:
00878     case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
00879     case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
00880     case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
00881     case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
00882         rc = KSSLCertificate::Expired;
00883         kdDebug(7029) << "KSSL apparently this is expired.  Not after: "
00884                 << getNotAfter() << endl;
00885     break;
00886 
00887     //case 1:
00888     case X509_V_ERR_APPLICATION_VERIFICATION:
00889     case X509_V_ERR_OUT_OF_MEM:
00890     case X509_V_ERR_UNABLE_TO_GET_CRL:
00891     case X509_V_ERR_CERT_CHAIN_TOO_LONG:
00892     default:
00893         rc = KSSLCertificate::Unknown;
00894     break;
00895 }
00896 
00897 d->m_stateCache = rc;
00898 d->m_stateCached = true;
00899 #endif
00900 return rc;
00901 }
00902 
00903 
00904 TQString KSSLCertificate::getNotBefore() const {
00905 #ifdef KSSL_HAVE_SSL
00906 return ASN1_UTCTIME_QString(d->kossl->X509_getm_notBefore(d->m_cert));
00907 #else
00908 return TQString::null;
00909 #endif
00910 }
00911 
00912 
00913 TQString KSSLCertificate::getNotAfter() const {
00914 #ifdef KSSL_HAVE_SSL
00915 return ASN1_UTCTIME_QString(d->kossl->X509_getm_notAfter(d->m_cert));
00916 #else
00917 return TQString::null;
00918 #endif
00919 }
00920 
00921 
00922 TQDateTime KSSLCertificate::getQDTNotBefore() const {
00923 #ifdef KSSL_HAVE_SSL
00924 return ASN1_UTCTIME_QDateTime(d->kossl->X509_getm_notBefore(d->m_cert), NULL);
00925 #else
00926 return TQDateTime::currentDateTime();
00927 #endif
00928 }
00929 
00930 
00931 TQDateTime KSSLCertificate::getQDTNotAfter() const {
00932 #ifdef KSSL_HAVE_SSL
00933 return ASN1_UTCTIME_QDateTime(d->kossl->X509_getm_notAfter(d->m_cert), NULL);
00934 #else
00935 return TQDateTime::currentDateTime();
00936 #endif
00937 }
00938 
00939 
00940 TQDateTime KSSLCertificate::getQDTLastUpdate() const {
00941 #ifdef KSSL_HAVE_SSL
00942 return ASN1_UTCTIME_QDateTime((ASN1_UTCTIME*)d->kossl->X509_CRL_get0_lastUpdate(d->m_cert_crl), NULL);
00943 #else
00944 return TQDateTime::currentDateTime();
00945 #endif
00946 }
00947 
00948 
00949 TQDateTime KSSLCertificate::getQDTNextUpdate() const {
00950 #ifdef KSSL_HAVE_SSL
00951 return ASN1_UTCTIME_QDateTime((ASN1_UTCTIME*)d->kossl->X509_CRL_get0_nextUpdate(d->m_cert_crl), NULL);
00952 #else
00953 return TQDateTime::currentDateTime();
00954 #endif
00955 }
00956 
00957 
00958 int operator==(KSSLCertificate &x, KSSLCertificate &y) {
00959 #ifndef KSSL_HAVE_SSL
00960   return 1;
00961 #else
00962   if (!KOSSL::self()->X509_cmp(x.getCert(), y.getCert())) return 1;
00963   return 0;
00964 #endif
00965 }
00966 
00967 
00968 KSSLCertificate *KSSLCertificate::replicate() {
00969 // The new certificate doesn't have the cached value.  It's probably
00970 // better this way.  We can't anticipate every reason for doing this.
00971 KSSLCertificate *newOne = new KSSLCertificate();
00972 #ifdef KSSL_HAVE_SSL
00973     newOne->setCert(d->kossl->X509_dup(getCert()));
00974     KSSLCertChain *c = d->_chain.replicate();
00975     newOne->setChain(c->rawChain());
00976     delete c;
00977 #endif
00978 return newOne;
00979 }
00980 
00981 
00982 TQString KSSLCertificate::toString() {
00983 return KCodecs::base64Encode(toDer());
00984 }
00985 
00986 
00987 TQString KSSLCertificate::verifyText(KSSLValidation x) {
00988 switch (x) {
00989 case KSSLCertificate::Ok:
00990     return i18n("The certificate is valid.");
00991 case KSSLCertificate::PathLengthExceeded:
00992 case KSSLCertificate::ErrorReadingRoot:
00993 case KSSLCertificate::NoCARoot:
00994     return i18n("Certificate signing authority root files could not be found so the certificate is not verified.");
00995 case KSSLCertificate::SelfSignedChain:
00996 case KSSLCertificate::InvalidCA:
00997     return i18n("Certificate signing authority is unknown or invalid.");
00998 case KSSLCertificate::SelfSigned:
00999     return i18n("Certificate is self-signed and thus may not be trustworthy.");
01000 case KSSLCertificate::Expired:
01001     return i18n("Certificate has expired.");
01002 case KSSLCertificate::Revoked:
01003     return i18n("Certificate has been revoked.");
01004 case KSSLCertificate::NoSSL:
01005     return i18n("SSL support was not found.");
01006 case KSSLCertificate::Untrusted:
01007     return i18n("Signature is untrusted.");
01008 case KSSLCertificate::SignatureFailed:
01009     return i18n("Signature test failed.");
01010 case KSSLCertificate::Rejected:
01011 case KSSLCertificate::InvalidPurpose:
01012     return i18n("Rejected, possibly due to an invalid purpose.");
01013 case KSSLCertificate::PrivateKeyFailed:
01014     return i18n("Private key test failed.");
01015 case KSSLCertificate::InvalidHost:
01016     return i18n("The certificate has not been issued for this host.");
01017 case KSSLCertificate::Irrelevant:
01018     return i18n("This certificate is not relevant.");
01019 default:
01020 break;
01021 }
01022 
01023 return i18n("The certificate is invalid.");
01024 }
01025 
01026 
01027 TQByteArray KSSLCertificate::toDer() {
01028 TQByteArray qba;
01029 #ifdef KSSL_HAVE_SSL
01030 unsigned int certlen = d->kossl->i2d_X509(getCert(), NULL);
01031 unsigned char *cert = new unsigned char[certlen];
01032 unsigned char *p = cert;
01033     // FIXME: return code!
01034     d->kossl->i2d_X509(getCert(), &p);
01035 
01036     // encode it into a QString
01037     qba.duplicate((const char*)cert, certlen);
01038     delete[] cert;
01039 #endif
01040 return qba;
01041 }
01042 
01043 
01044 
01045 TQByteArray KSSLCertificate::toPem() {
01046 TQByteArray qba;
01047 TQString thecert = toString();
01048 const char *header = "-----BEGIN CERTIFICATE-----\n";
01049 const char *footer = "-----END CERTIFICATE-----\n";
01050 
01051     // We just do base64 on the ASN1
01052     //  64 character lines  (unpadded)
01053     unsigned int xx = thecert.length() - 1;
01054     for (unsigned int i = 0; i < xx/64; i++) {
01055         thecert.insert(64*(i+1)+i, '\n');
01056     }
01057 
01058     thecert.prepend(header);
01059 
01060     if (thecert[thecert.length()-1] != '\n')
01061         thecert += "\n";
01062 
01063     thecert.append(footer);
01064 
01065     qba.duplicate(thecert.local8Bit(), thecert.length());
01066 return qba;
01067 }
01068 
01069 
01070 #define NETSCAPE_CERT_HDR     "certificate"
01071 #ifdef KSSL_HAVE_SSL
01072 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
01073 typedef struct NETSCAPE_X509_st
01074 {
01075     ASN1_OCTET_STRING *header;
01076     X509 *cert;
01077 } NETSCAPE_X509;
01078 #endif
01079 #endif
01080 
01081 // what a piece of crap this is
01082 TQByteArray KSSLCertificate::toNetscape() {
01083 TQByteArray qba;
01084 #ifdef KSSL_HAVE_SSL
01085 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
01086     NETSCAPE_X509 nx;
01087     ASN1_OCTET_STRING hdr;
01088 #else
01089   ASN1_HEADER ah;
01090   ASN1_OCTET_STRING os;
01091 #endif
01092     KTempFile ktf;
01093 
01094 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
01095     hdr.data = (unsigned char *)NETSCAPE_CERT_HDR;
01096     hdr.length = strlen(NETSCAPE_CERT_HDR);
01097     nx.header = &hdr;
01098     nx.cert = getCert();
01099 
01100     d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&nx);
01101 #else
01102    os.data = (unsigned char *)NETSCAPE_CERT_HDR;
01103    os.length = strlen(NETSCAPE_CERT_HDR);
01104    ah.header = &os;
01105    ah.data = (char *)getCert();
01106    ah.meth = d->kossl->X509_asn1_meth();
01107 
01108    d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&ah);
01109 #endif
01110 
01111     ktf.close();
01112 
01113     TQFile qf(ktf.name());
01114     qf.open(IO_ReadOnly);
01115     char *buf = new char[qf.size()];
01116     qf.readBlock(buf, qf.size());
01117     qba.duplicate(buf, qf.size());
01118     qf.close();
01119     delete[] buf;
01120 
01121     ktf.unlink();
01122 
01123 #endif
01124 return qba;
01125 }
01126 
01127 
01128 
01129 TQString KSSLCertificate::toText() {
01130 TQString text;
01131 #ifdef KSSL_HAVE_SSL
01132 KTempFile ktf;
01133 
01134     d->kossl->X509_print(ktf.fstream(), getCert());
01135     ktf.close();
01136 
01137     TQFile qf(ktf.name());
01138     qf.open(IO_ReadOnly);
01139     char *buf = new char[qf.size()+1];
01140     qf.readBlock(buf, qf.size());
01141     buf[qf.size()] = 0;
01142     text = buf;
01143     delete[] buf;
01144     qf.close();
01145     ktf.unlink();
01146 #endif
01147 return text;
01148 }
01149 
01150 // KDE 4: Make it const TQString &
01151 bool KSSLCertificate::setCert(TQString& cert) {
01152 #ifdef KSSL_HAVE_SSL
01153 TQByteArray qba, qbb = cert.local8Bit().copy();
01154     KCodecs::base64Decode(qbb, qba);
01155     unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
01156     X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size());
01157     if (x5c) {
01158         setCert(x5c);
01159         return true;
01160     }
01161 #endif
01162 return false;
01163 }
01164 
01165 
01166 KSSLX509V3& KSSLCertificate::x509V3Extensions() {
01167 return d->_extensions;
01168 }
01169 
01170 
01171 bool KSSLCertificate::isSigner() {
01172 return d->_extensions.certTypeCA();
01173 }
01174 
01175 
01176 TQStringList KSSLCertificate::subjAltNames() const {
01177     TQStringList rc;
01178 #ifdef KSSL_HAVE_SSL
01179     STACK_OF(GENERAL_NAME) *names;
01180     names = (STACK_OF(GENERAL_NAME)*)d->kossl->X509_get_ext_d2i(d->m_cert, NID_subject_alt_name, 0, 0);
01181 
01182     if (!names) {
01183         return rc;
01184     }
01185 
01186     int cnt = d->kossl->OPENSSL_sk_num(names);
01187 
01188     for (int i = 0; i < cnt; i++) {
01189         const GENERAL_NAME *val = (const GENERAL_NAME *)d->kossl->OPENSSL_sk_value(names, i);
01190         if (val->type != GEN_DNS) {
01191             continue;
01192         }
01193 
01194         TQString s = (const char *)d->kossl->ASN1_STRING_data(val->d.ia5);
01195         if (!s.isEmpty()  &&
01196                 /* skip subjectAltNames with embedded NULs */
01197                 s.length() == (unsigned int)d->kossl->ASN1_STRING_length(val->d.ia5)) {
01198             rc += s;
01199         }
01200     }
01201     d->kossl->OPENSSL_sk_free(names);
01202 #endif
01203     return rc;
01204 }
01205 
01206 
01207 TQDataStream& operator<<(TQDataStream& s, const KSSLCertificate& r) {
01208 TQStringList qsl;
01209 TQPtrList<KSSLCertificate> cl = const_cast<KSSLCertificate&>(r).chain().getChain();
01210 
01211     for (KSSLCertificate *c = cl.first(); c != 0; c = cl.next()) {
01212         qsl << c->toString();
01213     }
01214 
01215     cl.setAutoDelete(true);
01216 
01217     s << const_cast<KSSLCertificate&>(r).toString() << qsl;
01218 
01219 return s;
01220 }
01221 
01222 
01223 TQDataStream& operator>>(TQDataStream& s, KSSLCertificate& r) {
01224 TQStringList qsl;
01225 TQString cert;
01226 
01227 s >> cert >> qsl;
01228 
01229     if (r.setCert(cert) && !qsl.isEmpty())
01230         r.chain().setCertChain(qsl);
01231 
01232 return s;
01233 }
01234 
01235 
01236 

tdeio/kssl

Skip menu "tdeio/kssl"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

tdeio/kssl

Skip menu "tdeio/kssl"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/kssl by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.