Updated Apr 2025

corePKCS11 Objects Demo

Introduction

This demo is the third in the corePKCS11 demo series. It introduces the section of the PKCS #11 API used for managing objects. An object is defined as "An item that is stored on a token. May be data, a certificate, or a key." This demo will give an overview of how PKCS #11 can be used to abstract some commonly used objects. This interface is particularly useful because it is very portable and flexible. Using PKCS #11 to manipulate these objects benefits security because it reduces the scope of attack on the objects to a module that is specialized for cryptographic operations and protecting objects.

Note: This demo will write a public and private EC key to the Windows file system. They will both be contained in a binary formatted file called "

FreeRTOS_P11_Key.dat
". The sign and verify demo has a direct dependency on this file, and will not work without it.

The PKCS #11 standard can be found hereexternal_link.

The corePKCS11 demo projects use the FreeRTOS Windows port, so they can be built and evaluated with the free Community version of Visual Studioexternal_link on Windows without the need for any particular MCU hardware.

The set of functions presented in this demo are categorized as:

  • Object Management Functions

Source Code Organization

The Visual Studio solution for the PKCS #11 based mutual authentication demo is called

pkcs11\_demo.sln
and is located in the
FreeRTOS\FreeRTOS-Plus\Demo\corePKCS11\_Windows\_Simulator\
directory of the main FreeRTOS download.

Click to enlarge

Configuring the Demo Project

To configure the demo project, set

configPKCS11\_OBJECT\_DEMO
to 1 in
pkcs11\_demo\_config.h
. This is enabled by default. After you complete this, the demo can be run, there are no other configuration steps required for this demo.

Building the Demo Project

The demo project uses the free community edition of Visual Studioexternal_link.

  1. Open the
    FreeRTOS\FreeRTOS-Plus\Demo\corePKCS11_Windows_Simulator\pkcs11_demo.sln
    Visual Studio solution file from within the Visual Studio IDE.
  2. Select '
    build solution
    ' from the IDE's '
    build
    ' menu.

Functionality

Once enabled, this demo's entry point is

vPKCS11ObjectDemo
. Currently, the demo is split into two smaller demos:
prvObjectImporting
shows how to import an object into a PKCS #11 module and
prvObjectGeneration
shows how to generate objects within the PKCS #11 module.

It is more secure to generate credentials directly on the IoT device because the credentials will not be exposed to any external system. It is even more secure if the IoT device has a secure element. Secure elements are specialty chips that protect sensitive data such as private keys. They provide extra protection against attackers who might attempt to extract an IoT device's private key. Simply storing a private key in flash memory is not safe.

The demo shows how to import a certificate into a PKCS #11 stack. This is useful because it allows you to store certificates from any server your application wishes to trust. A template is an array of CK_ATTRIBUTE's that describes an object.

Creating an X.509 certificate template:

1/* The PKCS11_CertificateTemplate_t is a custom struct defined in "iot\_pkcs11.h"
2 * in order to make it easier to import a certificate. This struct will be
3 * populated with the parameters necessary to import the certificate into the
4 * Cryptoki library.
5 */
6PKCS11_CertificateTemplate_t xCertificateTemplate;
7
8/* The object class is specified as a certificate to help the Cryptoki library
9 * parse the arguments.
10 */
11CK_OBJECT_CLASS xCertificateClass = CKO_CERTIFICATE;
12
13/* The certificate type is x509, which is the only type
14 * supported by this stack. To read more about x509 certificates, use
15 * the following links:
16 *
18 * ssl.com
19 *
20 */
21CK_CERTIFICATE_TYPE xCertificateType = CKC_X_509;
22
23/* The label will help the application identify which object it wants
24 * to access.
25 */
26CK_BYTE pucLabel[] = pkcs11configLABEL_DEVICE_CERTIFICATE_FOR_TLS;
27
28/* Specify certificate class. */
29xCertificateTemplate.xObjectClass.type = CKA_CLASS;
30xCertificateTemplate.xObjectClass.pValue = &xCertificateClass;
31xCertificateTemplate.xObjectClass.ulValueLen = sizeof( xCertificateClass );
32
33/* Specify certificate subject. */
34xCertificateTemplate.xSubject.type = CKA_SUBJECT;
35xCertificateTemplate.xSubject.pValue = xSubject;
36xCertificateTemplate.xSubject.ulValueLen = strlen( ( const char * ) xSubject );
37
38/* Point to contents of certificate. */
39xCertificateTemplate.xValue.type = CKA_VALUE;
40xCertificateTemplate.xValue.pValue = ( CK_VOID_PTR ) pkcs11demo_RSA_CERTIFICATE;
41xCertificateTemplate.xValue.ulValueLen = ( CK_ULONG ) sizeof( pkcs11demo_RSA_CERTIFICATE );
42
43/* Specify certificate label. */
44xCertificateTemplate.xLabel.type = CKA_LABEL;
45xCertificateTemplate.xLabel.pValue = ( CK_VOID_PTR ) pucLabel;
46xCertificateTemplate.xLabel.ulValueLen = strlen( ( const char * ) pucLabel );
47
48/* Specify certificate type as x509. */
49xCertificateTemplate.xCertificateType.type = CKA_CERTIFICATE_TYPE;
50xCertificateTemplate.xCertificateType.pValue = &xCertificateType;
51xCertificateTemplate.xCertificateType.ulValueLen = sizeof( CK_CERTIFICATE_TYPE );
52
53/* Specify that the certificate should be on a token. */
54xCertificateTemplate.xTokenObject.type = CKA_TOKEN;
55xCertificateTemplate.xTokenObject.pValue = &xTokenStorage;
56xCertificateTemplate.xTokenObject.ulValueLen = sizeof( xTokenStorage );
57

After the template has been created it can be passed to

C_CreateObject
, along with the number of entries in the array. The PKCS #11 module will parse the arguments and return
CKR_OK
if it is able to create the x509 certificate. This method is a good way to import well known certificates into the PKCS #11 module.

Creating a X.509 certificate:

1/* Once the Cryptoki library has finished importing the new certificate
2 * a CK_OBJECT_HANDLE is associated with it. The application can now use this
3 * to refer to the object in following operations.
4 *
5 * xCertHandle in the below example will have it's value modified to
6 * be the CK_OBJECT_HANDLE.
7 *
8 * To compare the hard coded x509, in PEM format, with the DER formatted
9 * x509 certificate that is created by the Cryptoki library, use the following
10 * OpenSSL command:
11 * "$ openssl x509 -in FreeRTOS_P11_Certificate.dat -inform der -text"
12 *
13 * See this explanation for the difference between the PEM format and the
14 * DER format:
16 *
17 */
18xResult = pxFunctionList->C_CreateObject( hSession,
19 ( CK_ATTRIBUTE_PTR ) &xCertificateTemplate,
20 sizeof( xCertificateTemplate ) / sizeof( CK_ATTRIBUTE ),
21 &xCertHandle );
22
23configASSERT( xResult == CKR_OK );
24configASSERT( xCertHandle != CK_INVALID_HANDLE );
25

The second half of the demo covers how to generate a key pair using PKCS #11. This method is preferable because the application is never exposed to the memory that contains the private key. This reduces the potential ways an attacker could extract the private key, since it was never actually stored outside of the PKCS #11 module.

Once again, a template is used to generate the keys in the following code.

Creating a key pair generation template:

1/* CK_ATTTRIBUTE's contain an attribute type, a value, and the length of
2 * the value. An array of CK_ATTRIBUTEs is called a template. They are used
3 * to create, search for, and manipulate objects. The order of the
4 * template does not matter.
5 *
6 * In the below template we create a public key:
7 * Specify the key type as EC.
8 * The key will be able to verify a message.
9 * Specify the EC Curve.
10 * Assign a label to the object that will be created.
11 */
12CK_ATTRIBUTE xPublicKeyTemplate[] =
13{
14 { CKA_KEY_TYPE, &xKeyType, sizeof( xKeyType ) },
15 { CKA_VERIFY, &xTrue, sizeof( xTrue ) },
16 { CKA_EC_PARAMS, xEcParams, sizeof( xEcParams ) },
17 { CKA_LABEL, pucPublicKeyLabel, sizeof( pucPublicKeyLabel ) - 1 }
18};
19
20/* In the below template we create a private key:
21 * The key type is EC.
22 * The key is a token object.
23 * The key will be a private key.
24 * The key will be able to sign messages.
25 * Assign a label to the object that will be created.
26 */
27CK_ATTRIBUTE xPrivateKeyTemplate[] =
28{
29 { CKA_KEY_TYPE, &xKeyType, sizeof( xKeyType ) },
30 { CKA_TOKEN, &xTrue, sizeof( xTrue ) },
31 { CKA_PRIVATE, &xTrue, sizeof( xTrue ) },
32 { CKA_SIGN, &xTrue, sizeof( xTrue ) },
33 { CKA_LABEL, pucPrivateKeyLabel, sizeof( pucPrivateKeyLabel ) - 1 }
34};
35

Finally, this template is created and when it is passed it to

C_GenerateKeyPair
a new key pair will be created by the PKCS #11 module.

Creating a key pair:

1/* This function will generate a new EC private and public key pair. You can
2 * use " $openssl ec -inform der -in FreeRTOS_P11_Key.dat -text " to see
3 * the structure of the keys that were generated.
4 */
5xResult = pxFunctionList->C_GenerateKeyPair( hSession,
6 &xMechanism,
7 xPublicKeyTemplate,
8 sizeof( xPublicKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
9 xPrivateKeyTemplate,
10 sizeof( xPrivateKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
11 &xPublicKeyHandle,
12 &xPrivateKeyHandle );
13configASSERT( xResult == CKR_OK );
14