'OpenSSl Error: peer did not return a certificate

I am using OpenSSL integration on my existing code to achieve SSL security. My Client side code is in c++ and is on Windows OS and the back-end code, server, code is on AIX.

The certificates are created by following the below commands on AIX and the client certificate and key created are being used at clent end i.e Windows:

//Commands to create the CA authority

  1. openssl genrsa -des3 -out Keys/RootCA_test.key 2048

  2. openssl req -new -x509 -days 360 -key Keys/RootCA_test.key -out Certificates/RootCA_test.crt

//Commands to create the server certificate

  1. openssl genrsa -out Keys/server_test.key 2048
  2. openssl req -new -key Keys/server_test.key -out CSR/server_test.csr
  3. openssl ca -days 360 -in CSR/server_test.csr -out Certificates/server_test.crt -keyfile Keys/RootCA_test.key -cert Certificates/RootCA_test.crt

//Commands to create the client certificate

  1. openssl genrsa -out Keys/client_test.key 2048

  2. openssl req -new -key Keys/client_test.key -out CSR/client_test.csr

  3. openssl ca -days 360 -in CSR/client_test.csr -out Certificates/client_test.crt -keyfile Keys/RootCA_test.key -cert Certificates/RootCA_test.crt

After integrating the code looks like:

Client Code - On Windows

 #include "stdafx.h"
    #include <string>
    #include <stdio.h>
    #include <openssl/ssl.h> // SSL and SSL_CTX for SSL connections
    #include <openssl/err.h> // Error reporting


    SOCKET s;
    SSL_CTX *ctx;
    SSL *ssl;
    int OpenConnection(const char *hostname, int port)
    {   int sd;
        struct hostent *host;
        struct sockaddr_in addr;

        if ( (host = gethostbyname(hostname)) == NULL )
        {
            perror(hostname);
            abort();
        }
        sd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);    
        memset(&addr,0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = *(long*)(host->h_addr);
        if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
        {
            close(sd);
            perror(hostname);
            abort();
        }
        return sd;
    }

    BOOL InitOpenSSL()//OPENSSL
    {
        //set default locations for trusted CA certificates
        CString sslCrtFilePath  = "C:\\Program Files\\cv\\certificates\\client_test.crt";
        CString sslKeyFilePath  = "C:\\Program Files\\cv\\certificates\\client_test.key";
        CString sslRootFilePath = "C:\\Program Files\\cv\\certificates\\RootCA_test.crt";
        int server;
        char buf[1024];
        int bytes;
        char hostname[]="20.17.127.235";   
        int portnum = 4005;
        SSL_library_init();
        SSL_METHOD *method;    

        OpenSSL_add_all_algorithms();  /* Load cryptos, et.al. */
        SSL_load_error_strings();   /* Bring in and register error messages */
        method = SSLv23_client_method();//SSLv23_method();  /* Create new client-method instance */
        ctx = SSL_CTX_new(method);   /* Create new context */
        if ( ctx == NULL )
        {        
            abort();
        }
        if (!(LoadCertificates(sslRootFilePath.GetBuffer(sslRootFilePath.GetLength()),sslCrtFilePath.GetBuffer(sslCrtFilePath.GetLength()), sslKeyFilePath.GetBuffer(sslKeyFilePath.GetLength()))))
        {
            s = INVALID_SOCKET;     
            cout << "Failed to load certificate file and key file.";
            return false;
        }   
        ctx  = SSL_CTX_new(method);   /* Create new context */  
        ssl = SSL_new(ctx);      /* create new SSL connection state */
        if ( ctx == NULL )
        {
            ERR_print_errors_fp(stderr);
            s = INVALID_SOCKET;
            cout << "Error in creating SSL_CTX object.";
            return FALSE;
        }
        server = OpenConnection(hostname, portnum);
        SSL_set_fd(ssl, server);    /* attach the socket descriptor */   
        int n = SSL_connect(ssl);
        if ( n != 1 )   /* perform the connection */
        {
            int rc = SSL_get_error(ssl,n);  
            cout << "Error in SSL_connect";      
            exit(1);
        }
        else
        {   char *msg = "Hello! I am Client.Who are you ?\n";
            cout << "Connected with " << SSL_get_cipher(ssl) << " encryption" ;        
            SSL_write(ssl, msg, strlen(msg));   /* encrypt & send message */
            bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
            buf[bytes] = 0;
            cout << buf;
            SSL_free(ssl);        /* release connection state */
        }
        close(server);         /* close socket */
        SSL_CTX_free(ctx);        /* release context */
        return 0;   

    }
    bool LoadCertificates(char* sslRootFilePath,char* CertFile, char* KeyFile)//OPENSSL
    {
         if(!SSL_CTX_load_verify_locations(ctx,sslRootFilePath , NULL))
            {
                /* Handle error here */ 
                s = INVALID_SOCKET;
                cout << "Failed to load root CA certificate.";
                return FALSE;
            }       
            /*Set cipher list*/
            if (SSL_CTX_set_cipher_list(ctx,CIPHER_LIST) <= 0) 
            {
                cout << "Error setting the cipher list.";
            }

            if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM ) <= 0 )
            {
                cout << "Failed in setting the local certificate from CertFile.";
                return false;
            }
            /* set the private key from KeyFile (may be the same as CertFile) */
             if ( SSL_CTX_use_PrivateKey_file (ctx, KeyFile , SSL_FILETYPE_PEM) != 1 ) //SSL_FILETYPE_PEM
            {
                cout << "Failed in setting the private key from KeyFile.";
                return false;        
            }
            /* verify private key */
            if ( !SSL_CTX_check_private_key(ctx) )
            {
                cout << ("Failed in verifying private key.", MB_TOPMOST | MB_SETFOREGROUND|MB_OK);
                return false;        
            }
    }
    int main()
    {   
        BOOL st = InitOpenSSL();
        return 0;
    }

Server Code On AIX

SSL_CTX *ctx; SSL *ssl;

    string root,key,cert;
    int OpenListener(int port)
    {
         cout <<  "OpenListener() Start" << endl ;
         int sd;
        struct sockaddr_in addr;   
        int portno = 4005;
        sd = socket(AF_INET, SOCK_STREAM, 0); 
         memset(&addr,0, sizeof(addr));

         addr.sin_family = AF_INET;
         addr.sin_port = htons(portno);
         addr.sin_addr.s_addr = INADDR_ANY;


        if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
        {
            cout << "can't bind port" << endl;
            abort();
        }
        if ( listen(sd, 10) != 0 )
        {
         cout << "Can't configure listening port" << endl;
         abort();
        }
        cout << "Port : " <<  addr.sin_port  << " Address : " << addr.sin_addr.s_addr << endl;
        cout <<  "OpenListener() End" << endl ;
        return sd;
    }
    void Servlet(SSL* ssl) 
    {
     cout <<  "Servlet() Start" << endl;
     char buf[1024];
     char reply[1024];
     int sd, bytes;

     if ( SSL_accept(ssl) != 1 )     /* do SSL-protocol accept */
     ERR_print_errors_fp(stderr);
     else
      {
            cout <<  "SSL_accept() executed" << endl;
            ShowCerts();        /* get any certificates */
            bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
            if ( bytes > 0 )
            {
                buf[bytes] = 0;
                cout << "Client msg: " <<  buf << endl;            
                SSL_write(ssl, reply, strlen(reply)); /* send reply */
            }
            else
              {
                cout << " Bytes returned by SSL_read() is 0" << endl;
                ERR_print_errors_fp(stderr);
               }
        }
        sd = SSL_get_fd(ssl);       /* get socket connection */
        SSL_free(ssl);         /* release SSL state */
        close(sd);          /* close connection */
        cout <<  "Servlet() End" << endl;
    }
    void ShowCerts()
    {
        cout <<  "ShowCerts() Start " << endl;
        X509 *cert;
        char *line;
        cout << "SSL_get_peer_certificate Initiated " << endl;
        cert = SSL_get_peer_certificate(ssl);       /* Get certificates (if available) */
        if ( cert != NULL )
        {
            cout << "Server certificates: " << endl;
            line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
            cout << "Subject: " << line  << endl;
            free(line);
            line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
            cout << "Issuer: " << line  << endl;
            free(line);
            X509_free(cert);
        }
        else
          cout << "SSL_get_peer_certificate() returns NULL  " << endl;

        cout <<  "ShowCerts() End " << endl;

    }

    bool InitOpenSSL()
    {
        cout <<  "InitOpenSSL() Starts" << endl;
        SSL_library_init();
        SSL_METHOD *method;

        OpenSSL_add_all_algorithms();  /* Load cryptos, et.al. */
        SSL_load_error_strings();   /* Bring in and register error messages */
        method = const_cast <SSL_METHOD *> (SSLv23_server_method());  /* Create new server-method instance */
        ctx  = SSL_CTX_new(method);   /* Create new context */

            if ( ctx == NULL )
            {
                    ERR_print_errors_fp(stderr);
                    cout << "Error in creating SSL_CTX object."  << endl;
                    return false;
            }
            //set default locations for trusted CA certificates
            cout << "Server Certificate Used : " << cert << endl;
            cout << "Server Key Used         : " << key  << endl;
            if (!(LoadCertificates(const_cast<char *> (cert.c_str()), const_cast <char*> (key.c_str()))) )
            {
                    cout << "Failed to load certificate file and key file." << endl;
                    return false;
            }
           SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
           SSL_CTX_set_verify_depth(ctx, 4); 
           if(!SSL_CTX_load_verify_locations(ctx,root.c_str() , NULL) )
              cout << "SSL_CTX_load_verify_locations failed." << endl;
           else
              cout << "SSL_CTX_load_verify_locations passed." << endl;

           int  server = OpenListener(4005);                                /* create server socket */
           cout << "OpenListener() returns : " << server << endl;
           while (1)
           {
             cout << "In While(1) Loop " << endl;
             struct sockaddr_in addr;
             socklen_t len = sizeof(addr);
             cout << "::accept() called, get ready!" << endl ;
             int client = ::accept(server, (struct sockaddr*)&addr, &len);          /* accept connection as usual */
             cout << "::accept() returns " << client << endl;
             //printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
             cout << "Connection " << inet_ntoa(addr.sin_addr) << ntohs(addr.sin_port) << endl;
             ssl = SSL_new(ctx);                                            /* get new SSL state with context */
             SSL_set_fd(ssl, client);                                               /* set connection socket to SSL state */
             Servlet(ssl);                                                                  /* service connection */
           }
        close(server);                                                                              /* close server socket */
        SSL_CTX_free(ctx);                                                                  /* release context */
        cout <<  "InitOpenSSL() Ends" << endl;
    }
    bool LoadCertificates(char* CertFile, char* KeyFile)
    {
        cout <<  "LoadCertificates() Start" << endl;
        bool rc = true;
         /* set the local certificate from CertFile */
        if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
            {
               cout << "Failed to get the certificate file" << endl;
               rc = false;
            }
            /* set the private key from KeyFile (may be the same as CertFile) */
        if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
        {
               cout << "Failed to get the private key file" << endl;
               rc = false;
            }
            /* verify private key */
        if ( !SSL_CTX_check_private_key(ctx) )
        {
              cout << "Private key does not match the public certificate" << endl;
              rc = false;
            }
        cout <<  "LoadCertificates() End" << endl;
            return rc;
    }



    int main()
    {
            cout << "Root path:" << endl;
            cin >> root;
            cout << "Key path:" << endl;
            cin >> key;
            cout << "Cert path:" << endl;
            cin >> cert;

            InitOpenSSL();
            return 0;
    }

On Running the server on AIX and then the client on Windows , Output is something like:

Root path:
/tmp/Certificates/RootCA_test.crt
Key path:
/tmp/Keys/server_test.key 
Cert path:
/tmp/Certificates/server_test.crt

InitOpenSSL() Starts
Server Certificate Used : /tmp/Certificates/server_test.crt
Server Key Used         : /tmp/Keys/server_test.key
LoadCertificates() Start
LoadCertificates() End
SSL_CTX_load_verify_locations passed for /tmp/Certificates/RootCA_test.crt
OpenListener() Start
Port : 4005 Address : 0
OpenListener() End
OpenListener() returns : 3
In While(1) Loop
::accept() called, get ready!
::accept() returns 4
Connection xx.xx.xx.xxxxx
Servlet() Start    
**1152921504606846944:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate:s3_srvr.c:3281:**
Servlet() End
In While(1) Loop
::accept() called, get ready!

Please can you help me with this error : 1152921504606846944:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate:s3_srvr.c:3281:

I tried various links and googled out too but no answer seems to work for this!

Is the way by which I am creating the certificates and key is OK?

Is there any piece of code needs to be added or removed in client/server code snippet given above? As there are many different approaches for doing the same!

An interesting conclusion is that when I run openssl commmand on the AIX server, it seems to make a connectivity:

my_server_07:  openssl s_server -cert /tmp/Certificates/server_test.crt -key /tmp/Keys/server_test.key -port 4005
Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT

-----BEGIN SSL SESSION PARAMETERS-----
MFUCAQECAgMDBALAMAQABDDNSf27vf0Jg6GLr+Z7DP/DasT0+dCDRprYoQ4kMMIk
bwtptVYQUgIpkLk/SRDhdhqhBgIEVkB9J6IEAgIBLKQGBAQAAAAB
-----END SSL SESSION PARAMETERS-----
Shared ciphers:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:IDEA-CBC-SHA:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA
CIPHER is ECDHE-RSA-AES256-GCM-SHA384
Secure Renegotiation IS supported
Hello! I am Client.Who are you ?
I am Server AIX :)

This works fine which gives me an impression that my client side code and certificates are OK and are working fine as I am able to receive the client message on server and the server message on client. Isn't it ?

But when I run the the server side code of mine on AIX and the client side openssl command as follows: C:\Windows\system32>openssl s_client -connect xx.xx.xxx.xxx:4005

The output is as follows on Client Side (server shows the same error: 1152921504606846944:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate:s3_srvr.c:3281:)

Loading 'screen' into random state - done
CONNECTED(000000D0)
depth=1 /C=IN/ST=XX/L=AAA/O=BBB/OU=CCC/CN=root_crt/[email protected]
verify error:num=19:self signed certificate in certificate chain
verify return:0
1520:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:.\ssl\s3_pkt.c:1146:SSL alert number 40
1520:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:.\ssl\s23_lib.c:178:**

The error : verify error:num=19:self signed certificate in certificate chain seems to point to some type of certificate signing process. I looked on the various forums and the opessl.org but nowhere seems to give a proper working resolution of this.

Please help me in whatever way you think that can lead to fix these issues. Thanks in advance....!!



Solution 1:[1]

I think part of the issue may be the lack of a call to SSL_CTX_load_verify_locations(), e.g. in your LoadCertificates function.

Part of requesting that the client send its certificate, via the CertificateRequest message, is including, in that request, a list of the CAs that the server trusts (i.e. that it will use for verifying any client-provided certificates). Servers may trust multiple different CAs, and a given client may have multiple different certificates to choose from. The CertificateRequest message thus contains a list of the CAs, and the client will then choose which of its client certificates matches up with those CAs.

Thus to configure OpenSSL with that list of CAs used for verifying client certs, you would use the SSL_CTX_load_verify_locations() function, and point it at a PEM file of concatenated certificates, and/or a directory of trusted certificates (hashed using the OpenSSL c_rehash utility). Without this, your server may be sending the CertificateRequest message, but with an empty list of CAs, and thus the client does not/cannot choose which of its client certs to send.

Hopefully this helps!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community