kio Library API Documentation

ksslcertificate.cc

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