wolfssl-freertos/FreeRTOS-AWS/lib/pkcs11/portable/pc/windows/wolf_pkcs11.c

1479 lines
39 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 wolf_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"
#ifdef WOLF_AWSTLS
/* wolfSSL library (github.com/wolfSSL/wolfssl) */
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/sha.h>
#include <wolfssl/wolfcrypt/asn_public.h>
#include <wolfssl/wolfcrypt/coding.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/rsa.h>
#include <wolfssl/wolfcrypt/error-crypt.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
#define DER_TMP_BUFFER_LEN 2048
typedef enum {
WOLFSSL_PK_NONE = 0,
WOLFSSL_PK_RSA,
WOLFSSL_PK_RSASSA_PSS,
WOLFSSL_PK_ECKEY,
WOLFSSL_PK_ECKEY_DH,
WOLFSSL_PK_ECDSA,
} wolfSSL_pk_type_t;
typedef struct wolfSSL_pk_context {
union {
#ifndef NO_RSA
RsaKey rsa;
#endif
#ifdef HAVE_ECC
ecc_key ecc;
#endif
void* ptr;
} key;
int type; /* wolfSSL_pk_type_t */
int keyBits;
byte* der;
word32 derLen;
} wolfSSL_pk_context;
void wolfSSL_pk_init( wolfSSL_pk_context *pk )
{
if (pk) {
XMEMSET(pk, 0, sizeof(*pk));
}
}
wolfSSL_pk_type_t wolfSSL_pk_get_type( const wolfSSL_pk_context *pk )
{
if (pk)
return pk->type;
return WOLFSSL_PK_NONE;
}
size_t wolfSSL_pk_get_bitlen( const wolfSSL_pk_context *pk )
{
if (pk)
return pk->keyBits;
return 0;
}
void* wolfSSL_pk_get_key( const wolfSSL_pk_context *pk )
{
if (pk)
return pk->key.ptr;
return NULL;
}
int wolfSSL_pk_get_key_der( const wolfSSL_pk_context *pk, byte* der, word32* derLen )
{
int ret = -1;
if (pk && der && derLen) {
if (*derLen >= pk->derLen)
return BUFFER_E;
memcpy(der, pk->der, pk->derLen);
*derLen = pk->derLen;
ret = 0;
}
return ret;
}
void wolfSSL_pk_key_free( wolfSSL_pk_context *pk )
{
/* cleanup keys */
switch (pk->type) {
case WOLFSSL_PK_RSA:
case WOLFSSL_PK_RSASSA_PSS:
#ifndef NO_RSA
wc_FreeRsaKey(&pk->key.rsa);
#endif
break;
case WOLFSSL_PK_ECKEY:
case WOLFSSL_PK_ECKEY_DH:
case WOLFSSL_PK_ECDSA:
#ifdef HAVE_ECC
wc_ecc_free(&pk->key.ecc);
#endif
break;
}
}
int wolfSSL_pk_create_key(wolfSSL_pk_context *pk,
const unsigned char *der, size_t derlen)
{
int ret = -1;
word32 idx = 0;
switch (pk->type) {
case WOLFSSL_PK_RSA:
case WOLFSSL_PK_RSASSA_PSS:
#ifndef NO_RSA
ret = wc_InitRsaKey(&pk->key.rsa, NULL);
if (ret == 0) {
ret = wc_RsaPrivateKeyDecode(der, &idx, &pk->key.rsa, derlen);
if (ret == 0) {
/* get key size */
ret = wc_RsaEncryptSize(&pk->key.rsa);
if (ret > 0) {
pk->keyBits = ret * 8;
ret = 0;
}
else {
ret = -1;
}
}
else {
wolfSSL_pk_key_free(pk);
}
}
#endif
break;
case WOLFSSL_PK_ECKEY:
case WOLFSSL_PK_ECKEY_DH:
case WOLFSSL_PK_ECDSA:
#ifdef HAVE_ECC
ret = wc_ecc_init(&pk->key.ecc);
if (ret == 0) {
ret = wc_EccPrivateKeyDecode(der, &idx, &pk->key.ecc, derlen);
if (ret == 0) {
/* get key size */
ret = wc_ecc_size(&pk->key.ecc);
if (ret > 0) {
pk->keyBits = ret * 8;
ret = 0;
}
else {
ret = -1;
}
}
else {
wolfSSL_pk_key_free(pk);
}
}
#endif
break;
}
return ret;
}
int wolfSSL_pk_parse_key( wolfSSL_pk_context *pk,
const unsigned char *key, size_t keylen,
const unsigned char *pwd, size_t pwdlen )
{
int ret, derLen;
byte derTmp[DER_TMP_BUFFER_LEN];
byte* der = derTmp;
(void)pwdlen;
if (pk == NULL || key == NULL || keylen <= 0)
return -1;
/* convert PEM to der */
ret = wc_KeyPemToDer(key, keylen, der, sizeof(derTmp), (const char*)pwd);
if (ret <= 0) {
/* try using it directly */
der = (byte*)key;
derLen = keylen;
}
else {
derLen = ret;
}
pk->derLen = derLen;
pk->der = (byte*)pvPortMalloc(derLen);
if (pk->der) {
memcpy(pk->der, der, derLen);
}
/* try RSA */
pk->type = WOLFSSL_PK_RSA;
ret = wolfSSL_pk_create_key(pk, der, derLen);
if (ret != 0) {
/* try ECC */
pk->type = WOLFSSL_PK_ECDSA;
ret = wolfSSL_pk_create_key(pk, der, derLen);
}
return ret;
}
int wolfSSL_pk_sign(wolfSSL_pk_context *pk,
int hashType, int mgf,
const unsigned char * pucHash,
unsigned int uiHashLen,
unsigned char * pucSig,
size_t * pxSigLen,
WC_RNG* pRng)
{
int ret = -1;
switch (pk->type) {
#ifndef NO_RSA
case WOLFSSL_PK_RSA:
#ifdef WC_RSA_PSS
case WOLFSSL_PK_RSASSA_PSS:
#endif
{
if (pk->type == WOLFSSL_PK_RSA)
ret = wc_RsaSSL_Sign(pucHash, uiHashLen, pucSig, *pxSigLen,
&pk->key.rsa, pRng);
#ifdef WC_RSA_PSS
else
ret = wc_RsaPSS_Sign(pucHash, uiHashLen, pucSig, *pxSigLen,
(enum wc_HashType)hashType, mgf, &pk->key.rsa, pRng);
#endif
if (ret > 0) {
*pxSigLen = ret;
ret = 0;
}
else {
ret = CKR_SIGNATURE_LEN_RANGE;
}
break;
}
#endif /* !NO_RSA */
#ifdef HAVE_ECC
case WOLFSSL_PK_ECKEY:
case WOLFSSL_PK_ECKEY_DH:
case WOLFSSL_PK_ECDSA:
ret = wc_ecc_sign_hash(pucHash, uiHashLen, pucSig, pxSigLen, pRng, &pk->key.ecc);
break;
#endif /* HAVE_ECC */
default:
break;
}
(void)pk;
(void)hashType;
(void)pucHash;
(void)uiHashLen;
(void)pucSig;
(void)pxSigLen;
(void)pRng;
return ret;
}
int wolfSSL_pk_verify(wolfSSL_pk_context *pk,
int hashType, int mgf,
const unsigned char * pucHash,
unsigned int uiHashLen,
const unsigned char * pucSig,
size_t ulSigLen)
{
int ret = -1;
switch (pk->type) {
#ifndef NO_RSA
case WOLFSSL_PK_RSA:
#ifdef WC_RSA_PSS
case WOLFSSL_PK_RSASSA_PSS:
#endif
{
byte* plain = pvPortMalloc(ulSigLen);
if (plain == NULL)
return CKR_HOST_MEMORY;
if (pk->type == WOLFSSL_PK_RSA)
ret = wc_RsaSSL_Verify(pucHash, uiHashLen, plain, ulSigLen,
&pk->key.rsa);
#ifdef WC_RSA_PSS
else
ret = wc_RsaPSS_Verify((byte*)pucHash, uiHashLen, plain, ulSigLen,
(enum wc_HashType)hashType, mgf, &pk->key.rsa);
#endif
if ((int)ulSigLen == ret &&
XMEMCMP(pucSig, plain, ret) == 0) {
ret = CKR_OK;
}
else {
ret = CKR_SIGNATURE_INVALID;
}
vPortFree(plain);
break;
}
#endif /* !NO_RSA */
#ifdef HAVE_ECC
case WOLFSSL_PK_ECKEY:
case WOLFSSL_PK_ECKEY_DH:
case WOLFSSL_PK_ECDSA:
{
int verify = 0;
ret = wc_ecc_verify_hash(pucSig, ulSigLen, pucHash, uiHashLen,
&verify, &pk->key.ecc);
if (ret == 0 && verify == 1) {
ret = CKR_OK;
}
else {
ret = CKR_SIGNATURE_INVALID;
}
break;
}
#endif /* HAVE_ECC */
default:
break;
}
(void)pk;
(void)hashType;
(void)pucHash;
(void)uiHashLen;
(void)pucSig;
(void)ulSigLen;
return ret;
}
void wolfSSL_pk_free( wolfSSL_pk_context *pk )
{
if (pk == NULL)
return;
/* cleanup keys */
wolfSSL_pk_key_free(pk);
if (pk->der) {
vPortFree(pk->der);
pk->der = NULL;
}
}
/**
* @brief Key structure.
*/
typedef struct P11Key
{
wolfSSL_pk_context xWolfPkCtx;
WOLFSSL_X509* xWolfX509Cli;
} 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;
WC_RNG xWolfDrbgCtx;
} 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 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 ) );
wolfSSL_pk_init( &pxSessionObj->pxCurrentKey->xWolfPkCtx );
xResult = wolfSSL_pk_parse_key(
&pxSessionObj->pxCurrentKey->xWolfPkCtx,
( const unsigned char * ) pcEncodedKey,
ulEncodedKeyLength,
NULL,
0 );
if (xResult != 0) {
xResult = CKR_FUNCTION_FAILED;
}
}
/*
* Initialize the certificate field, if requested.
*/
if( ( CKR_OK == xResult ) && ( NULL != pcEncodedCertificate ) )
{
pxSessionObj->pxCurrentKey->xWolfX509Cli =
wolfSSL_X509_load_certificate_buffer(
(const unsigned char *)pcEncodedCertificate,
ulEncodedCertificateLength,
WOLFSSL_FILETYPE_PEM);
if (pxSessionObj->pxCurrentKey->xWolfX509Cli == NULL) {
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;
}
/* handle cert including null term */
if (pucCertificateData[ulCertificateDataLength-1] == '\0')
ulCertificateDataLength--;
/* 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;
}
/* handle key including null term */
if (pucKeyData[ulKeyDataLength-1] == '\0')
ulKeyDataLength--;
/* Attach the certificate and key to the session. */
xResult = prvInitializeKey( pxSession,
( const char * ) pucKeyData,
ulKeyDataLength,
( const char * ) 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 )
{
/* Clean-up. */
wolfSSL_pk_free( &pxKey->xWolfPkCtx );
wolfSSL_X509_free(pxKey->xWolfX509Cli);
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 )
{
xResult = wc_InitRng( &pxSessionObj->xWolfDrbgCtx );
if (xResult != 0)
xResult = CKR_RANDOM_NO_RNG;
}
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 );
}
wc_FreeRng( &pxSession->xWolfDrbgCtx );
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;
wolfSSL_pk_type_t xWolfPkType;
CK_ULONG xP11KeyType, iAttrib, xKeyBitLen;
vedCliKey cliKey;
( 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.
*/
xWolfPkType = wolfSSL_pk_get_type( &pxSession->pxCurrentKey->xWolfPkCtx );
switch( xWolfPkType )
{
case WOLFSSL_PK_RSA:
case WOLFSSL_PK_RSASSA_PSS:
xP11KeyType = CKK_RSA;
break;
case WOLFSSL_PK_ECKEY:
case WOLFSSL_PK_ECKEY_DH:
xP11KeyType = CKK_EC;
break;
case WOLFSSL_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.
*/
int derLen = 0;
pvAttr = ( CK_VOID_PTR )wolfSSL_X509_get_der(
pxSession->pxCurrentKey->xWolfX509Cli, &derLen);
ulAttrLength = derLen;
break;
}
case CKA_MODULUS_BITS:
case CKA_PRIME_BITS:
/*
* Key strength size query, handled the same for RSA or ECDSA
* in this port.
*/
xKeyBitLen = wolfSSL_pk_get_bitlen(
&pxSession->pxCurrentKey->xWolfPkCtx );
ulAttrLength = sizeof( xKeyBitLen );
pvAttr = &xKeyBitLen;
break;
case CKA_VENDOR_DEFINED:
{
/*
* Return the key context for application-layer use.
*/
memset(&cliKey, 0, sizeof(cliKey));
cliKey.der = pxSession->pxCurrentKey->xWolfPkCtx.der;
cliKey.derLen = pxSession->pxCurrentKey->xWolfPkCtx.derLen;
ulAttrLength = sizeof(cliKey);
pvAttr = &cliKey;
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 != wolfSSL_pk_sign(
&pxSessionObj->pxCurrentKey->xWolfPkCtx,
WC_HASH_TYPE_SHA256, WC_MGF1SHA256,
pucData,
ulDataLen,
pucSignature,
( size_t * ) pulSignatureLen,
&pxSessionObj->xWolfDrbgCtx ) )
{
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 != wolfSSL_pk_verify(
&pxSessionObj->pxCurrentKey->xWolfPkCtx,
WC_HASH_TYPE_SHA256, WC_MGF1SHA256,
pucData,
ulDataLen,
pucSignature,
( size_t ) 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 != wc_RNG_GenerateBlock( &pxSessionObj->xWolfDrbgCtx, pucRandomData, ulRandomLen ) )
{
return CKR_FUNCTION_FAILED;
}
return CKR_OK;
}
#endif /* WOLF_AWSTLS */