SSL握手成功后如何获取peer的QSslCertificate

Posted

技术标签:

【中文标题】SSL握手成功后如何获取peer的QSslCertificate【英文标题】:How to obtain peer's QSslCertificate after successful SSL handshake 【发布时间】:2015-03-02 15:49:10 【问题描述】:

当使用 Qt 进行 HTTPS 请求时,我尝试在 SSL 握手后获取对等方的证书,以便跟踪证书的未来变化。

QNetworkAccessManager nam;
nam.get(QNetworkRequest(QUrl("https://google.com/")));    // example URL

QObject::connect(&nam, &QNetworkAccessManager::encrypted, [](QNetworkReply *reply)
    qDebug() << reply->sslConfiguration().peerCertificate();
);

根据documentation of QNetworkAccessManager::encrypted,上面的代码应该可以访问服务器的证书:

当 SSL/TLS 会话成功完成初始握手时会发出此信号。此时,尚未传输任何用户数据。该信号可用于对证书链执行额外检查,例如在网站证书发生更改时通知用户。如果回复不符合预期标准,则应通过连接到此信号的插槽调用 QNetworkReply::abort() 来中止它。可以使用 QNetworkReply::sslConfiguration() 方法检查正在使用的 SSL 配置。

另外,来自documentation of QSslConfiguration::peerCertificate()

因为对等证书是在握手阶段设置的,所以从连接到 QSslSocket::sslErrors() 信号、QNetworkReply::sslErrors() 信号或 QSslSocket::encrypted 的插槽访问对等证书是安全的() 信号。

但是,证书始终为空。上述代码的调试输出(进入应用的事件循环后)为:

QSslCertificate( "" , "" , "1B2M2Y8AsgTpgAmY7PhCfg==" , () , () , QMap() , QDateTime(" Qt::LocalTime") , QDateTime(" Qt::LocalTime") )

另一方面,如果遇到 SSL 错误,并且如果我连接到 sslErrors,我确实会获得证书。例如,对于 Ubuntu / Apache 下的默认证书,由于证书中缺少主机名而未被 Qt 接受,我得到 "https://localhost" 以下内容:

QSslCertificate( "3" , "95:b0:93:f2:16:bb:22:cb" , "cXB6WctE7oZsrvZLU2BWUw==" , () , () , QMap() , QDateTime("2014-07-10 23:04:06.000 UTC Qt::UTC") , QDateTime("2024-07-07 23:04:06.000 UTC Qt::UTC") )

SSL 握手成功后如何获取证书?

我使用 QNetworkAccessManager 的信号以及 QNetworkReply 的信号进行了测试;结果是一样的。


MCVE 可以在https://bitbucket.org/leemes/ssltest找到,随意克隆和摆弄:

git clone https://bitbucket.org/leemes/ssltest.git

我使用 Qt 5.4.0 和 Qt 5.3.1 进行了测试;结果是一样的。

【问题讨论】:

【参考方案1】:

这是 Qt 5.4.0 之前的一个错误。它已在 Qt 5.4.1 中修复。

https://bugreports.qt.io/browse/QTBUG-40401

【讨论】:

以上是关于SSL握手成功后如何获取peer的QSslCertificate的主要内容,如果未能解决你的问题,请参考以下文章

HTTPS|SSL笔记-SSL双向认证成功握手过程(含wireshark分析)

Android Studio的安装及"SSL peer shut down incorrectly"问题

当 curl 成功时,Java HTTPS 客户端失败 SSL 握手

javax.net.ssl.SSLHandshakeException:握手期间远程主机关闭连接

BT客户端实现 Peer协议设计

已成功与服务器建立连接,但是在登录前的握手期间发生错误。 (provider: SSL Provider, error: 0 - 等待的