• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kio

ksslcertificate.cc

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

kio

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal