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