Key

Securing Keys and Certificates with i.MX 95 Verdin EVK using PKCS#11 with OP-TEE

Toradex recently launched the i.MX 95 Verdin Evaluation Kit, designed to accelerate next-generation Edge AI, automotive, industrial and medical applications all of which are industries that require high levels of security.

An essential aspect of achieving a high level of security is the management and storage of cryptographic keys. This is crucial for authenticating to cloud services, establishing secure network connections, and enabling secure over-the-air updates. A common practice is to use a Trusted Platform Module (TPM) to store keys, however this requires additional hardware. The i.MX 95 provides an integrated solution by incorporating a Trusted Execution Environment (TEE) with Arm TrustZone, creating a secure, isolated area within the processor. This secure environment operates alongside the main operating system to handle sensitive tasks such as cryptographic key management, secure boot and data encryption.

In this blog, we will explore how to build and customise a Yocto reference image for the i.MX 95 Verdin EVK, utilising the TEE and Arm TrustZone with OP-TEE and PKCS#11. We will also demonstrate how to generate a public-private key pair as PKCS#11 objects, create a self-signed certificate with OpenSSL, storing it as a PKCS#11 object and use it to connect to a web server.

Leveraging OP-TEE and PKCS#11

OP-TEE is an open-source implementation of a TEE designed to comply with the GlobalPlatform TEE specifications. Leveraging Arm TrustZone, OP-TEE isolates sensitive operations, such as cryptographic functions, secure data management and authentication from the main operating system, providing a trusted environment for secure execution.

OP-TEE provides two options for secure persistent storage. The first option uses the Normal World (REE), where data is encrypted and stored in the Linux file system. The second option utilises Replay Protected Memory Blocks (RPMB) on the eMMC, which is the recommended option for enhanced security. These storage options can be configured in OP-TEE by setting either CFG_REE_FS or CFG_RPMB_FS, both of which use a key derived from the Hardware Unique Key (HUK). The HUK is a device-specific, hardware-embedded key that forms the foundation of OP-TEE’s security. It is typically configured via vendor tools, with its security implementation managed by the vendor. In this case, NXP’s i.MX 9 series uses the EdgeLock® secure enclave to securely manage the HUK.

PKCS#11 is a standard API for accessing cryptographic tokens like Hardware Secure Module (HSM), smart cards and secure key storage. It enables platform-independent cryptographic operations, ensuring interoperability and simplifying secure key management. The PKCS#11 Trusted Application (TA) within OP-TEE acts as a software-based HSM, which provides the standard-compliant API for interacting with cryptographic tokens provisioned by OP-TEE.

Build i.MX 95 Verdin EVK Image

As of writing this, Toradex do not provide a reference image for the i.MX 95 Verdin Evaluation Kit for Yocto. Therefore, the example below uses NXP’s reference image instead.

Firstly, set up the manifest and populate the Yocto project layer sources with the following commands:

mkdir imx95-19x19-verdin-yocto
cd imx95-19x19-verdin-yocto
repo init -u https://github.com/nxp-imx/imx-manifest -b imx-linux-scarthgap -m imx-6.6.52-2.2.0.xml
repo sync

Configure the build for i.MX 95 Verdin EVK:

MACHINE=imx95-19x19-verdin DISTRO=fsl-imx-xwayland source ./imx-setup-release.sh -b bld-xwayland

In local.conf, or in the image recipe, add the following line:

IMAGE_INSTALL:append = " libp11 opensc curl"

This will add the pkcs11-tool, pkcs11 engine and curl which we will use later for testing

Note: We will also use the OpenSSL binary and the OP-TEE test framework, which includes the xtest utility, both of which are pre-configured for installation by default.

Build the target image

bitbake core-image-minimal

Flash the image onto a SD card

sudo bmaptool copy ${BUILDDIR}/tmp/deploy/images/imx95-19x19-verdin/core-image-minimal-imx95-19x19-verdin.rootfs.wic.zst /dev/sd<x>

Ensure the board is powered off by switching SW6 to the ‘OFF’ position. Insert the SD card, then configure the boot switch (SW2) to ‘1011’ for SD boot. Finally, power on the board by switching S6 to the ‘ON’ position.

Verify OP-TEE is installed and working

Once the board has booted up, log in as root, no password is required. To verify that the OP-TEE device driver has successfully loaded, run the following command:

root@imx95-19x19-verdin:~# dmesg | grep optee
 [    1.632146] optee: probing for conduit method.
 [    1.636410] optee: revision 4.4 (60beb308810f9561)
 [    1.636999] optee: dynamic shared memory is enabled
 [    1.646679] optee: initialized driver
root@imx95-19x19-verdin:~#

This output verifies that the OP-TEE driver has been successfully loaded. In this instance, the driver is operating with version 4.4.

To verify that the OP-TEE PKCS#11 TA is installed we can simply check that /lib/optee_armtz/fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta (it will always have this odd name) is present and to test that everything is functioning, we can run the OP-TEE PKCS#11 test suite using xtest as shown below:

root@imx95-19x19-verdin:~# xtest -t pkcs11
Run test suite with level=0
...
pkcs11_1028 OK
pkcs11_1029 OK
pkcs11_1030 OK
+-----------------------------------------------------
5679 subtests of which 0 failed
31 test cases of which 0 failed
0 test cases were skipped
TEE test application done!
root@imx95-19x19-verdin:~#

Verify OP-TEE provides PKCS#11

To verify that the pkcs11-tool is installed and OP-TEE is available as a provider, execute the following command:

root@imx95-19x19-verdin:~# pkcs11-tool --show-info --module /usr/lib/libckteec.so.0
 Cryptoki version 2.40
 Manufacturer     Linaro
 Library          OP-TEE PKCS11 Cryptoki library (ver 0.1)
 Using slot 0 with a present token (0x0)
 root@imx95-19x19-verdin:~#

Create a PKCS#11 token

First, we need to initialise a Security Officer PIN (SO-PIN) and assign the token the name “cert_token”. The SO-PIN is used to authenticate the administrator of the HSM, define policies, configure roles, and initialise tokens.

root@imx95-19x19-verdin:~# pkcs11-tool --module /usr/lib/libckteec.so.0 --slot 0 --init-token --label cert_token --so-pin 1234567890
 Token successfully initialized

Note: This is will also clear the token if it already contains objects

Next, log in to the token using the SO-PIN and set the user PIN to 12345

root@imx95-19x19-verdin:~# pkcs11-tool --module /usr/lib/libckteec.so.0 --token-label cert_token --login --so-pin 1234567890 --init-pin --pin 12345
 User PIN successfully initialized

Create RSA Public Private Key

Once the token is initialised, we can generate an RSA 2048 key pair using the pkcs11-tool. This process creates a non-extractable private key within OP-TEE, ensuring the key remains securely confined within the Trusted Execution Environment.

root@imx95-19x19-verdin:~# pkcs11-tool --module /usr/lib/libckteec.so.0 --token-label cert_token --pin=12345 --keypairgen --key-type RSA:2048 --label cert_key --id 1
 Key pair generated:
 Private Key Object; RSA 
   label:      cert_key
   ID:         01
   Usage:      decrypt, sign
   Access:     sensitive, always sensitive, never extractable, local
   uri:        pkcs11:model=OP-TEE%20TA;manufacturer=Linaro;serial=0000000000000000;token=cert_token;id=%01;object=cert_key;type=private
 Public Key Object; RSA 2048 bits
   label:      cert_key
   ID:         01
   Usage:      encrypt, verify
   Access:     local
   uri:        pkcs11:model=OP-TEE%20TA;manufacturer=Linaro;serial=0000000000000000;token=cert_token;id=%01;object=cert_key;type=public
 root@imx95-19x19-verdin:~#

Integrate the PKCS#11 Engine with OpenSSL

For application-level integration, OpenSSL, in combination with the PKCS#11 engine from the libp11 library, serves as the interface between PKCS#11 and TLS-based authentication. To enable OpenSSL to recognise the PKCS#11 module and configure user authentication, we need to create an OpenSSL configuration file, optee_hsm.conf. This file will specify the location of the PKCS#11 module and define the user’s PIN for authentication.

openssl_conf = openssl_conf

[openssl_conf]
engines = engines_config

[engines_config]
pkcs11 = engine_pkcs11_parameters

[engine_pkcs11_parameters]
engine_id = pkcs11
dynamic_path = /usr/lib/engines-3/pkcs11.so
MODULE_PATH = /usr/lib/libckteec.so.0
PIN = 12345
init = 0

Create device cert with OpenSSL PKCS#11 engine

The OP-TEE PKCS#11 TA cannot directly generate certificates. However, it can create key pairs within the PKCS#11 module, which can then be used with OpenSSL to generate certificates. Now that we have already generated our key pair using the PKCS#11 module and created an OpenSSL configuration file for OpenSSL to recognise it, we can generate a self-signed certificate with the following command:

root@imx95-19x19-verdin:~# OPENSSL_CONF=optee_hsm.conf openssl req -engine pkcs11 -new -x509 -key "pkcs11:token=cert_token;object=cert_key;type=private" -keyform engine -out /tmp/rsa.hsm.crt -sha256 -days 365 -nodes -subj "/CN=www.example.com"
Engine "pkcs11" set.
root@imx95-19x19-verdin:~#

It is important to note that PKCS#11 uses URIs to reference specific objects within the PKCS#11 token. These URIs are displayed when generating or listing objects. For example, running `pkcs11-tool –module /usr/lib/libckteec.so.0 –token-label cert_token –list-objects –login –pin=12345`

Import certificate to PKCS#11 token

Use the pkcs11-tool utility to import the self-signed certificate into the PKCS#11 token:

root@imx95-19x19-verdin:~# pkcs11-tool --module /usr/lib/libckteec.so.0 --token-label cert_token --pin 12345 --write-object /tmp/rsa.hsm.crt --type cert --label cert_key --id 1
 Created certificate:
 Certificate Object; type = X.509 cert
   label:      cert_certificate
   subject:    DN: CN=www.example.com
   serial:     3BE6897698A957B67FBD1DD2F50F89D1F5AC27B7
   ID:         01
   uri:        pkcs11:model=OP-TEE%20TA;manufacturer=Linaro;serial=0000000000000000;token=cert_token;id=%01;object=cert_certificate;type=cert
 root@imx95-19x19-verdin:~#

Testing with cURL

To test our self-signed certificate and private key, we first need to set up a TLS server on a host. This involves creating a public-private key pair, generating a self-signed certificate and then launching the web server. We can do this using the following commands:

openssl genpkey -algorithm RSA -out server_key.pem -pkeyopt rsa_keygen_bits:2048 > /dev/null 2>&1 
openssl req -new -x509 -key server_key.pem -subj '/CN=Server' -out server_cert.pem
openssl s_server -accept 8080 -cert server_cert.pem -key server_key.pem -www -Verify 1

This start a TLS server that listens on port 8080. The -www option enables a basic web server to display connection details, while the -Verify 1 option enforces client certificate verification.

Now, on the device, we can use cURL to establish a connection to the host server on port 8080 (in this case, 192.168.88.236) using the PKCS#11 client certificate and private key:

root@imx95-19x19-verdin:~# OPENSSL_CONF=optee_hsm.conf curl -k --cert "pkcs11:token=cert_token;object=cert_key;type=cert" --key "pkcs11:token=cert_token;object=cert_key;type=private" https://192.168.88.236:8080

To confirm that everything is working correctly, you should see the client certificate we created in the HTML response from the server. This indicates that the server successfully recognised and authenticated the client certificate.

Conclusion

We demonstrated how to build and custom Yocto reference image for the i.MX 95 Verdin EVK. We explored the process of securely generating a private/public key pair as PKCS#11 objects and using them to create a self-signed certificate with OpenSSL. By integrating PKCS#11 and OP-TEE, we showcased a secure, standardised approach to managing device keys and certificates, without the need for additional hardware like TPMs.

Security Considerations

It’s important to note that security is only as secure as the underlying hardware and software configuration. Here are a few key considerations:

As previously mentioned the Hardware Unique Key (HUK) is a critical component of OP-TEE, as it serves as a non-extractable, device-specific key from which other cryptographic keys are derived. OP-TEE provides a default HUK value of all zeros as a stub for vendors to implement platform-specific HUK support. Therefore, it is crucial to choose a vendor that not only supports this feature but also implements a secure and reliable method for generating and protecting the HUK within the hardware such as i.MX 95 EdgeLock secure enclave.

Secure boot and chain of trust must be implemented to ensure that only authenticated and trusted software is executed on the device. This ensures that any unauthorised or tampered software is prevented from running, protecting the integrity of the Trusted Execution Environment (TEE) and the overall system.

Trusted Applications (TAs) are signed to ensure their authenticity and integrity. By default, OP-TEE OS includes a keypair (keys/default_ta.pem), with the public key being compiled into the OS to validate TA signatures during loading. This default keypair should be replaced with a custom one, ensuring the private key remains securely stored offline.

One solution for securely storing keys offline is to use the YubiHSM 2, a tool for managing private keys and streamlining tasks such as code signing. To learn more about securely implementing code signing with a YubiHSM 2, check out our previous blog post.

Find out More

Toradex specializes in embedded computing technology, offering Arm®-based System on Modules (SoMs) and Customized SBCs. Complemented with direct online sales and long-term product availability, Toradex offers direct premium support and ex-stock availability with local warehouses. Founded in 2003 and headquartered in Horw, Switzerland, the company’s network stretches globally with additional offices in the USA, Canada, China, India, Japan, and Brazil.

You may also like...

Popular Posts