1236 lines
35 KiB
C
Executable File
1236 lines
35 KiB
C
Executable File
/*
|
|
* Amazon FreeRTOS PKCS#11 for Windows Simulator V1.0.1
|
|
* Copyright (C) 2017 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.
|
|
*
|
|
* http://aws.amazon.com/freertos
|
|
* http://www.FreeRTOS.org
|
|
*/
|
|
|
|
|
|
/**
|
|
* @file pkcs11.c
|
|
* @brief Windows simulator PKCS#11 implementation for software keys. This
|
|
* file deviates from the FreeRTOS style standard for some function names and
|
|
* data types in order to maintain compliance with the PKCS#11 standard.
|
|
*/
|
|
|
|
/* FreeRTOS includes. */
|
|
#include "FreeRTOS.h"
|
|
#include "FreeRTOSIPConfig.h"
|
|
#include "task.h"
|
|
#include "aws_crypto.h"
|
|
#include "aws_pkcs11.h"
|
|
|
|
#ifndef WOLF_AWSTLS
|
|
|
|
/* mbedTLS includes. */
|
|
#include "mbedtls/pk.h"
|
|
#include "mbedtls/pk_internal.h"
|
|
#include "mbedtls/x509_crt.h"
|
|
#include "mbedtls/ctr_drbg.h"
|
|
#include "mbedtls/entropy.h"
|
|
#include "mbedtls/sha256.h"
|
|
#include "mbedtls/base64.h"
|
|
#include "aws_clientcredential.h"
|
|
|
|
/* C runtime includes. */
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
/**
|
|
* @brief File storage location definitions.
|
|
*/
|
|
#define pkcs11FILE_NAME_CLIENT_CERTIFICATE "FreeRTOS_P11_Certificate.dat"
|
|
#define pkcs11FILE_NAME_KEY "FreeRTOS_P11_Key.dat"
|
|
|
|
/**
|
|
* @brief Cryptoki module attribute definitions.
|
|
*/
|
|
#define pkcs11SLOT_ID 1
|
|
#define pkcs11OBJECT_HANDLE_PUBLIC_KEY 1
|
|
#define pkcs11OBJECT_HANDLE_PRIVATE_KEY 2
|
|
#define pkcs11OBJECT_HANDLE_CERTIFICATE 3
|
|
|
|
#define pkcs11SUPPORTED_KEY_BITS 2048
|
|
|
|
typedef int ( * pfnMbedTlsSign )( void * ctx,
|
|
mbedtls_md_type_t md_alg,
|
|
const unsigned char * hash,
|
|
size_t hash_len,
|
|
unsigned char * sig,
|
|
size_t * sig_len,
|
|
int ( *f_rng )( void *, unsigned char *, size_t ),
|
|
void * p_rng );
|
|
|
|
/**
|
|
* @brief Key structure.
|
|
*/
|
|
typedef struct P11Key
|
|
{
|
|
mbedtls_pk_context xMbedPkCtx;
|
|
mbedtls_x509_crt xMbedX509Cli;
|
|
mbedtls_pk_info_t xMbedPkInfo;
|
|
pfnMbedTlsSign pfnSavedMbedSign;
|
|
void * pvSavedMbedPkCtx;
|
|
} P11Key_t, * P11KeyPtr_t;
|
|
|
|
/**
|
|
* @brief Session structure.
|
|
*/
|
|
typedef struct P11Session
|
|
{
|
|
P11KeyPtr_t pxCurrentKey;
|
|
CK_ULONG ulState;
|
|
CK_BBOOL xOpened;
|
|
CK_BBOOL xFindObjectInit;
|
|
CK_BBOOL xFindObjectComplete;
|
|
CK_OBJECT_CLASS xFindObjectClass;
|
|
mbedtls_ctr_drbg_context xMbedDrbgCtx;
|
|
mbedtls_entropy_context xMbedEntropyContext;
|
|
} P11Session_t, * P11SessionPtr_t;
|
|
|
|
/**
|
|
* @brief Helper definitions.
|
|
*/
|
|
#define pkcs11CREATE_OBJECT_MIN_ATTRIBUTE_COUNT 3
|
|
#define pkcs11CERTIFICATE_ATTRIBUTE_COUNT 3
|
|
#define pkcs11PRIVATE_KEY_ATTRIBUTE_COUNT 4
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Maps an opaque caller session handle into its internal state structure.
|
|
*/
|
|
static P11SessionPtr_t prvSessionPointerFromHandle( CK_SESSION_HANDLE xSession )
|
|
{
|
|
return ( P11SessionPtr_t ) xSession; /*lint !e923 Allow casting integer type to pointer for handle. */
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Writes a file to local storage.
|
|
*/
|
|
static BaseType_t prvSaveFile( char * pcFileName,
|
|
uint8_t * pucData,
|
|
uint32_t ulDataSize )
|
|
{
|
|
uint32_t ulStatus = 0;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD lpNumberOfBytesWritten;
|
|
|
|
/* Open the file. */
|
|
hFile = CreateFileA( pcFileName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if( INVALID_HANDLE_VALUE == hFile )
|
|
{
|
|
ulStatus = GetLastError();
|
|
}
|
|
|
|
/* Write the data. */
|
|
if( ERROR_SUCCESS == ulStatus )
|
|
{
|
|
if( FALSE == WriteFile( hFile, pucData, ulDataSize, &lpNumberOfBytesWritten, NULL ) )
|
|
{
|
|
ulStatus = GetLastError();
|
|
}
|
|
}
|
|
|
|
/* Clean up. */
|
|
if( INVALID_HANDLE_VALUE != hFile )
|
|
{
|
|
CloseHandle( hFile );
|
|
}
|
|
|
|
return 0 == ulStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Reads a file from local storage.
|
|
*/
|
|
static BaseType_t prvReadFile( char * pcFileName,
|
|
uint8_t ** ppucData,
|
|
uint32_t * pulDataSize )
|
|
{
|
|
uint32_t ulStatus = 0;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
uint32_t ulSize = 0;
|
|
|
|
/* Open the file. */
|
|
hFile = CreateFileA( pcFileName,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if( INVALID_HANDLE_VALUE == hFile )
|
|
{
|
|
ulStatus = GetLastError();
|
|
}
|
|
|
|
if( 0 == ulStatus )
|
|
{
|
|
/* Get the file size. */
|
|
*pulDataSize = GetFileSize( hFile, ( LPDWORD ) ( &ulSize ) );
|
|
|
|
/* Create a buffer. */
|
|
*ppucData = pvPortMalloc( *pulDataSize );
|
|
|
|
if( NULL == *ppucData )
|
|
{
|
|
ulStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
/* Read the file. */
|
|
if( 0 == ulStatus )
|
|
{
|
|
if( FALSE == ReadFile( hFile,
|
|
*ppucData,
|
|
*pulDataSize,
|
|
( LPDWORD ) ( &ulSize ),
|
|
NULL ) )
|
|
{
|
|
ulStatus = GetLastError();
|
|
}
|
|
}
|
|
|
|
/* Confirm the amount of data read. */
|
|
if( 0 == ulStatus )
|
|
{
|
|
if( ulSize != *pulDataSize )
|
|
{
|
|
ulStatus = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
/* Clean up. */
|
|
if( INVALID_HANDLE_VALUE != hFile )
|
|
{
|
|
CloseHandle( hFile );
|
|
}
|
|
|
|
return 0 == ulStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Sign a cryptographic hash with the private key.
|
|
*
|
|
* @param[in] pvContext Crypto context.
|
|
* @param[in] xMdAlg Unused.
|
|
* @param[in] pucHash Length in bytes of hash to be signed.
|
|
* @param[in] uiHashLen Byte array of hash to be signed.
|
|
* @param[out] pucSig RSA signature bytes.
|
|
* @param[in] pxSigLen Length in bytes of signature buffer.
|
|
* @param[in] piRng Unused.
|
|
* @param[in] pvRng Unused.
|
|
*
|
|
* @return Zero on success.
|
|
*/
|
|
static int prvPrivateKeySigningCallback( void * pvContext,
|
|
mbedtls_md_type_t xMdAlg,
|
|
const unsigned char * pucHash,
|
|
unsigned int uiHashLen,
|
|
unsigned char * pucSig,
|
|
size_t * pxSigLen,
|
|
int ( *piRng )( void *, unsigned char *, size_t ), /*lint !e955 This parameter is unused. */
|
|
void * pvRng )
|
|
{
|
|
BaseType_t xResult = 0;
|
|
P11SessionPtr_t pxSession = ( P11SessionPtr_t ) pvContext;
|
|
CK_MECHANISM xMech = { 0 };
|
|
|
|
/* Unreferenced parameters. */
|
|
( void ) ( piRng );
|
|
( void ) ( pvRng );
|
|
( void ) ( xMdAlg );
|
|
|
|
/* Use the PKCS#11 module to sign. */
|
|
xMech.mechanism = CKM_SHA256;
|
|
|
|
xResult = ( BaseType_t ) C_SignInit(
|
|
( CK_SESSION_HANDLE ) pxSession,
|
|
&xMech,
|
|
( CK_OBJECT_HANDLE ) pxSession->pxCurrentKey );
|
|
|
|
if( 0 == xResult )
|
|
{
|
|
xResult = ( BaseType_t ) C_Sign(
|
|
( CK_SESSION_HANDLE ) pxSession,
|
|
( CK_BYTE_PTR ) pucHash, /*lint !e9005 The interfaces are from 3rdparty libraries, we are not suppose to change them. */
|
|
uiHashLen,
|
|
pucSig,
|
|
( CK_ULONG_PTR ) pxSigLen );
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Initializes a key structure.
|
|
*/
|
|
static CK_RV prvInitializeKey( P11SessionPtr_t pxSessionObj,
|
|
const char * pcEncodedKey,
|
|
const uint32_t ulEncodedKeyLength,
|
|
const char * pcEncodedCertificate,
|
|
const uint32_t ulEncodedCertificateLength )
|
|
{
|
|
CK_RV xResult = 0;
|
|
|
|
/*
|
|
* Create the key structure, but allow an existing one to be used.
|
|
*/
|
|
|
|
if( NULL == pxSessionObj->pxCurrentKey )
|
|
{
|
|
if( NULL == ( pxSessionObj->pxCurrentKey = ( P11KeyPtr_t ) pvPortMalloc(
|
|
sizeof( P11Key_t ) ) ) ) /*lint !e9087 Allow casting void* to other types. */
|
|
{
|
|
xResult = CKR_HOST_MEMORY;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize the key field, if requested.
|
|
*/
|
|
|
|
if( ( CKR_OK == xResult ) && ( NULL != pcEncodedKey ) )
|
|
{
|
|
memset( pxSessionObj->pxCurrentKey, 0, sizeof( P11Key_t ) );
|
|
mbedtls_pk_init( &pxSessionObj->pxCurrentKey->xMbedPkCtx );
|
|
|
|
if( 0 != mbedtls_pk_parse_key(
|
|
&pxSessionObj->pxCurrentKey->xMbedPkCtx,
|
|
( const unsigned char * ) pcEncodedKey,
|
|
ulEncodedKeyLength,
|
|
NULL,
|
|
0 ) )
|
|
{
|
|
xResult = CKR_FUNCTION_FAILED;
|
|
}
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
/* Swap out the signing function pointer. */
|
|
memcpy(
|
|
&pxSessionObj->pxCurrentKey->xMbedPkInfo,
|
|
pxSessionObj->pxCurrentKey->xMbedPkCtx.pk_info,
|
|
sizeof( pxSessionObj->pxCurrentKey->xMbedPkInfo ) );
|
|
pxSessionObj->pxCurrentKey->pfnSavedMbedSign = pxSessionObj->pxCurrentKey->xMbedPkInfo.sign_func;
|
|
pxSessionObj->pxCurrentKey->xMbedPkInfo.sign_func = prvPrivateKeySigningCallback;
|
|
pxSessionObj->pxCurrentKey->xMbedPkCtx.pk_info = &pxSessionObj->pxCurrentKey->xMbedPkInfo;
|
|
|
|
/* Swap out the underlying internal key context. */
|
|
pxSessionObj->pxCurrentKey->pvSavedMbedPkCtx = pxSessionObj->pxCurrentKey->xMbedPkCtx.pk_ctx;
|
|
pxSessionObj->pxCurrentKey->xMbedPkCtx.pk_ctx = pxSessionObj;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize the certificate field, if requested.
|
|
*/
|
|
|
|
if( ( CKR_OK == xResult ) && ( NULL != pcEncodedCertificate ) )
|
|
{
|
|
mbedtls_x509_crt_init( &pxSessionObj->pxCurrentKey->xMbedX509Cli );
|
|
|
|
if( 0 != mbedtls_x509_crt_parse(
|
|
&pxSessionObj->pxCurrentKey->xMbedX509Cli,
|
|
( const unsigned char * ) pcEncodedCertificate,
|
|
ulEncodedCertificateLength ) )
|
|
{
|
|
xResult = CKR_FUNCTION_FAILED;
|
|
}
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Load the default key and certificate from storage.
|
|
*/
|
|
static CK_RV prvLoadAndInitializeDefaultCertificateAndKey( P11SessionPtr_t pxSession )
|
|
{
|
|
CK_RV xResult = 0;
|
|
uint8_t * pucCertificateData = NULL;
|
|
uint32_t ulCertificateDataLength = 0;
|
|
BaseType_t xFreeCertificate = pdFALSE;
|
|
uint8_t * pucKeyData = NULL;
|
|
uint32_t ulKeyDataLength = 0;
|
|
BaseType_t xFreeKey = pdFALSE;
|
|
|
|
/* Read the certificate from storage. */
|
|
if( pdFALSE == prvReadFile( pkcs11FILE_NAME_CLIENT_CERTIFICATE,
|
|
&pucCertificateData,
|
|
&ulCertificateDataLength ) )
|
|
{
|
|
pucCertificateData = ( uint8_t * ) clientcredentialCLIENT_CERTIFICATE_PEM;
|
|
ulCertificateDataLength = clientcredentialCLIENT_CERTIFICATE_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
xFreeCertificate = pdTRUE;
|
|
}
|
|
|
|
/* Read the private key from storage. */
|
|
if( pdFALSE == prvReadFile( pkcs11FILE_NAME_KEY,
|
|
&pucKeyData,
|
|
&ulKeyDataLength ) )
|
|
{
|
|
pucKeyData = ( uint8_t * ) clientcredentialCLIENT_PRIVATE_KEY_PEM;
|
|
ulKeyDataLength = clientcredentialCLIENT_PRIVATE_KEY_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
xFreeKey = pdTRUE;
|
|
}
|
|
|
|
/* Attach the certificate and key to the session. */
|
|
xResult = prvInitializeKey( pxSession,
|
|
( const char * ) pucKeyData,
|
|
ulKeyDataLength,
|
|
( const char * ) pucCertificateData,
|
|
ulCertificateDataLength );
|
|
|
|
/* Stir the random pot. */
|
|
mbedtls_entropy_update_manual( &pxSession->xMbedEntropyContext,
|
|
pucKeyData,
|
|
ulKeyDataLength );
|
|
mbedtls_entropy_update_manual( &pxSession->xMbedEntropyContext,
|
|
pucCertificateData,
|
|
ulCertificateDataLength );
|
|
|
|
/* Clean-up. */
|
|
if( ( NULL != pucCertificateData ) && ( pdTRUE == xFreeCertificate ) )
|
|
{
|
|
vPortFree( pucCertificateData );
|
|
}
|
|
|
|
if( ( NULL != pucKeyData ) && ( pdTRUE == xFreeKey ) )
|
|
{
|
|
vPortFree( pucKeyData );
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Cleans up a key structure.
|
|
*/
|
|
static void prvFreeKey( P11KeyPtr_t pxKey )
|
|
{
|
|
if( NULL != pxKey )
|
|
{
|
|
/* Restore the internal key context. */
|
|
pxKey->xMbedPkCtx.pk_ctx = pxKey->pvSavedMbedPkCtx;
|
|
|
|
/* Clean-up. */
|
|
mbedtls_pk_free( &pxKey->xMbedPkCtx );
|
|
mbedtls_x509_crt_free( &pxKey->xMbedX509Cli );
|
|
vPortFree( pxKey );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/*
|
|
* PKCS#11 module implementation.
|
|
*/
|
|
|
|
/**
|
|
* @brief PKCS#11 interface functions implemented by this Cryptoki module.
|
|
*/
|
|
static CK_FUNCTION_LIST prvP11FunctionList =
|
|
{
|
|
{ CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
|
|
C_Initialize,
|
|
C_Finalize,
|
|
NULL,
|
|
C_GetFunctionList,
|
|
C_GetSlotList,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
C_OpenSession,
|
|
C_CloseSession,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
C_CreateObject,
|
|
NULL,
|
|
C_DestroyObject,
|
|
NULL,
|
|
C_GetAttributeValue,
|
|
NULL,
|
|
C_FindObjectsInit,
|
|
C_FindObjects,
|
|
C_FindObjectsFinal,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
C_SignInit,
|
|
C_Sign,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
C_VerifyInit,
|
|
C_Verify,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
C_GenerateRandom,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/**
|
|
* @brief Initialize the Cryptoki module for use.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_Initialize )( CK_VOID_PTR pvInitArgs )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
( void ) ( pvInitArgs );
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Un-initialize the Cryptoki module.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_Finalize )( CK_VOID_PTR pvReserved )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
( void ) ( pvReserved );
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Query the list of interface function pointers.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_GetFunctionList )( CK_FUNCTION_LIST_PTR_PTR ppxFunctionList )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
*ppxFunctionList = &prvP11FunctionList;
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Query the list of slots. A single default slot is implemented.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_GetSlotList )( CK_BBOOL xTokenPresent,
|
|
CK_SLOT_ID_PTR pxSlotList,
|
|
CK_ULONG_PTR pulCount )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
( void ) ( xTokenPresent );
|
|
|
|
if( NULL == pxSlotList )
|
|
{
|
|
*pulCount = 1;
|
|
}
|
|
else
|
|
{
|
|
if( 0u == *pulCount )
|
|
{
|
|
return CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
pxSlotList[ 0 ] = pkcs11SLOT_ID;
|
|
*pulCount = 1;
|
|
}
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Start a session for a cryptographic command sequence.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_OpenSession )( CK_SLOT_ID xSlotID,
|
|
CK_FLAGS xFlags,
|
|
CK_VOID_PTR pvApplication,
|
|
CK_NOTIFY xNotify,
|
|
CK_SESSION_HANDLE_PTR pxSession )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
CK_RV xResult = CKR_OK;
|
|
P11SessionPtr_t pxSessionObj = NULL;
|
|
|
|
( void ) ( xSlotID );
|
|
( void ) ( pvApplication );
|
|
( void ) ( xNotify );
|
|
|
|
/*
|
|
* Make space for the context.
|
|
*/
|
|
if( NULL == ( pxSessionObj = ( P11SessionPtr_t ) pvPortMalloc( sizeof( P11Session_t ) ) ) ) /*lint !e9087 Allow casting void* to other types. */
|
|
{
|
|
xResult = CKR_HOST_MEMORY;
|
|
}
|
|
|
|
/*
|
|
* Assume that there's no performance tradeoff in loading the default key
|
|
* now, since that's the principal use case for opening a session in this
|
|
* provider anyway. This way, the private key can be used for seeding the RNG,
|
|
* especially if there's no hardware-based alternative.
|
|
*/
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
memset( pxSessionObj, 0, sizeof( P11Session_t ) );
|
|
xResult = prvLoadAndInitializeDefaultCertificateAndKey( pxSessionObj );
|
|
}
|
|
|
|
/*
|
|
* Initialize RNG.
|
|
*/
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
memset( &pxSessionObj->xMbedEntropyContext,
|
|
0,
|
|
sizeof( pxSessionObj->xMbedEntropyContext ) );
|
|
|
|
mbedtls_entropy_init( &pxSessionObj->xMbedEntropyContext );
|
|
}
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
mbedtls_ctr_drbg_init( &pxSessionObj->xMbedDrbgCtx );
|
|
|
|
if( 0 != mbedtls_ctr_drbg_seed( &pxSessionObj->xMbedDrbgCtx,
|
|
mbedtls_entropy_func,
|
|
&pxSessionObj->xMbedEntropyContext,
|
|
NULL,
|
|
0 ) )
|
|
{
|
|
xResult = CKR_FUNCTION_FAILED;
|
|
}
|
|
}
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
/*
|
|
* Assign the session.
|
|
*/
|
|
|
|
pxSessionObj->ulState =
|
|
0u != ( xFlags & CKF_RW_SESSION ) ? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION;
|
|
pxSessionObj->xOpened = CK_TRUE;
|
|
|
|
/*
|
|
* Return the session.
|
|
*/
|
|
|
|
*pxSession = ( CK_SESSION_HANDLE ) pxSessionObj; /*lint !e923 Allow casting pointer to integer type for handle. */
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/**
|
|
* @brief Terminate a session and release resources.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_CloseSession )( CK_SESSION_HANDLE xSession )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
CK_RV xResult = CKR_OK;
|
|
P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession );
|
|
|
|
if( NULL != pxSession )
|
|
{
|
|
/*
|
|
* Tear down the session.
|
|
*/
|
|
|
|
if( NULL != pxSession->pxCurrentKey )
|
|
{
|
|
prvFreeKey( pxSession->pxCurrentKey );
|
|
}
|
|
|
|
mbedtls_ctr_drbg_free( &pxSession->xMbedDrbgCtx );
|
|
vPortFree( pxSession );
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/**
|
|
* @brief Provides import and storage of a single client certificate and
|
|
* associated private key.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_CreateObject )( CK_SESSION_HANDLE xSession,
|
|
CK_ATTRIBUTE_PTR pxTemplate,
|
|
CK_ULONG ulCount,
|
|
CK_OBJECT_HANDLE_PTR pxObject )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
CK_RV xResult = CKR_OK;
|
|
|
|
( void )( xSession );
|
|
|
|
/*
|
|
* Check parameters.
|
|
*/
|
|
if( ( pkcs11CREATE_OBJECT_MIN_ATTRIBUTE_COUNT > ulCount ) ||
|
|
( NULL == pxTemplate ) ||
|
|
( NULL == pxObject ) )
|
|
{
|
|
xResult = CKR_ARGUMENTS_BAD;
|
|
}
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
if( ( CKA_CLASS != pxTemplate[ 0 ].type ) ||
|
|
( sizeof( CK_OBJECT_CLASS ) != pxTemplate[ 0 ].ulValueLen ) )
|
|
{
|
|
xResult = CKR_ARGUMENTS_BAD;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle the object by class.
|
|
*/
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
switch( *( ( uint32_t * ) pxTemplate[ 0 ].pValue ) )
|
|
{
|
|
case CKO_CERTIFICATE:
|
|
|
|
/* Validate the attribute count for this object class. */
|
|
if( pkcs11CERTIFICATE_ATTRIBUTE_COUNT != ulCount )
|
|
{
|
|
xResult = CKR_ARGUMENTS_BAD;
|
|
break;
|
|
}
|
|
|
|
/* Validate the next attribute type. */
|
|
if( CKA_VALUE )
|
|
{
|
|
if( CKA_VALUE != pxTemplate[ 1 ].type )
|
|
{
|
|
xResult = CKR_ARGUMENTS_BAD;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( *( ( uint32_t * )pxTemplate[ 2 ].pValue ) == pkcs11CERTIFICATE_TYPE_USER )
|
|
{
|
|
/* Write out the client certificate. */
|
|
if( pdFALSE == prvSaveFile( pkcs11FILE_NAME_CLIENT_CERTIFICATE,
|
|
pxTemplate[ 1 ].pValue,
|
|
pxTemplate[ 1 ].ulValueLen ) )
|
|
{
|
|
xResult = CKR_DEVICE_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
else if( *( ( uint32_t * )pxTemplate[ 2 ].pValue ) == pkcs11CERTIFICATE_TYPE_ROOT )
|
|
{
|
|
/* Ignore writing the default root certificate. */
|
|
}
|
|
break;
|
|
|
|
case CKO_PRIVATE_KEY:
|
|
|
|
/* Validate the attribute count for this object class. */
|
|
if( pkcs11PRIVATE_KEY_ATTRIBUTE_COUNT != ulCount )
|
|
{
|
|
xResult = CKR_ARGUMENTS_BAD;
|
|
break;
|
|
}
|
|
|
|
/* Find the key bytes. */
|
|
if( CKA_VALUE )
|
|
{
|
|
if( CKA_VALUE != pxTemplate[ 3 ].type )
|
|
{
|
|
xResult = CKR_ARGUMENTS_BAD;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Write out the key. */
|
|
if( pdFALSE == prvSaveFile( pkcs11FILE_NAME_KEY,
|
|
pxTemplate[ 3 ].pValue,
|
|
pxTemplate[ 3 ].ulValueLen ) )
|
|
{
|
|
xResult = CKR_DEVICE_ERROR;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
xResult = CKR_ARGUMENTS_BAD;
|
|
}
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/**
|
|
* @brief Free resources attached to an object handle.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_DestroyObject )( CK_SESSION_HANDLE xSession,
|
|
CK_OBJECT_HANDLE xObject )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
( void ) ( xSession );
|
|
( void ) ( xObject );
|
|
|
|
/*
|
|
* This implementation uses virtual handles, and the certificate and
|
|
* private key data are attached to the session, so nothing to do here.
|
|
*/
|
|
return CKR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Query the value of the specified cryptographic object attribute.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_GetAttributeValue )( CK_SESSION_HANDLE xSession,
|
|
CK_OBJECT_HANDLE xObject,
|
|
CK_ATTRIBUTE_PTR pxTemplate,
|
|
CK_ULONG ulCount )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
CK_RV xResult = CKR_OK;
|
|
P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession );
|
|
CK_VOID_PTR pvAttr = NULL;
|
|
CK_ULONG ulAttrLength = 0;
|
|
mbedtls_pk_type_t xMbedPkType;
|
|
CK_ULONG xP11KeyType, iAttrib, xKeyBitLen;
|
|
|
|
( void ) ( xObject );
|
|
|
|
/*
|
|
* Enumerate the requested attributes.
|
|
*/
|
|
|
|
for( iAttrib = 0; iAttrib < ulCount && CKR_OK == xResult; iAttrib++ )
|
|
{
|
|
/*
|
|
* Get the attribute data and size.
|
|
*/
|
|
|
|
switch( pxTemplate[ iAttrib ].type )
|
|
{
|
|
case CKA_KEY_TYPE:
|
|
|
|
/*
|
|
* Map the private key type between APIs.
|
|
*/
|
|
xMbedPkType = mbedtls_pk_get_type( &pxSession->pxCurrentKey->xMbedPkCtx );
|
|
|
|
switch( xMbedPkType )
|
|
{
|
|
case MBEDTLS_PK_RSA:
|
|
case MBEDTLS_PK_RSA_ALT:
|
|
case MBEDTLS_PK_RSASSA_PSS:
|
|
xP11KeyType = CKK_RSA;
|
|
break;
|
|
|
|
case MBEDTLS_PK_ECKEY:
|
|
case MBEDTLS_PK_ECKEY_DH:
|
|
xP11KeyType = CKK_EC;
|
|
break;
|
|
|
|
case MBEDTLS_PK_ECDSA:
|
|
xP11KeyType = CKK_ECDSA;
|
|
break;
|
|
|
|
default:
|
|
xResult = CKR_ATTRIBUTE_VALUE_INVALID;
|
|
break;
|
|
}
|
|
|
|
ulAttrLength = sizeof( xP11KeyType );
|
|
pvAttr = &xP11KeyType;
|
|
break;
|
|
|
|
case CKA_VALUE:
|
|
|
|
/*
|
|
* Assume that the query is for the encoded client certificate.
|
|
*/
|
|
pvAttr = ( CK_VOID_PTR ) pxSession->pxCurrentKey->xMbedX509Cli.raw.p; /*lint !e9005 !e9087 Allow casting other types to void*. */
|
|
ulAttrLength = pxSession->pxCurrentKey->xMbedX509Cli.raw.len;
|
|
break;
|
|
|
|
case CKA_MODULUS_BITS:
|
|
case CKA_PRIME_BITS:
|
|
|
|
/*
|
|
* Key strength size query, handled the same for RSA or ECDSA
|
|
* in this port.
|
|
*/
|
|
xKeyBitLen = mbedtls_pk_get_bitlen(
|
|
&pxSession->pxCurrentKey->xMbedPkCtx );
|
|
ulAttrLength = sizeof( xKeyBitLen );
|
|
pvAttr = &xKeyBitLen;
|
|
break;
|
|
|
|
case CKA_VENDOR_DEFINED:
|
|
|
|
/*
|
|
* Return the key context for application-layer use.
|
|
*/
|
|
ulAttrLength = sizeof( pxSession->pxCurrentKey->xMbedPkCtx );
|
|
pvAttr = &pxSession->pxCurrentKey->xMbedPkCtx;
|
|
break;
|
|
|
|
default:
|
|
xResult = CKR_ATTRIBUTE_TYPE_INVALID;
|
|
break;
|
|
}
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
/*
|
|
* Copy out the data and size.
|
|
*/
|
|
|
|
if( NULL != pxTemplate[ iAttrib ].pValue )
|
|
{
|
|
if( pxTemplate[ iAttrib ].ulValueLen < ulAttrLength )
|
|
{
|
|
xResult = CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
memcpy( pxTemplate[ iAttrib ].pValue, pvAttr, ulAttrLength );
|
|
}
|
|
}
|
|
|
|
pxTemplate[ iAttrib ].ulValueLen = ulAttrLength;
|
|
}
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/**
|
|
* @brief Begin an enumeration sequence for the objects of the specified type.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_FindObjectsInit )( CK_SESSION_HANDLE xSession,
|
|
CK_ATTRIBUTE_PTR pxTemplate,
|
|
CK_ULONG ulCount )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession );
|
|
|
|
( void ) ( ulCount );
|
|
|
|
/*
|
|
* Allow filtering on a single object class attribute.
|
|
*/
|
|
|
|
pxSession->xFindObjectInit = CK_TRUE;
|
|
pxSession->xFindObjectComplete = CK_FALSE;
|
|
memcpy( &pxSession->xFindObjectClass,
|
|
pxTemplate[ 0 ].pValue,
|
|
sizeof( CK_OBJECT_CLASS ) );
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Query the objects of the requested type.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_FindObjects )( CK_SESSION_HANDLE xSession,
|
|
CK_OBJECT_HANDLE_PTR pxObject,
|
|
CK_ULONG ulMaxObjectCount,
|
|
CK_ULONG_PTR pulObjectCount )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
CK_RV xResult = CKR_OK;
|
|
BaseType_t xDone = pdFALSE;
|
|
P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession );
|
|
|
|
/*
|
|
* Check parameters.
|
|
*/
|
|
|
|
if( ( CK_BBOOL ) CK_FALSE == pxSession->xFindObjectInit )
|
|
{
|
|
xResult = CKR_OPERATION_NOT_INITIALIZED;
|
|
xDone = pdTRUE;
|
|
}
|
|
|
|
if( ( pdFALSE == xDone ) && ( 0u == ulMaxObjectCount ) )
|
|
{
|
|
xResult = CKR_ARGUMENTS_BAD;
|
|
xDone = pdTRUE;
|
|
}
|
|
|
|
if( ( pdFALSE == xDone ) && ( ( CK_BBOOL ) CK_TRUE == pxSession->xFindObjectComplete ) )
|
|
{
|
|
*pulObjectCount = 0;
|
|
xResult = CKR_OK;
|
|
xDone = pdTRUE;
|
|
}
|
|
|
|
/*
|
|
* Load the default private key and certificate.
|
|
*/
|
|
|
|
if( ( pdFALSE == xDone ) && ( NULL == pxSession->pxCurrentKey ) )
|
|
{
|
|
if( CKR_OK != ( xResult = prvLoadAndInitializeDefaultCertificateAndKey( pxSession ) ) )
|
|
{
|
|
xDone = pdTRUE;
|
|
}
|
|
}
|
|
|
|
if( pdFALSE == xDone )
|
|
{
|
|
/*
|
|
* Return object handles based on find type.
|
|
*/
|
|
|
|
switch( pxSession->xFindObjectClass )
|
|
{
|
|
case CKO_PRIVATE_KEY:
|
|
*pxObject = pkcs11OBJECT_HANDLE_PRIVATE_KEY;
|
|
*pulObjectCount = 1;
|
|
break;
|
|
|
|
case CKO_PUBLIC_KEY:
|
|
*pxObject = pkcs11OBJECT_HANDLE_PUBLIC_KEY;
|
|
*pulObjectCount = 1;
|
|
break;
|
|
|
|
case CKO_CERTIFICATE:
|
|
*pxObject = pkcs11OBJECT_HANDLE_CERTIFICATE;
|
|
*pulObjectCount = 1;
|
|
break;
|
|
|
|
default:
|
|
*pxObject = 0;
|
|
*pulObjectCount = 0;
|
|
break;
|
|
}
|
|
|
|
pxSession->xFindObjectComplete = CK_TRUE;
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/**
|
|
* @brief Terminate object enumeration.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_FindObjectsFinal )( CK_SESSION_HANDLE xSession )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
CK_RV xResult = CKR_OK;
|
|
P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession );
|
|
|
|
/*
|
|
* Check parameters.
|
|
*/
|
|
|
|
if( ( CK_BBOOL ) CK_FALSE == pxSession->xFindObjectInit )
|
|
{
|
|
xResult = CKR_OPERATION_NOT_INITIALIZED;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Clean-up find objects state.
|
|
*/
|
|
|
|
pxSession->xFindObjectInit = CK_FALSE;
|
|
pxSession->xFindObjectComplete = CK_FALSE;
|
|
pxSession->xFindObjectClass = 0;
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/**
|
|
* @brief Begin a digital signature generation session.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_SignInit )( CK_SESSION_HANDLE xSession,
|
|
CK_MECHANISM_PTR pxMechanism,
|
|
CK_OBJECT_HANDLE xKey )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
( void ) ( xSession );
|
|
( void ) ( pxMechanism );
|
|
( void ) ( xKey );
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Digitally sign the indicated cryptographic hash bytes.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_Sign )( CK_SESSION_HANDLE xSession,
|
|
CK_BYTE_PTR pucData,
|
|
CK_ULONG ulDataLen,
|
|
CK_BYTE_PTR pucSignature,
|
|
CK_ULONG_PTR pulSignatureLen )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
CK_RV xResult = CKR_OK;
|
|
P11SessionPtr_t pxSessionObj = prvSessionPointerFromHandle( xSession );
|
|
|
|
/*
|
|
* Support length check.
|
|
*/
|
|
|
|
if( NULL == pucSignature )
|
|
{
|
|
*pulSignatureLen = pkcs11SUPPORTED_KEY_BITS / 8;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Check algorithm support.
|
|
*/
|
|
|
|
if( ( CK_ULONG ) cryptoSHA256_DIGEST_BYTES != ulDataLen )
|
|
{
|
|
xResult = CKR_DATA_LEN_RANGE;
|
|
}
|
|
|
|
/*
|
|
* Sign the data.
|
|
*/
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
if( 0 != pxSessionObj->pxCurrentKey->pfnSavedMbedSign(
|
|
pxSessionObj->pxCurrentKey->pvSavedMbedPkCtx,
|
|
MBEDTLS_MD_SHA256,
|
|
pucData,
|
|
ulDataLen,
|
|
pucSignature,
|
|
( size_t * ) pulSignatureLen,
|
|
mbedtls_ctr_drbg_random,
|
|
&pxSessionObj->xMbedDrbgCtx ) )
|
|
{
|
|
xResult = CKR_FUNCTION_FAILED;
|
|
}
|
|
}
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/**
|
|
* @brief Begin a digital signature verification session.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_VerifyInit )( CK_SESSION_HANDLE xSession,
|
|
CK_MECHANISM_PTR pxMechanism,
|
|
CK_OBJECT_HANDLE xKey )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
( void ) ( xSession );
|
|
( void ) ( pxMechanism );
|
|
( void ) ( xKey );
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Verify the digital signature of the specified data using the public
|
|
* key attached to this session.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_Verify )( CK_SESSION_HANDLE xSession,
|
|
CK_BYTE_PTR pucData,
|
|
CK_ULONG ulDataLen,
|
|
CK_BYTE_PTR pucSignature,
|
|
CK_ULONG ulSignatureLen )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
CK_RV xResult = CKR_OK;
|
|
P11SessionPtr_t pxSessionObj = prvSessionPointerFromHandle( xSession );
|
|
|
|
/* Verify the signature. */
|
|
if( 0 != pxSessionObj->pxCurrentKey->xMbedPkInfo.verify_func(
|
|
pxSessionObj->pxCurrentKey->pvSavedMbedPkCtx,
|
|
MBEDTLS_MD_SHA256,
|
|
pucData,
|
|
ulDataLen,
|
|
pucSignature,
|
|
ulSignatureLen ) )
|
|
{
|
|
xResult = CKR_SIGNATURE_INVALID;
|
|
}
|
|
|
|
/* Return the signature verification result. */
|
|
return xResult;
|
|
}
|
|
|
|
/**
|
|
* @brief Generate cryptographically random bytes.
|
|
*/
|
|
CK_DEFINE_FUNCTION( CK_RV, C_GenerateRandom )( CK_SESSION_HANDLE xSession,
|
|
CK_BYTE_PTR pucRandomData,
|
|
CK_ULONG ulRandomLen )
|
|
{ /*lint !e9072 It's OK to have different parameter name. */
|
|
P11SessionPtr_t pxSessionObj = prvSessionPointerFromHandle( xSession );
|
|
|
|
if( 0 != mbedtls_ctr_drbg_random( &pxSessionObj->xMbedDrbgCtx, pucRandomData, ulRandomLen ) )
|
|
{
|
|
return CKR_FUNCTION_FAILED;
|
|
}
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
#endif /* !#ifndef WOLF_AWSTLS */
|