# kio Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# ksslcertificate.cc

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:23 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001