summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Demo/AWS/Fleet_Provisioning_Windows_Simulator/Fleet_Provisioning_With_CSR_Demo/pkcs11_operations.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Demo/AWS/Fleet_Provisioning_Windows_Simulator/Fleet_Provisioning_With_CSR_Demo/pkcs11_operations.c')
-rw-r--r--FreeRTOS-Plus/Demo/AWS/Fleet_Provisioning_Windows_Simulator/Fleet_Provisioning_With_CSR_Demo/pkcs11_operations.c691
1 files changed, 691 insertions, 0 deletions
diff --git a/FreeRTOS-Plus/Demo/AWS/Fleet_Provisioning_Windows_Simulator/Fleet_Provisioning_With_CSR_Demo/pkcs11_operations.c b/FreeRTOS-Plus/Demo/AWS/Fleet_Provisioning_Windows_Simulator/Fleet_Provisioning_With_CSR_Demo/pkcs11_operations.c
new file mode 100644
index 000000000..9b5a34b98
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/AWS/Fleet_Provisioning_Windows_Simulator/Fleet_Provisioning_With_CSR_Demo/pkcs11_operations.c
@@ -0,0 +1,691 @@
+/*
+ * FreeRTOS V202111.00
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+/**
+ * @file pkcs11_operations.c
+ *
+ * @brief This file provides wrapper functions for PKCS11 operations.
+ */
+
+/* Standard includes. */
+#include <errno.h>
+#include <assert.h>
+
+/* Config include. */
+#include "demo_config.h"
+
+/* Interface include. */
+#include "pkcs11_operations.h"
+
+/* PKCS #11 include. */
+#include "core_pkcs11_config.h"
+#include "core_pki_utils.h"
+#include "mbedtls_utils.h"
+
+/* MbedTLS include. */
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/entropy_poll.h"
+#include "mbedtls/error.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/pk_internal.h"
+#include "mbedtls/sha256.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_csr.h"
+
+/**
+ * @brief Represents string to be logged when mbedTLS returned error
+ * does not contain a high-level code.
+ */
+static const char * pcNoHighLevelMbedTlsCodeStr = "<No-High-Level-Code>";
+
+/**
+ * @brief Represents string to be logged when mbedTLS returned error
+ * does not contain a low-level code.
+ */
+static const char * pcNoLowLevelMbedTlsCodeStr = "<No-Low-Level-Code>";
+
+/**
+ * @brief Utility for converting the high-level code in an mbedTLS error to
+ * string, if the code-contains a high-level code; otherwise, using a default
+ * string.
+ */
+#define mbedtlsHighLevelCodeOrDefault( mbedTlsCode ) \
+ ( mbedtls_high_level_strerr( mbedTlsCode ) != NULL ) \
+ ? mbedtls_high_level_strerr( mbedTlsCode ) \
+ : pcNoHighLevelMbedTlsCodeStr
+
+/**
+ * @brief Utility for converting the level-level code in an mbedTLS error to
+ * string, if the code-contains a level-level code; otherwise, using a default
+ * string.
+ */
+#define mbedtlsLowLevelCodeOrDefault( mbedTlsCode ) \
+ ( mbedtls_low_level_strerr( mbedTlsCode ) != NULL ) \
+ ? mbedtls_low_level_strerr( mbedTlsCode ) \
+ : pcNoLowLevelMbedTlsCodeStr
+
+/**
+ * @brief Struct containing parameters needed by the signing callback.
+ */
+typedef struct SigningCallbackContext
+{
+ CK_SESSION_HANDLE p11Session;
+ CK_OBJECT_HANDLE p11PrivateKey;
+} SigningCallbackContext_t;
+
+/**
+ * @brief Parameters for the signing callback. This needs to be global as
+ * MbedTLS passes the key context to the signing function, so we cannot pass
+ * our own.
+ */
+static SigningCallbackContext_t xSigningContext = { 0 };
+
+/*-----------------------------------------------------------*/
+
+/**
+ * @brief Delete the specified crypto object from storage.
+ *
+ * @param[in] xSession The PKCS #11 session.
+ * @param[in] pxPkcsLabelsPtr The list of labels to remove.
+ * @param[in] pxClass The list of corresponding classes.
+ * @param[in] xCount The length of #pxPkcsLabelsPtr and #pxClass.
+ */
+static CK_RV prvDestroyProvidedObjects( CK_SESSION_HANDLE xSession,
+ CK_BYTE_PTR * pxPkcsLabelsPtr,
+ CK_OBJECT_CLASS * pxClass,
+ CK_ULONG xCount );
+
+/**
+ * @brief Read the specified ECDSA public key into the MbedTLS ECDSA context.
+ *
+ * @param[in] xP11Session The PKCS #11 session.
+ * @param[in] pxEcdsaContext The context in which to store the key.
+ * @param[in] xPublicKey The public key to read.
+ */
+static int prvExtractEcPublicKey( CK_SESSION_HANDLE xP11Session,
+ mbedtls_ecdsa_context * pxEcdsaContext,
+ CK_OBJECT_HANDLE xPublicKey );
+
+/**
+ * @brief MbedTLS callback for signing using the provisioned private key. Used for
+ * signing the CSR.
+ *
+ * @param[in] pxContext Unused.
+ * @param[in] xMdAlg Unused.
+ * @param[in] pucHash Data to sign.
+ * @param[in] xHashLen Length of #pucHash.
+ * @param[out] pucSig The signature
+ * @param[out] pxSigLen The length of the signature.
+ * @param[in] pxRng Unused.
+ * @param[in] pxRngContext Unused.
+ */
+static int32_t prvPrivateKeySigningCallback( void * pxContext,
+ mbedtls_md_type_t xMdAlg,
+ const unsigned char * pucHash,
+ size_t xHashLen,
+ unsigned char * pucSig,
+ size_t * pxSigLen,
+ int ( * pxRng )( void *, unsigned char *, size_t ),
+ void * pxRngContext );
+
+/**
+ * @brief MbedTLS random generation callback to generate random values with
+ * PKCS #11.
+ *
+ * @param[in] pxCtx Pointer to the PKCS #11 session handle.
+ * @param[out] pucRandom Buffer to write random data to.
+ * @param[in] xRandomLength Length of random data to write.
+ */
+static int prvRandomCallback( void * pxCtx,
+ unsigned char * pucRandom,
+ size_t xRandomLength );
+
+/**
+ * @brief Generate a new ECDSA key pair using PKCS #11.
+ *
+ * @param[in] xSession The PKCS #11 session.
+ * @param[in] pcPrivateKeyLabel The label to store the private key.
+ * @param[in] pcPublicKeyLabel The label to store the public key.
+ * @param[out] xPrivateKeyHandlePtr The handle of the private key.
+ * @param[out] xPublicKeyHandlePtr The handle of the public key.
+ */
+static CK_RV prvGenerateKeyPairEC( CK_SESSION_HANDLE xSession,
+ const char * pcPrivateKeyLabel,
+ const char * pcPublicKeyLabel,
+ CK_OBJECT_HANDLE_PTR xPrivateKeyHandlePtr,
+ CK_OBJECT_HANDLE_PTR xPublicKeyHandlePtr );
+
+/*-----------------------------------------------------------*/
+
+static CK_RV prvDestroyProvidedObjects( CK_SESSION_HANDLE xSession,
+ CK_BYTE_PTR * pxPkcsLabelsPtr,
+ CK_OBJECT_CLASS * pxClass,
+ CK_ULONG xCount )
+{
+ CK_RV xResult;
+ CK_FUNCTION_LIST_PTR xFunctionList;
+ CK_OBJECT_HANDLE xObjectHandle;
+ CK_BYTE * pxLabelPtr;
+ CK_ULONG xIndex = 0;
+
+ xResult = C_GetFunctionList( &xFunctionList );
+
+ if( xResult != CKR_OK )
+ {
+ LogError( ( "Could not get a PKCS #11 function pointer." ) );
+ }
+ else
+ {
+ for( xIndex = 0; xIndex < xCount; xIndex++ )
+ {
+ pxLabelPtr = pxPkcsLabelsPtr[ xIndex ];
+
+ xResult = xFindObjectWithLabelAndClass( xSession, ( char * ) pxLabelPtr,
+ strnlen( ( char * ) pxLabelPtr, pkcs11configMAX_LABEL_LENGTH ),
+ pxClass[ xIndex ], &xObjectHandle );
+
+ while( ( xResult == CKR_OK ) && ( xObjectHandle != CK_INVALID_HANDLE ) )
+ {
+ xResult = xFunctionList->C_DestroyObject( xSession, xObjectHandle );
+
+ /* PKCS #11 allows a module to maintain multiple objects with the same
+ * label and type. The intent of this loop is to try to delete all of
+ * them. However, to avoid getting stuck, we won't try to find another
+ * object of the same label/type if the previous delete failed. */
+ if( xResult == CKR_OK )
+ {
+ xResult = xFindObjectWithLabelAndClass( xSession, ( char * ) pxLabelPtr,
+ strnlen( ( char * ) pxLabelPtr, pkcs11configMAX_LABEL_LENGTH ),
+ pxClass[ xIndex ], &xObjectHandle );
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ return xResult;
+}
+
+/*-----------------------------------------------------------*/
+
+static int prvExtractEcPublicKey( CK_SESSION_HANDLE xP11Session,
+ mbedtls_ecdsa_context * pxEcdsaContext,
+ CK_OBJECT_HANDLE xPublicKey )
+{
+ CK_ATTRIBUTE xEcTemplate = { 0 };
+ int xMbedtlsRet = -1;
+ CK_RV xPkcs11ret = CKR_OK;
+ CK_BYTE pxEcPoint[ 67 ] = { 0 };
+ CK_FUNCTION_LIST_PTR xP11FunctionList;
+
+ mbedtls_ecdsa_init( pxEcdsaContext );
+ mbedtls_ecp_group_init( &( pxEcdsaContext->grp ) );
+
+ xPkcs11ret = C_GetFunctionList( &xP11FunctionList );
+
+ if( xPkcs11ret != CKR_OK )
+ {
+ LogError( ( "Could not get a PKCS #11 function pointer." ) );
+ }
+ else
+ {
+ xEcTemplate.type = CKA_EC_POINT;
+ xEcTemplate.pValue = pxEcPoint;
+ xEcTemplate.ulValueLen = sizeof( pxEcPoint );
+ xPkcs11ret = xP11FunctionList->C_GetAttributeValue( xP11Session, xPublicKey, &xEcTemplate, 1 );
+
+ if( xPkcs11ret != CKR_OK )
+ {
+ LogError( ( "Failed to extract EC public key. Could not get attribute value. "
+ "C_GetAttributeValue failed with %lu.", xPkcs11ret ) );
+ }
+ }
+
+ if( xPkcs11ret == CKR_OK )
+ {
+ xMbedtlsRet = mbedtls_ecp_group_load( &( pxEcdsaContext->grp ), MBEDTLS_ECP_DP_SECP256R1 );
+
+ if( xMbedtlsRet != 0 )
+ {
+ LogError( ( "Failed creating an EC key. "
+ "mbedtls_ecp_group_load failed: MbedTLS"
+ "error = %s : %s.",
+ mbedtlsHighLevelCodeOrDefault( xMbedtlsRet ),
+ mbedtlsLowLevelCodeOrDefault( xMbedtlsRet ) ) );
+ xPkcs11ret = CKR_FUNCTION_FAILED;
+ }
+ else
+ {
+ xMbedtlsRet = mbedtls_ecp_point_read_binary( &( pxEcdsaContext->grp ), &( pxEcdsaContext->Q ), &pxEcPoint[ 2 ], xEcTemplate.ulValueLen - 2 );
+
+ if( xMbedtlsRet != 0 )
+ {
+ LogError( ( "Failed creating an EC key. "
+ "mbedtls_ecp_group_load failed: MbedTLS"
+ "error = %s : %s.",
+ mbedtlsHighLevelCodeOrDefault( xMbedtlsRet ),
+ mbedtlsLowLevelCodeOrDefault( xMbedtlsRet ) ) );
+ xPkcs11ret = CKR_FUNCTION_FAILED;
+ }
+ }
+ }
+
+ return xMbedtlsRet;
+}
+
+/*-----------------------------------------------------------*/
+
+static int32_t prvPrivateKeySigningCallback( void * pxContext,
+ mbedtls_md_type_t xMdAlg,
+ const unsigned char * pucHash,
+ size_t xHashLen,
+ unsigned char * pucSig,
+ size_t * pxSigLen,
+ int ( * pxRng )( void *, unsigned char *, size_t ),
+ void * pxRngContext )
+{
+ CK_RV xRet = CKR_OK;
+ int32_t usResult = 0;
+ CK_MECHANISM xMech = { 0 };
+ CK_BYTE pxToBeSigned[ 256 ];
+ CK_ULONG xToBeSignedLen = sizeof( pxToBeSigned );
+ CK_FUNCTION_LIST_PTR xFunctionList = NULL;
+
+ /* Unreferenced parameters. */
+ ( void ) ( pxContext );
+ ( void ) ( pxRng );
+ ( void ) ( pxRngContext );
+ ( void ) ( xMdAlg );
+
+ /* Sanity check buffer length. */
+ if( xHashLen > sizeof( pxToBeSigned ) )
+ {
+ xRet = CKR_ARGUMENTS_BAD;
+ }
+
+ xMech.mechanism = CKM_ECDSA;
+ memcpy( pxToBeSigned, pucHash, xHashLen );
+ xToBeSignedLen = xHashLen;
+
+ if( xRet == CKR_OK )
+ {
+ xRet = C_GetFunctionList( &xFunctionList );
+ }
+
+ if( xRet == CKR_OK )
+ {
+ xRet = xFunctionList->C_SignInit( xSigningContext.p11Session, &xMech,
+ xSigningContext.p11PrivateKey );
+ }
+
+ if( xRet == CKR_OK )
+ {
+ *pxSigLen = sizeof( pxToBeSigned );
+ xRet = xFunctionList->C_Sign( xSigningContext.p11Session, pxToBeSigned,
+ xToBeSignedLen, pucSig, ( CK_ULONG_PTR ) pxSigLen );
+ }
+
+ if( xRet == CKR_OK )
+ {
+ /* 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 )
+ {
+ xRet = CKR_FUNCTION_FAILED;
+ LogError( ( "Failed to sign message using PKCS #11. Expected signature "
+ "length of %lu, but received %lu.",
+ ( unsigned long ) pkcs11ECDSA_P256_SIGNATURE_LENGTH,
+ ( unsigned long ) *pxSigLen ) );
+ }
+
+ if( xRet == CKR_OK )
+ {
+ PKI_pkcs11SignatureTombedTLSSignature( pucSig, pxSigLen );
+ }
+ }
+
+ if( xRet != CKR_OK )
+ {
+ LogError( ( "Failed to sign message using PKCS #11 with error code %lu.", xRet ) );
+ usResult = -1;
+ }
+
+ return usResult;
+}
+
+/*-----------------------------------------------------------*/
+
+static int prvRandomCallback( void * pxCtx,
+ unsigned char * pucRandom,
+ size_t xRandomLength )
+{
+ CK_SESSION_HANDLE * pxP11Session = ( CK_SESSION_HANDLE * ) pxCtx;
+ CK_RV xRes;
+ CK_FUNCTION_LIST_PTR xP11FunctionList;
+
+ xRes = C_GetFunctionList( &xP11FunctionList );
+
+ if( xRes != CKR_OK )
+ {
+ LogError( ( "Failed to generate a random number in RNG callback. Could not get a "
+ "PKCS #11 function pointer." ) );
+ }
+ else
+ {
+ xRes = xP11FunctionList->C_GenerateRandom( *pxP11Session, pucRandom, xRandomLength );
+
+ if( xRes != CKR_OK )
+ {
+ LogError( ( "Failed to generate a random number in RNG callback. "
+ "C_GenerateRandom failed with %lu.", ( unsigned long ) xRes ) );
+ }
+ }
+
+ return ( int ) xRes;
+}
+
+/*-----------------------------------------------------------*/
+
+static CK_RV prvGenerateKeyPairEC( CK_SESSION_HANDLE xSession,
+ const char * pcPrivateKeyLabel,
+ const char * pcPublicKeyLabel,
+ CK_OBJECT_HANDLE_PTR xPrivateKeyHandlePtr,
+ CK_OBJECT_HANDLE_PTR xPublicKeyHandlePtr )
+{
+ CK_RV xResult;
+ CK_MECHANISM xMechanism = { CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 };
+ CK_FUNCTION_LIST_PTR xFunctionList;
+ CK_BYTE pxEcParams[] = pkcs11DER_ENCODED_OID_P256; /* prime256v1 */
+ CK_KEY_TYPE xKeyType = CKK_EC;
+
+ CK_BBOOL xTrueObject = CK_TRUE;
+ CK_ATTRIBUTE pxPublicKeyTemplate[] =
+ {
+ { CKA_KEY_TYPE, NULL /* &keyType */, sizeof( xKeyType ) },
+ { CKA_VERIFY, NULL /* &trueObject */, sizeof( xTrueObject ) },
+ { CKA_EC_PARAMS, NULL /* ecParams */, sizeof( pxEcParams ) },
+ { CKA_LABEL, ( void * ) pcPublicKeyLabel, strnlen( pcPublicKeyLabel, pkcs11configMAX_LABEL_LENGTH )}
+ };
+
+ /* Aggregate initializers must not use the address of an automatic variable. */
+ pxPublicKeyTemplate[ 0 ].pValue = &xKeyType;
+ pxPublicKeyTemplate[ 1 ].pValue = &xTrueObject;
+ pxPublicKeyTemplate[ 2 ].pValue = &pxEcParams;
+
+ CK_ATTRIBUTE privateKeyTemplate[] =
+ {
+ { CKA_KEY_TYPE, NULL /* &keyType */, sizeof( xKeyType ) },
+ { CKA_TOKEN, NULL /* &trueObject */, sizeof( xTrueObject ) },
+ { CKA_PRIVATE, NULL /* &trueObject */, sizeof( xTrueObject ) },
+ { CKA_SIGN, NULL /* &trueObject */, sizeof( xTrueObject ) },
+ { CKA_LABEL, ( void * ) pcPrivateKeyLabel, strnlen( pcPrivateKeyLabel, pkcs11configMAX_LABEL_LENGTH )}
+ };
+
+ /* Aggregate initializers must not use the address of an automatic variable. */
+ privateKeyTemplate[ 0 ].pValue = &xKeyType;
+ privateKeyTemplate[ 1 ].pValue = &xTrueObject;
+ privateKeyTemplate[ 2 ].pValue = &xTrueObject;
+ privateKeyTemplate[ 3 ].pValue = &xTrueObject;
+
+ xResult = C_GetFunctionList( &xFunctionList );
+
+ if( xResult != CKR_OK )
+ {
+ LogError( ( "Could not get a PKCS #11 function pointer." ) );
+ }
+ else
+ {
+ xResult = xFunctionList->C_GenerateKeyPair( xSession,
+ &xMechanism,
+ pxPublicKeyTemplate,
+ sizeof( pxPublicKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
+ privateKeyTemplate, sizeof( privateKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
+ xPublicKeyHandlePtr,
+ xPrivateKeyHandlePtr );
+ }
+
+ return xResult;
+}
+
+/*-----------------------------------------------------------*/
+
+bool xGenerateKeyAndCsr( CK_SESSION_HANDLE xP11Session,
+ const char * pcPrivKeyLabel,
+ const char * pcPubKeyLabel,
+ char * pcCsrBuffer,
+ size_t xCsrBufferLength,
+ size_t * pxOutCsrLength )
+{
+ CK_OBJECT_HANDLE xPrivKeyHandle;
+ CK_OBJECT_HANDLE xPubKeyHandle;
+ CK_RV xPkcs11Ret = CKR_OK;
+ mbedtls_pk_context xPrivKey;
+ mbedtls_pk_info_t xPrivKeyInfo;
+ mbedtls_ecdsa_context xEcdsaContext;
+ mbedtls_x509write_csr xReq;
+ int32_t ulMbedtlsRet = -1;
+ const mbedtls_pk_info_t * pxHeader = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY );
+
+ configASSERT( pcPrivKeyLabel != NULL );
+ configASSERT( pcPubKeyLabel != NULL );
+ configASSERT( pcCsrBuffer != NULL );
+ configASSERT( pxOutCsrLength != NULL );
+
+ xPkcs11Ret = prvGenerateKeyPairEC( xP11Session,
+ pcPrivKeyLabel,
+ pcPubKeyLabel,
+ &xPrivKeyHandle,
+ &xPubKeyHandle );
+
+ if( xPkcs11Ret == CKR_OK )
+ {
+ mbedtls_x509write_csr_init( &xReq );
+ mbedtls_x509write_csr_set_md_alg( &xReq, MBEDTLS_MD_SHA256 );
+
+ ulMbedtlsRet = mbedtls_x509write_csr_set_key_usage( &xReq, MBEDTLS_X509_KU_DIGITAL_SIGNATURE );
+
+ if( ulMbedtlsRet == 0 )
+ {
+ ulMbedtlsRet = mbedtls_x509write_csr_set_ns_cert_type( &xReq, MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT );
+ }
+
+ if( ulMbedtlsRet == 0 )
+ {
+ ulMbedtlsRet = mbedtls_x509write_csr_set_subject_name( &xReq, democonfigCSR_SUBJECT_NAME );
+ }
+
+ if( ulMbedtlsRet == 0 )
+ {
+ mbedtls_pk_init( &xPrivKey );
+ }
+
+ if( ulMbedtlsRet == 0 )
+ {
+ ulMbedtlsRet = prvExtractEcPublicKey( xP11Session, &xEcdsaContext, xPubKeyHandle );
+ }
+
+ if( ulMbedtlsRet == 0 )
+ {
+ xSigningContext.p11Session = xP11Session;
+ xSigningContext.p11PrivateKey = xPrivKeyHandle;
+
+ memcpy( &xPrivKeyInfo, pxHeader, sizeof( mbedtls_pk_info_t ) );
+
+ xPrivKeyInfo.sign_func = prvPrivateKeySigningCallback;
+ xPrivKey.pk_info = &xPrivKeyInfo;
+ xPrivKey.pk_ctx = &xEcdsaContext;
+
+ mbedtls_x509write_csr_set_key( &xReq, &xPrivKey );
+
+ ulMbedtlsRet = mbedtls_x509write_csr_pem( &xReq, ( unsigned char * ) pcCsrBuffer,
+ xCsrBufferLength, &prvRandomCallback,
+ &xP11Session );
+ }
+
+ mbedtls_x509write_csr_free( &xReq );
+ mbedtls_ecdsa_free( &xEcdsaContext );
+ mbedtls_ecp_group_free( &( xEcdsaContext.grp ) );
+ }
+
+ *pxOutCsrLength = strlen( pcCsrBuffer );
+
+ return( ulMbedtlsRet == 0 );
+}
+
+/*-----------------------------------------------------------*/
+
+bool xLoadCertificate( CK_SESSION_HANDLE xP11Session,
+ const char * pcCertificate,
+ const char * pcLabel,
+ size_t xCertificateLength )
+{
+ PKCS11_CertificateTemplate_t xCertificateTemplate;
+ CK_OBJECT_CLASS xCertificateClass = CKO_CERTIFICATE;
+ CK_CERTIFICATE_TYPE xCertificateType = CKC_X_509;
+ CK_FUNCTION_LIST_PTR xFunctionList = NULL;
+ CK_RV xResult = CKR_OK;
+ uint8_t * pucDerObject = NULL;
+ int32_t ulConversion = 0;
+ size_t xDerLen = 0;
+ CK_BBOOL xTokenStorage = CK_TRUE;
+ CK_BYTE pxSubject[] = "TestSubject";
+ CK_OBJECT_HANDLE xObjectHandle = CK_INVALID_HANDLE;
+
+ configASSERT( pcLabel != NULL );
+
+ if( pcCertificate == NULL )
+ {
+ LogError( ( "Certificate cannot be null." ) );
+ xResult = CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+
+ if( xResult == CKR_OK )
+ {
+ /* Convert the certificate to DER format from PEM. The DER key should
+ * be about 3/4 the size of the PEM key, so mallocing the PEM key size
+ * is sufficient. */
+ pucDerObject = ( uint8_t * ) malloc( xCertificateLength + 1 );
+ xDerLen = xCertificateLength + 1;
+
+ if( pucDerObject != NULL )
+ {
+ ulConversion = convert_pem_to_der( ( unsigned char * ) pcCertificate,
+ xCertificateLength + 1,
+ pucDerObject, &xDerLen );
+
+ if( 0 != ulConversion )
+ {
+ LogError( ( "Failed to convert provided certificate." ) );
+ xResult = CKR_ARGUMENTS_BAD;
+ }
+ }
+ else
+ {
+ LogError( ( "Failed to allocate buffer for converting certificate to DER." ) );
+ xResult = CKR_HOST_MEMORY;
+ }
+ }
+
+ if( xResult == CKR_OK )
+ {
+ xResult = C_GetFunctionList( &xFunctionList );
+
+ if( xResult != CKR_OK )
+ {
+ LogError( ( "Could not get a PKCS #11 function pointer." ) );
+ }
+ }
+
+ if( xResult == CKR_OK )
+ {
+ /* Initialize the client certificate template. */
+ xCertificateTemplate.xObjectClass.type = CKA_CLASS;
+ xCertificateTemplate.xObjectClass.pValue = &xCertificateClass;
+ xCertificateTemplate.xObjectClass.ulValueLen = sizeof( xCertificateClass );
+ xCertificateTemplate.xSubject.type = CKA_SUBJECT;
+ xCertificateTemplate.xSubject.pValue = pxSubject;
+ xCertificateTemplate.xSubject.ulValueLen = strlen( ( const char * ) pxSubject );
+ xCertificateTemplate.xValue.type = CKA_VALUE;
+ xCertificateTemplate.xValue.pValue = pucDerObject;
+ xCertificateTemplate.xValue.ulValueLen = xDerLen;
+ xCertificateTemplate.xLabel.type = CKA_LABEL;
+ xCertificateTemplate.xLabel.pValue = ( CK_VOID_PTR ) pcLabel;
+ xCertificateTemplate.xLabel.ulValueLen = strnlen( pcLabel, pkcs11configMAX_LABEL_LENGTH );
+ 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 );
+
+ /* Best effort clean-up of the existing object, if it exists. */
+ prvDestroyProvidedObjects( xP11Session, ( CK_BYTE_PTR * ) &pcLabel, &xCertificateClass, 1 );
+
+ /* Create an object using the encoded client certificate. */
+ LogInfo( ( "Writing certificate into label \"%s\".", pcLabel ) );
+
+ xResult = xFunctionList->C_CreateObject( xP11Session,
+ ( CK_ATTRIBUTE_PTR ) &xCertificateTemplate,
+ sizeof( xCertificateTemplate ) / sizeof( CK_ATTRIBUTE ),
+ &xObjectHandle );
+ }
+
+ if( pucDerObject != NULL )
+ {
+ free( pucDerObject );
+ }
+
+ return( xResult == CKR_OK );
+}
+
+/*-----------------------------------------------------------*/
+
+bool xPkcs11CloseSession( CK_SESSION_HANDLE xP11Session )
+{
+ CK_RV xResult = CKR_OK;
+ CK_FUNCTION_LIST_PTR xFunctionList = NULL;
+
+ xResult = C_GetFunctionList( &xFunctionList );
+
+ if( xResult == CKR_OK )
+ {
+ xResult = xFunctionList->C_CloseSession( xP11Session );
+ }
+
+ if( xResult == CKR_OK )
+ {
+ xResult = xFunctionList->C_Finalize( NULL );
+ }
+
+ return( xResult == CKR_OK );
+}
+
+/*-----------------------------------------------------------*/