| /* |
| * FreeRTOS PKCS #11 V2.0.3 |
| * 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. |
| * |
| * http://aws.amazon.com/freertos |
| * http://www.FreeRTOS.org |
| */ |
| |
| /** |
| * @file iot_pkcs11_mbedtls.c |
| * @brief mbedTLS-based 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 "iot_pkcs11_config.h" |
| #include "iot_crypto.h" |
| #include "iot_pkcs11.h" |
| #include "iot_pkcs11_pal.h" |
| #include "iot_pki_utils.h" |
| |
| /* 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 "threading_alt.h" |
| |
| /* Credential includes. */ |
| #include "aws_clientcredential.h" |
| #include "aws_clientcredential_keys.h" |
| #include "iot_default_root_certificates.h" |
| |
| #if ( pkcs11configOTA_SUPPORTED == 1 ) |
| #include "aws_ota_codesigner_certificate.h" |
| #endif |
| |
| /* C runtime includes. */ |
| #include <stdio.h> |
| #include <string.h> |
| |
| 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 ); |
| |
| #define PKCS11_PRINT( X ) vLoggingPrintf X |
| #define PKCS11_WARNING_PRINT( X ) /* vLoggingPrintf X */ |
| |
| /* Indicates that no PKCS #11 operation is underway for given session. */ |
| #define pkcs11NO_OPERATION ( ( CK_MECHANISM_TYPE ) 0xFFFFFFFFF ) |
| |
| /* The size of the buffer malloc'ed for the exported public key in C_GenerateKeyPair */ |
| #define pkcs11KEY_GEN_MAX_DER_SIZE 200 |
| |
| /* The slot ID to be returned by this PKCS #11 implementation. |
| * Note that this implementation does not have a concept of "slots" so this number is arbitrary. */ |
| #define pkcs11SLOT_ID 1 |
| |
| /* Private defines for checking that attribute templates are complete. */ |
| #define LABEL_IN_TEMPLATE ( 1U ) |
| #define PRIVATE_IN_TEMPLATE ( 1U << 1 ) |
| #define SIGN_IN_TEMPLATE ( 1U << 2 ) |
| #define EC_PARAMS_IN_TEMPLATE ( 1U << 3 ) |
| #define VERIFY_IN_TEMPLATE ( 1U << 4 ) |
| |
| typedef struct P11Object_t |
| { |
| CK_OBJECT_HANDLE xHandle; /* The "PAL Handle". */ |
| CK_BYTE xLabel[ pkcs11configMAX_LABEL_LENGTH + 1 ]; /* Plus 1 for the null terminator. */ |
| } P11Object_t; |
| |
| /* This structure helps the aws_pkcs11_mbedtls.c maintain a mapping of all objects in one place. |
| * Because some objects exist in device NVM and must be called by their "PAL Handles", and other |
| * objects do not have designated NVM storage locations, the ObjectList maintains a list |
| * of what object handles are available. |
| */ |
| typedef struct P11ObjectList_t |
| { |
| SemaphoreHandle_t xMutex; /* Mutex that protects write operations to the xObjects array. */ |
| P11Object_t xObjects[ pkcs11configMAX_NUM_OBJECTS ]; |
| } P11ObjectList_t; |
| |
| /* PKCS #11 Module Object */ |
| typedef struct P11Struct_t |
| { |
| CK_BBOOL xIsInitialized; /* Indicates whether PKCS #11 module has been initialized with a call to C_Initialize. */ |
| mbedtls_ctr_drbg_context xMbedDrbgCtx; /* CTR-DRBG context for PKCS #11 module - used to generate pseudo-random numbers. */ |
| mbedtls_entropy_context xMbedEntropyContext; /* Entropy context for PKCS #11 module - used to collect entropy for RNG. */ |
| P11ObjectList_t xObjectList; /* List of PKCS #11 objects that have been found/created since module initialization. |
| * The array position indicates the "App Handle" */ |
| } P11Struct_t, * P11Context_t; |
| |
| /* The global PKCS #11 module object. |
| * Entropy/randomness and object lists are shared across PKCS #11 sessions. */ |
| static P11Struct_t xP11Context; |
| |
| /** |
| * @brief Session structure. |
| */ |
| typedef struct P11Session |
| { |
| CK_ULONG ulState; /* Stores the session flags. */ |
| CK_BBOOL xOpened; /* Set to CK_TRUE upon opening PKCS #11 session. */ |
| CK_MECHANISM_TYPE xOperationInProgress; /* Indicates if a digest operation is in progress. */ |
| CK_BBOOL xFindObjectInit; |
| CK_BBOOL xFindObjectComplete; |
| CK_BYTE * pxFindObjectLabel; /* Pointer to the label for the search in progress. Should be NULL if no search in progress. */ |
| uint8_t xFindObjectLabelLength; |
| CK_MECHANISM_TYPE xVerifyMechanism; /* The mechanism of verify operation in progress. Set during C_VerifyInit. */ |
| SemaphoreHandle_t xVerifyMutex; /* Protects the verification key from being modified while in use. */ |
| mbedtls_pk_context xVerifyKey; /* Verification key. Set during C_VerifyInit. */ |
| CK_MECHANISM_TYPE xSignMechanism; /* Mechanism of the sign operation in progress. Set during C_SignInit. */ |
| SemaphoreHandle_t xSignMutex; /* Protects the signing key from being modified while in use. */ |
| mbedtls_pk_context xSignKey; /* Signing key. Set during C_SignInit. */ |
| mbedtls_sha256_context xSHA256Context; /* Context for in progress digest operation. */ |
| } P11Session_t, * P11SessionPtr_t; |
| |
| |
| |
| /** |
| * @brief Helper definitions. |
| */ |
| #define PKCS11_MODULE_IS_INITIALIZED ( ( xP11Context.xIsInitialized == CK_TRUE ) ? CK_TRUE : CK_FALSE ) |
| #define PKCS11_SESSION_IS_OPEN( xSessionHandle ) ( ( ( ( P11SessionPtr_t ) xSessionHandle )->xOpened ) == CK_TRUE ? CKR_OK : CKR_SESSION_CLOSED ) |
| #define PKCS11_SESSION_IS_VALID( xSessionHandle ) ( ( ( P11SessionPtr_t ) xSessionHandle != NULL ) ? PKCS11_SESSION_IS_OPEN( xSessionHandle ) : CKR_SESSION_HANDLE_INVALID ) |
| #define PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSessionHandle ) ( PKCS11_MODULE_IS_INITIALIZED ? PKCS11_SESSION_IS_VALID( xSessionHandle ) : CKR_CRYPTOKI_NOT_INITIALIZED ) |
| /*-----------------------------------------------------------*/ |
| /*--------- See iot_pkcs11_pal.c for definitions ------------*/ |
| |
| |
| |
| /** |
| * @brief Maps an opaque caller session handle into its internal state structure. |
| */ |
| P11SessionPtr_t prvSessionPointerFromHandle( CK_SESSION_HANDLE xSession ) |
| { |
| return ( P11SessionPtr_t ) xSession; /*lint !e923 Allow casting integer type to pointer for handle. */ |
| } |
| |
| |
| /* |
| * 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_GetInfo */ |
| C_GetFunctionList, |
| C_GetSlotList, |
| NULL, /*C_GetSlotInfo*/ |
| C_GetTokenInfo, |
| NULL, /*C_GetMechanismList*/ |
| C_GetMechanismInfo, |
| C_InitToken, |
| NULL, /*C_InitPIN*/ |
| NULL, /*C_SetPIN*/ |
| C_OpenSession, |
| C_CloseSession, |
| NULL, /*C_CloseAllSessions*/ |
| NULL, /*C_GetSessionInfo*/ |
| NULL, /*C_GetOperationState*/ |
| NULL, /*C_SetOperationState*/ |
| C_Login, /*C_Login*/ |
| NULL, /*C_Logout*/ |
| C_CreateObject, |
| NULL, /*C_CopyObject*/ |
| C_DestroyObject, |
| NULL, /*C_GetObjectSize*/ |
| C_GetAttributeValue, |
| NULL, /*C_SetAttributeValue*/ |
| C_FindObjectsInit, |
| C_FindObjects, |
| C_FindObjectsFinal, |
| NULL, /*C_EncryptInit*/ |
| NULL, /*C_Encrypt*/ |
| NULL, /*C_EncryptUpdate*/ |
| NULL, /*C_EncryptFinal*/ |
| NULL, /*C_DecryptInit*/ |
| NULL, /*C_Decrypt*/ |
| NULL, /*C_DecryptUpdate*/ |
| NULL, /*C_DecryptFinal*/ |
| C_DigestInit, |
| NULL, /*C_Digest*/ |
| C_DigestUpdate, |
| NULL, /* C_DigestKey*/ |
| C_DigestFinal, |
| C_SignInit, |
| C_Sign, |
| NULL, /*C_SignUpdate*/ |
| NULL, /*C_SignFinal*/ |
| NULL, /*C_SignRecoverInit*/ |
| NULL, /*C_SignRecover*/ |
| C_VerifyInit, |
| C_Verify, |
| NULL, /*C_VerifyUpdate*/ |
| NULL, /*C_VerifyFinal*/ |
| NULL, /*C_VerifyRecoverInit*/ |
| NULL, /*C_VerifyRecover*/ |
| NULL, /*C_DigestEncryptUpdate*/ |
| NULL, /*C_DecryptDigestUpdate*/ |
| NULL, /*C_SignEncryptUpdate*/ |
| NULL, /*C_DecryptVerifyUpdate*/ |
| NULL, /*C_GenerateKey*/ |
| C_GenerateKeyPair, |
| NULL, /*C_WrapKey*/ |
| NULL, /*C_UnwrapKey*/ |
| NULL, /*C_DeriveKey*/ |
| NULL, /*C_SeedRandom*/ |
| C_GenerateRandom, |
| NULL, /*C_GetFunctionStatus*/ |
| NULL, /*C_CancelFunction*/ |
| NULL /*C_WaitForSlotEvent*/ |
| }; |
| |
| /*-----------------------------------------------------------*/ |
| |
| /* Note: Before prvMbedTLS_Initialize can be called, CRYPTO_Init() |
| * must be called to initialize the mbedTLS mutex & heap management functions. */ |
| CK_RV prvMbedTLS_Initialize( void ) |
| { |
| CK_RV xResult = CKR_OK; |
| |
| if( xP11Context.xIsInitialized == CK_TRUE ) |
| { |
| xResult = CKR_CRYPTOKI_ALREADY_INITIALIZED; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| memset( &xP11Context, 0, sizeof( xP11Context ) ); |
| xP11Context.xObjectList.xMutex = xSemaphoreCreateMutex(); |
| |
| CRYPTO_Init(); |
| /* Initialize the entropy source and DRBG for the PKCS#11 module */ |
| mbedtls_entropy_init( &xP11Context.xMbedEntropyContext ); |
| mbedtls_ctr_drbg_init( &xP11Context.xMbedDrbgCtx ); |
| |
| if( 0 != mbedtls_ctr_drbg_seed( &xP11Context.xMbedDrbgCtx, |
| mbedtls_entropy_func, |
| &xP11Context.xMbedEntropyContext, |
| NULL, |
| 0 ) ) |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| else |
| { |
| xP11Context.xIsInitialized = CK_TRUE; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /* Searches a template for the CKA_CLASS attribute. */ |
| CK_RV prvGetObjectClass( CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_CLASS * pxClass ) |
| { |
| CK_RV xResult = CKR_TEMPLATE_INCOMPLETE; |
| uint32_t ulIndex = 0; |
| |
| /* Search template for class attribute. */ |
| for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) |
| { |
| CK_ATTRIBUTE xAttribute = pxTemplate[ ulIndex ]; |
| |
| if( xAttribute.type == CKA_CLASS ) |
| { |
| memcpy( pxClass, xAttribute.pValue, sizeof( CK_OBJECT_CLASS ) ); |
| xResult = CKR_OK; |
| break; |
| } |
| } |
| |
| return xResult; |
| } |
| /*-----------------------------------------------------------------------*/ |
| /* Functions for maintaining the PKCS #11 module's label-handle lookups. */ |
| /*-----------------------------------------------------------------------*/ |
| |
| |
| /** |
| * @brief Searches the PKCS #11 module's object list for label and provides handle. |
| * |
| * @param[in] pcLabel Array containing label. |
| * @param[in] xLableLength Length of the label, in bytes. |
| * @param[out] pxPalHandle Pointer to the PAL handle to be provided. |
| * CK_INVALID_HANDLE if no object found. |
| * @param[out] pxAppHandle Pointer to the application handle to be provided. |
| * CK_INVALID_HANDLE if no object found. |
| */ |
| void prvFindObjectInListByLabel( uint8_t * pcLabel, |
| size_t xLabelLength, |
| CK_OBJECT_HANDLE_PTR pxPalHandle, |
| CK_OBJECT_HANDLE_PTR pxAppHandle ) |
| { |
| uint8_t ucIndex; |
| |
| *pxPalHandle = CK_INVALID_HANDLE; |
| *pxAppHandle = CK_INVALID_HANDLE; |
| |
| for( ucIndex = 0; ucIndex < pkcs11configMAX_NUM_OBJECTS; ucIndex++ ) |
| { |
| if( 0 == memcmp( pcLabel, xP11Context.xObjectList.xObjects[ ucIndex ].xLabel, xLabelLength ) ) |
| { |
| *pxPalHandle = xP11Context.xObjectList.xObjects[ ucIndex ].xHandle; |
| *pxAppHandle = ucIndex + 1; /* Zero is not a valid handle, so let's offset by 1. */ |
| break; |
| } |
| } |
| } |
| |
| /** |
| * @brief Looks up a PKCS #11 object's label and PAL handle given an application handle. |
| * |
| * @param[in] xAppHandle The handle of the object being lookedup for, used by the application. |
| * @param[out] xPalHandle Pointer to the handle corresponding to xPalHandle being used by the PAL. |
| * @param[out] ppcLabel Pointer to an array containing label. NULL if object not found. |
| * @param[out] pxLabelLength Pointer to label length (includes a string null terminator). |
| * 0 if no object found. |
| */ |
| void prvFindObjectInListByHandle( CK_OBJECT_HANDLE xAppHandle, |
| CK_OBJECT_HANDLE_PTR pxPalHandle, |
| uint8_t ** ppcLabel, |
| size_t * pxLabelLength ) |
| { |
| int lIndex = xAppHandle - 1; |
| |
| *ppcLabel = NULL; |
| *pxLabelLength = 0; |
| *pxPalHandle = CK_INVALID_HANDLE; |
| |
| if( lIndex < pkcs11configMAX_NUM_OBJECTS ) /* Check that handle is in bounds. */ |
| { |
| if( xP11Context.xObjectList.xObjects[ lIndex ].xHandle != CK_INVALID_HANDLE ) |
| { |
| *ppcLabel = xP11Context.xObjectList.xObjects[ lIndex ].xLabel; |
| *pxLabelLength = strlen( ( const char * ) xP11Context.xObjectList.xObjects[ lIndex ].xLabel ) + 1; |
| *pxPalHandle = xP11Context.xObjectList.xObjects[ lIndex ].xHandle; |
| } |
| } |
| } |
| |
| /** |
| * @brief Removes an object from the module object list (xP11Context.xObjectList) |
| * |
| * \warn This does not delete the object from NVM. |
| * |
| * @param[in] xAppHandle Application handle of the object to be deleted. |
| * |
| */ |
| CK_RV prvDeleteObjectFromList( CK_OBJECT_HANDLE xAppHandle ) |
| { |
| CK_RV xResult = CKR_OK; |
| BaseType_t xGotSemaphore = pdFALSE; |
| int lIndex = xAppHandle - 1; |
| |
| if( lIndex >= pkcs11configMAX_NUM_OBJECTS ) |
| { |
| xResult = CKR_OBJECT_HANDLE_INVALID; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| xGotSemaphore = xSemaphoreTake( xP11Context.xObjectList.xMutex, portMAX_DELAY ); |
| } |
| |
| if( ( xGotSemaphore == pdTRUE ) && ( xResult == CKR_OK ) ) |
| { |
| if( xP11Context.xObjectList.xObjects[ lIndex ].xHandle != CK_INVALID_HANDLE ) |
| { |
| memset( &xP11Context.xObjectList.xObjects[ lIndex ], 0, sizeof( P11Object_t ) ); |
| } |
| else |
| { |
| xResult = CKR_OBJECT_HANDLE_INVALID; |
| } |
| |
| xSemaphoreGive( xP11Context.xObjectList.xMutex ); |
| } |
| else |
| { |
| xResult = CKR_CANT_LOCK; |
| } |
| |
| return xResult; |
| } |
| |
| |
| /** |
| * @brief Add an object that exists in NVM to the application object array. |
| * |
| * @param[in[ xPalHandle The handle used by the PKCS #11 PAL for object. |
| * @param[out] pxAppHandle Updated to contain the application handle corresponding to xPalHandle. |
| * @param[in] pcLabel Pointer to object label. |
| * @param[in] xLabelLength Length of the PKCS #11 label. |
| * |
| */ |
| CK_RV prvAddObjectToList( CK_OBJECT_HANDLE xPalHandle, |
| CK_OBJECT_HANDLE_PTR pxAppHandle, |
| uint8_t * pcLabel, |
| size_t xLabelLength ) |
| { |
| CK_RV xResult = CKR_OK; |
| BaseType_t xGotSemaphore; |
| |
| CK_BBOOL xObjectFound = CK_FALSE; |
| int lInsertIndex = -1; |
| int lSearchIndex = pkcs11configMAX_NUM_OBJECTS - 1; |
| |
| xGotSemaphore = xSemaphoreTake( xP11Context.xObjectList.xMutex, portMAX_DELAY ); |
| |
| if( xGotSemaphore == pdTRUE ) |
| { |
| for( lSearchIndex = pkcs11configMAX_NUM_OBJECTS - 1; lSearchIndex >= 0; lSearchIndex-- ) |
| { |
| if( xP11Context.xObjectList.xObjects[ lSearchIndex ].xHandle == xPalHandle ) |
| { |
| /* Object already exists in list. */ |
| xObjectFound = CK_TRUE; |
| break; |
| } |
| else if( xP11Context.xObjectList.xObjects[ lSearchIndex ].xHandle == CK_INVALID_HANDLE ) |
| { |
| lInsertIndex = lSearchIndex; |
| } |
| } |
| |
| if( xObjectFound == CK_FALSE ) |
| { |
| if( lInsertIndex != -1 ) |
| { |
| if( xLabelLength < pkcs11configMAX_LABEL_LENGTH ) |
| { |
| xP11Context.xObjectList.xObjects[ lInsertIndex ].xHandle = xPalHandle; |
| memcpy( xP11Context.xObjectList.xObjects[ lInsertIndex ].xLabel, pcLabel, xLabelLength ); |
| *pxAppHandle = lInsertIndex + 1; |
| } |
| else |
| { |
| xResult = CKR_DATA_LEN_RANGE; |
| } |
| } |
| } |
| |
| xSemaphoreGive( xP11Context.xObjectList.xMutex ); |
| } |
| else |
| { |
| xResult = CKR_CANT_LOCK; |
| } |
| |
| return xResult; |
| } |
| |
| #if ( pkcs11configPAL_DESTROY_SUPPORTED != 1 ) |
| |
| CK_RV PKCS11_PAL_DestroyObject( CK_OBJECT_HANDLE xAppHandle ) |
| { |
| uint8_t * pcLabel = NULL; |
| size_t xLabelLength = 0; |
| uint32_t ulObjectLength = 0; |
| CK_BBOOL xIsPrivate = CK_TRUE; |
| CK_RV xResult = CKR_OK; |
| CK_BBOOL xFreeMemory = CK_FALSE; |
| CK_BYTE_PTR pxObject = NULL; |
| CK_ATTRIBUTE xLabel; |
| CK_OBJECT_HANDLE xPalHandle; |
| CK_OBJECT_HANDLE xPalHandle2; |
| CK_OBJECT_HANDLE xAppHandle2; |
| CK_BYTE_PTR pxZeroedData = NULL; |
| |
| prvFindObjectInListByHandle( xAppHandle, &xPalHandle, &pcLabel, &xLabelLength ); |
| |
| if( pcLabel != NULL ) |
| { |
| xResult = PKCS11_PAL_GetObjectValue( xPalHandle, &pxObject, &ulObjectLength, &xIsPrivate ); |
| |
| if( xResult == CKR_OK ) |
| { |
| xFreeMemory = CK_TRUE; |
| /* Some ports return a pointer to memory for which using memset directly won't work. */ |
| pxZeroedData = pvPortMalloc( ulObjectLength ); |
| |
| if( NULL != pxZeroedData ) |
| { |
| /* Zero out the object. */ |
| memset( pxZeroedData, 0x0, ulObjectLength ); |
| /* Create an object label attribute. */ |
| xLabel.type = CKA_LABEL; |
| xLabel.pValue = pcLabel; |
| xLabel.ulValueLen = xLabelLength; |
| /* Overwrite the object in NVM with zeros. */ |
| xPalHandle2 = PKCS11_PAL_SaveObject( &xLabel, pxZeroedData, ulObjectLength ); |
| |
| if( xPalHandle2 != xPalHandle ) |
| { |
| xResult = CKR_GENERAL_ERROR; |
| } |
| |
| vPortFree( pxZeroedData ); |
| } |
| else |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( 0 == memcmp( xLabel.pValue, pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS, xLabelLength ) ) |
| { |
| prvFindObjectInListByLabel( ( uint8_t * ) pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS, strlen( ( char * ) pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS ), &xPalHandle, &xAppHandle2 ); |
| |
| if( xPalHandle != CK_INVALID_HANDLE ) |
| { |
| xResult = prvDeleteObjectFromList( xAppHandle2 ); |
| } |
| } |
| else if( 0 == memcmp( xLabel.pValue, pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS, xLabelLength ) ) |
| { |
| prvFindObjectInListByLabel( ( uint8_t * ) pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS, strlen( ( char * ) pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS ), &xPalHandle, &xAppHandle2 ); |
| |
| if( xPalHandle != CK_INVALID_HANDLE ) |
| { |
| xResult = prvDeleteObjectFromList( xAppHandle2 ); |
| } |
| } |
| |
| xResult = prvDeleteObjectFromList( xAppHandle ); |
| } |
| |
| if( xFreeMemory == CK_TRUE ) |
| { |
| PKCS11_PAL_GetObjectValueCleanup( pxObject, ulObjectLength ); |
| } |
| |
| return xResult; |
| } |
| |
| #endif /* if ( pkcs11configPAL_DESTROY_SUPPORTED != 1 ) */ |
| |
| #if ( pkcs11configJITP_CODEVERIFY_ROOT_CERT_SUPPORTED != 1 ) |
| |
| /* Returns True if the object is not stored in NVM & must be looked up in header file. |
| * Returns false if object is an NVM supported object. */ |
| |
| BaseType_t xIsObjectWithNoNvmStorage( uint8_t * pucLabel, |
| size_t xLength, |
| uint8_t ** ppucCertData ) |
| { |
| BaseType_t xResult = CK_TRUE; |
| |
| if( 0 == memcmp( pucLabel, pkcs11configLABEL_JITP_CERTIFICATE, strlen( ( char * ) pkcs11configLABEL_JITP_CERTIFICATE ) ) ) |
| { |
| if( NULL != keyJITR_DEVICE_CERTIFICATE_AUTHORITY_PEM ) |
| { |
| *ppucCertData = ( uint8_t * ) keyJITR_DEVICE_CERTIFICATE_AUTHORITY_PEM; |
| } |
| else |
| { |
| PKCS11_PRINT( ( "ERROR: JITP Certificate not specified.\r\n" ) ); |
| } |
| } |
| else if( 0 == memcmp( pucLabel, pkcs11configLABEL_ROOT_CERTIFICATE, strlen( ( char * ) pkcs11configLABEL_ROOT_CERTIFICATE ) ) ) |
| { |
| /* Use either Verisign or Starfield root CA, |
| * depending on whether this is an ATS endpoint. */ |
| if( strstr( clientcredentialMQTT_BROKER_ENDPOINT, "-ats.iot" ) == NULL ) |
| { |
| *ppucCertData = ( uint8_t * ) tlsVERISIGN_ROOT_CERTIFICATE_PEM; |
| } |
| else |
| { |
| *ppucCertData = ( uint8_t * ) tlsSTARFIELD_ROOT_CERTIFICATE_PEM; |
| } |
| } |
| |
| #if ( pkcs11configOTA_SUPPORTED == 1 ) |
| else if( 0 == memcmp( pucLabel, pkcs11configLABEL_CODE_VERIFICATION_KEY, strlen( ( char * ) pkcs11configLABEL_CODE_VERIFICATION_KEY ) ) ) |
| { |
| *ppucCertData = ( uint8_t * ) signingcredentialSIGNING_CERTIFICATE_PEM; |
| } |
| #endif |
| else |
| { |
| xResult = CK_FALSE; |
| } |
| |
| return xResult; |
| } |
| |
| |
| #endif /* if ( pkcs11configJITP_CODEVERIFY_ROOT_CERT_SUPPORTED != 1 ) */ |
| |
| |
| /*-------------------------------------------------------------*/ |
| |
| #if !defined( pkcs11configC_INITIALIZE_ALT ) |
| |
| /** |
| * @brief Initialize the PKCS #11 module for use. |
| * |
| * @note C_Initialize is not thread-safe. |
| * |
| * C_Initialize should be called (and allowed to return) before |
| * any additional PKCS #11 operations are invoked. |
| * |
| * In this implementation, all arguments are ignored. |
| * Thread protection for the rest of PKCS #11 functions |
| * default to FreeRTOS primitives. |
| * |
| * @param[in] pvInitArgs This parameter is ignored. |
| * |
| * @return CKR_OK if successful. |
| * CKR_CRYPTOKI_ALREADY_INITIALIZED if C_Initialize was previously called. |
| * All other errors indicate that the PKCS #11 module is not ready to be used. |
| * See <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_Initialize )( CK_VOID_PTR pvInitArgs ) |
| { /*lint !e9072 It's OK to have different parameter name. */ |
| ( void ) ( pvInitArgs ); |
| |
| CK_RV xResult = CKR_OK; |
| |
| if( xP11Context.xIsInitialized != CK_TRUE ) |
| { |
| xResult = prvMbedTLS_Initialize(); |
| } |
| else |
| { |
| xResult = CKR_CRYPTOKI_ALREADY_INITIALIZED; |
| } |
| |
| return xResult; |
| } |
| #endif /* if !defined( pkcs11configC_INITIALIZE_ALT ) */ |
| |
| /** |
| * @brief Un-initialize the Cryptoki module. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_Finalize )( CK_VOID_PTR pvReserved ) |
| { |
| /*lint !e9072 It's OK to have different parameter name. */ |
| CK_RV xResult = CKR_OK; |
| |
| if( pvReserved != NULL ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( xP11Context.xIsInitialized == CK_FALSE ) |
| { |
| xResult = CKR_CRYPTOKI_NOT_INITIALIZED; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| mbedtls_entropy_free( &xP11Context.xMbedEntropyContext ); |
| |
| mbedtls_ctr_drbg_free( &xP11Context.xMbedDrbgCtx ); |
| |
| vSemaphoreDelete( xP11Context.xObjectList.xMutex ); |
| |
| xP11Context.xIsInitialized = CK_FALSE; |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Obtain a pointer to the PKCS #11 module's list |
| * of function pointers. |
| * |
| * All other PKCS #11 functions should be invoked using the returned |
| * function list. |
| * |
| * \warn Do not overwrite the function list. |
| * |
| * \param[in] ppxFunctionList Pointer to the location where |
| * pointer to function list will be placed. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_GetFunctionList )( CK_FUNCTION_LIST_PTR_PTR ppxFunctionList ) |
| { /*lint !e9072 It's OK to have different parameter name. */ |
| CK_RV xResult = CKR_OK; |
| |
| if( NULL == ppxFunctionList ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| else |
| { |
| *ppxFunctionList = &prvP11FunctionList; |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Query the list of slots. A single default slot is implemented. |
| * |
| * This port does not implement the concept of separate slots/tokens. |
| * |
| * \param[in] xTokenPresent This parameter is unused by this port. |
| * \param[in] pxSlotList Pointer to an array of slot IDs. |
| * At this time, only 1 slot is implemented. |
| * \param[in,out] pulCount Length of the slot list pxSlotList. Updated |
| * to contain the actual number of slots written |
| * to the list. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_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. */ |
| CK_RV xResult = CKR_OK; |
| |
| /* Since the mbedTLS implementation of PKCS#11 does not depend |
| * on a physical token, this parameter is ignored. */ |
| ( void ) ( xTokenPresent ); |
| |
| if( PKCS11_MODULE_IS_INITIALIZED != CK_TRUE ) |
| { |
| xResult = CKR_CRYPTOKI_NOT_INITIALIZED; |
| } |
| |
| if( NULL == pulCount ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( NULL == pxSlotList ) |
| { |
| *pulCount = 1; |
| } |
| else |
| { |
| if( 0u == *pulCount ) |
| { |
| xResult = CKR_BUFFER_TOO_SMALL; |
| } |
| else |
| { |
| pxSlotList[ 0 ] = pkcs11SLOT_ID; |
| *pulCount = 1; |
| } |
| } |
| } |
| |
| return xResult; |
| } |
| |
| |
| /** |
| * @brief This function is not implemented for this port. |
| * |
| * C_GetTokenInfo() is only implemented for compatibility with other ports. |
| * All inputs to this function are ignored, and calling this |
| * function on this port does provide any information about |
| * the PKCS #11 token. |
| * |
| * @return CKR_OK. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_GetTokenInfo )( CK_SLOT_ID slotID, |
| CK_TOKEN_INFO_PTR pInfo ) |
| { |
| /* Avoid compiler warnings about unused variables. */ |
| ( void ) slotID; |
| ( void ) pInfo; |
| |
| return CKR_OK; |
| } |
| |
| /** |
| * @brief This function obtains information about a particular |
| * mechanism possibly supported by a token. |
| * |
| * \param[in] xSlotID This parameter is unused in this port. |
| * \param[in] type The cryptographic capability for which support |
| * information is being queried. |
| * \param[out] pInfo Algorithm sizes and flags for the requested |
| * mechanism, if supported. |
| * |
| * @return CKR_OK if the mechanism is supported. Otherwise, CKR_MECHANISM_INVALID. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_GetMechanismInfo )( CK_SLOT_ID slotID, |
| CK_MECHANISM_TYPE type, |
| CK_MECHANISM_INFO_PTR pInfo ) |
| { |
| CK_RV xResult = CKR_MECHANISM_INVALID; |
| struct CryptoMechanisms |
| { |
| CK_MECHANISM_TYPE xType; |
| CK_MECHANISM_INFO xInfo; |
| } |
| pxSupportedMechanisms[] = |
| { |
| { CKM_RSA_PKCS, { 2048, 2048, CKF_SIGN } }, |
| { CKM_RSA_X_509, { 2048, 2048, CKF_VERIFY } }, |
| #if ( pkcs11configSUPPRESS_ECDSA_MECHANISM != 1 ) |
| { CKM_ECDSA, { 256, 256, CKF_SIGN | CKF_VERIFY } }, |
| { CKM_EC_KEY_PAIR_GEN, { 256, 256, CKF_GENERATE_KEY_PAIR } }, |
| #endif |
| { CKM_SHA256, { 0, 0, CKF_DIGEST } } |
| }; |
| uint32_t ulMech = 0; |
| |
| /* Look for the requested mechanism in the above table. */ |
| for( ; ulMech < sizeof( pxSupportedMechanisms ) / sizeof( pxSupportedMechanisms[ 0 ] ); ulMech++ ) |
| { |
| if( pxSupportedMechanisms[ ulMech ].xType == type ) |
| { |
| /* The mechanism is supported. Copy out the details and break |
| * out of the loop. */ |
| memcpy( pInfo, &( pxSupportedMechanisms[ ulMech ].xInfo ), sizeof( CK_MECHANISM_INFO ) ); |
| xResult = CKR_OK; |
| break; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief This function is not implemented for this port. |
| * |
| * C_InitToken() is only implemented for compatibility with other ports. |
| * All inputs to this function are ignored, and calling this |
| * function on this port does not add any security. |
| * |
| * @return CKR_OK. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_InitToken )( CK_SLOT_ID slotID, |
| CK_UTF8CHAR_PTR pPin, |
| CK_ULONG ulPinLen, |
| CK_UTF8CHAR_PTR pLabel ) |
| { |
| /* Avoid compiler warnings about unused variables. */ |
| ( void ) slotID; |
| ( void ) pPin; |
| ( void ) ulPinLen; |
| ( void ) pLabel; |
| |
| return CKR_OK; |
| } |
| |
| /** |
| * @brief Start a session for a cryptographic command sequence. |
| * |
| * \note PKCS #11 module must have been previously initialized with a call to |
| * C_Initialize() before calling C_OpenSession(). |
| * |
| * |
| * \param[in] xSlotID This parameter is unused in this port. |
| * \param[in] xFlags Session flags - CKF_SERIAL_SESSION is a |
| * mandatory flag. |
| * \param[in] pvApplication This parameter is unused in this port. |
| * \param[in] xNotify This parameter is unused in this port. |
| * \param[in] pxSession Pointer to the location that the created |
| * session's handle will be placed. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_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; |
| CK_BBOOL xSessionMemAllocated = CK_FALSE; |
| CK_BBOOL xSignMutexCreated = CK_FALSE; |
| CK_BBOOL xVerifyMutexCreated = CK_FALSE; |
| |
| ( void ) ( xSlotID ); |
| ( void ) ( pvApplication ); |
| ( void ) ( xNotify ); |
| |
| /* Check that the PKCS #11 module is initialized. */ |
| if( PKCS11_MODULE_IS_INITIALIZED != CK_TRUE ) |
| { |
| xResult = CKR_CRYPTOKI_NOT_INITIALIZED; |
| } |
| |
| /* Check arguments. */ |
| if( NULL == pxSession ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| /* For legacy reasons, the CKF_SERIAL_SESSION bit MUST always be set. */ |
| if( 0 == ( CKF_SERIAL_SESSION & xFlags ) ) |
| { |
| xResult = CKR_SESSION_PARALLEL_NOT_SUPPORTED; |
| } |
| |
| /* |
| * Make space for the context. |
| */ |
| if( CKR_OK == xResult ) |
| { |
| pxSessionObj = ( P11SessionPtr_t ) pvPortMalloc( sizeof( struct P11Session ) ); /*lint !e9087 Allow casting void* to other types. */ |
| |
| if( NULL == pxSessionObj ) |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| else |
| { |
| xSessionMemAllocated = CK_TRUE; |
| } |
| |
| /* |
| * Zero out the session structure. |
| */ |
| if( CKR_OK == xResult ) |
| { |
| memset( pxSessionObj, 0, sizeof( P11Session_t ) ); |
| } |
| |
| pxSessionObj->xSignMutex = xSemaphoreCreateMutex(); |
| |
| if( NULL == pxSessionObj->xSignMutex ) |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| else |
| { |
| xSignMutexCreated = CK_TRUE; |
| } |
| |
| pxSessionObj->xVerifyMutex = xSemaphoreCreateMutex(); |
| |
| if( NULL == pxSessionObj->xVerifyMutex ) |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| else |
| { |
| xVerifyMutexCreated = CK_TRUE; |
| } |
| } |
| |
| 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. */ |
| } |
| |
| /* |
| * Initialize the operation in progress. |
| */ |
| if( CKR_OK == xResult ) |
| { |
| pxSessionObj->xOperationInProgress = pkcs11NO_OPERATION; |
| } |
| |
| if( CKR_OK != xResult ) |
| { |
| if( xSessionMemAllocated == CK_TRUE ) |
| { |
| if( xSignMutexCreated == CK_TRUE ) |
| { |
| vSemaphoreDelete( pxSessionObj->xSignMutex ); |
| } |
| |
| if( xVerifyMutexCreated == CK_TRUE ) |
| { |
| vSemaphoreDelete( pxSessionObj->xVerifyMutex ); |
| } |
| |
| vPortFree( pxSessionObj ); |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Terminate a session and release resources. |
| * |
| * @param[in] xSession The session handle to |
| * be terminated. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_CloseSession )( CK_SESSION_HANDLE xSession ) |
| { |
| /*lint !e9072 It's OK to have different parameter name. */ |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); |
| |
| if( xResult == CKR_OK ) |
| { |
| /* |
| * Tear down the session. |
| */ |
| |
| if( NULL != pxSession->xSignKey.pk_ctx ) |
| { |
| mbedtls_pk_free( &pxSession->xSignKey ); |
| } |
| |
| if( NULL != pxSession->xSignMutex ) |
| { |
| vSemaphoreDelete( pxSession->xSignMutex ); |
| } |
| |
| /* Free the public key context if it exists. */ |
| if( NULL != pxSession->xVerifyKey.pk_ctx ) |
| { |
| mbedtls_pk_free( &pxSession->xVerifyKey ); |
| } |
| |
| if( NULL != pxSession->xVerifyMutex ) |
| { |
| vSemaphoreDelete( pxSession->xVerifyMutex ); |
| } |
| |
| mbedtls_sha256_free( &pxSession->xSHA256Context ); |
| |
| vPortFree( pxSession ); |
| } |
| else |
| { |
| xResult = CKR_SESSION_HANDLE_INVALID; |
| } |
| |
| return xResult; |
| } |
| |
| |
| /** |
| * @brief This function is not implemented for this port. |
| * |
| * C_Login() is only implemented for compatibility with other ports. |
| * All inputs to this function are ignored, and calling this |
| * function on this port does not add any security. |
| * |
| * @return CKR_OK. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_Login )( CK_SESSION_HANDLE hSession, |
| CK_USER_TYPE userType, |
| CK_UTF8CHAR_PTR pPin, |
| CK_ULONG ulPinLen ) |
| { |
| /* Avoid warnings about unused parameters. */ |
| ( void ) hSession; |
| ( void ) userType; |
| ( void ) pPin; |
| ( void ) ulPinLen; |
| |
| /* THIS FUNCTION IS NOT IMPLEMENTED FOR MBEDTLS-BASED PORTS. |
| * If login capability is required, implement it here. |
| * Defined for compatibility with other PKCS #11 ports. */ |
| return CKR_OK; |
| } |
| |
| /* Helper function for parsing the templates of device certificates for |
| * C_CreateObject. */ |
| CK_RV prvCreateCertificate( CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_HANDLE_PTR pxObject ) |
| { |
| CK_RV xResult = CKR_OK; |
| CK_BYTE_PTR pxCertificateValue = NULL; |
| CK_ULONG xCertificateLength = 0; |
| CK_ATTRIBUTE_PTR pxLabel = NULL; |
| CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; |
| CK_CERTIFICATE_TYPE xCertificateType = 0; /* = CKC_X_509; */ |
| uint32_t ulIndex = 0; |
| CK_BBOOL xBool = CK_FALSE; |
| CK_ATTRIBUTE xAttribute; |
| |
| /* Search for the pointer to the certificate VALUE. */ |
| for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) |
| { |
| xAttribute = pxTemplate[ ulIndex ]; |
| |
| switch( xAttribute.type ) |
| { |
| case ( CKA_VALUE ): |
| pxCertificateValue = xAttribute.pValue; |
| xCertificateLength = xAttribute.ulValueLen; |
| break; |
| |
| case ( CKA_LABEL ): |
| |
| if( xAttribute.ulValueLen <= pkcs11configMAX_LABEL_LENGTH ) |
| { |
| pxLabel = &pxTemplate[ ulIndex ]; |
| } |
| else |
| { |
| xResult = CKR_DATA_LEN_RANGE; |
| } |
| |
| break; |
| |
| case ( CKA_CERTIFICATE_TYPE ): |
| memcpy( &xCertificateType, xAttribute.pValue, sizeof( CK_CERTIFICATE_TYPE ) ); |
| |
| if( xCertificateType != CKC_X_509 ) |
| { |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_TOKEN ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only token key object is supported. \r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_CLASS ): |
| case ( CKA_SUBJECT ): |
| |
| /* Do nothing. This was already parsed out of the template previously. */ |
| break; |
| |
| default: |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| break; |
| } |
| } |
| |
| if( ( pxCertificateValue == NULL ) || ( pxLabel == NULL ) ) |
| { |
| xResult = CKR_TEMPLATE_INCOMPLETE; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| xPalHandle = PKCS11_PAL_SaveObject( pxLabel, pxCertificateValue, xCertificateLength ); |
| |
| if( xPalHandle == 0 ) /*Invalid handle. */ |
| { |
| xResult = CKR_DEVICE_MEMORY; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| xResult = prvAddObjectToList( xPalHandle, pxObject, pxLabel->pValue, pxLabel->ulValueLen ); |
| /* TODO: If this fails, should the object be wiped back out of flash? But what if that fails?!?!? */ |
| } |
| |
| return xResult; |
| } |
| |
| #define PKCS11_INVALID_KEY_TYPE ( ( CK_KEY_TYPE ) 0xFFFFFFFF ) |
| |
| /* Helper to search an attribute for the key type attribute. */ |
| void prvGetKeyType( CK_KEY_TYPE * pxKeyType, |
| CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount ) |
| { |
| uint32_t ulIndex; |
| CK_ATTRIBUTE xAttribute; |
| |
| *pxKeyType = PKCS11_INVALID_KEY_TYPE; |
| |
| for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) |
| { |
| xAttribute = pxTemplate[ ulIndex ]; |
| |
| if( xAttribute.type == CKA_KEY_TYPE ) |
| { |
| memcpy( pxKeyType, xAttribute.pValue, sizeof( CK_KEY_TYPE ) ); |
| break; |
| } |
| } |
| } |
| |
| /* Helper to search a template for the label attribute. */ |
| void prvGetLabel( CK_ATTRIBUTE_PTR * ppxLabel, |
| CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount ) |
| { |
| CK_ATTRIBUTE xAttribute; |
| uint32_t ulIndex; |
| |
| *ppxLabel = NULL; |
| |
| for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) |
| { |
| xAttribute = pxTemplate[ ulIndex ]; |
| |
| if( xAttribute.type == CKA_LABEL ) |
| { |
| *ppxLabel = &pxTemplate[ ulIndex ]; |
| break; |
| } |
| } |
| } |
| |
| /* Because public and private keys are stored in the same slot for this port, |
| * importing one after the other requires a read of what was previously in the slot, |
| * combination of the public and private key in DER format, and re-import of the |
| * combination. */ |
| CK_RV prvGetExistingKeyComponent( CK_OBJECT_HANDLE_PTR pxPalHandle, |
| mbedtls_pk_context * pxMbedContext, |
| CK_ATTRIBUTE_PTR pxLabel ) |
| { |
| uint8_t * pucData = NULL; |
| size_t xDataLength = 0; |
| CK_BBOOL xIsPrivate = CK_TRUE; |
| BaseType_t xResult = CKR_OK; |
| int lMbedResult = 0; |
| CK_BBOOL xNeedToFreeMem = CK_FALSE; |
| |
| *pxPalHandle = CK_INVALID_HANDLE; |
| |
| if( 0 == memcmp( pxLabel->pValue, pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS, pxLabel->ulValueLen ) ) |
| { |
| *pxPalHandle = PKCS11_PAL_FindObject( ( uint8_t * ) pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS, ( uint8_t ) pxLabel->ulValueLen ); |
| } |
| else if( 0 == memcmp( pxLabel->pValue, pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS, pxLabel->ulValueLen ) ) |
| { |
| *pxPalHandle = PKCS11_PAL_FindObject( ( uint8_t * ) pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS, ( uint8_t ) pxLabel->ulValueLen ); |
| } |
| |
| if( *pxPalHandle != CK_INVALID_HANDLE ) |
| { |
| xResult = PKCS11_PAL_GetObjectValue( *pxPalHandle, &pucData, ( uint32_t * ) &xDataLength, &xIsPrivate ); |
| |
| if( xResult == CKR_OK ) |
| { |
| xNeedToFreeMem = CK_TRUE; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( xIsPrivate == CK_TRUE ) |
| { |
| lMbedResult = mbedtls_pk_parse_key( pxMbedContext, pucData, xDataLength, NULL, 0 ); |
| } |
| else |
| { |
| lMbedResult = mbedtls_pk_parse_public_key( pxMbedContext, pucData, xDataLength ); |
| } |
| } |
| |
| if( lMbedResult != 0 ) |
| { |
| *pxPalHandle = CK_INVALID_HANDLE; |
| } |
| |
| if( xNeedToFreeMem == CK_TRUE ) |
| { |
| PKCS11_PAL_GetObjectValueCleanup( pucData, xDataLength ); |
| } |
| |
| return xResult; |
| } |
| |
| /* Helper function for checking attribute templates of elliptic curve |
| * private keys before import with C_CreateObject. */ |
| CK_RV prvCreateEcPrivateKey( mbedtls_pk_context * pxMbedContext, |
| CK_ATTRIBUTE_PTR * ppxLabel, |
| CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_HANDLE_PTR pxObject ) |
| { |
| CK_RV xResult = CKR_OK; |
| int lMbedReturn; |
| CK_BBOOL xBool; |
| uint32_t ulIndex; |
| CK_ATTRIBUTE xAttribute; |
| |
| /* Key will be assembled in the mbedTLS key context and then exported to DER for storage. */ |
| mbedtls_ecp_keypair * pxKeyPair = ( mbedtls_ecp_keypair * ) pxMbedContext->pk_ctx; |
| |
| for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) |
| { |
| xAttribute = pxTemplate[ ulIndex ]; |
| |
| switch( xAttribute.type ) |
| { |
| case ( CKA_CLASS ): |
| case ( CKA_KEY_TYPE ): |
| |
| /* Do nothing. |
| * Key type and object type were checked previously. */ |
| break; |
| |
| case ( CKA_TOKEN ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only token key creation is supported. \r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_SIGN ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only keys with signing priveledges are supported. \r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_LABEL ): |
| |
| if( xAttribute.ulValueLen <= pkcs11configMAX_LABEL_LENGTH ) |
| { |
| *ppxLabel = &pxTemplate[ ulIndex ]; |
| } |
| else |
| { |
| xResult = CKR_DATA_LEN_RANGE; |
| } |
| |
| break; |
| |
| case ( CKA_EC_PARAMS ): |
| |
| if( memcmp( ( CK_BYTE[] ) pkcs11DER_ENCODED_OID_P256, xAttribute.pValue, xAttribute.ulValueLen ) ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only elliptic curve P-256 is supported.\r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_VALUE ): |
| lMbedReturn = mbedtls_mpi_read_binary( &pxKeyPair->d, |
| xAttribute.pValue, |
| xAttribute.ulValueLen ); |
| |
| if( lMbedReturn != 0 ) |
| { |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| default: |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| break; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| |
| /* Helper function for parsing RSA Private Key attribute templates |
| * for C_CreateObject. */ |
| CK_RV prvCreateRsaPrivateKey( mbedtls_pk_context * pxMbedContext, |
| CK_ATTRIBUTE_PTR * ppxLabel, |
| CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_HANDLE_PTR pxObject ) |
| { |
| CK_RV xResult = CKR_OK; |
| mbedtls_rsa_context * pxRsaContext; |
| int lMbedReturn = 0; |
| CK_BBOOL xBool; |
| uint32_t ulIndex; |
| CK_ATTRIBUTE xAttribute; |
| |
| *ppxLabel = NULL; |
| pxRsaContext = pxMbedContext->pk_ctx; |
| mbedtls_rsa_init( pxRsaContext, MBEDTLS_RSA_PKCS_V15, 0 /*ignored.*/ ); |
| |
| /* Parse template and collect the relevant parts. */ |
| for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) |
| { |
| xAttribute = pxTemplate[ ulIndex ]; |
| |
| switch( xAttribute.type ) |
| { |
| case ( CKA_CLASS ): |
| case ( CKA_KEY_TYPE ): |
| |
| /* Do nothing. |
| * Key type & object type were checked previously. |
| */ |
| break; |
| |
| case ( CKA_TOKEN ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only token key creation is supported. \r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_LABEL ): |
| |
| if( xAttribute.ulValueLen <= pkcs11configMAX_LABEL_LENGTH ) |
| { |
| *ppxLabel = &pxTemplate[ ulIndex ]; |
| } |
| else |
| { |
| xResult = CKR_DATA_LEN_RANGE; |
| } |
| |
| break; |
| |
| case ( CKA_SIGN ): |
| memcpy( &xBool, xAttribute.pValue, xAttribute.ulValueLen ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "Only RSA private keys with signing permissions supported. \r\n" ) ); |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| } |
| |
| break; |
| |
| case ( CKA_MODULUS ): |
| lMbedReturn |= mbedtls_rsa_import_raw( pxRsaContext, |
| xAttribute.pValue, xAttribute.ulValueLen, /* N */ |
| NULL, 0, /* P */ |
| NULL, 0, /* Q */ |
| NULL, 0, /* D */ |
| NULL, 0 ); /* E */ |
| break; |
| |
| case ( CKA_PUBLIC_EXPONENT ): |
| lMbedReturn |= mbedtls_rsa_import_raw( pxRsaContext, |
| NULL, 0, /* N */ |
| NULL, 0, /* P */ |
| NULL, 0, /* Q */ |
| NULL, 0, /* D */ |
| xAttribute.pValue, xAttribute.ulValueLen ); /* E */ |
| break; |
| |
| case ( CKA_PRIME_1 ): |
| lMbedReturn |= mbedtls_rsa_import_raw( pxRsaContext, |
| NULL, 0, /* N */ |
| xAttribute.pValue, xAttribute.ulValueLen, /* P */ |
| NULL, 0, /* Q */ |
| NULL, 0, /* D */ |
| NULL, 0 ); /* E */ |
| break; |
| |
| case ( CKA_PRIME_2 ): |
| lMbedReturn |= mbedtls_rsa_import_raw( pxRsaContext, |
| NULL, 0, /* N */ |
| NULL, 0, /* P */ |
| xAttribute.pValue, xAttribute.ulValueLen, /* Q */ |
| NULL, 0, /* D */ |
| NULL, 0 ); /* E */ |
| break; |
| |
| case ( CKA_PRIVATE_EXPONENT ): |
| lMbedReturn |= mbedtls_rsa_import_raw( pxRsaContext, |
| NULL, 0, /* N */ |
| NULL, 0, /* P */ |
| NULL, 0, /* Q */ |
| xAttribute.pValue, xAttribute.ulValueLen, /* D */ |
| NULL, 0 ); /* E */ |
| break; |
| |
| case ( CKA_EXPONENT_1 ): |
| lMbedReturn |= mbedtls_mpi_read_binary( &pxRsaContext->DP, xAttribute.pValue, xAttribute.ulValueLen ); |
| break; |
| |
| case ( CKA_EXPONENT_2 ): |
| lMbedReturn |= mbedtls_mpi_read_binary( &pxRsaContext->DQ, xAttribute.pValue, xAttribute.ulValueLen ); |
| break; |
| |
| case ( CKA_COEFFICIENT ): |
| lMbedReturn |= mbedtls_mpi_read_binary( &pxRsaContext->QP, xAttribute.pValue, xAttribute.ulValueLen ); |
| break; |
| |
| default: |
| PKCS11_PRINT( ( "Unknown attribute found for RSA private key. %d \r\n", xAttribute.type ) ); |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| break; |
| } |
| } |
| |
| if( lMbedReturn != 0 ) |
| { |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| return xResult; |
| } |
| |
| /* Helper function for importing private keys using template |
| * C_CreateObject. */ |
| CK_RV prvCreatePrivateKey( CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_HANDLE_PTR pxObject ) |
| { |
| /* TODO: How long is a typical RSA key anyhow? */ |
| #define MAX_LENGTH_KEY 3000 |
| mbedtls_pk_context xMbedContext; |
| int lDerKeyLength = 0; |
| int lActualKeyLength = 0; |
| int compare = 0; |
| CK_BYTE_PTR pxDerKey = NULL; |
| CK_RV xResult = CKR_OK; |
| CK_KEY_TYPE xKeyType; |
| CK_ATTRIBUTE_PTR pxLabel = NULL; |
| CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; |
| mbedtls_rsa_context * pxRsaCtx = NULL; |
| mbedtls_ecp_keypair * pxKeyPair = NULL; |
| |
| mbedtls_pk_init( &xMbedContext ); |
| |
| |
| prvGetKeyType( &xKeyType, pxTemplate, ulCount ); |
| |
| if( xKeyType == CKK_RSA ) |
| { |
| /* mbedtls_rsa_context must be malloc'ed to use with mbedtls_pk_free function. */ |
| pxRsaCtx = pvPortMalloc( sizeof( mbedtls_rsa_context ) ); |
| |
| if( pxRsaCtx != NULL ) |
| { |
| xMbedContext.pk_ctx = pxRsaCtx; |
| xMbedContext.pk_info = &mbedtls_rsa_info; |
| xResult = prvCreateRsaPrivateKey( &xMbedContext, |
| &pxLabel, |
| pxTemplate, |
| ulCount, |
| pxObject ); |
| } |
| else |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| } |
| |
| #if ( pkcs11configSUPPRESS_ECDSA_MECHANISM != 1 ) |
| else if( xKeyType == CKK_EC ) /* CKK_EC = CKK_ECDSA. */ |
| { |
| /* Key will be assembled in the mbedTLS key context and then exported to DER for storage. */ |
| prvGetLabel( &pxLabel, pxTemplate, ulCount ); |
| |
| xResult = prvGetExistingKeyComponent( &xPalHandle, &xMbedContext, pxLabel ); |
| |
| if( xPalHandle == CK_INVALID_HANDLE ) |
| { |
| /* An mbedTLS key is comprised of 2 pieces of data- an "info" and a "context". |
| * Since a valid key was not found by prvGetExistingKeyComponent, we are going to initialize |
| * the structure so that the mbedTLS structures will look the same as they would if a key |
| * had been found, minus the public key component. */ |
| |
| /* If a key had been found by prvGetExistingKeyComponent, the keypair context |
| * would have been malloc'ed. */ |
| pxKeyPair = pvPortMalloc( sizeof( mbedtls_ecp_keypair ) ); |
| |
| if( pxKeyPair != NULL ) |
| { |
| /* Initialize the info. */ |
| xMbedContext.pk_info = &mbedtls_eckey_info; |
| |
| /* Initialize the context. */ |
| xMbedContext.pk_ctx = pxKeyPair; |
| mbedtls_ecp_keypair_init( pxKeyPair ); |
| mbedtls_ecp_group_init( &pxKeyPair->grp ); |
| /*/ * At this time, only P-256 curves are supported. * / */ |
| mbedtls_ecp_group_load( &pxKeyPair->grp, MBEDTLS_ECP_DP_SECP256R1 ); |
| } |
| else |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| } |
| |
| xResult = prvCreateEcPrivateKey( &xMbedContext, |
| &pxLabel, |
| pxTemplate, |
| ulCount, |
| pxObject ); |
| } |
| #endif /* if ( pkcs11configSUPPRESS_ECDSA_MECHANISM != 1 ) */ |
| else |
| { |
| xResult = CKR_MECHANISM_INVALID; |
| } |
| |
| /* Convert back to DER and save to memory. */ |
| if( xResult == CKR_OK ) |
| { |
| pxDerKey = pvPortMalloc( MAX_LENGTH_KEY ); |
| |
| if( pxDerKey == NULL ) |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| lDerKeyLength = mbedtls_pk_write_key_der( &xMbedContext, pxDerKey, MAX_LENGTH_KEY ); |
| lActualKeyLength = lDerKeyLength; |
| |
| if( lDerKeyLength < 0 ) |
| { |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| /* Clean up the mbedTLS key context. */ |
| mbedtls_pk_free( &xMbedContext ); |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| /* TODO: Remove this hack. |
| * mbedtls_pk_write_key_der appends empty public |
| * key data when saving EC private key |
| * that does not have a public key associated with it. |
| * a1 04 -> Application identifier of length 4 |
| * 03 02 -> Bit string of length 2 |
| * 00 00 -> "Public key" |
| * https://forums.mbed.com/t/how-do-i-write-an-ec-private-key-w-no-public-key-to-der-format/4728 */ |
| if( xKeyType == CKK_EC ) /* CKK_EC = CKK_ECDSA. */ |
| { |
| /* If there was no public key in the structure, this byte |
| * array will be appended to the valid private key. |
| * It must be removed so that we can read the private |
| * key back at a later time. */ |
| uint8_t emptyPubKey[ 6 ] = { 0xa1, 0x04, 0x03, 0x02, 0x00, 0x00 }; |
| compare = memcmp( &pxDerKey[ MAX_LENGTH_KEY - 6 ], emptyPubKey, 6 ); |
| |
| if( compare == 0 ) |
| { |
| /* Do not write the last 6 bytes to key storage. */ |
| pxDerKey[ MAX_LENGTH_KEY - lDerKeyLength + 1 ] -= 6; |
| lActualKeyLength -= 6; |
| } |
| } |
| } |
| |
| /* Save the object to device NVM. */ |
| if( xResult == CKR_OK ) |
| { |
| xPalHandle = PKCS11_PAL_SaveObject( pxLabel, |
| pxDerKey + ( MAX_LENGTH_KEY - lDerKeyLength ), |
| lActualKeyLength ); |
| |
| if( xPalHandle == 0 ) |
| { |
| xResult = CKR_DEVICE_MEMORY; |
| } |
| } |
| |
| /* Store the PAL handle/label/application handle in lookup. */ |
| if( xResult == CKR_OK ) |
| { |
| xResult = prvAddObjectToList( xPalHandle, pxObject, pxLabel->pValue, pxLabel->ulValueLen ); |
| } |
| |
| if( pxDerKey != NULL ) |
| { |
| vPortFree( pxDerKey ); |
| } |
| |
| return xResult; |
| } |
| |
| /* Helper function for importing elliptic curve public keys from |
| * template using C_CreateObject. */ |
| CK_RV prvCreateECPublicKey( mbedtls_pk_context * pxMbedContext, |
| CK_ATTRIBUTE_PTR * ppxLabel, |
| CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_HANDLE_PTR pxObject ) |
| { |
| CK_RV xResult = CKR_OK; |
| int lMbedReturn; |
| CK_BBOOL xBool; |
| uint32_t ulIndex; |
| CK_ATTRIBUTE xAttribute; |
| |
| /* Key will be assembled in the mbedTLS key context and then exported to DER for storage. */ |
| mbedtls_ecp_keypair * pxKeyPair = ( mbedtls_ecp_keypair * ) pxMbedContext->pk_ctx; |
| |
| for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) |
| { |
| xAttribute = pxTemplate[ ulIndex ]; |
| |
| switch( xAttribute.type ) |
| { |
| case ( CKA_CLASS ): |
| case ( CKA_KEY_TYPE ): |
| |
| /* Do nothing. |
| * Key type and class were checked previously. */ |
| break; |
| |
| case ( CKA_TOKEN ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only token key creation is supported. \r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_LABEL ): |
| |
| if( xAttribute.ulValueLen < pkcs11configMAX_LABEL_LENGTH ) |
| { |
| *ppxLabel = &pxTemplate[ ulIndex ]; |
| } |
| else |
| { |
| xResult = CKR_DATA_LEN_RANGE; |
| } |
| |
| break; |
| |
| case ( CKA_VERIFY ): |
| memcpy( &xBool, xAttribute.pValue, xAttribute.ulValueLen ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "Only EC Public Keys with verify permissions supported. \r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_EC_PARAMS ): |
| |
| if( memcmp( ( CK_BYTE[] ) pkcs11DER_ENCODED_OID_P256, xAttribute.pValue, xAttribute.ulValueLen ) ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only elliptic curve P-256 is supported.\r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_EC_POINT ): |
| /* The first 2 bytes are for ASN1 type/length encoding. */ |
| lMbedReturn = mbedtls_ecp_point_read_binary( &pxKeyPair->grp, &pxKeyPair->Q, ( ( uint8_t * ) ( xAttribute.pValue ) + 2 ), ( xAttribute.ulValueLen - 2 ) ); |
| |
| if( lMbedReturn != 0 ) |
| { |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| default: |
| PKCS11_PRINT( ( "Unsupported attribute found for EC public key. %d \r\n", xAttribute.type ) ); |
| xResult = CKR_ATTRIBUTE_TYPE_INVALID; |
| break; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /* Helper function for importing public keys using |
| * C_CreateObject. */ |
| CK_RV prvCreatePublicKey( CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_HANDLE_PTR pxObject ) |
| { |
| #define MAX_PUBLIC_KEY_SIZE 3000 |
| mbedtls_pk_context xMbedContext; |
| int lDerKeyLength; |
| CK_BYTE_PTR pxDerKey = NULL; |
| CK_KEY_TYPE xKeyType; |
| CK_RV xResult = CKR_OK; |
| CK_ATTRIBUTE_PTR pxLabel = NULL; |
| CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; |
| CK_BBOOL xPrivateKeyFound = CK_FALSE; |
| mbedtls_pk_init( &xMbedContext ); |
| mbedtls_ecp_keypair * pxKeyPair; |
| |
| |
| prvGetKeyType( &xKeyType, pxTemplate, ulCount ); |
| |
| if( xKeyType == CKK_RSA ) |
| { |
| xResult = CKR_ATTRIBUTE_TYPE_INVALID; |
| } |
| |
| #if ( pkcs11configSUPPRESS_ECDSA_MECHANISM != 1 ) |
| else if( xKeyType == CKK_EC ) /* CKK_EC = CKK_ECDSA. */ |
| { |
| prvGetLabel( &pxLabel, pxTemplate, ulCount ); |
| |
| xResult = prvGetExistingKeyComponent( &xPalHandle, &xMbedContext, pxLabel ); |
| |
| if( xPalHandle == CK_INVALID_HANDLE ) |
| { |
| /* An mbedTLS key is comprised of 2 pieces of data- an "info" and a "context". |
| * Since a valid key was not found by prvGetExistingKeyComponent, we are going to initialize |
| * the structure so that the mbedTLS structures will look the same as they would if a key |
| * had been found, minus the private key component. */ |
| |
| /* If a key had been found by prvGetExistingKeyComponent, the keypair context |
| * would have been malloc'ed. */ |
| pxKeyPair = pvPortMalloc( sizeof( mbedtls_ecp_keypair ) ); |
| |
| if( pxKeyPair != NULL ) |
| { |
| /* Initialize the info. */ |
| xMbedContext.pk_info = &mbedtls_eckey_info; |
| |
| /* Initialize the context. */ |
| xMbedContext.pk_ctx = pxKeyPair; |
| mbedtls_ecp_keypair_init( pxKeyPair ); |
| mbedtls_ecp_group_init( &pxKeyPair->grp ); |
| /*/ * At this time, only P-256 curves are supported. * / */ |
| mbedtls_ecp_group_load( &pxKeyPair->grp, MBEDTLS_ECP_DP_SECP256R1 ); |
| } |
| else |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| } |
| else |
| { |
| xPrivateKeyFound = CK_TRUE; |
| } |
| |
| xResult = prvCreateECPublicKey( &xMbedContext, &pxLabel, pxTemplate, ulCount, pxObject ); |
| } |
| #endif /* if ( pkcs11configSUPPRESS_ECDSA_MECHANISM != 1 ) */ |
| else |
| { |
| PKCS11_PRINT( ( "Invalid key type %d \r\n", xKeyType ) ); |
| xResult = CKR_MECHANISM_INVALID; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| /* Store the key.*/ |
| pxDerKey = pvPortMalloc( MAX_PUBLIC_KEY_SIZE ); |
| |
| if( pxDerKey == NULL ) |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( xPrivateKeyFound == CK_FALSE ) |
| { |
| lDerKeyLength = mbedtls_pk_write_pubkey_der( &xMbedContext, pxDerKey, MAX_PUBLIC_KEY_SIZE ); |
| } |
| else |
| { |
| lDerKeyLength = mbedtls_pk_write_key_der( &xMbedContext, pxDerKey, MAX_PUBLIC_KEY_SIZE ); |
| } |
| |
| /* Clean up the mbedTLS key context. */ |
| mbedtls_pk_free( &xMbedContext ); |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| xPalHandle = PKCS11_PAL_SaveObject( pxLabel, |
| pxDerKey + ( MAX_LENGTH_KEY - lDerKeyLength ), |
| lDerKeyLength ); |
| |
| if( xPalHandle == CK_INVALID_HANDLE ) |
| { |
| xResult = CKR_DEVICE_MEMORY; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| xResult = prvAddObjectToList( xPalHandle, pxObject, pxLabel->pValue, pxLabel->ulValueLen ); |
| } |
| |
| if( pxDerKey != NULL ) |
| { |
| vPortFree( pxDerKey ); |
| } |
| |
| return xResult; |
| } |
| |
| |
| /** |
| * @brief Create a PKCS #11 certificate, public key, or private key object |
| * by importing it into device storage. |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pxTemplate List of attributes of the object to |
| * be created. |
| * @param[in] ulCount Number of attributes in pxTemplate. |
| * @param[out] pxObject Pointer to the location where the created |
| * object's handle will be placed. |
| * |
| * <table> |
| * <tr><th> Object Type <th> Template Attributes |
| * <tr><td rowspan="6">Certificate<td>CKA_CLASS |
| * <tr> <td>CKA_VALUE |
| * <tr> <td>CKA_TOKEN |
| * <tr> <td>CKA_LABEL |
| * <tr> <td>CKA_CERTIFICATE_TYPE |
| * <tr> <td>CKA_VALUE |
| * <tr><td rowspan="7">EC Private Key<td>CKA_CLASS |
| * <tr> <td>CKA_KEY_TYPE |
| * <tr> <td>CKA_TOKEN |
| * <tr> <td>CKA_LABEL |
| * <tr> <td>CKA_SIGN |
| * <tr> <td>CKA_EC_PARAMS |
| * <tr> <td>CKA_VALUE |
| * <tr><td rowspan="7">EC Public Key<td>CKA_CLASS |
| * <tr> <td>CKA_KEY_TYPE |
| * <tr> <td>CKA_TOKEN |
| * <tr> <td>CKA_VERIFY |
| * <tr> <td>CKA_LABEL |
| * <tr> <td>CKA_EC_PARAMS |
| * <tr> <td>CKA_EC_POINT |
| * <tr><td rowspan="13">RSA Private Key<td>CKA_CLASS |
| * <tr> <td>CKA_KEY_TYPE |
| * <tr> <td>CKA_TOKEN |
| * <tr> <td>CKA_LABEL |
| * <tr> <td>CKA_SIGN |
| * <tr> <td>CKA_MODULUS |
| * <tr> <td>CKA_PUBLIC_EXPONENT |
| * <tr> <td>CKA_PRIME_1 |
| * <tr> <td>CKA_PRIME_2 |
| * <tr> <td>CKA_PRIVATE_EXPONENT |
| * <tr> <td>CKA_EXPONENT_1 |
| * <tr> <td>CKA_EXPONENT_2 |
| * <tr> <td>CKA_COEFFICIENT |
| * </table> |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_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 = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| CK_OBJECT_CLASS xClass; |
| |
| if( ( NULL == pxTemplate ) || |
| ( NULL == pxObject ) ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| xResult = prvGetObjectClass( pxTemplate, ulCount, &xClass ); |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| switch( xClass ) |
| { |
| case CKO_CERTIFICATE: |
| xResult = prvCreateCertificate( pxTemplate, ulCount, pxObject ); |
| break; |
| |
| case CKO_PRIVATE_KEY: |
| xResult = prvCreatePrivateKey( pxTemplate, ulCount, pxObject ); |
| break; |
| |
| case CKO_PUBLIC_KEY: |
| xResult = prvCreatePublicKey( pxTemplate, ulCount, pxObject ); |
| break; |
| |
| default: |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| break; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Destroy an object. |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] xObject Handle of the object to be destroyed. |
| * |
| * \warn In this implementation, if either the device public key or the device |
| * private key (labels pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS and |
| * pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS) are deleted, both keys will |
| * be destroyed. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_DestroyObject )( CK_SESSION_HANDLE xSession, |
| CK_OBJECT_HANDLE xObject ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| |
| if( xResult == CKR_OK ) |
| { |
| xResult = PKCS11_PAL_DestroyObject( xObject ); |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Query the value of the specified cryptographic object attribute. |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] xObject PKCS #11 object handle to be queried. |
| * @param[in,out] pxTemplate Attribute template. |
| * pxTemplate.pValue should be set to the attribute |
| * to be queried. pxTemplate.ulValueLen should be |
| * set to the length of the buffer allocated at |
| * pxTemplate.pValue, and will be updated to contain |
| * the actual length of the data copied. |
| * pxTemplate.pValue should be set to point to |
| * a buffer to receive the attribute value data. |
| * If parameter length is unknown, |
| * pxTemplate.pValue may be set to NULL, and |
| * this function will set the required buffer length |
| * in pxTemplate.ulValueLen. |
| * @param[in] ulCount The number of attributes in the template. |
| * |
| * <table> |
| * <tr><th> Object Type <th> Queryable Attributes |
| * <tr><td rowspan="2">Certificate<td>CKA_CLASS |
| * <tr> <td>CKA_VALUE |
| * <tr><td rowspan="3">EC Private Key<td>CKA_CLASS |
| * <tr> <td>CKA_KEY_TYPE |
| * <tr> <td>CKA_EC_PARAMS |
| * <tr><td rowspan="4">EC Public Key<td>CKA_CLASS |
| * <tr> <td>CKA_KEY_TYPE |
| * <tr> <td>CKA_EC_PARAMS |
| * <tr> <td>CKA_EC_POINT |
| * <tr><td rowspan="2">RSA Private Key<td>CKA_CLASS |
| * <tr> <td>CKA_KEY_TYPE |
| * <tr><td rowspan="2">RSA Public Key<td>CKA_CLASS |
| * <tr> <td>CKA_KEY_TYPE |
| * </table> |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_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 = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| CK_BBOOL xIsPrivate = CK_TRUE; |
| CK_ULONG iAttrib; |
| mbedtls_pk_context xKeyContext = { 0 }; |
| mbedtls_pk_type_t xKeyType; |
| mbedtls_ecp_keypair * pxKeyPair; |
| CK_KEY_TYPE xPkcsKeyType = ( CK_KEY_TYPE ) ~0; |
| CK_OBJECT_CLASS xClass; |
| uint8_t * pxObjectValue = NULL; |
| uint32_t ulLength = 0; |
| uint8_t ucP256Oid[] = pkcs11DER_ENCODED_OID_P256; |
| int lMbedTLSResult = 0; |
| CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; |
| size_t xSize; |
| uint8_t * pcLabel = NULL; |
| |
| |
| if( ( NULL == pxTemplate ) || ( 0 == ulCount ) ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| /* |
| * Copy the object into a buffer. |
| */ |
| |
| prvFindObjectInListByHandle( xObject, &xPalHandle, &pcLabel, &xSize ); /*pcLabel and xSize are ignored. */ |
| |
| if( xPalHandle != CK_INVALID_HANDLE ) |
| { |
| xResult = PKCS11_PAL_GetObjectValue( xPalHandle, &pxObjectValue, &ulLength, &xIsPrivate ); |
| } |
| else |
| { |
| xResult = CKR_OBJECT_HANDLE_INVALID; |
| } |
| } |
| |
| /* Determine what kind of object we are dealing with. */ |
| if( xResult == CKR_OK ) |
| { |
| /* Is it a key? */ |
| mbedtls_pk_init( &xKeyContext ); |
| |
| if( 0 == mbedtls_pk_parse_key( &xKeyContext, pxObjectValue, ulLength, NULL, 0 ) ) |
| { |
| if( xIsPrivate ) |
| { |
| xClass = CKO_PRIVATE_KEY; |
| } |
| else |
| { |
| xClass = CKO_PUBLIC_KEY; |
| } |
| } |
| else if( 0 == mbedtls_pk_parse_public_key( &xKeyContext, pxObjectValue, ulLength ) ) |
| { |
| xClass = CKO_PUBLIC_KEY; |
| } |
| else |
| { |
| /* TODO: Do we want to safety parse the cert? |
| * Assume certificate. */ |
| xClass = CKO_CERTIFICATE; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| for( iAttrib = 0; iAttrib < ulCount && CKR_OK == xResult; iAttrib++ ) |
| { |
| switch( pxTemplate[ iAttrib ].type ) |
| { |
| case CKA_CLASS: |
| |
| if( pxTemplate[ iAttrib ].pValue == NULL ) |
| { |
| pxTemplate[ iAttrib ].ulValueLen = sizeof( CK_OBJECT_CLASS ); |
| } |
| else |
| { |
| if( pxTemplate[ iAttrib ].ulValueLen >= sizeof( CK_OBJECT_CLASS ) ) |
| { |
| memcpy( pxTemplate[ iAttrib ].pValue, &xClass, sizeof( CK_OBJECT_CLASS ) ); |
| } |
| else |
| { |
| xResult = CKR_BUFFER_TOO_SMALL; |
| } |
| } |
| |
| break; |
| |
| case CKA_VALUE: |
| |
| if( xIsPrivate == CK_TRUE ) |
| { |
| pxTemplate[ iAttrib ].ulValueLen = CK_UNAVAILABLE_INFORMATION; |
| xResult = CKR_ATTRIBUTE_SENSITIVE; |
| } |
| else |
| { |
| if( pxTemplate[ iAttrib ].pValue == NULL ) |
| { |
| pxTemplate[ iAttrib ].ulValueLen = ulLength; |
| } |
| else if( pxTemplate[ iAttrib ].ulValueLen < ulLength ) |
| { |
| xResult = CKR_BUFFER_TOO_SMALL; |
| } |
| else |
| { |
| memcpy( pxTemplate[ iAttrib ].pValue, pxObjectValue, ulLength ); |
| } |
| } |
| |
| break; |
| |
| case CKA_KEY_TYPE: |
| |
| if( pxTemplate[ iAttrib ].pValue == NULL ) |
| { |
| pxTemplate[ iAttrib ].ulValueLen = sizeof( CK_KEY_TYPE ); |
| } |
| else if( pxTemplate[ iAttrib ].ulValueLen < sizeof( CK_KEY_TYPE ) ) |
| { |
| xResult = CKR_BUFFER_TOO_SMALL; |
| } |
| else |
| { |
| if( 0 != xResult ) |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| else |
| { |
| xKeyType = mbedtls_pk_get_type( &xKeyContext ); |
| |
| switch( xKeyType ) |
| { |
| case MBEDTLS_PK_RSA: |
| case MBEDTLS_PK_RSA_ALT: |
| case MBEDTLS_PK_RSASSA_PSS: |
| xPkcsKeyType = CKK_RSA; |
| break; |
| |
| case MBEDTLS_PK_ECKEY: |
| case MBEDTLS_PK_ECKEY_DH: |
| xPkcsKeyType = CKK_EC; |
| break; |
| |
| case MBEDTLS_PK_ECDSA: |
| xPkcsKeyType = CKK_ECDSA; |
| break; |
| |
| default: |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| break; |
| } |
| |
| memcpy( pxTemplate[ iAttrib ].pValue, &xPkcsKeyType, sizeof( CK_KEY_TYPE ) ); |
| } |
| } |
| |
| break; |
| |
| case CKA_PRIVATE_EXPONENT: |
| |
| xResult = CKR_ATTRIBUTE_SENSITIVE; |
| |
| break; |
| |
| case CKA_EC_PARAMS: |
| |
| /* TODO: Add check that is key, is ec key. */ |
| |
| pxTemplate[ iAttrib ].ulValueLen = sizeof( ucP256Oid ); |
| |
| if( pxTemplate[ iAttrib ].pValue != NULL ) |
| { |
| if( pxTemplate[ iAttrib ].ulValueLen < sizeof( ucP256Oid ) ) |
| { |
| xResult = CKR_BUFFER_TOO_SMALL; |
| } |
| else |
| { |
| memcpy( pxTemplate[ iAttrib ].pValue, ucP256Oid, sizeof( ucP256Oid ) ); |
| } |
| } |
| |
| break; |
| |
| case CKA_EC_POINT: |
| |
| if( pxTemplate[ iAttrib ].pValue == NULL ) |
| { |
| pxTemplate[ iAttrib ].ulValueLen = 67; /* TODO: Is this large enough?*/ |
| } |
| else |
| { |
| pxKeyPair = ( mbedtls_ecp_keypair * ) xKeyContext.pk_ctx; |
| *( ( uint8_t * ) pxTemplate[ iAttrib ].pValue ) = 0x04; /* Mark the point as uncompressed. */ |
| lMbedTLSResult = mbedtls_ecp_tls_write_point( &pxKeyPair->grp, |
| &pxKeyPair->Q, |
| MBEDTLS_ECP_PF_UNCOMPRESSED, |
| &xSize, |
| ( uint8_t * ) pxTemplate[ iAttrib ].pValue + 1, |
| pxTemplate[ iAttrib ].ulValueLen - 1 ); |
| |
| if( lMbedTLSResult < 0 ) |
| { |
| if( lMbedTLSResult == MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ) |
| { |
| xResult = CKR_BUFFER_TOO_SMALL; |
| } |
| else |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| } |
| else |
| { |
| pxTemplate[ iAttrib ].ulValueLen = xSize + 1; |
| } |
| } |
| |
| break; |
| |
| default: |
| xResult = CKR_ATTRIBUTE_TYPE_INVALID; |
| } |
| } |
| |
| /* Free the buffer where object was stored. */ |
| PKCS11_PAL_GetObjectValueCleanup( pxObjectValue, ulLength ); |
| |
| /* Free the mbedTLS structure used to parse the key. */ |
| mbedtls_pk_free( &xKeyContext ); |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Initializes a search for an object by its label. |
| * |
| * \sa C_FindObjects() and C_FindObjectsFinal() which must be called |
| * after C_FindObjectsInit(). |
| * |
| * \note FindObjects parameters are shared by a session. Calling |
| * C_FindObjectsInit(), C_FindObjects(), and C_FindObjectsFinal() with the |
| * same session across different tasks may lead to unexpected results. |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pxTemplate Pointer to a template which specifies |
| * the object attributes to match. |
| * In this port, the only searchable attribute |
| * is object label. All other attributes will |
| * be ignored. |
| * @param[in] ulCount The number of attributes in pxTemplate. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_FindObjectsInit )( CK_SESSION_HANDLE xSession, |
| CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulCount ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); |
| CK_BYTE * pxFindObjectLabel = NULL; |
| uint32_t ulIndex; |
| CK_ATTRIBUTE xAttribute; |
| |
| if( NULL == pxTemplate ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( ( ulCount != 1 ) && ( ulCount != 2 ) ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| PKCS11_PRINT( ( "ERROR: Find objects does not support searching by %d attributes. \r\n", ulCount ) ); |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pxSession->pxFindObjectLabel != NULL ) |
| { |
| xResult = CKR_OPERATION_ACTIVE; |
| PKCS11_PRINT( ( "ERROR: Find object operation already in progress. \r\n" ) ); |
| } |
| } |
| |
| /* Malloc space to save template information. */ |
| if( xResult == CKR_OK ) |
| { |
| pxFindObjectLabel = pvPortMalloc( pxTemplate->ulValueLen + 1 ); /* Add 1 to guarantee null termination for PAL. */ |
| pxSession->pxFindObjectLabel = pxFindObjectLabel; |
| |
| if( pxFindObjectLabel != NULL ) |
| { |
| memset( pxFindObjectLabel, 0, pxTemplate->ulValueLen + 1 ); |
| } |
| else |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| } |
| |
| /* Search template for label. |
| * NOTE: This port only supports looking up objects by CKA_LABEL and all |
| * other search attributes are ignored. */ |
| if( xResult == CKR_OK ) |
| { |
| xResult = CKR_TEMPLATE_INCOMPLETE; |
| |
| for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) /* TODO: Re-evaluate the need for this for loop... we are making bad assumptions if 2 objects have the same label anyhow! */ |
| { |
| xAttribute = pxTemplate[ ulIndex ]; |
| |
| if( xAttribute.type == CKA_LABEL ) |
| { |
| memcpy( pxSession->pxFindObjectLabel, xAttribute.pValue, xAttribute.ulValueLen ); |
| xResult = CKR_OK; |
| } |
| else |
| { |
| PKCS11_WARNING_PRINT( ( "WARNING: Search parameters other than label are ignored.\r\n" ) ); |
| } |
| } |
| } |
| |
| /* Clean up memory if there was an error parsing the template. */ |
| if( xResult != CKR_OK ) |
| { |
| if( pxFindObjectLabel != NULL ) |
| { |
| vPortFree( pxFindObjectLabel ); |
| pxSession->pxFindObjectLabel = NULL; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Find an object. |
| * |
| * \sa C_FindObjectsInit() which must be called before calling C_FindObjects() |
| * and C_FindObjectsFinal(), which must be called after. |
| * |
| * \note FindObjects parameters are shared by a session. Calling |
| * C_FindObjectsInit(), C_FindObjects(), and C_FindObjectsFinal() with the |
| * same session across different tasks may lead to unexpected results. |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[out] pxObject Points to the handle of the object to |
| * be found. |
| * @param[in] ulMaxObjectCount The size of the pxObject object handle |
| * array. In this port, this value should |
| * always be set to 1, as searching for |
| * multiple objects is not supported. |
| * @param[out] pulObjectCount The actual number of objects that are |
| * found. In this port, if an object is found |
| * this value will be 1, otherwise if the |
| * object is not found, it will be set to 0. |
| * |
| * \note In the event that an object does not exist, CKR_OK will be returned, but |
| * pulObjectCount will be set to 0. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_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 = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| |
| BaseType_t xDone = pdFALSE; |
| P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); |
| |
| CK_BYTE_PTR pcObjectValue = NULL; |
| uint32_t xObjectLength = 0; |
| CK_BBOOL xIsPrivate = CK_TRUE; |
| CK_BYTE xByte = 0; |
| CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; |
| uint32_t ulIndex; |
| |
| /* |
| * Check parameters. |
| */ |
| if( ( NULL == pxObject ) || |
| ( NULL == pulObjectCount ) ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| xDone = pdTRUE; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pxSession->pxFindObjectLabel == NULL ) |
| { |
| xResult = CKR_OPERATION_NOT_INITIALIZED; |
| xDone = pdTRUE; |
| } |
| |
| if( 0u == ulMaxObjectCount ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| xDone = pdTRUE; |
| } |
| |
| if( 1u != ulMaxObjectCount ) |
| { |
| PKCS11_WARNING_PRINT( ( "WARN: Searching for more than 1 object not supported. \r\n" ) ); |
| } |
| |
| if( ( pdFALSE == xDone ) && ( ( CK_BBOOL ) CK_TRUE == pxSession->xFindObjectComplete ) ) |
| { |
| *pulObjectCount = 0; |
| xResult = CKR_OK; |
| xDone = pdTRUE; |
| } |
| } |
| |
| /* TODO: Re-inspect this previous logic. */ |
| if( ( pdFALSE == xDone ) ) |
| { |
| /* Try to find the object in module's list first. */ |
| prvFindObjectInListByLabel( pxSession->pxFindObjectLabel, strlen( ( const char * ) pxSession->pxFindObjectLabel ), &xPalHandle, pxObject ); |
| |
| /* Check with the PAL if the object was previously stored. */ |
| if( *pxObject == CK_INVALID_HANDLE ) |
| { |
| xPalHandle = PKCS11_PAL_FindObject( pxSession->pxFindObjectLabel, ( uint8_t ) strlen( ( const char * ) pxSession->pxFindObjectLabel ) ); |
| } |
| |
| if( xPalHandle != CK_INVALID_HANDLE ) |
| { |
| xResult = PKCS11_PAL_GetObjectValue( xPalHandle, &pcObjectValue, &xObjectLength, &xIsPrivate ); |
| |
| if( xResult == CKR_OK ) |
| { |
| for( ulIndex = 0; ulIndex < xObjectLength; ulIndex++ ) |
| { |
| xByte |= pcObjectValue[ ulIndex ]; |
| } |
| |
| if( xByte == 0 ) /* Deleted objects are overwritten completely w/ zero. */ |
| { |
| *pxObject = CK_INVALID_HANDLE; |
| } |
| else |
| { |
| xResult = prvAddObjectToList( xPalHandle, pxObject, pxSession->pxFindObjectLabel, strlen( ( const char * ) pxSession->pxFindObjectLabel ) ); |
| *pulObjectCount = 1; |
| } |
| |
| PKCS11_PAL_GetObjectValueCleanup( pcObjectValue, xObjectLength ); |
| } |
| } |
| else |
| { |
| /* Note: Objects living in header files are not destroyed. */ |
| /* According to the PKCS #11 standard, not finding an object results in a CKR_OK return value with an object count of 0. */ |
| *pulObjectCount = 0; |
| PKCS11_WARNING_PRINT( ( "WARN: Object with label '%s' not found. \r\n", ( char * ) pxSession->pxFindObjectLabel ) ); |
| } |
| } |
| |
| /* Clean up memory if there was an error finding the object. */ |
| if( xResult != CKR_OK ) |
| { |
| if( pxSession->pxFindObjectLabel != NULL ) |
| { |
| vPortFree( pxSession->pxFindObjectLabel ); |
| pxSession->pxFindObjectLabel = NULL; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Completes an object search operation. |
| * |
| * \sa C_FindObjectsInit(), C_FindObjects() which must be called before |
| * calling C_FindObjectsFinal(). |
| * |
| * \note FindObjects parameters are shared by a session. Calling |
| * C_FindObjectsInit(), C_FindObjects(), and C_FindObjectsFinal() with the |
| * same session across different tasks may lead to unexpected results. |
| * |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_FindObjectsFinal )( CK_SESSION_HANDLE xSession ) |
| { /*lint !e9072 It's OK to have different parameter name. */ |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| |
| P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); |
| |
| /* |
| * Check parameters. |
| */ |
| if( xResult == CKR_OK ) |
| { |
| if( pxSession->pxFindObjectLabel == NULL ) |
| { |
| xResult = CKR_OPERATION_NOT_INITIALIZED; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| /* |
| * Clean-up find objects state. |
| */ |
| vPortFree( pxSession->pxFindObjectLabel ); |
| pxSession->pxFindObjectLabel = NULL; |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Begins a digest (hash) operation. |
| * |
| * \sa C_DigestUpdate(), C_DigestFinal() |
| * |
| * \note Digest parameters are shared by a session. Calling |
| * C_DigestInit(), C_DigestUpdate(), and C_DigestFinal() with the |
| * same session across different tasks may lead to unexpected results. |
| * |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pMechanism Digesting mechanism. This port only supports |
| * the mechanism CKM_SHA256. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_DigestInit )( CK_SESSION_HANDLE xSession, |
| CK_MECHANISM_PTR pMechanism ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); |
| |
| if( pMechanism == NULL ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pMechanism->mechanism != CKM_SHA256 ) |
| { |
| xResult = CKR_MECHANISM_INVALID; |
| } |
| } |
| |
| /* |
| * Initialize the requested hash type |
| */ |
| if( xResult == CKR_OK ) |
| { |
| mbedtls_sha256_init( &pxSession->xSHA256Context ); |
| |
| if( 0 != mbedtls_sha256_starts_ret( &pxSession->xSHA256Context, 0 ) ) |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| else |
| { |
| pxSession->xOperationInProgress = pMechanism->mechanism; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| |
| /** |
| * @brief Continues a multi-part digest (hash) operation. |
| * |
| * \sa C_DigestInit(), C_DigestFinal() |
| * |
| * \note Digest parameters are shared by a session. Calling |
| * C_DigestInit(), C_DigestUpdate(), and C_DigestFinal() with the |
| * same session across different tasks may lead to unexpected results. |
| * |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pPart Pointer to the data to be added to the digest. |
| * @param[in] ulPartLen Length of the data located at pPart. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_DigestUpdate )( CK_SESSION_HANDLE xSession, |
| CK_BYTE_PTR pPart, |
| CK_ULONG ulPartLen ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); |
| |
| if( pPart == NULL ) |
| { |
| PKCS11_PRINT( ( "ERROR: Null digest mechanism provided. \r\n" ) ); |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pxSession->xOperationInProgress != CKM_SHA256 ) |
| { |
| xResult = CKR_OPERATION_NOT_INITIALIZED; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( 0 != mbedtls_sha256_update_ret( &pxSession->xSHA256Context, pPart, ulPartLen ) ) |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| pxSession->xOperationInProgress = pkcs11NO_OPERATION; |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Complete a multi-part digest (hash) operation. |
| * |
| * \sa C_DigestInit(), C_DigestUpdate() |
| * |
| * \note Digest parameters are shared by a session. Calling |
| * C_DigestInit(), C_DigestUpdate(), and C_DigestFinal() with the |
| * same session across different tasks may lead to unexpected results. |
| * |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[out] pDigest Pointer to the location that receives |
| * the message digest. Memory must be allocated |
| * by the caller. Caller is responsible for allocating memory. |
| * Providing NULL for this input will cause |
| * pulDigestLen to be updated for length of |
| * buffer required. |
| * @param[in,out] pulDigestLen Points to the location that holds the length |
| * of the message digest. If pDigest is NULL, |
| * this value is updated to contain the length |
| * of the buffer needed to hold the digest. Else |
| * it is updated to contain the actual length of |
| * the digest placed in pDigest. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_DigestFinal )( CK_SESSION_HANDLE xSession, |
| CK_BYTE_PTR pDigest, |
| CK_ULONG_PTR pulDigestLen ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| |
| P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); |
| |
| if( pulDigestLen == NULL ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pxSession->xOperationInProgress != CKM_SHA256 ) |
| { |
| xResult = CKR_OPERATION_NOT_INITIALIZED; |
| pxSession->xOperationInProgress = pkcs11NO_OPERATION; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pDigest == NULL ) |
| { |
| /* Supply the required buffer size. */ |
| *pulDigestLen = pkcs11SHA256_DIGEST_LENGTH; |
| } |
| else |
| { |
| if( *pulDigestLen < pkcs11SHA256_DIGEST_LENGTH ) |
| { |
| xResult = CKR_BUFFER_TOO_SMALL; |
| } |
| else |
| { |
| if( 0 != mbedtls_sha256_finish_ret( &pxSession->xSHA256Context, pDigest ) ) |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| |
| pxSession->xOperationInProgress = pkcs11NO_OPERATION; |
| } |
| } |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Begin creating a digital signature. |
| * |
| * \sa C_Sign() completes signatures initiated by C_SignInit(). |
| * |
| * \note C_Sign() parameters are shared by a session. Calling |
| * C_SignInit() & C_Sign() with the same session across different |
| * tasks may lead to unexpected results. |
| * |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pxMechanism Mechanism used to sign. |
| * This port supports the following mechanisms: |
| * - CKM_RSA_PKCS for RSA signatures |
| * - CKM_ECDSA for elliptic curve signatures |
| * Note that neither of these mechanisms perform |
| * hash operations. |
| * @param[in] xKey The handle of the private key to be used for |
| * signature. Key must be compatible with the |
| * mechanism chosen by pxMechanism. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_SignInit )( CK_SESSION_HANDLE xSession, |
| CK_MECHANISM_PTR pxMechanism, |
| CK_OBJECT_HANDLE xKey ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| CK_BBOOL xIsPrivate = CK_TRUE; |
| CK_BBOOL xCleanupNeeded = CK_FALSE; |
| CK_OBJECT_HANDLE xPalHandle; |
| uint8_t * pxLabel = NULL; |
| size_t xLabelLength = 0; |
| mbedtls_pk_type_t xKeyType; |
| |
| /*lint !e9072 It's OK to have different parameter name. */ |
| P11SessionPtr_t pxSession = prvSessionPointerFromHandle( xSession ); |
| uint8_t * keyData = NULL; |
| uint32_t ulKeyDataLength = 0; |
| |
| if( NULL == pxMechanism ) |
| { |
| PKCS11_PRINT( ( "ERROR: Null signing mechanism provided. \r\n" ) ); |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| /* Retrieve key value from storage. */ |
| if( xResult == CKR_OK ) |
| { |
| prvFindObjectInListByHandle( xKey, |
| &xPalHandle, |
| &pxLabel, |
| &xLabelLength ); |
| |
| if( xPalHandle != CK_INVALID_HANDLE ) |
| { |
| xResult = PKCS11_PAL_GetObjectValue( xPalHandle, &keyData, &ulKeyDataLength, &xIsPrivate ); |
| |
| if( xResult == CKR_OK ) |
| { |
| xCleanupNeeded = CK_TRUE; |
| } |
| else |
| { |
| PKCS11_PRINT( ( "ERROR: Unable to retrieve value of private key for signing %d. \r\n", xResult ) ); |
| } |
| } |
| else |
| { |
| xResult = CKR_KEY_HANDLE_INVALID; |
| } |
| } |
| |
| /* Check that a private key was retrieved. */ |
| if( xResult == CKR_OK ) |
| { |
| if( xIsPrivate != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Sign operation attempted with public key. \r\n" ) ); |
| xResult = CKR_KEY_TYPE_INCONSISTENT; |
| } |
| } |
| |
| /* Convert the private key from storage format to mbedTLS usable format. */ |
| if( xResult == CKR_OK ) |
| { |
| /* Grab the sign mutex. This ensures that no signing operation |
| * is underway on another thread where modification of key would lead to hard fault.*/ |
| if( pdTRUE == xSemaphoreTake( pxSession->xSignMutex, portMAX_DELAY ) ) |
| { |
| /* Free the private key context if it exists. |
| * TODO: Check if the key is the same as was used previously. */ |
| if( NULL != pxSession->xSignKey.pk_ctx ) |
| { |
| mbedtls_pk_free( &pxSession->xSignKey ); |
| } |
| |
| mbedtls_pk_init( &pxSession->xSignKey ); |
| |
| if( 0 != mbedtls_pk_parse_key( &pxSession->xSignKey, keyData, ulKeyDataLength, NULL, 0 ) ) |
| { |
| PKCS11_PRINT( ( "ERROR: Unable to parse private key for signing. \r\n" ) ); |
| xResult = CKR_KEY_HANDLE_INVALID; |
| } |
| |
| xSemaphoreGive( pxSession->xSignMutex ); |
| } |
| else |
| { |
| xResult = CKR_CANT_LOCK; |
| } |
| } |
| |
| /* Key has been parsed into mbedTLS pk structure. |
| * Free the memory allocated to copy the key out of flash. */ |
| if( xCleanupNeeded == CK_TRUE ) |
| { |
| PKCS11_PAL_GetObjectValueCleanup( keyData, ulKeyDataLength ); |
| } |
| |
| /* Check that the mechanism and key type are compatible, supported. */ |
| if( xResult == CKR_OK ) |
| { |
| xKeyType = mbedtls_pk_get_type( &pxSession->xSignKey ); |
| |
| if( pxMechanism->mechanism == CKM_RSA_PKCS ) |
| { |
| if( xKeyType != MBEDTLS_PK_RSA ) |
| { |
| PKCS11_PRINT( ( "ERROR: Signing key type (%d) does not match RSA mechanism \r\n", xKeyType ) ); |
| xResult = CKR_KEY_TYPE_INCONSISTENT; |
| } |
| } |
| else if( pxMechanism->mechanism == CKM_ECDSA ) |
| { |
| if( ( xKeyType != MBEDTLS_PK_ECDSA ) && ( xKeyType != MBEDTLS_PK_ECKEY ) ) |
| { |
| PKCS11_PRINT( ( "ERROR: Signing key type (%d) does not match ECDSA mechanism \r\n", xKeyType ) ); |
| xResult = CKR_KEY_TYPE_INCONSISTENT; |
| } |
| } |
| else |
| { |
| PKCS11_PRINT( ( "ERROR: Unsupported mechanism type %d \r\n", pxMechanism->mechanism ) ); |
| xResult = CKR_MECHANISM_INVALID; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| pxSession->xSignMechanism = pxMechanism->mechanism; |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Performs a digital signature operation. |
| * |
| * \sa C_SignInit() initiates signatures signature creation. |
| * |
| * \note C_Sign() parameters are shared by a session. Calling |
| * C_SignInit() & C_Sign() with the same session across different |
| * tasks may lead to unexpected results. |
| * |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pucData Data to be signed. |
| * Note: Some applications may require this data to |
| * be hashed before passing to C_Sign(). |
| * @param[in] ulDataLen Length of pucData, in bytes. |
| * @param[out] pucSignature Buffer where signature will be placed. |
| * Caller is responsible for allocating memory. |
| * Providing NULL for this input will cause |
| * pulSignatureLen to be updated for length of |
| * buffer required. |
| * @param[in,out] pulSignatureLen Length of pucSignature buffer. |
| * If pucSignature is non-NULL, pulSignatureLen is |
| * updated to contain the actual signature length. |
| * If pucSignature is NULL, pulSignatureLen is |
| * updated to the buffer length required for signature |
| * data. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_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 = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| P11SessionPtr_t pxSessionObj = prvSessionPointerFromHandle( xSession ); |
| CK_ULONG xSignatureLength = 0; |
| CK_ULONG xExpectedInputLength = 0; |
| CK_BYTE_PTR pxSignatureBuffer = pucSignature; |
| CK_BBOOL xSignatureGenerated = CK_FALSE; |
| uint8_t ecSignature[ pkcs11ECDSA_P256_SIGNATURE_LENGTH + 15 ]; /*TODO: Figure out this length. */ |
| int lMbedTLSResult; |
| |
| if( ( NULL == pulSignatureLen ) || ( NULL == pucData ) ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( CKR_OK == xResult ) |
| { |
| /* Update the signature length. */ |
| |
| if( pxSessionObj->xSignMechanism == CKM_RSA_PKCS ) |
| { |
| xSignatureLength = pkcs11RSA_2048_SIGNATURE_LENGTH; |
| xExpectedInputLength = pkcs11RSA_SIGNATURE_INPUT_LENGTH; |
| } |
| else if( pxSessionObj->xSignMechanism == CKM_ECDSA ) |
| { |
| xSignatureLength = pkcs11ECDSA_P256_SIGNATURE_LENGTH; |
| xExpectedInputLength = pkcs11SHA256_DIGEST_LENGTH; |
| pxSignatureBuffer = ecSignature; |
| } |
| else |
| { |
| xResult = CKR_OPERATION_NOT_INITIALIZED; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| /* Calling application is trying to determine length needed for signature buffer. */ |
| if( NULL != pucSignature ) |
| { |
| /* Check that the signature buffer is long enough. */ |
| if( *pulSignatureLen < xSignatureLength ) |
| { |
| xResult = CKR_BUFFER_TOO_SMALL; |
| } |
| |
| /* Check that input data to be signed is the expected length. */ |
| if( CKR_OK == xResult ) |
| { |
| if( xExpectedInputLength != ulDataLen ) |
| { |
| xResult = CKR_DATA_LEN_RANGE; |
| } |
| } |
| |
| /* Sign the data.*/ |
| if( CKR_OK == xResult ) |
| { |
| if( pdTRUE == xSemaphoreTake( pxSessionObj->xSignMutex, portMAX_DELAY ) ) |
| { |
| lMbedTLSResult = mbedtls_pk_sign( &pxSessionObj->xSignKey, |
| MBEDTLS_MD_NONE, |
| pucData, |
| ulDataLen, |
| pxSignatureBuffer, |
| ( size_t * ) &xExpectedInputLength, |
| mbedtls_ctr_drbg_random, |
| &xP11Context.xMbedDrbgCtx ); |
| |
| if( lMbedTLSResult != CKR_OK ) |
| { |
| PKCS11_PRINT( ( "mbedTLS sign failed with error %d \r\n", lMbedTLSResult ) ); |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| |
| xSemaphoreGive( pxSessionObj->xSignMutex ); |
| xSignatureGenerated = CK_TRUE; |
| } |
| else |
| { |
| xResult = CKR_CANT_LOCK; |
| } |
| } |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| /* If this an EC signature, reformat from ASN.1 encoded to 64-byte R & S components */ |
| if( ( pxSessionObj->xSignMechanism == CKM_ECDSA ) && ( xSignatureGenerated == CK_TRUE ) ) |
| { |
| lMbedTLSResult = PKI_mbedTLSSignatureToPkcs11Signature( pucSignature, ecSignature ); |
| |
| if( lMbedTLSResult != 0 ) |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| } |
| } |
| |
| if( ( xResult == CKR_OK ) || ( xResult == CKR_BUFFER_TOO_SMALL ) ) |
| { |
| *pulSignatureLen = xSignatureLength; |
| } |
| |
| /* Complete the operation in the context. */ |
| if( xResult != CKR_BUFFER_TOO_SMALL ) |
| { |
| pxSessionObj->xSignMechanism = pkcs11NO_OPERATION; |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Begin a digital signature verification. |
| * |
| * \sa C_Verify() completes verifications initiated by C_VerifyInit(). |
| * |
| * \note C_Verify() parameters are shared by a session. Calling |
| * C_VerifyInit() & C_Verify() with the same session across different |
| * tasks may lead to unexpected results. |
| * |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pxMechanism Mechanism used to verify signature. |
| * This port supports the following mechanisms: |
| * - CKM_RSA_X_509 for RSA verifications |
| * - CKM_ECDSA for elliptic curve verifications |
| * @param[in] xKey The handle of the public key to be used for |
| * verification. Key must be compatible with the |
| * mechanism chosen by pxMechanism. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_VerifyInit )( CK_SESSION_HANDLE xSession, |
| CK_MECHANISM_PTR pxMechanism, |
| CK_OBJECT_HANDLE xKey ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| CK_BBOOL xIsPrivate = CK_TRUE; |
| P11SessionPtr_t pxSession; |
| uint8_t * keyData = NULL; |
| uint32_t ulKeyDataLength = 0; |
| CK_BBOOL xCleanupNeeded = CK_FALSE; |
| mbedtls_pk_type_t xKeyType; |
| CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; |
| uint8_t * pxLabel = NULL; |
| size_t xLabelLength = 0; |
| |
| pxSession = prvSessionPointerFromHandle( xSession ); |
| |
| if( NULL == pxMechanism ) |
| { |
| PKCS11_PRINT( ( "ERROR: Null verification mechanism provided. \r\n" ) ); |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| /* Retrieve key value from storage. */ |
| if( xResult == CKR_OK ) |
| { |
| prvFindObjectInListByHandle( xKey, |
| &xPalHandle, |
| &pxLabel, |
| &xLabelLength ); |
| |
| if( xPalHandle != CK_INVALID_HANDLE ) |
| { |
| xResult = PKCS11_PAL_GetObjectValue( xPalHandle, &keyData, &ulKeyDataLength, &xIsPrivate ); |
| |
| if( xResult == CKR_OK ) |
| { |
| xCleanupNeeded = CK_TRUE; |
| } |
| else |
| { |
| PKCS11_PRINT( ( "ERROR: Unable to retrieve value of private key for signing %d. \r\n", xResult ) ); |
| } |
| } |
| else |
| { |
| xResult = CKR_KEY_HANDLE_INVALID; |
| } |
| } |
| |
| /* Check that a public key was retrieved. */ |
| if( xResult == CKR_OK ) |
| { |
| if( xIsPrivate != CK_FALSE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Verify operation attempted with private key. \r\n" ) ); |
| xResult = CKR_KEY_TYPE_INCONSISTENT; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pdTRUE == xSemaphoreTake( pxSession->xVerifyMutex, portMAX_DELAY ) ) |
| { |
| /* Free the public key context if it exists. |
| * TODO: Check if the key is the same as used by last verify operation. */ |
| if( NULL != pxSession->xVerifyKey.pk_ctx ) |
| { |
| mbedtls_pk_free( &pxSession->xVerifyKey ); |
| } |
| |
| mbedtls_pk_init( &pxSession->xVerifyKey ); |
| |
| if( 0 != mbedtls_pk_parse_public_key( &pxSession->xVerifyKey, keyData, ulKeyDataLength ) ) |
| { |
| if( 0 != mbedtls_pk_parse_key( &pxSession->xVerifyKey, keyData, ulKeyDataLength, NULL, 0 ) ) |
| { |
| PKCS11_PRINT( ( "ERROR: Unable to parse public key for verification. \r\n" ) ); |
| xResult = CKR_KEY_HANDLE_INVALID; |
| } |
| } |
| |
| xSemaphoreGive( pxSession->xVerifyMutex ); |
| } |
| else |
| { |
| xResult = CKR_CANT_LOCK; |
| } |
| } |
| |
| if( xCleanupNeeded == CK_TRUE ) |
| { |
| PKCS11_PAL_GetObjectValueCleanup( keyData, ulKeyDataLength ); |
| } |
| |
| /* Check that the mechanism and key type are compatible, supported. */ |
| if( xResult == CKR_OK ) |
| { |
| xKeyType = mbedtls_pk_get_type( &pxSession->xSignKey ); |
| |
| if( pxMechanism->mechanism == CKM_RSA_X_509 ) |
| { |
| if( xKeyType != MBEDTLS_PK_RSA ) |
| { |
| PKCS11_PRINT( ( "ERROR: Verification key type (%d) does not match RSA mechanism \r\n", xKeyType ) ); |
| xResult = CKR_KEY_TYPE_INCONSISTENT; |
| } |
| } |
| else if( pxMechanism->mechanism == CKM_ECDSA ) |
| { |
| if( ( xKeyType != MBEDTLS_PK_ECDSA ) && ( xKeyType != MBEDTLS_PK_ECKEY ) ) |
| { |
| PKCS11_PRINT( ( "ERROR: Verification key type (%d) does not match ECDSA mechanism \r\n", xKeyType ) ); |
| xResult = CKR_KEY_TYPE_INCONSISTENT; |
| } |
| } |
| else |
| { |
| PKCS11_PRINT( ( "ERROR: Unsupported mechanism type %d \r\n", pxMechanism->mechanism ) ); |
| xResult = CKR_MECHANISM_INVALID; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| pxSession->xVerifyMechanism = pxMechanism->mechanism; |
| } |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Verifies a digital signature. |
| * |
| * \note C_VerifyInit() must have been called previously. |
| * |
| * \note C_Verify() parameters are shared by a session. Calling |
| * C_VerifyInit() & C_Verify() with the same session across different |
| * tasks may lead to unexpected results. |
| * |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pucData Data who's signature is to be verified. |
| * Note: In this implementation, this is generally |
| * expected to be the hash of the data. |
| * @param[in] ulDataLen Length of pucData. |
| * @param[in] pucSignature The signature to be verified. |
| * @param[in] ulSignatureLength Length of pucSignature in bytes. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_Verify )( CK_SESSION_HANDLE xSession, |
| CK_BYTE_PTR pucData, |
| CK_ULONG ulDataLen, |
| CK_BYTE_PTR pucSignature, |
| CK_ULONG ulSignatureLen ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| P11SessionPtr_t pxSessionObj; |
| int lMbedTLSResult; |
| |
| pxSessionObj = prvSessionPointerFromHandle( xSession ); /*lint !e9072 It's OK to have different parameter name. */ |
| |
| /* Check parameters. */ |
| if( ( NULL == pucData ) || |
| ( NULL == pucSignature ) ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| /* Check that the signature and data are the expected length. |
| * These PKCS #11 mechanism expect data to be pre-hashed/formatted. */ |
| if( xResult == CKR_OK ) |
| { |
| if( pxSessionObj->xVerifyMechanism == CKM_RSA_X_509 ) |
| { |
| if( ulDataLen != pkcs11RSA_2048_SIGNATURE_LENGTH ) |
| { |
| xResult = CKR_DATA_LEN_RANGE; |
| } |
| |
| if( ulSignatureLen != pkcs11RSA_2048_SIGNATURE_LENGTH ) |
| { |
| xResult = CKR_SIGNATURE_LEN_RANGE; |
| } |
| } |
| else if( pxSessionObj->xVerifyMechanism == CKM_ECDSA ) |
| { |
| if( ulDataLen != pkcs11SHA256_DIGEST_LENGTH ) |
| { |
| xResult = CKR_DATA_LEN_RANGE; |
| } |
| |
| if( ulSignatureLen != pkcs11ECDSA_P256_SIGNATURE_LENGTH ) |
| { |
| xResult = CKR_SIGNATURE_LEN_RANGE; |
| } |
| } |
| else |
| { |
| xResult = CKR_OPERATION_NOT_INITIALIZED; |
| } |
| } |
| |
| /* Verification step. */ |
| if( xResult == CKR_OK ) |
| { |
| /* Perform an RSA verification. */ |
| if( pxSessionObj->xVerifyMechanism == CKM_RSA_X_509 ) |
| { |
| if( pdTRUE == xSemaphoreTake( pxSessionObj->xVerifyMutex, portMAX_DELAY ) ) |
| { |
| /* Verify the signature. If a public key is present, use it. */ |
| if( NULL != pxSessionObj->xVerifyKey.pk_ctx ) |
| { |
| if( 0 != mbedtls_pk_verify( &pxSessionObj->xVerifyKey, |
| MBEDTLS_MD_SHA256, |
| pucData, |
| ulDataLen, |
| pucSignature, |
| ulSignatureLen ) ) |
| { |
| xResult = CKR_SIGNATURE_INVALID; |
| } |
| } |
| |
| xSemaphoreGive( pxSessionObj->xVerifyMutex ); |
| } |
| else |
| { |
| xResult = CKR_CANT_LOCK; |
| } |
| } |
| |
| /* Perform an ECDSA verification. */ |
| else if( pxSessionObj->xVerifyMechanism == CKM_ECDSA ) |
| { |
| /* TODO: Refactor w/ test code |
| * An ECDSA signature is comprised of 2 components - R & S. C_Sign returns them one after another. */ |
| mbedtls_ecdsa_context * pxEcdsaContext; |
| mbedtls_mpi xR; |
| mbedtls_mpi xS; |
| mbedtls_mpi_init( &xR ); |
| mbedtls_mpi_init( &xS ); |
| lMbedTLSResult = mbedtls_mpi_read_binary( &xR, &pucSignature[ 0 ], 32 ); |
| lMbedTLSResult |= mbedtls_mpi_read_binary( &xS, &pucSignature[ 32 ], 32 ); |
| |
| if( lMbedTLSResult != 0 ) |
| { |
| xResult = CKR_SIGNATURE_INVALID; |
| PKCS11_PRINT( ( "Failed to parse EC signature: %d \r\n", lMbedTLSResult ) ); |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pdTRUE == xSemaphoreTake( pxSessionObj->xVerifyMutex, portMAX_DELAY ) ) |
| { |
| /* Verify the signature. If a public key is present, use it. */ |
| if( NULL != pxSessionObj->xVerifyKey.pk_ctx ) |
| { |
| pxEcdsaContext = pxSessionObj->xVerifyKey.pk_ctx; |
| lMbedTLSResult = mbedtls_ecdsa_verify( &pxEcdsaContext->grp, pucData, ulDataLen, &pxEcdsaContext->Q, &xR, &xS ); |
| } |
| |
| xSemaphoreGive( pxSessionObj->xVerifyMutex ); |
| |
| if( lMbedTLSResult != 0 ) |
| { |
| xResult = CKR_SIGNATURE_INVALID; |
| PKCS11_PRINT( ( "Failed to parse EC signature: %d \r\n", lMbedTLSResult ) ); |
| } |
| } |
| } |
| |
| mbedtls_mpi_free( &xR ); |
| mbedtls_mpi_free( &xS ); |
| } |
| } |
| |
| /* Return the signature verification result. */ |
| return xResult; |
| } |
| |
| |
| /* Checks that the private key template provided for C_GenerateKeyPair |
| * contains all necessary attributes, and does not contain any invalid |
| * attributes. */ |
| CK_RV prvCheckGenerateKeyPairPrivateTemplate( CK_ATTRIBUTE_PTR * ppxLabel, |
| CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulTemplateLength ) |
| { |
| CK_ATTRIBUTE xAttribute; |
| CK_RV xResult = CKR_OK; |
| CK_BBOOL xBool; |
| CK_ULONG xTemp; |
| CK_ULONG xIndex; |
| uint32_t xAttributeMap = 0; |
| uint32_t xRequiredAttributeMap = ( LABEL_IN_TEMPLATE | PRIVATE_IN_TEMPLATE | SIGN_IN_TEMPLATE ); |
| |
| for( xIndex = 0; xIndex < ulTemplateLength; xIndex++ ) |
| { |
| xAttribute = pxTemplate[ xIndex ]; |
| |
| switch( xAttribute.type ) |
| { |
| case ( CKA_LABEL ): |
| *ppxLabel = &pxTemplate[ xIndex ]; |
| xAttributeMap |= LABEL_IN_TEMPLATE; |
| break; |
| |
| case ( CKA_TOKEN ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only token key generation is supported. \r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| case ( CKA_KEY_TYPE ): |
| memcpy( &xTemp, xAttribute.pValue, sizeof( CK_ULONG ) ); |
| |
| if( xTemp != CKK_EC ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only EC key pair generation is supported. \r\n" ) ); |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| } |
| |
| break; |
| |
| case ( CKA_PRIVATE ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Generating private keys that are not marked private is not supported. \r\n" ) ); |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| } |
| |
| xAttributeMap |= PRIVATE_IN_TEMPLATE; |
| break; |
| |
| case ( CKA_SIGN ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Generating private keys that cannot sign is not supported. \r\n" ) ); |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| } |
| |
| xAttributeMap |= SIGN_IN_TEMPLATE; |
| break; |
| |
| default: |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| break; |
| } |
| } |
| |
| if( ( xAttributeMap & xRequiredAttributeMap ) != xRequiredAttributeMap ) |
| { |
| xResult = CKR_TEMPLATE_INCOMPLETE; |
| } |
| |
| return xResult; |
| } |
| |
| /* Checks that the public key template provided for C_GenerateKeyPair |
| * contains all necessary attributes, and does not contain any invalid |
| * attributes. */ |
| CK_RV prvCheckGenerateKeyPairPublicTemplate( CK_ATTRIBUTE_PTR * ppxLabel, |
| CK_ATTRIBUTE_PTR pxTemplate, |
| CK_ULONG ulTemplateLength ) |
| { |
| CK_ATTRIBUTE xAttribute; |
| CK_RV xResult = CKR_OK; |
| CK_BBOOL xBool; |
| CK_KEY_TYPE xKeyType; |
| CK_BYTE xEcParams[] = pkcs11DER_ENCODED_OID_P256; |
| int lCompare; |
| CK_ULONG ulIndex; |
| uint32_t xAttributeMap = 0; |
| uint32_t xRequiredAttributeMap = ( LABEL_IN_TEMPLATE | EC_PARAMS_IN_TEMPLATE | VERIFY_IN_TEMPLATE ); |
| |
| for( ulIndex = 0; ulIndex < ulTemplateLength; ulIndex++ ) |
| { |
| xAttribute = pxTemplate[ ulIndex ]; |
| |
| switch( xAttribute.type ) |
| { |
| case ( CKA_LABEL ): |
| |
| *ppxLabel = &pxTemplate[ ulIndex ]; |
| xAttributeMap |= LABEL_IN_TEMPLATE; |
| break; |
| |
| case ( CKA_KEY_TYPE ): |
| memcpy( &xKeyType, xAttribute.pValue, sizeof( CK_KEY_TYPE ) ); |
| |
| if( xKeyType != CKK_EC ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only EC key pair generation is supported. \r\n" ) ); |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| } |
| |
| break; |
| |
| case ( CKA_EC_PARAMS ): |
| lCompare = memcmp( xEcParams, xAttribute.pValue, sizeof( xEcParams ) ); |
| |
| if( lCompare != 0 ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only P-256 key generation is supported. \r\n" ) ); |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| } |
| |
| xAttributeMap |= EC_PARAMS_IN_TEMPLATE; |
| break; |
| |
| case ( CKA_VERIFY ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Generating public keys that cannot verify is not supported. \r\n" ) ); |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| } |
| |
| xAttributeMap |= VERIFY_IN_TEMPLATE; |
| break; |
| |
| case ( CKA_TOKEN ): |
| memcpy( &xBool, xAttribute.pValue, sizeof( CK_BBOOL ) ); |
| |
| if( xBool != CK_TRUE ) |
| { |
| PKCS11_PRINT( ( "ERROR: Only token key generation is supported. \r\n" ) ); |
| xResult = CKR_ATTRIBUTE_VALUE_INVALID; |
| } |
| |
| break; |
| |
| default: |
| xResult = CKR_TEMPLATE_INCONSISTENT; |
| break; |
| } |
| } |
| |
| if( ( xAttributeMap & xRequiredAttributeMap ) != xRequiredAttributeMap ) |
| { |
| xResult = CKR_TEMPLATE_INCOMPLETE; |
| } |
| |
| return xResult; |
| } |
| |
| |
| /** |
| * @brief Generate a new public-private key pair. |
| * |
| * This port only supports generating elliptic curve P-256 |
| * key pairs. |
| * |
| * @param[in] xSession Handle of a valid PKCS #11 session. |
| * @param[in] pxMechanism Pointer to a mechanism. At this time, |
| * CKM_EC_KEY_PAIR_GEN is the only supported mechanism. |
| * @param[in] pxPublicKeyTemplate Pointer to a list of attributes that the generated |
| * public key should possess. |
| * Public key template must have the following attributes: |
| * - CKA_LABEL |
| * - Label should be no longer than #pkcs11configMAX_LABEL_LENGTH |
| * and must be supported by port's PKCS #11 PAL. |
| * - CKA_EC_PARAMS |
| * - Must equal pkcs11DER_ENCODED_OID_P256. |
| * Only P-256 keys are supported. |
| * - CKA_VERIFY |
| * - Must be set to true. Only public keys used |
| * for verification are supported. |
| * Public key templates may have the following attributes: |
| * - CKA_KEY_TYPE |
| * - Must be set to CKK_EC. Only elliptic curve key |
| * generation is supported. |
| * - CKA_TOKEN |
| * - Must be set to CK_TRUE. |
| * @param[in] ulPublicKeyAttributeCount Number of attributes in pxPublicKeyTemplate. |
| * @param[in] pxPrivateKeyTemplate Pointer to a list of attributes that the generated |
| * private key should possess. |
| * Private key template must have the following attributes: |
| * - CKA_LABEL |
| * - Label should be no longer than #pkcs11configMAX_LABEL_LENGTH |
| * and must be supported by port's PKCS #11 PAL. |
| * - CKA_PRIVATE |
| * - Must be set to true. |
| * - CKA_SIGN |
| * - Must be set to true. Only private keys used |
| * for signing are supported. |
| * Private key template may have the following attributes: |
| * - CKA_KEY_TYPE |
| * - Must be set to CKK_EC. Only elliptic curve key |
| * generation is supported. |
| * - CKA_TOKEN |
| * - Must be set to CK_TRUE. |
| * |
| * @param[in] ulPrivateKeyAttributeCount Number of attributes in pxPrivateKeyTemplate. |
| * @param[out] pxPublicKey Pointer to the handle of the public key to be created. |
| * @param[out] pxPrivateKey Pointer to the handle of the private key to be created. |
| * |
| * \note Not all attributes specified by the PKCS #11 standard are supported. |
| * \note CKA_LOCAL attribute is not supported. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_GenerateKeyPair )( CK_SESSION_HANDLE xSession, |
| CK_MECHANISM_PTR pxMechanism, |
| CK_ATTRIBUTE_PTR pxPublicKeyTemplate, |
| CK_ULONG ulPublicKeyAttributeCount, |
| CK_ATTRIBUTE_PTR pxPrivateKeyTemplate, |
| CK_ULONG ulPrivateKeyAttributeCount, |
| CK_OBJECT_HANDLE_PTR pxPublicKey, |
| CK_OBJECT_HANDLE_PTR pxPrivateKey ) |
| { |
| CK_RV xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| uint8_t * pucDerFile = pvPortMalloc( pkcs11KEY_GEN_MAX_DER_SIZE ); |
| int lMbedResult = 0; |
| mbedtls_pk_context xCtx = { 0 }; |
| CK_ATTRIBUTE_PTR pxPrivateLabel = NULL; |
| CK_ATTRIBUTE_PTR pxPublicLabel = NULL; |
| CK_OBJECT_HANDLE xPalPublic = CK_INVALID_HANDLE; |
| CK_OBJECT_HANDLE xPalPrivate = CK_INVALID_HANDLE; |
| |
| #if ( pkcs11configSUPPRESS_ECDSA_MECHANISM == 1 ) |
| if( xResult == CKR_OK ) |
| { |
| xResult = CKR_MECHANISM_INVALID; |
| } |
| #endif |
| |
| if( xResult == CKR_OK ) |
| { |
| if( ( pxPublicKeyTemplate == NULL ) || |
| ( pxPrivateKeyTemplate == NULL ) || |
| ( pxPublicKey == NULL ) || |
| ( pxPrivateKey == NULL ) || |
| ( pxMechanism == NULL ) ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( pucDerFile == NULL ) |
| { |
| xResult = CKR_HOST_MEMORY; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( CKM_EC_KEY_PAIR_GEN != pxMechanism->mechanism ) |
| { |
| xResult = CKR_MECHANISM_PARAM_INVALID; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| xResult = prvCheckGenerateKeyPairPrivateTemplate( &pxPrivateLabel, |
| pxPrivateKeyTemplate, |
| ulPrivateKeyAttributeCount ); |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| xResult = prvCheckGenerateKeyPairPublicTemplate( &pxPublicLabel, |
| pxPublicKeyTemplate, |
| ulPublicKeyAttributeCount ); |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| mbedtls_pk_init( &xCtx ); |
| lMbedResult = mbedtls_pk_setup( &xCtx, mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ); |
| } |
| |
| if( lMbedResult != 0 ) |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| if( 0 != mbedtls_ecp_gen_key( MBEDTLS_ECP_DP_SECP256R1, |
| mbedtls_pk_ec( xCtx ), |
| mbedtls_ctr_drbg_random, |
| &xP11Context.xMbedDrbgCtx ) ) |
| { |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| lMbedResult = mbedtls_pk_write_pubkey_der( &xCtx, pucDerFile, pkcs11KEY_GEN_MAX_DER_SIZE ); |
| } |
| |
| if( lMbedResult > 0 ) |
| { |
| xPalPublic = PKCS11_PAL_SaveObject( pxPublicLabel, pucDerFile + pkcs11KEY_GEN_MAX_DER_SIZE - lMbedResult, lMbedResult ); |
| } |
| else |
| { |
| xResult = CKR_GENERAL_ERROR; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| lMbedResult = mbedtls_pk_write_key_der( &xCtx, pucDerFile, pkcs11KEY_GEN_MAX_DER_SIZE ); |
| } |
| |
| if( lMbedResult > 0 ) |
| { |
| xPalPrivate = PKCS11_PAL_SaveObject( pxPrivateLabel, pucDerFile + pkcs11KEY_GEN_MAX_DER_SIZE - lMbedResult, lMbedResult ); /* TS-7249. */ |
| } |
| else |
| { |
| xResult = CKR_GENERAL_ERROR; |
| } |
| |
| if( ( xPalPublic != CK_INVALID_HANDLE ) && ( xPalPrivate != CK_INVALID_HANDLE ) ) |
| { |
| xResult = prvAddObjectToList( xPalPrivate, pxPrivateKey, pxPrivateLabel->pValue, pxPrivateLabel->ulValueLen ); |
| |
| if( xResult == CKR_OK ) |
| { |
| xResult = prvAddObjectToList( xPalPublic, pxPublicKey, pxPublicLabel->pValue, pxPublicLabel->ulValueLen ); |
| |
| if( xResult != CKR_OK ) |
| { |
| PKCS11_PAL_DestroyObject( *pxPrivateKey ); |
| } |
| } |
| } |
| |
| /* Clean up. */ |
| if( NULL != pucDerFile ) |
| { |
| vPortFree( pucDerFile ); |
| } |
| |
| mbedtls_pk_free( &xCtx ); |
| |
| return xResult; |
| } |
| |
| /** |
| * @brief Generate cryptographically random bytes. |
| * |
| * @param xSession[in] Handle of a valid PKCS #11 session. |
| * @param pucRandomData[out] Pointer to location that random data will be placed. |
| * It is the responsiblity of the application to allocate |
| * this memory. |
| * @param ulRandomLength[in] Length of data (in bytes) to be generated. |
| * |
| * @return CKR_OK if successful. |
| * Else, see <a href="https://tiny.amazon.com/wtscrttv">PKCS #11 specification</a> |
| * for more information. |
| */ |
| CK_DECLARE_FUNCTION( CK_RV, C_GenerateRandom )( CK_SESSION_HANDLE xSession, |
| CK_BYTE_PTR pucRandomData, |
| CK_ULONG ulRandomLen ) |
| { |
| CK_RV xResult = CKR_OK; |
| int lMbedResult = 0; |
| |
| xResult = PKCS11_SESSION_VALID_AND_MODULE_INITIALIZED( xSession ); |
| |
| if( ( NULL == pucRandomData ) || |
| ( ulRandomLen == 0 ) ) |
| { |
| xResult = CKR_ARGUMENTS_BAD; |
| } |
| |
| if( xResult == CKR_OK ) |
| { |
| lMbedResult = mbedtls_ctr_drbg_random( &xP11Context.xMbedDrbgCtx, pucRandomData, ulRandomLen ); |
| |
| if( lMbedResult != 0 ) |
| { |
| PKCS11_PRINT( ( "ERROR: DRBG failed %d \r\n", lMbedResult ) ); |
| xResult = CKR_FUNCTION_FAILED; |
| } |
| } |
| |
| return xResult; |
| } |