首页 > 代码库 > 捉虫记:QT5.2 SSL握手失败问题
捉虫记:QT5.2 SSL握手失败问题
最近在测试项目的时候,出现了这样一个bug:在某些win7和 win8主机上,我们的客户端使用paypal进行付款时,出现SSL握手失败的问题。
项目使用QT5.2.1开发,由于QT移植了开源的webkit,我们在项目中内置了一个浏览器,用来完成商品浏览和付款。
问题来了,当然需要进行“捉虫”了。
自从上次OpenSSL爆出“心脏出血”(见wiki),我们也使用了最新的openssl代码。
首先,需要定位问题出现的位置具体在哪里。
好在QT是开源的,方便我们定位问题,开启Debug模式,修改qtbase\src\network\network.pro文件:
修改
#DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG
为
DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG
然后使用qmake / namke,重新编译network模块,这样就可以查看Debug信息。
然后,我们从log里面看到下面的信息:
verification error: dumping bad certificate
"-----BEGIN CERTIFICATE-----
MIICPTCCAaYCEQDknv3zOugOz6URPhmkJAIyMA0GCSqGSIb3DQEBAgUAMF8xCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05
NjAxMjkwMDAwMDBaFw0wNDAxMDcyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD
VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMyBQdWJsaWMgUHJp
bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB
jQAwgYkCgYEAyVxZnvIbigEUtBDfBEDb41evakVAj4QMC9Ez2dkRz+4CWB8l9yqo
RAWq7AMfeH+ek7maAKojfdashaJjRcdyJ8z0TMZ1cdI5709C8HXfCpDGjiBvmA/4
rCNfcCk2pMmG57GaIMtTpYXnPb59mv4kRTPcdhXtD6JxZExlLoFoRacCAwEAATAN
BgkqhkiG9w0BAQIFAAOBgQBhcOwvP579K+ZoVCGwZ3kIDCCWMYoNer62Jt95LCJp
STbjl3diYaIy13pUITa6Ask05yXaRDWw0lyAXbOU+Pms7qRgdSoflUkjsUp89LNH
ciFbfperVKxi513srpvSybIk+4Kt6WcVS7qqpvCXoPawl1cAyAw8CaCCBLpB2veZ
pA==
-----END CERTIFICATE-----
"
...
Issuer: O= ("VeriSign, Inc.") CN= () L= () OU= ("Class 3 Public Primary Certification Authority") C= ("US") ST= ()
...
Valid: QDateTime("1996-01-29 00:00:00.000 UTC Qt::UTC") - QDateTime("2004-01-07 23:59:59.000 UTC Qt::UTC")
然来是系统中有一个证书过期了,导致SSL验证失败。
网上百度下,发现某些WIN 7(win 8) 确实有这个问题。而这些都是操作系统自带的证书,我们当然不能在客户的电脑上面随意删除这个证书,那么只能修改QT源代码了。
通过查找,最后定位在qtbase\src\network\ssl\qsslcontext.cpp文件的180行,有下面几行代码:
foreach (const QSslCertificate &caCertificate, expiredCerts) { q_X509_STORE_add_cert(sslContext->ctx->cert_store, reinterpret_cast<X509 *>(caCertificate.handle())); }看代码,可以猜测到这里把一些过期证书添加到了SSL验证列表里面,那么,现在问题好解决,把上面的代码注释掉,从SSL验证列表里删除过期证书即可。
重新编译,调试,OK。