diff options
Diffstat (limited to 'src/network/ssl/qsslsocket_openssl.cpp')
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 392 |
1 files changed, 46 insertions, 346 deletions
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index ab82cdcfc9..2d771b5637 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/ ** @@ -54,7 +54,6 @@ ****************************************************************************/ //#define QSSLSOCKET_DEBUG -//#define QT_DECRYPT_SSL_TRAFFIC #include "qssl_p.h" #include "qsslsocket_openssl_p.h" @@ -97,70 +96,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 +110,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, @@ -227,7 +148,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; @@ -268,12 +189,12 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *ciph } // static -inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx) { - QSslErrorEntry result = { +inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx) +{ + return { q_X509_STORE_CTX_get_error(ctx), q_X509_STORE_CTX_get_error_depth(ctx) }; - return result; } // ### This list is shared between all threads, and protected by a @@ -283,6 +204,7 @@ struct QSslErrorList QMutex mutex; QVector<QSslErrorEntry> errors; }; + Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList) int q_X509Callback(int ok, X509_STORE_CTX *ctx) @@ -290,6 +212,7 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx) if (!ok) { // Store the error and at which depth the error was detected. _q_sslErrorList()->errors << QSslErrorEntry::fromStoreContext(ctx); +#if !QT_CONFIG(opensslv11) #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl) << "verification error: dumping bad certificate"; qCDebug(lcSsl) << QSslCertificatePrivate::QSslCertificate_from_X509(q_X509_STORE_CTX_get_current_cert(ctx)).toPem(); @@ -310,9 +233,10 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx) << "ST=" << cert.subjectInfo(QSslCertificate::StateOrProvinceName); qCDebug(lcSsl) << "Valid:" << cert.effectiveDate() << '-' << cert.expiryDate(); } -#endif +#endif // QSSLSOCKET_DEBUG +#endif // !QT_CONFIG(opensslv11) } - // 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; @@ -397,7 +321,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()) @@ -438,13 +362,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) @@ -466,16 +390,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. @@ -486,91 +400,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(); - -#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 @@ -587,26 +416,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; @@ -628,7 +437,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; @@ -664,7 +477,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)); @@ -698,13 +511,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); } @@ -891,10 +705,9 @@ void QSslSocketBackendPrivate::transmit() // Write encrypted data from the buffer into the read BIO. int writtenToBio = q_BIO_write(readBio, data.constData(), encryptedBytesRead); - // do the actual read() here and throw away the results. + // Throw away the results. if (writtenToBio > 0) { - // ### TODO: make this cheaper by not making it memcpy. E.g. make it work with data=0x0 or make it work with seek - plainSocket->read(data.data(), writtenToBio); + plainSocket->skip(writtenToBio); } else { // ### Better error handling. setErrorAndEmit(QAbstractSocket::SslInternalError, @@ -943,15 +756,15 @@ void QSslSocketBackendPrivate::transmit() // we have a readBufferMaxSize. There's no point in leaving data there // just so that readBuffer.size() == readBufferMaxSize. int readBytes = 0; - data.resize(4096); - ::memset(data.data(), 0, data.size()); + const int bytesToRead = 4096; do { // Don't use SSL_pending(). It's very unreliable. - if ((readBytes = q_SSL_read(ssl, data.data(), data.size())) > 0) { + readBytes = q_SSL_read(ssl, buffer.reserve(bytesToRead), bytesToRead); + if (readBytes > 0) { #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: decrypted" << readBytes << "bytes"; #endif - buffer.append(data.constData(), readBytes); + buffer.chop(bytesToRead - readBytes); if (readyReadEmittedPointer) *readyReadEmittedPointer = true; @@ -960,6 +773,7 @@ void QSslSocketBackendPrivate::transmit() transmitting = true; continue; } + buffer.chop(bytesToRead); // Error. switch (q_SSL_get_error(ssl, readBytes)) { @@ -1502,14 +1316,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(); } @@ -1535,112 +1343,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(); @@ -1694,12 +1396,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); @@ -1713,11 +1415,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())); } } @@ -1741,11 +1440,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); @@ -1819,7 +1514,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); @@ -1834,7 +1530,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); |