kio Library API Documentation

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 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:31 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001