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
here.
The corePKCS11 demo projects use the
FreeRTOS Windows port, so they can be built and evaluated with the
free Community version
of Visual Studio 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 Studio.
- Open the
FreeRTOS\FreeRTOS-Plus\Demo\corePKCS11_Windows_Simulator\pkcs11_demo.sln
Visual Studio solution file from within the Visual Studio IDE.
- 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:
PKCS11_CertificateTemplate_t xCertificateTemplate;
CK_OBJECT_CLASS xCertificateClass = CKO_CERTIFICATE;
CK_CERTIFICATE_TYPE xCertificateType = CKC_X_509;
CK_BYTE pucLabel[] = pkcs11configLABEL_DEVICE_CERTIFICATE_FOR_TLS;
xCertificateTemplate.xObjectClass.type = CKA_CLASS;
xCertificateTemplate.xObjectClass.pValue = &xCertificateClass;
xCertificateTemplate.xObjectClass.ulValueLen = sizeof( xCertificateClass );
xCertificateTemplate.xSubject.type = CKA_SUBJECT;
xCertificateTemplate.xSubject.pValue = xSubject;
xCertificateTemplate.xSubject.ulValueLen = strlen( ( const char * ) xSubject );
xCertificateTemplate.xValue.type = CKA_VALUE;
xCertificateTemplate.xValue.pValue = ( CK_VOID_PTR ) pkcs11demo_RSA_CERTIFICATE;
xCertificateTemplate.xValue.ulValueLen = ( CK_ULONG ) sizeof( pkcs11demo_RSA_CERTIFICATE );
xCertificateTemplate.xLabel.type = CKA_LABEL;
xCertificateTemplate.xLabel.pValue = ( CK_VOID_PTR ) pucLabel;
xCertificateTemplate.xLabel.ulValueLen = strlen( ( const char * ) pucLabel );
xCertificateTemplate.xCertificateType.type = CKA_CERTIFICATE_TYPE;
xCertificateTemplate.xCertificateType.pValue = &xCertificateType;
xCertificateTemplate.xCertificateType.ulValueLen = sizeof( CK_CERTIFICATE_TYPE );
xCertificateTemplate.xTokenObject.type = CKA_TOKEN;
xCertificateTemplate.xTokenObject.pValue = &xTokenStorage;
xCertificateTemplate.xTokenObject.ulValueLen = sizeof( xTokenStorage );
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:
xResult = pxFunctionList->C_CreateObject( hSession,
( CK_ATTRIBUTE_PTR ) &xCertificateTemplate,
sizeof( xCertificateTemplate ) / sizeof( CK_ATTRIBUTE ),
&xCertHandle );
configASSERT( xResult == CKR_OK );
configASSERT( xCertHandle != CK_INVALID_HANDLE );
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:
CK_ATTRIBUTE xPublicKeyTemplate[] =
{
{ CKA_KEY_TYPE, &xKeyType, sizeof( xKeyType ) },
{ CKA_VERIFY, &xTrue, sizeof( xTrue ) },
{ CKA_EC_PARAMS, xEcParams, sizeof( xEcParams ) },
{ CKA_LABEL, pucPublicKeyLabel, sizeof( pucPublicKeyLabel ) - 1 }
};
CK_ATTRIBUTE xPrivateKeyTemplate[] =
{
{ CKA_KEY_TYPE, &xKeyType, sizeof( xKeyType ) },
{ CKA_TOKEN, &xTrue, sizeof( xTrue ) },
{ CKA_PRIVATE, &xTrue, sizeof( xTrue ) },
{ CKA_SIGN, &xTrue, sizeof( xTrue ) },
{ CKA_LABEL, pucPrivateKeyLabel, sizeof( pucPrivateKeyLabel ) - 1 }
};
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:
xResult = pxFunctionList->C_GenerateKeyPair( hSession,
&xMechanism,
xPublicKeyTemplate,
sizeof( xPublicKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
xPrivateKeyTemplate,
sizeof( xPrivateKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
&xPublicKeyHandle,
&xPrivateKeyHandle );
configASSERT( xResult == CKR_OK );
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.