USING WOLFSSL WITH UTASKER

Introduction

wolfSSL is happy to announce that the wolfSSL embedded SSL/TLS and wolfCrypt cryptography libraries have been ported to the uTasker operating system.

uTasker is an operating system, stack, and collection of services designed for embedded devices.  It includes an OS, filesystem, device drivers, and TCP/IP stack among other features.  The uTasker package includes a device simulator, allowing developers to test and debug code faster than would be possible on physical hardware itself.  Complete details on the uTasker stack can be found on the project website: http://www.utasker.com/.

This document describes the wolfSSL uTasker port and how to use wolfSSL in a uTasker-based project to secure socket connections.  This document should act as a supplement to the wolfSSL Manual.

Table of Contents

  1. wolfSSL Source Files
  2. wolfSSL uTasker Configuration
  3. Standard Library Usage
  4. Time Functionality
  5. I/O Callbacks
  6. Debug Message Logging
  7. Random Number Generation
  8. Filesystem Integration
  9. Cryptography Verification
  10. Using wolfSSL with uTasker
  11. Example Projects
  12. Additional Tuning Resources
  13. Support

1. wolfSSL Source Files

The wolfSSL and wolfCrypt libraries are dual-licensed under both GPLv2 and a standard commercial license. This dual-license model makes it easy to evaluate, test and prototype with the GPLv2-licensed code then seamlessly migrate to the commercially-licensed sources if necessary.

The GPLv2-licensed version of wolfSSL may be downloaded from the wolfSSL website:
https://www.wolfssl.com/download/

After downloading the wolfSSL package, the wolfSSL and wolfCrypt source code should be added to a uTasker project file structure.  If using the “uTaskerV1.4” project as a base, a logical location for the wolfSSL source files would be:

uTasker_M522XX_V1.4-6_npw\Applications\uTaskerV1.4\wolfssl

The structure of the “wolfssl” directory should remain intact for ease of future upgrades.

Specific areas of interest in the wolfSSL package structure include:

wolfssl\wolfssl[TLS and crypto header files]
wolfssl\src     [TLS source files]
wolfssl\wolfcrypt\src[crypto source files]
wolfssl\wolfcrypt\test\test.c      [cryptography test code]

Source and header files from these locations should be added to the uTasker project.

wolfSSL has added a new preprocessor define to enable the uTasker port layer called WOLFSSL_UTASKER.  The port currently includes example client and server uTasker tasks which make use of the wolfSSL I/O abstraction layer to send and receive data over a secure SSL/TLS connection using uTasker RAW sockets.  The example tasks have been tested using the uTasker device simulator contained in the “uTasker_M522XX_V1.4-6” distribution.

What this means for projects using uTasker is that network connections can now communicate securely over SSL/TLS, using the progressive and lightweight wolfSSL SSL/TLS library.  Applications can also take advantage of the underlying wolfCrypt cryptography library to access crypto operations directly (block ciphers, stream ciphers, AEAD ciphers, hash functions, public key algorithms, and certificate verification routines).

2. wolfSSL uTasker Configuration

The wolfSSL library configuration for uTasker is located in the following file:

wolfssl\wolfssl\wolfcrypt\settings.h

The WOLFSSL_UTASKER define should be uncommented at the top of the file.  This enables the WOLFSSL_UTASKER port layer.

3. Standard Library Usage

wolfSSL contains a standard library abstraction layer which allows ports and/or applications to use different standard library calls than the defaults.  The wolfSSL uTasker port has been modified to use the available uTasker standard library replacement functions where possible, and falls back to the regular standard library functions where replacements are not available in uTasker.

The following code section from settings.h is responsible for mapping these functions:

/* use uTasker std library replacements where available */
#define STRING_USER
#define XMEMCPY(d,s,l)         uMemcpy((d),(s),(l))
#define XMEMSET(b,c,l)         uMemset((b),(c),(l))
#define XMEMCMP(s1,s2,n)       uMemcmp((s1),(s2),(n))
#define XMEMMOVE(d,s,l)        memmove((d),(s),(l))
#define XSTRLEN(s1)            uStrlen((s1))
#define XSTRNCPY(s1,s2,n)      strncpy((s1),(s2),(n))
#define XSTRSTR(s1,s2)         strstr((s1),(s2))
#define XSTRNSTR(s1,s2,n)      mystrnstr((s1),(s2),(n))
#define XSTRNCMP(s1,s2,n)      strncmp((s1),(s2),(n))
#define XSTRNCAT(s1,s2,n)      strncat((s1),(s2),(n))
#define XSTRNCASECMP(s1,s2,n)  _strnicmp((s1),(s2),(n))
#if defined(WOLFSSL_CERT_EXT) || defined(HAVE_ALPN)
#define XSTRTOK            strtok_r
#endif

4. Time Functionality

wolfSSL uses time functionality in two locations:

Session Cache Expiration

A wolfSSL server contains a session cache which allows clients to resume a previously-negotiated session.  A resumed session has the performance advantage of being able to skip several steps in the SSL/TLS handshake that were performed the first time the session was initiated.

To manage the expiration of sessions in the session cache, wolfSSL requires that the following function in “wolfssl\src\internal.c” return a count in seconds.  This needs to have second accuracy, but does not need to be correlated to an accurate time source.  The following is the default LowResTimer() implementation used in the wolfSSL uTasker port:

word32 LowResTimer(void)
{
return (word32)(uTaskerSystemTick / TICK_RESOLUTION);
}

Certificate Date Range Validation

wolfSSL needs the number of seconds since the Unix epoch in order to correctly validate “Not Before” and “Not After” validity ranges in certificates.  This is used during the peer authentication steps as part of the SSL/TLS handshake process.

The wolfSSL uTasker port requires that the user defines XTIME in settings.h to a function that will return the number of seconds since the Unix epoch.  USER_TIME also needs to be defined in settings.h.

The following note can be found in the WOLFSSL_UTASKER block in wolfSSL’s settings.h file:

/* User needs to define XTIME to function that provides
* seconds since Unix epoch. */
#ifndef XTIME
   #error User must define XTIME in wolfSSL settings.h
/* #define XTIME fnSecondsSinceEpoch */
#endif

5. Input / Output Callbacks

wolfSSL provides the functionality for applications to write and register custom Send and Receive callbacks.  Whenever wolfSSL wants or needs to send data to advance the internal SSL/TLS state machine, wolfSSL will call the SEND callback.  Likewise, whenever wolfSSL needs to receive data, it will call the RECEIVE callback.  Application layer API functions which end up calling these callbacks include functions such as wolfSSL_connect(), wolfSSL_accept(), wolfSSL_read(), and wolfSSL_write().

The wolfSSL uTasker Kickstart included the creation of custom Send/Receive callbacks that work with uTasker RAW sockets and example tasks.  These can be found in the wolfSSL uTasker example client task (wolfSSLClientTask.c):

/*
* wolfSSL send callback
*
* This function is called by wolfSSL whenever it needs to send data.
* Returns number of bytes sent, or negative error.
* WOLFSSL_CBIO_ERR_WANT_WRITE should be returned if more data is
* needed to be sent and wolfSSL should call this function again.
*/
int UTasker_Send(WOLFSSL* ssl, char* buf, int sz, void* ctx);

/*
* wolfSSL receive callback
*
* This function is called by wolfSSL whenever it needs to read data.
* Returns number of bytes received, or negative error.
* WOLFSSL_CBIO_ERR_WANT_READ should be returned if more data is
* needed to be read and wolfSSL should call this function again.
*/

int UTasker_Receive(WOLFSSL* ssl, char* buf, int sz, void* ctx);

The job of the UTasker_Receive callback is to place data into the provided buffer “buf”. wolfSSL asks for “sz” bytes of data, but if the callback has less data than requested, it can copy the number of bytes it has available into “buf” and return the number of bytes that have been written.

The job of the UTasker_Send callback is to send the data in the buffer “buf” to the peer. The number of bytes in “buf” is given to the callback through the “sz” parameter. If the callback is only able to send part of the data in “buf”, it should return the number of bytes that were sent.

These callbacks are registered with wolfSSL by the application using:

/* register wolfSSL send/recv callbacks */
void wolfSSL_SetIOSend(WOLFSSL_CTX* ctx, CallbackIOSend CBIOSend);
void wolfSSL_SetIORecv(WOLFSSL_CTX* ctx, CallbackIORecv CBIORecv);

Accompanying these callbacks are a “context” structure that is used for each.  A pointer to these custom structures are passed to the SEND and RECEIVE callbacks through the fourth parameter (“ctx”).  With the uTasker examples, this context is what the callbacks use to know how to access data buffers, socket descriptors, and ACK flags.  The I/O context structures can be found in the example client task (wolfSSLClientTask.c) or server task (wolfSSLServerTask.c):

/* wolfSSL send callback context struct */
typedef struct stUTASKER_SENDCTX {
TCP_MESSAGE*  message;/* TCP frame to send */
USOCKET*      socket;/* socket pointer */
unsigned int  dataLen;/* length of data in message frame*/
unsigned char ackd;     /* has ACK been received for data */
unsigned char flags;/* socket flags, ie: TCP_FLAG_PUSH*/
} UTASKER_SENDCTX;

/* wolfSSL recv callback context struct */
typedef struct stUTASKER_RECVCTX {
USOCKET*       socket;/* socket pointer */
unsigned int   used;/* bytes used in buffer */
unsigned int   offset;/* current offset in buffer */
unsigned int   bufLen;/* total size of buffer in bytes */
unsigned char* buffer;/* recv data buffer */
} UTASKER_RECVCTX;

The I/O contexts are registered by the application using:

void wolfSSL_SetIOReadCtx( WOLFSSL* ssl, void *ctx);
void wolfSSL_SetIOWriteCtx(WOLFSSL* ssl, void *ctx);

6. Debug Message Logging

wolfSSL has the ability to output internal debug messages at runtime.  To enable debugging, wolfSSL must be compiled with DEBUG_WOLFSSL defined, and the application must call wolfSSL_Debugging_ON() before any other wolfSSL calls.

The wolfSSL uTasker port by default will call fnDebugMsg() to output debug messages.  If a different output channel is desired by the user for debug messages, the application can write and register a custom Logging Callback with wolfSSL.  Instructions on doing this can be found in Section 8.1 of the wolfSSL Manual.

7. Random Number Generation

wolfSSL uses the uTasker fnRandom() function as an entropy source for seeding the wolfCrypt PRNG.  This is mapped/registered with wolfSSL in <wolfssl/wolfcrypt/settings.h>.

8. Filesystem Integration

The wolfSSL uTasker port does not include filesystem support at this time.  Applications should load certificates and keys through memory buffers (C arrays).  API functions to do this can be found in Section 17.2 of the wolfSSL Manual.

9. Cryptographic Verification

The wolfCrypt cryptography algorithms were verified for correct operation on the uTasker Simulator using the wolfCrypt tests found in the example client task.  When the example client or server tasks are run, the first thing that will happen is that the crypto tests will run.  Output should be similar to:

Starting wolfSSL Server Task
MD5      test passed!
MD4      test passed!
SHA      test passed!
SHA-256  test passed!
HMAC-MD5 test passed!
HMAC-SHA test passed!
HMAC-SHA256 test passed!
ARC4     test passed!
HC-128   test passed!
Rabbit   test passed!
DES      test passed!
DES3     test passed!
AES      test passed!
RANDOM   test passed!
RSA      test passed!
DH       test passed!
DSA      test passed!
PWDBASED test passed!
ECC      test passed!
STATUS: wolfCrypt Tests Passed!

10. Using wolfSSL with uTasker

Before using wolfSSL in a uTasker-based project, the following will need to be done.  These are mentioned in more detail above:

  1. Add wolfSSL and wolfCrypt source and header files to uTasker project.
  2. Make sure WOLFSSL_UTASKER is uncommented in ./wolfssl/wolfcrypt/settings.h, or defined either at the Visual Studio project preprocessor settings level or in user_settings.h if HAVE_USER_SETTINGS is defined.
  3. Define XTIME in settings.h (or user_settings.h if HAVE_USER_SETTINGS has been defined) to an appropriate function which returns seconds since the Unix epoch.  See note in WOLFSSL_UTASKER block of settings.h.
  4. Register Send/Recv callbacks and contexts with wolfSSL from the application code.  See Section 5 above.  Sample callbacks from the client and server example tasks can be used, or custom ones can be written.
  5. API documentation for wolfSSL can be found in the wolfSSL Manual.

11. Example Projects

wolfSSL has created two example tasks that demonstrate wolfSSL usage with uTasker and RAW sockets.  These task are available in the wolfSSL examples repository:

wolfSSL uTasker Examples

The uTasker Simulator IP address, Netmask, Gateway, and DNS server need to be set accordingly in UTasker’s application.c.

1. Example Client Task
Location: wolfSSLClientTask.c / wolfSSLClientTask.h

The example client task:
a. Runs cryptography tests to verify algorithms are working correctly in environment.
b. Creates and connects a TCP socket to https://www.example.com (93.184.216.34, port 443) by default.
c. Initializes and sets up wolfSSL library and SSL/TLS context, loading CA certificate used to verify server certificate chain.
d. After socket is connected, performs SSL/TLS handshake by calling wolfSSL_connect().
e. Sends a simple HTTP GET message to the server.
f. Receives and prints server response.
g. Shuts down socket, frees SSL/TLS resources.

The example client task contains Send and Receive callback functions which are registered with wolfSSL.  The CA certificate buffer is located in the wolfSSLClientTask.h header file.

2. Example Server Task
Location: wolfSSLServerTask.c / wolfSSLServerTask.h

The example server task:
a. Runs cryptography tests to verify algorithms are working correctly in environment.
b. Sets up the SSL/TLS context, loading server certificate and key file.
c. Creates a TCP socket and sets the socket to listen mode.
d. Once a client connection is received, creates SSL/TLS session.
e. Receives a message from the client (ie: ‘hello wolfssl!’).
f. Sends back a message to the server (ie: ‘I hear you fa shizzle!’)
g. Closes connection, frees resources, loops back around to c) above to wait for another client connection.

The example server task uses the same Send/Receive callbacks from wolfSSLClientTask.c.  Server certificate and key buffers are located in wolfSSLServerTask.c, and correspond to the example server certificate and key that ship with the wolfSSL package under the “./certs” directory.

This server task has been set up to receive connections from the wolfSSL proper example client (./examples/client/client).  The wolfSSL example client can be compiled and run from the wolfSSL package by following steps similar to the below.  These steps are for a Unix/Linux type environment.  For Windows users, wolfSSL includes a Visual Studio solution file that compiles the wolfSSL examples and library.

$ cd wolfssl-3.9.0-commercial
$ ./configure
$ make
$ ./examples/client/client -h 192.168.1.144 -p 443

The “-h” option specifies the host to connect to, while the “-p” option specifies the port.  Running the main wolfSSL example with the “-help” option will print out full usage.

3. Switching Between Client and Server Tasks

The wolfSSL example uTasker client and server tasks have not been written to run at the same time.  As such, the following steps will switch the test being run between Client and/or Server:

In UTasker’s TaskConfig.h, add a line similar to one of the following two lines and recompile the uTasker project, depending on if you want the client example or server example to run.  This should be familiar to users familiar with adding a new task to a UTasker project.

/*{ "x wolfSSL client", fnTLSClientTask, NO_QUE,(DELAY_LIMIT)(5 * SEC), (DELAY_LIMIT)(2 * SEC), UTASKER_STOP }, */
/* { "wolfSSL server", fnTLSServerTask, NO_QUE,(DELAY_LIMIT)(5 * SEC), (DELAY_LIMIT)(2 * SEC), UTASKER_STOP }, */

12. Additional Tuning Resources

The wolfSSL library has many different options for enabling and disabling features.  The default wolfSSL feature configuration has been used for this uTasker port, with the following non-default features enabled in settings.h:

ECC - Enabled so that applications have ECDHE_RSA cipher suites available. (HAVE_ECC, ECC_TIMING_RESISTANT, ALT_ECC_SIZE).

Fastmath - The fastmath math library has been enabled. This is faster than the normal big integer library.  RAM usage in total is roughly the same as the normal big integer library, but fastmath puts more on the stack and less on the heap.  Peak expected RAM usage can be found in the wolfSSL Resource Use document. (USE_FAST_MATH, TFM_TIMING_RESISTANT).

Please reference the wolfSSL Manual for a complete list of features available.

13. Support

Please contact support@wolfssl.com with any questions about using wolfSSL with uTasker.  For licensing and business inquiries, please contact facts@wolfssl.com.