Porting the PKCS #11 library - FreeRTOS

Porting the PKCS #11 library

FreeRTOS uses the open standard PKCS #11 “CryptoKi” API as the abstraction layer for cryptographic operations, including:

  • Signing and verifying.

  • Storage and enumeration of X.509 certificates.

  • Storage and management of cryptographic keys.

For more information, see PKCS #11 Cryptographic Token Interface Base Specification.

Storing private keys in general-purpose flash memory can be convenient in evaluation and rapid prototyping scenarios. In production scenarios, to reduce the threats of data theft and device duplication, we recommend that you use dedicated cryptographic hardware. Cryptographic hardware includes components with features that prevent cryptographic secret keys from being exported. To use dedicated cryptographic hardware with FreeRTOS, you need to port the PKCS #11 API to the hardware. For information about the FreeRTOS PKCS #11 library, see FreeRTOS PKCS #11 Library in the FreeRTOS User Guide.


To port the PKCS #11 library, you need the following:


To port the PKCS #11 library

  1. Port the PKCS #11 API functions.

    The PKCS #11 API is dependent on the implementation of cryptographic primitives, such as SHA256 hashing and Elliptic Curve Digital Signature Algorithm (ECDSA) signing.

    The FreeRTOS implementation of PKCS #11 uses the cryptographic primitives implemented in the mbedTLS library. FreeRTOS includes a port for mbedTLS. If your target hardware offloads crypto to a separate module, or if you want to use a software implementation of the cryptographic primitives other than mbedTLS, you need to modify the existing PKCS #11 port.

  2. Port the PKCS # 11 Platform Abstraction Layer (PAL) for device-specific certificate and key storage.

    If you decide to use the FreeRTOS implementation of PKCS #11, little customization is required to read and write cryptographic objects to non-volatile memory (NVM), such as onboard flash memory.

    Cryptographic objects should be stored in a section of NVM that is not initialized and is not erased on device reprogramming. Users of the PKCS #11 library should be able to provision devices with credentials, and then reprogram the device with a new application that accesses these credentials through the PKCS #11 interface.

    PKCS #11 PAL ports must provide a location to store:

    • The device client certificate.

    • The device client private key.

    • The device client public key.

    • A trusted root CA.

    • A code-verification public key (or a certificate that contains the code-verification public key) for secure bootloader and over-the-air (OTA) updates.

    • A Just-In-Time provisioning certificate.

    freertos/vendors/vendor/boards/board/ports/pkcs11/iot_pkcs11_pal.c contains empty definitions for the PAL functions. You must provide ports for, at minimum, the functions listed in this table:

    Function Description
    PKCS11_PAL_Initialize Initializes the PAL layer. Called by the PKCS #11 library at the start of it's initialization sequence.
    PKCS11_PAL_SaveObject Writes data to non-volatile storage.
    PKCS11_PAL_FindObject Uses a PKCS #11 CKA_LABEL to search for a corresponding PKCS #11 object in non-volatile storage, and returns that object’s handle, if it exists.
    PKCS11_PAL_GetObjectValue Retrieves the value of an object, given the handle.
    PKCS11_PAL_GetObjectValueCleanup Cleanup for the PKCS11_PAL_GetObjectValue call. Can be used to free memory allocated in a PKCS11_PAL_GetObjectValue call.
  3. Add support for a cryptographically random entropy source to your port:

    • If your ports use the mbedTLS library for underlying cryptographic and TLS support, and your device has a true random number generator (TRNG):

      1. Implement the mbedtls_hardware_poll() function to seed the deterministic random bit generator (DRBG) that mbedTLS uses to produce a cryptographically random bit stream. The mbedtls_hardware_poll() function is located in freertos/vendors/vendor/boards/board/ports/pkcs11/iot_pkcs11_pal.c.

    • If your ports use the mbedTLS library for underlying cryptographic and TLS support, but your device does not have a TRNG:

      1. Make a copy of freertos/libraries/3rdparty/mbedtls/include/mbedtls/config.h, and in that copy, uncomment MBEDTLS_ENTROPY_NV_SEED, and comment out MBEDTLS_ENTROPY_HARDWARE_ALT.

        Save the modified version of config.h to freertos/vendors/vendor/boards/board/aws_tests/config_files/config.h. Do not overwrite the original file.

      2. Implement the functions mbedtls_nv_seed_poll(), nv_seed_read_func(), and nv_seed_write_func().

        For information about implementing these functions, see the comments in the mbedtls/include/mbedtls/entropy_poll.h and mbedtls/include/mbedtls/config.h mbedTLS header files.


    A seed file with an NIST-approved entropy source must be supplied to the device at manufacturing time.


    If you are interested in the FreeRTOS Qualification Program, please read our requirements for RNG.

    For more information about NIST-approved DRBGs and entropy sources, see the following NIST publications:


If you are using an IDE to build test projects, you need to set up your library port in the IDE project.

Setting up the IDE test project

If you are using an IDE for porting and testing, you need to add some source files to the IDE test project before you can test your ported code.


In the following steps, make sure that you add the source files to your IDE project from their on-disk location. Do not create duplicate copies of source files.

To set up the PKCS #11 library in the IDE project

  1. Add the source file freertos/vendors/vendor/boards/board/ports/pkcs11/iot_pkcs11_pal.c to the aws_tests IDE project.

  2. Add all of the files in the freertos/libraries/abstractions/pkcs11 directory and its subdirectories to the aws_tests IDE project.

  3. Add all of the files in the freertos/libraries/freertos_plus/standard/pkcs11 directory and its subdirectories to the aws_tests IDE project. These files implement wrappers for commonly grouped PKCS #11 function sets.

  4. Add the source file freertos/libraries/freertos_plus/standard/crypto/src/aws_crypto.c to the aws_tests IDE project. This file implements the CRYPTO abstraction wrapper for mbedTLS.

  5. Add all of the source and header files from freertos/libraries/3rdparty/mbedtls and its subdirectories to the aws_tests IDE project.

  6. Add freertos/libraries/3rdparty/mbedtls/include and freertos/libraries/abstractions/pkcs11 to the compiler’s include path.

Configuring the CMakeLists.txt file

If you are using CMake to build your test project, you need to define a portable layer target for the library in your CMake list file.

To define a library's portable layer target in CMakeLists.txt, follow the instructions in FreeRTOS portable layers.

The CMakeLists.txt template list file under freertos/vendors/vendor/boards/board/CMakeLists.txt includes example portable layer target definitions. You can uncomment the definition for the library that you are porting, and modify it to fit your platform.

See below for an example portable layer target definition for the PKCS #11 library that uses the mbedTLS-based software implementation of PKCS #11 and supplies a port-specific PKCS #11 PAL file.

# PKCS11 afr_mcu_port(pkcs11_implementation DEPENDS AFR::pkcs11_mbedtls) target_sources( AFR::pkcs11_implementation::mcu_port INTERFACE "${afr_ports_dir}/pkcs11/iot_pkcs11_pal.c" )

Setting up your local testing environment

After you set up the library in the IDE project, you need to configure some other files for testing.

To configure the source and header files for the PKCS #11 tests

  1. If you have ported the Secure Sockets library, open freertos/libraries/freertos_plus/standard/utils/src/iot_system_init.c, and in the function SYSTEM_Init(), uncomment calls to SOCKETS_Init().

  2. Open freertos/vendors/vendor/boards/board/aws_tests/config_files/aws_test_runner_config.h, and set the testrunnerFULL_PKCS11_ENABLED macro to 1 to enable the PKCS #11 test.

Running the tests

To execute the PKCS #11 tests

  1. Build the test project, and then flash it to your device for execution.

  2. Check the test results in the UART console.


    Testing is complete when all tests pass.


To officially qualify a device for FreeRTOS, you need to validate the device's ported source code with AWS IoT Device Tester. Follow the instructions in Using AWS IoT Device Tester for FreeRTOS in the FreeRTOS User Guide to set up Device Tester for port validation. To test a specific library's port, the correct test group must be enabled in the device.json file in the Device Tester configs folder.

After you finish porting the FreeRTOS PKCS #11 library to your device, you can start porting the TLS library. See Porting the TLS library for instructions.