Topic: STM32F4 HAL, FreeRTOS, LWIP and WolfSSL

I'm trying to build a simple client application using the above processor and packages.  I have the ethernet driver functioning with the LWIP stack, and can make connections and exchange data with straight TCP connections.  I have WolfSSL building, and almost running, with what I think is two last issues which I need help figuring out.  When I try to connect via a TLS 1.2 connection to my host, I have the following problems.

1. Unable to verify host cert.

I believe this is because I don't have the proper PEM file (actually hardcoded since the demo doesn't have a filesystem) loaded.  I was able to work around this by using wolfSSL_CTX_set_verify to set a callback that allows overriding this failure.  I found this in the MQTT demo app.  I don't think this is an issue, since it worked for the MQTT demo and allowed data exchange.

2. Failure in the Encrypt() function

The connection proceeds through wolfSSL_write into SendData, wolfSSL_negotiate, wolfSSL_connect, SendFinished, BuildMessage and into Encrypt.  Once there, one of the first things Encrypt does is check if the encrypt ciphers are set up.

    switch (ssl->encrypt.state) {
        case CIPHER_STATE_BEGIN:
        {
            if (ssl->encrypt.setup == 0) {
                WOLFSSL_MSG("Encrypt ciphers not setup");
                return ENCRYPT_ERROR;
            }

For some reason, they are not set up on my system, and I cannot figure out why, or where they were supposed to be set up.

The debug output, from the point where I override the cert failure up to this point is below.

Verified Peer's cert
wolfSSL Entering ERR_error_string
TLS Verify Callback: PreVerify 0, Error -188 (ASN no signer error to confirm failure)
  Subject's domain name is wrs2test.hmps-apps.net
  Allowing cert anyways
Verify callback overriding error!
wolfSSL Leaving DoCertificate, return 0
wolfSSL Leaving DoHandShakeMsgType(), return 0
wolfSSL Leaving DoHandShakeMsg(), return 0
received record layer msg
wolfSSL Entering DoHandShakeMsg()
wolfSSL Entering DoHandShakeMsgType
No KeyExchange required
processing server hello done
wolfSSL Leaving DoHandShakeMsgType(), return 0
wolfSSL Leaving DoHandShakeMsg(), return 0
connect state: HELLO_AGAIN
connect state: HELLO_AGAIN_REPLY
connect state: FIRST_REPLY_DONE
connect state: FIRST_REPLY_FIRST
wolfSSL Entering SendClientKeyExchange
wolfSSL Entering RsaEnc
wolfSSL Leaving RsaEnc, return 0
growing output buffer

Shrinking output buffer

wolfSSL Leaving SendClientKeyExchange, return 0
sent: client key exchange
connect state: FIRST_REPLY_SECOND
connect state: FIRST_REPLY_THIRD
growing output buffer

Shrinking output buffer

sent: change cipher spec
connect state: FIRST_REPLY_FOURTH
growing output buffer

wolfSSL Entering BuildMessage
Encrypt ciphers not setup

I'm using the user_settings.h file attached.  I'm sure I must be missing something here, or not setting something up properly, but have been beating my head against the wall for two days trying to figure it out.

Minus my cert and not public server info, the following is the code I'm running.  Hopefully someone can see where I've messed up from this.

int ssl_init_done = 0;

/* Define a structure to hold the WolfSSL context. */
WOLFSSL_CTX* xWolfSSL_Context;
WOLFSSL* xWolfSSL_Object = NULL;

static int tls_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)
{
    char buffer[80];

    printf("TLS Verify Callback: PreVerify %d, Error %d (%s)\r\n", preverify,
        store->error, wolfSSL_ERR_error_string(store->error, buffer));
    printf("  Subject's domain name is %s\r\n", store->domain);

    /* Allowing to continue */
    /* Should check certificate and return 0 if not okay */
    printf("  Allowing cert anyways\r\n");

    return 1;
}

void test_secure(void)
{
  struct hostent *server;
  int socket_fd;
  struct sockaddr_in ra;

  int recv_data;
  char data_buffer[1024];

  int Step = 0;

  while (Step >= 0)
  {
    switch (Step)
    {
      case 0 :
        printf("Initializing WolfSSL if needed\r\n");
        if (ssl_init_done == 0)
        {
          wolfSSL_Init();
          ssl_init_done = 1;
        }
        break;
      case 1 :
        printf("Creating WolfSSL context if needed\r\n");
        /* Attempt to create a context that uses the TLS V1.2 client protocol. */
        if (ssl_init_done == 1)
        {
          xWolfSSL_Context = wolfSSL_CTX_new( wolfTLSv1_2_client_method() );

          if( xWolfSSL_Context == NULL )
          {
            printf("Failed to create WolfSSL context\r\n");
            Step = -1;
          }
          else
          {
            ssl_init_done = 2;

            wolfSSL_CTX_set_verify(xWolfSSL_Context, SSL_VERIFY_PEER, tls_verify_cb);

          }
        }
        break;
      case 2 :
        printf("Loading WolfSSL CA Certificate\r\n");
        if (ssl_init_done == 2)
        {
          int rc = SSL_FAILURE;

          /* Load CA certificate file */
          rc = wolfSSL_CTX_load_verify_buffer(xWolfSSL_Context, cert, strlen(cert), SSL_FILETYPE_PEM);

          if (rc != SSL_SUCCESS)
          {
            printf("Failed to load CA Certificate\r\n");
            Step = -1;
          }
          else
            ssl_init_done = 3;
        }
        break;
      case 3 :
        printf("Create the socket\r\n");
        socket_fd = socket(PF_INET, SOCK_STREAM, 0);
        if ( socket_fd < 0 )
        {
          printf("Socket call failed\r\n");
          Step = -1;
        }
        break;
      case 4 :
        {
          /* gethostbyname: get the server's DNS entry */
          printf("Gethostbyname: get the %s server's DNS entry\r\n", HMPS_TEST_SECURE_HOST);
          server = gethostbyname(HMPS_TEST_SECURE_HOST);
          if (server == NULL)
          {
            printf("ERROR, no such host as %s\r\n", HMPS_TEST_SECURE_HOST);
            Step = -1;
          }
          else
            printf("Host %s resolved to IP address %s\r\n",server->h_name,inet_ntoa(*server->h_addr_list[0]));

        }
        break;
      case 5 :
        printf("Connecting to server.\r\n");

        memset(&ra, 0, sizeof(struct sockaddr_in));
        ra.sin_family = AF_INET;
        memcpy((char *)&ra.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
        ra.sin_port = htons(HMPS_TEST_SECURE_PORT);
        if(connect(socket_fd,(struct sockaddr const*)&ra,sizeof(struct sockaddr_in)) < 0)
        {
          printf("Connect failed \n");
          Step = -1;
        }
        else
          printf("Connected to IP address %s\r\n",inet_ntoa(ra.sin_addr.s_addr));
        break;
      case 6 :
        printf("Creating WolfSSL Object\r\n");
        // The connect was successful.  Create a WolfSSL object to associate with
        // this connection.  The context created during initialisation is passed as
        // the function parameter.
        if( xWolfSSL_Object == NULL )
          xWolfSSL_Object = wolfSSL_new( xWolfSSL_Context );

        if( xWolfSSL_Object == NULL )
        {
          printf("Failed to create WolfSSL Object\n");
          Step = -1;
        }
        break;
      case 7:
        printf("Associating WolfSSL Object to socket\r\n");
        // Associate the created WolfSSL object with the connected socket.
        wolfSSL_set_fd( xWolfSSL_Object, socket_fd );
        break;
      case 8 :
        {
          char buf[1024];
          int n;

          sprintf(buf,HMPS_TEST_SECURE_MSG);

          /* send the message line to the server */
          printf("Send the message %s to the server\r\n", HMPS_TEST_SECURE_MSG);

wolfSSL_Debugging_ON();
          n = wolfSSL_write( xWolfSSL_Object, buf, strlen(buf));
wolfSSL_Debugging_OFF();
          if (n != strlen(buf))
          {
            printf("ERROR writing to socket\r\n");
            Step = -1;
          }
        }
        break;
      case 9 :
        printf("Receive data\r\n");
        recv_data = wolfSSL_read( xWolfSSL_Object, data_buffer,sizeof(data_buffer));
        if(recv_data < 0)
        {
          printf("Receive failed\r\n");
          Step = -1;
        }
        else
        {
          data_buffer[recv_data] = 0x00; // Force terminating NULL
          printf("Received data: %s\r\n", data_buffer);
        }
        break;
      case 10 :
        Step = -1;
        break;
    }
    if (Step >= 0)
      Step ++;
  }

  if( xWolfSSL_Object != NULL )
  {
    printf("Clean up WolfSSL\r\n");

    // WolfSSL objects should be deleted when they are no longer required.
    wolfSSL_free( xWolfSSL_Object );
    xWolfSSL_Object = NULL;

    // The WolfSSL context should be deleted if it is no longer required.  However,
    // because most deeply embedded applications will keep the context for the lifetime
    // of the application, and only ever be restarted when the system is rebooted, it
    // might be that the context is never explicitly freed.
    // wolfSSL_CTX_free( xWolfSSL_Context );

    // The library itself should be shut down cleanly if it too is no longer
    // required.  Again, because most deeply embedded applications will require the
    // library for the lifetime of the application, and only ever be restarted when
    // the system is rebooted, it might be that the library is never explicitly closed.
    // wolfSSL_Cleanup();
  }
  close(socket_fd);

  printf("Test complete\r\n");
}

Thanks in advance for any insight,
  Jeff.

Share

Re: STM32F4 HAL, FreeRTOS, LWIP and WolfSSL

Made a small amount of progress.  HAVE_AES was not defined, preventing loading the cipher.  This was not defined because it was specifically undefined because NO_AES_DECRYPT was defined.  This was defined because HAVE_AESGCM was defined, and this was done in user_settings.h.  I reused the user_settings.h from I believe the MQTT demo, so I'm not sure why that was done.  The offending section is below with the offending line commented out.

/* AES */
#undef NO_AES
#if 1
    #define HAVE_AESGCM
    #ifdef HAVE_AESGCM
        // #define NO_AES_DECRYPT
        #define HAVE_AESGCM_DECRYPT
    #endif

    /* GCM Method: GCM_SMALL, GCM_WORD32 or GCM_TABLE */
    #undef  GCM_SMALL
    #define GCM_SMALL
#else
    #define NO_AES
#endif

This gets me past this error, but I still do not get communications.  The code enters CBIOSend via SendBuffered() at the end of SendFinished() and never returns.  So now I'm trying to figure out why this is happening.  This may require WireShark.

Share

Re: STM32F4 HAL, FreeRTOS, LWIP and WolfSSL

Hi Jeff,

1. Unable to verify host cert.

To verify the host you need at a minimum a copy of the Host's ROOT CA. You can easily load this in PEM or DER format without a file system. Just use:

wolfSSL_CTX_load_verify_buffer(ssl_object, cert_buffer, sizeof(cert_buffer), SSL_FILETYPE_PEM);

Then format your cert like this:

const unsigned char cert_buffer[] = { "\n\
-----BEGIN CERTIFICATE-----\n\
MIICVzCCAd2gAwIBAgIBKDAKBggqhkjOPQQDAzBBMRMwEQYKCZImiZPyLGQBGRYD\n\
bWlsMRgwFgYKCZImiZPyLGQBGRYIVHlwZTFQS0kxEDAOBgNVBAsTB1BLSUNBMDEw\n\
HhcNMTcwNDE0MTgxMjM3WhcNMjIwNDE0MTgxMjM3WjA3MRUwEwYDVQQFEwxBMDAw\n\
MTAwMDAwMTExHjAcBgNVBAMTFTIuMTYuODQwLjEuMTAxLjIuMS4xNzB2MBAGByqG\n\
SM49AgEGBSuBBAAiA2IABDLKAVvq5fRxDwtVNWczivw7dPECc0I6d6V/+poMFGTC\n\
OhJ+1jubn6VwWGqE5oGm22vJ2CjXC8yTwt+HJ/NVN/oylXGRRAjH0kghGzBP7Zr8\n\
S85cmtn3lP7ygUx7WGNK5qOBsjCBrzATBgNVHSMEDDAKgAhx+thUesQIQzARBgNV\n\
HQ4ECgQI8oFMe1hjSuYwDgYDVR0PAQH/BAQDAgeAMBYGA1UdIAQPMA0wCwYJYIZI\n\
AWUCAQsGMCsGA1UdEQQkMCKgIAYIKwYBBQUHCASgFDASBghghkgBZQIBEQQGoAAQ\n\
AAARMDAGA1UdHwQpMCcwJaAjoCGGH2h0dHBzOi8vUHJpbWFyeVBERS9wa2kvMTAw\n\
MTI3MzkwCgYIKoZIzj0EAwMDaAAwZQIxANMDtwbS4vD+zrge2vuTLwt0cy0J6j9P\n\
LldPMuKrAxRMVQ0fTgDMlxjGyV7onb0NxAIwXW2qCXjEvZBzgOx+IQnCHOjxDLp2\n\
/bDPlrF8llEDzjYvTLmN0cUZ5bwcOQygi3Xo\n\
-----END CERTIFICATE-----\n\n"
};



2. Failure in the Encrypt() function

Yes my first thought here was that you have no encryption configured IE no aes, no 3des, no camellia... etc. The MQTT user_settings example is quite sophisticated but intended to try and present all the available options for customizing our library. You have resolved this already based on the above.

Finally I see you are calling wolfSSL_write() which will call wolfSSL_connect() if the handshake has not completed already, however the downside to doing this is that you will not be able to debug if something goes wrong in the handshake.

I would recommend trying this BEFORE calling wolfSSL_write():

return_value = wolfSSL_connect(xWolfSSL_Object);

if (return_value != SSL_SUCCESS) {
    printf("Handshake failed with error code: %d\n", return_value);
}

Is there an error code returned? If so what is the value? If it is -300 or less it is a TLS error and the definition can be found in <wolf-root>/wolfssl/error-ssl.h otherwise if it is in the -200 to 0 range the definition is crypto related and can be found in <wolf-root>/wolfssl/wolfcrypt/error-crypt.h


Regards,

Kaleb