PKCS #11 includes many functions and supports a variety of use cases. The FreeRTOS PKCS #11 library only implements a small subset of functions for the use cases first describe. Each function is fully documented in the PKCS #11 standard. The terminology can be difficult for the first reader, so we also provide examples code below.
PKCS #11 operational functions:
C_Random. Random numbers are required by the TCP/IP stack (for example, when selecting an initial sequence number), within cryptographic algorithms, and during the TLS handshake.
C_Sign. Signing a message sent to another network node allows that node to identify the messages true origin.
C_FindObject. Finds an object managed by PKCS #11, for example the client certificate.
C_GetAttributeValue. This API gets the value of an object's attribute, for example if the object is a key type or a certificate type.
PKCS #11 administrative functions:
C_Initialize. Initializes the crypto libraries.
C_Finalize. Cleans up resources used by the crypto libraries.
C_OpenSession. Opens a session (or connection) between a software application and a particular crypto token.
C_CloseSession. Closes the session opened by C_OpenSession.
C_Login. Logs into a token.
C_GetFunctionList. Obtains a struct containing function pointers for use in calling the PKCS #11 APIs.
C_GetSlotList. Obtains the list of slots, which can be used to access any token in a slot.
Code Samples
Here are some example code snippets that showcase how one might use the PKCS #11 API.
Using C_GenerateRandom:
This code snippet shows how to use PKCS #11 to get a random number. For example, this function can be used for FreeRTOS+TCP to generate random TCP numbers.
Using C_Sign to add our private key's signature to our message:
This is a snippet from the TLS layer of our code that uses PKCS #11 for the C_Sign operation. In this example, just before we send a TLS message, we call into the PKCS #11 layer and ask it to sign our message with our private key.
static int prvPrivateKeySigningCallback( void * pvContext,
mbedtls_md_type_t xMdAlg,
const unsigned char * pucHash,
size_t xHashLen,
unsigned char* pucSig,
size_t * pxSigLen,
int ( *piRng ) ( void *, unsigned char *, size_t ),
void * pvRng )
{
CK_RV xResult = CKR_OK;
int lFinalResult = 0;
TLSContext_t * pxTLSContext = ( TLSContext_t* ) pvContext;
CK_MECHANISM xMech = { 0 };
CK_BYTE xToBeSigned[ 256 ];
CK_ULONG xToBeSignedLen = sizeof( xToBeSigned );
/* Unreferenced parameters. */
( void )( piRng );
( void )( pvRng );
( void )( xMdAlg);
/* Sanity check buffer length. */
if ( xHashLen > sizeof( xToBeSigned ) )
{
xResult = CKR_ARGUMENTS_BAD;
}
/* Format the hash data to be signed. */
if ( CKK_RSA == pxTLSContext->xKeyType )
{
xMech.mechanism = CKM_RSA_PKCS;
/* mbedTLS expects hashed data without padding, but PKCS #11 C_Sign
* function performs a hash & sign if hash algorithm is specified. This
* helper function applies padding indicating data was hashed with
* SHA-256 while still allowing pre-hashed data to be provided. */
xResult = vAppendSHA256AlgorithmIdentifierSequence( ( uint8_t * ) pucHash, xToBeSigned );
xToBeSignedLen = pkcs11RSA_SIGNATURE_INPUT_LENGTH;
}
else if ( CKK_EC == pxTLSContext->xKeyType )
{
xMech.mechanism = CKM_ECDSA;
memcpy( xToBeSigned, pucHash, xHashLen );
xToBeSignedLen = xHashLen;
}
else
{
xResult = CKR_ARGUMENTS_BAD;
}
if ( CKR_OK == xResult )
{
/* Use the PKCS#11 module to sign. */
xResult = pxTLSContext->
pxP11FunctionList->C_SignInit( pxTLSContext->xP11Session,
&xMech,
pxTLSContext->xP11PrivateKey );
}
if ( CKR_OK == xResult )
{
*pxSigLen = sizeof( xToBeSigned );
xResult = pxTLSContext->
pxP11FunctionList->C_Sign( ( CK_SESSION_HANDLE ) pxTLSContext->xP11Session,
xToBeSigned,
xToBeSignedLen,
pucSig,
( CK_ULONG_PTR ) pxSigLen );
}
if ( ( xResult == CKR_OK ) && ( CKK_EC == pxTLSContext->xKeyType ) )
{
/* PKCS #11 for P256 returns a 64-byte signature with 32 bytes for R and
* 32 bytes for S. This must be converted to an ASN.1 encoded array. */
if (*pxSigLen != pkcs11ECDSA_P256_SIGNATURE_LENGTH)
{
xResult = CKR_FUNCTION_FAILED;
}
if ( xResult == CKR_OK )
{
PKI_pkcs11SignatureTombedTLSSignature( pucSig, pxSigLen );
}
}
if ( xResult != CKR_OK )
{
TLS_PRINT( ( "ERROR: Failure in signing callback: %d \r\n", xResult ) );
lFinalResult = TLS_ERROR_SIGN;
}
return lFinalResult;
}
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.