Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Which version of QT supports TLS1.2



    1. The problem :
      (1) the HTTPS communication mode is upgraded from TLSv1.0 to TLSv1.2, QT communication fails, what is the cause;
      (2) Which version of QT supports TLS1.2?

    2. Development environment: Fedora 14, QT5.3.2, openssl1.0.2;

    3. Fedora14 comes with openssl1.0.0, because openssl1.0.0 does not support TLS1.2, so openssl is upgraded to 1.0.2

    4. The code QSslSocket->setProtocol(QSsl::TLSv1_0), at this time TLSv1.0 connects to the server successfully, but setProtocol(QSsl::TLSv1_2) error log "Unable to init SSL Context: ".

    5. logs as follow:
      20-10-16 15:22:48 Pivotal(csocket.cpp | 407): connect to "187.72.72.78"
      20-10-16 15:22:48 Debug(sslhelper.cpp | 124): socket Mode Change: 1
      20-10-16 15:22:48 Error(csocket.cpp | 1530): sslsocket error: QAbstractSocket::SocketError( 21 ) "Error creating SSL context ()"
      20-10-16 15:22:48 Error(chttpclient.cpp | 1271): http client error: 1021 "Error creating SSL context ()"
      20-10-16 15:22:48 Error(chttpclient.cpp | 1271): http client error: 1021 "Error creating SSL context ()"
      20-10-16 15:22:48 Error(csocket.cpp | 1530): sslsocket error: QAbstractSocket::SocketError( 20 ) "Unable to init SSL Context: "
      20-10-16 15:22:48 Error(chttpclient.cpp | 1271): http client error: 1020 "Unable to init SSL Context: "
      20-10-16 15:22:48 Error(chttpclient.cpp | 1271): http client error: 1020 "Unable to init SSL Context: "
      20-10-16 15:22:48 Error(csocket.cpp | 1530): sslsocket error: QAbstractSocket::SocketError( 20 ) "Unable to init SSL Context: "
      20-10-16 15:22:48 Error(chttpclient.cpp | 1049): http client error: 1020 "Unable to init SSL Context: "
      20-10-16 15:22:48 Trace(cnetworkheader.cpp | 31): A CNetworkHeader delete: 0xbfcbb174
      20-10-16 15:22:48 Debug(tscsnetworkaccess.cpp | 303): first request post code 1020 content "" header ""
      20-10-16 15:22:48 Error(cnetworkreply.cpp | 148): error: 1020 "Unable to init SSL Context: "
      20-10-16 15:22:48 Error(tscsnetworkaccess.cpp | 365): network error: 1020 "Unable to init SSL Context: "


  • Lifetime Qt Champion

    If it would not be implemented than the enum would not be there or there would be a comment about this. But you've the Qt source code, take a look by yourself.



  • This post is deleted!


  • code print log,as follows:
    qDebug() << QSslSocket::supportsSsl() << QSslSocket::sslLibraryVersionNumber() << QSslSocket::sslLibraryVersionString();

    output :
    20-10-21 18:48:39 Debug(main.cpp | 96): true 268443839 "OpenSSL 1.0.2k 26 Jan 2017"

    Help document of QT5.3.2 is as follows(https://doc.qt.io/archives/qt-5.5/qssl.html#SslProtocol-enum):I want to know what the value of th question mark means, , whether TLSV1.2 is realized ?

    Constant Value Description
    QSsl::SslV3 0 SSLv3
    QSsl::SslV2 1 SSLv2
    QSsl::TlsV1_0 2 TLSv1.0
    QSsl::TlsV1 TlsV1_0 Obsolete, means the same as TlsV1_0
    QSsl::TlsV1_1 ? TLSv1.1
    QSsl::TlsV1_2 ? TLSv1.2
    QSsl::UnknownProtocol -1 The cipher's protocol cannot be determined.
    QSsl::AnyProtocol ? The socket understands SSLv2, SSLv3, and TLSv1.0. This value is used by QSslSocket only.
    QSsl::TlsV1SslV3 ? this will send a TLS 1.0 Client Hello, enabling TLSv1_0 and SSLv3 connections.
    QSsl::SecureProtocols ? The default option, using protocols known to be secure; currently behaves like TlsV1SslV3.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    First thing to start: using an OpenSSL version that is 3 years old for secure connection is a bad idea.

    Second, Qt 5.3.2 is more than outdated. Current version is 5.15.1 with 6.0 entering beta.

    You should really consider updating your development system.



  • @SGaist said in Which version of QT supports TLS1.2:

    Hi and welcome to devnet,

    First thing to start: using an OpenSSL version that is 3 years old for secure connection is a bad idea.

    Second, Qt 5.3.2 is more than outdated. Current version is 5.15.1 with 6.0 entering beta.

    You should really consider updating your development system.

    Thank you,

    1. Regarding the operating system, since hundreds of thousands of devices in production are all Fedora 14, updating the operating system to the latest version Fedora 31 is not realistic.
    2. Regarding the QT version, I want to use the new version QT5.11, but QT5.11 cannot be installed on Fedora 14.
    3. Regarding secure connection, It is no problem to update the Openssl version from 1.0.2 to 1.1.1. The purpose is to use TLS1.2.

    My questions:

    1. I learned that Openssl has supported TLS1.2 since 1.0.1, but I does not know which version of QT supports TLS1.2.
    2. It is understood that Openssl has supported TLS1.2 since 1.0.1, but I does not know which version of QT supports TLS1.2. In the help documentation of QT5.3.2, there is a constant QSsl::TlsV1_2, but its value is Question mark. I don’t know whether QT5.3.2 supports TlsV1.2. But after QT5.11, the value of QSsl::TlsV1_2 changed from question mark to 4

  • Lifetime Qt Champion

    @duan said in Which version of QT supports TLS1.2:

    but its value is Question mark

    Don't know why it's so important to know the value (and why not simply looking at your sources - it's a plain enum) but https://doc.qt.io/qt-5/qssl.html - it's 4



  • This post is deleted!


  • @Christian-Ehrlicher
    Thank you ,

    1. In the help documentation of QT5.3.2, as follows,

    Constant Value Description
    QSsl::SslV3 0 SSLv3
    QSsl::SslV2 1 SSLv2
    QSsl::TlsV1_0 2 TLSv1.0
    QSsl::TlsV1_1 ? TLSv1.1
    QSsl::TlsV1_2 ? TLSv1.2
    QSsl::UnknownProtocol -1 The cipher's protocol cannot be determined.
    QSsl::AnyProtocol ? The socket understands SSLv2, SSLv3, and TLSv1.0. This value is used by QSslSocket only.

    1. the source code of Q5.3.2 , as follows,
      enum SslProtocol {
      SslV3,
      SslV2,
      TlsV1_0,
      #if QT_DEPRECATED_SINCE(5,0)
      TlsV1 = TlsV1_0,
      #endif
      TlsV1_1,
      TlsV1_2,
      AnyProtocol,
      UnknownProtocol = -1
      };

    2. See above,the source code of Q5.3.2 has constant QSsl::TlsV1_2.
      My code setProtocol(QSsl::TLSv1_2) error "Unable to init SSL Context".
      My code setProtocol(QSsl::TLSv1_0), this connects to the server successfully.

    So I wonder whether Q5.3.2 implements TLS1.2?


  • Lifetime Qt Champion

    If it would not be implemented than the enum would not be there or there would be a comment about this. But you've the Qt source code, take a look by yourself.



  • @Christian-Ehrlicher
    Thank you ,
    Now, I don’t know what causes sslContext->ctx to be NULL, or how to debug this problem?

    1. code of printing OpenSSL version is as follows:
      qDebug() << QSslSocket::supportsSsl() << QSslSocket::sslLibraryVersionNumber() << QSslSocket::sslLibraryVersionString();

    log of outputing OpenSSL version :
    20-10-21 18:48:39 Debug(main.cpp | 96): true 268443839 "OpenSSL 1.0.2k 26 Jan 2017"

    1. My code error log is as follows :
      20-10-16 15:22:48 Pivotal(csocket.cpp | 407): connect to "187.72.72.78"
      20-10-16 15:22:48 Debug(sslhelper.cpp | 124): socket Mode Change: 1
      20-10-16 15:22:48 Error(csocket.cpp | 1530): sslsocket error: QAbstractSocket::SocketError( 21 ) "Error creating SSL context ()"
      20-10-16 15:22:48 Error(chttpclient.cpp | 1271): http client error: 1021 "Error creating SSL context ()"

    2. I checked the source code of Q5.3.2 and found that there is a constant “case QSsl::TlsV1_2” judgment. The error message "Error creating SSL context (%1)" appears in the code below, and sslContext->ctx is NULL.

    QSslContext* QSslContext::fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
    
    {
        QSslContext *sslContext = new QSslContext();
        sslContext->sslConfiguration = configuration;
        sslContext->errorCode = QSslError::NoError;
    
        bool client = (mode == QSslSocket::SslClientMode);
    
        bool reinitialized = false;
    init_context:
        switch (sslContext->sslConfiguration.protocol()) {
        case QSsl::SslV2:
    #ifndef OPENSSL_NO_SSL2
            sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method());
    #else
            sslContext->ctx = 0; // SSL 2 not supported by the system, but chosen deliberately -> error
    #endif
            break;
        case QSsl::SslV3:
            sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method());
            break;
        case QSsl::SecureProtocols: // SslV2 will be disabled below
        case QSsl::TlsV1SslV3: // SslV2 will be disabled below
        case QSsl::AnyProtocol:
        default:
            sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
            break;
        case QSsl::TlsV1_0:
            sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_client_method() : q_TLSv1_server_method());
            break;
        case QSsl::TlsV1_1:
    #if OPENSSL_VERSION_NUMBER >= 0x10001000L
            sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_1_client_method() : q_TLSv1_1_server_method());
    #else
            sslContext->ctx = 0; // TLS 1.1 not supported by the system, but chosen deliberately -> error
    #endif
            break;
        case QSsl::TlsV1_2:
    #if OPENSSL_VERSION_NUMBER >= 0x10001000L
            sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_2_client_method() : q_TLSv1_2_server_method());
    #else
            sslContext->ctx = 0; // TLS 1.2 not supported by the system, but chosen deliberately -> error
    #endif
            break;
        }
        if (!sslContext->ctx) {
            // After stopping Flash 10 the SSL library looses its ciphers. Try re-adding them
            // by re-initializing the library.
            if (!reinitialized) {
                reinitialized = true;
                if (q_SSL_library_init() == 1)
                    goto init_context;
            }
    
            sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
            sslContext->errorCode = QSslError::UnspecifiedError;
            return sslContext;
        }
    
        // Enable bug workarounds.
        long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
        q_SSL_CTX_set_options(sslContext->ctx, options);
    
    #if OPENSSL_VERSION_NUMBER >= 0x10000000L
        // Tell OpenSSL to release memory early
        // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
        if (q_SSLeay() >= 0x10000000L)
            q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
    #endif
    
        // Initialize ciphers
        QByteArray cipherString;
        int first = true;
        QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
        if (ciphers.isEmpty())
            ciphers = QSslSocketPrivate::defaultCiphers();
        foreach (const QSslCipher &cipher, ciphers) {
            if (first)
                first = false;
            else
                cipherString.append(':');
            cipherString.append(cipher.name().toLatin1());
        }
    
        if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, cipherString.data())) {
            sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
            sslContext->errorCode = QSslError::UnspecifiedError;
            return sslContext;
        }
    
        // Add all our CAs to this store.
        foreach (const QSslCertificate &caCertificate, sslContext->sslConfiguration.caCertificates()) {
            // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
            //
            // If several CA certificates matching the name, key identifier, and
            // serial number condition are available, only the first one will be
            // examined. This may lead to unexpected results if the same CA
            // certificate is available with different expiration dates. If a
            // ``certificate expired'' verification error occurs, no other
            // certificate will be searched. Make sure to not have expired
            // certificates mixed with valid ones.
            //
            // See also: QSslSocketBackendPrivate::verify()
            if (caCertificate.expiryDate() >= QDateTime::currentDateTime()) {
                q_X509_STORE_add_cert(sslContext->ctx->cert_store, (X509 *)caCertificate.handle());
            }
        }
    
        if (QSslSocketPrivate::s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
            // tell OpenSSL the directories where to look up the root certs on demand
            QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
            for (int a = 0; a < unixDirs.count(); ++a)
                q_SSL_CTX_load_verify_locations(sslContext->ctx, 0, unixDirs.at(a).constData());
        }
    
        if (!sslContext->sslConfiguration.localCertificate().isNull()) {
            // Require a private key as well.
            if (sslContext->sslConfiguration.privateKey().isNull()) {
                sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
                sslContext->errorCode = QSslError::UnspecifiedError;
                return sslContext;
            }
    
            // Load certificate
            if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
                sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
                sslContext->errorCode = QSslError::UnspecifiedError;
                return sslContext;
            }
    
            if (configuration.d->privateKey.algorithm() == QSsl::Opaque) {
                sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
            } else {
                // Load private key
                sslContext->pkey = q_EVP_PKEY_new();
                // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
                // this lead to a memory leak. Now we use the *_set1_* functions which do not
                // take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
                if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
                    q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
                else
                    q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
            }
    
            if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, sslContext->pkey)) {
                sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
                sslContext->errorCode = QSslError::UnspecifiedError;
                return sslContext;
            }
            if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
                sslContext->pkey = 0; // Don't free the private key, it belongs to QSslKey
    
            // Check if the certificate matches the private key.
            if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
                sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
                sslContext->errorCode = QSslError::UnspecifiedError;
                return sslContext;
            }
    
            // If we have any intermediate certificates then we need to add them to our chain
            bool first = true;
            foreach (const QSslCertificate &cert, configuration.d->localCertificateChain) {
                if (first) {
                    first = false;
                    continue;
                }
                q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
                               q_X509_dup(reinterpret_cast<X509 *>(cert.handle())));
            }
        }
    
        // Initialize peer verification.
        if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
            q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, 0);
        } else {
            q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_PEER, q_X509Callback);
        }
    
        // Set verification depth.
        if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
            q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth());
    
        // set persisted session if the user set it
        if (!configuration.sessionTicket().isEmpty())
            sslContext->setSessionASN1(configuration.sessionTicket());
    
        // Set temp DH params
        DH *dh = 0;
        dh = get_dh1024();
        q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
        q_DH_free(dh);
    
    #ifndef OPENSSL_NO_EC
        // Set temp ECDH params
        EC_KEY *ecdh = 0;
        ecdh = q_EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
        q_SSL_CTX_set_tmp_ecdh(sslContext->ctx, ecdh);
        q_EC_KEY_free(ecdh);
    #endif // OPENSSL_NO_EC
    
        return sslContext;
    }
    

Log in to reply