I have a C++ application that uses Boost_asio to do TCP/IP connection who read a .php document in a Web server that in turn uses the php script to update certain statistics.
The whole thing work as planned, but recently the server changed to use SSL (Google mandatory) and naturally, the previous connection stopped to work.
After a lot of theoretical reading about SSL, I'm still in the dark about certain practical details.
Using the example in the Boost asio documentation and a file “cacert.pem”, downloaded form somewhere following indications in this site, I'm able to run correctly the example using:
<host> = “www.google.com” and <port> = “https”.
Using the example “as is”, the Google server response is:
Verifying /OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
Verifying /C=US/O=Google Trust Services/CN=Google Internet Authority G3
Verifying /C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
Enter message: Reply:
But when using
<host> = “www.zator.com” and <port> = “https”
my domain, hosted in 1&1 IONOS, the reply is:
Handshake failed: tlsv1 alert internal error
At this point I have several questions:
What in the hell mean the sentence: ctx.load_verify_file("cacert.pem"); ?
The content of that file, can be the culprit of the fail when connecting with my domain?
Is that sentence essential to complete the connection?
In the case of google server (absence of error), is it supposed that after the sentence io_context.run(); the connection has been correctly established?
Assuming I make public the client's member socket_ (private in the example), can I continue with some as (I can't test that in google :-)
std::string request("GET /mystatistics.php HTTP/1.1\r\n\r\n");
boost::asio::write(c.socket_, boost::asio::buffer(request));
boost::system::error_code ec;
std::string response;
do { // read response
char buf[1024];
size_t bytes_transferred = c.socket_.read_some(boost::asio::buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
} while (!ec);
std::cout << "Response received: '" << response << "'\n";
Thanks in advance.
I've found some useful information here. A good, albeit partial info, and a good start point to further search
Related
Im am working with libcurl on Visual Studio 2017 to get an request from a google url but the program crashes without call the exception that is trapped. I´ve tested with 2 others urls and it worked fine. The google url is:
"https://maps.googleapis.com/maps/api/elevation/json?locations=-23.64737184441803,-46.624&key=AIza...."
When I execute perform the code breaks without been catch by the exception:
the code is:
std::stringstream get_response(std::string_view url)
{
std::stringstream str;
curl::curl_ios<std::stringstream> writer(str);
curl::curl_easy easy(writer);
easy.add<CURLOPT_URL>(url.data());
easy.add<CURLOPT_FOLLOWLOCATION>(1L);
easy.add<CURLOPT_VERBOSE>(1L);
try
{
easy.perform();
}
catch (curl::curl_easy_exception error)
{
auto errors = error.get_traceback();
error.print_traceback();
}
return str;
}
I´ve looked at several sites without success.
Any help will be appreciated
I got a little more information from the log:
...
schannel: SSL/TLS connection with maps.googleapis.com port 443 (step 2/3)
schannel: encrypted data got 778
schannel: encrypted data buffer: offset 3542 length 4096
schannel: next InitializeSecurityContext failed: Unknown error (0x80092013) -The revocation function was unable to check revocation because the revocation server was offline.
Marked for [closure]: Failed HTTPS connection
....
how to solve this?
Thanks
I'm trying to establish DTLS connection using openssl (c++).
However whereas there is DTLSv1_listen() function for server side I can't find any client side equivalent to actually establish UDP connection to server from client. Or send something to DTLS server. Could someone help me understand how to establish "connection" to DTLS server (I know the point of UDP and datagram communication is to be connectionless but by connection I mean scheme like DNS request+response)?
I need to send single message to server and then receive 1 response message. Encrypted. With certificate verification. How such communication scheme would work in DTLS world?
What are you using for signalling. You actually don't have to use openssl for your signalling layer you could use a Memory Bio and read and write from it.
With DTLS You will have 2 sides here, a Client and a Server. The Client will initiate things with a Client Hello. The server hopefully receives it, writes it into the bio, reads back a Server Hello and responds via the signalling layer.
There is a lot of stuff required to really finish up your app into the real world so I wont cover everything.
If you have a SSL Context, and you have your BIO's created. To Initiate the Server:
SSL_set_accept_state(*sslContext)
and to initiate the client:
SSL_set_connect_state(*sslContext);
You then want to start a handshake on the client. There is so many factors here on how your application is going to work its hard to give advice but the client should call:
SSL_do_handshake(*sslContext);
Depending on how you have wired everything up, your program may automatically send the client hello at this point. You can use Wireshark, grab only UDP and at the top filter DTLS to see it. If not you may be required to signal manually.
I wrote the following program myself to test OpenSSL dll's to see if there were any issues after compiling them. I can't share all the code with you but it shows how in memory you can use a single console app to do the handshake (no transmission via the internet just to see how it works).
Notes:
The BIO is a Memory BIO in this case.
Handshake is a SSL_do_handshake
WriteCipherText is a call to BIO_write
ReadCipherText is a call to BIO_read
You have to open it and do the other basic setup states first. At the end both of the handshakes will return 1 for succcess. This just kind of shows you how to do a basic memory DTLS handshake using openssl.
Console.WriteLine("[Client] Open: " + Client.Open("ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:AES128-SHA:AES128-GCM-SHA256:AES128-SHA256", "SRTP_AES128_CM_SHA1_80"));
Console.WriteLine("[Server] Open: " + Server.Open("ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:AES128-SHA:AES128-GCM-SHA256:AES128-SHA256", "SRTP_AES128_CM_SHA1_80"));
Console.WriteLine("[Client] Handshake" + Client.Handshake());
Console.WriteLine("Client: [Read] Client Hello");
var clientHello = Client.ReadCipherText();
Console.WriteLine("[Server] Write Hello: " + Server.WriteCipherText(clientHello));
Console.WriteLine("[Server] Handshake" + Server.Handshake());
clientHello.Free();
Console.WriteLine("[Server] Read Server Hello");
var serverHello = Server.ReadCipherText();
Console.WriteLine("[Client] Write Server Hello: " + Client.WriteCipherText(serverHello));
Console.WriteLine("[Client] Handshake" + Client.Handshake());
serverHello.Free();
Console.WriteLine("[Client] Read Certificate");
var clientCertificate = Client.ReadCipherText();
Console.WriteLine("[Server] Write Certificate: " + Server.WriteCipherText(clientCertificate));
Console.WriteLine("[Server] Handshake: " + Server.Handshake());
clientCertificate.Free();
Console.WriteLine("[Server] Read Change Cipher Spec");
var serverChangeCipherSpec = Server.ReadCipherText();
Console.WriteLine("[Client] Write Change Cipher Spec: " + Client.WriteCipherText(serverChangeCipherSpec));
serverChangeCipherSpec.Free();
Console.WriteLine("[Client] Handshake" + Client.Handshake());
Console.WriteLine("[Server] Handshake" + Server.Handshake());
Console.ReadLine();
Lots of helpful resources too to take a look at:
https://web.archive.org/web/20150814081716/http://sctp.fh-muenster.de/dtls-samples.html This ones really good
http://chris-wood.github.io/2016/05/06/OpenSSL-DTLS.html
https://wiki.openssl.org/index.php/SSL/TLS_Client
On the client side you create the UDP-socket, pass it with BIO_new_dgram to the SSL context and connect it with connect() or BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &server_sockaddr). The connect just forces the file descriptors write to always be sent to server_sockaddr.
Now just do a regular SSL_connect and it should work.
For server side it's a little more complicated. I made a post and an example implementation
Providing a MCVE is going to be hard, the scenario is the following:
a server written in c++ with boost asio offers some services
a client written in c++ with boost asio requests services
There are custom headers and most communication is done using multipart/form.
However, in the case where the server returns a 401 for an unauthorized access,
the client receives a broken pipe (system error 32).
AFAIK this happens when the server connection closes too early.
So, running into gdb, I can see that the problem is indeed the transition from the async_write which sends the request, to the async_read_until which reads the first line of the HTTP Header:
The connect routine sends the request from the client to the server:
boost::asio::async_write(*socket_.get(),
request_,
boost::bind(&asio_handler<http_socket>::write_request,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
And the write_request callback, checks if the request was sent OK, and then reads the first line (until the first newline):
template <class T>
void asio_handler<T>::write_request(const boost::system::error_code & err,
const std::size_t bytes)
{
if (!err) {
// read until first newline
boost::asio::async_read_until(*socket_,
buffer_,
"\r\n",
boost::bind(&asio_handler::read_status_line,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else {
end(err);
}
}
The problem is that the end(err) is always called with a broken pipe (error code 32). Meaning, as far as I understand, that the server closed the connection. The server indeed closes the connection, but only after it has sent a message HTTP/1.1 401 Unauthorized.
using curl with the appropriate request, we do get the actual message/error before the server closes the connection
using our client written in C++/boost asio we only get the broken pipe and no data
only when the server leaves the connection open, do we get to the point of reading the error (401) but that defeats the purpose, since now the connection is left open.
I would really appreciate any hints or tips. I understand that without the code its hard to help, so I can add more source at any time.
EDIT:
If I do not check for errors between writing the request, and reading the server reply, then I do get the actual HTTP 401 error. However this seems counter-intuitive, and I am not sure why this happens or if it is supposed to happen.
The observed behavior is allowed per the HTTP specification.
A client or server may close the socket at anytime. The server can provide a response and close the connection before the client has finished transmitting the request. When writing the body, it is recommended that clients monitor the socket for an error or close notification. From the RFC 7230, HTTP/1.1: Message Syntax and Routing Section 6.5. Failures and Timeouts:
6.5. Failures and Timeouts
A client, server, or proxy MAY close the transport connection at any time. [...]
A client sending a message body SHOULD monitor the network connection for an error response while it is transmitting the request. If the client sees a response that indicates the server does not wish to receive the message body and is closing the connection, the client SHOULD immediately cease transmitting the body and close its side of the connection.
On a graceful connection closure, the server will send a response to the client before closing the underlying socket:
6.6. Tear-down
A server that sends a "close" connection option MUST initiate a close of the connection [...] after it sends the response containing "close". [...]
Given the above behaviors, there are three possible scenarios. The async_write() operation completes with:
success, indicating the request was written in full. The client may or may not have received the HTTP Response yet
an error, indicating the request was not written in full. If there is data available to be read on the socket, then it may contain the HTTP Response sent by the server before the connection terminated. The HTTP connection may have terminated gracefully
an error, indicating the request was not written in full. If there is no data available to be read on the socket, then the HTTP connection was not terminated gracefully
Consider either:
initiating the async_read() operation if the async_write() is successful or there is data available to be read
void write_request(
const boost::system::error_code & error,
const std::size_t bytes_transferred)
{
// The server may close the connection before the HTTP Request finished
// writing. In that case, the HTTP Response will be available on the
// socket. Only stop the call chain if an error occurred and no data is
// available.
if (error && !socket_->available())
{
return;
}
boost::asio::async_read_until(*socket_, buffer_, "\r\n", ...);
}
per the RFC recommendation, initiate the async_read() operation at the same time as the async_write(). If the server indicates the HTTP connection is closing, then the client would shutdown its send side of the socket. The additional state handling may not warrant the extra complexity
Im trying to send an email in C++. I found the class CSmtp which looks like a fine one.So I tried out the example project but it gives the ErrorCode :
Error: Undefined error id.
Now I tried to find out where the problem is because the errorcode is too general.I Debuged the project find this Errorcode
ErrorCode WSA_SELECT (109) ECSmtp::CSmtpError
I googled after it but found no answer.Someone can help ?
Link for class : CSmtp with SSL/TLS
Code:
#include "CSmtp.h"
#include <iostream>
int main()
{
bool bError = false;
try
{
CSmtp mail;
#define test_gmail_tls
#if defined(test_gmail_tls)
mail.SetSMTPServer("smtp.gmail.com",587);
mail.SetSecurityType(USE_TLS);
#elif defined(test_gmail_ssl)
mail.SetSMTPServer("smtp.gmail.com",465);
mail.SetSecurityType(USE_SSL);
#elif defined(test_hotmail_TLS)
mail.SetSMTPServer("smtp.live.com",25);
mail.SetSecurityType(USE_TLS);
#elif defined(test_aol_tls)
mail.SetSMTPServer("smtp.aol.com",587);
mail.SetSecurityType(USE_TLS);
#elif defined(test_yahoo_ssl)
mail.SetSMTPServer("plus.smtp.mail.yahoo.com",465);
mail.SetSecurityType(USE_SSL);
#endif
mail.SetLogin("* My Email Adress *");
mail.SetPassword("*Password*");
mail.SetSenderName("User");
mail.SetSenderMail("* My Email Adress *");
mail.SetReplyTo("* Email Adress of my friend *");
mail.SetSubject("The message");
mail.SetXPriority(XPRIORITY_NORMAL);
mail.SetXMailer("The Bat! (v3.02) Professional");
mail.AddMsgLine("Hello,");
mail.AddMsgLine("");
mail.AddMsgLine("...");
mail.AddMsgLine("How are you today?");
mail.AddMsgLine("");
mail.AddMsgLine("Regards");
mail.ModMsgLine(5,"regards");
mail.DelMsgLine(2);
mail.AddMsgLine("User");
//mail.AddAttachment("../test1.jpg");
//mail.AddAttachment("c:\\test2.exe");
//mail.AddAttachment("c:\\test3.txt");
mail.Send();
}
catch(ECSmtp e)
{
std::cout << "Error: " << e.GetErrorText().c_str() << ".\n";
bError = true;
}
if(!bError)
std::cout << "Mail was send successfully.\n";
return 0;
}
I would suggest you to go with powershell script for sending email and then call that script from your c++ program. Use smtp.gmail.com as server & 465 port. :)
This can help..
https://github.com/udit043/Send-email-using-powershell
Standard C++11 does not have such facilities (but your particular OS might provide additional SMTP client libraries). Maybe you want a library like vmime or a framework like POCO
Notice that the very ability of email is operating system specific.
Also, most SMTP servers are configured to reject open mail relaying (otherwise, they would be used by spam bots, and emails going thru them would be rejected since blacklisted).
You could for example configure some SMTP service on your local machine or server, and programmatically send email thru localhost (then the SMTP server would spool and relay the email, etc.) - or to some specific and well-defined "smarthost" if your system and network has one; you probably don't want to wire-in some SMTP relay host names in your program, and you do want the email to be spooled (not lost!) if the recipient SMTP server is down or unreachable; in other words, you need some SMTP server.
You certainly don't want to code your SMTP server from scratch!
Hence, your program should only send SMTP to some trusted host, which is correctly configured to avoid spamming (then you might need to set some From or Reply-To SMTP header to something appropriate for your SMTP host). Be sure that major Internet companies like Google, Yahoo, AOL etc... are configuring carefully their SMTP service to disallow open relay spamming. Often, they accept SMTP relay connections only from their business clients (and they would cut a client doing automated spamming). So you should send SMTP to your ISP's SMTP server (or to some local or near SMTP server).
Notice that spamming is usually forbidden by law or by your ISP terms of service.
You could also run some command (e.g. using popen) to send mail ...
I am behind a http/https proxy. So to download a file using QNetworkAccessManager, i set the proxy as following:
if(no_proxy)
{
QNetworkProxyFactory::setUseSystemConfiguration (false);
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
}
else if(system_proxy)
{
QNetworkProxyQuery pQuery(QUrl(QLatin1String("http://www.google.com")));
QList<QNetworkProxy>listOfProxies =QNetworkProxyFactory::systemProxyForQuery(pQuery);
QNetworkProxy::setApplicationProxy(listOfProxies.first());
}
else if(manual_proxy)
{
proxy.setHostName(address);
proxy.setPort(port);
if(http_proxy)
proxy.setType(QNetworkProxy::HttpProxy);
else if(socks_proxy)
proxy.setType(QNetworkProxy::Socks5Proxy);
else if(ftp_proxy)
proxy.setType(QNetworkProxy::FtpCachingProxy);
QNetworkProxy::setApplicationProxy(proxy);
}
Now behind http squid proxy server, this code works fine in case of http urls. But, if i try to download a file with ftp url the download fails with the error
no suitable proxy found
It does not seem to use http proxy for ftp urls. But, we have such options like in firefox:
use this proxy server for all protocols
How to do similar thing in Qt!
Update:
void DownloadThread::startDownload()
{
QString args =downUrl,tempFN;
QUrl url = QUrl::fromEncoded(args.toLocal8Bit());
request.setUrl(url);
request.setRawHeader("User-Agent", userAgent);
request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
reply.setCookieJar(cookieJar);
reply=manager.get(request);
connect(reply, SIGNAL(readyRead()),this,
SLOT(saveToDisk()));
...
}
Have you tried explicitly setting the Qftp proxy?
int setProxy ( const QString & host, quint16 port )
That might get you more joy, but yes, you have to set the proxies up for each connection normally, however, there is always the possibility that the proxy you are trying to use doesn't support FTP? If you pass me some more details about the proxy and where your problems lie (request/response code for example)
Also in squid.conf may want to change/add the following in case they are not present
acl SSL_ports port 443 21
acl FTP proto FTP
always_direct allow FTP
http_access allow ftp
Also, worth checking that the firewall allows port 20, 21 & 443 (I know its a simple check, but often I find its things like these that can be a real pain to find as a root cause).
Do you have a copy of the log file that is generated? it would be interesting/helpful to see what error code is being returned. Also, have you tried manually stepping through the program to see what is contained in the variables at run-time, that would give you a better picture of what is happening, as it may be that everything is fine and that there is a simple way to progress which the contents of the variables will lead you to in short order (might not be the case but it usually worth a try).