⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qsslsocket_openssl.cpp

📁 奇趣公司比较新的qt/emd版本
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtNetwork module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file.  Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************//******************************************************************************** In addition, as a special exception, Trolltech gives permission to link** the code of its release of Qt with the OpenSSL project's "OpenSSL" library** (or modified versions of the "OpenSSL" library that use the same license** as the original version), and distribute the linked executables.**** You must comply with the GNU General Public License version 2 in all** respects for all of the code used other than the "OpenSSL" code.  If you** modify this file, you may extend this exception to your version of the file,** but you are not obligated to do so.  If you do not wish to do so, delete** this exception statement from your version of this file.******************************************************************************/#include "qsslsocket_openssl_p.h"#include "qsslsocket_openssl_symbols_p.h"#include "qsslsocket.h"#include "qsslcertificate_p.h"#include "qsslcipher_p.h"#include <QtCore/qdatetime.h>#include <QtCore/qdebug.h>#include <QtCore/qdir.h>#include <QtCore/qdiriterator.h>#include <QtCore/qfile.h>#include <QtCore/qfileinfo.h>#include <QtCore/qmutex.h>#include <QtCore/qthread.h>#include <QtCore/qurl.h>#include <QtCore/qvarlengtharray.h>// Useful defines#define SSL_ERRORSTR() QString::fromLocal8Bit(q_ERR_error_string(q_ERR_get_error(), NULL))/* \internal    From OpenSSL's thread(3) manual page:    OpenSSL can safely be used in multi-threaded applications provided that at    least two callback functions are set.    locking_function(int mode, int n, const char *file, int line) is needed to    perform locking on shared data structures.  (Note that OpenSSL uses a    number of global data structures that will be implicitly shared    when-whenever ever multiple threads use OpenSSL.)  Multi-threaded    applications will crash at random if it is not set.  ...    ...    id_function(void) is a function that returns a thread ID. It is not    needed on Windows nor on platforms where getpid() returns a different    ID for each thread (most notably Linux)*/class OpenSslLocks{public:    inline OpenSslLocks()        : initLocker(QMutex::Recursive),          locksLocker(QMutex::Recursive)    {        QMutexLocker locker(&locksLocker);        int numLocks = q_CRYPTO_num_locks();        locks = new QMutex *[numLocks];        memset(locks, 0, numLocks * sizeof(QMutex *));    }    inline ~OpenSslLocks()    {        QMutexLocker locker(&locksLocker);        for (int i = 0; i < q_CRYPTO_num_locks(); ++i)            delete locks[i];        delete [] locks;    }    inline QMutex *lock(int num)    {        QMutexLocker locker(&locksLocker);        QMutex *tmp = locks[num];        if (!tmp)            tmp = locks[num] = new QMutex(QMutex::Recursive);        return tmp;    }    QMutex *globalLock()    {        return &locksLocker;    }    QMutex *initLock()    {        return &initLocker;    }private:    QMutex initLocker;    QMutex locksLocker;    QMutex **locks;};Q_GLOBAL_STATIC(OpenSslLocks, openssl_locks)extern "C" {static void locking_function(int mode, int lockNumber, const char *, int){    QMutex *mutex = openssl_locks()->lock(lockNumber);    // Lock or unlock it    if (mode & CRYPTO_LOCK)        mutex->lock();    else        mutex->unlock();}static unsigned long id_function(){    return (unsigned long)QThread::currentThreadId();}} // extern "C"QSslSocketBackendPrivate::QSslSocketBackendPrivate()    : ssl(0),      ctx(0),      readBio(0),      writeBio(0),      session(0){    // Calls SSL_library_init().    ensureInitialized();}QSslSocketBackendPrivate::~QSslSocketBackendPrivate(){}QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher){    QSslCipher ciph;    char buf [256];    QString descriptionOneLine = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf, sizeof(buf)));    QStringList descriptionList = descriptionOneLine.split(QLatin1String(" "), QString::SkipEmptyParts);    if (descriptionList.size() > 5) {        // ### crude code.        ciph.d->isNull = false;        ciph.d->name = descriptionList.at(0);        QString protoString = descriptionList.at(1);        ciph.d->protocolString = protoString;        ciph.d->protocol = QSsl::UnknownProtocol;        if (protoString == QLatin1String("SSLv3"))            ciph.d->protocol = QSsl::SslV3;        else if (protoString == QLatin1String("SSLv2"))            ciph.d->protocol = QSsl::SslV2;        else if (protoString == QLatin1String("TLSv1"))            ciph.d->protocol = QSsl::TlsV1;                if (descriptionList.at(2).startsWith(QLatin1String("Kx=")))            ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3);        if (descriptionList.at(3).startsWith(QLatin1String("Au=")))            ciph.d->authenticationMethod = descriptionList.at(3).mid(3);        if (descriptionList.at(4).startsWith(QLatin1String("Enc=")))            ciph.d->encryptionMethod = descriptionList.at(4).mid(4);        ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == QLatin1String("export"));        ciph.d->bits = cipher->strength_bits;        ciph.d->supportedBits = cipher->alg_bits;    }    return ciph;}// ### This list is shared between all threads, and protected by a// mutex. Investigate using thread local storage instead.struct QSslErrorList{    QMutex mutex;    QList<int> errors;};Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList)static int q_X509Callback(int ok, X509_STORE_CTX *ctx){    if (!ok)        _q_sslErrorList()->errors << ctx->error;    return ctx->error;}bool QSslSocketBackendPrivate::initSslContext(){    Q_Q(QSslSocket);    // Create and initialize SSL context. Accept SSLv2, SSLv3 and TLSv1.    bool client = (mode == QSslSocket::SslClientMode);    switch (protocol) {    case QSsl::SslV2:        ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method());        break;    case QSsl::SslV3:        ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method());        break;    case QSsl::AnyProtocol:    default:        ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());        break;    case QSsl::TlsV1:        ctx = q_SSL_CTX_new(client ? q_TLSv1_client_method() : q_TLSv1_server_method());        break;    }    if (!ctx) {        // ### Bad error code        q->setErrorString(QSslSocket::tr("Error creating SSL context (%1)").arg(SSL_ERRORSTR()));        q->setSocketError(QAbstractSocket::UnknownSocketError);        emit q->error(QAbstractSocket::UnknownSocketError);        return false;    }    // Enable all bug workarounds.    q_SSL_CTX_set_options(ctx, SSL_OP_ALL);    // Initialize ciphers    QByteArray cipherString;    int first = true;    foreach (const QSslCipher &cipher, ciphers.isEmpty() ? defaultCiphers() : ciphers) {        if (first)            first = false;        else            cipherString.append(":");        cipherString.append(cipher.name().toLatin1());    }    if (!q_SSL_CTX_set_cipher_list(ctx, cipherString.data())) {        // ### Bad error code        q->setErrorString(QSslSocket::tr("Invalid or empty cipher list (%1)").arg(SSL_ERRORSTR()));        q->setSocketError(QAbstractSocket::UnknownSocketError);        emit q->error(QAbstractSocket::UnknownSocketError);        return false;    }    // Add all our CAs to this store.    foreach (const QSslCertificate &caCertificate, q->caCertificates())        q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());    // Register a custom callback to get all verification errors.    X509_STORE_set_verify_cb_func(ctx->cert_store, q_X509Callback);    if (!localCertificate.isNull()) {        // Require a private key as well.        if (privateKey.isNull()) {            q->setErrorString(QSslSocket::tr("Cannot provide a certificate with no key, %1").arg(SSL_ERRORSTR()));            emit q->error(QAbstractSocket::UnknownSocketError);            return false;        }        // Load certificate        if (!q_SSL_CTX_use_certificate(ctx, (X509 *)localCertificate.handle())) {            q->setErrorString(QSslSocket::tr("Error loading local certificate, %1").arg(SSL_ERRORSTR()));            emit q->error(QAbstractSocket::UnknownSocketError);            return false;        }        // Load private key        EVP_PKEY *pkey = q_EVP_PKEY_new();        if (privateKey.algorithm() == QSsl::Rsa)            q_EVP_PKEY_assign_RSA(pkey, (RSA *)privateKey.handle());        else            q_EVP_PKEY_assign_DSA(pkey, (DSA *)privateKey.handle());        if (!q_SSL_CTX_use_PrivateKey(ctx, pkey)) {            q->setErrorString(QSslSocket::tr("Error loading private key, %1").arg(SSL_ERRORSTR()));            emit q->error(QAbstractSocket::UnknownSocketError);            return false;        }        // Check if the certificate matches the private key.        if (!q_SSL_CTX_check_private_key(ctx)) {            q->setErrorString(QSslSocket::tr("Private key does not certificate public key, %1").arg(SSL_ERRORSTR()));            emit q->error(QAbstractSocket::UnknownSocketError);            return false;        }    }    // Create and initialize SSL session    if (!(ssl = q_SSL_new(ctx))) {        // ### Bad error code        q->setErrorString(QSslSocket::tr("Error creating SSL session, %1").arg(SSL_ERRORSTR()));        q->setSocketError(QAbstractSocket::UnknownSocketError);        emit q->error(QAbstractSocket::UnknownSocketError);        return false;    }    // Clear the session.    q_SSL_clear(ssl);    errorList.clear();    // Initialize memory BIOs for encryption and decryption.    readBio = q_BIO_new(q_BIO_s_mem());    writeBio = q_BIO_new(q_BIO_s_mem());    if (!readBio || !writeBio) {        // ### Bad error code        q->setErrorString(QSslSocket::tr("Error creating SSL session: %1").arg(SSL_ERRORSTR()));        q->setSocketError(QAbstractSocket::UnknownSocketError);        emit q->error(QAbstractSocket::UnknownSocketError);        return false;    }    // Assign the bios.    q_SSL_set_bio(ssl, readBio, writeBio);    if (mode == QSslSocket::SslClientMode)        q_SSL_set_connect_state(ssl);    else        q_SSL_set_accept_state(ssl);    return true;}/*!    \internal    Declared static in QSslSocketPrivate, makes sure the SSL libraries have    been initialized.*/bool QSslSocketPrivate::ensureInitialized(){    if (!q_resolveOpenSslSymbols())        return false;    // Check if the library itself needs to be initialized.    QMutexLocker locker(openssl_locks()->initLock());    static int q_initialized = false;    if (!q_initialized) {        q_initialized = true;        // Initialize OpenSSL.        q_CRYPTO_set_id_callback(id_function);        q_CRYPTO_set_locking_callback(locking_function);        if (q_SSL_library_init() != 1)            return false;        q_SSL_load_error_strings();        // Initialize OpenSSL's random seed.        if (!q_RAND_status()) {            struct {                int msec;                int sec;                void *stack;            } randomish;            // This is probably not secure enough.            randomish.stack = (void *)&randomish;            randomish.msec = QTime::currentTime().msec();            randomish.sec = QTime::currentTime().second();            q_RAND_seed((const char *)&randomish, sizeof(randomish));        }        resetDefaultCiphers();        setDefaultCaCertificates(systemCaCertificates());

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -