kssl.cc Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kssl.cc

    00001 /* This file is part of the KDE project
    00002  *
    00003  * Copyright (C) 2000 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 #ifdef HAVE_CONFIG_H
    00021 #include <config.h>
    00022 #endif
    00023
    00024 // this hack provided by Malte Starostik to avoid glibc/openssl bug
    00025 // on some systems
    00026 #ifdef KSSL_HAVE_SSL
    00027 #include <unistd.h>
    00028 #include <netinet/in.h>
    00029 #include <sys/socket.h>
    00030 #define crypt _openssl_crypt
    00031 #include <openssl/ssl.h>
    00032 #include <openssl/x509.h>
    00033 #include <openssl/x509v3.h>
    00034 #include <openssl/pem.h>
    00035 #include <openssl/rand.h>
    00036 #undef crypt
    00037 #endif
    00038
    00039 #include "kssl.h"
    00040
    00041 #include <kdebug.h>
    00042 #include <kstandarddirs.h>
    00043 #include <ksock.h>
    00044 #include <ksockaddr.h>
    00045
    00046 #include <kopenssl.h>
    00047 #include <ksslx509v3.h>
    00048 #include <ksslpkcs12.h>
    00049 #include <klocale.h>
    00050 #include <ksocks.h>
    00051
    00052 #define sk_dup d->kossl->sk_dup
    00053
    00054 class KSSLPrivate {
    00055 public:
    00056   KSSLPrivate() {
    00057     lastInitTLS = false;
    00058     kossl = KOpenSSLProxy::self();
    00059   }
    00060
    00061   ~KSSLPrivate() {
    00062
    00063   }
    00064
    00065   bool lastInitTLS;
    00066   KSSLCertificate::KSSLValidation m_cert_vfy_res;
    00067   QString proxyPeer;
    00068
    00069 #ifdef KSSL_HAVE_SSL
    00070     SSL *m_ssl;
    00071     SSL_CTX *m_ctx;
    00072     SSL_METHOD *m_meth;
    00073 #endif
    00074   KOSSL *kossl;
    00075 };
    00076
    00077
    00078 KSSL::KSSL(bool init) {
    00079   d = new KSSLPrivate;
    00080   m_bInit = false;
    00081   m_bAutoReconfig = true;
    00082   m_cfg = new KSSLSettings();
    00083 #ifdef KSSL_HAVE_SSL
    00084   d->m_ssl = NULL;
    00085 #endif
    00086
    00087  if (init) initialize();
    00088 }
    00089
    00090
    00091 KSSL::~KSSL() {
    00092   close();
    00093   delete m_cfg;
    00094   delete d;
    00095 }
    00096
    00097
    00098 int KSSL::seedWithEGD() {
    00099 int rc = 0;
    00100   #ifdef KSSL_HAVE_SSL
    00101   if (m_cfg->useEGD() && !m_cfg->getEGDPath().isEmpty()) {
    00102     rc = d->kossl->RAND_egd(m_cfg->getEGDPath().latin1());
    00103     if (rc < 0)
    00104       kdDebug(7029) << "KSSL: Error seeding PRNG with the EGD." << endl;
    00105     else
    00106       kdDebug(7029) << "KSSL: PRNG was seeded with " << rc
    00107                 << " bytes from the EGD." << endl;
    00108   } else if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
    00109           rc = d->kossl->RAND_load_file(m_cfg->getEGDPath().latin1(), -1);
    00110     if (rc < 0)
    00111       kdDebug(7029) << "KSSL: Error seeding PRNG with the entropy file." << endl;
    00112     else
    00113       kdDebug(7029) << "KSSL: PRNG was seeded with " << rc
    00114                 << " bytes from the entropy file." << endl;
    00115   }
    00116   #endif
    00117   return rc;
    00118 }
    00119
    00120
    00121 bool KSSL::TLSInit() {
    00122 #ifdef KSSL_HAVE_SSL
    00123   // kdDebug(7029) << "KSSL TLS initialize" << endl;
    00124   if (m_bInit) return false;
    00125
    00126   if (m_bAutoReconfig)
    00127     m_cfg->load();
    00128
    00129   if (!m_cfg->tlsv1()) return false;
    00130
    00131   seedWithEGD();
    00132   d->m_meth = d->kossl->TLSv1_client_method();
    00133   d->lastInitTLS = true;
    00134
    00135   d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
    00136   if (d->m_ctx == NULL) {
    00137     return false;
    00138   }
    00139
    00140   // set cipher list
    00141   QString clist = m_cfg->getCipherList();
    00142   //kdDebug(7029) << "Cipher list: " << clist << endl;
    00143   if (!clist.isEmpty())
    00144     d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
    00145
    00146   m_bInit = true;
    00147 return true;
    00148 #else
    00149 return false;
    00150 #endif
    00151 }
    00152
    00153
    00154 bool KSSL::initialize() {
    00155 #ifdef KSSL_HAVE_SSL
    00156   kdDebug(7029) << "KSSL initialize" << endl;
    00157   if (m_bInit) return false;
    00158
    00159   if (m_bAutoReconfig)
    00160     m_cfg->load();
    00161
    00162   seedWithEGD();
    00163   // FIXME: we should be able to force SSL off entirely.
    00164   //        This logic here makes v2 a "default" if no other SSL
    00165   //        version is turned on.  IMHO this is the safest one to
    00166   //        use as the default anyways, so I'm not changing it yet.
    00167   d->lastInitTLS = false;
    00168
    00169   m_pi.reset();
    00170
    00171   if (m_cfg->sslv2() && m_cfg->sslv3())
    00172     d->m_meth = d->kossl->SSLv23_client_method();
    00173   else if (m_cfg->sslv3())
    00174     d->m_meth = d->kossl->SSLv3_client_method();
    00175   else
    00176     d->m_meth = d->kossl->SSLv2_client_method();
    00177
    00178   /*
    00179   if (m_cfg->sslv2() && m_cfg->sslv3()) kdDebug(7029) << "Double method" << endl;
    00180   else if (m_cfg->sslv2()) kdDebug(7029) << "SSL2 method" << endl;
    00181   else if (m_cfg->sslv3()) kdDebug(7029) << "SSL3 method" << endl;
    00182   */
    00183
    00184   d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
    00185   if (d->m_ctx == NULL) {
    00186     return false;
    00187   }
    00188
    00189   // set cipher list
    00190   QString clist = m_cfg->getCipherList();
    00191   kdDebug(7029) << "Cipher list: " << clist << endl;
    00192   if (!clist.isEmpty())
    00193     d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
    00194
    00195   m_bInit = true;
    00196 return true;
    00197 #else
    00198 return false;
    00199 #endif
    00200 }
    00201
    00202
    00203
    00204
    00205 void KSSL::close() {
    00206 #ifdef KSSL_HAVE_SSL
    00207   //kdDebug(7029) << "KSSL close" << endl;
    00208   if (!m_bInit) return;
    00209   if (d->m_ssl) {
    00210      d->kossl->SSL_shutdown(d->m_ssl);
    00211      d->kossl->SSL_free(d->m_ssl);
    00212      d->m_ssl = NULL;
    00213   }
    00214   d->kossl->SSL_CTX_free(d->m_ctx);
    00215   if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
    00216           d->kossl->RAND_write_file(m_cfg->getEGDPath().latin1());
    00217   }
    00218   m_bInit = false;
    00219 #endif
    00220 }
    00221
    00222
    00223 bool KSSL::reInitialize() {
    00224   close();
    00225   return initialize();
    00226 }
    00227
    00228 // get the callback file - it's hidden away in here
    00229 #include "ksslcallback.c"
    00230
    00231
    00232 bool KSSL::setVerificationLogic() {
    00233 #if 0
    00234 #ifdef KSSL_HAVE_SSL
    00235   //  SSL_set_verify_result(d->m_ssl, X509_V_OK);
    00236   //  SSL_CTX_set_verify(d->m_ctx, SSL_VERIFY_PEER, X509Callback);
    00237 #endif
    00238 #endif
    00239   return true;
    00240 }
    00241
    00242
    00243 int KSSL::accept(int sock) {
    00244 #ifdef KSSL_HAVE_SSL
    00245   // kdDebug(7029) << "KSSL accept" << endl;
    00246   int rc;
    00247   if (!m_bInit) return -1;
    00248   d->m_ssl = d->kossl->SSL_new(d->m_ctx);
    00249   if (!d->m_ssl) return -1;
    00250
    00251 /*
    00252   if (!setVerificationLogic())
    00253     return -1;
    00254 */
    00255
    00256   if (!d->lastInitTLS)
    00257     d->kossl->SSL_set_options(d->m_ssl, SSL_OP_NO_TLSv1);
    00258   d->kossl->SSL_set_options(d->m_ssl, SSL_OP_ALL);
    00259
    00260   rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
    00261   if (rc == 0) return rc;
    00262
    00263   rc = d->kossl->SSL_accept(d->m_ssl);
    00264   if (rc == 1) {
    00265     setConnectionInfo();
    00266     setPeerInfo();
    00267     kdDebug(7029) << "KSSL connected OK" << endl;
    00268   } else {
    00269     kdDebug(7029) << "KSSL accept failed - rc = " << rc << endl;
    00270     kdDebug(7029) << "                      ERROR = " << d->kossl->SSL_get_error(d->m_ssl, rc) << endl;
    00271     return -1;
    00272   }
    00273   return rc;
    00274 #else
    00275   return -1;
    00276 #endif
    00277 }
    00278
    00279
    00280 int KSSL::connect(int sock) {
    00281 #ifdef KSSL_HAVE_SSL
    00282   // kdDebug(7029) << "KSSL connect" << endl;
    00283   int rc;
    00284   if (!m_bInit) return -1;
    00285   d->m_ssl = d->kossl->SSL_new(d->m_ctx);
    00286   if (!d->m_ssl) return -1;
    00287
    00288 /*
    00289   if (!setVerificationLogic())
    00290     return -1;
    00291 */
    00292
    00293   if (!d->lastInitTLS)
    00294     d->kossl->SSL_set_options(d->m_ssl, SSL_OP_NO_TLSv1);
    00295   d->kossl->SSL_set_options(d->m_ssl, SSL_OP_ALL);
    00296
    00297   rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
    00298   if (rc == 0) return rc;
    00299
    00300   rc = d->kossl->SSL_connect(d->m_ssl);
    00301   if (rc == 1) {
    00302     setConnectionInfo();
    00303     setPeerInfo();
    00304     kdDebug(7029) << "KSSL connected OK" << endl;
    00305   } else {
    00306     kdDebug(7029) << "KSSL connect failed - rc = " << rc << endl;
    00307     kdDebug(7029) << "                      ERROR = " << d->kossl->SSL_get_error(d->m_ssl, rc) << endl;
    00308     d->kossl->ERR_print_errors_fp(stderr);
    00309     return -1;
    00310   }
    00311   return rc;
    00312 #else
    00313   return -1;
    00314 #endif
    00315 }
    00316
    00317
    00318 int KSSL::pending() {
    00319 #ifdef KSSL_HAVE_SSL
    00320   if (!m_bInit) return -1;
    00321   return d->kossl->SSL_pending(d->m_ssl);
    00322 #else
    00323   return -1;
    00324 #endif
    00325 }
    00326
    00327
    00328 int KSSL::peek(void *buf, int len) {
    00329 #ifdef KSSL_HAVE_SSL
    00330   if (!m_bInit) return -1;
    00331   return d->kossl->SSL_peek(d->m_ssl, buf, len);
    00332 #else
    00333   return -1;
    00334 #endif
    00335 }
    00336
    00337
    00338 int KSSL::read(void *buf, int len) {
    00339 #ifdef KSSL_HAVE_SSL
    00340   if (!m_bInit) return -1;
    00341
    00342   int rc = d->kossl->SSL_read(d->m_ssl, (char *)buf, len);
    00343   if (rc <= 0) {
    00344     int err = d->kossl->SSL_get_error(d->m_ssl, rc);
    00345     kdDebug(7029) << "SSL READ ERROR: " << err << endl;
    00346     if (err != SSL_ERROR_NONE && err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL)
    00347       rc = -1;      // OpenSSL returns 0 on error too
    00348 //    else if (err == SSL_ERROR_ZERO_RETURN)
    00349 //      rc = 0;
    00350   }
    00351   return rc;
    00352 #else
    00353   return -1;
    00354 #endif
    00355 }
    00356
    00357
    00358 int KSSL::write(const void *buf, int len) {
    00359 #ifdef KSSL_HAVE_SSL
    00360   if (!m_bInit) return -1;
    00361
    00362   int rc = d->kossl->SSL_write(d->m_ssl, (const char *)buf, len);
    00363   if (rc <= 0) {      // OpenSSL returns 0 on error too
    00364     int err = d->kossl->SSL_get_error(d->m_ssl, rc);
    00365     kdDebug(7029) << "SSL WRITE ERROR: " << err << endl;
    00366     if (err != SSL_ERROR_NONE && err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL)
    00367       rc = -1;
    00368   }
    00369
    00370   return rc;
    00371 #else
    00372   return -1;
    00373 #endif
    00374 }
    00375
    00376
    00377 bool KSSL::reconfig() {
    00378   return reInitialize();
    00379 }
    00380
    00381
    00382 void KSSL::setAutoReconfig(bool ar) {
    00383   m_bAutoReconfig = ar;
    00384 }
    00385
    00386
    00387 bool KSSL::setSettings(KSSLSettings *settings) {
    00388   delete m_cfg;
    00389   m_cfg = settings;
    00390   return reconfig();
    00391 }
    00392
    00393
    00394 #ifdef KSSL_HAVE_SSL
    00395 bool KSSL::m_bSSLWorks = true;
    00396 #else
    00397 bool KSSL::m_bSSLWorks = false;
    00398 #endif
    00399
    00400 bool KSSL::doesSSLWork() {
    00401   return m_bSSLWorks;
    00402 }
    00403
    00404
    00405 void KSSL::setConnectionInfo() {
    00406 #ifdef KSSL_HAVE_SSL
    00407   SSL_CIPHER *sc;
    00408   char buf[1024];   // WARNING - is this making us non-thread-safe?  FIXME
    00409
    00410   buf[0] = 0;  // for safety.
    00411   sc = d->kossl->SSL_get_current_cipher(d->m_ssl);
    00412   if (!sc) {
    00413    kdDebug(7029) << "KSSL get current cipher failed - we're probably gonna crash!" << endl;
    00414   return;
    00415   }
    00416   // set the number of bits, bits used
    00417   m_ci.m_iCipherUsedBits = d->kossl->SSL_CIPHER_get_bits(sc, &(m_ci.m_iCipherBits));
    00418   // set the cipher version
    00419   m_ci.m_cipherVersion = d->kossl->SSL_CIPHER_get_version(sc);
    00420   // set the cipher name
    00421   m_ci.m_cipherName = d->kossl->SSL_CIPHER_get_name(sc);
    00422   // set the cipher description
    00423   m_ci.m_cipherDescription = d->kossl->SSL_CIPHER_description(sc, buf, 1023);
    00424
    00425 #endif
    00426 }
    00427
    00428
    00429 void KSSL::setPeerInfo() {
    00430 #ifdef KSSL_HAVE_SSL
    00431   m_pi.setPeerHost(d->proxyPeer);
    00432   m_pi.m_cert.setCert(d->kossl->SSL_get_peer_certificate(d->m_ssl));
    00433   STACK_OF(X509) *xs = d->kossl->SSL_get_peer_cert_chain(d->m_ssl);
    00434   if (xs) xs = sk_X509_dup(xs);   // Leak?
    00435   m_pi.m_cert.setChain((void *)xs);
    00436 #endif
    00437 }
    00438
    00439
    00440 KSSLConnectionInfo& KSSL::connectionInfo() {
    00441   return m_ci;
    00442 }
    00443
    00444
    00445 void KSSL::setPeerHost(QString realHost) {
    00446    d->proxyPeer = realHost;
    00447 }
    00448
    00449 // deprecated
    00450 void KSSL::setProxyUse(bool, QString, int, QString) {
    00451 }
    00452
    00453
    00454 KSSLPeerInfo& KSSL::peerInfo() {
    00455   return m_pi;
    00456 }
    00457
    00458
    00459 bool KSSL::setClientCertificate(KSSLPKCS12 *pkcs) {
    00460 #ifdef KSSL_HAVE_SSL
    00461         if (!pkcs || !pkcs->getCertificate()) return false;
    00462
    00463   int rc;
    00464   X509 *x = pkcs->getCertificate()->getCert();
    00465   EVP_PKEY *k = pkcs->getPrivateKey();
    00466
    00467   if (!x || !k) return false;
    00468
    00469   if (!pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())
    00470           return false;
    00471
    00472   rc = d->kossl->SSL_CTX_use_certificate(d->m_ctx, x);
    00473   if (rc <= 0) {
    00474     kdDebug(7029) << "KSSL - SSL_CTX_use_certificate failed.  rc = " << rc << endl;
    00475     return false;
    00476   }
    00477
    00478   rc = d->kossl->SSL_CTX_use_PrivateKey(d->m_ctx, k);
    00479   if (rc <= 0) {
    00480     kdDebug(7029) << "KSSL - SSL_CTX_use_PrivateKey failed.  rc = " << rc << endl;
    00481     return false;
    00482   }
    00483
    00484   return true;
    00485 #else
    00486   return false;
    00487 #endif
    00488 }
    00489
    00490 #undef sk_dup
    00491

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:21 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001