I found the following code snippet and did few changes to post json data to a re_url . But it is showing error failed connection ...the server listens on the 8888 port for json data.
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#define APIKEY "YOUR_API_KEY"
#define HOST "https://YOUR_WEB_SERVER_URI"
#define PORT "8888"
char *s = "somejson";
int main() {
//
// Initialize the variables
//
BIO* bio;
SSL* ssl;
SSL_CTX* ctx;
//
// Registers the SSL/TLS ciphers and digests.
//
// Basically start the security layer.
//
SSL_library_init();
//
// Creates a new SSL_CTX object as a framework to establish TLS/SSL
// or DTLS enabled connections
//
ctx = SSL_CTX_new(SSLv23_client_method());
//
// -> Error check
//
if (ctx == NULL)
{
printf("Ctx is null\n");
}
//
// Creates a new BIO chain consisting of an SSL BIO
//
bio = BIO_new_ssl_connect(ctx);
//
// Use the variable from the beginning of the file to create a
// string that contains the URL to the site that you want to connect
// to while also specifying the port.
//
BIO_set_conn_hostname(bio, HOST ":" PORT);
//
// Attempts to connect the supplied BIO
//
if(BIO_do_connect(bio) <= 0)
{
printf("Failed connection\n");
return 1;
}
else
{
printf("Connected\n");
}
//
// The bare minimum to make a HTTP request.
//
char* write_buf = "POST / HTTP/1.1\r\n"
"Host: " HOST "\r\n"
"Authorization: Basic " APIKEY "\r\n"
"Connection: close\r\n"
"\r\n";
//
// Attempts to write len bytes from buf to BIO
//
if(BIO_write(bio, write_buf, strlen(write_buf)) <= 0)
{
//
// Handle failed writes here
//
if(!BIO_should_retry(bio))
{
// Not worth implementing, but worth knowing.
}
//
// -> Let us know about the failed writes
//
printf("Failed write\n");
}
//
// Variables used to read the response from the server
//
int size;
char buf[1024];
//
// Read the response message
//
for(;;)
{
//
// Get chunks of the response 1023 at the time.
//
size = BIO_read(bio, buf, 1023);
//
// If no more data, then exit the loop
//
if(size <= 0)
{
break;
}
//
// Terminate the string with a 0, to let know C when the string
// ends.
//
buf[size] = 0;
//
// -> Print out the response
//
printf("%s", buf);
}
//
// Clean after ourselves
//
BIO_free_all(bio);
SSL_CTX_free(ctx);
return 0;
}
The code above will explain in details how to establish a TLS connection with a remote server.
Important note: this code doesn't check if the public key was signed by a valid authority. Meaning I don't use root certificates for validation. Don't forget to implement this check otherwise you won't know if you are connecting the right website
When it comes to the request itself. It is nothing more then writing the HTTP request by hand.
You can also find under this link an explanation how to instal openSSL in your system, and how to compile the code so it uses the secure library.
From BIO_set_conn_hostname:
BIO_set_conn_hostname() uses the string name to set the hostname. The
hostname can be an IP address. The hostname can also include the port
in the form hostname:port . It is also acceptable to use the form
"hostname/any/other/path" or "hostname:port/any/other/path".
You do not provide a valid host name:
#define HOST "https://YOUR_WEB_SERVER_URI"
...
// Use the variable from the beginning of the file to create a
// string that contains the URL to the site that you want to connect
// to while also specifying the port.
BIO_set_conn_hostname(bio, HOST ":" PORT);
The comment correctly refers to a URL but instead you provide a URI which is most probably wrong.
If you replace YOUR_WEB... with the real host name, it is still a URI and not a host name.
Try to remove the "https://" part and only provide the host name.
Related
I'm trying to port the file_serving example to use HTTPS.
I've attempted to move the spiff file server functionality to the existing https_server example inside esp-idf but I get the error: httpd_server_init: error in creating ctrl socket (112)
I realize that this is probably not the easiest way to do it and instead I should work on re-writing the original file_serving example code to use https instead. The function to start the server is in the file_server.c:
/* Function to start the file server */
esp_err_t start_file_server(const char *base_path)
{
static struct file_server_data *server_data = NULL;
/* Validate file storage base path */
if (!base_path || strcmp(base_path, "/spiffs") != 0) {
ESP_LOGE(TAG, "File server presently supports only '/spiffs' as base path");
return ESP_ERR_INVALID_ARG;
}
if (server_data) {
ESP_LOGE(TAG, "File server already started");
return ESP_ERR_INVALID_STATE;
}
/* Allocate memory for server data */
server_data = calloc(1, sizeof(struct file_server_data));
if (!server_data) {
ESP_LOGE(TAG, "Failed to allocate memory for server data");
return ESP_ERR_NO_MEM;
}
strlcpy(server_data->base_path, base_path,
sizeof(server_data->base_path));
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
/* Use the URI wildcard matching function in order to
* allow the same handler to respond to multiple different
* target URIs which match the wildcard scheme */
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_LOGI(TAG, "Starting HTTP Server");
if (httpd_start(&server, &config) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start file server!");
return ESP_FAIL;
}
/* URI handler for getting uploaded files */
httpd_uri_t file_download = {
.uri = "/*", // Match all URIs of type /path/to/file
.method = HTTP_GET,
.handler = download_get_handler,
.user_ctx = server_data // Pass server data as context
};
httpd_register_uri_handler(server, &file_download);
/* URI handler for uploading files to server */
httpd_uri_t file_upload = {
.uri = "/upload/*", // Match all URIs of type /upload/path/to/file
.method = HTTP_POST,
.handler = upload_post_handler,
.user_ctx = server_data // Pass server data as context
};
httpd_register_uri_handler(server, &file_upload);
/* URI handler for deleting files from server */
httpd_uri_t file_delete = {
.uri = "/delete/*", // Match all URIs of type /delete/path/to/file
.method = HTTP_POST,
.handler = delete_post_handler,
.user_ctx = server_data // Pass server data as context
};
httpd_register_uri_handler(server, &file_delete);
return ESP_OK;
}
The main function references the start_file_server and that is shown below as well:
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
/* Initialize file storage */
ESP_ERROR_CHECK(init_spiffs());
/* Start the file server */
ESP_ERROR_CHECK(start_file_server("/spiffs"));
}
I have the https_server example running and I have https_mbedtls client connecting to it and not authenticating the validity of my self-signed cert. This same https_mbedtls client would be used to connect the the file_server (https).
the original file_server example includes esp_http_server.h. I assume that I need to instead include esp_https_server.h
Below are the changes that I have made to it:
/* Function to start the file server */
esp_err_t start_file_server(const char *base_path)
{
static struct file_server_data *server_data = NULL;
/* Validate file storage base path */
if (!base_path || strcmp(base_path, "/spiffs") != 0) {
ESP_LOGE(TAG, "File server presently supports only '/spiffs' as base path");
return ESP_ERR_INVALID_ARG;
}
if (server_data) {
ESP_LOGE(TAG, "File server already started");
return ESP_ERR_INVALID_STATE;
}
/* Allocate memory for server data */
server_data = calloc(1, sizeof(struct file_server_data));
if (!server_data) {
ESP_LOGE(TAG, "Failed to allocate memory for server data");
return ESP_ERR_NO_MEM;
}
strlcpy(server_data->base_path, base_path,
sizeof(server_data->base_path));
//***********
httpd_handle_t server = NULL;
httpd_ssl_config_t config = HTTPD_SSL_CONFIG_DEFAULT();
//***********
extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end");
conf.cacert_pem = cacert_pem_start;
conf.cacert_len = cacert_pem_end - cacert_pem_start;
extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
conf.prvtkey_pem = prvtkey_pem_start;
conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
//***********
/* Use the URI wildcard matching function in order to
* allow the same handler to respond to multiple different
* target URIs which match the wildcard scheme */
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_LOGI(TAG, "Starting HTTPS Server");
//***********
if (httpd_ssl_start(&server, &config) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start file server!");
return ESP_FAIL;
}
/* URI handler for getting uploaded files */
httpd_uri_t file_download = {
.uri = "/*", // Match all URIs of type /path/to/file
.method = HTTP_GET,
.handler = download_get_handler,
.user_ctx = server_data // Pass server data as context
};
httpd_register_uri_handler(server, &file_download);
/* URI handler for uploading files to server */
httpd_uri_t file_upload = {
.uri = "/upload/*", // Match all URIs of type /upload/path/to/file
.method = HTTP_POST,
.handler = upload_post_handler,
.user_ctx = server_data // Pass server data as context
};
httpd_register_uri_handler(server, &file_upload);
/* URI handler for deleting files from server */
httpd_uri_t file_delete = {
.uri = "/delete/*", // Match all URIs of type /delete/path/to/file
.method = HTTP_POST,
.handler = delete_post_handler,
.user_ctx = server_data // Pass server data as context
};
httpd_register_uri_handler(server, &file_delete);
return ESP_OK;
}
When I go flash through ESP-IDF command line I get the following error:
../main/file_server.c:22:10: fatal error: esp_https_server.h: No such file or directory
#include "esp_https_server.h"
^~~~~~~~~~~~~~~~~~~~
compilation terminated.
To fix this, I try to add "REQUIRES esp_https_server" to the CMakeLists.txt in the main directory. This replaces the previous error with
../main/main.c:16:10: fatal error: esp_spiffs.h: No such file or directory
#include "esp_spiffs.h"
^~~~~~~~~~~~~~
compilation terminated.
The same thing happens where it can't find additional requirements until my CMakeLists.txt looks like this:
idf_component_register(SRCS "main.c" "file_server.c"
INCLUDE_DIRS "."
EMBED_FILES "favicon.ico" "upload_script.html"
EMBED_TXTFILES "certs/cacert.pem"
"certs/prvtkey.pem"
REQUIRES esp_https_server spiffs nvs_flash protocol_examples_common)
And the error I get at this point is once again unable to find esp_https_server.h
../main/file_server.c:22:10: fatal error: esp_https_server.h: No such file or directory
#include "esp_https_server.h"
^~~~~~~~~~~~~~~~~~~~
compilation terminated.
I hope you understand the frustrating predicament that I'm in and I would greatly appreciate any input on how to fix this "No such file or directory" error or any tips on how to port this example to https as well. Thank you.
My supervising professor had a look at the problem and found the solution. Here are the changes that were needed to be made:
Include the following line in the sdkconfig file:
CONFIG_ESP_HTTPS_SERVER_ENABLE=y
“config” instead of “conf” in the file file_server.c and the configuration for the http server is a subcomponent of the https configuration and needs a "httpd.” after the “config.”:
extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end");
config.cacert_pem = cacert_pem_start;
config.cacert_len = cacert_pem_end - cacert_pem_start;
extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
config.prvtkey_pem = prvtkey_pem_start;
config.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
//***********
/* Use the URI wildcard matching function in order to
* allow the same handler to respond to multiple different
* target URIs which match the wildcard scheme */
config.httpd.uri_match_fn = httpd_uri_match_wildcard;
https://github.com/cesanta/mongoose/blob/master/examples/http-restful-server/main.c
This below code has hardcoded link https://localhost:8000. The server receives requests from clients using same link on same system. But if sending request with ip of server system from other system on network then getting connection refused error. How we do binding ip dynamically.
// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
//
// HTTP server example. This server serves both static and dynamic content.
// It implements the following endpoints:
// /api/f1 - respond with JSON string {"result": 123}
// /api/f2/:id - wildcard example, respond with JSON string {"result": "URI"}
// any other URI serves static files from s_web_directory
// To enable SSL/TLS (using self-signed certificates in PEM files),
// 1. Change s_listen_on from http:// to https://
// 2. make MBEDTLS_DIR=/path/to/your/mbedtls/installation
// 3. curl -k https://127.0.0.1:8000
#include "mongoose.h"
static const char *s_listen_on = "https://localhost:8000";
static const char *s_web_directory = ".";
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_ACCEPT && mg_url_is_ssl(s_listen_on)) {
// If s_listen_on URL is https://, tell listening connection to use TLS
struct mg_tls_opts opts = {
//.ca = "ca.pem", // Uncomment to enable two-way SSL
.cert = "server.pem", // Certificate PEM file
.certkey = "server.pem", // This pem conains both cert and key
};
mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_http_match_uri(hm, "/api/f1")) {
mg_http_reply(c, 200, "", "{\"result\": %d}\n", 123); // Serve REST
} else if (mg_http_match_uri(hm, "/api/f2/*")) {
mg_http_reply(c, 200, "", "{\"result\": \"%.*s\"}\n", (int) hm->uri.len,
hm->uri.ptr);
} else {
struct mg_http_serve_opts opts = {.root_dir = s_web_directory};
mg_http_serve_dir(c, ev_data, &opts);
}
}
(void) fn_data;
}
int main(void) {
struct mg_mgr mgr; // Event manager
mg_log_set("2"); // Set to 3 to enable debug
mg_mgr_init(&mgr); // Initialise event manager
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
mg_mgr_free(&mgr);
return 0;
}
Change s_listen_on:
static const char *s_listen_on = "http://0.0.0.0:8000";
This way, it won't use SSL, and listen for incoming connections from anywhere, not just your own workstation. Listening on localhost listens only for connections from your own workstation.
On the Eclipse Paho MQTT website, the developers provide a client example (http://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/pubsync.html) that does the following:
Create a client object with the specified parameters
Connect the client with the specified connection options
Publish a MQTT message
Disconnect the client
Destroy the client object
This works well if all you want is to publish one single message.
In my code, I have a function that contains pretty much the same code as in the aforementioned example, however, the function is called repeatedly from main() as I need to publish a large number of messages one after another. The problem is, if I use the code exactly as in the example, every time my function is called a new connection is created and shortly after destroyed. This happens again and again and again as long as the function is called repeatedly, causing a huge overhead.
Is there a way to check whether a client object has already been created, and if so, don't do it again but use the existing one?
In my understanding, the MQTTClient_isConnected() function is supposed to do that: https://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/_m_q_t_t_client_8h.html#ad9e40bdb7149ee3e5d075db7f51a735f
But if I try it like this, I get a Segmentation fault:
if (!MQTTClient_isConnected(client)) {
MQTTClient_create(&client, mqtt.addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = TOKEN;
if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
printf("\n==> Connection to MQTT Broker failed.\n");
MQTTClient_destroy(&client);
exit(EXIT_FAILURE);
}
}
[EDIT]
Here is a simple demo code that better illustrates what I'm trying to accomplish:
#include <stdio.h>
#include <MQTTClient.h>
MQTTClient client;
void publish_MQTT() {
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
char *payload = (char *)calloc(1024, sizeof(char));
strcpy(payload, "hello");
printf("DEBUG_BEFORE >> MQTTClient_isConnected(client) = %d\n", MQTTClient_isConnected(client)); // DEBUG OUTPUT
if (!MQTTClient_isConnected(client)) {
MQTTClient_create(&client, addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = TOKEN;
if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
fprintf(stderr, RED "\n==> Connection to MQTT Broker failed.\n" RESET_CL);
MQTTClient_destroy(&client);
free(payload);
exit(EXIT_FAILURE);
}
}
printf("DEBUG_AFTER >> MQTTClient_isConnected(client) = %d\n", MQTTClient_isConnected(client)); // DEBUG OUTPUT
pubmsg.payload = payload;
pubmsg.payloadlen = strlen(payload);
pubmsg.qos = QOS;
pubmsg.retained = 0;
MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
MQTTClient_waitForCompletion(client, token, TIMEOUT);
//MQTTClient_disconnect(client, 10000);
//MQTTClient_destroy(&client);
free(payload);
}
int main(void) {
for (i=0; i<1000; i++) {
publish_MQTT();
}
return 0;
}
Please ignore the fact that the addr parameter is never specified (in my real code it is) or that it is pretty useless specifying a message in the publish_MQTT() function (in my real code, data is passed from main() to that function).
I figured it out: Apparently, there is absolutely nothing wrong with the example codes in the original posting.
It turns out I was appending the port of the MQTT server to the addr parameter again and again (in a section of the code not shown here as I didn't suspect the source of the error to be there), every time the publish_MQTT() function was called. This made the addr char string grow and eventually exceed the specified length, thus causing the SegFault.
This way everything works just as intended:
printf("\nADDR = %s\n\n", addr); // DEBUG OUTPUT
if (!MQTTClient_isConnected(client)) {
strcat(strcat(addr, ":"), pt); // This line needed to be placed here, not before that if block
MQTTClient_create(&client, addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = TOKEN;
if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
printf("\n==> Connection to MQTT Broker failed.\n");
MQTTClient_destroy(&client);
free(payload);
exit(EXIT_FAILURE);
}
}
Probably you are setting up "clean session flag", what's mean: "
If the ClientId represents a Client already connected to the Server then the Server MUST disconnect the existing Client [MQTT-3.1.4-2]." (from mqtt standard). So you client is disconnected (the existing one).
Code from example seems to be reasobable. It looks like there is problem with passing function argument. For example if function needed address, and you are giving objects itself.
Morze from standard:
"3.2.2.2 Session Present
Position: bit 0 of the Connect Acknowledge Flags.
If the Server accepts a connection with CleanSession set to 1, the Server MUST set Session Present to 0 in the CONNACK packet in addition to setting a zero return code in the CONNACK packet [MQTT-3.2.2-1].
If the Server accepts a connection with CleanSession set to 0, the value set in Session Present depends on whether the Server already has stored Session state for the supplied client ID. If the Server has stored Session state, it MUST set Session Present to 1 in the CONNACK packet [MQTT-3.2.2-2]. If the Server does not have stored Session state, it MUST set Session Present to 0 in the CONNACK packet. This is in addition to setting a zero return code in the CONNACK packet".
Having strange connection failure with openssl SSLConnect with my SSLCLIENT.
We are trying to establish ssl connection with a server. We notice that SSL_CONNECT is failing with error code "SSL_ERROR_SYSCALL".
For further depth we tried printing strerror(errno) which return "scuccess" "0".
However i am just trying to understand what might be the exact cause for this issue
Added code snippet for SSL init and connect::
request some guidance:
int setupSSL(int server){
int retVal = 0;
int errorStatus = 0;
int retryMaxCount = 6;
static int sslInitContext=0;
if(sslInitContext == 0)
{
if(InitCTX() != 0)
{
return -1;
}
else
{
sslInitContext=1;
}
}
retVal = SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( retVal != 1 )
{
/* perform the connection */
sprintf(debugBuf,"SYSTEM:SOCKET:Could not set ssl FD: %d %s\n",retVal,strerror(retVal));
debug_log(debugBuf,TRACE_LOG);
CloseSocket(server);
return -1;
}
do
{
retVal = SSL_connect(ssl);
errorStatus = SSL_get_error (ssl, retVal);
switch (errorStatus)
{
case SSL_ERROR_NONE:
retVal = 0;
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
retVal = 1;
break;
default:
sprintf(debugBuf,"SYSTEM:SSL_SOCKET:Could not build SSL session(Other error): %d %s\n",errorStatus,strerror(errno));
debug_log(debugBuf,TRACE_LOG);
CloseSocket(server);
return -1;
}
sprintf(debugBuf,"SYSTEM:SSL_SOCKET:SSL CONNECTION Under PROGRESS: %d with remaining retries %d\n",errorStatus,retryMaxCount);
debug_log(debugBuf,TRACE_LOG);
if (retVal)
{
struct timeval tv;
fd_set sockReadSet;
tv.tv_sec = 2;
tv.tv_usec = 0;
FD_ZERO(&sockReadSet);
FD_CLR(server, &sockReadSet);
FD_SET(server,&sockReadSet);
retVal = select(server+1, &sockReadSet, NULL, NULL, &tv);
if (retVal >= 1)
{
retVal = 1;
}
else
{
retVal = -1;
}
retryMaxCount--;
if (retryMaxCount <= 0 )
break;
}
}while(!SSL_is_init_finished (ssl) && retVal == 1);
cert = SSL_get_peer_certificate(ssl);
if(cert == NULL)
{
debug_log("SYSTEM:SSL_SOCKET:Unable to retrive server certificate\n",TRACE_LOG);
CloseSocket(server);
return -1;
}
if(SSL_get_verify_result(ssl)!=X509_V_OK)
{
debug_log("SYSTEM:SSL_SOCKET:Certificate doesn't verify\n",TRACE_LOG);
CloseSocket(server);
return -1;
}
/*X509_NAME_get_text_by_NID (X509_get_subject_name (cert), NID_commonName, peer_CN, 256);
if(strcasecmp(peer_CN, cnName)){
debug_log("SYSTEM:SSL_SOCKET:Common name doesn't match host name\n",TRACE_LOG);
return -1;
}*/
return 0;
// LoadCertificates(ctx, CertFile, KeyFile);
}
int InitCTX(void)
{
int errorStatus = 0;
static int isSslInit = 1;
if(isSslInit)
{
OpenSSL_add_all_algorithms();/* Load cryptos, et.al. */
SSL_load_error_strings();/* Bring in and register error messages */
if(SSL_library_init() < 0)
{
debug_log("SYSTEM:SSL_SOCKET:Could not initialize the OpenSSL library\n",TRACE_LOG);
return -1;
}
method = TLSv1_client_method();
isSslInit=0;
}
ctx = SSL_CTX_new(method);/* Create new context */
if ( ctx == NULL)
{
debug_log("SYSTEM:SSL_SOCKET:Unable to create a new SSL context structure\n",TRACE_LOG);
//sprintf(debugBuf,"SYSTEM:SSL_SOCKET:Unable to create a new SSL context structure: %d %s\n",errorStatus,strerror(retVal));
//debug_log(debugBuf,TRACE_LOG);
return -1;
}
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
if (SSL_CTX_use_certificate_file(ctx,CertFile, SSL_FILETYPE_PEM) <= 0)
{
SSL_CTX_free(ctx);
ctx = NULL;
debug_log("SYSTEM:SSL_SOCKET:Error setting the certificate file.\n",TRACE_LOG);
return -1;
}
/* Set the list of trusted CAs based on the file and/or directory provided*/
if(SSL_CTX_load_verify_locations(ctx,CertFile,NULL)<1)
{
SSL_CTX_free(ctx);
ctx = NULL;
debug_log("SYSTEM:SSL_SOCKET:Error setting verify location.\n",TRACE_LOG);
return -1;
}
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_set_timeout (ctx, 300);
ssl = SSL_new(ctx); /* create new SSL connection state */
if(ssl == NULL)
{
sprintf(debugBuf,"SYSTEM:SOCKET:SSL:Unable to create SSL_new context\n");
debug_log(debugBuf,DEBUG_LOG);
if(ctx != NULL)
SSL_CTX_free(ctx);
return -1;
}
return 0;
}
Also is it advised to maintain SSL context for new connections or should we destroy and re init the ssl context??
Added PCAP info:
https://drive.google.com/file/d/0B60pejPe6yiSUk1MMmI1cERMaFU/view?usp=sharing
client: 198.168.51.10 (198.168.51.10), Server: 192.168.96.7 (192.168.96.7)
We are trying to establish ssl connection with a server. We notice that SSL_CONNECT is failing with error code "SSL_ERROR_SYSCALL".
This is usually the case if the other side is simply closing the connection. Microsoft SChannel does this on many kind of handshake problems instead of sending a TLS alert back. This can happen for problems like invalid protocol or no common ciphers etc. It also can happen if you try to do a TLS handshake with a server which does not speak TLS at all on this port. Look at logs at the server side for problems.
Of course it can also be something different so you might check the errno to get more details about the problem. It might also help if you do a packet capture to check what's going on on the wire. Best would be to do this capture on the client and server side to make sure that no middlebox like a firewall is tampering with the connection.
Also is it advised to maintain SSL context for new connections or should we destroy and re init the ssl context??
The context is just a collection of settings, certificates etc and is not affected by the SSL connection itself. You can reuse it for other connection later or at the same time.
EDIT, after the packet capture was attached:
There are multiple TCP connection in the file between client and server and only inside a single one the client tries to initiate a handshake, i.e. the ClientHello can be seen. The server closes the connection. A few things a interesting:
TCP handshake takes very long. The server only replies after 1.6 seconds after receiving the SYN with the SYN+ACK. Also the other replies take 800ms which is very long given that both addresses are in a private network (192.168.0.0). This might indicate a slow connection or VPN (this is about the latency of a satellite link), some middlebox (firewall) slowing everything down or a really slow server.
Client sends TLS 1.0 request. It might be that the server will do only TLS 1.1+. Some TLS stacks (see above) simply close the connection on such errors instead of sending an unsupported protocol alert. But given that the server is slow it might also be old and only support SSL 3.0 or lower.
Client does not use SNI extension. More and more servers need this and might simply close if they don't get the extension.
It is hard to know what really is going on without having access to the server. I recommend to look for error messages on the server side and use tools like SSLyze to check the requirements of the server, i.e. supported TLS versions, ciphers etc.
Apart from that client offers dangerously weak ciphers like various EXPORT ciphers. This looks for me like the defaults of a considerably old OpenSSL version.
I have a tiny C proxy server which I just want to get one request at a time from the client and send back the response from the server. No pipelining, no anything advanced, just a persistent http connection.
Structs:
typedef struct http_request {
char* h_data; // Header raw data
int h_size; // Header size
char host[5000]; // Host to connect to
char resource[5000]; // Resource to get
} http_request;
typedef struct http_response {
char* h_data; // Header raw data
int h_size; // Header size
char* b_data; // Body raw data
int b_size; // Content-length of the body
} http_response;
Code:
while(1){
// Waiting for user to connect
int sock_user = accept(sock, (struct sockaddr*)NULL, NULL);
int sock_host=-1;
// Accept 1 request at a time and respond
while(1){
http_request req;
http_response resp;
// 1. Client ==> Proxy Server
http_parse_request(sock_user, &req); // uses recv(sock_user)
// 2. Client Proxy ==> Server
if (sock_host < 0)
sock_host=proxy_connect_host(req.host);
write(sock_host, req.h_data, req.h_size);
// 3. Client Proxy <== Server
http_parse_response(sock_host, &resp); // uses send(sock_host)
// 4. Client <== Proxy Server
write(sock_user, resp.h_data, resp.h_size);
write(sock_user, resp.b_data, resp.b_size);
}
}
Now this works good for a few first pages. Then the program blocks at step 1 and the browser just shows Waiting for www.calcoolate.com... all the time.
Firebug:
All of those GET, are requests sent to my proxy. I however receive only the first two of them. I double checked the return value of each write() and recv() and they seem to match exactly with what is expected. I checked for both -1s and 0s.
There must be something wrong with the logic of my proxy.. Any ideas?