File indexing completed on 2024-03-24 15:27:56

0001 /* This file is part of the KDE project
0002  *
0003  * Copyright (C) 2000-2003 George Staikos <staikos@kde.org>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #include "kssl.h"
0022 
0023 #include <ksslconfig.h>
0024 
0025 // this hack provided by Malte Starostik to avoid glibc/openssl bug
0026 // on some systems
0027 #if KSSL_HAVE_SSL
0028 #define crypt _openssl_crypt
0029 #include <openssl/ssl.h>
0030 #include <openssl/x509.h>
0031 #include <openssl/x509v3.h>
0032 #include <openssl/pem.h>
0033 #include <openssl/rand.h>
0034 #undef crypt
0035 #endif
0036 
0037 #include <kopenssl.h>
0038 #include <ksslx509v3.h>
0039 #include <klocalizedstring.h>
0040 
0041 #include <QAbstractSocket>
0042 #include <QFile>
0043 
0044 #ifdef __GNUC__
0045 #warning "kssl.cpp contains temporary functions! Clean up"
0046 #warning "kssl.cpp needs to be ported to QSslSocket"
0047 #endif
0048 
0049 class KSSLPrivate
0050 {
0051 public:
0052     KSSLPrivate()
0053     {
0054         kossl = KOpenSSLProxy::self();
0055     }
0056 
0057     ~KSSLPrivate() {}
0058 
0059 #if KSSL_HAVE_SSL
0060     SSL *m_ssl;
0061     SSL_CTX *m_ctx;
0062     SSL_METHOD *m_meth;
0063 #endif
0064     KOSSL *kossl;
0065 };
0066 
0067 KSSL::KSSL(bool init)
0068 {
0069     d = new KSSLPrivate;
0070     m_bInit = false;
0071     m_bAutoReconfig = true;
0072     m_cfg = new KSSLSettings();
0073 #if KSSL_HAVE_SSL
0074     d->m_ssl = nullptr;
0075 #endif
0076 
0077     if (init) {
0078         initialize();
0079     }
0080 }
0081 
0082 KSSL::~KSSL()
0083 {
0084     close();
0085     delete m_cfg;
0086     delete d;
0087 }
0088 
0089 int KSSL::seedWithEGD()
0090 {
0091     int rc = 0;
0092 #if KSSL_HAVE_SSL
0093     if (m_cfg->useEGD() && !m_cfg->getEGDPath().isEmpty()) {
0094         rc = d->kossl->RAND_egd(QFile::encodeName(m_cfg->getEGDPath()).constData());
0095         if (rc < 0) {
0096             qWarning() << "KSSL: Error seeding PRNG with the EGD.";
0097         } else {
0098             //qDebug() << "KSSL: PRNG was seeded with" << rc << "bytes from the EGD.";
0099         }
0100     } else if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
0101         rc = d->kossl->RAND_load_file(QFile::encodeName(m_cfg->getEGDPath()).constData(), -1);
0102         if (rc < 0) {
0103             qWarning() << "KSSL: Error seeding PRNG with the entropy file.";
0104         } else {
0105             //qDebug() << "KSSL: PRNG was seeded with" << rc << "bytes from the entropy file.";
0106         }
0107     }
0108 #endif
0109     return rc;
0110 }
0111 
0112 bool KSSL::initialize()
0113 {
0114 #if KSSL_HAVE_SSL
0115     //qDebug() << "KSSL initialize";
0116     if (m_bInit) {
0117         return false;
0118     }
0119 
0120     if (m_bAutoReconfig) {
0121         m_cfg->load();
0122     }
0123 
0124     seedWithEGD();
0125 
0126     d->m_meth = d->kossl->SSLv23_client_method();
0127     d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
0128     if (d->m_ctx == nullptr) {
0129         return false;
0130     }
0131 
0132     // set cipher list
0133     QString clist = m_cfg->getCipherList();
0134     //qDebug() << "Cipher list: " << clist;
0135     if (!clist.isEmpty()) {
0136         d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.toLatin1().constData()));
0137     }
0138 
0139     m_bInit = true;
0140     return true;
0141 #else
0142     return false;
0143 #endif
0144 }
0145 
0146 void KSSL::close()
0147 {
0148 #if KSSL_HAVE_SSL
0149     //qDebug() << "KSSL close";
0150     if (!m_bInit) {
0151         return;
0152     }
0153 
0154     if (d->m_ssl) {
0155         d->kossl->SSL_shutdown(d->m_ssl);
0156         d->kossl->SSL_free(d->m_ssl);
0157         d->m_ssl = nullptr;
0158     }
0159 
0160     d->kossl->SSL_CTX_free(d->m_ctx);
0161     if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
0162         d->kossl->RAND_write_file(m_cfg->getEGDPath().toLatin1().constData());
0163     }
0164 
0165     m_bInit = false;
0166 #endif
0167 }
0168 
0169 bool KSSL::reInitialize()
0170 {
0171     close();
0172     return initialize();
0173 }
0174 
0175 // get the callback file - it's hidden away in here
0176 //#include "ksslcallback.c"
0177 
0178 bool KSSL::reconfig()
0179 {
0180     return reInitialize();
0181 }
0182 
0183 void KSSL::setAutoReconfig(bool ar)
0184 {
0185     m_bAutoReconfig = ar;
0186 }
0187 
0188 bool KSSL::setSettings(KSSLSettings *settings)
0189 {
0190     delete m_cfg;
0191     m_cfg = settings;
0192     return reconfig();
0193 }
0194 
0195 KSSLSettings *KSSL::settings()
0196 {
0197     return m_cfg;
0198 }
0199 
0200 #if KSSL_HAVE_SSL
0201 bool KSSL::m_bSSLWorks = true;
0202 #else
0203 bool KSSL::m_bSSLWorks = false;
0204 #endif
0205 
0206 bool KSSL::doesSSLWork()
0207 {
0208     return m_bSSLWorks;
0209 }
0210