Solved Which version of QT supports TLS1.2
-
-
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? -
Development environment: Fedora 14, QT5.3.2, openssl1.0.2;
-
Fedora14 comes with openssl1.0.0, because openssl1.0.0 does not support TLS1.2, so openssl is upgraded to 1.0.2
-
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: ".
-
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: "
-
-
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. -
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,
- 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.
- Regarding the QT version, I want to use the new version QT5.11, but QT5.11 cannot be installed on Fedora 14.
- 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:
- I learned that Openssl has supported TLS1.2 since 1.0.1, but I does not know which version of QT supports TLS1.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
-
@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 ,- 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.-
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
}; -
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?
-
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?- 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"-
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 ()" -
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; }
- code of printing OpenSSL version is as follows: