【问题标题】:Trouble getting POCO HTTPSClientSession to send a request - certificate verify failed无法让 POCO HTTPSClientSession 发送请求 - 证书验证失败
【发布时间】:2013-06-27 22:12:09
【问题描述】:

我正在尝试使用 POCO 库编写一个向服务器发出 HTTPS 请求的程序。出于测试目的,我正在连接到具有自签名证书的服务器,并且我希望允许客户端连接。为了让这种情况发生,我尝试安装一个InvalidCertificateHandler,它是AcceptCertificateHandler 的一个实例——我认为它会接受证书,即使它没有签名。这是我正在使用的代码:

try {
            Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> pAcceptCertHandler =
                                             new Poco::Net::AcceptCertificateHandler(true);
            Poco::Net::Context::Ptr pContext =
                new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "",
                                       "","",Poco::Net::Context::VERIFY_RELAXED,
                                       9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
            SSLManager::instance().initializeClient(NULL, pAcceptCertHandler, pContext);

            Poco::Net::HTTPSClientSession theSess(myHostName,myHostPort);

            // Create the HTTP request object
            Poco::Net::HTTPRequest request("POST",
                              "https://myservername.com/MockServlet/activateEnc","1.1");

            // Send the request
            std::cout << "Debug point A" << std::endl;
            std::ostream& aStream = theSess.sendRequest(request);
            std::cout << "Debug point B" << std::endl;
            if (aStream.fail()) {
                std::cout << "Fail to send HTTP request for activateEnc" << std::endl;
                return WSERR_CONNECTION_ERR;
            }   
        } catch (Poco::Exception& exc) {
            std::cout << "Exception caught while attempting to connect." << std::endl;
            std::cerr << exc.displayText() << std::endl;
            return WSERR_CONNECTION_ERR;
        }   

当我运行这段代码时,我得到以下输出:

Debug point A
Exception caught while attempting to connect.
Certificate validation error: Unacceptable certificate from myservername.com: application verification failure

我的期望是,由于我使用的是 AcceptCertificateHandler,因此即使证书无效,它也会被接受。我可能做错了什么?

几个注意事项:

  1. 在 Context 对象构造函数调用中,我为 privateKeyFile、certificateFile 和 caLocation 参数传递了空字符串。我这样做的原因是因为我认为作为客户端我不需要私钥、客户端证书或证书颁发机构证书。也许这就是问题所在?
  2. 在调用 initializeClient 时,我将 NULL 作为 PrivateKeyPasshraseHandler 传递 - 因为我没有为客户端使用私钥。
  3. 在使用 Context 对象之前,我没有调用 Context::useCertificate()。文档说您需要调用 userCertificate() 或 usePrivateKey(),但我不确定要传递什么,或者客户端是否需要,或者仅服务器需要。也许这就是问题所在?

【问题讨论】:

    标签: c++ openssl poco-libraries


    【解决方案1】:

    我发现如果您在 TLS(也可能是 SSL)握手期间通过主机名连接到服务器,该主机名不等于服务器证书中的主机名,则会发生同样的错误。在Poco::Net::HTTPSClientSession theSess(myHostName, myHostPort); 中使用正确的主机名可以解决这个问题。

    在我的情况下,正确的名称在证书的字段 CN 中,我通过以下命令找到它(例如维基百科):

    openssl s_client -connect en.wikipedia.org:443 -tls1 -state
    

    在输出中我们看到:

    <...>
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIKCTCCCPGgAwIBAgIQARQZX2b6/4/WbhJJblFvTzANBgkqhkiG9w0BAQUFADBm
    <...>
    JW1fZqU0WxncxV8AfXeWfKzI1vkil45CJ4g++7U=
    -----END CERTIFICATE-----
    subject=/C=US/ST=California/L=San Francisco/O=Wikimedia Foundation, Inc./CN=*.wikipedia.org
    <...>
    

    有它:CN=*.wikipedia.org,所以使用任何%domain%.wikipedia.org 作为主机名应该没问题。

    附:顺便说一句,Poco 中可能存在一些与 SSL 相关的错误的异常类,并带有更详细的错误消息。

    【讨论】:

      【解决方案2】:

      经过进一步实验,问题原来是服务器上的证书不仅是自签名的,而且还过期了。我尝试连接到不同的服务器,发现我能够。因此,即使使用 AcceptCertificateHandler,库似乎也不会接受过期的证书。

      更新证书使其不再过期后,能够建立连接。

      【讨论】:

      • 连接到 smtp.gmail.com 时出现此错误...有什么建议吗?你认为谷歌在某处有过期的证书吗?我间歇性地得到它,但一天几次,比如 5 或 6 次。
      • 这里只是在黑暗中拍摄:可能是因为谷歌的两步验证(见下面的cmets答案):stackoverflow.com/questions/11183738/…
      【解决方案3】:

      我完全被这个问题所困扰,原来是证书 CN。显然在 POCO 中,您可以使用配置选项 openSSL.client.extendedVerification = falsepContext-&gt;enableExtendedCertificateVerification(false); 禁用验证

      【讨论】:

        猜你喜欢
        • 2013-09-30
        • 1970-01-01
        • 2015-07-26
        • 2015-10-19
        • 2020-08-14
        • 2014-03-28
        • 2018-03-16
        • 1970-01-01
        • 2021-11-10
        相关资源
        最近更新 更多