kio Library API Documentation

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., 59 Temple Place - Suite 330,
00018  * Boston, MA 02111-1307, 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"):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::getKeyType() const {
00283 QString rc = "";
00284 
00285 #ifdef KSSL_HAVE_SSL
00286     EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert);
00287     if (pkey) {
00288         #ifndef NO_RSA
00289             if (pkey->type == EVP_PKEY_RSA)
00290                 rc = "RSA";
00291             else
00292         #endif
00293         #ifndef NO_DSA
00294             if (pkey->type == EVP_PKEY_DSA)
00295                 rc = "DSA";
00296             else
00297         #endif
00298                 rc = "Unknown";
00299         d->kossl->EVP_PKEY_free(pkey);
00300     }
00301 #endif
00302 
00303 return rc;
00304 }
00305 
00306 
00307 
00308 QString KSSLCertificate::getPublicKeyText() const {
00309 QString rc = "";
00310 char *x = NULL;
00311 
00312 #ifdef KSSL_HAVE_SSL
00313     EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert);
00314     if (pkey) {
00315         rc = i18n("Unknown", "Unknown key algorithm");
00316         #ifndef NO_RSA
00317             if (pkey->type == EVP_PKEY_RSA) {
00318                 rc = i18n("Key type: RSA (%1 bit)") + "\n";
00319 
00320                 x = d->kossl->BN_bn2hex(pkey->pkey.rsa->n);
00321                 rc += i18n("Modulus: ");
00322                 rc = rc.arg(strlen(x)*4);
00323                 for (unsigned int i = 0; i < strlen(x); i++) {
00324                     if (i%40 != 0 && i%2 == 0)
00325                         rc += ":";
00326                     else if (i%40 == 0)
00327                         rc += "\n";
00328                     rc += x[i];
00329                 }
00330                 rc += "\n";
00331                 d->kossl->OPENSSL_free(x);
00332 
00333                 x = d->kossl->BN_bn2hex(pkey->pkey.rsa->e);
00334                 rc += i18n("Exponent: 0x") + x + "\n";
00335                 d->kossl->OPENSSL_free(x);
00336             }
00337         #endif
00338         #ifndef NO_DSA
00339             if (pkey->type == EVP_PKEY_DSA) {
00340                 rc = i18n("Key type: DSA (%1 bit)") + "\n";
00341 
00342                 x = d->kossl->BN_bn2hex(pkey->pkey.dsa->p);
00343                 rc += i18n("Prime: ");
00344                 // hack - this may not be always accurate
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.dsa->q);
00357                 rc += i18n("160 bit Prime Factor: ");
00358                 for (unsigned int i = 0; i < strlen(x); i++) {
00359                     if (i%40 != 0 && i%2 == 0)
00360                         rc += ":";
00361                     else if (i%40 == 0)
00362                         rc += "\n";
00363                     rc += x[i];
00364                 }
00365                 rc += "\n";
00366                 d->kossl->OPENSSL_free(x);
00367     
00368                 x = d->kossl->BN_bn2hex(pkey->pkey.dsa->g);
00369                 rc += QString("g: ");
00370                 for (unsigned int i = 0; i < strlen(x); i++) {
00371                     if (i%40 != 0 && i%2 == 0)
00372                         rc += ":";
00373                     else if (i%40 == 0)
00374                         rc += "\n";
00375                     rc += x[i];
00376                 }
00377                 rc += "\n";
00378                 d->kossl->OPENSSL_free(x);
00379     
00380                 x = d->kossl->BN_bn2hex(pkey->pkey.dsa->pub_key);
00381                 rc += i18n("Public Key: ");
00382                 for (unsigned int i = 0; i < strlen(x); i++) {
00383                     if (i%40 != 0 && i%2 == 0)
00384                         rc += ":";
00385                     else if (i%40 == 0)
00386                         rc += "\n";
00387                     rc += x[i];
00388                 }
00389                 rc += "\n";
00390                 d->kossl->OPENSSL_free(x);
00391             }
00392         #endif
00393         d->kossl->EVP_PKEY_free(pkey);
00394     }
00395 #endif
00396 
00397 return rc;
00398 }
00399 
00400 
00401 
00402 QString KSSLCertificate::getIssuer() const {
00403 QString rc = "";
00404 
00405 #ifdef KSSL_HAVE_SSL
00406     char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_issuer_name(d->m_cert), 0, 0);
00407 
00408     if (!t)
00409         return rc;
00410 
00411     rc = t;
00412     d->kossl->OPENSSL_free(t);
00413 #endif
00414 
00415 return rc;
00416 }
00417 
00418 void KSSLCertificate::setChain(void *c) {
00419 #ifdef KSSL_HAVE_SSL
00420     d->_chain.setChain(c);
00421 #endif
00422     d->m_stateCached = false;
00423     d->m_stateCache = KSSLCertificate::Unknown;
00424 }
00425 
00426 void KSSLCertificate::setCert(X509 *c) {
00427 #ifdef KSSL_HAVE_SSL
00428 d->m_cert = c;
00429 if (c) {
00430     d->_extensions.flags = 0;
00431     d->kossl->X509_check_purpose(c, -1, 0);    // setup the fields (!!)
00432 
00433 #if 0
00434     kdDebug(7029) << "---------------- Certificate ------------------" 
00435               << endl;
00436     kdDebug(7029) << getSubject() << endl;
00437 #endif
00438 
00439     for (int j = 0; j < d->kossl->X509_PURPOSE_get_count(); j++) {
00440         X509_PURPOSE *ptmp = d->kossl->X509_PURPOSE_get0(j);
00441         int id = d->kossl->X509_PURPOSE_get_id(ptmp);
00442         for (int ca = 0; ca < 2; ca++) {
00443             int idret = d->kossl->X509_check_purpose(c, id, ca);
00444             if (idret == 1 || idret == 2) {   // have it
00445 //              kdDebug() << "PURPOSE: " << id << (ca?" CA":"") << endl;
00446                 if (!ca)
00447                     d->_extensions.flags |= (1L <<(id-1));
00448                 else d->_extensions.flags |= (1L <<(16+id-1));
00449             } else {
00450                 if (!ca)
00451                     d->_extensions.flags &= ~(1L <<(id-1));
00452                 else d->_extensions.flags &= ~(1L <<(16+id-1));
00453             }
00454         }
00455     }
00456 
00457 #if 0
00458     kdDebug(7029) << "flags: " << QString::number(c->ex_flags, 2)
00459               << "\nkeyusage: " << QString::number(c->ex_kusage, 2)
00460               << "\nxkeyusage: " << QString::number(c->ex_xkusage, 2)
00461               << "\nnscert: " << QString::number(c->ex_nscert, 2)
00462               << endl;
00463     if (c->ex_flags & EXFLAG_KUSAGE)
00464         kdDebug(7029) << "     --- Key Usage extensions found" << endl;
00465         else kdDebug(7029) << "     --- Key Usage extensions NOT found" << endl;
00466 
00467     if (c->ex_flags & EXFLAG_XKUSAGE)
00468         kdDebug(7029) << "     --- Extended key usage extensions found" << endl;
00469         else kdDebug(7029) << "     --- Extended key usage extensions NOT found" << endl;
00470 
00471     if (c->ex_flags & EXFLAG_NSCERT)
00472         kdDebug(7029) << "     --- NS extensions found" << endl;
00473         else kdDebug(7029) << "     --- NS extensions NOT found" << endl;
00474 
00475         if (d->_extensions.certTypeSSLCA())
00476                 kdDebug(7029) << "NOTE: this is an SSL CA file." << endl;
00477         else kdDebug(7029) << "NOTE: this is NOT an SSL CA file." << endl;
00478 
00479         if (d->_extensions.certTypeEmailCA())
00480                 kdDebug(7029) << "NOTE: this is an EMAIL CA file." << endl;
00481         else kdDebug(7029) << "NOTE: this is NOT an EMAIL CA file." << endl;
00482 
00483         if (d->_extensions.certTypeCodeCA())
00484                 kdDebug(7029) << "NOTE: this is a CODE CA file." << endl;
00485         else kdDebug(7029) << "NOTE: this is NOT a CODE CA file." << endl;
00486 
00487         if (d->_extensions.certTypeSSLClient())
00488                 kdDebug(7029) << "NOTE: this is an SSL client." << endl;
00489         else kdDebug(7029) << "NOTE: this is NOT an SSL client." << endl;
00490 
00491         if (d->_extensions.certTypeSSLServer())
00492                 kdDebug(7029) << "NOTE: this is an SSL server." << endl;
00493         else kdDebug(7029) << "NOTE: this is NOT an SSL server." << endl;
00494 
00495         if (d->_extensions.certTypeNSSSLServer())
00496                 kdDebug(7029) << "NOTE: this is a NETSCAPE SSL server." << endl;
00497         else kdDebug(7029) << "NOTE: this is NOT a NETSCAPE SSL server." << endl;
00498 
00499         if (d->_extensions.certTypeSMIME())
00500                 kdDebug(7029) << "NOTE: this is an SMIME certificate." << endl;
00501         else kdDebug(7029) << "NOTE: this is NOT an SMIME certificate." << endl;
00502 
00503         if (d->_extensions.certTypeSMIMEEncrypt())
00504                 kdDebug(7029) << "NOTE: this is an SMIME encrypt cert." << endl;
00505         else kdDebug(7029) << "NOTE: this is NOT an SMIME encrypt cert." << endl;
00506 
00507         if (d->_extensions.certTypeSMIMESign())
00508                 kdDebug(7029) << "NOTE: this is an SMIME sign cert." << endl;
00509         else kdDebug(7029) << "NOTE: this is NOT an SMIME sign cert." << endl;
00510 
00511         if (d->_extensions.certTypeCRLSign())
00512                 kdDebug(7029) << "NOTE: this is a CRL signer." << endl;
00513         else kdDebug(7029) << "NOTE: this is NOT a CRL signer." << endl;
00514 
00515     kdDebug(7029) << "-----------------------------------------------" 
00516               << endl;
00517 #endif
00518 }
00519 #endif
00520 d->m_stateCached = false;
00521 d->m_stateCache = KSSLCertificate::Unknown;
00522 }
00523 
00524 X509 *KSSLCertificate::getCert() {
00525 #ifdef KSSL_HAVE_SSL
00526     return d->m_cert;
00527 #endif
00528 return 0;
00529 }
00530 
00531 // pull in the callback.  It's common across multiple files but we want
00532 // it to be hidden.
00533 
00534 #include "ksslcallback.c"
00535 
00536 
00537 bool KSSLCertificate::isValid(KSSLCertificate::KSSLPurpose p) {
00538     return (validate(p) == KSSLCertificate::Ok);
00539 }
00540 
00541 
00542 bool KSSLCertificate::isValid() {
00543     return isValid(KSSLCertificate::SSLServer);
00544 }
00545 
00546 
00547 int KSSLCertificate::purposeToOpenSSL(KSSLCertificate::KSSLPurpose p) const {
00548 int rc = 0;
00549 #ifdef KSSL_HAVE_SSL
00550     if (p == KSSLCertificate::SSLServer) {
00551         rc = X509_PURPOSE_SSL_SERVER;
00552     } else if (p == KSSLCertificate::SSLClient) {
00553         rc = X509_PURPOSE_SSL_CLIENT;
00554     } else if (p == KSSLCertificate::SMIMEEncrypt) {
00555         rc = X509_PURPOSE_SMIME_ENCRYPT;
00556     } else if (p == KSSLCertificate::SMIMESign) {
00557         rc = X509_PURPOSE_SMIME_SIGN;
00558     } else if (p == KSSLCertificate::Any) {
00559         rc = X509_PURPOSE_ANY;
00560     }
00561 #endif
00562 return rc;  
00563 }
00564 
00565 
00566 // For backward compatibility
00567 KSSLCertificate::KSSLValidation KSSLCertificate::validate() {
00568     return validate(KSSLCertificate::SSLServer);
00569 }
00570 
00571 KSSLCertificate::KSSLValidation KSSLCertificate::validate(KSSLCertificate::KSSLPurpose purpose)
00572 {
00573     KSSLValidationList result = validateVerbose(purpose);
00574     if (result.isEmpty())
00575         return KSSLCertificate::Ok;
00576     else
00577         return result.first();
00578 } 
00579 
00580 //
00581 // See apps/verify.c in OpenSSL for the source of most of this logic.
00582 //
00583 
00584 // CRL files?  we don't do that yet
00585 KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose) 
00586 {
00587     KSSLValidationList errors;
00588     if (d->_lastPurpose != purpose && d->m_stateCached) {
00589         d->m_stateCached = false;
00590     }
00591 
00592     if (!d->m_stateCached)
00593         d->_lastPurpose = purpose;
00594 
00595 #ifdef KSSL_HAVE_SSL
00596     X509_STORE *certStore;
00597     X509_LOOKUP *certLookup;
00598     X509_STORE_CTX *certStoreCTX;
00599     int rc = 0;
00600 
00601     if (!d->m_cert)
00602     {
00603         errors << KSSLCertificate::Unknown;
00604         return errors;
00605     }
00606 
00607     if (d->m_stateCached) {
00608         errors << d->m_stateCache;
00609         return errors;
00610     }
00611 
00612     QStringList qsl = KGlobal::dirs()->resourceDirs("kssl");
00613 
00614     if (qsl.isEmpty()) {
00615         errors << KSSLCertificate::NoCARoot;
00616         return errors;
00617     }
00618 
00619     KSSLCertificate::KSSLValidation ksslv = Unknown;
00620 
00621     for (QStringList::Iterator j = qsl.begin(); j != qsl.end(); ++j) {
00622         struct stat sb;
00623         QString _j = (*j)+"ca-bundle.crt";
00624         if (-1 == stat(_j.ascii(), &sb)) continue;
00625 
00626         certStore = d->kossl->X509_STORE_new();
00627         if (!certStore)
00628         {
00629             errors << KSSLCertificate::Unknown;
00630             return errors;
00631         }
00632 
00633         X509_STORE_set_verify_cb_func(certStore, X509Callback);
00634 
00635         certLookup = d->kossl->X509_STORE_add_lookup(certStore, d->kossl->X509_LOOKUP_file());
00636         if (!certLookup) {
00637             ksslv = KSSLCertificate::Unknown;
00638             d->kossl->X509_STORE_free(certStore);
00639             continue;
00640         }
00641 
00642         if (!d->kossl->X509_LOOKUP_load_file(certLookup, _j.ascii(), X509_FILETYPE_PEM)) {
00643             // error accessing directory and loading pems
00644             kdDebug(7029) << "KSSL couldn't read CA root: " 
00645                     << _j << endl;
00646             ksslv = KSSLCertificate::ErrorReadingRoot;
00647             d->kossl->X509_STORE_free(certStore);
00648             continue;
00649         }
00650 
00651         // This is the checking code
00652         certStoreCTX = d->kossl->X509_STORE_CTX_new();
00653 
00654         // this is a bad error - could mean no free memory.
00655         // This may be the wrong thing to do here
00656         if (!certStoreCTX) {
00657             kdDebug(7029) << "KSSL couldn't create an X509 store context." << endl;
00658             d->kossl->X509_STORE_free(certStore);
00659             continue;
00660         }
00661 
00662         d->kossl->X509_STORE_CTX_init(certStoreCTX, certStore, d->m_cert, NULL);
00663         if (d->_chain.isValid())
00664             d->kossl->X509_STORE_CTX_set_chain(certStoreCTX, (STACK_OF(X509)*)d->_chain.rawChain());
00665 
00666         //kdDebug(7029) << "KSSL setting CRL.............." << endl;
00667         // int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
00668 
00669         d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX, purposeToOpenSSL(purpose));
00670 
00671         certStoreCTX->error = X509_V_OK;
00672         rc = d->kossl->X509_verify_cert(certStoreCTX);
00673         int errcode = certStoreCTX->error;
00674         ksslv = processError(errcode);
00675         // For servers, we can try NS_SSL_SERVER too
00676         if (ksslv != KSSLCertificate::Ok &&
00677             purpose == KSSLCertificate::SSLServer) {
00678             d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX,
00679                         X509_PURPOSE_NS_SSL_SERVER);
00680 
00681             certStoreCTX->error = X509_V_OK;
00682             rc = d->kossl->X509_verify_cert(certStoreCTX);
00683             errcode = certStoreCTX->error;
00684             ksslv = processError(errcode);
00685         }
00686         d->kossl->X509_STORE_CTX_free(certStoreCTX);
00687         d->kossl->X509_STORE_free(certStore);
00688         // end of checking code
00689         //
00690 
00691         //kdDebug(7029) << "KSSL Validation procedure RC: " 
00692         //      << rc << endl;
00693         //kdDebug(7029) << "KSSL Validation procedure errcode: "
00694         //      << errcode << endl;
00695         //kdDebug(7029) << "KSSL Validation procedure RESULTS: "
00696         //      << ksslv << endl;
00697 
00698         if (ksslv != NoCARoot && ksslv != InvalidCA) {
00699             d->m_stateCached = true;
00700             d->m_stateCache = ksslv;
00701             break;
00702         }
00703     }
00704     
00705     if (ksslv != KSSLCertificate::Ok)
00706         errors << ksslv;
00707 #else
00708     errors << KSSLCertificate::NoSSL;
00709 #endif
00710     return errors;
00711 }
00712 
00713 
00714 
00715 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate() {
00716     return revalidate(KSSLCertificate::SSLServer);
00717 }
00718 
00719 
00720 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate(KSSLCertificate::KSSLPurpose p) {
00721     d->m_stateCached = false;
00722     return validate(p);
00723 }
00724 
00725 
00726 KSSLCertificate::KSSLValidation KSSLCertificate::processError(int ec) {
00727 KSSLCertificate::KSSLValidation rc;
00728 
00729 rc = KSSLCertificate::Unknown;
00730 #ifdef KSSL_HAVE_SSL
00731     switch (ec) {
00732     case X509_V_OK:       // OK
00733         rc = KSSLCertificate::Ok;
00734     break;
00735 
00736 
00737     case X509_V_ERR_CERT_REJECTED:
00738         rc = KSSLCertificate::Rejected;
00739     break;
00740 
00741 
00742     case X509_V_ERR_CERT_UNTRUSTED:
00743         rc = KSSLCertificate::Untrusted;
00744     break;
00745 
00746 
00747     case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
00748     case X509_V_ERR_CERT_SIGNATURE_FAILURE:
00749     case X509_V_ERR_CRL_SIGNATURE_FAILURE:
00750     case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
00751     case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
00752         rc = KSSLCertificate::SignatureFailed;
00753     break;
00754 
00755     case X509_V_ERR_INVALID_CA:
00756     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
00757     case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
00758     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
00759         rc = KSSLCertificate::InvalidCA;
00760     break;
00761 
00762 
00763     case X509_V_ERR_INVALID_PURPOSE:
00764         rc = KSSLCertificate::InvalidPurpose;
00765     break;
00766 
00767 
00768     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
00769     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
00770         rc = KSSLCertificate::SelfSigned;
00771     break;
00772 
00773 
00774     case X509_V_ERR_CERT_REVOKED:
00775         rc = KSSLCertificate::Revoked;
00776     break;
00777 
00778     case X509_V_ERR_PATH_LENGTH_EXCEEDED:
00779         rc = KSSLCertificate::PathLengthExceeded;
00780     break;
00781 
00782     case X509_V_ERR_CERT_NOT_YET_VALID:
00783     case X509_V_ERR_CERT_HAS_EXPIRED:
00784     case X509_V_ERR_CRL_NOT_YET_VALID:
00785     case X509_V_ERR_CRL_HAS_EXPIRED:
00786     case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
00787     case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
00788     case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
00789     case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
00790         rc = KSSLCertificate::Expired;
00791         kdDebug(7029) << "KSSL apparently this is expired.  Not after: "
00792                 << getNotAfter() << endl;
00793     break;
00794 
00795     //case 1:
00796     case X509_V_ERR_APPLICATION_VERIFICATION:
00797     case X509_V_ERR_OUT_OF_MEM:
00798     case X509_V_ERR_UNABLE_TO_GET_CRL:
00799     case X509_V_ERR_CERT_CHAIN_TOO_LONG:
00800     default:
00801         rc = KSSLCertificate::Unknown;
00802     break;
00803 }
00804 
00805 d->m_stateCache = rc;
00806 d->m_stateCached = true;
00807 #endif
00808 return rc;
00809 }
00810 
00811 
00812 QString KSSLCertificate::getNotBefore() const {
00813 #ifdef KSSL_HAVE_SSL
00814 return ASN1_UTCTIME_QString(X509_get_notBefore(d->m_cert));
00815 #else
00816 return QString::null;
00817 #endif
00818 }
00819 
00820 
00821 QString KSSLCertificate::getNotAfter() const {
00822 #ifdef KSSL_HAVE_SSL
00823 return ASN1_UTCTIME_QString(X509_get_notAfter(d->m_cert));
00824 #else
00825 return QString::null;
00826 #endif
00827 }
00828 
00829 
00830 QDateTime KSSLCertificate::getQDTNotBefore() const {
00831 #ifdef KSSL_HAVE_SSL
00832 return ASN1_UTCTIME_QDateTime(X509_get_notBefore(d->m_cert), NULL);
00833 #else
00834 return QDateTime::currentDateTime();
00835 #endif
00836 }
00837 
00838 
00839 QDateTime KSSLCertificate::getQDTNotAfter() const {
00840 #ifdef KSSL_HAVE_SSL
00841 return ASN1_UTCTIME_QDateTime(X509_get_notAfter(d->m_cert), NULL);
00842 #else
00843 return QDateTime::currentDateTime();
00844 #endif
00845 }
00846 
00847 
00848 int operator==(KSSLCertificate &x, KSSLCertificate &y) {
00849 #ifndef KSSL_HAVE_SSL
00850   return 1;
00851 #else
00852   if (!KOSSL::self()->X509_cmp(x.getCert(), y.getCert())) return 1;
00853   return 0;
00854 #endif
00855 }
00856 
00857 
00858 KSSLCertificate *KSSLCertificate::replicate() {
00859 // The new certificate doesn't have the cached value.  It's probably
00860 // better this way.  We can't anticipate every reason for doing this.
00861 KSSLCertificate *newOne = new KSSLCertificate();
00862 #ifdef KSSL_HAVE_SSL
00863     newOne->setCert(d->kossl->X509_dup(getCert()));
00864     KSSLCertChain *c = d->_chain.replicate();
00865     newOne->setChain(c->rawChain());
00866     delete c;
00867 #endif
00868 return newOne;
00869 }
00870 
00871 
00872 QString KSSLCertificate::toString() {
00873 return KCodecs::base64Encode(toDer());
00874 }
00875 
00876 
00877 QString KSSLCertificate::verifyText(KSSLValidation x) {
00878 switch (x) {
00879 case KSSLCertificate::Ok:
00880     return i18n("The certificate is valid.");
00881 case KSSLCertificate::PathLengthExceeded:
00882 case KSSLCertificate::ErrorReadingRoot:
00883 case KSSLCertificate::NoCARoot:
00884     return i18n("Certificate signing authority root files could not be found so the certificate is not verified.");
00885 case KSSLCertificate::InvalidCA:
00886     return i18n("Certificate signing authority is unknown or invalid.");
00887 case KSSLCertificate::SelfSigned:
00888     return i18n("Certificate is self-signed and thus may not be trustworthy.");
00889 case KSSLCertificate::Expired:
00890     return i18n("Certificate has expired.");
00891 case KSSLCertificate::Revoked:
00892     return i18n("Certificate has been revoked.");
00893 case KSSLCertificate::NoSSL:
00894     return i18n("SSL support was not found.");
00895 case KSSLCertificate::Untrusted:
00896     return i18n("Signature is untrusted.");
00897 case KSSLCertificate::SignatureFailed:
00898     return i18n("Signature test failed.");
00899 case KSSLCertificate::Rejected:
00900 case KSSLCertificate::InvalidPurpose:
00901     return i18n("Rejected, possibly due to an invalid purpose.");
00902 case KSSLCertificate::PrivateKeyFailed:
00903     return i18n("Private key test failed.");
00904 case KSSLCertificate::InvalidHost:
00905     return i18n("The certificate has not been issued for this host.");
00906 default:
00907 break;
00908 }
00909 
00910 return i18n("The certificate is invalid.");
00911 }
00912 
00913 
00914 QByteArray KSSLCertificate::toDer() {
00915 QByteArray qba;
00916 #ifdef KSSL_HAVE_SSL
00917 unsigned int certlen = d->kossl->i2d_X509(getCert(), NULL);
00918 // These should technically be unsigned char * but it doesn't matter
00919 // for our purposes
00920 char *cert = new char[certlen];
00921 char *p = cert;
00922     // FIXME: return code!
00923     d->kossl->i2d_X509(getCert(), (unsigned char **)&p);
00924 
00925     // encode it into a QString
00926     qba.duplicate(cert, certlen);
00927     delete[] cert;
00928 #endif
00929 return qba;
00930 }
00931 
00932 
00933 
00934 QByteArray KSSLCertificate::toPem() {
00935 QByteArray qba;
00936 QString thecert = toString();
00937 const char *header = "-----BEGIN CERTIFICATE-----\n";
00938 const char *footer = "-----END CERTIFICATE-----\n";
00939 
00940     // We just do base64 on the ASN1
00941     //  64 character lines  (unpadded)
00942     unsigned int xx = thecert.length() - 1;
00943     for (unsigned int i = 0; i < xx/64; i++) {
00944         thecert.insert(64*(i+1)+i, '\n');
00945     }
00946 
00947     thecert.prepend(header);
00948 
00949     if (thecert[thecert.length()-1] != '\n')
00950         thecert += "\n";
00951 
00952     thecert.append(footer);
00953 
00954     qba.duplicate(thecert.local8Bit(), thecert.length());
00955 return qba;
00956 }
00957 
00958 
00959 #define NETSCAPE_CERT_HDR     "certificate"
00960 
00961 // what a piece of crap this is
00962 QByteArray KSSLCertificate::toNetscape() {
00963 QByteArray qba;
00964 #ifdef KSSL_HAVE_SSL
00965 ASN1_HEADER ah;
00966 ASN1_OCTET_STRING os;
00967 KTempFile ktf;
00968 
00969     os.data = (unsigned char *)NETSCAPE_CERT_HDR;
00970     os.length = strlen(NETSCAPE_CERT_HDR);
00971     ah.header = &os;
00972     ah.data = (char *)getCert();
00973     ah.meth = d->kossl->X509_asn1_meth();
00974 
00975     d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&ah);
00976 
00977     ktf.close();
00978 
00979     QFile qf(ktf.name());
00980     qf.open(IO_ReadOnly);
00981     char *buf = new char[qf.size()];
00982     qf.readBlock(buf, qf.size());
00983     qba.duplicate(buf, qf.size());
00984     qf.close();
00985     delete[] buf;
00986 
00987     ktf.unlink();
00988 
00989 #endif
00990 return qba;
00991 }
00992 
00993 
00994 
00995 QString KSSLCertificate::toText() {
00996 QString text;
00997 #ifdef KSSL_HAVE_SSL
00998 KTempFile ktf;
00999 
01000     d->kossl->X509_print(ktf.fstream(), getCert());
01001     ktf.close();
01002 
01003     QFile qf(ktf.name());
01004     qf.open(IO_ReadOnly);
01005     char *buf = new char[qf.size()+1];
01006     qf.readBlock(buf, qf.size());
01007     buf[qf.size()] = 0;
01008     text = buf;
01009     delete[] buf;
01010     qf.close();
01011     ktf.unlink();
01012 #endif
01013 return text;
01014 }
01015 
01016 // KDE 4: Make it const QString &
01017 bool KSSLCertificate::setCert(QString& cert) {
01018 #ifdef KSSL_HAVE_SSL
01019 QByteArray qba, qbb = cert.local8Bit().copy();
01020     KCodecs::base64Decode(qbb, qba);
01021     unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
01022     X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size());
01023     if (x5c) {
01024         setCert(x5c);
01025         return true;
01026     }
01027 #endif
01028 return false;
01029 }
01030 
01031 
01032 KSSLX509V3& KSSLCertificate::x509V3Extensions() {
01033 return d->_extensions;
01034 }
01035 
01036 
01037 bool KSSLCertificate::isSigner() {
01038 return d->_extensions.certTypeCA();
01039 }
01040 
01041 
01042 QDataStream& operator<<(QDataStream& s, const KSSLCertificate& r) {
01043 QStringList qsl;
01044 QPtrList<KSSLCertificate> cl = const_cast<KSSLCertificate&>(r).chain().getChain();
01045 
01046     for (KSSLCertificate *c = cl.first(); c != 0; c = cl.next()) {
01047         qsl << c->toString();
01048     }
01049 
01050     cl.setAutoDelete(true);
01051 
01052     s << const_cast<KSSLCertificate&>(r).toString() << qsl;
01053 
01054 return s;
01055 }
01056 
01057 
01058 QDataStream& operator>>(QDataStream& s, KSSLCertificate& r) {
01059 QStringList qsl;
01060 QString cert;
01061 
01062 s >> cert >> qsl;
01063 
01064     if (r.setCert(cert) && !qsl.isEmpty())
01065         r.chain().setCertChain(qsl);
01066 
01067 return s;
01068 }
01069 
01070 
01071 
KDE Logo
This file is part of the documentation for kio Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 5 07:20:42 2004 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003