|
|
|
/* This file is part of the KDE project
|
|
|
|
*
|
|
|
|
* Copyright (C) 2000-2003 George Staikos <staikos@kde.org>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public License
|
|
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// this hack provided by Malte Starostik to avoid glibc/openssl bug
|
|
|
|
// on some systems
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#define crypt _openssl_crypt
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
#include <openssl/x509.h>
|
|
|
|
#include <openssl/x509v3.h>
|
|
|
|
#include <openssl/pem.h>
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
#undef crypt
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "kssl.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <ksock.h>
|
|
|
|
#include <ksockaddr.h>
|
|
|
|
|
|
|
|
#include <kopenssl.h>
|
|
|
|
#include <ksslx509v3.h>
|
|
|
|
#include <ksslpkcs12.h>
|
|
|
|
#include <ksslsession.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <ksocks.h>
|
|
|
|
|
|
|
|
|
|
|
|
class KSSLPrivate {
|
|
|
|
public:
|
|
|
|
KSSLPrivate() {
|
|
|
|
lastInitTLS = false;
|
|
|
|
kossl = KOpenSSLProxy::self();
|
|
|
|
session = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
~KSSLPrivate() {
|
|
|
|
delete session;
|
|
|
|
session = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool lastInitTLS;
|
|
|
|
KSSLCertificate::KSSLValidation m_cert_vfy_res;
|
|
|
|
TQString proxyPeer;
|
|
|
|
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
SSL *m_ssl;
|
|
|
|
SSL_CTX *m_ctx;
|
|
|
|
SSL_METHOD *m_meth;
|
|
|
|
#endif
|
|
|
|
KSSLSession *session;
|
|
|
|
KOSSL *kossl;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
KSSL::KSSL(bool init) {
|
|
|
|
d = new KSSLPrivate;
|
|
|
|
m_bInit = false;
|
|
|
|
m_bAutoReconfig = true;
|
|
|
|
m_cfg = new KSSLSettings();
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
d->m_ssl = 0L;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (init)
|
|
|
|
initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KSSL::~KSSL() {
|
|
|
|
close();
|
|
|
|
delete m_cfg;
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KSSL::seedWithEGD() {
|
|
|
|
int rc = 0;
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
if (m_cfg->useEGD() && !m_cfg->getEGDPath().isEmpty()) {
|
|
|
|
rc = d->kossl->RAND_egd(m_cfg->getEGDPath().latin1());
|
|
|
|
if (rc < 0)
|
|
|
|
kdDebug(7029) << "KSSL: Error seeding PRNG with the EGD." << endl;
|
|
|
|
else kdDebug(7029) << "KSSL: PRNG was seeded with " << rc
|
|
|
|
<< " bytes from the EGD." << endl;
|
|
|
|
} else if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
|
|
|
|
rc = d->kossl->RAND_load_file(m_cfg->getEGDPath().latin1(), -1);
|
|
|
|
if (rc < 0)
|
|
|
|
kdDebug(7029) << "KSSL: Error seeding PRNG with the entropy file." << endl;
|
|
|
|
else kdDebug(7029) << "KSSL: PRNG was seeded with " << rc
|
|
|
|
<< " bytes from the entropy file." << endl;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KSSL::TLSInit() {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
// kdDebug(7029) << "KSSL TLS initialize" << endl;
|
|
|
|
if (m_bInit)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (m_bAutoReconfig)
|
|
|
|
m_cfg->load();
|
|
|
|
|
|
|
|
if (!m_cfg->tlsv1())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
seedWithEGD();
|
|
|
|
d->m_meth = d->kossl->TLS_client_method();
|
|
|
|
d->lastInitTLS = true;
|
|
|
|
|
|
|
|
m_pi.reset();
|
|
|
|
|
|
|
|
d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
|
|
|
|
if (d->m_ctx == 0L) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set cipher list
|
|
|
|
TQString clist = m_cfg->getCipherList();
|
|
|
|
//kdDebug(7029) << "Cipher list: " << clist << endl;
|
|
|
|
if (!clist.isEmpty())
|
|
|
|
d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
|
|
|
|
|
|
|
|
m_bInit = true;
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KSSL::initialize() {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
kdDebug(7029) << "KSSL initialize" << endl;
|
|
|
|
if (m_bInit)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (m_bAutoReconfig)
|
|
|
|
m_cfg->load();
|
|
|
|
|
|
|
|
seedWithEGD();
|
|
|
|
// FIXME: we should be able to force SSL off entirely.
|
|
|
|
d->lastInitTLS = false;
|
|
|
|
|
|
|
|
m_pi.reset();
|
|
|
|
|
|
|
|
if (m_cfg->tlsv1() || (m_cfg->sslv3() && m_cfg->sslv2())) {
|
|
|
|
d->m_meth = d->kossl->TLS_client_method();
|
|
|
|
}
|
|
|
|
else if (m_cfg->sslv3()) {
|
|
|
|
d->m_meth = d->kossl->SSLv3_client_method();
|
|
|
|
}
|
|
|
|
else if (m_cfg->sslv2()) {
|
|
|
|
d->m_meth = d->kossl->SSLv2_client_method();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (m_cfg->sslv2() && m_cfg->sslv3()) kdDebug(7029) << "Double method" << endl;
|
|
|
|
else if (m_cfg->sslv2()) kdDebug(7029) << "SSL2 method" << endl;
|
|
|
|
else if (m_cfg->sslv3()) kdDebug(7029) << "SSL3 method" << endl;
|
|
|
|
*/
|
|
|
|
|
|
|
|
d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
|
|
|
|
if (d->m_ctx == 0L) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set cipher list
|
|
|
|
TQString clist = m_cfg->getCipherList();
|
|
|
|
kdDebug(7029) << "Cipher list: " << clist << endl;
|
|
|
|
if (!clist.isEmpty())
|
|
|
|
d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
|
|
|
|
|
|
|
|
m_bInit = true;
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KSSL::takeSession(KSSLSession *session) {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
if (!session) {
|
|
|
|
delete d->session;
|
|
|
|
d->session = 0L;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Take session reference
|
|
|
|
d->session = new KSSLSession;
|
|
|
|
d->session->_session = session->_session;
|
|
|
|
session->_session = 0L;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KSSL::close() {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
//kdDebug(7029) << "KSSL close" << endl;
|
|
|
|
if (!m_bInit)
|
|
|
|
return;
|
|
|
|
|
|
|
|
delete d->session;
|
|
|
|
d->session = 0L;
|
|
|
|
|
|
|
|
if (d->m_ssl) {
|
|
|
|
d->kossl->SSL_shutdown(d->m_ssl);
|
|
|
|
d->kossl->SSL_free(d->m_ssl);
|
|
|
|
d->m_ssl = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->kossl->SSL_CTX_free(d->m_ctx);
|
|
|
|
if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
|
|
|
|
d->kossl->RAND_write_file(m_cfg->getEGDPath().latin1());
|
|
|
|
}
|
|
|
|
|
|
|
|
m_bInit = false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KSSL::reInitialize() {
|
|
|
|
close();
|
|
|
|
return initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the callback file - it's hidden away in here
|
|
|
|
//#include "ksslcallback.c"
|
|
|
|
|
|
|
|
|
|
|
|
bool KSSL::setVerificationLogic() {
|
|
|
|
#if 0
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
// SSL_set_verify_result(d->m_ssl, X509_V_OK);
|
|
|
|
// SSL_CTX_set_verify(d->m_ctx, SSL_VERIFY_PEER, X509Callback);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KSSL::accept(int sock) {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
// kdDebug(7029) << "KSSL accept" << endl;
|
|
|
|
int rc;
|
|
|
|
if (!m_bInit)
|
|
|
|
return -1;
|
|
|
|
d->m_ssl = d->kossl->SSL_new(d->m_ctx);
|
|
|
|
if (!d->m_ssl)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (d->session) {
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
|
|
if (static_cast<SSL_SESSION*>(d->session->_session)->sess_cert == 0)
|
|
|
|
{
|
|
|
|
kdDebug(7029) << "Can't reuse session, no certificate." << endl;
|
|
|
|
delete d->session;
|
|
|
|
d->session = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (1 == d->kossl->SSL_set_session(d->m_ssl,
|
|
|
|
static_cast<SSL_SESSION*>(d->session->_session))) {
|
|
|
|
kdDebug(7029) << "Session ID is being reused." << endl;
|
|
|
|
} else {
|
|
|
|
kdDebug(7029) << "Error attempting to reuse session." << endl;
|
|
|
|
delete d->session;
|
|
|
|
d->session = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (!setVerificationLogic()) {
|
|
|
|
d->kossl->SSL_shutdown(d->m_ssl);
|
|
|
|
d->kossl->SSL_free(d->m_ssl);
|
|
|
|
d->m_ssl = 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
int off = SSL_OP_ALL;
|
|
|
|
if (!d->lastInitTLS && !m_cfg->tlsv1())
|
|
|
|
off |= SSL_OP_NO_TLSv1;
|
|
|
|
if (!m_cfg->sslv3())
|
|
|
|
off |= SSL_OP_NO_SSLv3;
|
|
|
|
if (!m_cfg->sslv2())
|
|
|
|
off |= SSL_OP_NO_SSLv2;
|
|
|
|
|
|
|
|
d->kossl->_SSL_set_options(d->m_ssl, off);
|
|
|
|
|
|
|
|
rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
|
|
|
|
if (rc == 0) {
|
|
|
|
d->kossl->SSL_shutdown(d->m_ssl);
|
|
|
|
d->kossl->SSL_free(d->m_ssl);
|
|
|
|
d->m_ssl = 0;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
|
|
|
d->kossl->SSL_set_tlsext_host_name(d->m_ssl, d->proxyPeer.ascii());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
rc = d->kossl->SSL_accept(d->m_ssl);
|
|
|
|
if (rc == 1) {
|
|
|
|
setConnectionInfo();
|
|
|
|
setPeerInfo();
|
|
|
|
kdDebug(7029) << "KSSL connected OK" << endl;
|
|
|
|
} else {
|
|
|
|
kdDebug(7029) << "KSSL accept failed - rc = " << rc << endl;
|
|
|
|
kdDebug(7029) << " ERROR = "
|
|
|
|
<< d->kossl->SSL_get_error(d->m_ssl, rc) << endl;
|
|
|
|
d->kossl->SSL_shutdown(d->m_ssl);
|
|
|
|
d->kossl->SSL_free(d->m_ssl);
|
|
|
|
d->m_ssl = 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d->kossl->_SSL_session_reused(d->m_ssl)) {
|
|
|
|
if (d->session) {
|
|
|
|
kdDebug(7029) << "Session reuse failed. New session used instead." << endl;
|
|
|
|
delete d->session;
|
|
|
|
d->session = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d->session) {
|
|
|
|
SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
|
|
|
|
if (sess) {
|
|
|
|
d->session = new KSSLSession;
|
|
|
|
d->session->_session = sess;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KSSL::connect(int sock) {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
// kdDebug(7029) << "KSSL connect" << endl;
|
|
|
|
int rc;
|
|
|
|
if (!m_bInit)
|
|
|
|
return -1;
|
|
|
|
d->m_ssl = d->kossl->SSL_new(d->m_ctx);
|
|
|
|
if (!d->m_ssl)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (d->session) {
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
|
|
if (static_cast<SSL_SESSION*>(d->session->_session)->sess_cert == 0)
|
|
|
|
{
|
|
|
|
kdDebug(7029) << "Can't reuse session, no certificate." << endl;
|
|
|
|
delete d->session;
|
|
|
|
d->session = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (1 == d->kossl->SSL_set_session(d->m_ssl,
|
|
|
|
static_cast<SSL_SESSION*>(d->session->_session))) {
|
|
|
|
kdDebug(7029) << "Session ID is being reused." << endl;
|
|
|
|
} else {
|
|
|
|
kdDebug(7029) << "Error attempting to reuse session." << endl;
|
|
|
|
delete d->session;
|
|
|
|
d->session = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (!setVerificationLogic()) {
|
|
|
|
d->kossl->SSL_shutdown(d->m_ssl);
|
|
|
|
d->kossl->SSL_free(d->m_ssl);
|
|
|
|
d->m_ssl = 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
int off = SSL_OP_ALL;
|
|
|
|
if (!d->lastInitTLS && !m_cfg->tlsv1())
|
|
|
|
off |= SSL_OP_NO_TLSv1;
|
|
|
|
if (!m_cfg->sslv3())
|
|
|
|
off |= SSL_OP_NO_SSLv3;
|
|
|
|
if (!m_cfg->sslv2())
|
|
|
|
off |= SSL_OP_NO_SSLv2;
|
|
|
|
|
|
|
|
d->kossl->_SSL_set_options(d->m_ssl, off);
|
|
|
|
|
|
|
|
rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
|
|
|
|
if (rc == 0) {
|
|
|
|
d->kossl->SSL_shutdown(d->m_ssl);
|
|
|
|
d->kossl->SSL_free(d->m_ssl);
|
|
|
|
d->m_ssl = 0;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
|
|
|
d->kossl->SSL_set_tlsext_host_name(d->m_ssl, d->proxyPeer.ascii());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
connect_again:
|
|
|
|
rc = d->kossl->SSL_connect(d->m_ssl);
|
|
|
|
if (rc == 1) {
|
|
|
|
setConnectionInfo();
|
|
|
|
setPeerInfo();
|
|
|
|
kdDebug(7029) << "KSSL connected OK" << endl;
|
|
|
|
} else {
|
|
|
|
int err = d->kossl->SSL_get_error(d->m_ssl, rc);
|
|
|
|
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
|
|
|
|
// nonblocking - but we block anyways in connect() :)
|
|
|
|
goto connect_again;
|
|
|
|
} else {
|
|
|
|
kdDebug(7029) << "KSSL connect failed - rc = "
|
|
|
|
<< rc << endl;
|
|
|
|
kdDebug(7029) << " ERROR = "
|
|
|
|
<< err << endl;
|
|
|
|
d->kossl->ERR_print_errors_fp(stderr);
|
|
|
|
d->kossl->SSL_shutdown(d->m_ssl);
|
|
|
|
d->kossl->SSL_free(d->m_ssl);
|
|
|
|
d->m_ssl = 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d->kossl->_SSL_session_reused(d->m_ssl)) {
|
|
|
|
if (d->session) {
|
|
|
|
kdDebug(7029) << "Session reuse failed. New session used instead." << endl;
|
|
|
|
delete d->session;
|
|
|
|
d->session = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d->session) {
|
|
|
|
SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
|
|
|
|
if (sess) {
|
|
|
|
d->session = new KSSLSession;
|
|
|
|
d->session->_session = sess;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KSSL::pending() {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
if (!m_bInit)
|
|
|
|
return -1;
|
|
|
|
return d->kossl->SSL_pending(d->m_ssl);
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KSSL::peek(void *buf, int len) {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
if (!m_bInit)
|
|
|
|
return -1;
|
|
|
|
// FIXME: enhance to work the way read() does below, handling errors
|
|
|
|
return d->kossl->SSL_peek(d->m_ssl, buf, len);
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KSSL::read(void *buf, int len) {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
int rc = 0;
|
|
|
|
int maxIters = 10;
|
|
|
|
|
|
|
|
if (!m_bInit)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
read_again:
|
|
|
|
rc = d->kossl->SSL_read(d->m_ssl, (char *)buf, len);
|
|
|
|
if (rc <= 0) {
|
|
|
|
int err = d->kossl->SSL_get_error(d->m_ssl, rc);
|
|
|
|
|
|
|
|
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
|
|
|
|
kdDebug(7029) << "SSL read() returning 0: " << err << endl;
|
|
|
|
if (maxIters-- > 0) {
|
|
|
|
::usleep(20000); // 20ms sleep
|
|
|
|
goto read_again;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(7029) << "SSL READ ERROR: " << err << endl;
|
|
|
|
if (err != SSL_ERROR_NONE &&
|
|
|
|
err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL) {
|
|
|
|
rc = -1; // OpenSSL returns 0 on error too
|
|
|
|
d->kossl->ERR_print_errors_fp(stderr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// else if (err == SSL_ERROR_ZERO_RETURN)
|
|
|
|
// rc = 0;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KSSL::write(const void *buf, int len) {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
if (!m_bInit)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
write_again:
|
|
|
|
int rc = d->kossl->SSL_write(d->m_ssl, (const char *)buf, len);
|
|
|
|
if (rc <= 0) { // OpenSSL returns 0 on error too
|
|
|
|
int err = d->kossl->SSL_get_error(d->m_ssl, rc);
|
|
|
|
|
|
|
|
if (err == SSL_ERROR_WANT_WRITE) {
|
|
|
|
::usleep(20000); // 20ms sleep
|
|
|
|
goto write_again;
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(7029) << "SSL WRITE ERROR: " << err << endl;
|
|
|
|
if (err != SSL_ERROR_NONE &&
|
|
|
|
err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL)
|
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KSSL::reconfig() {
|
|
|
|
return reInitialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KSSL::setAutoReconfig(bool ar) {
|
|
|
|
m_bAutoReconfig = ar;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KSSL::setSettings(KSSLSettings *settings) {
|
|
|
|
delete m_cfg;
|
|
|
|
m_cfg = settings;
|
|
|
|
return reconfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
bool KSSL::m_bSSLWorks = true;
|
|
|
|
#else
|
|
|
|
bool KSSL::m_bSSLWorks = false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool KSSL::doesSSLWork() {
|
|
|
|
return m_bSSLWorks;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KSSL::setConnectionInfo() {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
SSL_CIPHER *sc;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
buf[0] = 0; // for safety.
|
|
|
|
sc = d->kossl->SSL_get_current_cipher(d->m_ssl);
|
|
|
|
if (!sc) {
|
|
|
|
kdDebug(7029) << "KSSL get current cipher failed - we're probably gonna crash!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the number of bits, bits used
|
|
|
|
m_ci.m_iCipherUsedBits = d->kossl->SSL_CIPHER_get_bits(sc, &(m_ci.m_iCipherBits));
|
|
|
|
// set the cipher version
|
|
|
|
m_ci.m_cipherVersion = d->kossl->SSL_CIPHER_get_version(sc);
|
|
|
|
// set the cipher name
|
|
|
|
m_ci.m_cipherName = d->kossl->SSL_CIPHER_get_name(sc);
|
|
|
|
// set the cipher description
|
|
|
|
m_ci.m_cipherDescription = d->kossl->SSL_CIPHER_description(sc, buf, 1023);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KSSL::setPeerInfo() {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
m_pi.setPeerHost(d->proxyPeer);
|
|
|
|
m_pi.m_cert.setCert(d->kossl->SSL_get_peer_certificate(d->m_ssl));
|
|
|
|
STACK_OF(X509) *xs = d->kossl->SSL_get_peer_cert_chain(d->m_ssl);
|
|
|
|
if (xs)
|
|
|
|
xs = reinterpret_cast<STACK_OF(X509)*>(d->kossl->OPENSSL_sk_dup(xs)); // Leak?
|
|
|
|
m_pi.m_cert.setChain((void *)xs);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KSSLConnectionInfo& KSSL::connectionInfo() {
|
|
|
|
return m_ci;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// KDE 4: Make it const TQString &
|
|
|
|
void KSSL::setPeerHost(TQString realHost) {
|
|
|
|
d->proxyPeer = realHost;
|
|
|
|
}
|
|
|
|
|
|
|
|
// deprecated
|
|
|
|
void KSSL::setProxyUse(bool, TQString, int, TQString) {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KSSLPeerInfo& KSSL::peerInfo() {
|
|
|
|
return m_pi;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KSSL::setClientCertificate(KSSLPKCS12 *pkcs) {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
if (!pkcs || !pkcs->getCertificate())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int rc;
|
|
|
|
X509 *x = pkcs->getCertificate()->getCert();
|
|
|
|
EVP_PKEY *k = pkcs->getPrivateKey();
|
|
|
|
|
|
|
|
if (!x || !k) return false;
|
|
|
|
|
|
|
|
if (!pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
rc = d->kossl->SSL_CTX_use_certificate(d->m_ctx, x);
|
|
|
|
if (rc <= 0) {
|
|
|
|
kdDebug(7029) << "KSSL - SSL_CTX_use_certificate failed. rc = " << rc << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = d->kossl->SSL_CTX_use_PrivateKey(d->m_ctx, k);
|
|
|
|
if (rc <= 0) {
|
|
|
|
kdDebug(7029) << "KSSL - SSL_CTX_use_PrivateKey failed. rc = " << rc << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
const KSSLSession* KSSL::session() const {
|
|
|
|
return d->session;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KSSL::reusingSession() const {
|
|
|
|
#ifdef KSSL_HAVE_SSL
|
|
|
|
return (d->m_ssl && d->kossl->_SSL_session_reused(d->m_ssl));
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|