Случай из реальной жизни

Случай из реальной жизни : работала некая программа под Windows , написанная на Qt 4.8.1 и вдруг 30.09.2021г - не смогла установить HTTPS соединение с неким сервером в интернете...

Оказалось на хостинге сервера истек сертификат TLSv1.0 !

Так же выяснилось ,что программа использовала библиотеки openssl 1.0.0.1 (TLSv1.0).

Что делать? ...

В итоге оказалось, что достаточно добавить одну строчку в коде Qt (qsslsocket_openssl.cpp) и отредактировать другую:

 ctx = SSL_CTX_new(client ? TLSv1_2_client_method() : TLSv1_2_server_method());
options = SSL_OP_ALL|SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;// | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;

и соединение заработает на протоколе TLS1.2, но при условии, что библиотеки openssl будут собраны в версии 1.0.2 (конечно-же).

Но сначала надо понять как изначально в Qt 4.8.1 организована работа с openssl.

Есть пара файлов, которые определяют связи qt библиотек с внешними исходниками openssl:
qsslsocket_openssl_symbols.cpp ,
qsslsocket_openssl_symbols.h

Эти файлы создают указатели на функции openssl. Кстати это не удобно при отладке (не получится войти отладчиком внутрь функции).

Подключаем openssl напрямую.


.....
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
const SSL_METHOD *q_SSLv2_client_method();
const SSL_METHOD *q_SSLv3_client_method();
const SSL_METHOD *q_SSLv23_client_method();
const SSL_METHOD *q_TLSv1_client_method();
const SSL_METHOD *q_SSLv2_server_method();
const SSL_METHOD *q_SSLv3_server_method();
const SSL_METHOD *q_SSLv23_server_method();
const SSL_METHOD *q_TLSv1_server_method();
....

Выясняется, что в исходникамх openssl 1.0.2u конечно уже есть функции:
TLSv1_1_client_method и
TLSv1_2_client_method .

Вот где надо все-лишь внести изменения, это функция initSslContext:

    switch (configuration.protocol) {
    case QSsl::SslV2:
#ifndef OPENSSL_NO_SSL2
        ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method());
#else
        ctx = 0; // SSL 2 not supported by the system, but chosen deliberately -> error
#endif
        break;
    case QSsl::SslV3:
        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:
        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;
    }

Тут надо добавить реализацию вызова метода TLSv1_2_client_method.

Ошибка QSslSocket: cannot call unresolved function скорее всего связана с тем, что не все укзатели на функции openssl определены.

Еще возможно у вас где-то подключаются библиотеки другой версии openssl. Путь к ssleay32.dll и libeay32.dll надо указать правильно в network.pro.

Или как вариант путь указать глобально при настройке среды сборки через configure.exe :

configure.exe -opensource -confirm-license -debug-and-release -mp -platform win32-msvc2010 -shared -nomake examples -nomake demos -nomake tests -no-qt3support -no-scripttools -no-opengl -no-phonon -qt-sql-sqlite -qt-libjpeg -qt-zlib -qt-libpng -openssl OPENSSL_LIBS="-llibeay32 -lssleay32" -I D:\OpenSSL\dll_for_Qt\include -I D:\OpenSSL\dll_for_Qt\bin -nomake -dont-process

конфигурирование qt с openssl.

Кстати там же в network.pro можно включить максимальный вывод отладочной информации:

DEFINES += QT_BUILD_NETWORK_LIB QT_NO_USING_NAMESPACE
DEFINES += QLOCALSERVER_DEBUG QLOCALSOCKET_DEBUG  # my
DEFINES += QNETWORKDISKCACHE_DEBUG  # my
DEFINES += QSSLSOCKET_DEBUG  # my
#DEFINES += QHOSTINFO_DEBUG # error occured (my)
DEFINES += QABSTRACTSOCKET_DEBUG QNATIVESOCKETENGINE_DEBUG  # my
DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG  # my
DEFINES += QUDPSOCKET_DEBUG QUDPSERVER_DEBUG  # my

Чтобы включить отладочную информации в openssl тоже есть специальные дефайны макросы и дефайны компиляции.

При соединении с сервером возникает непонятная ошибка в слоте sslErrors:

QSslError : "The host name did not match any of the valid hosts for this certificate".

Примечание: интересно, что даже когда соединение по TLSv1.2 заработало ошибка осталась. А ошибка ли это...

На самом деле эту ошибку можно игнорировать. Причины ее как раз могут быть связаны с истекшим сроком сертификата сервера версии TLSv1.0, но при этом соединение сможет быть установлено.

Чтобы разобраться, что идет не так при установлении соединения TLS логично отлаживать исходники openssl прямо в исходниках Qt.

Поэтому появилась идея перейти к портированию openssl 1.0.2 на Qt Creator 2.4.1 (под Windows).

Для начала разбираемся как собрать openssl 1.0.2 в среде Qt .