Home > OS >  Why system's ssl certificates are not verified?
Why system's ssl certificates are not verified?

Time:08-09

I made the following piece of software that sends a Https get request towards google's homepage via SSL:

#include <stdio.h>
#include<string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <netdb.h>
#include <unistd.h>

#include <stdlib.h>

#ifndef INADDR_NONE
    #define INADDR_NONE 0xffffffff
#endif  //INADDR_NONE 

typedef int SOCKET;

SOCKET OpenConnection(char* hostname, char* port){
    struct hostent *phe;
    struct sockaddr_in sin;
    unsigned int port_as_integer = htons((unsigned short)atoi(port));

    int sock;

    memset(&sin,0,sizeof(sin));
    sin.sin_family = AF_INET;

    if(port_as_integer == 0){
        return -1;
    }

    sin.sin_port = port_as_integer;
    
    if(phe = gethostbyname(hostname)){
        memcpy(&sin.sin_addr,phe->h_addr, phe->h_length);
    } else if((sin.sin_addr.s_addr = inet_addr(hostname)) == INADDR_NONE){
        return -1;
    }

    sock = socket(PF_INET,SOCK_STREAM,6);

    if(socket < 0 || connect(sock, (const struct sockaddr *)&sin, sizeof(sin) ) < 0 ){
        return -1;
    }

    return (SOCKET) sock;
}

int verifyCerts( SSL_CTX* ctx )
{
    
    const char *path = getenv(X509_get_default_cert_dir_env());

    if (!path){
        path = X509_get_default_cert_dir();
    }

    return SSL_CTX_load_verify_locations(ctx,NULL,path);
}

void releaseSocket( SSL_CTX* ctx, int server)
{
    /* close socket */
    close(server);   
    /* release context */
    SSL_CTX_free(ctx);        
    putchar('\n');
}


SSL_CTX* InitCTX(void)
{
    OpenSSL_add_all_algorithms(); 
    SSL_load_error_strings();
    const SSL_METHOD* method = SSLv23_method();
    SSL_CTX* ctx = SSL_CTX_new(method);
    SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1);
    
    if (ctx == NULL)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
   
    int value = verifyCerts( ctx );
    if(value == 0) {
        printf("Certificate error\n");
        exit(1);
    }

    SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);

    return ctx;
}

void ShowCerts(SSL* ssl)
{
    X509* cert;
    char* line;
    cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
    if (cert != NULL)
    {
        printf("Server certificates:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("Subject: %s\n", line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("Issuer: %s\n", line);
        //free(line);       /* free the malloc'ed string */
        X509_free(cert);     /* free the malloc'ed certificate copy */
    } else {
        printf("Info: No client certificates configured.\n");
    } 
}

int main(int argc, char* argv[])
{
    printf("Initializing Connection");
    char buf[1024];
    
    SSL_library_init();
    char* hostname = "google.com";
    char* portnum = "443";

    int bytes=0,error=0;

    const char* cpRequestMessage = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Mozilla/5.0 (Android 4.4; Tablet; rv:41.0) Gecko/41.0 Firefox/41.0\r\nConnection: close\r\nAccept: text/html;UTF-8\r\nAccept-Lang: gr\r\n\r\n";

    SSL_CTX* ctx = InitCTX();
    int server = OpenConnection(hostname, portnum);
    SSL* ssl = SSL_new(ctx);      /* create new SSL connection state */
    SSL_set_fd(ssl, server);    /* attach the socket descriptor */


    if (SSL_connect(ssl) == FAIL) {
        ERR_print_errors_fp(stderr);
    } else {

        printf("\n\nConnected with %s encryption\n", SSL_get_cipher(ssl));
       
        /* encrypt & send message */
        printf("REQUEST:\n\n%s\n",cpRequestMessage);
        SSL_write(ssl, cpRequestMessage, strlen(cpRequestMessage));  


        do {

            int bytes = SSL_read(ssl, buf, sizeof(buf));
            int error = SSL_get_error(ssl,bytes);

            switch (error)
            {
                case SSL_ERROR_SSL:
                    puts("SSL ERROR SSL");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_SYSCALL:
                    puts("SSL ERROR SYSCALL");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_ASYNC_JOB:
                    puts("SSL ERROR WANT ASYNC_LOOKUP");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_ASYNC:
                    puts("SSL ERROR WANT X509_LOOKUP");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_X509_LOOKUP:
                    puts("SSL ERROR WANT X509_LOOKUP");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_WRITE:
                    puts("SSL ERROR WANT WRITE");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_READ:
                    puts("SSL ERROR WANT READ");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_ZERO_RETURN:
                    puts("SSL ERROR SSL_ERROR_ZERO_RETURN");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_NONE:
                default:
                    break;
            }

            puts(buf);
        } while (bytes>0);
        
        /* release connection state */
        SSL_free(ssl);       
    }

    releaseSocket(ctx,server);   
    putchar('\n');
    return 0;
}

The verification happens using system's CA path folder. But for some reason SSL certificates are not verified:

39690623349184:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:../ssl/statem/statem_clnt.c:1924:
Initializing Connection

Do you know the reason why that happens?

Edit 1

I also tried to manually place the system's certificate path:

First I detected the path (despite the command that fails I just need to find the location of the certs.

update-ca-certificates  --verbose
Updating certificates in /etc/ssl/certs...
/usr/sbin/update-ca-certificates: 101: /usr/sbin/update-ca-certificates: cannot create /etc/ssl/certs/ca-certificates.crt.new: Permission denied

Then I tried doing the following:

int verifyCerts( SSL_CTX* ctx )
{

    return SSL_CTX_load_verify_locations(ctx,NULL,"/etc/ssl/certs");
}

By manually specifying the path as /etc/ssl/certs. The rationale is to check whether or not I can verify using a hardcoded location for the certificates provided from my system.

Once I rebuilt my application, I found out that still fails:

139850890965440:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:../ssl/statem/statem_clnt.c:1924:
Initializing Connection

But the path is full of certificates:

$ ls -l /etc/ssl/certs/ | head
σύνολο 560
lrwxrwxrwx 1 root root     23 Ιουν  9 21:35 002c0b4f.0 -> GlobalSign_Root_R46.pem
lrwxrwxrwx 1 root root     45 Μαΐ   8  2020 02265526.0 -> Entrust_Root_Certification_Authority_-_G2.pem
lrwxrwxrwx 1 root root     36 Μαΐ   8  2020 03179a64.0 -> Staat_der_Nederlanden_EV_Root_CA.pem
lrwxrwxrwx 1 root root     27 Μαΐ   8  2020 062cdee6.0 -> GlobalSign_Root_CA_-_R3.pem
lrwxrwxrwx 1 root root     25 Μαΐ   8  2020 064e0aa9.0 -> QuoVadis_Root_CA_2_G3.pem
lrwxrwxrwx 1 root root     50 Μαΐ   8  2020 06dc52d5.0 -> SSL.com_EV_Root_Certification_Authority_RSA_R2.pem
lrwxrwxrwx 1 root root     54 Μαΐ   8  2020 09789157.0 -> Starfield_Services_Root_Certificate_Authority_-_G2.pem
lrwxrwxrwx 1 root root     15 Οκτ  30  2020 0a775a30.0 -> GTS_Root_R3.pem
lrwxrwxrwx 1 root root     16 Μαΐ   8  2020 0b1b94ef.0 -> CFCA_EV_ROOT.pem

All of them symlinked from various paths.

CodePudding user response:

You are unable to verify the certificate because you need to place the following line (as specified upon this answer) to main function:

    int res = SSL_set_tlsext_host_name(ssl, hostname);
    if(res == 0) {
        ERR_print_errors_fp(stderr);
    }

Resulting this main:

int main(int argc, char* argv[])
{
    printf("Initializing Connection");
    char buf[1024];
    
    SSL_library_init();
    char* hostname = "google.com";
    char* portnum = "443";

    int bytes=0,error=0;

    const char* cpRequestMessage = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Mozilla/5.0 (Android 4.4; Tablet; rv:41.0) Gecko/41.0 Firefox/41.0\r\nConnection: close\r\nAccept: text/html;UTF-8\r\nAccept-Lang: gr\r\n\r\n";

    SSL_CTX* ctx = InitCTX();
    int server = OpenConnection(hostname, portnum);
    SSL* ssl = SSL_new(ctx);      /* create new SSL connection state */
    SSL_set_fd(ssl, server);    /* attach the socket descriptor */

    int res = SSL_set_tlsext_host_name(ssl, hostname);
    if(res == 0) {
        ERR_print_errors_fp(stderr);
    }
    
    if (SSL_connect(ssl) == FAIL) {
        ERR_print_errors_fp(stderr);
    } else {

        printf("\n\nConnected with %s encryption\n", SSL_get_cipher(ssl));
       
        /* encrypt & send message */
        printf("REQUEST:\n\n%s\n",cpRequestMessage);
        SSL_write(ssl, cpRequestMessage, strlen(cpRequestMessage));  


        do {

            int bytes = SSL_read(ssl, buf, sizeof(buf));
            int error = SSL_get_error(ssl,bytes);

            switch (error)
            {
                case SSL_ERROR_SSL:
                    puts("SSL ERROR SSL");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_SYSCALL:
                    puts("SSL ERROR SYSCALL");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_ASYNC_JOB:
                    puts("SSL ERROR WANT ASYNC_LOOKUP");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_ASYNC:
                    puts("SSL ERROR WANT X509_LOOKUP");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_X509_LOOKUP:
                    puts("SSL ERROR WANT X509_LOOKUP");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_WRITE:
                    puts("SSL ERROR WANT WRITE");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_WANT_READ:
                    puts("SSL ERROR WANT READ");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_ZERO_RETURN:
                    puts("SSL ERROR SSL_ERROR_ZERO_RETURN");
                    releaseSocket(ctx,server);
                    return 1;
                case SSL_ERROR_NONE:
                default:
                    break;
            }

            puts(buf);
        } while (bytes>0);
        
        /* release connection state */
        SSL_free(ssl);       
    }

    releaseSocket(ctx,server);   
    putchar('\n');
    return 0;
}

Using that you can verify using systems certificates. The verifyCerts works fine as seems here:

int verifyCerts( SSL_CTX* ctx )
{
    
    const char *path = getenv(X509_get_default_cert_dir_env());

    if (!path){
        path = X509_get_default_cert_dir();
    }

    return SSL_CTX_load_verify_locations(ctx,NULL,path);
}
  • Related