QSslCertificate 如何获取 Windows 中显示的公钥

Posted

技术标签:

【中文标题】QSslCertificate 如何获取 Windows 中显示的公钥【英文标题】:QSslCertificate how to get public Key as displayed in Windows 【发布时间】:2017-03-14 21:33:46 【问题描述】:

Windows 在 Chrome 中查看证书详细信息时显示的给定证书的公钥与 Qt 在连接到加密信号的插槽中返回的公钥不同。

auto onEncrypt = [](QNetworkReply* rpl) 
    auto cert = rpl->sslConfiguration().peerCertificate();
    auto publicKey = cert.publicKey();

    QString winHexKey = "3082010a0282010100d8..."; // as displayed in cert info of Chrome on Windows for the Public Key
    auto windowsKey = QByteArray::fromHex(winHexKey.toUtf8());
    if (windowsKey == publicKey.toPem())
        std::cout << "PEM key matched\n";
    else if (windowsKey == publicKey.toDer())
        std::cout << "DER key matched\n";
    else if (winHexKey == publicKey.toPem().toHex())
        std::cout << "Hex PEM key matched\n";
    else if (winHexKey == publicKey.toDer().toHex())
        std::cout << "Hex DER key matched\n";
    else
        std::cout << "No match!\n";
    std::cout << publicKey.toPem().toHex().toStdString() << '\n'; // 902 characters worth starting with 2d2d2d2d2d
;
QNetworkAccessManager mgr;
QObject::connect(&mgr, &QNetworkAccessManager::encrypted, onEncrypt);
QNetworkRequest r(QUrl::fromUserInput("https://www.qt.io"));
mgr.get(r);

总是导致不匹配。有趣的是,公钥的十六进制输出比 Windows 显示的要大得多。

如何获取服务器提供的证书的公钥,并根据证书中的内容进行验证?

【问题讨论】:

【参考方案1】:

如何获取服务器提供的证书的公钥

公钥是证书的一部分。证书还将包含散列,它可以对证书内容进行一些基本的完整性检查。要检查服务器是否确实与证书匹配,您必须尝试建立加密通道。服务器以与从客户端观察到的证书一致的方式引导加密通道 - 也就是说,服务器与为其提供的证书匹配;或者它没有——这是引起警报的原因。

根据证书中的内容进行验证?

X.509 证书还包含哈希,可用于完整性检查。

Chrome 显示的内容与您的代码执行的操作之间的差异在于 Chrome 会解码 PEM/DER/BER。 DER/BER 添加一些额外的元数据来描述字段类型和长度等内容; PEM 是底层 X.509 证书内容的特定编码。

【讨论】:

但这并不能真正回答我的问题。是的,公钥是证书的一部分,但我需要验证它以确保它是预期的证书(因此是真正的服务器),而不仅仅是一些自签名证书(如果添加到信任库,它也会被信任) ) 某处。也不能使用指纹,因为如果更新证书,指纹就会改变,而公钥不一定会改变。 从您的问题中看不出您知道这一点。如果您期望某个公钥,则通过扩展您期望签名的某个值。 CN 等其他字段毕竟也不应该改变。 X.509 证书的重点是您并不真正关心服务器的特定密钥是什么,而是任何与证书匹配的密钥都可以,并且您拥有从证书到 CA 的外部信任链到客户端信任库来验证该事实【参考方案2】:

如果您想发送带有对等验证的请求,则无需手动验证。使用 QSslConfiguration 并将 Chrome 中的证书文件设置为 CA 证书。示例:

QSslConfiguration config = QSslConfiguration::defaultConfiguration();
// Load certificate from file to QByteArray chromeCertificateByteArray
QSslCertificate ca = QSslCertificate(chromeCertificateByteArray); 
QList <QSslCertificate> caList;
caList.append(ca);
config.setCaCertificates(caList);

QNetworkRequest request(QUrl::fromUserInput("https://www.qt.io"));
request.setSslConfiguration(config);

QNetworkAccessManager networkManager;
QNetworkReply* reply = networkManager.get(request);

【讨论】:

那么只需使用 CA 链并使其成为该连接唯一接受的 CA 吗?如果证书被更新并且 CA 决定使用另一个中间证书怎么办?或者更改他们的根证书以进行签名?在那种情况下,如果我做对了,它就会失败。

以上是关于QSslCertificate 如何获取 Windows 中显示的公钥的主要内容,如果未能解决你的问题,请参考以下文章

想在wind中试验python接口,该怎么做到

matlab 如何从wind中获取股票数据 收盘 开盘 最高 最低 交易量

在 World Wind 显示中获取 JPopupMenu

JavaFX,NASA World Wind:如何将 JavaFX 组添加到 NASA World Wind Model

wind能帮忙加工数据吗

python金融分析小知识(27)——如何通过python连接Wind(万得)数据库