kio Library API Documentation

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 
KDE Logo
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