diff options
author | Richard J. Moore <rich@kde.org> | 2017-03-23 12:43:22 +0100 |
---|---|---|
committer | André Klitzing <aklitzing@gmail.com> | 2017-07-04 18:03:59 +0000 |
commit | cfbe03a6e035ab3cce5f04962cddd06bd414dcea (patch) | |
tree | 6623e0eac0924a92662d3953609d84d4d94dda8d /src/network/ssl/qsslsocket_openssl.cpp | |
parent | 10de063ff12cdba07b4620182aced8ed05ee3505 (diff) |
QSslSocket: OpenSSL 1.1 backend
This patch-set implements a new QSslSocket backend based on OpenSSL 1.1.
1. General.
The code in this patch was organized to achieve these (somewhat contradicting)
objectives:
- keep the new code free of #if-ery, as far as possible;
- make it easy to clean away dead code when we're eventually able to retire
out-dated OpenSSL versions;
- reduce the amount of code duplication.
If changes in some file/component were insignificant (~5 one-liners per file),
we still use pp-checks like: #if QT_CONFIG(opensslv11) ... #else ... #endif -
the logic is simple and it's still easy to clean the code if we remove the legacy
back-end. Where it saved #if-ery, we also introduced 'forward-compatible'
macros implementing equivalents of 1.1 functions using older OpenSSL.
In case some class contains a lot of version-specific ifdefs (particularly where
nested #if-ery was complex) we choose to split code into: "pre11" h/cpp files,
"shared" h/cpp files (they preserve their original names, e.g qsslsocket_openssl.cpp)
and "11" h/cpp files. If in future we remove the legacy back-end, "pre11" should be
removed; "shared" and "11" parts - merged.
2. Configuration.
We introduced a new feature 'opensslv11' which complements the pre-existing
'openssl' and 'openssl-linked' features. The 'opensslv11' feature is enabled
by a simple test which either compiles successfully or ends in a compilation
error, depending on a value of the OPENSSL_VERSION_NUMBER constant. If the
feature was enabled, we also append an additional compilation flag
-DOPENSSL_API_COMPAT=0x10100000L to make sure our new code does not contain
deprecated structures, function calls, macro-invocations from OpenSSL < 1.1.
Change-Id: I2064efbe9685def5d2bb2233a66f7581954fb74a
Reviewed-by: André Klitzing <aklitzing@gmail.com>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/network/ssl/qsslsocket_openssl.cpp')
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 412 |
1 files changed, 35 insertions, 377 deletions
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index b4bfaca8be..02bd4389af 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2014 Governikus GmbH & Co. KG ** Contact: https://www.qt.io/licensing/ ** @@ -97,70 +97,6 @@ bool QSslSocketPrivate::s_loadRootCertsOnDemand = false; int QSslSocketBackendPrivate::s_indexForSSLExtraData = -1; #endif -/* \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 - whenever 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 QOpenSslLocks -{ -public: - inline QOpenSslLocks() - : 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 ~QOpenSslLocks() - { - QMutexLocker locker(&locksLocker); - for (int i = 0; i < q_CRYPTO_num_locks(); ++i) - delete locks[i]; - delete [] locks; - - QSslSocketPrivate::deinitialize(); - } - 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(QOpenSslLocks, openssl_locks) - QString QSslSocketBackendPrivate::getErrorsFromOpenSsl() { QString errorString; @@ -175,20 +111,6 @@ QString QSslSocketBackendPrivate::getErrorsFromOpenSsl() } 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 (quintptr)QThread::currentThreadId(); -} #if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK) static unsigned int q_ssl_psk_client_callback(SSL *ssl, @@ -212,48 +134,6 @@ static unsigned int q_ssl_psk_server_callback(SSL *ssl, #endif } // extern "C" -static void q_OpenSSL_add_all_algorithms_safe() -{ -#ifdef Q_OS_WIN - // Prior to version 1.0.1m an attempt to call OpenSSL_add_all_algorithms on - // Windows could result in 'exit' call from OPENSSL_config (QTBUG-43843). - // We can predict this and avoid OPENSSL_add_all_algorithms call. - // From OpenSSL docs: - // "An application does not need to add algorithms to use them explicitly, - // for example by EVP_sha1(). It just needs to add them if it (or any of - // the functions it calls) needs to lookup algorithms. - // The cipher and digest lookup functions are used in many parts of the - // library. If the table is not initialized several functions will - // misbehave and complain they cannot find algorithms. This includes the - // PEM, PKCS#12, SSL and S/MIME libraries. This is a common query in - // the OpenSSL mailing lists." - // - // Anyway, as a result, we chose not to call this function if it would exit. - - if (q_SSLeay() < 0x100010DFL) - { - // Now, before we try to call it, check if an attempt to open config file - // will result in exit: - if (char *confFileName = q_CONF_get1_default_config_file()) { - BIO *confFile = q_BIO_new_file(confFileName, "r"); - const auto lastError = q_ERR_peek_last_error(); - q_OPENSSL_free(confFileName); - if (confFile) { - q_BIO_free(confFile); - } else { - q_ERR_clear_error(); - if (ERR_GET_REASON(lastError) == ERR_R_SYS_LIB) { - qCWarning(lcSsl, "failed to open openssl.conf file"); - return; - } - } - } - } -#endif // Q_OS_WIN - - q_OpenSSL_add_all_algorithms(); -} - QSslSocketBackendPrivate::QSslSocketBackendPrivate() : ssl(0), readBio(0), @@ -269,7 +149,7 @@ QSslSocketBackendPrivate::~QSslSocketBackendPrivate() destroySslContext(); } -QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher) +QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher) { QSslCipher ciph; @@ -310,7 +190,8 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *ciph } // static -inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx) { +inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx) +{ return { q_X509_STORE_CTX_get_error(ctx), q_X509_STORE_CTX_get_error_depth(ctx) @@ -324,6 +205,7 @@ struct QSslErrorList QMutex mutex; QVector<QSslErrorEntry> errors; }; + Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList) int q_X509Callback(int ok, X509_STORE_CTX *ctx) @@ -353,7 +235,7 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx) } #endif } - // Always return OK to allow verification to continue. We're handle the + // Always return OK to allow verification to continue. We handle the // errors gracefully after collecting all errors, after verification has // completed. return 1; @@ -438,7 +320,7 @@ bool QSslSocketBackendPrivate::initSslContext() if (configuration.protocol != QSsl::SslV2 && configuration.protocol != QSsl::SslV3 && configuration.protocol != QSsl::UnknownProtocol && - mode == QSslSocket::SslClientMode && q_SSLeay() >= 0x00090806fL) { + mode == QSslSocket::SslClientMode && QSslSocket::sslLibraryVersionNumber() >= 0x00090806fL) { // Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format. QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName; if (tlsHostName.isEmpty()) @@ -479,13 +361,13 @@ bool QSslSocketBackendPrivate::initSslContext() #if OPENSSL_VERSION_NUMBER >= 0x10001000L // Save a pointer to this object into the SSL structure. - if (q_SSLeay() >= 0x10001000L) + if (QSslSocket::sslLibraryVersionNumber() >= 0x10001000L) q_SSL_set_ex_data(ssl, s_indexForSSLExtraData, this); #endif #if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK) // Set the client callback for PSK - if (q_SSLeay() >= 0x10001000L) { + if (QSslSocket::sslLibraryVersionNumber() >= 0x10001000L) { if (mode == QSslSocket::SslClientMode) q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback); else if (mode == QSslSocket::SslServerMode) @@ -507,16 +389,6 @@ void QSslSocketBackendPrivate::destroySslContext() /*! \internal -*/ -void QSslSocketPrivate::deinitialize() -{ - q_CRYPTO_set_id_callback(0); - q_CRYPTO_set_locking_callback(0); - q_ERR_free_strings(); -} - -/*! - \internal Does the minimum amount of initialization to determine whether SSL is supported or not. @@ -527,91 +399,6 @@ bool QSslSocketPrivate::supportsSsl() return ensureLibraryLoaded(); } -bool QSslSocketPrivate::ensureLibraryLoaded() -{ - if (!q_resolveOpenSslSymbols()) - return false; - - // Check if the library itself needs to be initialized. - QMutexLocker locker(openssl_locks()->initLock()); - - if (!s_libraryLoaded) { - s_libraryLoaded = 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(); - q_OpenSSL_add_all_algorithms_safe(); - -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - if (q_SSLeay() >= 0x10001000L) - QSslSocketBackendPrivate::s_indexForSSLExtraData = q_SSL_get_ex_new_index(0L, NULL, NULL, NULL, NULL); -#endif - - // Initialize OpenSSL's random seed. - if (!q_RAND_status()) { - qWarning("Random number generator not seeded, disabling SSL support"); - return false; - } - } - return true; -} - -void QSslSocketPrivate::ensureCiphersAndCertsLoaded() -{ - QMutexLocker locker(openssl_locks()->initLock()); - if (s_loadedCiphersAndCerts) - return; - s_loadedCiphersAndCerts = true; - - resetDefaultCiphers(); - resetDefaultEllipticCurves(); - -#if QT_CONFIG(library) - //load symbols needed to receive certificates from system store -#if defined(Q_OS_WIN) - HINSTANCE hLib = LoadLibraryW(L"Crypt32"); - if (hLib) { - ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW"); - ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore"); - ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore"); - if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore) - qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen - } else { - qCWarning(lcSsl, "could not load crypt32 library"); // should never happen - } -#elif defined(Q_OS_QNX) - s_loadRootCertsOnDemand = true; -#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC) - // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there) - QList<QByteArray> dirs = unixRootCertDirectories(); - QStringList symLinkFilter; - symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]"); - for (int a = 0; a < dirs.count(); ++a) { - QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files); - if (iterator.hasNext()) { - s_loadRootCertsOnDemand = true; - break; - } - } -#endif -#endif // QT_CONFIG(library) - // if on-demand loading was not enabled, load the certs now - if (!s_loadRootCertsOnDemand) - setDefaultCaCertificates(systemCaCertificates()); -#ifdef Q_OS_WIN - //Enabled for fetching additional root certs from windows update on windows 6+ - //This flag is set false by setDefaultCaCertificates() indicating the app uses - //its own cert bundle rather than the system one. - //Same logic that disables the unix on demand cert loading. - //Unlike unix, we do preload the certificates from the cert store. - if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_6_0) - s_loadRootCertsOnDemand = true; -#endif -} /*! \internal @@ -628,26 +415,6 @@ void QSslSocketPrivate::ensureInitialized() ensureCiphersAndCertsLoaded(); } -long QSslSocketPrivate::sslLibraryVersionNumber() -{ - if (!supportsSsl()) - return 0; - - return q_SSLeay(); -} - -QString QSslSocketPrivate::sslLibraryVersionString() -{ - if (!supportsSsl()) - return QString(); - - const char *versionString = q_SSLeay_version(SSLEAY_VERSION); - if (!versionString) - return QString(); - - return QString::fromLatin1(versionString); -} - long QSslSocketPrivate::sslLibraryBuildVersionNumber() { return OPENSSL_VERSION_NUMBER; @@ -669,7 +436,11 @@ QString QSslSocketPrivate::sslLibraryBuildVersionString() */ void QSslSocketPrivate::resetDefaultCiphers() { +#if QT_CONFIG(opensslv11) + SSL_CTX *myCtx = q_SSL_CTX_new(q_TLS_client_method()); +#else SSL_CTX *myCtx = q_SSL_CTX_new(q_SSLv23_client_method()); +#endif SSL *mySsl = q_SSL_new(myCtx); QList<QSslCipher> ciphers; @@ -705,7 +476,7 @@ void QSslSocketPrivate::resetDefaultEllipticCurves() QVector<QSslEllipticCurve> curves; #ifndef OPENSSL_NO_EC - const size_t curveCount = q_EC_get_builtin_curves(NULL, 0); + const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0); QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount)); @@ -739,13 +510,14 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) { HCERTSTORE hSystemStore; hSystemStore = ptrCertOpenSystemStoreW(0, L"ROOT"); - if(hSystemStore) { - PCCERT_CONTEXT pc = NULL; - while(1) { - pc = ptrCertFindCertificateInStore( hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pc); - if(!pc) + if (hSystemStore) { + PCCERT_CONTEXT pc = nullptr; + while (1) { + pc = ptrCertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc); + if (!pc) break; - QByteArray der((const char *)(pc->pbCertEncoded), static_cast<int>(pc->cbCertEncoded)); + QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded), + static_cast<int>(pc->cbCertEncoded)); QSslCertificate cert(der, QSsl::Der); systemCerts.append(cert); } @@ -1543,14 +1315,8 @@ QSslCipher QSslSocketBackendPrivate::sessionCipher() const { if (!ssl) return QSslCipher(); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - // FIXME This is fairly evil, but needed to keep source level compatibility - // with the OpenSSL 0.9.x implementation at maximum -- some other functions - // don't take a const SSL_CIPHER* when they should - SSL_CIPHER *sessionCipher = const_cast<SSL_CIPHER *>(q_SSL_get_current_cipher(ssl)); -#else - SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl); -#endif + + const SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl); return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher(); } @@ -1576,112 +1342,6 @@ QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const return QSsl::UnknownProtocol; } -void QSslSocketBackendPrivate::continueHandshake() -{ - Q_Q(QSslSocket); - // if we have a max read buffer size, reset the plain socket's to match - if (readBufferMaxSize) - plainSocket->setReadBufferSize(readBufferMaxSize); - - if (q_SSL_ctrl((ssl), SSL_CTRL_GET_SESSION_REUSED, 0, NULL)) - configuration.peerSessionShared = true; - -#ifdef QT_DECRYPT_SSL_TRAFFIC - if (ssl->session && ssl->s3) { - const char *mk = reinterpret_cast<const char *>(ssl->session->master_key); - QByteArray masterKey(mk, ssl->session->master_key_length); - const char *random = reinterpret_cast<const char *>(ssl->s3->client_random); - QByteArray clientRandom(random, SSL3_RANDOM_SIZE); - - // different format, needed for e.g. older Wireshark versions: -// const char *sid = reinterpret_cast<const char *>(ssl->session->session_id); -// QByteArray sessionID(sid, ssl->session->session_id_length); -// QByteArray debugLineRSA("RSA Session-ID:"); -// debugLineRSA.append(sessionID.toHex().toUpper()); -// debugLineRSA.append(" Master-Key:"); -// debugLineRSA.append(masterKey.toHex().toUpper()); -// debugLineRSA.append("\n"); - - QByteArray debugLineClientRandom("CLIENT_RANDOM "); - debugLineClientRandom.append(clientRandom.toHex().toUpper()); - debugLineClientRandom.append(" "); - debugLineClientRandom.append(masterKey.toHex().toUpper()); - debugLineClientRandom.append("\n"); - - QString sslKeyFile = QDir::tempPath() + QLatin1String("/qt-ssl-keys"); - QFile file(sslKeyFile); - if (!file.open(QIODevice::Append)) - qCWarning(lcSsl) << "could not open file" << sslKeyFile << "for appending"; - if (!file.write(debugLineClientRandom)) - qCWarning(lcSsl) << "could not write to file" << sslKeyFile; - file.close(); - } else { - qCWarning(lcSsl, "could not decrypt SSL traffic"); - } -#endif - - // Cache this SSL session inside the QSslContext - if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionSharing)) { - if (!sslContextPointer->cacheSession(ssl)) { - sslContextPointer.clear(); // we could not cache the session - } else { - // Cache the session for permanent usage as well - if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionPersistence)) { - if (!sslContextPointer->sessionASN1().isEmpty()) - configuration.sslSession = sslContextPointer->sessionASN1(); - configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint(); - } - } - } - -#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_NEXTPROTONEG) - - configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status; - if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) { - // we could not agree -> be conservative and use HTTP/1.1 - configuration.nextNegotiatedProtocol = QByteArrayLiteral("http/1.1"); - } else { - const unsigned char *proto = 0; - unsigned int proto_len = 0; -#if OPENSSL_VERSION_NUMBER >= 0x10002000L - if (q_SSLeay() >= 0x10002000L) { - q_SSL_get0_alpn_selected(ssl, &proto, &proto_len); - if (proto_len && mode == QSslSocket::SslClientMode) { - // Client does not have a callback that sets it ... - configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated; - } - } - - if (!proto_len) { // Test if NPN was more lucky ... -#else - { -#endif - q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len); - } - - if (proto_len) - configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len); - else - configuration.nextNegotiatedProtocol.clear(); - } -#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ... - -#if OPENSSL_VERSION_NUMBER >= 0x10002000L - if (q_SSLeay() >= 0x10002000L && mode == QSslSocket::SslClientMode) { - EVP_PKEY *key; - if (q_SSL_get_server_tmp_key(ssl, &key)) - configuration.ephemeralServerKey = QSslKey(key, QSsl::PublicKey); - } -#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ... - - connectionEncrypted = true; - emit q->encrypted(); - if (autoStartHandshake && pendingClose) { - pendingClose = false; - q->disconnectFromHost(); - } -} - QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509) { ensureInitialized(); @@ -1735,12 +1395,12 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> & QMutexLocker sslErrorListMutexLocker(&_q_sslErrorList()->mutex); // Register a custom callback to get all verification errors. - X509_STORE_set_verify_cb_func(certStore, q_X509Callback); + q_X509_STORE_set_verify_cb(certStore, q_X509Callback); // Build the chain of intermediate certificates STACK_OF(X509) *intermediates = 0; if (certificateChain.length() > 1) { - intermediates = (STACK_OF(X509) *) q_sk_new_null(); + intermediates = (STACK_OF(X509) *) q_OPENSSL_sk_new_null(); if (!intermediates) { q_X509_STORE_free(certStore); @@ -1754,11 +1414,8 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> & first = false; continue; } -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - q_sk_push( (_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle())); -#else - q_sk_push( (STACK *)intermediates, reinterpret_cast<char *>(cert.handle())); -#endif + + q_OPENSSL_sk_push((OPENSSL_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle())); } } @@ -1782,11 +1439,7 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> & (void) q_X509_verify_cert(storeContext); q_X509_STORE_CTX_free(storeContext); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - q_sk_free( (_STACK *) intermediates); -#else - q_sk_free( (STACK *) intermediates); -#endif + q_OPENSSL_sk_free((OPENSSL_STACK *)intermediates); // Now process the errors const auto errorList = std::move(_q_sslErrorList()->errors); @@ -1860,7 +1513,8 @@ bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device, // Convert to Qt types if (!key->d->fromEVP_PKEY(pkey)) { qCWarning(lcSsl, "Unable to convert private key"); - q_sk_pop_free(reinterpret_cast<STACK *>(ca), reinterpret_cast<void(*)(void*)>(q_sk_free)); + q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca), + reinterpret_cast<void (*)(void *)>(q_OPENSSL_sk_free)); q_X509_free(x509); q_EVP_PKEY_free(pkey); q_PKCS12_free(p12); @@ -1875,7 +1529,11 @@ bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device, *caCertificates = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(ca); // Clean up - q_sk_pop_free(reinterpret_cast<STACK *>(ca), reinterpret_cast<void(*)(void*)>(q_sk_free)); + // TODO: verify ASAP, in the past we had sk_pop_free with q_OPENSSL_sk_free + // which seems to be blatantly wrong and even crashes with 1.1. + q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca), + reinterpret_cast<void (*)(void *)>(q_X509_free)); + q_X509_free(x509); q_EVP_PKEY_free(pkey); q_PKCS12_free(p12); |