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