我在 Windows 8.1 上安装了 Qt 5.4.0,在 ArchLinux 上安装了 Qt 5.4.2,得到了完全相同的结果。
我的网站需要客户端 SSL 证书。自执行
以来,服务器似乎已正确配置openssl s_client -connect myserver:443 -cert client.crt -key client.key
打印
Verify return code: 0 (ok)
此外,
curl --cert client.pem https://myserver/
工作得很好。
服务器证书有效,浏览器接受它,等等。客户端证书是自签名的。为了以防万一,服务器是nginx,这里是相关的配置片段
listen *:443 ssl;
server_name myserver;
ssl on;
ssl_certificate /etc/nginx/ssl/myserver.crt;
ssl_certificate_key /etc/nginx/ssl/myserver.key;
ssl_dhparam /etc/nginx/ssl/myserver.dh;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_prefer_server_ciphers on;
ssl_client_certificate /etc/nginx/ssl/ca.crt;
ssl_verify_client on;
不过下面这个最简单的Qt5应用
#include <qcoreapplication.h>
#include <qfile.h>
#include <qnetworkaccessmanager.h>
#include <qnetworkconfiguration.h>
#include <qnetworkproxy.h>
#include <qnetworkreply.h>
#include <qnetworkrequest.h>
#include <qsslcertificate.h>
#include <qsslconfiguration.h>
#include <qsslkey.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QNetworkProxyFactory::setUseSystemConfiguration(true);
QSslConfiguration sslConfiguration;
QFile privateKeyFile("client.key");
privateKeyFile.open(QIODevice::ReadOnly);
QFile certificateFile("client.crt");
certificateFile.open(QIODevice::ReadOnly);
QSslKey privateKey(&privateKeyFile, QSsl::Opaque);
QSslCertificate certificate(&certificateFile);
qWarning() << QSslSocket::supportsSsl();
qWarning() << certificate.serialNumber();
qWarning() << certificate.subjectInfo(QSslCertificate::CommonName);
qWarning() << certificate.expiryDate();
sslConfiguration.setPrivateKey(privateKey);
sslConfiguration.setLocalCertificate(certificate);
QNetworkRequest networkRequest(QUrl("https://server/"));
networkRequest.setSslConfiguration(sslConfiguration);
QNetworkAccessManager networkAccessManager;
QNetworkReply* networkReply = networkAccessManager.get(networkRequest);
QEventLoop loop;
QObject::connect(&networkAccessManager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
loop.exec();
qWarning() << networkReply->error();
qWarning() << networkReply->errorString();
delete networkReply;
return a.exec();
}
在 Windows 上出现以下控制台输出失败
QSslSocket: cannot resolve TLSv1_1_client_method
QSslSocket: cannot resolve TLSv1_2_client_method
QSslSocket: cannot resolve TLSv1_1_server_method
QSslSocket: cannot resolve TLSv1_2_server_method
QSslSocket: cannot resolve SSL_select_next_proto
QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb
QSslSocket: cannot resolve SSL_get0_next_proto_negotiated
true
"01"
("AA-00-00-00")
QDateTime("2035-06-21 21:41:13.000 UTC Qt::UTC")
99
"Unable to init SSL Context: "
以及 Linux 上的以下控制台输出
true
"01"
("AA-00-00-00")
QDateTime("2035-06-21 21:41:13.000 UTC Qt::UTC")
99
"Unable to init SSL Context: "
如果我删除“networkRequest.setSslConfiguration(sslConfiguration);”我刚从服务器收到 400 错误,指出我需要发送客户端证书。
添加“sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);”没有任何改变。
我很乐意得到任何可能导致 Qt5 代码失败的建议。
最佳答案
Qt 在运行时解析 OpenSSL 函数,这些警告是它的结果。可能是您的程序根本找不到 OpenSSL,或者它找到的版本太旧。从 Qt 5.2 开始,需要 OpenSSL v1.0.0 或更高版本。
来自 Qt documentation :
Support for Secure Sockets Layer (SSL) communication is provided by the OpenSSL Toolkit, which must be obtained separately.
From Qt version 5.2 onwards, the officially supported version for OpenSSL is 1.0.0 or later. Versions >= 0.9.7 and < 1.0.0 might work, but are not guaranteed to.
关于Qt5客户端证书认证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31039631/