Use wolfSSL for TLS connections

The Azure Sphere SDK includes a subset of the wolfSSL library for transport layer security (TLS), which high-level applications can use to create secure client-side TLS connections.

The wolfSSL API reference provides thorough documentation of the wolfSSL API, along with many examples. Azure Sphere supports a subset of the API that ensures binary compatibility.

Requirements for applications that use the wolfSSL library

Applications that use the wolfSSL library must include the necessary header files and build configuration.

The wolfSSL client TLS API doesn't require capabilities in the application manifest. However, if the application connects to an internet endpoint, the application manifest must include information about the connection. See Connect to web services for more details on enabling connectivity.

Header files

Applications that use the wolfSSL API must include the ssl.h header file, and may require one or more additional header files, depending on the wolfSSL features in use:

#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/ssl.h>

See the wolfSSL documentation to determine which header files your application requires.

Build configuration

To build an application with wolfSSL client TLS API support, edit the CMakeLists.txt file to specify the target API set and link the wolfSSL library.

  1. Set the TARGET_API_SET to 6 or greater.

    azsphere_configure_api(TARGET_API_SET "6")
    
  2. Add wolfssl to the list of target_link_libraries to link the wolfSSL library into the project:

    target_link_libraries(${PROJECT_NAME} applibs pthread gcc_s c wolfssl)
    

Supported features

The Azure Sphere SDK supports client-side wolfSSL TLS functionality. Notable unsupported scenarios include:

  • Only wolfSSL client-side TLS connections are supported. Server-side TLS connections are not supported.

  • An application can either use the built-in wolfSSL TLS support or use and link in another wolfSSL library implementation. However, mixed use of the built-in support with another wolfSSL library is not supported.

Use wolfSSL in Azure Sphere

High-level Azure Sphere applications can use wolfSSL to create and communicate over a client-side TLS connection. Applications typically must use a combination of the techniques to create and communicate over these connections.

Initialize wolfSSL

To create a TLS connection with wolfSSL, the application first must initialize the library and the SSL context (CTX), as in the following code snippet:

    // Configure the wolfSSL library
    if (wolfSSL_Init() != WOLFSSL_SUCCESS) {
        Log_Debug("Error initializing wolfSSL library.\n");
        goto cleanupLabel;
    }

    // Configure wolfSSL CTX functionality
    if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())) == NULL) {
        Log_Debug("Error initializing wolfSSL CTX library.\n");
        goto cleanupLabel;
    }

Load the client certificate

After wolfSSL is initialized, it can load a client certificate for use with the TLS connection. You can include the certificate in the application image package, as described in Add CA certificates to the image package.

The following example shows how an app can use Storage_GetAbsolutePathInImagePackage to get the path to a client certificate that is part of the application image package, and then call wolfSSL_CTX_load_verify_locations to load the certificate into wolfSSL. Note that the app must include the storage.h header file to use Storage_GetAbsolutePathInImagePackage.

   #include <applibs/storage.h>
   ...

    // Get the full path to the certificate file used to authenticate the HTTPS server identity.
    // The .pem file is the certificate that is used to verify the
    // server identity.
    certificatePath = Storage_GetAbsolutePathInImagePackage("certs/YourDesiredCert.pem");
    if (certificatePath == NULL) {
        Log_Debug("The certificate path could not be resolved: errno=%d (%s)\n", errno,
                  strerror(errno));
        goto cleanupLabel;
    }

    // Load the client certificate into wolfSSL
    if (wolfSSL_CTX_load_verify_locations(ctx, certificatePath, NULL) != WOLFSSL_SUCCESS) {
        Log_Debug("Error loading certificate.\n");
        goto cleanupLabel;
    }

Create the connection

After loading the client certificate, the app can establish the TLS connection. This step involves creating an SSL object, associating it with a socket descriptor, and then creating the connection, as in this example:

 // Create the SSL object
    if ((ssl = wolfSSL_new(ctx)) == NULL) {
        Log_Debug("Error creating final SSL object.\n");
        goto cleanupLabel;
    }

    // Attach the socket file descriptor to wolfSSL
    if (wolfSSL_set_fd(ssl, sockfd) != WOLFSSL_SUCCESS) {
        Log_Debug("Error attaching socket fd to wolfSSL.\n");
        goto cleanupLabel;
    }

    // Do the SSL connection between both sides
    if (wolfSSL_connect(ssl) != WOLFSSL_SUCCESS) {
        Log_Debug("Error establishing TLS connection to host.\n");
        goto cleanupLabel;
    }

Read and write data from the connection

To write and read data from the connection, the application can use wolfSSL_write and wolfSSL_read, respectively, as the below shows. In this example the write to the server contains a standard HTTP/1.1 request to retrieve the content of the page.

    sprintf(buffer, "GET / HTTP/1.1\r\nHost: example.com\r\nAccept: */*\r\n\r\n");
    ret = wolfSSL_write(ssl, buffer, (int)strlen(buffer));
    if (ret != strlen(buffer)) {
        Log_Debug("Error writing GET command to server.\n");
        goto cleanupLabel;
    }

    // Read the data back
    ret = wolfSSL_read(ssl, buffer, BUFFER_SIZE);
    if (ret == -1) {
        Log_Debug("Error reading from host.\n");
        goto cleanupLabel;
    }

    Log_Debug("Received %d bytes from host.\n", ret);
    Log_Debug("%s\n", buffer);

Cleanup

When the application is done using the connection, it should free the related resources.

    if (certificatePath) {
        free(certificatePath);
    }
    if (ssl) {
        wolfSSL_free(ssl);
    }
    if (ctx) {
        wolfSSL_CTX_free(ctx);
        wolfSSL_Cleanup();
    }