Validating a host using SSL Wildcard certificates - c++

My HTTPS Client uses Poco C++ to connect with our server, which uses a wildcard certificate (*.example.com). The connection fails with a CertificateValidationException and the error message is "Unacceptable certificate from x.y.z.w: application verification failure".
The weird thing is it doesn't ALWAYS fail, just most of the time. After much debugging, my hunch is it has something to do with topology (going across subnets, for example) or with how/when the host name is translated to an I.P. address.
I think this because in cases where everything works as expected, the local DNS is routing the host name. But in cases where it doesn't work (above error message), the host name translation is on a local box like my PC.
Is there a way to narrow down what's going on here? Is this a common or known problem?
Thanks.

I just ran into this same symptom myself. Using Poco::Net::HTTPSClientSession, I could connect just fine to non-wildcard sites, but failed with the exception and message mentioned above when connecting to *.example.com wildcard sites. Note however that the behavior I observed was 100% consistent, never intermittent.
After debugging through Poco source code, I found the problem in how the HTTPSClientConnection class sets itself up to perform certificate validation. I filed Poco issue #1303 on pocoproject.org, but the skinny is that if you create an HTTPSClientSession using the no-arg constructor, you will always get this exception when connecting to server with a wildcard cert. For example:
Poco::URI uri("http://blah.example.com"); // SSL cert is for *.example.com
Poco::Net::HTTPSClientSession session; // Note no-arg constructor
session.setHost(uri.getHost());
session.setPort(uri.getPort());
Poco::Net::HTTPRequest req;
// Populate req...
session.sendRequest(req); // Throws CertificateValidationException:
// "Unacceptable certificate from x.x.x.x,
// application verification failure"
The problem is that when validating the cert, the various Poco::Net classes look up the peer name as an IP address if the hostname hasn't been set already, and then subsequently try to match that IP addr against the wildcard cert CN (obviously, x.y.z.w will fail to match against *.example.com).
The good news is that there are several easy workarounds. The easiest is to just use the HTTPSClientSession(host, port) constructor, which will set the proper host name on the underlying SecureStreamSocket so that subsequent certificate validation matches a real hostname (blah.example.com) against the cert (CN=*.example.com), instead of an IP addr:
Poco::URI uri("http://blah.example.com");
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort()); // Calls SecureStreamSocket::setPeerHostName() internally
There are other workarounds, too: create your own SecureStreamSocket first, call setPeerHostName() on it, and then pass that into the appropriate HTTPSClientSession constructor, etc. See the issue tracker link above for a few more ideas if needed.

Related

How to enable Cipher TLS_ECDHE_ECDSA on Windows server 2019 with AWS Load Balancer

The website is on Windows server 2019 with the AWS Load Balancer with ELB SecurityPolicy-2016-08. This policy definitely has the ECDHE_ECDSA cipher enabled. I have checked their docs. SSL certificate is installed on LB.
Running TLS Cipher Suites in PowerShell Windows server 2019 also shows these suits enabled but when running the website domain with SSLLabs or Zenmap. These suites are not appearing
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
or even these:
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
any ideas? the website is ASP.NetFramework 4.7. but I hardly think it has anything to do with the ciphers. Any help will be appreciated. Thanks
Zenmap Snapshot
AWS load balancer Snapshot
PowerShell Snapshot
Meta: this isn't about programming, and I'm not sure 'how to operate cloud' counts as development, so I authorize deletion if this is voted offtopic.
Your server is irrelevant and nothing you set or change on it will affect client(s).
You don't tell us which AWS load balancer you use but to be at HTTPS level it must be Application or Classic, and in either case to do HTTPS it must terminate the SSL/TLS protocol -- in other words, the LB establishes one SSL/TLS connection with the client and decrypts the incoming request, parses it, and then optionally uses a separate SSL/TLS connection to the backend to re-encrypt, and reverses the process on the response: decrypt from the backend if necessary and re-encrypt to the client. See the line "SSL Offloading" well down in the table on that page; that's a jargon way of saying "LB does the SSL/TLS for the client, your server does not".
Thus the settings in the LB, only, control the SSL/TLS seen by the client(s). ELBSecurityPolicy-2016-08 which is the default (and I'm guessing that might be why you used it) excludes all DHE-RSA ciphersuites. (To avoid confusion, note the AWS webpage uses the OpenSSL names for ciphersuites, where RSA-only keyexchange is omitted from the name, whereas Zenmap/nmap uses the RFC names TLS_RSA_with_whatever.) It does allow ECDHE_ECDSA suites, but those will actually be negotiated, and thus seen by a scanner like Zenmap/nmap, only if you configure an ECDSA certificate and key -- which I bet you didn't.

How to bind specific source IP address using Poco::Net::HTTPSClientSession

I have a https client that can run on one of two redundant hosts. Would like the host that is the 'Active' client host to use a specific IP address as the source address so that traffic appears to be coming from one source. Low level OS network setup to allow this is all in place. Our https client is built using the Poco::Net::HTTPSClientSession class.
From reading about this situation binding the shared source IP address to the client socket is the standard solution. Attempted the following code:
// set the shared IP address and use 0 (represents wildcard) for port
Poco::Net::SocketAddress sa = Poco::Net::SocketAddress(ipAddress, 0);
// bind the shared IP address to the socket
Poco::Net::SecureStreamSocket sss;
sss.impl()->bind(sa);
Poco::Net::HTTPSClientSession session(sss);
Unfortunately, this doesn't work as the bind() is throwing Poco::InvalidAccessException and exception message is "Cannot bind() a SecureStreamSocketImpl". Looked at the Poco source and bind() is just throwing this exception. Seems to not be allowed.
How to make this work with Poco::Net::HTTPSClientSession class?
Is it even possible to make it work with this class?
Not currently possible - there is a pending issue for it. It will be done eventually but currently there's no timeframe.

UnableToStartHostException for any hostname except localhost

Using Grapevine if I change the host to anything except "localhost" (or equivalent, 127.0.0.1/0.0.0.0) I will receive the following message:
Exception thrown: 'Grapevine.Exceptions.Server.UnableToStartHostException' in Grapevine.dll
I have tried: "*", "+" and an explicitly configured hostname (ie. "me.example.com").
There is no reason that this should fail at all, there is no other program or service using the hostname or port specified on any of the computers on this network, the ports are appropriately forwarded on both my router and firewall (even disabled the firewall and opened all ports temporarily to test).
Grapevine is using HttpListener under the hood. This answer to a similar question will likely solve your issue.

libcurl use same user defined port to send periodic request

I am working on a project need to send periodic alive message to https server.
Because of security issue, we need to use minimal number of ports (blocking unused ports as many as we can).
I am using c++ libcurl easy interface to send https request in linux.
I have tried to use the same curl handler object (CURL object) and set CURLOPT_LOCALPORT to a port number. The first request is ok. But in the second, libcurl verbose mode said address already in use.
However, when I comment out the port set through CURLOPT_LOCALPORT, it works on second connection also, and by setting VERBOSE to 1, I can see "Re-using existing connection" print out, which is missing in version setting up local port.
And I check with linux netstat, find out that it is using the same port.
I cannot figure out why setting up local port will make it failed.
And also, I have tried to close the connection using curl_easy_cleanup, but due to tcp time_wait state, we cannot reuse the port in a while, that's not what I want.
Could anyone provide a solution or suggestion to us? Thanks a lot.
Edit
My reason using one port is not to keep opening and closing connection too much.
Because of the security issue ...
There is no security issue. You need to get over this phobia about using multiple local outbound ports. There is zero security benefit in using fewer, or in constraining them in any way.

OpenSSL or LibreSSL C++ sample for client TLS connection

I am searching for a client TLS connection example in C++. Best for Visual Studio, but honestly it can be any compiler. I found several C samples. But no one worked. I started with this sample in C:
https://wiki.openssl.org/index.php/SSL/TLS_Client
But it failes on
res = BIO_do_connect(web);
with "system library" if I want to connect to my own node.js server (using the direct ip address) or with "bad hostname lookup" using encrypted.google.com as url.
Both with libressl and Visual Studio 2013.
Next stop: http://fm4dd.com/openssl/sslconnect.htm
Here the program runs successful. But any attempt to write to the SSL connection at the end with:
std::string json = "{'test':'huhu'}";
char buff[1024];
sprintf(buff, "POST /test.de HTTP/1.1 \nHost: test.de\nContent-Type: application/json\nContent-Length: %d\n\n", json.length());
std::string post = buff;
int snd = SSL_write(ssl, post.data(), post.length());
snd = SSL_write(ssl, json.data(), json.length());
forces the server to close the connection (I do not see exactly what happend as I do not now how I can tell node.js to tell me more).
So I search for a working sample or how to get a TLS connection with own certificate running in C++
I am searching for a client TLS connection example in C++.
I think there are a couple of ports of OpenSSL to C++. They try to do the full class wrapper thing. See openssl++ class on Google.
When I use it in C++, I use unique pointers for cleanup. See, for example, How to properly print RSA* as string in C++?. I use it primarily to ensure cleanup. I think its similar to Resource Acquisition Is Initialization pattern.
OpenSSL also provides a page for similar libraries and frameworks. See the Related Links page on the OpenSSL wiki.
But it fails on
res = BIO_do_connect(web);
with "system library" if I want to connect to my own node.js server (using the > direct ip address) or with "bad hostname lookup"
My guess here would be the name in the certificate does not match the name used in the URL to connect.
You can make the names work by adding an entry in your host file. Effectively, this is your local DNS override. See Microsoft TCP/IP Host Name Resolution Order.
Or, you can generate a certificate with all the required names. For that, see How to create a self-signed certificate with openssl?
forces the server to close the connection (I do not see exactly what happend as I do not now how I can tell node.js to tell me more).
"POST /test.de HTTP/1.1 \nHost: test.de\nContent-Type:
application/json\nContent-Length: %d\n\n"
Since you lack the Connection: close request header, the server is probably following RFC 7230, HTTP/1.1 Message Syntax and Routing, Section 6.1:
A server that does not support persistent connections MUST send the
"close" connection option in every response message that does not
have a 1xx (Informational) status code.
Also, that should probably be:
"POST /test.de HTTP/1.1\r\nHost: test.de\r\nContent-Type:
application/json\r\nContent-Length:%d\r\n\r\n"
\r\n is used as new line, not \r and not \n. A double \r\n is used to terminate the header. You can quickly verify be searching for "CRLF" in the standard. You will land in a discussion of the ABNF grammar.
So I search for a working sample or how to get a TLS connection with own certificate running in C++
The trick here is creating a well-formed certificate. For that, see How to create a self-signed certificate with openssl?
Here's an updated example for LibreSSL using pinned cert bundle: C++ libtls example on github