libucrl failed to check server certificate - ssl

I am using libcurl (in C) to login to a secure site (https). So far it was working fine. Since yesterday it is not able to login. The code looks as below.
bool login(char *user, char *password)
{
bool result = false;
CURL * curl = NULL;
char errbuf[CURL_ERROR_SIZE];
char status_text[1024];
CURLcode res;
long resp_code = 0;
int index;
/* These fields should be collected from license file */
char *user_field = "name";
char *password_field = "pass";
char *form_id_field = "form_id";
char *form_id = "user_login";
char *link = "https://example.com/user/login";
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl == NULL) goto on_error;
curl_easy_reset(curl);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/4.0");
curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)NULL);
curl_easy_setopt(curl, CURLOPT_URL, link);
res = curl_easy_perform(curl);
if(res == CURLE_OK)
{
curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_REFERER, link);
/* Data should be "name=user&pass=password&form_id=user-login" */
index = sprintf(status_text, "%s=%s&%s=%s&%s=%s",
user_field, user, password_field,
password, form_id_field, form_id);
*(status_text + index) = 0x0;
resp_code = 0;
res = CURLE_ABORTED_BY_CALLBACK;
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, status_text);
res = curl_easy_perform(curl);
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &resp_code);
if((resp_code == 200) && (res != CURLE_ABORTED_BY_CALLBACK))
{
result = true;
}
else
{
result = false;
}
}
on_error:
if(curl)
{
curl_easy_cleanup(curl);
curl_global_cleanup();
curl_global_cleanup();
}
return result;
}
While curl_easy_perform is executed it fails. The errbuf shows error like "server certificate verification failed. cafile /etc/ssl/certs/ca-certificates.crt crlfile none". I understand it is somewhat problematic with /etc/ssl/certs/ca-certificates.crt file, but I did not change anything.
What may be the issue here, any hint to fix this, highly appreciated.

It is more a hint than an answer but I don't have enough rep points to comment.
Since yesterday it is not able to login
This might be connected to the fact that Sectigo's legacy AddTrust External CA Root certificate expired on May 30, 2020 https://support.sectigo.com/articles/Knowledge/Sectigo-AddTrust-External-CA-Root-Expiring-May-30-2020
From the link above
Certificates for your site are issued from a “chain” of issuing or “intermediate” CA that completes a path back to these trusted root certificates.
If I understand the above statement correctly, AddTrust External CA Root certificate is probably one of the certs in chain thus validation fails - at least for some clients.
EDIT
What also worked for me is this https://www.agwa.name/blog/post/fixing_the_addtrust_root_expiration
edit /etc/ca-certificates.conf and put a bang/exclamation mark (!) before mozilla/AddTrust_External_Root.crt
Run update-ca-certificates

Related

OpenSSL TLS server cant get client cetificate

When I tried to auth client certificate on server side. But SSL_get_peer_certificate always return NULL even client sent correct Certificate(confirmed in wireshark log). Could you help give some suggestion?
I read all realted cases in stackoverflow, but still not find reason.
server code:
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
if(!SSL_CTX_use_certificate_file(ssl_ctx, serverCert_filename,SSL_FILETYPE_PEM)
|| !SSL_CTX_use_PrivateKey_file(ssl_ctx, serverKey_filename, SSL_FILETYPE_PEM)
|| !SSL_CTX_check_private_key(ssl_ctx))
{
ERR_print_errors_fp(stderr);
}
if (!SSL_CTX_load_verify_locations(ssl_ctx, serverCertRoot_filename, NULL))
{
print error info.
}
SSL_CTX_use_certificate_chain_file(ssl_ctx, serverCert_filename) ;
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
cert_names = SSL_load_client_CA_file(serverCertRoot_filename);//serverCert_filename //clientCert_filename //serverCertRoot_filename
if (cert_names != NULL)
{
SSL_CTX_set_client_CA_list(ssl_ctx, cert_names);
}
SSL_CTX_set_verify_depth(ssl_ctx, 10);
....
ssl = SSL_new(ssl_ctx);
X509* cert = NULL;
cert = SSL_get_peer_certificate(ssl);
//here, cert always is NULL
int res = SSL_get_verify_result(ssl);
client code:
//Client can work well.
ctx = SSL_CTX_new(method);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_verify_depth(ctx, 10);
if (!SSL_CTX_use_certificate_file(ctx, clientCert_filename, SSL_FILETYPE_PEM)
|| !SSL_CTX_use_PrivateKey_file(ctx, clientKey_filename, SSL_FILETYPE_PEM)
|| !SSL_CTX_check_private_key(ctx))
{
ERR_print_errors_fp(stderr);
}
if (!SSL_CTX_load_verify_locations(ctx, clientCertRoot_filename, NULL))
errhandle.
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
....
ssl = SSL_new(ssl_ctx);
peer_cert = SSL_get_peer_certificate(ssl);
int res = SSL_get_verify_result(ssl);

Connection failed with SSL with ESP8266

I want to create an SSL connection with my site to send data and every time I connect it fails!
I am using WiFiClientSecure.h library but I don't know where is the problem is it from code or library or from my site?
here is my code:
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <DHT.h>
#include <WiFiClientSecure.h>
#define DHTPIN D6
#define DHTTYPE DHT11
const char* ssid = "SSID";
const char* password = pass";
char host[] = "mysite.com";
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(115200);
delay(100);
dht.begin();
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Netmask: ");
Serial.println(WiFi.subnetMask());
Serial.print("Gateway: ");
Serial.println(WiFi.gatewayIP());
}
void loop (){
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
Serial.print("connecting to ");
Serial.println(host);
int httpPort = 443;
//Add a SSL client
WiFiClientSecure client;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
String url = "/insert.php?temp=" + String(t) + " ;
Serial.print("Requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
delay(500);
while(client.available()){
String line = client.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("closing connection");
}
Is the issue in the code or from my site?
The ESP8266 is an embedded processor. It has many limitations. One of them is that it doesn't store certificates for any CAs.
As the documentation for the esp32 says "here are three ways to establish a secure connection using the WiFiClientSecure class: using a root certificate authority (CA) cert, using a root CA cert plus a client cert and key, and using a pre-shared key (PSK)."
If your cert is signed by a server with a well known CA then you can use CA method. You call the setCACert function with the certifcate that you can obtain using openssl. You need to save this certificate in as an array. It should look someling like this (DER) format.
const char* test_root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" \
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" \
............
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" \
"-----END CERTIFICATE-----\n";
The in your code you should place a
client.setCACert(test_root_ca);
before you call the client.connect.

OpenLDAP - Enabling CRL check for LDAP TLS connections

I have a client that connects to LDAP server using TLS. For this connection, I want to enable CRL check and reject the connection only if any server/client certificates are revoked.
In special cases (like CRL missing, CRL expired) I want to ignore the error and establish the connection.
So I though to overwrite the default SSL verify call back to ignore the specific errors.
But the call back is not called at all. Always only default call-back is called.
Here is my call back:
static int verify_callback(int ok, X509_STORE_CTX *ctx)
{
X509* cert = X509_STORE_CTX_get_current_cert(ctx);
if (ok)
return ok;
int sslRet = X509_STORE_CTX_get_error(ctx);
const char* err = NULL;
switch (sslRet)
{
case X509_V_ERR_UNABLE_TO_GET_CRL:
case X509_V_ERR_CRL_HAS_EXPIRED:
case X509_V_ERR_CRL_NOT_YET_VALID:
printf( "CRL: Verification failed... but ignored : %d\n", sslRet);
return 1;
default:
err = X509_verify_cert_error_string(sslRet);
if (err)
printf( "CRL: Failed to verify : %s\n",err);
return 0;
}
return sslRet;
}
Default verify call-back is overwritten using the ldap call-back set option:
void ldap_tls_cb(LDAP * ld, SSL * ssl, SSL_CTX * ctx, void * arg)
{
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER , verify_callback);
printf("verify call back is set...\n");
return;
}
Main Program:
int main( int argc, char **argv )
{
LDAP *ldap;
int auth_method = LDAP_AUTH_SIMPLE; //LDAP_AUTH_SASL
int ldap_version = LDAP_VERSION3;
char *ldap_host = "10.104.40.35";
int ldap_port = 389;
if ( (ldap = ldap_init(ldap_host, ldap_port)) == NULL ) {
perror( "ldap_init failed" );
return( EXIT_FAILURE );
}
int result = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "ldap_set_option failed!");
return(EXIT_FAILURE);
}
int requireCert = LDAP_OPT_X_TLS_DEMAND;
result = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &requireCert);
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "ldap_set_option - req cert -failed!");
return(EXIT_FAILURE);
}
result = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, "/etc/certs/Cert.pem");
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "ldap_set_option - cert file - failed!");
return(EXIT_FAILURE);
}
int crlvalue = LDAP_OPT_X_TLS_CRL_ALL;
result =ldap_set_option(NULL, LDAP_OPT_X_TLS_CRLCHECK, &crlvalue);
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "ldap_set_option failed!");
return(EXIT_FAILURE);
}
int debug = 7;
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debug);
result = ldap_set_option(ldap, LDAP_OPT_X_TLS_CONNECT_CB, (void *)ldap_tls_cb);
if (result != LDAP_SUCCESS) {
fprintf(stderr, "ldap_set_option(LDAP_OPT_X_TLS_CONNECT_CB): %s\n", ldap_err2string(result));
return(1);
}
int msgidp = 0;
result = ldap_start_tls(ldap,NULL,NULL,&msgidp);
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "start tls failed!");
return result;
} else {
printf("Start tls success.\n");
}
LDAPMessage *resultm;
struct timeval timeout;
result = ldap_result(ldap, msgidp, 0, &timeout, &resultm );
if ( result == -1 || result == 0 ) {
printf("ldap_result failed;retC=%d \n", result);
return result;
}
result = ldap_parse_extended_result(ldap, resultm, NULL, NULL, 0 );
if ( result == LDAP_SUCCESS ) {
result = ldap_install_tls (ldap);
printf("installing tls... %s\n", ldap_err2string(result));
}
int request_id = 0;
result = ldap_sasl_bind(ldap, "", LDAP_SASL_SIMPLE, NULL, 0, 0, &request_id);
if ( result != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_x_bind_s: %s\n", ldap_err2string(result));
printf("LDAP bind error .. %d\n", result);
return(EXIT_FAILURE);
} else {
printf("LDAP connection successful.\n");
}
ldap_unbind(ldap);
return(EXIT_SUCCESS);
}
can someone help to check why my verify call-back is not called?
I think you need to set the callback on the SSL object directly instead of the context, so
void ldap_tls_cb(LDAP * ld, SSL * ssl, SSL_CTX * ctx, void * arg)
{
SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_callback);
printf("verify call back is set...\n");
return;
}
The reason for this is that the SSL handle has already been initialised by the time your connect callback is called (see the OpenLDAP code), and
it's too late to set this callback through the context at that point:
If no special callback was set before, the default callback for the underlying ctx is used, that was valid at the time ssl was created with SSL_new(3).
OpenLDAP can be built with GnuTLS, so you may need to check that it's using OpenSSL before setting the callback. The LDAP_OPT_X_TLS_PACKAGE option could be used for this (note that I haven't tested this code):
char* package = NULL;
int result = ldap_get_option(NULL, LDAP_OPT_X_TLS_PACKAGE, (void *)&package);
if (result != LDAP_OPT_SUCCESS) {
ldap_perror(ldap, "ldap_get_option failed!");
return(EXIT_FAILURE);
} else {
if (strcmp(package, "OpenSSL") == 0) {
// Set your callback
}
ldap_memfree(package);
}

SSL certificate prob: self signed certificate

I use this HTTP client to connect to my server
code :
curl = curl_easy_init();
if(curl) {
CURLcode res;
char errbuf[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
/* provide a buffer to store errors in */
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
/* set the error buffer as empty before performing a request */
errbuf[0] = 0;
/* perform the request */
res = curl_easy_perform(curl);
/* if the request did not complete correctly, show the error
information. if no detailed error information was written to errbuf
show the more generic information from curl_easy_strerror instead.
*/
if(res != CURLE_OK) {
size_t len = strlen(errbuf);
fprintf(stderr, "\nlibcurl: (%d) ", res);
if(len)
fprintf(stderr, "%s%s", errbuf,
((errbuf[len - 1] != '\n') ? "\n" : ""));
else
fprintf(stderr, "%s\n", curl_easy_strerror(res));
}
}
but the connexion failed and I got this error msg :
SSL certificate problem: self signed certificate
libcurl: (60) SSL certificate problem: self signed certificate
the certification is under /etc/ssl folder and it is a valid certification
how to proceed to solve this issue !

openssl header ssl

is there additional header which is presented by openssl before sending the message to socket ?
Thanks
I assume you're talking about TLS ("Secured TCP").
Then yes. Once the handshake between client and server is done, the "data" messages usually start with 3 special bytes (if I remember well) that indicates to the SSL layer that the frame is ciphered.
On the other hand, you cannot assume that the size of a ciphered frame will be the same of the raw frame/data.
Here you get an example function in C/C++.
bool isCiphered(const char* buf, size_t buflen)
{
if (buflen < 3)
{
return false;
}
uint8_t c = buf[0];
switch (c)
{
case 0x14:
case 0x15:
case 0x16:
case 0x17:
{
uint8_t v1 = buf[1];
uint8_t v2 = buf[2];
/* TLS v1 */
if ((v1 == 0x03) && (v2 == 0x01))
{
return true;
}
/* DTLS v1 */
if ((v1 == 0xfe) && (v2 == 0xff))
{
return true;
}
break;
}
}
return false;
}
I had to adapt my existing code so i'm not sure that compiles, but you should get the idea.