kio Library: ksslcertificate.cc Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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"):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 // These should technically be unsigned char * but it doesn't matter
    00962 // for our purposes
    00963 char *cert = new char[certlen];
    00964 char *p = cert;
    00965     // FIXME: return code!
    00966     d->kossl->i2d_X509(getCert(), (unsigned char **)&p);
    00967
    00968     // encode it into a QString
    00969     qba.duplicate(cert, certlen);
    00970     delete[] cert;
    00971 #endif
    00972 return qba;
    00973 }
    00974
    00975
    00976
    00977 QByteArray KSSLCertificate::toPem() {
    00978 QByteArray qba;
    00979 QString thecert = toString();
    00980 const char *header = "-----BEGIN CERTIFICATE-----\n";
    00981 const char *footer = "-----END CERTIFICATE-----\n";
    00982
    00983     // We just do base64 on the ASN1
    00984     //  64 character lines  (unpadded)
    00985     unsigned int xx = thecert.length() - 1;
    00986     for (unsigned int i = 0; i < xx/64; i++) {
    00987         thecert.insert(64*(i+1)+i, '\n');
    00988     }
    00989
    00990     thecert.prepend(header);
    00991
    00992     if (thecert[thecert.length()-1] != '\n')
    00993         thecert += "\n";
    00994
    00995     thecert.append(footer);
    00996
    00997     qba.duplicate(thecert.local8Bit(), thecert.length());
    00998 return qba;
    00999 }
    01000
    01001
    01002 #define NETSCAPE_CERT_HDR     "certificate"
    01003
    01004 // what a piece of crap this is
    01005 QByteArray KSSLCertificate::toNetscape() {
    01006 QByteArray qba;
    01007 #ifdef KSSL_HAVE_SSL
    01008 ASN1_HEADER ah;
    01009 ASN1_OCTET_STRING os;
    01010 KTempFile ktf;
    01011
    01012     os.data = (unsigned char *)NETSCAPE_CERT_HDR;
    01013     os.length = strlen(NETSCAPE_CERT_HDR);
    01014     ah.header = &os;
    01015     ah.data = (char *)getCert();
    01016     ah.meth = d->kossl->X509_asn1_meth();
    01017
    01018     d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&ah);
    01019
    01020     ktf.close();
    01021
    01022     QFile qf(ktf.name());
    01023     qf.open(IO_ReadOnly);
    01024     char *buf = new char[qf.size()];
    01025     qf.readBlock(buf, qf.size());
    01026     qba.duplicate(buf, qf.size());
    01027     qf.close();
    01028     delete[] buf;
    01029
    01030     ktf.unlink();
    01031
    01032 #endif
    01033 return qba;
    01034 }
    01035
    01036
    01037
    01038 QString KSSLCertificate::toText() {
    01039 QString text;
    01040 #ifdef KSSL_HAVE_SSL
    01041 KTempFile ktf;
    01042
    01043     d->kossl->X509_print(ktf.fstream(), getCert());
    01044     ktf.close();
    01045
    01046     QFile qf(ktf.name());
    01047     qf.open(IO_ReadOnly);
    01048     char *buf = new char[qf.size()+1];
    01049     qf.readBlock(buf, qf.size());
    01050     buf[qf.size()] = 0;
    01051     text = buf;
    01052     delete[] buf;
    01053     qf.close();
    01054     ktf.unlink();
    01055 #endif
    01056 return text;
    01057 }
    01058
    01059 // KDE 4: Make it const QString &
    01060 bool KSSLCertificate::setCert(QString& cert) {
    01061 #ifdef KSSL_HAVE_SSL
    01062 QByteArray qba, qbb = cert.local8Bit().copy();
    01063     KCodecs::base64Decode(qbb, qba);
    01064     unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
    01065     X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size());
    01066     if (x5c) {
    01067         setCert(x5c);
    01068         return true;
    01069     }
    01070 #endif
    01071 return false;
    01072 }
    01073
    01074
    01075 KSSLX509V3& KSSLCertificate::x509V3Extensions() {
    01076 return d->_extensions;
    01077 }
    01078
    01079
    01080 bool KSSLCertificate::isSigner() {
    01081 return d->_extensions.certTypeCA();
    01082 }
    01083
    01084
    01085 QStringList KSSLCertificate::subjAltNames() const {
    01086     QStringList rc;
    01087 #ifdef KSSL_HAVE_SSL
    01088     STACK_OF(GENERAL_NAME) *names;
    01089     names = (STACK_OF(GENERAL_NAME)*)d->kossl->X509_get_ext_d2i(d->m_cert, NID_subject_alt_name, 0, 0);
    01090
    01091     if (!names) {
    01092         return rc;
    01093     }
    01094
    01095     int cnt = d->kossl->sk_GENERAL_NAME_num(names);
    01096
    01097     for (int i = 0; i < cnt; i++) {
    01098         const GENERAL_NAME *val = (const GENERAL_NAME *)d->kossl->sk_value(names, i);
    01099         if (val->type != GEN_DNS) {
    01100             continue;
    01101         }
    01102
    01103         QString s = (const char *)d->kossl->ASN1_STRING_data(val->d.ia5);
    01104         if (!s.isEmpty()) {
    01105             rc += s;
    01106         }
    01107     }
    01108     d->kossl->sk_free(names);
    01109 #endif
    01110     return rc;
    01111 }
    01112
    01113
    01114 QDataStream& operator<<(QDataStream& s, const KSSLCertificate& r) {
    01115 QStringList qsl;
    01116 QPtrList<KSSLCertificate> cl = const_cast<KSSLCertificate&>(r).chain().getChain();
    01117
    01118     for (KSSLCertificate *c = cl.first(); c != 0; c = cl.next()) {
    01119         qsl << c->toString();
    01120     }
    01121
    01122     cl.setAutoDelete(true);
    01123
    01124     s << const_cast<KSSLCertificate&>(r).toString() << qsl;
    01125
    01126 return s;
    01127 }
    01128
    01129
    01130 QDataStream& operator>>(QDataStream& s, KSSLCertificate& r) {
    01131 QStringList qsl;
    01132 QString cert;
    01133
    01134 s >> cert >> qsl;
    01135
    01136     if (r.setCert(cert) && !qsl.isEmpty())
    01137         r.chain().setCertChain(qsl);
    01138
    01139 return s;
    01140 }
    01141
    01142
    01143

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:24:04 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003