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