Попытаемся сначала разобраться как работает TCP , ssl под Qt 4.8.1 .
собираем приложение с исходниками openssl 1.0.2 под Qt Creator 2.4.1
Что мы знаем на начальный момент : Qt 4.8.1 использует свободную библиотеку openssl, подключая ее функционал через 2 библиотеки libeay32 и ssleay32, а также подключает заголовочные файлы , поставляемые с этими библиотеками.
Запрос к серверу начинается у нас с команды :
QNetworkReply *reply = qnam.get(request );
Как проследить дальнейший путь ? Дело в том , что далее будет создан отдельный поток для выполнения запроса.
На самом деле все просто: собираем библиотеки Qt 4.8.1 с отладочной информацией (debug вариант, ключ -MDd). Потом делаем маленький тестовый проект для тестирования запроса к серверу.
И открываем оба проекта : сырцы Qt 4.8.1 (src.pro) и наш тестовый проект (назовем его my_qt_ssl.pro) в одном Qt Creator.
В результате будем запускать my_qt_ssl.pro в режиме отладки , и можно ставить точки останова в сырцах. Отладка будет останавливаться в сырцах.
Таким образом было установлено примерно такое исполнение запроса к серверу:
void QNetworkAccessHttpBackend::postRequest()
....
// Create the HTTP thread delegate
QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
....
connect(this, SIGNAL(startHttpRequest()), delegate, SLOT(startRequest()));
......
emit startHttpRequest()
.....
void QHttpThreadDelegate::startRequest()
....
QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetworkRequest &request)
Также можно в network.pro влючить дефайны отладочного вывода.
После этого не надо пересобирать все исходники src.pro , достаточно пересобрать только network.pro.
В результате по дебаг выводу стало видно, что не смотря на то , что у нас openssl 1.0.2 , qt все равно посылает первые байты такие:
0x16 0x03 0x01 0x02
16 это просто тип пакета.
А вот 3 1 означает протокол TLSv1.0.
На момент создания библиотек qt 4.8.1 (примерно 2008 г.) максимально использовали только TLSv1.0. Поэтому все логично и надо как-то библиотеки qt изменить , чтобы не использовали TLSv1.0, также кстати не использовали TLSv1.1, а использовали TLSv1.2.
# define TLS1_VERSION 0x0301
# define TLS1_1_VERSION 0x0302
# define TLS1_2_VERSION 0x0303
# define TLS_MAX_VERSION TLS1_2_VERSION
# define TLS1_VERSION_MAJOR 0x03
# define TLS1_VERSION_MINOR 0x01
# define TLS1_1_VERSION_MAJOR 0x03
# define TLS1_1_VERSION_MINOR 0x02
# define TLS1_2_VERSION_MAJOR 0x03
# define TLS1_2_VERSION_MINOR 0x03
Инициализация соединения , handshake и посылка первого пакета серверу очевидно происходит здесь:
void QSslSocketPrivate::resetDefaultCiphers()
вариант SSL_CTX *myCtx = q_SSL_CTX_new(q_SSLv23_client_method());
BC3-SHA:DES-CBC3-SHA:PSK-3DES-EDE-CBC-SHA
меняем на
SSL_CTX *myCtx = q_SSL_CTX_new(TLSv1_2_client_method());
ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:SRP-DSS-AES-256-CBC-SHA:SRP-RSA-AES-256-CBC-SHA:SRP-AES-256-CBC-SHA:DH-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DH-RSA-AES256-SHA256:DH-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DH-RSA-AES256-SHA:DH-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:DH-RSA-CAMELLIA256-SHA:DH-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:PSK-AES256-CBC-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:SRP-DSS-AES-128-CBC-SHA:SRP-RSA-AES-128-CBC-SHA:SRP-AES-128-CBC-SHA:DH-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DH-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DH-RSA-AES128-SHA256:DH-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DH-RSA-AES128-SHA:DH-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DH-RSA-SEED-SHA:DH-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:DH-RSA-CAMELLIA128-SHA:DH-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:IDEA-CBC-SHA:PSK-AES128-CBC-SHA:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:PSK-RC4-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:SRP-DSS-3DES-EDE-CBC-SHA:SRP-RSA-3DES-EDE-CBC-SHA:SRP-3DES-EDE-CBC-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DH-RSA-DES-CBC3-SHA:DH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:PSK-3DES-EDE-CBC-SHA
Обращаем внимание на функцию resetDefaultCiphers.
setSslConfiguration
defaultConfiguration
ensureInitialized
ensureCiphersAndCertsLoaded
resetDefaultCiphers
QSslCipher_from_SSL_CIPHER
Не важно какую из функций в resetDefaultCiphers мы вызовем
SSL_CTX *myCtx = q_SSL_CTX_new(q_SSLv23_client_method());
SSL_CTX *myCtx = q_SSL_CTX_new(TLSv1_2_client_method());
Список поддерживаемых наборов шифрования (cipher suites) получится такой :такой :
"ECDHE-RSA-AES256-GCM-SHA384"
"ECDHE-ECDSA-AES256-GCM-SHA384"
"ECDHE-RSA-AES256-SHA384"
"ECDHE-ECDSA-AES256-SHA384"
"ECDHE-RSA-AES256-SHA"
"ECDHE-ECDSA-AES256-SHA"
"SRP-DSS-AES-256-CBC-SHA"
"SRP-RSA-AES-256-CBC-SHA"
"SRP-AES-256-CBC-SHA"
"DH-DSS-AES256-GCM-SHA384"
"DHE-DSS-AES256-GCM-SHA384"
"DH-RSA-AES256-GCM-SHA384"
"DHE-RSA-AES256-GCM-SHA384"
"DHE-RSA-AES256-SHA256"
"DHE-DSS-AES256-SHA256"
"DH-RSA-AES256-SHA256"
"DH-DSS-AES256-SHA256"
"DHE-RSA-AES256-SHA"
"DHE-DSS-AES256-SHA"
"DH-RSA-AES256-SHA"
"DH-DSS-AES256-SHA"
"DHE-RSA-CAMELLIA256-SHA"
"DHE-DSS-CAMELLIA256-SHA"
"DH-RSA-CAMELLIA256-SHA"
"DH-DSS-CAMELLIA256-SHA"
"ECDH-RSA-AES256-GCM-SHA384"
"ECDH-ECDSA-AES256-GCM-SHA384"
"ECDH-RSA-AES256-SHA384"
"ECDH-ECDSA-AES256-SHA384"
"ECDH-RSA-AES256-SHA"
"ECDH-ECDSA-AES256-SHA"
"AES256-GCM-SHA384"
"AES256-SHA256"
"AES256-SHA"
"CAMELLIA256-SHA"
"PSK-AES256-CBC-SHA"
"ECDHE-RSA-AES128-GCM-SHA256"
"ECDHE-ECDSA-AES128-GCM-SHA256"
"ECDHE-RSA-AES128-SHA256"
"ECDHE-ECDSA-AES128-SHA256"
"ECDHE-RSA-AES128-SHA"
"ECDHE-ECDSA-AES128-SHA"
"SRP-DSS-AES-128-CBC-SHA"
"SRP-RSA-AES-128-CBC-SHA"
"SRP-AES-128-CBC-SHA"
"DH-DSS-AES128-GCM-SHA256"
"DHE-DSS-AES128-GCM-SHA256"
"DH-RSA-AES128-GCM-SHA256"
"DHE-RSA-AES128-GCM-SHA256"
"DHE-RSA-AES128-SHA256"
"DHE-DSS-AES128-SHA256"
"DH-RSA-AES128-SHA256"
"DH-DSS-AES128-SHA256"
"DHE-RSA-AES128-SHA"
"DHE-DSS-AES128-SHA"
"DH-RSA-AES128-SHA"
"DH-DSS-AES128-SHA"
"DHE-RSA-SEED-SHA"
"DHE-DSS-SEED-SHA"
"DH-RSA-SEED-SHA"
"DH-DSS-SEED-SHA"
"DHE-RSA-CAMELLIA128-SHA"
"DHE-DSS-CAMELLIA128-SHA"
"DH-RSA-CAMELLIA128-SHA"
"DH-DSS-CAMELLIA128-SHA"
"ECDH-RSA-AES128-GCM-SHA256"
"ECDH-ECDSA-AES128-GCM-SHA256"
"ECDH-RSA-AES128-SHA256"
"ECDH-ECDSA-AES128-SHA256"
"ECDH-RSA-AES128-SHA"
"ECDH-ECDSA-AES128-SHA"
"AES128-GCM-SHA256"
"AES128-SHA256"
"AES128-SHA"
"SEED-SHA"
"CAMELLIA128-SHA"
"IDEA-CBC-SHA"
"PSK-AES128-CBC-SHA"
"ECDHE-RSA-RC4-SHA"
"ECDHE-ECDSA-RC4-SHA"
"ECDH-RSA-RC4-SHA"
"ECDH-ECDSA-RC4-SHA"
"RC4-SHA"
"RC4-MD5"
"PSK-RC4-SHA"
"ECDHE-RSA-DES-CBC3-SHA"
"ECDHE-ECDSA-DES-CBC3-SHA"
"SRP-DSS-3DES-EDE-CBC-SHA"
"SRP-RSA-3DES-EDE-CBC-SHA"
"SRP-3DES-EDE-CBC-SHA"
"EDH-RSA-DES-CBC3-SHA"
"EDH-DSS-DES-CBC3-SHA"
"DH-RSA-DES-CBC3-SHA"
"DH-DSS-DES-CBC3-SHA"
"ECDH-RSA-DES-CBC3-SHA"
"ECDH-ECDSA-DES-CBC3-SHA"
"DES-CBC3-SHA"
"PSK-3DES-EDE-CBC-SHA"