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"):QString(d->kossl->OBJ_nid2ln(i)); 00204 00205 rc += "\n"; 00206 rc += i18n("Signature Contents:"); 00207 n = d->m_cert->signature->length; 00208 s = (char *)d->m_cert->signature->data; 00209 for (i = 0; i < n; i++) { 00210 if (i%20 != 0) rc += ":"; 00211 else rc += "\n"; 00212 rc.append(hv[(s[i]&0xf0)>>4]); 00213 rc.append(hv[s[i]&0x0f]); 00214 } 00215 00216 #endif 00217 00218 return rc; 00219 } 00220 00221 00222 void KSSLCertificate::getEmails(QStringList &to) const { 00223 to.clear(); 00224 #ifdef KSSL_HAVE_SSL 00225 if (!d->m_cert) 00226 return; 00227 00228 STACK *s = d->kossl->X509_get1_email(d->m_cert); 00229 if (s) { 00230 for(int n=0; n < s->num; n++) { 00231 to.append(d->kossl->sk_value(s,n)); 00232 } 00233 d->kossl->X509_email_free(s); 00234 } 00235 #endif 00236 } 00237 00238 00239 QString KSSLCertificate::getKDEKey() const { 00240 return getSubject() + " (" + getMD5DigestText() + ")"; 00241 } 00242 00243 00244 QString KSSLCertificate::getMD5DigestFromKDEKey(const QString &k) { 00245 QString rc; 00246 int pos = k.findRev('('); 00247 if (pos != -1) { 00248 unsigned int len = k.length(); 00249 if (k.at(len-1) == ')') { 00250 rc = k.mid(pos+1, len-pos-2); 00251 } 00252 } 00253 return rc; 00254 } 00255 00256 00257 QString KSSLCertificate::getMD5DigestText() const { 00258 QString rc = ""; 00259 00260 #ifdef KSSL_HAVE_SSL 00261 unsigned int n; 00262 unsigned char md[EVP_MAX_MD_SIZE]; 00263 00264 if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) { 00265 return rc; 00266 } 00267 00268 for (unsigned int j = 0; j < n; j++) { 00269 if (j > 0) 00270 rc += ":"; 00271 rc.append(hv[(md[j]&0xf0)>>4]); 00272 rc.append(hv[md[j]&0x0f]); 00273 } 00274 00275 #endif 00276 00277 return rc; 00278 } 00279 00280 00281 00282 QString KSSLCertificate::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 return validateVerbose(purpose, 0); 00588 } 00589 00590 KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose, KSSLCertificate *ca) 00591 { 00592 KSSLValidationList errors; 00593 if (ca || (d->_lastPurpose != purpose)) { 00594 d->m_stateCached = false; 00595 } 00596 00597 if (!d->m_stateCached) 00598 d->_lastPurpose = purpose; 00599 00600 #ifdef KSSL_HAVE_SSL 00601 X509_STORE *certStore; 00602 X509_LOOKUP *certLookup; 00603 X509_STORE_CTX *certStoreCTX; 00604 int rc = 0; 00605 00606 if (!d->m_cert) 00607 { 00608 errors << KSSLCertificate::Unknown; 00609 return errors; 00610 } 00611 00612 if (d->m_stateCached) { 00613 errors << d->m_stateCache; 00614 return errors; 00615 } 00616 00617 QStringList qsl = KGlobal::dirs()->resourceDirs("kssl"); 00618 00619 if (qsl.isEmpty()) { 00620 errors << KSSLCertificate::NoCARoot; 00621 return errors; 00622 } 00623 00624 KSSLCertificate::KSSLValidation ksslv = Unknown; 00625 00626 for (QStringList::Iterator j = qsl.begin(); j != qsl.end(); ++j) { 00627 struct stat sb; 00628 QString _j = (*j) + "ca-bundle.crt"; 00629 if (-1 == stat(_j.ascii(), &sb)) { 00630 continue; 00631 } 00632 00633 certStore = d->kossl->X509_STORE_new(); 00634 if (!certStore) { 00635 errors << KSSLCertificate::Unknown; 00636 return errors; 00637 } 00638 00639 X509_STORE_set_verify_cb_func(certStore, X509Callback); 00640 00641 certLookup = d->kossl->X509_STORE_add_lookup(certStore, d->kossl->X509_LOOKUP_file()); 00642 if (!certLookup) { 00643 ksslv = KSSLCertificate::Unknown; 00644 d->kossl->X509_STORE_free(certStore); 00645 continue; 00646 } 00647 00648 if (!d->kossl->X509_LOOKUP_load_file(certLookup, _j.ascii(), X509_FILETYPE_PEM)) { 00649 // error accessing directory and loading pems 00650 kdDebug(7029) << "KSSL couldn't read CA root: " 00651 << _j << endl; 00652 ksslv = KSSLCertificate::ErrorReadingRoot; 00653 d->kossl->X509_STORE_free(certStore); 00654 continue; 00655 } 00656 00657 // This is the checking code 00658 certStoreCTX = d->kossl->X509_STORE_CTX_new(); 00659 00660 // this is a bad error - could mean no free memory. 00661 // This may be the wrong thing to do here 00662 if (!certStoreCTX) { 00663 kdDebug(7029) << "KSSL couldn't create an X509 store context." << endl; 00664 d->kossl->X509_STORE_free(certStore); 00665 continue; 00666 } 00667 00668 d->kossl->X509_STORE_CTX_init(certStoreCTX, certStore, d->m_cert, NULL); 00669 if (d->_chain.isValid()) { 00670 d->kossl->X509_STORE_CTX_set_chain(certStoreCTX, (STACK_OF(X509)*)d->_chain.rawChain()); 00671 } 00672 00673 //kdDebug(7029) << "KSSL setting CRL.............." << endl; 00674 // int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x); 00675 00676 d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX, purposeToOpenSSL(purpose)); 00677 00678 KSSL_X509CallBack_ca = ca ? ca->d->m_cert : 0; 00679 KSSL_X509CallBack_ca_found = false; 00680 00681 certStoreCTX->error = X509_V_OK; 00682 rc = d->kossl->X509_verify_cert(certStoreCTX); 00683 int errcode = certStoreCTX->error; 00684 if (ca && !KSSL_X509CallBack_ca_found) { 00685 ksslv = KSSLCertificate::Irrelevant; 00686 } else { 00687 ksslv = processError(errcode); 00688 } 00689 // For servers, we can try NS_SSL_SERVER too 00690 if ( (ksslv != KSSLCertificate::Ok) && 00691 (ksslv != KSSLCertificate::Irrelevant) && 00692 purpose == KSSLCertificate::SSLServer) { 00693 d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX, 00694 X509_PURPOSE_NS_SSL_SERVER); 00695 00696 certStoreCTX->error = X509_V_OK; 00697 rc = d->kossl->X509_verify_cert(certStoreCTX); 00698 errcode = certStoreCTX->error; 00699 ksslv = processError(errcode); 00700 } 00701 d->kossl->X509_STORE_CTX_free(certStoreCTX); 00702 d->kossl->X509_STORE_free(certStore); 00703 // end of checking code 00704 // 00705 00706 //kdDebug(7029) << "KSSL Validation procedure RC: " 00707 // << rc << endl; 00708 //kdDebug(7029) << "KSSL Validation procedure errcode: " 00709 // << errcode << endl; 00710 //kdDebug(7029) << "KSSL Validation procedure RESULTS: " 00711 // << ksslv << endl; 00712 00713 if (ksslv != NoCARoot && ksslv != InvalidCA) { 00714 d->m_stateCached = true; 00715 d->m_stateCache = ksslv; 00716 } 00717 break; 00718 } 00719 00720 if (ksslv != KSSLCertificate::Ok) 00721 errors << ksslv; 00722 #else 00723 errors << KSSLCertificate::NoSSL; 00724 #endif 00725 return errors; 00726 } 00727 00728 00729 00730 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate() { 00731 return revalidate(KSSLCertificate::SSLServer); 00732 } 00733 00734 00735 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate(KSSLCertificate::KSSLPurpose p) { 00736 d->m_stateCached = false; 00737 return validate(p); 00738 } 00739 00740 00741 KSSLCertificate::KSSLValidation KSSLCertificate::processError(int ec) { 00742 KSSLCertificate::KSSLValidation rc; 00743 00744 rc = KSSLCertificate::Unknown; 00745 #ifdef KSSL_HAVE_SSL 00746 switch (ec) { 00747 case X509_V_OK: // OK 00748 rc = KSSLCertificate::Ok; 00749 break; 00750 00751 00752 case X509_V_ERR_CERT_REJECTED: 00753 rc = KSSLCertificate::Rejected; 00754 break; 00755 00756 00757 case X509_V_ERR_CERT_UNTRUSTED: 00758 rc = KSSLCertificate::Untrusted; 00759 break; 00760 00761 00762 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: 00763 case X509_V_ERR_CERT_SIGNATURE_FAILURE: 00764 case X509_V_ERR_CRL_SIGNATURE_FAILURE: 00765 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: 00766 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: 00767 rc = KSSLCertificate::SignatureFailed; 00768 break; 00769 00770 case X509_V_ERR_INVALID_CA: 00771 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: 00772 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: 00773 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: 00774 rc = KSSLCertificate::InvalidCA; 00775 break; 00776 00777 00778 case X509_V_ERR_INVALID_PURPOSE: 00779 rc = KSSLCertificate::InvalidPurpose; 00780 break; 00781 00782 00783 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: 00784 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: 00785 rc = KSSLCertificate::SelfSigned; 00786 break; 00787 00788 00789 case X509_V_ERR_CERT_REVOKED: 00790 rc = KSSLCertificate::Revoked; 00791 break; 00792 00793 case X509_V_ERR_PATH_LENGTH_EXCEEDED: 00794 rc = KSSLCertificate::PathLengthExceeded; 00795 break; 00796 00797 case X509_V_ERR_CERT_NOT_YET_VALID: 00798 case X509_V_ERR_CERT_HAS_EXPIRED: 00799 case X509_V_ERR_CRL_NOT_YET_VALID: 00800 case X509_V_ERR_CRL_HAS_EXPIRED: 00801 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: 00802 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: 00803 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: 00804 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: 00805 rc = KSSLCertificate::Expired; 00806 kdDebug(7029) << "KSSL apparently this is expired. Not after: " 00807 << getNotAfter() << endl; 00808 break; 00809 00810 //case 1: 00811 case X509_V_ERR_APPLICATION_VERIFICATION: 00812 case X509_V_ERR_OUT_OF_MEM: 00813 case X509_V_ERR_UNABLE_TO_GET_CRL: 00814 case X509_V_ERR_CERT_CHAIN_TOO_LONG: 00815 default: 00816 rc = KSSLCertificate::Unknown; 00817 break; 00818 } 00819 00820 d->m_stateCache = rc; 00821 d->m_stateCached = true; 00822 #endif 00823 return rc; 00824 } 00825 00826 00827 QString KSSLCertificate::getNotBefore() const { 00828 #ifdef KSSL_HAVE_SSL 00829 return ASN1_UTCTIME_QString(X509_get_notBefore(d->m_cert)); 00830 #else 00831 return QString::null; 00832 #endif 00833 } 00834 00835 00836 QString KSSLCertificate::getNotAfter() const { 00837 #ifdef KSSL_HAVE_SSL 00838 return ASN1_UTCTIME_QString(X509_get_notAfter(d->m_cert)); 00839 #else 00840 return QString::null; 00841 #endif 00842 } 00843 00844 00845 QDateTime KSSLCertificate::getQDTNotBefore() const { 00846 #ifdef KSSL_HAVE_SSL 00847 return ASN1_UTCTIME_QDateTime(X509_get_notBefore(d->m_cert), NULL); 00848 #else 00849 return QDateTime::currentDateTime(); 00850 #endif 00851 } 00852 00853 00854 QDateTime KSSLCertificate::getQDTNotAfter() const { 00855 #ifdef KSSL_HAVE_SSL 00856 return ASN1_UTCTIME_QDateTime(X509_get_notAfter(d->m_cert), NULL); 00857 #else 00858 return QDateTime::currentDateTime(); 00859 #endif 00860 } 00861 00862 00863 int operator==(KSSLCertificate &x, KSSLCertificate &y) { 00864 #ifndef KSSL_HAVE_SSL 00865 return 1; 00866 #else 00867 if (!KOSSL::self()->X509_cmp(x.getCert(), y.getCert())) return 1; 00868 return 0; 00869 #endif 00870 } 00871 00872 00873 KSSLCertificate *KSSLCertificate::replicate() { 00874 // The new certificate doesn't have the cached value. It's probably 00875 // better this way. We can't anticipate every reason for doing this. 00876 KSSLCertificate *newOne = new KSSLCertificate(); 00877 #ifdef KSSL_HAVE_SSL 00878 newOne->setCert(d->kossl->X509_dup(getCert())); 00879 KSSLCertChain *c = d->_chain.replicate(); 00880 newOne->setChain(c->rawChain()); 00881 delete c; 00882 #endif 00883 return newOne; 00884 } 00885 00886 00887 QString KSSLCertificate::toString() { 00888 return KCodecs::base64Encode(toDer()); 00889 } 00890 00891 00892 QString KSSLCertificate::verifyText(KSSLValidation x) { 00893 switch (x) { 00894 case KSSLCertificate::Ok: 00895 return i18n("The certificate is valid."); 00896 case KSSLCertificate::PathLengthExceeded: 00897 case KSSLCertificate::ErrorReadingRoot: 00898 case KSSLCertificate::NoCARoot: 00899 return i18n("Certificate signing authority root files could not be found so the certificate is not verified."); 00900 case KSSLCertificate::InvalidCA: 00901 return i18n("Certificate signing authority is unknown or invalid."); 00902 case KSSLCertificate::SelfSigned: 00903 return i18n("Certificate is self-signed and thus may not be trustworthy."); 00904 case KSSLCertificate::Expired: 00905 return i18n("Certificate has expired."); 00906 case KSSLCertificate::Revoked: 00907 return i18n("Certificate has been revoked."); 00908 case KSSLCertificate::NoSSL: 00909 return i18n("SSL support was not found."); 00910 case KSSLCertificate::Untrusted: 00911 return i18n("Signature is untrusted."); 00912 case KSSLCertificate::SignatureFailed: 00913 return i18n("Signature test failed."); 00914 case KSSLCertificate::Rejected: 00915 case KSSLCertificate::InvalidPurpose: 00916 return i18n("Rejected, possibly due to an invalid purpose."); 00917 case KSSLCertificate::PrivateKeyFailed: 00918 return i18n("Private key test failed."); 00919 case KSSLCertificate::InvalidHost: 00920 return i18n("The certificate has not been issued for this host."); 00921 case KSSLCertificate::Irrelevant: 00922 return i18n("This certificate is not relevant."); 00923 default: 00924 break; 00925 } 00926 00927 return i18n("The certificate is invalid."); 00928 } 00929 00930 00931 QByteArray KSSLCertificate::toDer() { 00932 QByteArray qba; 00933 #ifdef KSSL_HAVE_SSL 00934 unsigned int certlen = d->kossl->i2d_X509(getCert(), NULL); 00935 // These should technically be unsigned char * but it doesn't matter 00936 // for our purposes 00937 char *cert = new char[certlen]; 00938 char *p = cert; 00939 // FIXME: return code! 00940 d->kossl->i2d_X509(getCert(), (unsigned char **)&p); 00941 00942 // encode it into a QString 00943 qba.duplicate(cert, certlen); 00944 delete[] cert; 00945 #endif 00946 return qba; 00947 } 00948 00949 00950 00951 QByteArray KSSLCertificate::toPem() { 00952 QByteArray qba; 00953 QString thecert = toString(); 00954 const char *header = "-----BEGIN CERTIFICATE-----\n"; 00955 const char *footer = "-----END CERTIFICATE-----\n"; 00956 00957 // We just do base64 on the ASN1 00958 // 64 character lines (unpadded) 00959 unsigned int xx = thecert.length() - 1; 00960 for (unsigned int i = 0; i < xx/64; i++) { 00961 thecert.insert(64*(i+1)+i, '\n'); 00962 } 00963 00964 thecert.prepend(header); 00965 00966 if (thecert[thecert.length()-1] != '\n') 00967 thecert += "\n"; 00968 00969 thecert.append(footer); 00970 00971 qba.duplicate(thecert.local8Bit(), thecert.length()); 00972 return qba; 00973 } 00974 00975 00976 #define NETSCAPE_CERT_HDR "certificate" 00977 00978 // what a piece of crap this is 00979 QByteArray KSSLCertificate::toNetscape() { 00980 QByteArray qba; 00981 #ifdef KSSL_HAVE_SSL 00982 ASN1_HEADER ah; 00983 ASN1_OCTET_STRING os; 00984 KTempFile ktf; 00985 00986 os.data = (unsigned char *)NETSCAPE_CERT_HDR; 00987 os.length = strlen(NETSCAPE_CERT_HDR); 00988 ah.header = &os; 00989 ah.data = (char *)getCert(); 00990 ah.meth = d->kossl->X509_asn1_meth(); 00991 00992 d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&ah); 00993 00994 ktf.close(); 00995 00996 QFile qf(ktf.name()); 00997 qf.open(IO_ReadOnly); 00998 char *buf = new char[qf.size()]; 00999 qf.readBlock(buf, qf.size()); 01000 qba.duplicate(buf, qf.size()); 01001 qf.close(); 01002 delete[] buf; 01003 01004 ktf.unlink(); 01005 01006 #endif 01007 return qba; 01008 } 01009 01010 01011 01012 QString KSSLCertificate::toText() { 01013 QString text; 01014 #ifdef KSSL_HAVE_SSL 01015 KTempFile ktf; 01016 01017 d->kossl->X509_print(ktf.fstream(), getCert()); 01018 ktf.close(); 01019 01020 QFile qf(ktf.name()); 01021 qf.open(IO_ReadOnly); 01022 char *buf = new char[qf.size()+1]; 01023 qf.readBlock(buf, qf.size()); 01024 buf[qf.size()] = 0; 01025 text = buf; 01026 delete[] buf; 01027 qf.close(); 01028 ktf.unlink(); 01029 #endif 01030 return text; 01031 } 01032 01033 // KDE 4: Make it const QString & 01034 bool KSSLCertificate::setCert(QString& cert) { 01035 #ifdef KSSL_HAVE_SSL 01036 QByteArray qba, qbb = cert.local8Bit().copy(); 01037 KCodecs::base64Decode(qbb, qba); 01038 unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data()); 01039 X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size()); 01040 if (x5c) { 01041 setCert(x5c); 01042 return true; 01043 } 01044 #endif 01045 return false; 01046 } 01047 01048 01049 KSSLX509V3& KSSLCertificate::x509V3Extensions() { 01050 return d->_extensions; 01051 } 01052 01053 01054 bool KSSLCertificate::isSigner() { 01055 return d->_extensions.certTypeCA(); 01056 } 01057 01058 01059 QDataStream& operator<<(QDataStream& s, const KSSLCertificate& r) { 01060 QStringList qsl; 01061 QPtrList<KSSLCertificate> cl = const_cast<KSSLCertificate&>(r).chain().getChain(); 01062 01063 for (KSSLCertificate *c = cl.first(); c != 0; c = cl.next()) { 01064 qsl << c->toString(); 01065 } 01066 01067 cl.setAutoDelete(true); 01068 01069 s << const_cast<KSSLCertificate&>(r).toString() << qsl; 01070 01071 return s; 01072 } 01073 01074 01075 QDataStream& operator>>(QDataStream& s, KSSLCertificate& r) { 01076 QStringList qsl; 01077 QString cert; 01078 01079 s >> cert >> qsl; 01080 01081 if (r.setCert(cert) && !qsl.isEmpty()) 01082 r.chain().setCertChain(qsl); 01083 01084 return s; 01085 } 01086 01087 01088
KDE Logo
This file is part of the documentation for kio Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:54 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003