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
Related
I'm trying to send a client certificate to a webserver that requires it.
If I make the request from the command line curl command, it works.
I pass --key filename and --cert filename and everything works fine.
When I do it from the libcurl library, I do this:
curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert_file.c_str());
curl_easy_setopt(curl, CURLOPT_SSLKEY, client_key_file.c_str());
Same exact thing, the server says the client certificate is missing.
I tried doing things like giving it a nonexistent filename in hopes of provoking some other error messages that might give me a clue what's wrong, but libcurl (and command line curl for that matter) with verbose on don't yield any error messages when something goes wrong. Surely there's a failure case, but nothing is yielding me any kind of error to follow up on.
Is there any way to get more diagnostics out of libcurl?
Pulling what's left of my hair out here.
This is on windows 10 by the way, we built libcurl ourselves. SSL is built in, https connections work, I just can't get it to send the client cert and there's no indication what's going wrong.
UPDATE:
I think I found my problem...
https://curl.haxx.se/docs/todo.html#Add_support_for_client_certifica
Does anybody know how to make this work?
Okay so I worked something out.
It turns out you can build libcurl on windows with openssh or schannel.
If you use schannel, then the CURLOPT_SSLCERT and CURLOPT_SSLKEY do nothing. (no warning or error mind you.)
Maybe they do do something, in relation to schannel, but I couldn't find any docs on that.
So in short if you build libcurl with openssl you can supply a client cert to send in the TLS handshake.
The tipoff was here:
https://curl.haxx.se/docs/todo.html#Add_support_for_client_certifica
Support for CURLOPT_SSLCERT in conjunction with WinSSL/SChannel was added in curl 7.60.0 (changelog).
As the documentation for CURLOPT_SSLCERT states:
Client certificates must be specified by a path expression to a certificate store. [...] You can use "<store location>\<store name>\<thumbprint>" to refer to a certificate in the system certificates store, for example, "CurrentUser\MY\934a7ac6f8a5d579285a74fa61e19f23ddfe8d7a". [...] Following store locations are supported: CurrentUser, LocalMachine, CurrentService, Services, CurrentUserGroupPolicy, LocalMachineGroupPolicy, LocalMachineEnterprise.
I developed a SSLProxy as a man in the middle between client and server. Handshaking between client-proxy and proxy-server doing well. I receive a message from client and decrypt it with client_side SSL. Then encrypt it with server_side SSL. All thing is good except on thing: OpenSSL received all the message data in one SSL record but it sent them in 2 SSL records.
Question: How can I force OpenSSL to send data in 1 SSL record, because server configured only to use 1 SSL record?
Wireshark Screen:
192.168.2.127 is client.
192.168.0.230 is server.
Update: I need something like this. I tried to use them but I faced with this error:
error: ‘SSL_CTX_set_split_send_fragment’ was not declared in this scope
With SQL Server 2008 R2 SP3 and update KB3144114 to support TLSv1.2 my problem solved. But In SQL Server 2008 R2 (with TLSv1) problem still remain same as before and I couldn't find any solution for it.
You must use OpenSSL 1.1.X series for using "SSL_CTX_set_split_send_fragment function", that function is not available in older versions.
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.
I'm trying to work with Boost Asio instead of RakNet so I was trying to follow along with the examples on the Boost website but I have some questions left unanswered. Here's the link: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/tutorial/tutdaytime1.html
Just a heads up, I got the tutorial working, both the client and the server.
1) Why does the query need the string "daytime"? It's nowhere to be found in the server setup. The client only seems to connect when I'm using that string. (Tried with "test" and it didn't connect)
2) Why don't I need to give the client a port to connect to? Does it search for this port itself or is there and option to set this up manually as well?
Thanks in advance.
tcp::resolver::query query(argv[1], "daytime");
This lines resolves an endpoint, where argv[1] is the host, and "daytime" represents the port. Yeah, that's a little surprising, as you'd expect something like 80 or 443 there. However, what you see is the service-name which (like hostnames) can be used instead of a hardcoded port, and gets resolved by the operating system.
If hostnames are resolved via /etc/hosts, services are resolved via /etc/services (or C:\WINDOWS\system32\drivers\etc\services I suppose).
On my system this file contains:
daytime 13/tcp
daytime 13/udp
So, in fact you could just use "13" instead of "daytime". Note that this is the default port for the system daytime service. It "works" because your system answers on that port. (Or because your server is already running and uses that port, I don't know which server you run and how :))
Note: If you dont have time to read this long journey, the solution (with sourcecode) is here: http://www.coastrd.com/smtps.
For a long time sending email uing SMTP (port 25) via a remote mail server (usually at the website hosting company) was easy to do with an application. Open a TCP port 25, send "HELO ..." etc
To do this using googles email service is giving me a problem because they insist on using port 465 SMTPS ie SMTP with TLS encryption:
http://en.wikipedia.org/wiki/Transport_Layer_Security#How_it_works
In researching a way to do this with a language like C++ or a flavor of basic, i came across:
http://forums.realsoftware.com/viewtopic.php?f=2&t=29542
http://forums.realsoftware.com/viewtopic.php?f=2&t=26959&p=162671#p162671
and a Python question:
python smtp gmail authentication error (sending email through gmail smtp server)
If I am understanding this correctly, I am going to need to implement the TLS encryption in my C++ code, complete with all the hand shaking and negotiation?
From the C# question:
sending email with gmail smtp ( secure layer ) in c++
This library does not do it
http://johnwiggins.net/jwsmtp/
ADDED:
A lot of people are just installing the stunnel as a service and then configuring it to manage the an SSL connection
http://www.stunnel.org/about/
Stunnel is an OpenSSL wrapper. OpenSSL has some perfomance issues (http://josefsson.org/gnutls4win/)
"Initializing libgcrypt takes a long time on some systems, there has been reports that it can take around 10 seconds."
and requires: "libeay32.dll" 1.35MB + "libssl32.dll" 310k + "zlib1.dll" 75k
Then thre are a couple of commercial products:
http://www.chilkatsoft.com/downloads.asp
This product is mostly delivered as an Activex (COM) "dll" (requiring an installer on the users machine to 'register' the dll - another bad .net idea).
The installer loads "ChilkatMime.dll" 1.33Mb, "ChilkatCert.dll" 1.26MB, "ChilkatUtil.dll" 720k. The developers were not at all interested in cooperating on a true C .dll library that could be called from any language including C/C++/BASIC/Python etc etc. Given their attitude I am not surprised they have been the victim of code generators made by hackers.
Apart from the cheesy name and artwork, their products are reasonably priced, but the one I tried, connected on port 25 despite being told to use port 465.
By contrast, a commercial option from catalyst:
http://www.catalyst.com/products/sockettools/secure/library/index.html
is now available as component of the main socket tools product for 1/3 the price. These tools are first class! yes, you get what you pay for. The developers are responsive and open to suggestions. They offer ALL flavors of dll including a stand alone .dll that can be shipped with you product that is only 230k! For commecial solutions they win hands down.
An SLL/TLS connection can be made explicitly (as soon as the handshake begins the seesion) or implicitly (after the handshake using STARTTLS etc)
CodeIgniter is implicit for example (as are options in Python, asp, php etc)
http://codeigniter.com/forums/viewthread/84689/
Once the connection has been made, a "tunnel" exists through which a MIME session may proceed:
"EHLO " + sLocalHost + CRLF
"MAIL FROM: " + sMailFrom + CRLF
"RCPT TO: " + "me#mydomain.com" + CRLF
"DATA: Testing, Testing xyz" + CRLF
CRLF + "." + CRLF
"QUIT"
with the usual responses from the server.
Some languages handle the MIME communication for you (socket tools, codeigniter, etc) and you just feed in the email subject, body and address making it very easy to use
CryptLib is an open source solution that facilitates an SSL/TLS tunnel with a C style .dll in only 1MB (full compilation). Since the source is available, it is possible to compile a version of the dll with just the components you need that should come in somewhat less than that.
http://www.cs.auckland.ac.nz/~pgut001/cryptlib/download.html
The author was very responsive even though I got the library to work immediately and was asking about the MIME dialog. There is 330 page manual! Thank you.
THis library is not an MTA (mail transfer agent) so you must write the MIME conversation above, but it is FREE!
source code available here:
http://www.coastrd.com/smtps.
Check out http://sourceforge.net/projects/libquickmail/ .
This library can send mail with optional attachments to multiple recipients.
The SMTP transport relies on libcurl, so it supports things like authentication and TLS.
The C API is very simple to use.
Tested on Linux (GCC) and Windows (MinGW) but should work on any platform where libcurl is available.
You are correct that you'll need to enable TLS in your application. Instead of doing this on your own, I'd suggest looking into OpenSSL.
Additionally, You need to enable SMTP in your account and support SMTP authentication to send traffic through Gmail.
There is also a duplicate question that has some pointers and a C# implementation with code that might be able to help you out.
There is also a library that might be easier to use than rolling your own (although it doesn't currently have TLS support).