I have tried to define KEEP_PEER_CERT as well as running the configure script with --enable-sep but I am still unable to retrieve the peer certificate sad

Every once in a while the application gets 'lucky' and can retrieve the cert (usually after a clean build) but most of the time SSL_get_peer_certificate() still returns a NULL pointer.

Hello chrisc,

As always, your reply is very much appreciated and very helpful indeed. I just knew the peer cert was discarded to optimize memory usage, I just didn't know how to hang on to it.  smile

FYI, My application creates it's own peer certificates and currently stores the name of the user as the subject CN. After a successful SSL/TLS handshake this information is extracted from the peer certificate using

char *peer = X509_NAME_oneline(X509_get_subject_name(x509), nullptr, 0);

My next challenge is to extract the other information I need from the certificate.

I want to store the seed key for a one-time-password generator in the certificate (encrypted using the public key generated from the private key used with that peer certificate).
A have already found a way to store that data in the certificate (as part of the 'X509v3 Subject Alternative Name') like this:

$ openssl x509 -noout -text -in peer.pem

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 109881812884 (0x1995776794)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: O=openGalaxy, OU=openGalaxy websocket interface, CN=openGalaxyCA/emailAddress=<empty>
        Validity
            Not Before: Dec  2 18:36:53 2015 GMT
            Not After : Dec  1 18:36:53 2016 GMT
        Subject: O=openGalaxy, OU=openGalaxy websocket interface, CN=NAME SURNAME/emailAddress=EMAIL-ADDRESS
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                BA:33:4D:3C:60:14:B7:5F:9A:AA:A0:E6:8F:39:7F:10:23:9D:9C:C2
            X509v3 Authority Key Identifier: 
                keyid:CF:F9:12:EF:25:C4:D6:D7:68:E6:C1:4B:86:0F:C3:19:D8:9C:DC:66

            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Subject Alternative Name: 
                DirName:/CN=ENCRYPTED OTP SEED
            X509v3 Issuer Alternative Name: 
                email:<empty>
    Signature Algorithm: sha256WithRSAEncryption
         ...

My goal is to get and decrypt the otp seed from the peer certificate and then use it to generate a one-time-password the user of the certificate would have to match (possibly using http basic authentication once the SSL/TLS connection has been established). I have however not looked into retrieving or decrypting the otp seed from the peer certificate using wolfSSL library functions yet...

I have a couple of questions about WolfSSL and verifying peer certificates:

My applications calls

SSL_CTX_set_verify()

with

SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT

And it also wants to retrieve the X509 structure of each client's peer certificate in order to use information stored in it.

When I use OpenSSL my application does this by calling

SSL_get_peer_certificate()

right after the connection has been established.

But when I use this function with WolfSSL I run into difficulties.
With WolfSSL the SSL_get_peer_certificate() function allways returns a NULL pointer, unless it is called from within

int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx);

The problem I have with this is that from within verify_callback() I have no meaningfull place to store the information retrieved from any X509 structure.
Thus, I need to call SSL_get_peer_certificate() after the connection has been established and not from within verify_callback().

Is it possible to retrieve the peer certificate X509 structure after the connection has been established?
(Or is this information discarded by WolfSSL after verify_callback() completes, to save memory?)

My second question also relates to the process of verifiying a clients peer certificate.
Do I need to do extra verification when verify_callback() is called with preverify_ok=1 ?

With openSSL my application checks that SSL_get_verify_result() returns a value of X509_V_OK, but I have noticed that WolfSSL always returns X509_V_OK when you call this function (hardcoded into the C header files).

Just to be sure, my application uses a certificate manager to verify the peer certificate (again) like this:

     int n = 1; // Assume the peer certificate is invalid or could not be authenticated
     X509 * x509 = wolfSSL_get_peer_certificate(ssl);
     if(x509){
       WOLFSSL_CERT_MANAGER* cm = wolfSSL_CertManagerNew();
       if(cm != nullptr){
         if(wolfSSL_CertManagerLoadCA(cm, "ca.pem", nullptr) == SSL_SUCCESS){ // load the CA cert into the CM
           if(wolfSSL_CertManagerSetCRL_Cb(cm, MissingCRL) == SSL_SUCCESS){ // cb to call when the CRL cert is missing
             if(wolfSSL_CertManagerLoadCRL(cm, "/path/to/crl", SSL_FILETYPE_PEM, 0) == SSL_SUCCESS){ // load the CRL path into the CM
               if(wolfSSL_CertManagerEnableCRL(cm, WOLFSSL_CRL_CHECKALL) == SSL_SUCCESS){ // enable CRL checking for this CM
                 const unsigned char *der;
                 int der_length, verify_ok;
                 der = wolfSSL_X509_get_der(x509, &der_length); // get peer X509 certificate in DER format
                 verify_ok = wolfSSL_CertManagerVerifyBuffer(cm, der, der_length, SSL_FILETYPE_ASN1); // verify it using the CM
                 if(verify_ok == SSL_SUCCESS){
                   n = 0; // Allow the connection to continue.
                 }
                 else {
                   n = 1; // Block the connection.
                 }
               }
             }
           }
         }
         wolfSSL_CertManagerFree(cm);
       }
     }

Is this nessesary or can I trust the hardcoded X509_V_OK that SSL_get_verify_result() returns.

4

(4 replies, posted in wolfSSL)

No I don't mind, in fact I would like that very much.

Btw. this is my first experience using an SSL library and I really like wolfSSL. While OpenSSL is confusing the daylight out of me, wolfSSL is a little easier to understand and use.

5

(4 replies, posted in wolfSSL)

I have managed to solve the issue  smile
The working code can be sampled here: http://sourceforge.net/projects/galaxy4linux/

6

(4 replies, posted in wolfSSL)

I am writing an application that uses libwebsockets with CyaSSL/wolfSSL as SSL provider.
My application uses a selfsigned CA certificate and server certificate, both created with OpenSSL.
So far, so good. I even get a green lock in the navigation bar when I import the CA certificate into chrome and connect to the websocket.

But now I would like users connecting to the websocket to have to present a client certificate to be able to connect. Initially I thought that the code I was using works. Even blocking revoked client certificates.

Recently, I have discovered that any client certificate signed by an 'old' version of the CA certificate authenticates as valid when it should fail authentication, so the code only seems to work!
I've been staring myself blind on any documentation I can find on this subject, but so far I still haven't figured it out.

Can you SSL guru's please help me, or point me in the right direction?

The initialisation of the SSL library is done by libwebsockets, any 'extra' autentication like loading a certificate revocation list is done through a callback function. This is the relevant code for the libwebsockets initialization and the callback function for the html-protocol:

#include <wolfssl/openssl/ssl.h>

static struct libwebsocket_context * websocket_context;

static char *fn_ca_cert;      // complete path to CA certificate
static char *fn_srv_cert;     // complete path to Server certificate
static char *fn_srv_key;      // complete path to Server private key
static char *fn_crl_cert;     // complete path to CRL certificate
static char *path_crl_cert;   // complete path to CRL directory (ie. fn_crl_cert without the filename)

bool init_libwebsockets( void )
{
  struct lws_context_creation_info context_info;

  memset( &context_info, 0, sizeof context_info );
  ...
  ...
  context_info.ssl_cert_filepath = fn_srv_cert;
  context_info.ssl_private_key_filepath = fn_srv_key;
  context_info.options = LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
  ...
  websocket_context = libwebsocket_create_context( &context_info );
  if( websocket_context == NULL ){
    SYSLOG( LOG_ERR, "websocket: init failed\n" );
    return false;
  }
  
  return true;
}


static int websocket_callback_http( struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len ){
{
  int n;
  switch( reason ){

    ...
    ...

    // This callback loads the CRL
    // user = SSL_CTX*
    //
    case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS:
#if ! HAVE_NO_SSL
      {
        char errbuf[160];
        SSL_CTX *ctx = (SSL_CTX*) user;

        // Load the CA cert
        n = SSL_CTX_load_verify_locations( ctx, fn_ca_cert, NULL );
        if( n != 1 ){
          n = ERR_get_error();
          SYSLOG( LOG_ERR, "Encryption: problem loading CA certificate: %s", ERR_error_string( n, errbuf ) );
          return 1;
        }

        // Make sure our CRL exists
        FILE *fp = fopen( fn_crl_cert, "rt" );
        if( fp ){
          fclose( fp );

          // Load the CRL and activate CRL checking
          n = wolfSSL_CTX_LoadCRL( ctx, path_crl_cert, SSL_FILETYPE_PEM, 0 );
          if( n != 1 ){
            SYSLOG( LOG_ERR, "Encryption: problem loading CRL directory: %s", wolfSSL_ERR_error_string( n, errbuf ) );
            return 1;
          }

          n = wolfSSL_CTX_EnableCRL( ctx, 0 );
          if( n != 1 ){
            SYSLOG( LOG_ERR, "Encryption: problem enabling CRL: %s", wolfSSL_ERR_error_string( n, errbuf ) );
            return 1;
          }
        }
        else {
          SYSLOG( LOG_ERR, "Encryption: problem loading CRL: %s", fn_crl_cert );
          return 1;
        }
      }
#endif
      break;


    // This callback decides whether or not to allow a client to connect (for all
    // protocols) and is called as:
    // int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx);
    //
    // in   = SSL* 
    // user = X509_STORE_CTX*
    // len  = preverify_ok
    //
    // Libwebsocket return conventions apply as usual, ie. return nonzero to block
    // the connection.
    //
    case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION:
      {
        n = 0;
#if ! HAVE_NO_SSL
        int err = 0;
        char errbuf[256];

        if( !len ){
          // The client certificate failed to be verified,
          // log the error message and refuse the connection by returning nonzero.
          //
          err = X509_STORE_CTX_get_error( (X509_STORE_CTX*)user );
          int depth = X509_STORE_CTX_get_error_depth( (X509_STORE_CTX*)user );
          wolfSSL_ERR_error_string_n( err, errbuf, sizeof( errbuf ) );
          SYSLOG( LOG_ERR, "Encryption: Error: %s (%d), depth: %d", errbuf, err, depth );
          n = 1;
        }
#endif
      }
      return n;

    ...
    ...

    default:
      break;
  }
  return 0;
}