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 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::getMD5Digest() const { 00283 QString rc = ""; 00284 00285 #ifdef KSSL_HAVE_SSL 00286 unsigned int n; 00287 unsigned char md[EVP_MAX_MD_SIZE]; 00288 00289 if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) { 00290 return rc; 00291 } 00292 00293 for (unsigned int j = 0; j < n; j++) { 00294 rc.append(hv[(md[j]&0xf0)>>4]); 00295 rc.append(hv[md[j]&0x0f]); 00296 } 00297 00298 #endif 00299 00300 return rc; 00301 } 00302 00303 00304 00305 QString KSSLCertificate::getKeyType() const { 00306 QString rc = ""; 00307 00308 #ifdef KSSL_HAVE_SSL 00309 EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert); 00310 if (pkey) { 00311 #ifndef NO_RSA 00312 if (pkey->type == EVP_PKEY_RSA) 00313 rc = "RSA"; 00314 else 00315 #endif 00316 #ifndef NO_DSA 00317 if (pkey->type == EVP_PKEY_DSA) 00318 rc = "DSA"; 00319 else 00320 #endif 00321 rc = "Unknown"; 00322 d->kossl->EVP_PKEY_free(pkey); 00323 } 00324 #endif 00325 00326 return rc; 00327 } 00328 00329 00330 00331 QString KSSLCertificate::getPublicKeyText() const { 00332 QString rc = ""; 00333 char *x = NULL; 00334 00335 #ifdef KSSL_HAVE_SSL 00336 EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert); 00337 if (pkey) { 00338 rc = i18n("Unknown", "Unknown key algorithm"); 00339 #ifndef NO_RSA 00340 if (pkey->type == EVP_PKEY_RSA) { 00341 rc = i18n("Key type: RSA (%1 bit)") + "\n"; 00342 00343 x = d->kossl->BN_bn2hex(pkey->pkey.rsa->n); 00344 rc += i18n("Modulus: "); 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.rsa->e); 00357 rc += i18n("Exponent: 0x") + x + "\n"; 00358 d->kossl->OPENSSL_free(x); 00359 } 00360 #endif 00361 #ifndef NO_DSA 00362 if (pkey->type == EVP_PKEY_DSA) { 00363 rc = i18n("Key type: DSA (%1 bit)") + "\n"; 00364 00365 x = d->kossl->BN_bn2hex(pkey->pkey.dsa->p); 00366 rc += i18n("Prime: "); 00367 // hack - this may not be always accurate 00368 rc = rc.arg(strlen(x)*4) ; 00369 for (unsigned int i = 0; i < strlen(x); i++) { 00370 if (i%40 != 0 && i%2 == 0) 00371 rc += ":"; 00372 else if (i%40 == 0) 00373 rc += "\n"; 00374 rc += x[i]; 00375 } 00376 rc += "\n"; 00377 d->kossl->OPENSSL_free(x); 00378 00379 x = d->kossl->BN_bn2hex(pkey->pkey.dsa->q); 00380 rc += i18n("160 bit prime factor: "); 00381 for (unsigned int i = 0; i < strlen(x); i++) { 00382 if (i%40 != 0 && i%2 == 0) 00383 rc += ":"; 00384 else if (i%40 == 0) 00385 rc += "\n"; 00386 rc += x[i]; 00387 } 00388 rc += "\n"; 00389 d->kossl->OPENSSL_free(x); 00390 00391 x = d->kossl->BN_bn2hex(pkey->pkey.dsa->g); 00392 rc += QString("g: "); 00393 for (unsigned int i = 0; i < strlen(x); i++) { 00394 if (i%40 != 0 && i%2 == 0) 00395 rc += ":"; 00396 else if (i%40 == 0) 00397 rc += "\n"; 00398 rc += x[i]; 00399 } 00400 rc += "\n"; 00401 d->kossl->OPENSSL_free(x); 00402 00403 x = d->kossl->BN_bn2hex(pkey->pkey.dsa->pub_key); 00404 rc += i18n("Public key: "); 00405 for (unsigned int i = 0; i < strlen(x); i++) { 00406 if (i%40 != 0 && i%2 == 0) 00407 rc += ":"; 00408 else if (i%40 == 0) 00409 rc += "\n"; 00410 rc += x[i]; 00411 } 00412 rc += "\n"; 00413 d->kossl->OPENSSL_free(x); 00414 } 00415 #endif 00416 d->kossl->EVP_PKEY_free(pkey); 00417 } 00418 #endif 00419 00420 return rc; 00421 } 00422 00423 00424 00425 QString KSSLCertificate::getIssuer() const { 00426 QString rc = ""; 00427 00428 #ifdef KSSL_HAVE_SSL 00429 char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_issuer_name(d->m_cert), 0, 0); 00430 00431 if (!t) 00432 return rc; 00433 00434 rc = t; 00435 d->kossl->OPENSSL_free(t); 00436 #endif 00437 00438 return rc; 00439 } 00440 00441 void KSSLCertificate::setChain(void *c) { 00442 #ifdef KSSL_HAVE_SSL 00443 d->_chain.setChain(c); 00444 #endif 00445 d->m_stateCached = false; 00446 d->m_stateCache = KSSLCertificate::Unknown; 00447 } 00448 00449 void KSSLCertificate::setCert(X509 *c) { 00450 #ifdef KSSL_HAVE_SSL 00451 d->m_cert = c; 00452 if (c) { 00453 d->_extensions.flags = 0; 00454 d->kossl->X509_check_purpose(c, -1, 0); // setup the fields (!!) 00455 00456 #if 0 00457 kdDebug(7029) << "---------------- Certificate ------------------" 00458 << endl; 00459 kdDebug(7029) << getSubject() << endl; 00460 #endif 00461 00462 for (int j = 0; j < d->kossl->X509_PURPOSE_get_count(); j++) { 00463 X509_PURPOSE *ptmp = d->kossl->X509_PURPOSE_get0(j); 00464 int id = d->kossl->X509_PURPOSE_get_id(ptmp); 00465 for (int ca = 0; ca < 2; ca++) { 00466 int idret = d->kossl->X509_check_purpose(c, id, ca); 00467 if (idret == 1 || idret == 2) { // have it 00468 // kdDebug() << "PURPOSE: " << id << (ca?" CA":"") << endl; 00469 if (!ca) 00470 d->_extensions.flags |= (1L <<(id-1)); 00471 else d->_extensions.flags |= (1L <<(16+id-1)); 00472 } else { 00473 if (!ca) 00474 d->_extensions.flags &= ~(1L <<(id-1)); 00475 else d->_extensions.flags &= ~(1L <<(16+id-1)); 00476 } 00477 } 00478 } 00479 00480 #if 0 00481 kdDebug(7029) << "flags: " << QString::number(c->ex_flags, 2) 00482 << "\nkeyusage: " << QString::number(c->ex_kusage, 2) 00483 << "\nxkeyusage: " << QString::number(c->ex_xkusage, 2) 00484 << "\nnscert: " << QString::number(c->ex_nscert, 2) 00485 << endl; 00486 if (c->ex_flags & EXFLAG_KUSAGE) 00487 kdDebug(7029) << " --- Key Usage extensions found" << endl; 00488 else kdDebug(7029) << " --- Key Usage extensions NOT found" << endl; 00489 00490 if (c->ex_flags & EXFLAG_XKUSAGE) 00491 kdDebug(7029) << " --- Extended key usage extensions found" << endl; 00492 else kdDebug(7029) << " --- Extended key usage extensions NOT found" << endl; 00493 00494 if (c->ex_flags & EXFLAG_NSCERT) 00495 kdDebug(7029) << " --- NS extensions found" << endl; 00496 else kdDebug(7029) << " --- NS extensions NOT found" << endl; 00497 00498 if (d->_extensions.certTypeSSLCA()) 00499 kdDebug(7029) << "NOTE: this is an SSL CA file." << endl; 00500 else kdDebug(7029) << "NOTE: this is NOT an SSL CA file." << endl; 00501 00502 if (d->_extensions.certTypeEmailCA()) 00503 kdDebug(7029) << "NOTE: this is an EMAIL CA file." << endl; 00504 else kdDebug(7029) << "NOTE: this is NOT an EMAIL CA file." << endl; 00505 00506 if (d->_extensions.certTypeCodeCA()) 00507 kdDebug(7029) << "NOTE: this is a CODE CA file." << endl; 00508 else kdDebug(7029) << "NOTE: this is NOT a CODE CA file." << endl; 00509 00510 if (d->_extensions.certTypeSSLClient()) 00511 kdDebug(7029) << "NOTE: this is an SSL client." << endl; 00512 else kdDebug(7029) << "NOTE: this is NOT an SSL client." << endl; 00513 00514 if (d->_extensions.certTypeSSLServer()) 00515 kdDebug(7029) << "NOTE: this is an SSL server." << endl; 00516 else kdDebug(7029) << "NOTE: this is NOT an SSL server." << endl; 00517 00518 if (d->_extensions.certTypeNSSSLServer()) 00519 kdDebug(7029) << "NOTE: this is a NETSCAPE SSL server." << endl; 00520 else kdDebug(7029) << "NOTE: this is NOT a NETSCAPE SSL server." << endl; 00521 00522 if (d->_extensions.certTypeSMIME()) 00523 kdDebug(7029) << "NOTE: this is an SMIME certificate." << endl; 00524 else kdDebug(7029) << "NOTE: this is NOT an SMIME certificate." << endl; 00525 00526 if (d->_extensions.certTypeSMIMEEncrypt()) 00527 kdDebug(7029) << "NOTE: this is an SMIME encrypt cert." << endl; 00528 else kdDebug(7029) << "NOTE: this is NOT an SMIME encrypt cert." << endl; 00529 00530 if (d->_extensions.certTypeSMIMESign()) 00531 kdDebug(7029) << "NOTE: this is an SMIME sign cert." << endl; 00532 else kdDebug(7029) << "NOTE: this is NOT an SMIME sign cert." << endl; 00533 00534 if (d->_extensions.certTypeCRLSign()) 00535 kdDebug(7029) << "NOTE: this is a CRL signer." << endl; 00536 else kdDebug(7029) << "NOTE: this is NOT a CRL signer." << endl; 00537 00538 kdDebug(7029) << "-----------------------------------------------" 00539 << endl; 00540 #endif 00541 } 00542 #endif 00543 d->m_stateCached = false; 00544 d->m_stateCache = KSSLCertificate::Unknown; 00545 } 00546 00547 X509 *KSSLCertificate::getCert() { 00548 #ifdef KSSL_HAVE_SSL 00549 return d->m_cert; 00550 #endif 00551 return 0; 00552 } 00553 00554 // pull in the callback. It's common across multiple files but we want 00555 // it to be hidden. 00556 00557 #include "ksslcallback.c" 00558 00559 00560 bool KSSLCertificate::isValid(KSSLCertificate::KSSLPurpose p) { 00561 return (validate(p) == KSSLCertificate::Ok); 00562 } 00563 00564 00565 bool KSSLCertificate::isValid() { 00566 return isValid(KSSLCertificate::SSLServer); 00567 } 00568 00569 00570 int KSSLCertificate::purposeToOpenSSL(KSSLCertificate::KSSLPurpose p) const { 00571 int rc = 0; 00572 #ifdef KSSL_HAVE_SSL 00573 if (p == KSSLCertificate::SSLServer) { 00574 rc = X509_PURPOSE_SSL_SERVER; 00575 } else if (p == KSSLCertificate::SSLClient) { 00576 rc = X509_PURPOSE_SSL_CLIENT; 00577 } else if (p == KSSLCertificate::SMIMEEncrypt) { 00578 rc = X509_PURPOSE_SMIME_ENCRYPT; 00579 } else if (p == KSSLCertificate::SMIMESign) { 00580 rc = X509_PURPOSE_SMIME_SIGN; 00581 } else if (p == KSSLCertificate::Any) { 00582 rc = X509_PURPOSE_ANY; 00583 } 00584 #endif 00585 return rc; 00586 } 00587 00588 00589 // For backward compatibility 00590 KSSLCertificate::KSSLValidation KSSLCertificate::validate() { 00591 return validate(KSSLCertificate::SSLServer); 00592 } 00593 00594 KSSLCertificate::KSSLValidation KSSLCertificate::validate(KSSLCertificate::KSSLPurpose purpose) 00595 { 00596 KSSLValidationList result = validateVerbose(purpose); 00597 if (result.isEmpty()) 00598 return KSSLCertificate::Ok; 00599 else 00600 return result.first(); 00601 } 00602 00603 // 00604 // See apps/verify.c in OpenSSL for the source of most of this logic. 00605 // 00606 00607 // CRL files? we don't do that yet 00608 KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose) 00609 { 00610 return validateVerbose(purpose, 0); 00611 } 00612 00613 KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose, KSSLCertificate *ca) 00614 { 00615 KSSLValidationList errors; 00616 if (ca || (d->_lastPurpose != purpose)) { 00617 d->m_stateCached = false; 00618 } 00619 00620 if (!d->m_stateCached) 00621 d->_lastPurpose = purpose; 00622 00623 #ifdef KSSL_HAVE_SSL 00624 X509_STORE *certStore; 00625 X509_LOOKUP *certLookup; 00626 X509_STORE_CTX *certStoreCTX; 00627 int rc = 0; 00628 00629 if (!d->m_cert) 00630 { 00631 errors << KSSLCertificate::Unknown; 00632 return errors; 00633 } 00634 00635 if (d->m_stateCached) { 00636 errors << d->m_stateCache; 00637 return errors; 00638 } 00639 00640 QStringList qsl = KGlobal::dirs()->resourceDirs("kssl"); 00641 00642 if (qsl.isEmpty()) { 00643 errors << KSSLCertificate::NoCARoot; 00644 return errors; 00645 } 00646 00647 KSSLCertificate::KSSLValidation ksslv = Unknown; 00648 00649 for (QStringList::Iterator j = qsl.begin(); j != qsl.end(); ++j) { 00650 struct stat sb; 00651 QString _j = (*j) + "ca-bundle.crt"; 00652 if (-1 == stat(_j.ascii(), &sb)) { 00653 continue; 00654 } 00655 00656 certStore = d->kossl->X509_STORE_new(); 00657 if (!certStore) { 00658 errors << KSSLCertificate::Unknown; 00659 return errors; 00660 } 00661 00662 X509_STORE_set_verify_cb_func(certStore, X509Callback); 00663 00664 certLookup = d->kossl->X509_STORE_add_lookup(certStore, d->kossl->X509_LOOKUP_file()); 00665 if (!certLookup) { 00666 ksslv = KSSLCertificate::Unknown; 00667 d->kossl->X509_STORE_free(certStore); 00668 continue; 00669 } 00670 00671 if (!d->kossl->X509_LOOKUP_load_file(certLookup, _j.ascii(), X509_FILETYPE_PEM)) { 00672 // error accessing directory and loading pems 00673 kdDebug(7029) << "KSSL couldn't read CA root: " 00674 << _j << endl; 00675 ksslv = KSSLCertificate::ErrorReadingRoot; 00676 d->kossl->X509_STORE_free(certStore); 00677 continue; 00678 } 00679 00680 // This is the checking code 00681 certStoreCTX = d->kossl->X509_STORE_CTX_new(); 00682 00683 // this is a bad error - could mean no free memory. 00684 // This may be the wrong thing to do here 00685 if (!certStoreCTX) { 00686 kdDebug(7029) << "KSSL couldn't create an X509 store context." << endl; 00687 d->kossl->X509_STORE_free(certStore); 00688 continue; 00689 } 00690 00691 d->kossl->X509_STORE_CTX_init(certStoreCTX, certStore, d->m_cert, NULL); 00692 if (d->_chain.isValid()) { 00693 d->kossl->X509_STORE_CTX_set_chain(certStoreCTX, (STACK_OF(X509)*)d->_chain.rawChain()); 00694 } 00695 00696 //kdDebug(7029) << "KSSL setting CRL.............." << endl; 00697 // int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x); 00698 00699 d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX, purposeToOpenSSL(purpose)); 00700 00701 KSSL_X509CallBack_ca = ca ? ca->d->m_cert : 0; 00702 KSSL_X509CallBack_ca_found = false; 00703 00704 certStoreCTX->error = X509_V_OK; 00705 rc = d->kossl->X509_verify_cert(certStoreCTX); 00706 int errcode = certStoreCTX->error; 00707 if (ca && !KSSL_X509CallBack_ca_found) { 00708 ksslv = KSSLCertificate::Irrelevant; 00709 } else { 00710 ksslv = processError(errcode); 00711 } 00712 // For servers, we can try NS_SSL_SERVER too 00713 if ( (ksslv != KSSLCertificate::Ok) && 00714 (ksslv != KSSLCertificate::Irrelevant) && 00715 purpose == KSSLCertificate::SSLServer) { 00716 d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX, 00717 X509_PURPOSE_NS_SSL_SERVER); 00718 00719 certStoreCTX->error = X509_V_OK; 00720 rc = d->kossl->X509_verify_cert(certStoreCTX); 00721 errcode = certStoreCTX->error; 00722 ksslv = processError(errcode); 00723 } 00724 d->kossl->X509_STORE_CTX_free(certStoreCTX); 00725 d->kossl->X509_STORE_free(certStore); 00726 // end of checking code 00727 // 00728 00729 //kdDebug(7029) << "KSSL Validation procedure RC: " 00730 // << rc << endl; 00731 //kdDebug(7029) << "KSSL Validation procedure errcode: " 00732 // << errcode << endl; 00733 //kdDebug(7029) << "KSSL Validation procedure RESULTS: " 00734 // << ksslv << endl; 00735 00736 if (ksslv != NoCARoot && ksslv != InvalidCA) { 00737 d->m_stateCached = true; 00738 d->m_stateCache = ksslv; 00739 } 00740 break; 00741 } 00742 00743 if (ksslv != KSSLCertificate::Ok) 00744 errors << ksslv; 00745 #else 00746 errors << KSSLCertificate::NoSSL; 00747 #endif 00748 return errors; 00749 } 00750 00751 00752 00753 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate() { 00754 return revalidate(KSSLCertificate::SSLServer); 00755 } 00756 00757 00758 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate(KSSLCertificate::KSSLPurpose p) { 00759 d->m_stateCached = false; 00760 return validate(p); 00761 } 00762 00763 00764 KSSLCertificate::KSSLValidation KSSLCertificate::processError(int ec) { 00765 KSSLCertificate::KSSLValidation rc; 00766 00767 rc = KSSLCertificate::Unknown; 00768 #ifdef KSSL_HAVE_SSL 00769 switch (ec) { 00770 case X509_V_OK: // OK 00771 rc = KSSLCertificate::Ok; 00772 break; 00773 00774 00775 case X509_V_ERR_CERT_REJECTED: 00776 rc = KSSLCertificate::Rejected; 00777 break; 00778 00779 00780 case X509_V_ERR_CERT_UNTRUSTED: 00781 rc = KSSLCertificate::Untrusted; 00782 break; 00783 00784 00785 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: 00786 case X509_V_ERR_CERT_SIGNATURE_FAILURE: 00787 case X509_V_ERR_CRL_SIGNATURE_FAILURE: 00788 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: 00789 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: 00790 rc = KSSLCertificate::SignatureFailed; 00791 break; 00792 00793 case X509_V_ERR_INVALID_CA: 00794 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: 00795 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: 00796 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: 00797 rc = KSSLCertificate::InvalidCA; 00798 break; 00799 00800 00801 case X509_V_ERR_INVALID_PURPOSE: 00802 rc = KSSLCertificate::InvalidPurpose; 00803 break; 00804 00805 00806 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: 00807 rc = KSSLCertificate::SelfSigned; 00808 break; 00809 00810 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: 00811 rc = KSSLCertificate::SelfSignedChain; 00812 break; 00813 00814 case X509_V_ERR_CERT_REVOKED: 00815 rc = KSSLCertificate::Revoked; 00816 break; 00817 00818 case X509_V_ERR_PATH_LENGTH_EXCEEDED: 00819 rc = KSSLCertificate::PathLengthExceeded; 00820 break; 00821 00822 case X509_V_ERR_CERT_NOT_YET_VALID: 00823 case X509_V_ERR_CERT_HAS_EXPIRED: 00824 case X509_V_ERR_CRL_NOT_YET_VALID: 00825 case X509_V_ERR_CRL_HAS_EXPIRED: 00826 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: 00827 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: 00828 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: 00829 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: 00830 rc = KSSLCertificate::Expired; 00831 kdDebug(7029) << "KSSL apparently this is expired. Not after: " 00832 << getNotAfter() << endl; 00833 break; 00834 00835 //case 1: 00836 case X509_V_ERR_APPLICATION_VERIFICATION: 00837 case X509_V_ERR_OUT_OF_MEM: 00838 case X509_V_ERR_UNABLE_TO_GET_CRL: 00839 case X509_V_ERR_CERT_CHAIN_TOO_LONG: 00840 default: 00841 rc = KSSLCertificate::Unknown; 00842 break; 00843 } 00844 00845 d->m_stateCache = rc; 00846 d->m_stateCached = true; 00847 #endif 00848 return rc; 00849 } 00850 00851 00852 QString KSSLCertificate::getNotBefore() const { 00853 #ifdef KSSL_HAVE_SSL 00854 return ASN1_UTCTIME_QString(X509_get_notBefore(d->m_cert)); 00855 #else 00856 return QString::null; 00857 #endif 00858 } 00859 00860 00861 QString KSSLCertificate::getNotAfter() const { 00862 #ifdef KSSL_HAVE_SSL 00863 return ASN1_UTCTIME_QString(X509_get_notAfter(d->m_cert)); 00864 #else 00865 return QString::null; 00866 #endif 00867 } 00868 00869 00870 QDateTime KSSLCertificate::getQDTNotBefore() const { 00871 #ifdef KSSL_HAVE_SSL 00872 return ASN1_UTCTIME_QDateTime(X509_get_notBefore(d->m_cert), NULL); 00873 #else 00874 return QDateTime::currentDateTime(); 00875 #endif 00876 } 00877 00878 00879 QDateTime KSSLCertificate::getQDTNotAfter() const { 00880 #ifdef KSSL_HAVE_SSL 00881 return ASN1_UTCTIME_QDateTime(X509_get_notAfter(d->m_cert), NULL); 00882 #else 00883 return QDateTime::currentDateTime(); 00884 #endif 00885 } 00886 00887 00888 int operator==(KSSLCertificate &x, KSSLCertificate &y) { 00889 #ifndef KSSL_HAVE_SSL 00890 return 1; 00891 #else 00892 if (!KOSSL::self()->X509_cmp(x.getCert(), y.getCert())) return 1; 00893 return 0; 00894 #endif 00895 } 00896 00897 00898 KSSLCertificate *KSSLCertificate::replicate() { 00899 // The new certificate doesn't have the cached value. It's probably 00900 // better this way. We can't anticipate every reason for doing this. 00901 KSSLCertificate *newOne = new KSSLCertificate(); 00902 #ifdef KSSL_HAVE_SSL 00903 newOne->setCert(d->kossl->X509_dup(getCert())); 00904 KSSLCertChain *c = d->_chain.replicate(); 00905 newOne->setChain(c->rawChain()); 00906 delete c; 00907 #endif 00908 return newOne; 00909 } 00910 00911 00912 QString KSSLCertificate::toString() { 00913 return KCodecs::base64Encode(toDer()); 00914 } 00915 00916 00917 QString KSSLCertificate::verifyText(KSSLValidation x) { 00918 switch (x) { 00919 case KSSLCertificate::Ok: 00920 return i18n("The certificate is valid."); 00921 case KSSLCertificate::PathLengthExceeded: 00922 case KSSLCertificate::ErrorReadingRoot: 00923 case KSSLCertificate::NoCARoot: 00924 return i18n("Certificate signing authority root files could not be found so the certificate is not verified."); 00925 case KSSLCertificate::SelfSignedChain: 00926 case KSSLCertificate::InvalidCA: 00927 return i18n("Certificate signing authority is unknown or invalid."); 00928 case KSSLCertificate::SelfSigned: 00929 return i18n("Certificate is self-signed and thus may not be trustworthy."); 00930 case KSSLCertificate::Expired: 00931 return i18n("Certificate has expired."); 00932 case KSSLCertificate::Revoked: 00933 return i18n("Certificate has been revoked."); 00934 case KSSLCertificate::NoSSL: 00935 return i18n("SSL support was not found."); 00936 case KSSLCertificate::Untrusted: 00937 return i18n("Signature is untrusted."); 00938 case KSSLCertificate::SignatureFailed: 00939 return i18n("Signature test failed."); 00940 case KSSLCertificate::Rejected: 00941 case KSSLCertificate::InvalidPurpose: 00942 return i18n("Rejected, possibly due to an invalid purpose."); 00943 case KSSLCertificate::PrivateKeyFailed: 00944 return i18n("Private key test failed."); 00945 case KSSLCertificate::InvalidHost: 00946 return i18n("The certificate has not been issued for this host."); 00947 case KSSLCertificate::Irrelevant: 00948 return i18n("This certificate is not relevant."); 00949 default: 00950 break; 00951 } 00952 00953 return i18n("The certificate is invalid."); 00954 } 00955 00956 00957 QByteArray KSSLCertificate::toDer() { 00958 QByteArray qba; 00959 #ifdef KSSL_HAVE_SSL 00960 unsigned int certlen = d->kossl->i2d_X509(getCert(), NULL); 00961 unsigned char *cert = new unsigned char[certlen]; 00962 unsigned char *p = cert; 00963 // FIXME: return code! 00964 d->kossl->i2d_X509(getCert(), &p); 00965 00966 // encode it into a QString 00967 qba.duplicate((const char*)cert, certlen); 00968 delete[] cert; 00969 #endif 00970 return qba; 00971 } 00972 00973 00974 00975 QByteArray KSSLCertificate::toPem() { 00976 QByteArray qba; 00977 QString thecert = toString(); 00978 const char *header = "-----BEGIN CERTIFICATE-----\n"; 00979 const char *footer = "-----END CERTIFICATE-----\n"; 00980 00981 // We just do base64 on the ASN1 00982 // 64 character lines (unpadded) 00983 unsigned int xx = thecert.length() - 1; 00984 for (unsigned int i = 0; i < xx/64; i++) { 00985 thecert.insert(64*(i+1)+i, '\n'); 00986 } 00987 00988 thecert.prepend(header); 00989 00990 if (thecert[thecert.length()-1] != '\n') 00991 thecert += "\n"; 00992 00993 thecert.append(footer); 00994 00995 qba.duplicate(thecert.local8Bit(), thecert.length()); 00996 return qba; 00997 } 00998 00999 01000 #define NETSCAPE_CERT_HDR "certificate" 01001 01002 // what a piece of crap this is 01003 QByteArray KSSLCertificate::toNetscape() { 01004 QByteArray qba; 01005 #ifdef KSSL_HAVE_SSL 01006 #if OPENSSL_VERSION_NUMBER >= 0x10000000L 01007 NETSCAPE_X509 nx; 01008 ASN1_OCTET_STRING hdr; 01009 #else 01010 ASN1_HEADER ah; 01011 ASN1_OCTET_STRING os; 01012 #endif 01013 KTempFile ktf; 01014 01015 #if OPENSSL_VERSION_NUMBER >= 0x10000000L 01016 hdr.data = (unsigned char *)NETSCAPE_CERT_HDR; 01017 hdr.length = strlen(NETSCAPE_CERT_HDR); 01018 nx.header = &hdr; 01019 nx.cert = getCert(); 01020 01021 d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&nx); 01022 #else 01023 os.data = (unsigned char *)NETSCAPE_CERT_HDR; 01024 os.length = strlen(NETSCAPE_CERT_HDR); 01025 ah.header = &os; 01026 ah.data = (char *)getCert(); 01027 ah.meth = d->kossl->X509_asn1_meth(); 01028 01029 d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&ah); 01030 #endif 01031 01032 ktf.close(); 01033 01034 QFile qf(ktf.name()); 01035 qf.open(IO_ReadOnly); 01036 char *buf = new char[qf.size()]; 01037 qf.readBlock(buf, qf.size()); 01038 qba.duplicate(buf, qf.size()); 01039 qf.close(); 01040 delete[] buf; 01041 01042 ktf.unlink(); 01043 01044 #endif 01045 return qba; 01046 } 01047 01048 01049 01050 QString KSSLCertificate::toText() { 01051 QString text; 01052 #ifdef KSSL_HAVE_SSL 01053 KTempFile ktf; 01054 01055 d->kossl->X509_print(ktf.fstream(), getCert()); 01056 ktf.close(); 01057 01058 QFile qf(ktf.name()); 01059 qf.open(IO_ReadOnly); 01060 char *buf = new char[qf.size()+1]; 01061 qf.readBlock(buf, qf.size()); 01062 buf[qf.size()] = 0; 01063 text = buf; 01064 delete[] buf; 01065 qf.close(); 01066 ktf.unlink(); 01067 #endif 01068 return text; 01069 } 01070 01071 // KDE 4: Make it const QString & 01072 bool KSSLCertificate::setCert(QString& cert) { 01073 #ifdef KSSL_HAVE_SSL 01074 QByteArray qba, qbb = cert.local8Bit().copy(); 01075 KCodecs::base64Decode(qbb, qba); 01076 unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data()); 01077 X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size()); 01078 if (x5c) { 01079 setCert(x5c); 01080 return true; 01081 } 01082 #endif 01083 return false; 01084 } 01085 01086 01087 KSSLX509V3& KSSLCertificate::x509V3Extensions() { 01088 return d->_extensions; 01089 } 01090 01091 01092 bool KSSLCertificate::isSigner() { 01093 return d->_extensions.certTypeCA(); 01094 } 01095 01096 01097 QStringList KSSLCertificate::subjAltNames() const { 01098 QStringList rc; 01099 #ifdef KSSL_HAVE_SSL 01100 STACK_OF(GENERAL_NAME) *names; 01101 names = (STACK_OF(GENERAL_NAME)*)d->kossl->X509_get_ext_d2i(d->m_cert, NID_subject_alt_name, 0, 0); 01102 01103 if (!names) { 01104 return rc; 01105 } 01106 01107 int cnt = d->kossl->sk_GENERAL_NAME_num(names); 01108 01109 for (int i = 0; i < cnt; i++) { 01110 const GENERAL_NAME *val = (const GENERAL_NAME *)d->kossl->sk_value(names, i); 01111 if (val->type != GEN_DNS) { 01112 continue; 01113 } 01114 01115 QString s = (const char *)d->kossl->ASN1_STRING_data(val->d.ia5); 01116 if (!s.isEmpty() && 01117 /* skip subjectAltNames with embedded NULs */ 01118 s.length() == d->kossl->ASN1_STRING_length(val->d.ia5)) { 01119 rc += s; 01120 } 01121 } 01122 d->kossl->sk_free(names); 01123 #endif 01124 return rc; 01125 } 01126 01127 01128 QDataStream& operator<<(QDataStream& s, const KSSLCertificate& r) { 01129 QStringList qsl; 01130 QPtrList<KSSLCertificate> cl = const_cast<KSSLCertificate&>(r).chain().getChain(); 01131 01132 for (KSSLCertificate *c = cl.first(); c != 0; c = cl.next()) { 01133 qsl << c->toString(); 01134 } 01135 01136 cl.setAutoDelete(true); 01137 01138 s << const_cast<KSSLCertificate&>(r).toString() << qsl; 01139 01140 return s; 01141 } 01142 01143 01144 QDataStream& operator>>(QDataStream& s, KSSLCertificate& r) { 01145 QStringList qsl; 01146 QString cert; 01147 01148 s >> cert >> qsl; 01149 01150 if (r.setCert(cert) && !qsl.isEmpty()) 01151 r.chain().setCertChain(qsl); 01152 01153 return s; 01154 } 01155 01156 01157