Libcurl failed to receive handshake, SSL/TLS connection failed - ssl

I had an issue for the last few days and the hosting technical team wasn't able to help me out, which is why I am asking here. Any information would be highly appreciated.
Useful Information
Software receives the "schannel: failed to receive handshake, SSL/TLS connection failed" error
Software runs inside a VM with a Windows 7 OS
Everything runs perfectly fine for 2-3 days and once the issue appears, every single VM on the host experiences the same error.
IF the issue is present it will NOT go away, until EVERY single VM has been closed. After waiting 2 minutes I can restart all of the VM's and they will work perfectly fine.
IF the issue is present I can't access the API inside the VM, but I can inside the host (same IP).
IF the issue is present and the VM has been restarted it will still receive the issue, until all VM's have been closed and then restarted.
IF the issue is present and open the website inside the VM I get a network error, but I can access any other website.
There is no Firewall or Proxy inside the VM that could cause this issue.
The issue doesn't occur on every host at the same time and doesn't affect others.
We are using the cloud services from Hostinger.
No errors appear in the php log file.
How the issue occurs
Everythinig runs as expected for 1-2 days without any issues and all of a sudden every single instance on the host receives that error. Other hosts are running perfectly fine, until their 1-2 days pass.
Fixes that we have tried
Changing Server Location
Changing SSL/TLS encryption mode to Flexible
Disabling/Enabling Universal SSL
Pausing Cloudflare & pointing DNS back to hosting server
Forcing different TSL versions inside libcurl
Checking if the IP has been banned/blocked
Code (Most likely not the issue, since restarting the software doesn't fix it)
CURL* curl;
CURLcode res;
std::string response;
curl = curl_easy_init();
struct curl_slist* headers = NULL;
if (curl) {
headers = curl_slist_append(headers, "Connection: keep-alive");
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL,endpoint.c_str());
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
if (patchOrPOST == "PATCH")
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
}
else if (patchOrPOST == "PUT")
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
}
else if (patchOrPOST == "GET")
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
}
else if(patchOrPOST=="DELETE")
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
}
else
{
curl_easy_setopt(curl, CURLOPT_POST, 1);
}
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, json.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
//IS FOR THREADING
/*
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
*/
res= curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
if (res!= CURLE_OK) {
curl_easy_cleanup(curl);
return "ERROR";
}
res= curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
if (res!= CURLE_OK) {
curl_easy_cleanup(curl);
return "ERROR";
}
res = curl_easy_perform(curl);
long http_code;
/* Check for errors */
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
/* always cleanup */
curl_easy_cleanup(curl);
}
return response;
Error Response which occurs almost instantly after making the request
* Trying (OUR IP)...
* Connected to ourdomain.com (OUR IP) port 443 (#0)
* schannel: failed to receive handshake, SSL/TLS connection failed
* Closing connection 0
* schannel: shutting down SSL/TLS connection with ourdomain.com port 443
curl_easy_perform() failed: SSL connect error
Screenshots(Error was present on the host)
My question
What could be causing this issue and how could I receive better information or even solve this issue?

Related

arduino gets response 301 when making a HTTPS GET request

I am making a simple arduino app that send a GET request to a HTTPS site. The code I'm using is exactly the same as the code in the MKRGSM library examples (GsmSslWebClient). But for whatever reason I always get the same response when connecting to a HTTPS site: "301 moved permanently". I kind of know what that means, I am aware that you are supposed to just make another request to the location specified in the header. But I don't know what I have to change to be able to address a https site. I'm sorry for my ignorance and I do know that in the example it clearly states that it connects to http://www.arduino.cc/asciilogo.txt but why is it then any different than the normal http example?
I would also point out here, that I have tried changing port to 80 and client settings, to work for unprotected http which works just fine. So its just the https that doesn't work.
this is the code:
/*
Web client
This sketch connects to a website using SSL through a MKR GSM 1400 board. Specifically,
this example downloads the URL "http://www.arduino.cc/asciilogo.txt" and
prints it to the Serial monitor.
Circuit:
* MKR GSM 1400 board
* Antenna
* SIM card with a data plan
created 8 Mar 2012
by Tom Igoe
*/
// libraries
#include <MKRGSM.h>
#include "arduino_secrets.h"
// Please enter your sensitive data in the Secret tab or arduino_secrets.h
// PIN Number
const char PINNUMBER[] = SECRET_PINNUMBER;
// APN data
const char GPRS_APN[] = SECRET_GPRS_APN;
const char GPRS_LOGIN[] = SECRET_GPRS_LOGIN;
const char GPRS_PASSWORD[] = SECRET_GPRS_PASSWORD;
// initialize the library instance
GSMSSLClient client;
GPRS gprs;
GSM gsmAccess;
// URL, path and port (for example: arduino.cc)
char server[] = "arduino.cc";
char path[] = "/asciilogo.txt";
int port = 443; // port 443 is the default for HTTPS
void setup() {
// initialize serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("Starting Arduino web client.");
// connection state
bool connected = false;
// After starting the modem with GSM.begin()
// attach the shield to the GPRS network with the APN, login and password
while (!connected) {
if ((gsmAccess.begin(PINNUMBER) == GSM_READY) &&
(gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
connected = true;
} else {
Serial.println("Not connected");
delay(1000);
}
}
Serial.println("connecting...");
// if you get a connection, report back via serial:
if (client.connect(server, port)) {
Serial.println("connected");
// Make a HTTP request:
client.print("GET ");
client.print(path);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
} else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
void loop() {
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available()) {
char c = client.read();
Serial.print(c);
}
// if the server's disconnected, stop the client:
if (!client.available() && !client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing forevermore:
for (;;)
;
}
}
and this is the output:
Starting Arduino web client.
connecting...
connected
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 19 Nov 2020 20:24:07 GMT
Content-Type: text/html
Content-Length: 178
Connection: close
Location: https://www.arduino.cc/asciilogo.txt
Strict-Transport-Security: max-age=500; includeSubDomains
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
disconnecting.
It is also possible that I'm just stupid and the answer is clear as day, but if somebody could please tell me exactly what to do, maybe even put an example, that would be greatly appreciated.
I haven't really tried much except changing the setting to see if they work for normal http and some other libraries that worked even worse. Sadly that's all I could find on the internet since I'm not that skilled to be messing with libraries on my own. I am using arduino mkr gsm 1400.
Be sure to call me out if I missed to mention any detail that could help solving this issue
Thanks to anybody that can help me in advance.

Connecting Arduino to Heroku web connected to Django database

To describe my problem I was trying to connect my Arduino UNO to website created by me in Heroku.
Main purpose was to called rest api function in arduino conected to Internet and get a json data.
My Arduino code:
#include <ArduinoJson.h>
#include <Ethernet.h>
#include <SPI.h>
void setup() {
// Initialize Serial port
Serial.begin(9600);
while (!Serial) continue;
// Initialize Ethernet library
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
Ethernet.init(8); // use pin 53 for Ethernet CS
if (!Ethernet.begin(mac)) {
Serial.println(F("Failed to configure Ethernet"));
return;
}
delay(1000);
Serial.println(F("Connecting..."));
// Connect to HTTP server
EthernetClient client;
client.setTimeout(10000);
if (!client.connect("https://salty-cliffs-06856.herokuapp.com", 80)) {
Serial.println(F("Connection failed"));
return;
}
Serial.println(F("Connected!"));
// Send HTTP request
client.println(F("GET /api/command/ HTTP/1.1"));
client.println(F("Host: https://salty-cliffs-06856.herokuapp.com"));
client.println(F("Connection: close"));
Serial.println(F("Done"));
if (client.println() == 0) {
Serial.println(F("Failed to send request"));
return;
}
// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
Serial.println(status);
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(status);
return;
}
// Skip HTTP headers
char endOfHeaders[] = "\r\n\r\n";
if (!client.find(endOfHeaders)) {
Serial.println(F("Invalid response"));
return;
}
// Allocate JsonBuffer
// Use arduinojson.org/assistant to compute the capacity.
const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
DynamicJsonBuffer jsonBuffer(capacity);
// Parse JSON object
JsonObject& root = jsonBuffer.parseObject(client);
if (!root.success()) {
Serial.println(F("Parsing failed!"));
return;
}
// Extract values
Serial.println(F("Response:"));
Serial.println(root["command"].as<char*>());
// Disconnect
client.stop();
Everything was working fine with that code when I was trying putting there non-secured HTTP address. After putting there my web powered by Heroku secrued by HTTPS I always got error.
The program annouced error when I was checking HTTP status and in my Arduino port terminal I got response:
Unexpected response: HTTP/1.1 400 Bad Request
I checked my heroku logs but there are not listed any request from Arduino. (Just to be sure I tried to called API from web browser and it works)
Could you help me where could be a problem ? I was thinking that it could be because of secured HTTPS. What do you think ?
Thanks for every help :)
First, change client.connect("https://salty-cliffs-06856.herokuapp.com", 80)
from
`https`
to
`http`
as port 80 is not https port and Ethernet shield does not support SSL.
Secondly, you have a wrong http header for Host. the HTTP 1.1 requires that only the domain name to use used without the protocol (i.e. http://) prefix. So change the line:
client.println(F("Host: https://salty-cliffs-06856.herokuapp.com"));
to:
client.println(F("Host: salty-cliffs-06856.herokuapp.com"));

how to handle error 500 when requesting a distant server with guzzle?

i am requesting a webservice using :
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
try {
$client = new Client();
$response = $client->request('GET', $url); //it crashes at this line
$content = json_decode($response->getBody(), true);
}
catch (ConnectException $e) {
\Drupal::logger('amu_hal')->error('incorrect_url'.$url);
}
today the distant server return a error 500.
How can i modify my code not to crash my site when it happens?
I assume that by distant server you mean a server that takes a long time to connect. You can specify a timeout for the request.
Or perhaps the server returned error 500 and it fails during json_decode? You can check the status code returned by the request.
Or even perhaps the code is failing the line that you indicate but the exception ConnectException is not being caught? Try using Exception as a catch-all to debug this situation.
Instead of using Guzzle directly, I recommend that you use the Drupal wrapper (which uses Guzzle under the hood).
$client = Drupal::httpClient();
$request = $client->get($uri, ['connect_timeout' => 5]);
if ($request->getStatusCode() === 200) {
echo 'Connection Success';
} else {
echo sprintf('Error %d occurred', $request->getStatusCode());
}

Inserting client certificates into an HTTPS POST request

I'm building a hardware device which connects to the AWS IOT platform. According to the documentation the authentication with the aws iot platform is done with TLS. I have the Root CA, client key and client certificate files on the device that authorize the access. Is there a way to use these files in the HTTP header while making the POST request? If so, how? So far here is the code for the Energia IDE (based on the Arduino IDE) and using the WiFiClient methods.
if (client.sslConnect(aws_endpoint, 443))
{
Serial.println("\nConnected to AWS endpoint");
String PostData = "{\"value1\" : \"testValue\", \"value2\" : \"Hello\", \"value3\" : \"World!\" }";
request = "POST /things/";
request += thingname;
request += "/shadow";
request += " HTTP/1.1";
Serial.print("Request:\t"); Serial.println(request);
Serial.print("Post data:\t"); Serial.println(PostData);
client.println(request);
client.println("Host: ");
client.println(aws_endpoint);
client.println(":443");
client.println("User-Agent: Energia/1.1");
client.println("Connection: close");
client.println("Content-Type: application/json");
client.print("Content-Length: "); client.println(PostData.length());
client.println();
client.println(PostData);
client.println();
}
else
{
Serial.println("Connection failed");
}
Serial.println();
Serial.println("Server response:");
Serial.println();
// Capture response from the server. (10 second timeout)
long timeOut = 5000;
long lastTime = millis();
while((millis()-lastTime) < timeOut)
{ // Wait for incoming response from server
while (client.available())
{ // Characters incoming from the server
char c = client.read(); // Read characters
Serial.write(c);
}
}
This however, gives an authentication error:
HTTP/1.1 403 Forbidden
content-type: application/json
content-length: 91
date: Tue, 26 Jul 2016 11:46:59 GMT
x-amzn-RequestId: 4d5388a9-e3c4-460a-b674-c3f971f3330d
connection: Keep-Alive
x-amzn-ErrorType: ForbiddenException:
{"message":"Missing Authentication Token","traceId":"4d5388a9-e3c4-460a-b674-c3f971f3330d"}
The TLS client certificates would be sent/used as part of your client.sslConnect() call, not as part of the HTTP request. The TLS handshake (and exchange/validation of client and server certificates) happens before any HTTP message is sent.
This AWS forums post suggests that you may need to be using port 8443 (not port 443), for the shadow API. It looks like the use/requirement of TLS mutual authentication (via certificates), versus the use of AWS SIGv4 headers, is determined by AWS IOT based on the port used.
Hope this helps!

Arduino Ethernet Shield - No response on GET request to server

I have a code for the Arduino Ethernet Shield that will send a GET request to a server and return a PHP echo statement.
However, most of the time it fails to connect to the server.
When it does connect, I keep getting 403 Forbidden error or it says bad header format for "Host:".
I have checked every forum and all StackOverflow links related to the topic, but none of their solutions worked. My code is attached below.
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char server[] = "kanishkaganguly.byethost5.com";
IPAddress ip(192,168,0,103);
EthernetClient client;
void setup() {
Serial.begin(9600);
while (!Serial) {
;
}
Ethernet.begin(mac, ip);
delay(1000);
Serial.println("connecting...");
if (client.connect(server, 80)) {
Serial.println("connected");
client.println("GET /test.php HTTP/1.1");
client.println("Host: www.arduino.cc");
client.println("User-Agent: arduino-ethernet");
//client.println("User-Agent: Mozilla/5.0");
//This supposedly fixed 403 error for another user
client.println("Connection: close");
client.println();
}else {
Serial.println("connection failed");
}
}
void loop(){
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available()) {
char c = client.read();
Serial.print(c);
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing forevermore:
for(;;) ;
}
}
I figured out the problem. The client.println() as a new line isn't working for some reason. So, here is the updated code
client.print("GET /checkcontrol.php HTTP/1.1\r\n");
client.print("Host: shahz.webatu.com\r\n");
client.print("User-Agent: arduino-ethernet\r\n");
client.print("Connection: close\r\n\r\n");
The \r\n is the right way to go about adding a new line for the server to recognize.
The Host header specifies the hostname of the site you're connecting to. In this case, you are trying to connect to the domain kanishkaganguly.byethost5.com, but your Host header is set to www.arduino.cc. Usually this is incorrect. The Host header should match the domain, so both should be kanishkaganguly.byethost5.com.
When a client connects to a domain, the client first resolves the domain name to an IP, then makes the connection to that IP. Because the connection is made to the IP, the server does not know what domain name was looked up by the client. Because IPs are a limited resource, many hosting providers host multiple domains on a single IP. Without the Host header, the server would not know which page to return to the client.
The println command sends the text followed by "\r\n" so instead of changing every println for print, you could have added CRLF to the close line.
Client.println("Connection: close\r\n")