kio
kssl.cc
Go to the documentation of this file.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 m_pi.reset();
00142
00143 d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
00144 if (d->m_ctx == 0L) {
00145 return false;
00146 }
00147
00148
00149 QString clist = m_cfg->getCipherList();
00150
00151 if (!clist.isEmpty())
00152 d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
00153
00154 m_bInit = true;
00155 return true;
00156 #else
00157 return false;
00158 #endif
00159 }
00160
00161
00162 bool KSSL::initialize() {
00163 #ifdef KSSL_HAVE_SSL
00164 kdDebug(7029) << "KSSL initialize" << endl;
00165 if (m_bInit)
00166 return false;
00167
00168 if (m_bAutoReconfig)
00169 m_cfg->load();
00170
00171 seedWithEGD();
00172
00173 d->lastInitTLS = false;
00174
00175 m_pi.reset();
00176
00177 if (!m_cfg->tlsv1() && !m_cfg->sslv3() && m_cfg->sslv2())
00178 d->m_meth = d->kossl->SSLv2_client_method();
00179 else if (m_cfg->tlsv1() && !m_cfg->sslv3() && !m_cfg->sslv2())
00180 d->m_meth = d->kossl->TLSv1_client_method();
00181 else if (!m_cfg->tlsv1() && m_cfg->sslv3() && !m_cfg->sslv2())
00182 d->m_meth = d->kossl->SSLv3_client_method();
00183 else d->m_meth = d->kossl->SSLv23_client_method();
00184
00185
00186
00187
00188
00189
00190
00191 d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
00192 if (d->m_ctx == 0L) {
00193 return false;
00194 }
00195
00196
00197 QString clist = m_cfg->getCipherList();
00198 kdDebug(7029) << "Cipher list: " << clist << endl;
00199 if (!clist.isEmpty())
00200 d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
00201
00202 m_bInit = true;
00203 return true;
00204 #else
00205 return false;
00206 #endif
00207 }
00208
00209
00210 bool KSSL::setSession(const KSSLSession *session) {
00211 #ifdef KSSL_HAVE_SSL
00212 if (!session) {
00213 delete d->session;
00214 d->session = 0L;
00215 return true;
00216 }
00217
00218
00219 static_cast<SSL_SESSION*>(session->_session)->references++;
00220
00221 d->session = new KSSLSession;
00222 d->session->_session = session->_session;
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 (static_cast<SSL_SESSION*>(d->session->_session)->sess_cert == 0)
00288 {
00289 kdDebug(7029) << "Can't reuse session, no certificate." << endl;
00290 delete d->session;
00291 d->session = 0;
00292 } else if (1 == d->kossl->SSL_set_session(d->m_ssl,
00293 static_cast<SSL_SESSION*>(d->session->_session))) {
00294 kdDebug(7029) << "Session ID is being reused." << endl;
00295 } else {
00296 kdDebug(7029) << "Error attempting to reuse session." << endl;
00297 delete d->session;
00298 d->session = 0;
00299 }
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 int off = SSL_OP_ALL;
00312 if (!d->lastInitTLS && !m_cfg->tlsv1())
00313 off |= SSL_OP_NO_TLSv1;
00314 if (!m_cfg->sslv3())
00315 off |= SSL_OP_NO_SSLv3;
00316 if (!m_cfg->sslv2())
00317 off |= SSL_OP_NO_SSLv2;
00318
00319 d->kossl->SSL_set_options(d->m_ssl, off);
00320
00321 rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
00322 if (rc == 0) {
00323 d->kossl->SSL_shutdown(d->m_ssl);
00324 d->kossl->SSL_free(d->m_ssl);
00325 d->m_ssl = 0;
00326 return rc;
00327 }
00328
00329 rc = d->kossl->SSL_accept(d->m_ssl);
00330 if (rc == 1) {
00331 setConnectionInfo();
00332 setPeerInfo();
00333 kdDebug(7029) << "KSSL connected OK" << endl;
00334 } else {
00335 kdDebug(7029) << "KSSL accept failed - rc = " << rc << endl;
00336 kdDebug(7029) << " ERROR = "
00337 << d->kossl->SSL_get_error(d->m_ssl, rc) << endl;
00338 d->kossl->SSL_shutdown(d->m_ssl);
00339 d->kossl->SSL_free(d->m_ssl);
00340 d->m_ssl = 0;
00341 return -1;
00342 }
00343
00344 if (!d->kossl->SSL_session_reused(d->m_ssl)) {
00345 if (d->session) {
00346 kdDebug(7029) << "Session reuse failed. New session used instead." << endl;
00347 delete d->session;
00348 d->session = 0L;
00349 }
00350 }
00351
00352 if (!d->session) {
00353 SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
00354 if (sess) {
00355 d->session = new KSSLSession;
00356 d->session->_session = sess;
00357 }
00358 }
00359
00360 return rc;
00361 #else
00362 return -1;
00363 #endif
00364 }
00365
00366
00367 int KSSL::connect(int sock) {
00368 #ifdef KSSL_HAVE_SSL
00369
00370 int rc;
00371 if (!m_bInit)
00372 return -1;
00373 d->m_ssl = d->kossl->SSL_new(d->m_ctx);
00374 if (!d->m_ssl)
00375 return -1;
00376
00377 if (d->session) {
00378 if (static_cast<SSL_SESSION*>(d->session->_session)->sess_cert == 0)
00379 {
00380 kdDebug(7029) << "Can't reuse session, no certificate." << endl;
00381 delete d->session;
00382 d->session = 0;
00383 } else if (1 == d->kossl->SSL_set_session(d->m_ssl,
00384 static_cast<SSL_SESSION*>(d->session->_session))) {
00385 kdDebug(7029) << "Session ID is being reused." << endl;
00386 } else {
00387 kdDebug(7029) << "Error attempting to reuse session." << endl;
00388 delete d->session;
00389 d->session = 0;
00390 }
00391 }
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 int off = SSL_OP_ALL;
00403 if (!d->lastInitTLS && !m_cfg->tlsv1())
00404 off |= SSL_OP_NO_TLSv1;
00405 if (!m_cfg->sslv3())
00406 off |= SSL_OP_NO_SSLv3;
00407 if (!m_cfg->sslv2())
00408 off |= SSL_OP_NO_SSLv2;
00409
00410 d->kossl->SSL_set_options(d->m_ssl, off);
00411
00412 rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
00413 if (rc == 0) {
00414 d->kossl->SSL_shutdown(d->m_ssl);
00415 d->kossl->SSL_free(d->m_ssl);
00416 d->m_ssl = 0;
00417 return rc;
00418 }
00419
00420 connect_again:
00421 rc = d->kossl->SSL_connect(d->m_ssl);
00422 if (rc == 1) {
00423 setConnectionInfo();
00424 setPeerInfo();
00425 kdDebug(7029) << "KSSL connected OK" << endl;
00426 } else {
00427 int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00428 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
00429
00430 goto connect_again;
00431 } else {
00432 kdDebug(7029) << "KSSL connect failed - rc = "
00433 << rc << endl;
00434 kdDebug(7029) << " ERROR = "
00435 << err << endl;
00436 d->kossl->ERR_print_errors_fp(stderr);
00437 d->kossl->SSL_shutdown(d->m_ssl);
00438 d->kossl->SSL_free(d->m_ssl);
00439 d->m_ssl = 0;
00440 return -1;
00441 }
00442 }
00443
00444 if (!d->kossl->SSL_session_reused(d->m_ssl)) {
00445 if (d->session) {
00446 kdDebug(7029) << "Session reuse failed. New session used instead." << endl;
00447 delete d->session;
00448 d->session = 0L;
00449 }
00450 }
00451
00452 if (!d->session) {
00453 SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
00454 if (sess) {
00455 d->session = new KSSLSession;
00456 d->session->_session = sess;
00457 }
00458 }
00459
00460 return rc;
00461 #else
00462 return -1;
00463 #endif
00464 }
00465
00466
00467 int KSSL::pending() {
00468 #ifdef KSSL_HAVE_SSL
00469 if (!m_bInit)
00470 return -1;
00471 return d->kossl->SSL_pending(d->m_ssl);
00472 #else
00473 return -1;
00474 #endif
00475 }
00476
00477
00478 int KSSL::peek(void *buf, int len) {
00479 #ifdef KSSL_HAVE_SSL
00480 if (!m_bInit)
00481 return -1;
00482
00483 return d->kossl->SSL_peek(d->m_ssl, buf, len);
00484 #else
00485 return -1;
00486 #endif
00487 }
00488
00489
00490 int KSSL::read(void *buf, int len) {
00491 #ifdef KSSL_HAVE_SSL
00492 int rc = 0;
00493 int maxIters = 10;
00494
00495 if (!m_bInit)
00496 return -1;
00497
00498 read_again:
00499 rc = d->kossl->SSL_read(d->m_ssl, (char *)buf, len);
00500 if (rc <= 0) {
00501 int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00502
00503 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
00504 kdDebug(7029) << "SSL read() returning 0: " << err << endl;
00505 if (maxIters-- > 0) {
00506 ::usleep(20000);
00507 goto read_again;
00508 }
00509 return 0;
00510 }
00511
00512 kdDebug(7029) << "SSL READ ERROR: " << err << endl;
00513 if (err != SSL_ERROR_NONE &&
00514 err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL) {
00515 rc = -1;
00516 d->kossl->ERR_print_errors_fp(stderr);
00517 }
00518
00519
00520
00521 }
00522 return rc;
00523 #else
00524 return -1;
00525 #endif
00526 }
00527
00528
00529 int KSSL::write(const void *buf, int len) {
00530 #ifdef KSSL_HAVE_SSL
00531 if (!m_bInit)
00532 return -1;
00533
00534 write_again:
00535 int rc = d->kossl->SSL_write(d->m_ssl, (const char *)buf, len);
00536 if (rc <= 0) {
00537 int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00538
00539 if (err == SSL_ERROR_WANT_WRITE) {
00540 ::usleep(20000);
00541 goto write_again;
00542 }
00543
00544 kdDebug(7029) << "SSL WRITE ERROR: " << err << endl;
00545 if (err != SSL_ERROR_NONE &&
00546 err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL)
00547 rc = -1;
00548 }
00549
00550 return rc;
00551 #else
00552 return -1;
00553 #endif
00554 }
00555
00556
00557 bool KSSL::reconfig() {
00558 return reInitialize();
00559 }
00560
00561
00562 void KSSL::setAutoReconfig(bool ar) {
00563 m_bAutoReconfig = ar;
00564 }
00565
00566
00567 bool KSSL::setSettings(KSSLSettings *settings) {
00568 delete m_cfg;
00569 m_cfg = settings;
00570 return reconfig();
00571 }
00572
00573
00574 #ifdef KSSL_HAVE_SSL
00575 bool KSSL::m_bSSLWorks = true;
00576 #else
00577 bool KSSL::m_bSSLWorks = false;
00578 #endif
00579
00580 bool KSSL::doesSSLWork() {
00581 return m_bSSLWorks;
00582 }
00583
00584
00585 void KSSL::setConnectionInfo() {
00586 #ifdef KSSL_HAVE_SSL
00587 SSL_CIPHER *sc;
00588 char buf[1024];
00589
00590 buf[0] = 0;
00591 sc = d->kossl->SSL_get_current_cipher(d->m_ssl);
00592 if (!sc) {
00593 kdDebug(7029) << "KSSL get current cipher failed - we're probably gonna crash!" << endl;
00594 return;
00595 }
00596
00597
00598 m_ci.m_iCipherUsedBits = d->kossl->SSL_CIPHER_get_bits(sc, &(m_ci.m_iCipherBits));
00599
00600 m_ci.m_cipherVersion = d->kossl->SSL_CIPHER_get_version(sc);
00601
00602 m_ci.m_cipherName = d->kossl->SSL_CIPHER_get_name(sc);
00603
00604 m_ci.m_cipherDescription = d->kossl->SSL_CIPHER_description(sc, buf, 1023);
00605
00606 #endif
00607 }
00608
00609
00610 void KSSL::setPeerInfo() {
00611 #ifdef KSSL_HAVE_SSL
00612 m_pi.setPeerHost(d->proxyPeer);
00613 m_pi.m_cert.setCert(d->kossl->SSL_get_peer_certificate(d->m_ssl));
00614 STACK_OF(X509) *xs = d->kossl->SSL_get_peer_cert_chain(d->m_ssl);
00615 if (xs)
00616 xs = sk_X509_dup(xs);
00617 m_pi.m_cert.setChain((void *)xs);
00618 #endif
00619 }
00620
00621
00622 KSSLConnectionInfo& KSSL::connectionInfo() {
00623 return m_ci;
00624 }
00625
00626
00627
00628 void KSSL::setPeerHost(QString realHost) {
00629 d->proxyPeer = realHost;
00630 }
00631
00632
00633 void KSSL::setProxyUse(bool, QString, int, QString) {
00634 }
00635
00636
00637 KSSLPeerInfo& KSSL::peerInfo() {
00638 return m_pi;
00639 }
00640
00641
00642 bool KSSL::setClientCertificate(KSSLPKCS12 *pkcs) {
00643 #ifdef KSSL_HAVE_SSL
00644 if (!pkcs || !pkcs->getCertificate())
00645 return false;
00646
00647 int rc;
00648 X509 *x = pkcs->getCertificate()->getCert();
00649 EVP_PKEY *k = pkcs->getPrivateKey();
00650
00651 if (!x || !k) return false;
00652
00653 if (!pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())
00654 return false;
00655
00656 rc = d->kossl->SSL_CTX_use_certificate(d->m_ctx, x);
00657 if (rc <= 0) {
00658 kdDebug(7029) << "KSSL - SSL_CTX_use_certificate failed. rc = " << rc << endl;
00659 return false;
00660 }
00661
00662 rc = d->kossl->SSL_CTX_use_PrivateKey(d->m_ctx, k);
00663 if (rc <= 0) {
00664 kdDebug(7029) << "KSSL - SSL_CTX_use_PrivateKey failed. rc = " << rc << endl;
00665 return false;
00666 }
00667
00668 return true;
00669 #else
00670 return false;
00671 #endif
00672 }
00673
00674 #undef sk_dup
00675
00676 const KSSLSession* KSSL::session() const {
00677 return d->session;
00678 }
00679
00680 bool KSSL::reusingSession() const {
00681 #ifdef KSSL_HAVE_SSL
00682 return (d->m_ssl && d->kossl->SSL_session_reused(d->m_ssl));
00683 #else
00684 return false;
00685 #endif
00686 }
00687
00688