Trouble getting POCO HTTPSClientSession to send a

2019-04-11 04:12发布

问题:

I'm trying to use the POCO libraries to write a program that makes an HTTPS request to a server. For testing purposes, I'm connecting to a server which has a self-signed certificate, and I want to allow the client to connect anyway. To allow that to happen, I've attempted to install an InvalidCertificateHandler which is an instance of AcceptCertificateHandler - which I thought would accept the certificate even though it's not signed. Here's the code I'm using:

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;
        }   

When I run this code, I get the following output:

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

My expectation was that since I'm using the AcceptCertificateHandler, the certificate would be accepted even though it is not valid. What might I be doing wrong?

A couple notes:

  1. In the Context object constructor call, I'm passing empty strings for privateKeyFile, certificateFile, and caLocation arguments. The reason I did this is because I think that as a client I don't need a private key, client certificate, or certificate authority certificates. Maybe this is the problem?
  2. In the call to initializeClient, I'm passing NULL as the PrivateKeyPasshraseHandler - because I'm not using a private key for the client.
  3. I'm not calling Context::useCertificate() before using the Context object. The docs say you need to call either userCertificate() or usePrivateKey(), but I wasn't sure what to pass or if this was required for client, or only for a server. Maybe this is the problem?

回答1:

I found that same error occurs if you connect to server by hostname which is not equal to hostname coming in certificate of the server during the TLS (probably SSL too) handshake. Using right hostname in Poco::Net::HTTPSClientSession theSess(myHostName, myHostPort); solve this problem.

In my case right name was in field CN of certificate, I found it by follow command (for exmaple for wikipedia):

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

In output we see:

<...>
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
<...>

There is it: CN=*.wikipedia.org, so using any of %domain%.wikipedia.org as hostname should be ok.

P.S. By the way, there may be some exception class for SSL related errors in Poco with more verbose error message.



回答2:

After further experimenting, the problem turned out to be that the certificate on the server was not only self-signed, it was also expired. I tried connecting to different servers and found that I was able to. So it appears that the library will not accept an expired certificate, even when using an AcceptCertificateHandler.

After updating the certificate so it's no longer expired, was able to make the connection.



回答3:

I was stuck exactly with this issue, it turned out to be the certificates CN. Apparently in POCO you can disable the verification using configuration option openSSL.client.extendedVerification = false or pContext->enableExtendedCertificateVerification(false);