kssl.cc
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024
00025
00026
00027 #ifdef KSSL_HAVE_SSL
00028 #include <unistd.h>
00029 #include <netinet/in.h>
00030 #include <sys/socket.h>
00031 #define crypt _openssl_crypt
00032 #include <openssl/ssl.h>
00033 #include <openssl/x509.h>
00034 #include <openssl/x509v3.h>
00035 #include <openssl/pem.h>
00036 #include <openssl/rand.h>
00037 #undef crypt
00038 #endif
00039
00040 #include "kssl.h"
00041
00042 #include <kdebug.h>
00043 #include <kstandarddirs.h>
00044 #include <ksock.h>
00045 #include <ksockaddr.h>
00046
00047 #include <kopenssl.h>
00048 #include <ksslx509v3.h>
00049 #include <ksslpkcs12.h>
00050 #include <ksslsession.h>
00051 #include <klocale.h>
00052 #include <ksocks.h>
00053
00054 #define sk_dup d->kossl->sk_dup
00055
00056 class KSSLPrivate {
00057 public:
00058 KSSLPrivate() {
00059 lastInitTLS = false;
00060 kossl = KOpenSSLProxy::self();
00061 session = 0L;
00062 }
00063
00064 ~KSSLPrivate() {
00065 delete session;
00066 session = 0L;
00067 }
00068
00069 bool lastInitTLS;
00070 KSSLCertificate::KSSLValidation m_cert_vfy_res;
00071 QString proxyPeer;
00072
00073 #ifdef KSSL_HAVE_SSL
00074 SSL *m_ssl;
00075 SSL_CTX *m_ctx;
00076 SSL_METHOD *m_meth;
00077 #endif
00078 KSSLSession *session;
00079 KOSSL *kossl;
00080 };
00081
00082
00083 KSSL::KSSL(bool init) {
00084 d = new KSSLPrivate;
00085 m_bInit = false;
00086 m_bAutoReconfig = true;
00087 m_cfg = new KSSLSettings();
00088 #ifdef KSSL_HAVE_SSL
00089 d->m_ssl = 0L;
00090 #endif
00091
00092 if (init)
00093 initialize();
00094 }
00095
00096
00097 KSSL::~KSSL() {
00098 close();
00099 delete m_cfg;
00100 delete d;
00101 }
00102
00103
00104 int KSSL::seedWithEGD() {
00105 int rc = 0;
00106 #ifdef KSSL_HAVE_SSL
00107 if (m_cfg->useEGD() && !m_cfg->getEGDPath().isEmpty()) {
00108 rc = d->kossl->RAND_egd(m_cfg->getEGDPath().latin1());
00109 if (rc < 0)
00110 kdDebug(7029) << "KSSL: Error seeding PRNG with the EGD." << endl;
00111 else kdDebug(7029) << "KSSL: PRNG was seeded with " << rc
00112 << " bytes from the EGD." << endl;
00113 } else if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
00114 rc = d->kossl->RAND_load_file(m_cfg->getEGDPath().latin1(), -1);
00115 if (rc < 0)
00116 kdDebug(7029) << "KSSL: Error seeding PRNG with the entropy file." << endl;
00117 else kdDebug(7029) << "KSSL: PRNG was seeded with " << rc
00118 << " bytes from the entropy file." << endl;
00119 }
00120 #endif
00121 return rc;
00122 }
00123
00124
00125 bool KSSL::TLSInit() {
00126 #ifdef KSSL_HAVE_SSL
00127
00128 if (m_bInit)
00129 return false;
00130
00131 if (m_bAutoReconfig)
00132 m_cfg->load();
00133
00134 if (!m_cfg->tlsv1())
00135 return false;
00136
00137 seedWithEGD();
00138 d->m_meth = d->kossl->TLSv1_client_method();
00139 d->lastInitTLS = true;
00140
00141 d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
00142 if (d->m_ctx == 0L) {
00143 return false;
00144 }
00145
00146
00147 QString clist = m_cfg->getCipherList();
00148
00149 if (!clist.isEmpty())
00150 d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
00151
00152 m_bInit = true;
00153 return true;
00154 #else
00155 return false;
00156 #endif
00157 }
00158
00159
00160 bool KSSL::initialize() {
00161 #ifdef KSSL_HAVE_SSL
00162 kdDebug(7029) << "KSSL initialize" << endl;
00163 if (m_bInit)
00164 return false;
00165
00166 if (m_bAutoReconfig)
00167 m_cfg->load();
00168
00169 seedWithEGD();
00170
00171 d->lastInitTLS = false;
00172
00173 m_pi.reset();
00174
00175 if (m_cfg->sslv2() && !m_cfg->sslv3())
00176 d->m_meth = d->kossl->SSLv2_client_method();
00177 else if (m_cfg->sslv3() && !m_cfg->sslv2())
00178 d->m_meth = d->kossl->SSLv3_client_method();
00179 else d->m_meth = d->kossl->SSLv23_client_method();
00180
00181
00182
00183
00184
00185
00186
00187 d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
00188 if (d->m_ctx == 0L) {
00189 return false;
00190 }
00191
00192
00193 QString clist = m_cfg->getCipherList();
00194 kdDebug(7029) << "Cipher list: " << clist << endl;
00195 if (!clist.isEmpty())
00196 d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
00197
00198 m_bInit = true;
00199 return true;
00200 #else
00201 return false;
00202 #endif
00203 }
00204
00205
00206 bool KSSL::setSession(const KSSLSession *session) {
00207 #ifdef KSSL_HAVE_SSL
00208 if (!session) {
00209 delete d->session;
00210 d->session = 0L;
00211 return true;
00212 }
00213
00214
00215 static_cast<SSL_SESSION*>(session->_session)->references++;
00216
00217 d->session = new KSSLSession;
00218 d->session->_session = session->_session;
00219
00220 return true;
00221 #else
00222 return false;
00223 #endif
00224 }
00225
00226
00227 void KSSL::close() {
00228 #ifdef KSSL_HAVE_SSL
00229
00230 if (!m_bInit)
00231 return;
00232
00233 if (d->session) {
00234 delete d->session;
00235 d->session = 0L;
00236 }
00237
00238 if (d->m_ssl) {
00239 d->kossl->SSL_shutdown(d->m_ssl);
00240 d->kossl->SSL_free(d->m_ssl);
00241 d->m_ssl = 0L;
00242 }
00243
00244 d->kossl->SSL_CTX_free(d->m_ctx);
00245 if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
00246 d->kossl->RAND_write_file(m_cfg->getEGDPath().latin1());
00247 }
00248
00249 m_bInit = false;
00250 #endif
00251 }
00252
00253
00254 bool KSSL::reInitialize() {
00255 close();
00256 return initialize();
00257 }
00258
00259
00260
00261
00262
00263 bool KSSL::setVerificationLogic() {
00264 #if 0
00265 #ifdef KSSL_HAVE_SSL
00266
00267
00268 #endif
00269 #endif
00270 return true;
00271 }
00272
00273
00274 int KSSL::accept(int sock) {
00275 #ifdef KSSL_HAVE_SSL
00276
00277 int rc;
00278 if (!m_bInit)
00279 return -1;
00280 d->m_ssl = d->kossl->SSL_new(d->m_ctx);
00281 if (!d->m_ssl)
00282 return -1;
00283
00284 if (d->session) {
00285 if (1 == d->kossl->SSL_set_session(d->m_ssl,
00286 static_cast<SSL_SESSION*>(d->session->_session))) {
00287 kdDebug(7029) << "Session ID is being reused." << endl;
00288 } else {
00289 kdDebug(7029) << "Error attempting to reuse session." << endl;
00290 delete d->session;
00291 d->session = 0;
00292 }
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 if (!d->lastInitTLS)
00305 d->kossl->SSL_set_options(d->m_ssl, SSL_OP_NO_TLSv1);
00306
00307 d->kossl->SSL_set_options(d->m_ssl, SSL_OP_ALL);
00308
00309 rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
00310 if (rc == 0) {
00311 d->kossl->SSL_shutdown(d->m_ssl);
00312 d->kossl->SSL_free(d->m_ssl);
00313 d->m_ssl = 0;
00314 return rc;
00315 }
00316
00317 rc = d->kossl->SSL_accept(d->m_ssl);
00318 if (rc == 1) {
00319 setConnectionInfo();
00320 setPeerInfo();
00321 kdDebug(7029) << "KSSL connected OK" << endl;
00322 } else {
00323 kdDebug(7029) << "KSSL accept failed - rc = " << rc << endl;
00324 kdDebug(7029) << " ERROR = "
00325 << d->kossl->SSL_get_error(d->m_ssl, rc) << endl;
00326 d->kossl->SSL_shutdown(d->m_ssl);
00327 d->kossl->SSL_free(d->m_ssl);
00328 d->m_ssl = 0;
00329 return -1;
00330 }
00331
00332 if (!d->kossl->SSL_session_reused(d->m_ssl)) {
00333 if (d->session) {
00334 kdDebug(7029) << "Session reuse failed. New session used instead." << endl;
00335 delete d->session;
00336 d->session = 0L;
00337 }
00338 }
00339
00340 if (!d->session) {
00341 SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
00342 if (sess) {
00343 d->session = new KSSLSession;
00344 d->session->_session = sess;
00345 }
00346 }
00347
00348 return rc;
00349 #else
00350 return -1;
00351 #endif
00352 }
00353
00354
00355 int KSSL::connect(int sock) {
00356 #ifdef KSSL_HAVE_SSL
00357
00358 int rc;
00359 if (!m_bInit)
00360 return -1;
00361 d->m_ssl = d->kossl->SSL_new(d->m_ctx);
00362 if (!d->m_ssl)
00363 return -1;
00364
00365 if (d->session) {
00366 if (1 == d->kossl->SSL_set_session(d->m_ssl,
00367 static_cast<SSL_SESSION*>(d->session->_session))) {
00368 kdDebug(7029) << "Session ID is being reused." << endl;
00369 } else {
00370 kdDebug(7029) << "Error attempting to reuse session." << endl;
00371 delete d->session;
00372 d->session = 0;
00373 }
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 if (!d->lastInitTLS)
00386 d->kossl->SSL_set_options(d->m_ssl, SSL_OP_NO_TLSv1);
00387
00388 d->kossl->SSL_set_options(d->m_ssl, SSL_OP_ALL);
00389
00390 rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
00391 if (rc == 0) {
00392 d->kossl->SSL_shutdown(d->m_ssl);
00393 d->kossl->SSL_free(d->m_ssl);
00394 d->m_ssl = 0;
00395 return rc;
00396 }
00397
00398 connect_again:
00399 rc = d->kossl->SSL_connect(d->m_ssl);
00400 if (rc == 1) {
00401 setConnectionInfo();
00402 setPeerInfo();
00403 kdDebug(7029) << "KSSL connected OK" << endl;
00404 } else {
00405 int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00406 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
00407
00408 goto connect_again;
00409 } else {
00410 kdDebug(7029) << "KSSL connect failed - rc = "
00411 << rc << endl;
00412 kdDebug(7029) << " ERROR = "
00413 << err << endl;
00414 d->kossl->ERR_print_errors_fp(stderr);
00415 d->kossl->SSL_shutdown(d->m_ssl);
00416 d->kossl->SSL_free(d->m_ssl);
00417 d->m_ssl = 0;
00418 return -1;
00419 }
00420 }
00421
00422 if (!d->kossl->SSL_session_reused(d->m_ssl)) {
00423 if (d->session) {
00424 kdDebug(7029) << "Session reuse failed. New session used instead." << endl;
00425 delete d->session;
00426 d->session = 0L;
00427 }
00428 }
00429
00430 if (!d->session) {
00431 SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
00432 if (sess) {
00433 d->session = new KSSLSession;
00434 d->session->_session = sess;
00435 }
00436 }
00437
00438 return rc;
00439 #else
00440 return -1;
00441 #endif
00442 }
00443
00444
00445 int KSSL::pending() {
00446 #ifdef KSSL_HAVE_SSL
00447 if (!m_bInit)
00448 return -1;
00449 return d->kossl->SSL_pending(d->m_ssl);
00450 #else
00451 return -1;
00452 #endif
00453 }
00454
00455
00456 int KSSL::peek(void *buf, int len) {
00457 #ifdef KSSL_HAVE_SSL
00458 if (!m_bInit)
00459 return -1;
00460 return d->kossl->SSL_peek(d->m_ssl, buf, len);
00461 #else
00462 return -1;
00463 #endif
00464 }
00465
00466
00467 int KSSL::read(void *buf, int len) {
00468 #ifdef KSSL_HAVE_SSL
00469 int rc = 0;
00470
00471 if (!m_bInit)
00472 return -1;
00473
00474 rc = d->kossl->SSL_read(d->m_ssl, (char *)buf, len);
00475 if (rc <= 0) {
00476 int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00477
00478 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
00479 return 0;
00480 }
00481
00482 kdDebug(7029) << "SSL READ ERROR: " << err << endl;
00483 if (err != SSL_ERROR_NONE &&
00484 err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL) {
00485 rc = -1;
00486 }
00487
00488
00489
00490 }
00491 return rc;
00492 #else
00493 return -1;
00494 #endif
00495 }
00496
00497
00498 int KSSL::write(const void *buf, int len) {
00499 #ifdef KSSL_HAVE_SSL
00500 if (!m_bInit)
00501 return -1;
00502
00503 int rc = d->kossl->SSL_write(d->m_ssl, (const char *)buf, len);
00504 if (rc <= 0) {
00505 int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00506
00507 if (err == SSL_ERROR_WANT_WRITE) {
00508 return 0;
00509 }
00510
00511 kdDebug(7029) << "SSL WRITE ERROR: " << err << endl;
00512 if (err != SSL_ERROR_NONE &&
00513 err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL)
00514 rc = -1;
00515 }
00516
00517 return rc;
00518 #else
00519 return -1;
00520 #endif
00521 }
00522
00523
00524 bool KSSL::reconfig() {
00525 return reInitialize();
00526 }
00527
00528
00529 void KSSL::setAutoReconfig(bool ar) {
00530 m_bAutoReconfig = ar;
00531 }
00532
00533
00534 bool KSSL::setSettings(KSSLSettings *settings) {
00535 delete m_cfg;
00536 m_cfg = settings;
00537 return reconfig();
00538 }
00539
00540
00541 #ifdef KSSL_HAVE_SSL
00542 bool KSSL::m_bSSLWorks = true;
00543 #else
00544 bool KSSL::m_bSSLWorks = false;
00545 #endif
00546
00547 bool KSSL::doesSSLWork() {
00548 return m_bSSLWorks;
00549 }
00550
00551
00552 void KSSL::setConnectionInfo() {
00553 #ifdef KSSL_HAVE_SSL
00554 SSL_CIPHER *sc;
00555 char buf[1024];
00556
00557 buf[0] = 0;
00558 sc = d->kossl->SSL_get_current_cipher(d->m_ssl);
00559 if (!sc) {
00560 kdDebug(7029) << "KSSL get current cipher failed - we're probably gonna crash!" << endl;
00561 return;
00562 }
00563
00564
00565 m_ci.m_iCipherUsedBits = d->kossl->SSL_CIPHER_get_bits(sc, &(m_ci.m_iCipherBits));
00566
00567 m_ci.m_cipherVersion = d->kossl->SSL_CIPHER_get_version(sc);
00568
00569 m_ci.m_cipherName = d->kossl->SSL_CIPHER_get_name(sc);
00570
00571 m_ci.m_cipherDescription = d->kossl->SSL_CIPHER_description(sc, buf, 1023);
00572
00573 #endif
00574 }
00575
00576
00577 void KSSL::setPeerInfo() {
00578 #ifdef KSSL_HAVE_SSL
00579 m_pi.setPeerHost(d->proxyPeer);
00580 m_pi.m_cert.setCert(d->kossl->SSL_get_peer_certificate(d->m_ssl));
00581 STACK_OF(X509) *xs = d->kossl->SSL_get_peer_cert_chain(d->m_ssl);
00582 if (xs)
00583 xs = sk_X509_dup(xs);
00584 m_pi.m_cert.setChain((void *)xs);
00585 #endif
00586 }
00587
00588
00589 KSSLConnectionInfo& KSSL::connectionInfo() {
00590 return m_ci;
00591 }
00592
00593
00594
00595 void KSSL::setPeerHost(QString realHost) {
00596 d->proxyPeer = realHost;
00597 }
00598
00599
00600 void KSSL::setProxyUse(bool, QString, int, QString) {
00601 }
00602
00603
00604 KSSLPeerInfo& KSSL::peerInfo() {
00605 return m_pi;
00606 }
00607
00608
00609 bool KSSL::setClientCertificate(KSSLPKCS12 *pkcs) {
00610 #ifdef KSSL_HAVE_SSL
00611 if (!pkcs || !pkcs->getCertificate())
00612 return false;
00613
00614 int rc;
00615 X509 *x = pkcs->getCertificate()->getCert();
00616 EVP_PKEY *k = pkcs->getPrivateKey();
00617
00618 if (!x || !k) return false;
00619
00620 if (!pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())
00621 return false;
00622
00623 rc = d->kossl->SSL_CTX_use_certificate(d->m_ctx, x);
00624 if (rc <= 0) {
00625 kdDebug(7029) << "KSSL - SSL_CTX_use_certificate failed. rc = " << rc << endl;
00626 return false;
00627 }
00628
00629 rc = d->kossl->SSL_CTX_use_PrivateKey(d->m_ctx, k);
00630 if (rc <= 0) {
00631 kdDebug(7029) << "KSSL - SSL_CTX_use_PrivateKey failed. rc = " << rc << endl;
00632 return false;
00633 }
00634
00635 return true;
00636 #else
00637 return false;
00638 #endif
00639 }
00640
00641 #undef sk_dup
00642
00643 const KSSLSession* KSSL::session() const {
00644 return d->session;
00645 }
00646
00647 bool KSSL::reusingSession() const {
00648 #ifdef KSSL_HAVE_SSL
00649 return (d->m_ssl && d->kossl->SSL_session_reused(d->m_ssl));
00650 #else
00651 return false;
00652 #endif
00653 }
00654
00655
This file is part of the documentation for kio Library Version 3.2.0.