Qt Openssl之TLS initialization failed问题溯源

本文介绍了在Qt环境中遇到QSslSocket TLS初始化失败的问题,问题源于缺少或版本不匹配的openssl动态库。通过检查Qt源码定位到问题关键函数,分析了QSslSocket的错误提示。解决方案包括确保程序运行目录包含正确版本的openssl库,避免版本不兼容问题。同时,建议在部署时安装兼容的openssl库,并在代码中添加检测openssl环境的机制,以提供更清晰的错误信息。
摘要由CSDN通过智能技术生成


QSslSocket 之 TLS initialization failed 问题

背景介绍:

Qt使用openssl进行客户端和服务端https通信,当部署程序到新主机时,出现上述QSslSocket的TLS初始化失败问题。该问题的根源在于发布程序中并没有包含openssl动态库(或者包含错误的版本),而且新机器上也没有安装openssl动态库。
以下形式均是同一问题:

qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed
QSslSocket::connectToHostEncrypted: TLS initialization failed
QSslSocket::startClientEncryption: TLS initialization failed
QSslSocket::startServerEncryption: TLS initialization failed

我们知道,openssl的动态库只有两个。目前最新的长期支持版1.1.1,64位是这两个,libssl-1_1-x64.dll和libcrypto-1_1-x64.dll。
libssl库实现了所有的TLS协议版本,包括最新的TLSv1.3。
libcrypto库包括一套特别完备的通用的密码学(cryptography)库。这个库是TLS的基础,但是又完全可以单独作为一个加密解密的库来使用。
注意,以前的版本使用的是动态库libeay32.bll和ssleay32.bll,但是官方强烈推荐不要再使用旧版,应该尽快使用新版1.1.1的库。

问题定位:

由报错信息定位到Qt源码文件qsslsocket.cpp。

void QSslSocket::connectToHostEncrypted();

在这里插入图片描述
同理,在 void QSslSocket::startClientEncryption(); void QSslSocket::startServerEncryption(); 中均有同样的信息。
这个supportSsl()函数正是检测当前系统环境是否支持openssl,也就是是否存在上述两个动态库。
void QSslSocket::connectToHostEncrypted(); 用来客户端发起一个SSL握手的加密连接,包含调用startClientEncryption()。
void QSslSocket::startServerEncryption();用来服务端发起一个SSL握手的加密连接。
void QSslSocket::startClientEncryption();一般不直接使用,而使用connectToHostEncrypted()替代。

由上可知,服务端程序和客户端程序在检测到当前系统环境不支持openssl时,都可能出现上述初始化失败的错误。

问题解决:

  1. 发布使用了Openssl的程序时,记得要把编译时使用的Openssl库的动态库拷贝到程序运行目录中,libssl和libcrypto。
    注意这种方式,要特别注意版本问题。因为主机上可能有很多程序都包含openssl动态库,也可能安装了多个版本的openssl库。当部署时如果稀里糊涂地拷贝了一个版本的库,而没有使用编译时链接的库,就会导致不同版本间有时会不兼容的问题。
    比如,这次的情况是: 通过QSslSocket::sslLibraryBuildVersionString()得到程序构建时的openssl库版本是1.1.1g,而发布程序时在程序主目录里导入了安装的openssl库libssl-1_1-x64.dll和libcrypto-1_1-x64.dll,版本为1.1.1j,但是程序运行时就是检测不到openssl,也即QSslSocket::supportsSsl()为false。后来,下载并更换了最新的openssl库,版本为1.1.1k,程序成功检测到了openssl,并能正常使用。由上可得结论,似乎是1.1.1g不兼容1.1.1j,但是兼容1.1.1k。具体原因有待将来深入认识再下结论。

    查看openssl动态库的版本,只需查看相应文件属性即可,如下:
    在这里插入图片描述

  2. 在部署机器上,预安装兼容程序版本的Openssl库。
    推荐一个网站:
    window平台预编译的openssl库的网站:
    http://slproweb.com/products/Win32OpenSSL.html
    在这里插入图片描述

    如果仅仅是安装个openssl库环境而不做二次开发,选择Light版即可。另外,注意安装过程中,记得选择“拷贝库文件到系统目录中”,系统目录已经在环境变量中,这样该目录下的动态库可以被其他程序运行时加载。

经验积累:

代码中可以增加系统对openssl的支持情况的检测,使用 QSslSocket::supportsSsl() ,即可检测程序运行时平台是否具备openssl的环境,如检测不到,直接抛出更直接明了,可读性性更强的报错即可,而不使用默认的TLS initialization failed提示。
另外,可以增加qDebug() << QSslSocket::sslLibraryBuildVersionString();日志,和 qDebug() << QSslSocket::sslLibraryVersionString()日志,一个输出程序编译时指定的openssl库的版本,一个输出程序运行时检测到的openssl库的版本,这样有助于帮助分析一些奇怪问题。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值