I'm using the cURLpp library in C++ to download a file from the Internet as follows:
std::string download_file_contents(const std::string& download_url)
{
curlpp::Easy request;
request.setOpt(new curlpp::options::Url(download_url));
request.setOpt(new curlpp::options::FailOnError(true));
std::ostringstream response_stream;
request.setOpt(new curlpp::options::WriteStream(&response_stream));
request.perform();
return response_stream.str();
}
This code works fine for most users but some users instead get an exception which is shown inside a wxMessageBox as follows:
schannel: failed to receive handshake, SSL/TLS connection failed
A variation of this error might also be schannel: next InitializeSecurityContext failed
Researching this error message didn't yield anything too useful. I've been wondering what I could do regarding my implementation to fix this or what I would suggest a user to do on my system (generally Windows 7 and newer) to resolve this. I know the server is configured correctly since the connection is working for most users. It seems like some VPN connections or countries are more likely to run into this issue than others though.
I came to you today because I've got a problem with my Client+Server app. I built a server and client app which were working fine with QTcpSocket but I thought about adding some security and going for QSslSocket with delayed handshake. The problem is that my client is acting really weirdly. Here is the situation :
If I use connectToHostEncrypted() in my Client and call startServerEncryption() just after geting the socket in my incomingConnection slot it works fine.
But if I delay the handshake (by doing some read/write in the socket) and call later startServerEncryption(), I got the error : Error during SSL handshake: error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number on server side. I've also tried to use startClientEncryption() on client side but I get the same error.
The certificate is self-signed and loaded and applied to the socket correctly on server (I checked by testing the first situation with openssl s_client and the server accept all the protocol that I can test with (SSLv3, TLSv1, TLSv1.1, TLSv1.2).I cannot test with SSLv2 : on the Client, using this protocol with QSslSocket::setProtocol(QSsl::SslV2) show the error unsupported protocol and openssl s_client won't connect with the -ssl2 argument, it just show the available arguments.
I'm using Qt 5.9.1 and I've installed OpenSSL-Win32 v1.0.2L to get the dlls. I'm also compiling with msvc2015 32bit on Windows 7 64bit.
I hope that you can help me (and sorry for my bad english), Nicolas.
I've just found my error : I was using a readyRead slot which was using socket->readAll() and that prevented the SSL handshake ! I've also discovered that you need to call both startClientEncryption and startServerEncryption to make a SSL handshake.
I have ssl-server and ssl-client. it almost same with Boost ssl example.
now,
server open(listen) then client join and send data to server.
when sending data is done
close socket from client with socket_.lowest_layer().close();
I want change this to somethings half-close : send close, read open
and client should be send boost::asio::error::eof before half-close.
Then server catch boost::asio::error::eof and close socket from server.
Is there any more good matter? and boost have half-close?
TCP half-close (shutdown for output) cannot be used with SSL. SSL sends a close_notify, so as to enable truncation attacks to be detected, and this logically closes the SSL connection in both directions. If you just shutdown the underlying TCP socket yourself, SSL will consider that a truncation attack and make the SSL connection unusable.
I don't understand why you want to change to what you described. SSL already does essentially that itself with the close_notify.
I'm writing server application which uses boost::asio, and libssl via its integration with boost::asio. When there is incoming connection, the first time the handshake succeeded, but after the connection is dropped and the client tries to connect again, the handshake fails with the error:
session id context uninitialized
Here has proposed solution with using SSL_OP_NO_TICKET option when the SSL context is initialized. I'm using it the following way:
m_sslContext.set_options(SSL_OP_NO_TICKET);
In the beginning this resolves the problem, but now despite the option is still set the error appears again. Does anybody has an idea what other can be done with this problem?
I found that when the problem arises I still have an old connection to the same remote endpoint which tries to connect again. When I dropped the old connection properly the problem gone.
I got exactly the same error with client certificate verification enabled.
The solution was to create separate ssl_context for every connection, unlike in boost.asio examples.
One thing to note, SSL stream shutdown never completed in my case, it just would hang indefinitely. Perhaps, because the client didn't implement it correctly.
I send binary data from client (Debian 6.0.3) to server (Windows Server 2003). To bypass most firewalls I use HTTPS POST. Client and server are implemented using Boost.Asio and OpenSSL. First I implemented the simplest possible version and it worked fine.
HTTP Header:
POST / HTTP/1.1
User-Agent: my custom client v.1
[binary data]
([binary data] is not base64 encoded if this matters)
Then, on another client machine it failed (connected to the same server machine). The behavior is not stable. Connection always is established fine (port 443). Most time I pass SSL handshake fine but server receive no data (almost no data, sometimes a packet or two are actually received). Sometimes I receive SSL handshake error "short read". Sometimes I receive invalid data.
Client connects to server, handshakes, sends HTTP POST header and then infinitely sends binary data until something wrong hapenned. For test I use custom generated SSL certificate.
Server code:
namespace ssl = boost::asio::ssl;
ssl::context context(io_service, ssl::context::sslv23);
context.set_options(ssl::context::default_workarounds | ssl::context::no_sslv2);
context.use_certificate_chain_file("server.pem");
context.use_private_key_file("server.pem", boost::asio::ssl::context::pem);
ssl::stream<tcp::socket> socket(io_service, context);
// standard connection accepting
socket.async_handshake(ssl::stream_base::server, ...);
...
boost::asio::async_read_until(socket, POST_header, "\r\n\r\n", ...);
...
Client code:
ssl::context context(io_service, ssl::context::sslv23);
context.load_verify_file("server.crt");
socket.reset(new ssl::stream<tcp::socket>(io_service, context));
socket->set_verify_mode(ssl::verify_none);
// standard connection
socket.async_handshake(ssl::stream_base::client, ...);
...
(error handling is omitted along with not relevant code)
As you can see, it's the simplest possible SSL connection. What is wrong? Can the reason be a firewall?
I tried simple TCP w/o SSL over the same 443 port, this works fine.
EDIT:
Tried adding "Content-Type: application/octet-stream", doesn't help.
EDIT 2:
Usually I receive HTTP POST header fine. Then I send data chunks as chunk-size(4 bytes)chunk(chunk-size bytes).... Server receives chunk-size fine, but then nothing. Client doesn't notify server problems (no errors) and continue to send data. Sometimes server can receive chunk or two, sometimes it receives invalid chunk-size, but most time just nothing.
EDIT 3:
Compared captured traffic on client and server, didn't find any differences.
Solution
I was misled from the start with this problem. Narrowed it down to surprising details:
Sending over SSL socket fails if I use Boost.Asio multi-buffers in Boost v.1.48 (the most recent one at this moment). Example:
// data to send, protocol is [packet size: 4 bytes][packet: packet_size bytes]
std::vector<char> packet = ...;
uint32_t packet_size = packet.size();
// prepare buffers
boost::array<boost::asio::const_buffer, 2> bufs = {{boost::asio::buffer(&packet_size, sizeof(packet_size)), boost::asio::buffer(packet)}};
// send multi buffers by single call
boost::asio::async_write(socket, bufs, ...);
Sending separately packet_size and packet in this example works around the problem. I'm far from calling any suspicious behavior as a bug, especially if it's related with Boost libraries. But this one really looks like a bug. Tried on Boost v.1.47 - works fine. Tried with usual TCP socket (not SSL one) - works fine. The same on both Linux and Windows.
I'm going to find any reports about this problem in Asio mailing list and will report it if nothing found.
If you don't have to operate in front of web server, you don't have
to use HTTPS protocol. From the firewall point of view HTTPS looks like yet
another SSL connection and it has no idea what going through. So if the
only thing you need is just to pass the data - not to actual web server, use
just SSL connection over 443 port.
So just troubleshoot your SSL connection the problem has nothing to do with HTTP.
If you want to use HTTP web server and not custom client:
Two points:
You need to specify Content-Length.
If you are using HTTP/1.1 you need to specify Host header.
The simplest would be
POST /url HTTP/1.0
User-Agent: my custom client v.1
Content-Type: application/octet-stream
Content-Length: NNN
Actual Content
Or for HTTP/1.1
POST /url HTTP/1.1
Host: www.example.com
User-Agent: my custom client v.1
Content-Type: application/octet-stream
Content-Length: NNN
Actual Content
Note: you can't send infinite data. HTTP protocol requires fixed content-lenght
and most of the time web servers would load the data first before passing it to the
backend.
So you will have to transfer data by chunks.
I was misled from the start with this problem. Narrowed it down to surprising details:
Sending over SSL socket fails if I use Boost.Asio multi-buffers in Boost v.1.48 (the most recent one at this moment). Example:
// data to send, protocol is [packet size: 4 bytes][packet: packet_size bytes]
std::vector<char> packet = ...;
uint32_t packet_size = packet.size();
// prepare buffers
boost::array<boost::asio::const_buffer, 2> bufs = {{boost::asio::buffer(&packet_size, sizeof(packet_size)), boost::asio::buffer(packet)}};
// send multi buffers by single call
boost::asio::async_write(socket, bufs, ...);
Sending separately packet_size and packet in this example works around the problem. I'm far from calling any suspicious behavior as a bug, especially if it's related with Boost libraries. But this one really looks like a bug. Tried on Boost v.1.47 - works fine. Tried with usual TCP socket (not SSL one) - works fine. The same on both Linux and Windows.
I'm going to find any reports about this problem in Asio mailing list and will report it if nothing found.
(EDIT: I had originally deleted this because I had realised it wasn't using HTTP really. Following a comment where you think you might have a MITM proxy and should use proper HTTP, I'm undeleting/editing.)
POST / HTTP/1.1
User-Agent: my custom client v.1
[binary data]
Whether it's binary data or not, in plain HTTP or with SSL/TLS, you'll need a Content-Length header or to use chunked transfer encoding. This this section of the HTTP spec. A Content-Type header would be useful too.
Chunked transfer encoding is for when you don't necessarily know the length of the stream. (You always need some form of delimiters when sending data, if only to detect reliably when it ends.)
This being said, you should be able to find out whether you're behind a MITM proxy that looks into the application layer on top of SSL/TLS if you get a certificate that's not your servers. If you do still get a successful handshake with your won server cert, there isn't such a proxy. Even an HTTP proxy would use CONNECT and relay everything, without altering the SSL/TLS connection (and thus without altering your original pseudo-HTTP on top).