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