/* * corePKCS11 v3.5.0 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT * * 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. */ /** * @file core_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. */ /* PKCS #11 includes. */ #include "core_pkcs11_config.h" #include "core_pkcs11_config_defaults.h" #include "core_pkcs11.h" #include "core_pkcs11_pal.h" #include "core_pki_utils.h" /** * @brief Declaring MBEDTLS_ALLOW_PRIVATE_ACCESS allows access to mbedtls "private" fields. */ #define MBEDTLS_ALLOW_PRIVATE_ACCESS /* mbedTLS includes. */ #include "mbedtls/pk.h" #include "mbedtls/x509_crt.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/entropy.h" #include "mbedtls/sha256.h" #include "mbedtls/cmac.h" #include "mbedtls/platform.h" #include "mbedtls/threading.h" #include "mbedtls/error.h" /* C runtime includes. */ #include /*-----------------------------------------------------------*/ /** * @defgroup pkcs11_macros PKCS #11 Implementation Macros * @brief Macros for PKCS #11 software implementation. */ /** * @defgroup pkcs11_datatypes PKCS #11 Datatypes * @brief Internal datatypes for PKCS #11 software implementation. */ #ifndef DISABLE_LOGGING /** * @brief Represents string to be logged when mbedTLS returned error * does not contain a high-level code. */ static const char * pNoHighLevelMbedTlsCodeStr = ""; /** * @brief Represents string to be logged when mbedTLS returned error * does not contain a low-level code. */ static const char * pNoLowLevelMbedTlsCodeStr = ""; /** * @brief Utility for converting the high-level code in an mbedTLS error to string, * if the code-contains a high-level code; otherwise, using a default string. */ #define mbedtlsHighLevelCodeOrDefault( mbedTlsCode ) \ ( mbedtls_high_level_strerr( mbedTlsCode ) != NULL ) ? \ mbedtls_high_level_strerr( mbedTlsCode ) : pNoHighLevelMbedTlsCodeStr /** * @brief Utility for converting the level-level code in an mbedTLS error to string, * if the code-contains a level-level code; otherwise, using a default string. */ #define mbedtlsLowLevelCodeOrDefault( mbedTlsCode ) \ ( mbedtls_low_level_strerr( mbedTlsCode ) != NULL ) ? \ mbedtls_low_level_strerr( mbedTlsCode ) : pNoLowLevelMbedTlsCodeStr #endif /* ifndef DISABLE_LOGGING */ /** * @ingroup pkcs11_macros * @brief Delay to wait on acquiring a mutex, in ms. */ #define pkcs11MUTEX_WAIT_MS ( pdMS_TO_TICKS( 5000U ) ) /** * @ingroup pkcs11_macros * @brief Indicates that no PKCS #11 operation is underway for given session. */ #define pkcs11NO_OPERATION ( ( CK_MECHANISM_TYPE ) 0xFFFFFFFFUL ) /** * @ingroup pkcs11_macros * @brief size of a prime256v1 EC private key in bytes, when encoded in DER. */ #define pkcs11_PRIVATE_EC_PRIME_256_DER_SIZE 160 /** * @ingroup pkcs11_macros * @brief size of a prime256v1 EC public key in bytes, when encoded in DER. */ #define pkcs11_PUBLIC_EC_PRIME_256_DER_SIZE 100 /** * @ingroup pkcs11_macros * @brief size of a 2048 bit RSA public key in bytes, when encoded in DER. */ #define pkcs11_PUBLIC_RSA_2048_DER_SIZE 300 /** * @ingroup pkcs11_macros * @brief size of a 2048 bit RSA private key in bytes, in DER encoding. */ #define pkcs11_PRIVATE_RSA_2048_DER_SIZE 1200 /** * @ingroup pkcs11_macros * @brief Max size of an EC public key in bytes, in DER encoding. */ #define pkcs11_MAX_EC_PUBLIC_KEY_DER_SIZE pkcs11_PUBLIC_EC_PRIME_256_DER_SIZE /** * @ingroup pkcs11_macros * @brief Max size of an EC private key in bytes, in DER encoding. */ #define pkcs11_MAX_EC_PRIVATE_KEY_DER_SIZE pkcs11_PRIVATE_EC_PRIME_256_DER_SIZE /** * @ingroup pkcs11_macros * @brief Length of bytes to contain an EC point. * * This port currently only uses prime256v1, in which the fields are 32 bytes in * length. The public EC point is as long as the curve's fields * 2 + 1. * so the EC point for this port is (32 * 2) + 1 bytes in length. * * mbed TLS encodes the length of the point in the first byte of the buffer it * receives, so an additional 1 byte in length is added to account for this. * * In addition to this, an additional 1 byte is added to store information * indicating that the point is uncompressed. * * @note This length needs to be updated if using a different curve. * * To summarize: * 32 points of 2 bytes each + 1 point length byte, 1 length byte, and * 1 type (uncompressed) byte */ #define pkcs11EC_POINT_LENGTH ( ( 32UL * 2UL ) + 1UL + 1UL + 1UL ) /** * @ingroup pkcs11_macros * @brief Max size of a public key. * This macro defines the size of a key in bytes, in DER encoding. * * @note The largest RSA public key is used because EC keys are smaller. */ #define pkcs11_MAX_PUBLIC_KEY_DER_SIZE pkcs11_PUBLIC_RSA_2048_DER_SIZE /** * @ingroup pkcs11_macros * @brief Max key length of a key. * This macro defines the size of a key in bytes, in DER format. * * Currently the largest key type supported by this port is a 2048 bit * RSA private key. * * @note The largest RSA private key is used because EC keys are smaller and * the RSA public key is smaller. */ #define pkcs11_MAX_PRIVATE_KEY_DER_SIZE pkcs11_PRIVATE_RSA_2048_DER_SIZE /** * @ingroup pkcs11_macros * @brief The size of the buffer malloc'ed for the exported public key in C_GenerateKeyPair. */ #define pkcs11KEY_GEN_MAX_DER_SIZE 200 /** * @ingroup pkcs11_macros * @brief 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 /** * @ingroup pkcs11_macros * @brief Private defines for checking that attribute templates are complete. */ #define LABEL_IN_TEMPLATE ( 1U ) /**< Bit set for label in template. */ #define PRIVATE_IN_TEMPLATE ( 1U << 1 ) /**< Bit set for private key in in template. */ #define SIGN_IN_TEMPLATE ( 1U << 2 ) /**< Bit set for sign in template. */ #define EC_PARAMS_IN_TEMPLATE ( 1U << 3 ) /**< Bit set for EC params in template. */ #define VERIFY_IN_TEMPLATE ( 1U << 4 ) /**< Bit set for verify in template. */ /** * @ingroup pkcs11_macros * @brief Macro to signify an invalid PKCS #11 key type. */ #define PKCS11_INVALID_KEY_TYPE ( ( CK_KEY_TYPE ) 0xFFFFFFFFUL ) /** * @ingroup pkcs11_macros * @brief Private define for minimum SHA256-HMAC key size. */ #define PKCS11_SHA256_HMAC_MIN_SIZE ( 32UL ) /** * @ingroup pkcs11_macros * @brief Private define for minimum AES-CMAC key size, in bytes. */ #define PKCS11_AES_CMAC_MIN_SIZE ( 16UL ) /** * @ingroup pkcs11_macros * @brief Private define to inform mbedtls MD module to use an HMAC for the MD context. */ #define PKCS11_USING_HMAC ( 1 ) /** * @brief Define the MBEDTLS_VERSION_NUMBER as 0 if it is not defined, done for MISRA rule 20.9 */ #ifndef MBEDTLS_VERSION_NUMBER #define MBEDTLS_VERSION_NUMBER 0 #endif /** * @ingroup pkcs11_datatypes * @brief PKCS #11 object container. * * Maps a PKCS #11 object handle to it's label. */ typedef struct P11Object_t { CK_OBJECT_HANDLE xHandle; /**< @brief The "PAL Handle". */ CK_ULONG xLabelSize; /**< @brief Size of label. */ CK_BYTE xLabel[ pkcs11configMAX_LABEL_LENGTH + 1 ]; /**< @brief Plus 1 for the null terminator. */ } P11Object_t; /** * @ingroup pkcs11_datatypes * @brief PKCS #11 object container list. * * This structure helps the core_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 { mbedtls_threading_mutex_t xMutex; /**< @brief Mutex that protects write operations to the xObjects array. */ P11Object_t xObjects[ pkcs11configMAX_NUM_OBJECTS ]; /**< @brief List of PKCS #11 objects. */ } P11ObjectList_t; /** * @ingroup pkcs11_datatypes * @brief PKCS #11 Module Object */ typedef struct P11Struct_t { CK_BBOOL xIsInitialized; /**< @brief Indicates whether PKCS #11 module has been initialized with a call to C_Initialize. */ mbedtls_ctr_drbg_context xMbedDrbgCtx; /**< @brief CTR-DRBG context for PKCS #11 module - used to generate pseudo-random numbers. */ mbedtls_entropy_context xMbedEntropyContext; /**< @brief Entropy context for PKCS #11 module - used to collect entropy for RNG. */ mbedtls_threading_mutex_t xSessionMutex; /**< @brief Mutex that protects write operations to the pxSession array. */ P11ObjectList_t xObjectList; /**< @brief List of PKCS #11 objects that have been found/created since module initialization. * The array position indicates the "App Handle" */ } P11Struct_t; /** * @ingroup pkcs11_datatypes * @brief Session structure. */ typedef struct P11Session { CK_ULONG ulState; /**< @brief Stores the session flags. */ CK_BBOOL xOpened; /**< @brief Set to CK_TRUE upon opening PKCS #11 session. */ CK_MECHANISM_TYPE xOperationDigestMechanism; /**< @brief Indicates if a digest operation is in progress. */ CK_BYTE * pxFindObjectLabel; /**< @brief Pointer to the label for the search in progress. Should be NULL if no search in progress. */ CK_ULONG xFindObjectLabelLen; /**< @brief Size of current search label. */ CK_MECHANISM_TYPE xOperationVerifyMechanism; /**< @brief The mechanism of verify operation in progress. Set during C_VerifyInit. */ mbedtls_threading_mutex_t xVerifyMutex; /**< @brief Protects the verification key from being modified while in use. */ CK_OBJECT_HANDLE xVerifyKeyHandle; /**< @brief Object handle to the verification key. */ mbedtls_pk_context xVerifyKey; /**< @brief Verification key. Set during C_VerifyInit. */ CK_MECHANISM_TYPE xOperationSignMechanism; /**< @brief Mechanism of the sign operation in progress. Set during C_SignInit. */ mbedtls_threading_mutex_t xSignMutex; /**< @brief Protects the signing key from being modified while in use. */ CK_OBJECT_HANDLE xSignKeyHandle; /**< @brief Object handle to the signing key. */ mbedtls_pk_context xSignKey; /**< @brief Signing key. Set during C_SignInit. */ mbedtls_sha256_context xSHA256Context; /**< @brief Context for in progress digest operation. */ CK_OBJECT_HANDLE xHMACKeyHandle; /**< @brief Object handle to the HMAC key. */ mbedtls_md_context_t xHMACSecretContext; /**< @brief Context for in progress HMAC operation. Set during C_SignInit or C_VerifyInit. */ CK_OBJECT_HANDLE xCMACKeyHandle; /**< @brief Object handle to the CMAC key. */ mbedtls_cipher_context_t xCMACSecretContext; /**< @brief Context for in progress CMAC operation. Set during C_SignInit or C_VerifyInit. */ } P11Session_t; /*-----------------------------------------------------------*/ /** * @brief The global PKCS #11 module object. * Entropy/randomness and object lists are shared across PKCS #11 sessions. */ static P11Struct_t xP11Context; /** * @brief The global PKCS #11 session list. */ static P11Session_t pxP11Sessions[ pkcs11configMAX_SESSIONS ] = { 0 }; /** * @brief Helper to check if the current session is initialized and valid. */ static CK_RV prvCheckValidSessionAndModule( const P11Session_t * pxSession ) { CK_RV xResult = CKR_OK; /** MISRA Rule 10.5 - Cannot cast from unsigned to signed. * The rule 10.5 is violated because type of the boolean macros defined by PKCS #11 * are 0 and 1, which results in a signed integer, meanwhile the underlying * type of CK_BBOOL is an unsigned char. * * This means that our implementation conforms to the exception provided by MISRA * To quote MISRA: "An integer constant expression with the value 0 or 1 of either signedness * may be cast to a type which is defined as essentially Boolean. * This allows the implementation of non-C99 Boolean models." */ /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xP11Context.xIsInitialized == ( CK_BBOOL ) CK_FALSE ) { LogDebug( ( "Could not get a valid session. PKCS #11 was not initialized since xP11Context.xIsInitialized was CK_FALSE." ) ); xResult = CKR_CRYPTOKI_NOT_INITIALIZED; } else if( pxSession == NULL ) { LogDebug( ( "Could not get a valid session. PKCS #11 session handle pSession was NULL." ) ); xResult = CKR_SESSION_HANDLE_INVALID; } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ else if( pxSession->xOpened == ( CK_BBOOL ) CK_FALSE ) { LogDebug( ( "Could not get a valid session. PKCS #11 session handle was not initialized with a previous call to C_OpenSession." ) ); xResult = CKR_SESSION_HANDLE_INVALID; } else { /* Session is initialized and valid. */ } return xResult; } /** * @brief Maps an opaque caller session handle into its internal state structure. */ static P11Session_t * prvSessionPointerFromHandle( CK_SESSION_HANDLE xSession ) { P11Session_t * pxSession = NULL; if( ( xSession >= 1UL ) && ( xSession <= pkcs11configMAX_SESSIONS ) ) { /* Decrement by 1, invalid handles in PKCS #11 are defined to be 0. */ pxSession = &pxP11Sessions[ xSession - 1UL ]; } else { LogDebug( ( "Could not convert from CK_SESSION_HANDLE to P11Session_t pointer. Session handle was out of the valid range. Session handle was: %lu.", ( unsigned long int ) xSession ) ); } return pxSession; } /** * @brief Determines if an operation is in progress. */ static CK_BBOOL prvOperationActive( const P11Session_t * pxSession ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xResult = ( CK_BBOOL ) CK_FALSE; if( ( pxSession->xOperationDigestMechanism < pkcs11NO_OPERATION ) == CK_TRUE ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xResult = ( CK_BBOOL ) CK_TRUE; } else if( ( pxSession->xOperationSignMechanism < pkcs11NO_OPERATION ) == CK_TRUE ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xResult = ( CK_BBOOL ) CK_TRUE; } else if( ( pxSession->xOperationVerifyMechanism < pkcs11NO_OPERATION ) == CK_TRUE ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xResult = ( CK_BBOOL ) CK_TRUE; } else if( pxSession->pxFindObjectLabel != NULL ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xResult = ( CK_BBOOL ) CK_TRUE; } else { /* MISRA */ } return xResult; } /** * @brief Initialize mbedTLS. */ static CK_RV prvMbedTLS_Initialize( void ) { CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ int32_t lMbedTLSResult = 0; ( void ) memset( &xP11Context, 0, sizeof( xP11Context ) ); mbedtls_mutex_init( &xP11Context.xObjectList.xMutex ); mbedtls_mutex_init( &xP11Context.xSessionMutex ); /* Initialize the entropy source and DRBG for the PKCS#11 module */ mbedtls_entropy_init( &xP11Context.xMbedEntropyContext ); mbedtls_ctr_drbg_init( &xP11Context.xMbedDrbgCtx ); lMbedTLSResult = mbedtls_ctr_drbg_seed( &xP11Context.xMbedDrbgCtx, mbedtls_entropy_func, &xP11Context.xMbedEntropyContext, NULL, 0 ); if( 0 != lMbedTLSResult ) { LogError( ( "Could not initialize PKCS #11. Failed to seed the DRBG: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } else { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xP11Context.xIsInitialized = ( CK_BBOOL ) CK_TRUE; LogDebug( ( "PKCS #11 module was successfully initialized." ) ); } return xResult; } /** * @brief Searches a template for the CKA_CLASS attribute. */ static CK_RV prvGetObjectClass( const CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount, CK_OBJECT_CLASS * pxClass ) { CK_RV xResult = CKR_TEMPLATE_INCOMPLETE; CK_ULONG ulIndex = 0; /* Search template for class attribute. */ for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) { if( ( pxTemplate[ ulIndex ].type == CKA_CLASS ) && ( pxTemplate[ ulIndex ].ulValueLen == sizeof( CK_OBJECT_CLASS ) ) ) { LogDebug( ( "Successfully found object class attribute." ) ); ( void ) memcpy( pxClass, pxTemplate[ ulIndex ].pValue, sizeof( CK_OBJECT_CLASS ) ); xResult = CKR_OK; break; } } return xResult; } /** * @brief Parses attribute values for a certificate. */ static CK_RV prvCertAttParse( CK_ATTRIBUTE * pxAttribute, CK_CERTIFICATE_TYPE * pxCertificateType, CK_BYTE_PTR * ppxCertificateValue, CK_ULONG * pxCertificateLength, CK_ATTRIBUTE ** ppxLabel ) { CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; switch( pxAttribute->type ) { case ( CKA_VALUE ): *ppxCertificateValue = pxAttribute->pValue; *pxCertificateLength = pxAttribute->ulValueLen; break; case ( CKA_LABEL ): if( pxAttribute->ulValueLen <= pkcs11configMAX_LABEL_LENGTH ) { *ppxLabel = pxAttribute; } else { LogError( ( "Failed parsing certificate template. Label length " "was not in the valid range. Found %lu and expected %lu. " "Consider updating pkcs11configMAX_LABEL_LENGTH.", ( unsigned long int ) pxAttribute->ulValueLen, ( unsigned long int ) pkcs11configMAX_LABEL_LENGTH ) ); xResult = CKR_DATA_LEN_RANGE; } break; case ( CKA_CERTIFICATE_TYPE ): if( pxAttribute->ulValueLen == sizeof( CK_CERTIFICATE_TYPE ) ) { ( void ) memcpy( pxCertificateType, pxAttribute->pValue, sizeof( CK_CERTIFICATE_TYPE ) ); } if( *pxCertificateType != CKC_X_509 ) { LogError( ( "Failed parsing certificate template. Certificate type was invalid. " "Expected CKC_X_509, but found 0x%0lX.", ( unsigned long int ) *pxCertificateType ) ); xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; case ( CKA_TOKEN ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { 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: LogError( ( "Failed parsing certificate template. Received an unknown " "template type with value 0x%0lX.", ( unsigned long int ) pxAttribute->type ) ); xResult = CKR_ATTRIBUTE_TYPE_INVALID; break; } return xResult; } /** * @brief Parses attribute values for an RSA public Key. */ static CK_RV prvRsaPrivKeyAttParse( const CK_ATTRIBUTE * pxAttribute ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; CK_RV xResult = CKR_OK; if( pxAttribute->type == CKA_SIGN ) { if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, pxAttribute->ulValueLen ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool == ( CK_BBOOL ) CK_FALSE ) { xResult = CKR_ATTRIBUTE_VALUE_INVALID; LogError( ( "Failed to parse RSA private key. Expected sign permissions to be supported." ) ); } } return xResult; } /** * @brief Parses attribute values for an RSA public Key. */ static CK_RV prvRsaPubKeyAttParse( const CK_ATTRIBUTE * pxAttribute ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; CK_RV xResult = CKR_OK; if( pxAttribute->type == CKA_VERIFY ) { if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, pxAttribute->ulValueLen ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool == ( CK_BBOOL ) CK_FALSE ) { xResult = CKR_ATTRIBUTE_VALUE_INVALID; LogError( ( "Failed to parse RSA public key. Expected verify permissions to be supported." ) ); } } return xResult; } /** * @brief Parses attribute values for an RSA key an puts them in the mbed TLS context. */ static CK_RV prvRsaContextParse( const CK_ATTRIBUTE * pxAttribute, mbedtls_rsa_context * pxRsaContext ) { CK_RV xResult = CKR_OK; int32_t lMbedTLSResult = 0; switch( pxAttribute->type ) { case ( CKA_MODULUS ): lMbedTLSResult = mbedtls_rsa_import_raw( pxRsaContext, pxAttribute->pValue, pxAttribute->ulValueLen, /* N */ NULL, 0, /* P */ NULL, 0, /* Q */ NULL, 0, /* D */ NULL, 0 ); /* E */ break; case ( CKA_PUBLIC_EXPONENT ): lMbedTLSResult = mbedtls_rsa_import_raw( pxRsaContext, NULL, 0, /* N */ NULL, 0, /* P */ NULL, 0, /* Q */ NULL, 0, /* D */ pxAttribute->pValue, pxAttribute->ulValueLen ); /* E */ break; case ( CKA_PRIME_1 ): lMbedTLSResult = mbedtls_rsa_import_raw( pxRsaContext, NULL, 0, /* N */ pxAttribute->pValue, pxAttribute->ulValueLen, /* P */ NULL, 0, /* Q */ NULL, 0, /* D */ NULL, 0 ); /* E */ break; case ( CKA_PRIME_2 ): lMbedTLSResult = mbedtls_rsa_import_raw( pxRsaContext, NULL, 0, /* N */ NULL, 0, /* P */ pxAttribute->pValue, pxAttribute->ulValueLen, /* Q */ NULL, 0, /* D */ NULL, 0 ); /* E */ break; case ( CKA_PRIVATE_EXPONENT ): lMbedTLSResult = mbedtls_rsa_import_raw( pxRsaContext, NULL, 0, /* N */ NULL, 0, /* P */ NULL, 0, /* Q */ pxAttribute->pValue, pxAttribute->ulValueLen, /* D */ NULL, 0 ); /* E */ break; case ( CKA_EXPONENT_1 ): lMbedTLSResult = mbedtls_mpi_read_binary( &pxRsaContext->DP, pxAttribute->pValue, pxAttribute->ulValueLen ); break; case ( CKA_EXPONENT_2 ): lMbedTLSResult = mbedtls_mpi_read_binary( &pxRsaContext->DQ, pxAttribute->pValue, pxAttribute->ulValueLen ); break; case ( CKA_COEFFICIENT ): lMbedTLSResult = mbedtls_mpi_read_binary( &pxRsaContext->QP, pxAttribute->pValue, pxAttribute->ulValueLen ); break; default: /* This should never be reached, as the above types are what gets this function called. * Nevertheless this is an error case, and MISRA requires a default statement. */ xResult = CKR_ATTRIBUTE_TYPE_INVALID; break; } if( lMbedTLSResult != 0 ) { LogError( ( "Failed to parse RSA private key template: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } return xResult; } /** * @brief Parses attribute values for a RSA Key. */ static CK_RV prvRsaKeyAttParse( const CK_ATTRIBUTE * pxAttribute, mbedtls_rsa_context * pxRsaContext, CK_BBOOL xIsPrivate ) { CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; switch( pxAttribute->type ) { case ( CKA_CLASS ): case ( CKA_KEY_TYPE ): case ( CKA_LABEL ): /* Do nothing. These values were parsed previously. */ break; case ( CKA_TOKEN ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; case ( CKA_VERIFY ): /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_FALSE ) { xResult = prvRsaPubKeyAttParse( pxAttribute ); } else { xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; case ( CKA_SIGN ): /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_TRUE ) { xResult = prvRsaPrivKeyAttParse( pxAttribute ); } else { xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; case ( CKA_MODULUS ): case ( CKA_PUBLIC_EXPONENT ): case ( CKA_PRIME_1 ): case ( CKA_PRIME_2 ): case ( CKA_PRIVATE_EXPONENT ): case ( CKA_EXPONENT_1 ): case ( CKA_EXPONENT_2 ): case ( CKA_COEFFICIENT ): xResult = prvRsaContextParse( pxAttribute, pxRsaContext ); break; default: xResult = CKR_ATTRIBUTE_TYPE_INVALID; break; } return xResult; } /** * @brief Parses attribute values for a private EC Key. */ #ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM static CK_RV prvEcPrivKeyAttParse( const CK_ATTRIBUTE * pxAttribute, const mbedtls_pk_context * pxMbedContext ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; int32_t lMbedTLSResult = 0; CK_RV xResult = CKR_OK; mbedtls_ecp_keypair * pxKeyPair = ( mbedtls_ecp_keypair * ) pxMbedContext->pk_ctx; if( pxAttribute->type == CKA_SIGN ) { if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool == ( CK_BBOOL ) CK_FALSE ) { xResult = CKR_ATTRIBUTE_VALUE_INVALID; LogError( ( "Failed to parse EC private key. Only private keys with signing privileges are supported." ) ); } } else { lMbedTLSResult = mbedtls_mpi_read_binary( &pxKeyPair->d, pxAttribute->pValue, pxAttribute->ulValueLen ); if( lMbedTLSResult != 0 ) { xResult = CKR_FUNCTION_FAILED; LogError( ( "Failed to parse EC private key. MPI read binary failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } } return xResult; } #endif /* ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM */ /** * @brief Parses attribute values for a public EC Key. */ #ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM static CK_RV prvEcPubKeyAttParse( const CK_ATTRIBUTE * pxAttribute, const mbedtls_pk_context * pxMbedContext ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; int32_t lMbedTLSResult = 0; CK_RV xResult = CKR_OK; mbedtls_ecp_keypair * pxKeyPair = ( mbedtls_ecp_keypair * ) pxMbedContext->pk_ctx; if( pxAttribute->type == CKA_VERIFY ) { if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, pxAttribute->ulValueLen ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool == ( CK_BBOOL ) CK_FALSE ) { xResult = CKR_ATTRIBUTE_VALUE_INVALID; LogError( ( "Failed to parse EC public key. Expected verify permissions to be supported." ) ); } } else { /* Strip the ANS.1 Encoding of type and length. Otherwise mbed TLS * won't be able to parse the binary EC point. */ if( pxAttribute->ulValueLen >= 2UL ) { lMbedTLSResult = mbedtls_ecp_point_read_binary( &pxKeyPair->grp, &pxKeyPair->Q, ( ( uint8_t * ) ( pxAttribute->pValue ) + 2U ), ( pxAttribute->ulValueLen - 2U ) ); if( lMbedTLSResult != 0 ) { xResult = CKR_FUNCTION_FAILED; LogError( ( "Failed to parse EC public key. mbedtls_ecp_point_read_binary failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } } else { xResult = CKR_ATTRIBUTE_VALUE_INVALID; } } return xResult; } #endif /* ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM */ /** * @brief Parses attribute values for an EC Key. */ #ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM static CK_RV prvEcKeyAttParse( const CK_ATTRIBUTE * pxAttribute, const mbedtls_pk_context * pxMbedContext, CK_BBOOL xIsPrivate ) { CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; const CK_BYTE pxEcCurve[] = pkcs11DER_ENCODED_OID_P256; const CK_BYTE * pxEcAttVal = NULL; const CK_BBOOL * pxEcBoolAtt = NULL; /* Common EC key attributes. */ switch( pxAttribute->type ) { case ( CKA_CLASS ): case ( CKA_KEY_TYPE ): case ( CKA_LABEL ): break; case ( CKA_TOKEN ): pxEcBoolAtt = ( CK_BBOOL * ) pxAttribute->pValue; if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxEcBoolAtt, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { LogError( ( "Failed parsing EC key template. Expected token type to be true, but it was false." ) ); xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; case ( CKA_EC_PARAMS ): pxEcAttVal = ( CK_BYTE * ) pxAttribute->pValue; if( pxAttribute->ulValueLen == sizeof( pxEcCurve ) ) { if( memcmp( pxEcCurve, pxEcAttVal, sizeof( pxEcCurve ) ) != 0 ) { xResult = CKR_TEMPLATE_INCONSISTENT; LogError( ( "Failed parsing EC key template. The elliptic curve was wrong. Expected elliptic curve P-256." ) ); } } break; case ( CKA_VERIFY ): case ( CKA_EC_POINT ): /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_FALSE ) { xResult = prvEcPubKeyAttParse( pxAttribute, pxMbedContext ); } else { LogError( ( "Failed parsing EC key template. The key type " "did not match the template parameters. Expected " "a public key for CKA_VERIFY or CKA_EC_POINT." ) ); xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; case ( CKA_SIGN ): case ( CKA_VALUE ): /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_TRUE ) { xResult = prvEcPrivKeyAttParse( pxAttribute, pxMbedContext ); } else { LogError( ( "Failed parsing EC key template. The key type " "did not match the template parameters. Expected " "a private key for CKA_SIGN or CKA_VALUE." ) ); xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; default: LogError( ( "Failed parsing EC key template. Unknown attribute " "0x%0lX found for an EC key.", ( unsigned long int ) pxAttribute->type ) ); xResult = CKR_ATTRIBUTE_TYPE_INVALID; break; } return xResult; } #endif /* ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM */ /*-----------------------------------------------------------------------*/ /* 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] xLabelLength 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. */ static void prvFindObjectInListByLabel( const CK_BYTE * pcLabel, CK_ULONG xLabelLength, CK_OBJECT_HANDLE_PTR pxPalHandle, CK_OBJECT_HANDLE_PTR pxAppHandle ) { uint32_t ulIndex; *pxPalHandle = CK_INVALID_HANDLE; *pxAppHandle = CK_INVALID_HANDLE; for( ulIndex = 0; ulIndex < pkcs11configMAX_NUM_OBJECTS; ulIndex++ ) { if( 0 == memcmp( pcLabel, xP11Context.xObjectList.xObjects[ ulIndex ].xLabel, xLabelLength ) ) { LogDebug( ( "Found object in object list matching label." ) ); *pxPalHandle = xP11Context.xObjectList.xObjects[ ulIndex ].xHandle; *pxAppHandle = ulIndex + 1UL; /* 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] pxPalHandle 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. */ static void prvFindObjectInListByHandle( CK_OBJECT_HANDLE xAppHandle, CK_OBJECT_HANDLE_PTR pxPalHandle, CK_BYTE_PTR * ppcLabel, CK_ULONG_PTR pxLabelLength ) { CK_OBJECT_HANDLE ulIndex = xAppHandle - ( ( CK_OBJECT_HANDLE ) 1 ); *ppcLabel = NULL; *pxLabelLength = 0; *pxPalHandle = CK_INVALID_HANDLE; if( ulIndex < pkcs11configMAX_NUM_OBJECTS ) { if( xP11Context.xObjectList.xObjects[ ulIndex ].xHandle != CK_INVALID_HANDLE ) { LogDebug( ( "Found object in list by handle." ) ); *ppcLabel = xP11Context.xObjectList.xObjects[ ulIndex ].xLabel; *pxLabelLength = xP11Context.xObjectList.xObjects[ ulIndex ].xLabelSize; *pxPalHandle = xP11Context.xObjectList.xObjects[ ulIndex ].xHandle; } } } /** * @brief Removes an object from the module object list (xP11Context.xObjectList) * * @warning This does not delete the object from NVM. * * @param[in] xPalHandle PAL handle of the object to be deleted. */ static CK_RV prvDeleteObjectFromList( CK_OBJECT_HANDLE xPalHandle ) { CK_RV xResult = CKR_OK; int32_t lGotSemaphore = ( int32_t ) 0; CK_ULONG ulIndex; lGotSemaphore = mbedtls_mutex_lock( &xP11Context.xObjectList.xMutex ); if( lGotSemaphore == 0 ) { /* Remove all references that have the same PAL handle, as it has now * been deleted in the PKCS11_PAL. */ for( ulIndex = 0; ulIndex < pkcs11configMAX_NUM_OBJECTS; ulIndex++ ) { if( xP11Context.xObjectList.xObjects[ ulIndex ].xHandle == xPalHandle ) { ( void ) memset( &xP11Context.xObjectList.xObjects[ ulIndex ], 0, sizeof( P11Object_t ) ); } } ( void ) mbedtls_mutex_unlock( &xP11Context.xObjectList.xMutex ); } else { LogError( ( "Failed to remove an object from internal object list. " "Could not take the xObjectList mutex." ) ); 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. * */ static CK_RV prvAddObjectToList( CK_OBJECT_HANDLE xPalHandle, CK_OBJECT_HANDLE_PTR pxAppHandle, const CK_BYTE * pcLabel, CK_ULONG xLabelLength ) { CK_RV xResult = CKR_HOST_MEMORY; if( xLabelLength > pkcs11configMAX_LABEL_LENGTH ) { xResult = CKR_ARGUMENTS_BAD; LogError( ( "Failed to add object to internal object list: " "xLabelLength exceeds pkcs11configMAX_LABEL_LENGTH." ) ); } else if( 0 == mbedtls_mutex_lock( &xP11Context.xObjectList.xMutex ) ) { CK_ULONG ulSearchIndex; CK_ULONG ulEmptyIndex = 0; P11Object_t * pxEmptyP11Object = NULL; /* Iterate over list to find an existing entry containing xPalHandle */ for( ulSearchIndex = 0; ulSearchIndex < pkcs11configMAX_NUM_OBJECTS; ulSearchIndex++ ) { P11Object_t * pxP11Object = &( xP11Context.xObjectList.xObjects[ ulSearchIndex ] ); /* Update an existing entry with the desired xPalHandle */ if( pxP11Object->xHandle == xPalHandle ) { ( void ) memcpy( pxP11Object->xLabel, pcLabel, xLabelLength ); pxP11Object->xLabelSize = xLabelLength; xResult = CKR_OK; *pxAppHandle = ulSearchIndex + 1; /* Entry updated, so exit the loop. */ break; } else { if( ( pxP11Object->xHandle == CK_INVALID_HANDLE ) && ( pxEmptyP11Object == NULL ) ) { pxEmptyP11Object = pxP11Object; ulEmptyIndex = ulSearchIndex; } } } /* Check if we have reached the end of the list without writing */ if( ( xResult != CKR_OK ) && ( pxEmptyP11Object != NULL ) ) { pxEmptyP11Object->xHandle = xPalHandle; pxEmptyP11Object->xLabelSize = xLabelLength; ( void ) memcpy( pxEmptyP11Object->xLabel, pcLabel, xLabelLength ); *pxAppHandle = ulEmptyIndex + 1; xResult = CKR_OK; } ( void ) mbedtls_mutex_unlock( &xP11Context.xObjectList.xMutex ); } else { LogError( ( "Failed to add object to internal object list. Could not " "take xObjectList mutex." ) ); xResult = CKR_CANT_LOCK; } return xResult; } /** * @brief Append an empty public key to DER formatted EC private key. */ static CK_RV prvAppendEmptyECDerKey( uint8_t * pusECPrivateKey, uint32_t ulDerBufSize, int32_t lDerKeyLength, uint32_t * pulActualKeyLength ) { CK_RV xResult = CKR_OK; const uint8_t emptyPubKey[ 6 ] = { 0xa1, 0x04, 0x03, 0x02, 0x00, 0x00 }; int32_t lCompare = 0; /* * 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 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. */ lCompare = memcmp( &pusECPrivateKey[ ulDerBufSize - 6UL ], emptyPubKey, sizeof( emptyPubKey ) ); if( ( lCompare == 0 ) && ( *pulActualKeyLength >= 6UL ) ) { /* Do not write the last 6 bytes to key storage. */ pusECPrivateKey[ ulDerBufSize - ( uint32_t ) lDerKeyLength + ( ( uint32_t ) 1 ) ] -= ( uint8_t ) 6; *pulActualKeyLength -= ( ( uint32_t ) 6 ); } return xResult; } /** * @brief Save a DER formatted key in the PKCS #11 PAL. */ static CK_RV prvSaveDerKeyToPal( mbedtls_pk_context * pxMbedContext, CK_OBJECT_HANDLE_PTR pxObject, CK_ATTRIBUTE * pxLabel, CK_KEY_TYPE xKeyType, CK_BBOOL xIsPrivate ) { CK_RV xResult = CKR_OK; CK_BYTE_PTR pxDerKey = NULL; int32_t lDerKeyLength = 0; uint32_t ulActualKeyLength = 0; CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; uint32_t ulDerBufSize = 0; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_TRUE ) { LogDebug( ( "Key was private type." ) ); if( xKeyType == CKK_EC ) { LogDebug( ( "Received EC key type." ) ); ulDerBufSize = pkcs11_MAX_EC_PRIVATE_KEY_DER_SIZE; } else { LogDebug( ( "Received RSA key type." ) ); ulDerBufSize = pkcs11_MAX_PRIVATE_KEY_DER_SIZE; } } else { LogDebug( ( "Key was public type." ) ); if( xKeyType == CKK_EC ) { LogDebug( ( "Received EC key type." ) ); ulDerBufSize = pkcs11_MAX_EC_PUBLIC_KEY_DER_SIZE; } else { LogDebug( ( "Received RSA key type." ) ); ulDerBufSize = pkcs11_PUBLIC_RSA_2048_DER_SIZE; } } LogDebug( ( "Allocating a %lu bytes sized buffer to write the key to.", ( unsigned long int ) ulDerBufSize ) ); pxDerKey = mbedtls_calloc( 1, ulDerBufSize ); if( pxDerKey == NULL ) { LogError( ( "Failed saving DER formatted key to flash. Failed to malloc a buffer to contain the key for the mbed TLS context." ) ); xResult = CKR_HOST_MEMORY; } else { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_TRUE ) { lDerKeyLength = mbedtls_pk_write_key_der( pxMbedContext, pxDerKey, ulDerBufSize ); } else { lDerKeyLength = mbedtls_pk_write_pubkey_der( pxMbedContext, pxDerKey, ulDerBufSize ); } } if( lDerKeyLength < 0 ) { LogError( ( "Failed saving DER formatted key to flash. mbed TLS pk_write failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lDerKeyLength ), mbedtlsLowLevelCodeOrDefault( lDerKeyLength ) ) ); xResult = CKR_FUNCTION_FAILED; } else { /* Cast to unsigned int as the result was not negative. */ ulActualKeyLength = ( uint32_t ) lDerKeyLength; } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( ( xResult == CKR_OK ) && ( xIsPrivate == ( CK_BBOOL ) CK_TRUE ) && ( xKeyType == CKK_EC ) ) { xResult = prvAppendEmptyECDerKey( pxDerKey, ulDerBufSize, lDerKeyLength, &ulActualKeyLength ); } if( ( xResult == CKR_OK ) && ( lDerKeyLength > 0 ) && ( ( uint32_t ) lDerKeyLength < ulDerBufSize ) ) { xPalHandle = PKCS11_PAL_SaveObject( pxLabel, pxDerKey + ( ulDerBufSize - ( uint32_t ) lDerKeyLength ), ulActualKeyLength ); if( xPalHandle == CK_INVALID_HANDLE ) { LogError( ( "Failed saving DER formatted key to flash. Failed to write DER formatted key to the PKCS #11 PAL." ) ); xResult = CKR_DEVICE_MEMORY; } } if( xResult == CKR_OK ) { xResult = prvAddObjectToList( xPalHandle, pxObject, pxLabel->pValue, pxLabel->ulValueLen ); } mbedtls_free( pxDerKey ); return xResult; } /*-------------------------------------------------------------*/ /** * @brief Initializes Cryptoki. * * @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] pInitArgs 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. */ /* @[declare_pkcs11_mbedtls_c_initialize] */ CK_DECLARE_FUNCTION( CK_RV, C_Initialize )( CK_VOID_PTR pInitArgs ) { CK_RV xResult = CKR_OK; ( void ) ( pInitArgs ); /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xP11Context.xIsInitialized != ( CK_BBOOL ) CK_TRUE ) { xResult = PKCS11_PAL_Initialize(); if( xResult == CKR_OK ) { xResult = prvMbedTLS_Initialize(); } else { LogError( ( "Failed to initialize PKCS #11. PAL failed with error code: 0x%0lX", ( unsigned long int ) xResult ) ); } } else { xResult = CKR_CRYPTOKI_ALREADY_INITIALIZED; LogWarn( ( "Failed to initialize PKCS #11. PKCS #11 was already initialized." ) ); } if( xResult == CKR_OK ) { LogInfo( ( "PKCS #11 successfully initialized." ) ); } return xResult; } /* @[declare_pkcs11_mbedtls_c_initialize] */ /** * @brief Clean up miscellaneous Cryptoki-associated resources. */ /* @[declare_pkcs11_mbedtls_c_finalize] */ CK_DECLARE_FUNCTION( CK_RV, C_Finalize )( CK_VOID_PTR pReserved ) { CK_RV xResult = CKR_OK; if( pReserved != NULL ) { xResult = CKR_ARGUMENTS_BAD; LogError( ( "Failed to un-initialize PKCS #11. Received bad arguments. " "Parameters must be NULL, but were not." ) ); } if( xResult == CKR_OK ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xP11Context.xIsInitialized == ( CK_BBOOL ) CK_FALSE ) { xResult = CKR_CRYPTOKI_NOT_INITIALIZED; LogWarn( ( "PKCS #11 was already uninitialized." ) ); } } if( xResult == CKR_OK ) { mbedtls_entropy_free( &xP11Context.xMbedEntropyContext ); mbedtls_ctr_drbg_free( &xP11Context.xMbedDrbgCtx ); mbedtls_mutex_free( &xP11Context.xObjectList.xMutex ); mbedtls_mutex_free( &xP11Context.xSessionMutex ); /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xP11Context.xIsInitialized = ( CK_BBOOL ) CK_FALSE; LogInfo( ( "PKCS #11 was successfully uninitialized." ) ); } return xResult; } /* @[declare_pkcs11_mbedtls_c_finalize] */ /** * @brief Obtains entry points of Cryptoki library functions. * * All other PKCS #11 functions should be invoked using the returned * function list. * * @warning Do not overwrite the function list. * * \param[in] ppFunctionList Pointer to the location where * pointer to function list will be placed. * * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_getfunctionlist] */ CK_DECLARE_FUNCTION( CK_RV, C_GetFunctionList )( CK_FUNCTION_LIST_PTR_PTR ppFunctionList ) { CK_RV xResult = CKR_OK; 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*/ }; if( NULL == ppFunctionList ) { xResult = CKR_ARGUMENTS_BAD; LogError( ( "Failed to return function pointer list. Expected a valid " "pointer to a CK_FUNCTION_LIST, but the pointer was NULL." ) ); } else { *ppFunctionList = &prvP11FunctionList; } return xResult; } /* @[declare_pkcs11_mbedtls_c_getfunctionlist] */ /** * @brief Obtains a list of slots in the system. * * This port does not implement the concept of separate slots/tokens. * * \param[in] tokenPresent This parameter is unused by this port. * \param[in] pSlotList 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. */ /* @[declare_pkcs11_mbedtls_c_getslotlist] */ CK_DECLARE_FUNCTION( CK_RV, C_GetSlotList )( CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount ) { CK_RV xResult = CKR_OK; /* Since the mbedTLS implementation of PKCS#11 does not depend * on a physical token, this parameter is ignored. */ ( void ) ( tokenPresent ); /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xP11Context.xIsInitialized != ( CK_BBOOL ) CK_TRUE ) { xResult = CKR_CRYPTOKI_NOT_INITIALIZED; LogError( ( "Failed to get slot list. PKCS #11 must be initialized " "before any operations." ) ); } if( NULL == pulCount ) { xResult = CKR_ARGUMENTS_BAD; LogError( ( "Failed to get slot list. Count pointer was NULL." ) ); } if( xResult == CKR_OK ) { if( NULL == pSlotList ) { *pulCount = 1; } else { if( 0u == *pulCount ) { xResult = CKR_BUFFER_TOO_SMALL; LogWarn( ( "The buffer is too small to contain the slot list." ) ); } else { pSlotList[ 0 ] = pkcs11SLOT_ID; *pulCount = 1; LogDebug( ( "Successfully Returned a PKCS #11 slot with ID " "%lu with a count of %lu.", ( unsigned long int ) pkcs11SLOT_ID, ( unsigned long int ) *pulCount ) ); } } } return xResult; } /* @[declare_pkcs11_mbedtls_c_getslotlist] */ /** * @brief Obtains information about a particular token. * * @param[in] slotID This parameter is unused in this port. * @param[out] pInfo This parameter is unused in 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. */ /* @[declare_pkcs11_mbedtls_c_gettokeninfo] */ 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; LogWarn( ( "C_GetTokenInfo is not implemented." ) ); return CKR_OK; } /* @[declare_pkcs11_mbedtls_c_gettokeninfo] */ /** * @brief Obtains information about a particular mechanism. * * \param[in] slotID 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. */ /* @[declare_pkcs11_mbedtls_c_getmechanisminfo] */ 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 } }, #ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM { 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; ( void ) slotID; if( pInfo == NULL ) { xResult = CKR_ARGUMENTS_BAD; LogError( ( "Failed to get mechanism info. pInfo was NULL. Expected a " "pointer to a valid CK_MECHANISM_INFO struct." ) ); } else { /* 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. */ ( void ) memcpy( pInfo, &( pxSupportedMechanisms[ ulMech ].xInfo ), sizeof( CK_MECHANISM_INFO ) ); xResult = CKR_OK; break; } } } return xResult; } /* @[declare_pkcs11_mbedtls_c_getmechanisminfo] */ /** * @brief Initializes a token. 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. */ /* @[declare_pkcs11_mbedtls_c_inittoken] */ 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; LogWarn( ( "C_InitToken is not implemented." ) ); return CKR_OK; } /* @[declare_pkcs11_mbedtls_c_inittoken] */ /** * @brief Opens a connection between an application and a particular token or sets up an application callback for token insertion. * * \note PKCS #11 module must have been previously initialized with a call to * C_Initialize() before calling C_OpenSession(). * * * \param[in] slotID This parameter is unused in this port. * \param[in] flags Session flags - CKF_SERIAL_SESSION is a * mandatory flag. * \param[in] pApplication This parameter is unused in this port. * \param[in] Notify This parameter is unused in this port. * \param[in] phSession Pointer to the location that the created * session's handle will be placed. * * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_opensession] */ CK_DECLARE_FUNCTION( CK_RV, C_OpenSession )( CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession ) { CK_RV xResult = CKR_OK; P11Session_t * pxSessionObj = NULL; uint32_t ulSessionCount = 0; ( void ) ( slotID ); ( void ) ( pApplication ); /* Allow unused parameters to be cast to void to silence compiler warnings. * Even if they are a function pointer. */ /* MISRA Ref 11.1.1 [Object type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-111 */ ( void ) Notify; /* Check that the PKCS #11 module is initialized. */ /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xP11Context.xIsInitialized != ( CK_BBOOL ) CK_TRUE ) { xResult = CKR_CRYPTOKI_NOT_INITIALIZED; LogError( ( "Could not open a session. PKCS #11 must be initialized " "before any operations." ) ); } /* Check arguments. */ if( NULL == phSession ) { xResult = CKR_ARGUMENTS_BAD; LogError( ( "Could not open a session. phSession cannot be a NULL pointer." ) ); } /* For legacy reasons, the CKF_SERIAL_SESSION bit MUST always be set. */ if( ( CKR_OK == xResult ) && ( 0UL == ( CKF_SERIAL_SESSION & flags ) ) ) { xResult = CKR_SESSION_PARALLEL_NOT_SUPPORTED; LogError( ( "Could not open a session. CKR_SESSION_PARALLEL_NOT_SUPPORTED " "must always be a set flag." ) ); } /* * Make space for the context. */ if( CKR_OK == xResult ) { /* Get next open session slot. */ if( mbedtls_mutex_lock( &xP11Context.xSessionMutex ) == 0 ) { for( ulSessionCount = 0; ulSessionCount < pkcs11configMAX_SESSIONS; ++ulSessionCount ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( pxP11Sessions[ ulSessionCount ].xOpened == ( CK_BBOOL ) CK_FALSE ) { xResult = CKR_OK; pxSessionObj = &pxP11Sessions[ ulSessionCount ]; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ pxSessionObj->xOpened = ( CK_BBOOL ) CK_TRUE; break; } else { xResult = CKR_SESSION_COUNT; } } ( void ) mbedtls_mutex_unlock( &xP11Context.xSessionMutex ); } else { xResult = CKR_FUNCTION_FAILED; LogError( ( "Could not open a session. Unsuccessful in taking xSessionMutex." ) ); } if( CKR_OK == xResult ) { mbedtls_mutex_init( &pxSessionObj->xSignMutex ); mbedtls_mutex_init( &pxSessionObj->xVerifyMutex ); } } if( CKR_OK == xResult ) { /* * Assign the session. */ pxSessionObj->ulState = ( 0UL != ( flags & CKF_RW_SESSION ) ) ? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION; LogDebug( ( "Assigned a 0x%0lX Type Session.", ( unsigned long int ) pxSessionObj->ulState ) ); } /* * Initialize the operation in progress. */ if( CKR_OK == xResult ) { pxSessionObj->xOperationDigestMechanism = pkcs11NO_OPERATION; pxSessionObj->xOperationVerifyMechanism = pkcs11NO_OPERATION; pxSessionObj->xOperationSignMechanism = pkcs11NO_OPERATION; LogDebug( ( "Assigned Mechanisms to no operation in progress." ) ); } if( xResult == CKR_SESSION_COUNT ) { /* No available session. */ LogError( ( "Could not open a session. All sessions have " "been taken. Consider increasing value of " "pkcs11configMAX_SESSIONS." ) ); } if( CKR_OK == xResult ) { /* Increment by one, as invalid handles in PKCS #11 are 0. */ ++ulSessionCount; *phSession = ulSessionCount; LogDebug( ( "Current session count at %lu", ( unsigned long int ) ( ulSessionCount - 1UL ) ) ); } return xResult; } /* @[declare_pkcs11_mbedtls_c_opensession] */ /** * @brief Closes a session. * * @param[in] hSession The session handle to * be terminated. * * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_closesession] */ CK_DECLARE_FUNCTION( CK_RV, C_CloseSession )( CK_SESSION_HANDLE hSession ) { P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xP11Context.xIsInitialized == ( CK_BBOOL ) CK_FALSE ) { xResult = CKR_CRYPTOKI_NOT_INITIALIZED; LogError( ( "Could not close a session. PKCS #11 must be initialized " "before any operations." ) ); } else if( pxSession == NULL ) { xResult = CKR_SESSION_HANDLE_INVALID; LogError( ( "Could not close a session. The PKCS #11 session handle " "was invalid." ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ else if( pxSession->xOpened == ( CK_BBOOL ) CK_TRUE ) { /* * Tear down the session. */ mbedtls_pk_free( &pxSession->xSignKey ); pxSession->xSignKeyHandle = CK_INVALID_HANDLE; mbedtls_mutex_free( &pxSession->xSignMutex ); /* Free the public key context if it exists. */ mbedtls_pk_free( &pxSession->xVerifyKey ); pxSession->xVerifyKeyHandle = CK_INVALID_HANDLE; mbedtls_mutex_free( &pxSession->xVerifyMutex ); mbedtls_sha256_free( &pxSession->xSHA256Context ); /* memset clears the open flag, so there is no need to set it to CK_FALSE */ ( void ) memset( pxSession, 0, sizeof( P11Session_t ) ); LogInfo( ( "Successfully closed PKCS #11 session." ) ); } else { /* MISRA */ } return xResult; } /* @[declare_pkcs11_mbedtls_c_closesession] */ /** * @brief Logs into a token. 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. */ /* @[declare_pkcs11_mbedtls_c_login] */ 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; LogDebug( ( "C_Login is not implemented." ) ); /* 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; } /* @[declare_pkcs11_mbedtls_c_login] */ /** * @brief Helper function for parsing the templates of device certificates for C_CreateObject. * * @param[in] pxTemplate Pointer to PKCS #11 attribute template. * @param[in] ulCount length of templates array. * @param[in] pxObject Pointer to PKCS #11 object. * @return CKR_OK. */ static CK_RV prvCreateCertificate( CK_ATTRIBUTE * 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; CK_ULONG ulIndex = 0; /* Search for the pointer to the certificate VALUE. */ for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) { xResult = prvCertAttParse( &pxTemplate[ ulIndex ], &xCertificateType, &pxCertificateValue, &xCertificateLength, &pxLabel ); if( xResult != CKR_OK ) { break; } } if( ( xResult == CKR_OK ) && ( ( pxCertificateValue == NULL ) || ( pxLabel == NULL ) ) ) { LogError( ( "Failed to create certificate. Could not parse the " "certificate value or label from the template." ) ); xResult = CKR_TEMPLATE_INCOMPLETE; } if( xResult == CKR_OK ) { xPalHandle = PKCS11_PAL_SaveObject( pxLabel, pxCertificateValue, xCertificateLength ); if( xPalHandle == 0UL ) /*Invalid handle. */ { LogError( ( "Failed to create certificate. Could not save the " "certificate to the PKCS #11 PAL." ) ); xResult = CKR_DEVICE_MEMORY; } } if( xResult == CKR_OK ) { xResult = prvAddObjectToList( xPalHandle, pxObject, pxLabel->pValue, pxLabel->ulValueLen ); } return xResult; } /** * @brief Helper to search an attribute for the key type attribute. * * @param[out] pxKeyType pointer to key type. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. */ static void prvGetKeyType( CK_KEY_TYPE * pxKeyType, const CK_ATTRIBUTE * 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 ) && ( xAttribute.ulValueLen == sizeof( CK_KEY_TYPE ) ) ) { LogDebug( ( "Successfully found the key type in the template." ) ); ( void ) memcpy( pxKeyType, xAttribute.pValue, sizeof( CK_KEY_TYPE ) ); break; } } } /** * @brief Helper to search a template for the label attribute. * * @param[out] ppxLabel pointer to label. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. */ static void prvGetLabel( CK_ATTRIBUTE ** ppxLabel, CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount ) { CK_ATTRIBUTE xAttribute; CK_ULONG ulIndex; *ppxLabel = NULL; for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) { xAttribute = pxTemplate[ ulIndex ]; if( xAttribute.type == CKA_LABEL ) { LogDebug( ( "Successfully found the label in the template." ) ); *ppxLabel = &pxTemplate[ ulIndex ]; break; } } } #ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM /** * @brief Helper to search a template for the label attribute. * * @param[in] pxPalHandle opaque handle to PKCS #11 object. * @param[in] pxMbedContext mbedTLS pk context for parsing. * @param[in] pxLabel label of PKCS #11 object. * * @note 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. */ static CK_RV prvGetExistingKeyComponent( CK_OBJECT_HANDLE_PTR pxPalHandle, mbedtls_pk_context * pxMbedContext, const CK_ATTRIBUTE * pxLabel ) { CK_BYTE_PTR pucData = NULL; CK_ULONG ulDataLength = 0; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xIsPrivate = ( CK_BBOOL ) CK_TRUE; CK_RV xResult = CKR_OK; int32_t lMbedTLSResult = 0; CK_BYTE pxPubKeyLabel[] = { pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS }; CK_BYTE pxPrivKeyLabel[] = { pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS }; *pxPalHandle = CK_INVALID_HANDLE; if( 0 == strncmp( pxLabel->pValue, pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS, pxLabel->ulValueLen ) ) { *pxPalHandle = PKCS11_PAL_FindObject( pxPrivKeyLabel, pxLabel->ulValueLen ); } else if( 0 == strncmp( pxLabel->pValue, pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS, pxLabel->ulValueLen ) ) { *pxPalHandle = PKCS11_PAL_FindObject( pxPubKeyLabel, pxLabel->ulValueLen ); /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xIsPrivate = ( CK_BBOOL ) CK_FALSE; } else { /* Unknown label passed to function */ LogWarn( ( "Unknown label found." ) ); } if( *pxPalHandle != CK_INVALID_HANDLE ) { xResult = PKCS11_PAL_GetObjectValue( *pxPalHandle, &pucData, &ulDataLength, &xIsPrivate ); } else { LogDebug( ( "Could not find an existing PKCS #11 PAL object." ) ); } if( ( xResult == CKR_OK ) && ( *pxPalHandle != CK_INVALID_HANDLE ) ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_TRUE ) { #if MBEDTLS_VERSION_NUMBER < 0x03000000 lMbedTLSResult = mbedtls_pk_parse_key( pxMbedContext, pucData, ulDataLength, NULL, 0 ); #else lMbedTLSResult = mbedtls_pk_parse_key( pxMbedContext, pucData, ulDataLength, NULL, 0, mbedtls_ctr_drbg_random, &xP11Context.xMbedDrbgCtx ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ } else { lMbedTLSResult = mbedtls_pk_parse_public_key( pxMbedContext, pucData, ulDataLength ); } PKCS11_PAL_GetObjectValueCleanup( pucData, ulDataLength ); } if( lMbedTLSResult != 0 ) { LogError( ( "Failed to get existing object value. mbedTLS pk parse " "failed with mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); *pxPalHandle = CK_INVALID_HANDLE; } return xResult; } /** * @brief Helper function to load an EC group to the mbed TLS pk context. * @param[in] pxMbedContext mbedtls context used to load EC group params. * */ static CK_RV prvLoadEcGroup( mbedtls_pk_context * pxMbedContext ) { CK_RV xResult = CKR_OK; mbedtls_ecp_keypair * pxKeyPair; int32_t lMbedTLSResult = 0; pxKeyPair = mbedtls_calloc( 1, sizeof( mbedtls_ecp_keypair ) ); if( pxKeyPair != NULL ) { /* Initialize the info. */ pxMbedContext->pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); /* Initialize the context. */ pxMbedContext->pk_ctx = pxKeyPair; mbedtls_ecp_keypair_init( pxKeyPair ); mbedtls_ecp_group_init( &pxKeyPair->grp ); /* At this time, only P-256 curves are supported. */ lMbedTLSResult = mbedtls_ecp_group_load( &pxKeyPair->grp, MBEDTLS_ECP_DP_SECP256R1 ); if( lMbedTLSResult != 0 ) { LogError( ( "Failed creating an EC key. " "mbedtls_ecp_group_load failed: mbed " "TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } } else { LogError( ( "Failed creating an EC key. Could not allocate a " "mbedtls_ecp_keypair struct." ) ); xResult = CKR_HOST_MEMORY; } return xResult; } /** * @brief Helper function for importing elliptic curve keys from * template using C_CreateObject. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. * @param[in] pxObject PKCS #11 object handle. * @param[in] xIsPrivate boolean indicating whether the key is private or public. */ static CK_RV prvCreateECKey( CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR pxObject, CK_BBOOL xIsPrivate ) { CK_RV xResult = CKR_OK; uint32_t ulIndex; CK_ATTRIBUTE_PTR pxLabel = NULL; CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; mbedtls_pk_context xMbedContext; mbedtls_pk_init( &xMbedContext ); prvGetLabel( &pxLabel, pxTemplate, ulCount ); if( pxLabel == NULL ) { LogError( ( "Failed to create an EC key. Received a NULL label pointer." ) ); xResult = CKR_ARGUMENTS_BAD; } else { xResult = prvGetExistingKeyComponent( &xPalHandle, &xMbedContext, pxLabel ); } if( ( xResult == CKR_OK ) && ( 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. */ xResult = prvLoadEcGroup( &xMbedContext ); } /* Key will be assembled in the mbedTLS key context and then exported to DER for storage. */ if( xResult == CKR_OK ) { for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) { xResult = prvEcKeyAttParse( &pxTemplate[ ulIndex ], &xMbedContext, xIsPrivate ); if( xResult != CKR_OK ) { break; } } } if( xResult == CKR_OK ) { xResult = prvSaveDerKeyToPal( &xMbedContext, pxObject, pxLabel, CKK_EC, xIsPrivate ); } /* Clean up the mbedTLS key context. */ mbedtls_pk_free( &xMbedContext ); return xResult; } #endif /* ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM */ /** * @brief Helper function for parsing RSA Private Key attribute templates * for C_CreateObject. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. * @param[in] pxObject PKCS #11 object handle. * @param[in] xIsPrivate boolean indicating whether the key is private or public. */ static CK_RV prvCreateRsaKey( CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR pxObject, CK_BBOOL xIsPrivate ) { CK_RV xResult = CKR_OK; mbedtls_pk_context xMbedContext = { 0 }; uint32_t ulIndex; CK_ATTRIBUTE_PTR pxLabel = NULL; /* mbedtls_rsa_context must be malloc'ed to use with mbedtls_pk_free function. */ mbedtls_rsa_context * pxRsaCtx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_context ) ); prvGetLabel( &pxLabel, pxTemplate, ulCount ); if( pxLabel == NULL ) { LogError( ( "Failed creating an RSA key. Label was a NULL pointer." ) ); xResult = CKR_ARGUMENTS_BAD; } if( pxRsaCtx != NULL ) { mbedtls_pk_init( &xMbedContext ); xMbedContext.pk_ctx = pxRsaCtx; xMbedContext.pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); #if MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_rsa_init( pxRsaCtx, MBEDTLS_RSA_PKCS_V15, 0 /*ignored.*/ ); #else mbedtls_rsa_init( pxRsaCtx ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ } else { LogError( ( "Failed creating an RSA key. Could not malloc a " "mbedtls_rsa_context struct." ) ); xResult = CKR_HOST_MEMORY; } if( xResult == CKR_OK ) { /* Parse template and collect the relevant parts. */ for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) { xResult = prvRsaKeyAttParse( &pxTemplate[ ulIndex ], xMbedContext.pk_ctx, xIsPrivate ); if( xResult != CKR_OK ) { break; } } } if( xResult == CKR_OK ) { xResult = prvSaveDerKeyToPal( &xMbedContext, pxObject, pxLabel, CKK_RSA, xIsPrivate ); } /* Clean up the mbedTLS key context. */ mbedtls_pk_free( &xMbedContext ); return xResult; } /** * @brief Parses attribute values for a HMAC Key. */ static CK_RV prvHMACKeyAttParse( const CK_ATTRIBUTE * pxAttribute, CK_BYTE_PTR * ppxHmacKey, CK_ULONG * pulHmacKeyLen ) { CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; switch( pxAttribute->type ) { case ( CKA_CLASS ): case ( CKA_KEY_TYPE ): case ( CKA_LABEL ): /* Do nothing. These values were parsed previously. */ break; case ( CKA_TOKEN ): case ( CKA_VERIFY ): case ( CKA_SIGN ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; case ( CKA_VALUE ): if( ( pxAttribute->ulValueLen >= PKCS11_SHA256_HMAC_MIN_SIZE ) && ( pxAttribute->pValue != NULL ) ) { *ppxHmacKey = pxAttribute->pValue; *pulHmacKeyLen = pxAttribute->ulValueLen; } else { LogError( ( "Failed to create SHA256-HMAC secret key. " "Key should be at least 32 bytes and/or non-NULL." ) ); xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; default: xResult = CKR_ATTRIBUTE_TYPE_INVALID; break; } return xResult; } /** * @brief Helper function for parsing SHA256-HMAC Key attribute templates * for C_CreateObject. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. * @param[in] pxObject PKCS #11 object handle. */ static CK_RV prvCreateSHA256HMAC( CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR pxObject ) { CK_RV xResult = CKR_OK; uint32_t ulIndex; CK_ATTRIBUTE_PTR pxLabel = NULL; CK_BYTE_PTR pxSecretKeyValue = NULL; CK_ULONG ulSecretKeyValueLen = 0; CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; prvGetLabel( &pxLabel, pxTemplate, ulCount ); if( pxLabel == NULL ) { LogError( ( "Failed creating a SHA256-HMAC key. Label was a NULL pointer." ) ); xResult = CKR_ARGUMENTS_BAD; } if( xResult == CKR_OK ) { for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) { xResult = prvHMACKeyAttParse( &pxTemplate[ ulIndex ], &pxSecretKeyValue, &ulSecretKeyValueLen ); if( xResult != CKR_OK ) { break; } } } if( ( xResult == CKR_OK ) && ( pxSecretKeyValue != NULL ) && ( ulSecretKeyValueLen >= PKCS11_SHA256_HMAC_MIN_SIZE ) ) { xPalHandle = PKCS11_PAL_SaveObject( pxLabel, pxSecretKeyValue, ulSecretKeyValueLen ); if( xPalHandle == CK_INVALID_HANDLE ) { LogError( ( "Failed saving HMAC secret key to flash. Failed to the PKCS #11 PAL." ) ); xResult = CKR_DEVICE_MEMORY; } else { xResult = prvAddObjectToList( xPalHandle, pxObject, pxLabel->pValue, pxLabel->ulValueLen ); } } return xResult; } /** * @brief Parses attribute values for a CMAC Key. */ static CK_RV prvCMACKeyAttParse( const CK_ATTRIBUTE * pxAttribute, CK_BYTE_PTR * ppxCmacKey, CK_ULONG * pulCmacKeyLen ) { CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; switch( pxAttribute->type ) { case ( CKA_CLASS ): case ( CKA_KEY_TYPE ): case ( CKA_LABEL ): /* Do nothing. These values were parsed previously. */ break; case ( CKA_TOKEN ): case ( CKA_VERIFY ): case ( CKA_SIGN ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; case ( CKA_VALUE ): if( ( pxAttribute->ulValueLen >= PKCS11_AES_CMAC_MIN_SIZE ) && ( pxAttribute->pValue != NULL ) ) { *ppxCmacKey = pxAttribute->pValue; *pulCmacKeyLen = pxAttribute->ulValueLen; } else { LogError( ( "Failed to create SHA256-HMAC secret key. " "Key should be at least 32 bytes and/or non-NULL." ) ); xResult = CKR_ATTRIBUTE_VALUE_INVALID; } break; default: xResult = CKR_ATTRIBUTE_TYPE_INVALID; break; } return xResult; } /** * @brief Helper function for parsing AES-CMAC Key attribute templates * for C_CreateObject. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. * @param[in] pxObject PKCS #11 object handle. */ static CK_RV prvCreateAESCMAC( CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR pxObject ) { CK_RV xResult = CKR_OK; uint32_t ulIndex; CK_ATTRIBUTE_PTR pxLabel = NULL; CK_BYTE_PTR pxSecretKeyValue = NULL; CK_ULONG ulSecretKeyValueLen = 0; CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; prvGetLabel( &pxLabel, pxTemplate, ulCount ); if( pxLabel == NULL ) { LogError( ( "Failed creating an AES-CMAC key. Label was a NULL pointer." ) ); xResult = CKR_ARGUMENTS_BAD; } if( xResult == CKR_OK ) { for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) { xResult = prvCMACKeyAttParse( &pxTemplate[ ulIndex ], &pxSecretKeyValue, &ulSecretKeyValueLen ); if( xResult != CKR_OK ) { break; } } } if( ( xResult == CKR_OK ) && ( pxSecretKeyValue != NULL ) ) { xPalHandle = PKCS11_PAL_SaveObject( pxLabel, pxSecretKeyValue, ulSecretKeyValueLen ); if( xPalHandle == CK_INVALID_HANDLE ) { LogError( ( "Failed saving CMAC secret key to flash. Failed to the PKCS #11 PAL." ) ); xResult = CKR_DEVICE_MEMORY; } else { xResult = prvAddObjectToList( xPalHandle, pxObject, pxLabel->pValue, pxLabel->ulValueLen ); } } return xResult; } /** * @brief Helper function for importing private keys using template * C_CreateObject. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. * @param[in] pxObject PKCS #11 object handle. */ static CK_RV prvCreatePrivateKey( CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR pxObject ) { CK_RV xResult = CKR_OK; CK_KEY_TYPE xKeyType; prvGetKeyType( &xKeyType, pxTemplate, ulCount ); if( xKeyType == CKK_RSA ) { xResult = prvCreateRsaKey( pxTemplate, ulCount, pxObject, /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ ( CK_BBOOL ) CK_TRUE ); } #ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM /* CKK_EC = CKK_ECDSA. */ else if( xKeyType == CKK_EC ) { xResult = prvCreateECKey( pxTemplate, ulCount, pxObject, /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ ( CK_BBOOL ) CK_TRUE ); } #endif /* pkcs11configSUPPRESS_ECDSA_MECHANISM */ else { LogError( ( "Failed to create a key. Tried to create a key with an " "invalid or unknown mechanism." ) ); xResult = CKR_MECHANISM_INVALID; } return xResult; } /** * @brief Helper function for importing public keys using * C_CreateObject. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. * @param[in] pxObject PKCS #11 object handle. */ static CK_RV prvCreatePublicKey( CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR pxObject ) { CK_KEY_TYPE xKeyType = 0; CK_RV xResult = CKR_OK; prvGetKeyType( &xKeyType, pxTemplate, ulCount ); if( xKeyType == CKK_RSA ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xResult = prvCreateRsaKey( pxTemplate, ulCount, pxObject, ( CK_BBOOL ) CK_FALSE ); } #ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM else if( xKeyType == CKK_EC ) /* CKK_EC = CKK_ECDSA. */ { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xResult = prvCreateECKey( pxTemplate, ulCount, pxObject, ( CK_BBOOL ) CK_FALSE ); } #endif /* ifndef pkcs11configSUPPRESS_ECDSA_MECHANISM */ else { LogError( ( "Failed to create public key. Received an invalid mechanism. " "Invalid key type 0x%0lX", ( unsigned long int ) xKeyType ) ); xResult = CKR_MECHANISM_INVALID; } return xResult; } /** * @brief Helper function for importing secret keys using template * C_CreateObject. * @param[in] pxTemplate templates to search for a key in. * @param[in] ulCount length of templates array. * @param[in] pxObject PKCS #11 object handle. */ static CK_RV prvCreateSecretKey( CK_ATTRIBUTE * pxTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR pxObject ) { CK_RV xResult = CKR_OK; CK_KEY_TYPE xKeyType; prvGetKeyType( &xKeyType, pxTemplate, ulCount ); if( xKeyType == CKK_SHA256_HMAC ) { xResult = prvCreateSHA256HMAC( pxTemplate, ulCount, pxObject ); } else if( xKeyType == CKK_AES ) { xResult = prvCreateAESCMAC( pxTemplate, ulCount, pxObject ); } else { LogError( ( "Failed to create a key. Tried to create a key with an " "invalid or unknown mechanism. Only CKK_SHA256_HMAC is " "currently supported." ) ); xResult = CKR_MECHANISM_INVALID; } return xResult; } /** * @brief Creates an object. * * @param[in] hSession Handle of a valid PKCS #11 session. * @param[in] pTemplate List of attributes of the object to * be created. * @param[in] ulCount Number of attributes in pTemplate. * @param[out] phObject Pointer to the location where the created * object's handle will be placed. * * *
Object Type Template Attributes *
CertificateCKA_CLASS *
CKA_VALUE *
CKA_TOKEN *
CKA_LABEL *
CKA_CERTIFICATE_TYPE *
CKA_VALUE *
EC Private KeyCKA_CLASS *
CKA_KEY_TYPE *
CKA_TOKEN *
CKA_LABEL *
CKA_SIGN *
CKA_EC_PARAMS *
CKA_VALUE *
EC Public KeyCKA_CLASS *
CKA_KEY_TYPE *
CKA_TOKEN *
CKA_VERIFY *
CKA_LABEL *
CKA_EC_PARAMS *
CKA_EC_POINT *
RSA Private KeyCKA_CLASS *
CKA_KEY_TYPE *
CKA_TOKEN *
CKA_LABEL *
CKA_SIGN *
CKA_MODULUS *
CKA_PUBLIC_EXPONENT *
CKA_PRIME_1 *
CKA_PRIME_2 *
CKA_PRIVATE_EXPONENT *
CKA_EXPONENT_1 *
CKA_EXPONENT_2 *
CKA_COEFFICIENT *
* * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_createobject] */ CK_DECLARE_FUNCTION( CK_RV, C_CreateObject )( CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject ) { CK_OBJECT_CLASS xClass = 0; const P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); if( ( NULL == pTemplate ) || ( NULL == phObject ) ) { LogError( ( "Failed to create object. Received a NULL template or " "object pointer." ) ); xResult = CKR_ARGUMENTS_BAD; } if( xResult == CKR_OK ) { xResult = prvGetObjectClass( pTemplate, ulCount, &xClass ); } if( xResult == CKR_OK ) { LogInfo( ( "Creating a 0x%0lX type object.", ( unsigned long int ) xClass ) ); switch( xClass ) { case CKO_CERTIFICATE: xResult = prvCreateCertificate( pTemplate, ulCount, phObject ); break; case CKO_PRIVATE_KEY: xResult = prvCreatePrivateKey( pTemplate, ulCount, phObject ); break; case CKO_PUBLIC_KEY: xResult = prvCreatePublicKey( pTemplate, ulCount, phObject ); break; case CKO_SECRET_KEY: xResult = prvCreateSecretKey( pTemplate, ulCount, phObject ); break; default: xResult = CKR_ATTRIBUTE_VALUE_INVALID; break; } } return xResult; } /* @[declare_pkcs11_mbedtls_c_createobject] */ /** * @brief Destroys an object. * * @param[in] hSession Handle of a valid PKCS #11 session. * @param[in] hObject Handle of the object to be destroyed. * * @warning 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. */ /* @[declare_pkcs11_mbedtls_c_destroyobject] */ CK_DECLARE_FUNCTION( CK_RV, C_DestroyObject )( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject ) { const P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; CK_BYTE_PTR pcLabel = NULL; CK_ULONG xLabelLength = 0; prvFindObjectInListByHandle( hObject, &xPalHandle, &pcLabel, &xLabelLength ); if( xPalHandle == CK_INVALID_HANDLE ) { xResult = CKR_OBJECT_HANDLE_INVALID; } if( xResult == CKR_OK ) { xResult = PKCS11_PAL_DestroyObject( xPalHandle ); if( xResult == CKR_OK ) { xResult = prvDeleteObjectFromList( xPalHandle ); } else { LogError( ( "Failed to destroy object. PKCS11_PAL_DestroyObject failed." ) ); } } else { LogError( ( "Failed to destroy object. The session was invalid." ) ); } return xResult; } /* @[declare_pkcs11_mbedtls_c_destroyobject] */ /** * @brief Obtains an attribute value of an object. * @param[in] hSession Handle of a valid PKCS #11 session. * @param[in] hObject PKCS #11 object handle to be queried. * @param[in,out] pTemplate 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. * * *
Object Type Queryable Attributes *
CertificateCKA_CLASS *
CKA_VALUE *
EC Private KeyCKA_CLASS *
CKA_KEY_TYPE *
CKA_EC_PARAMS *
EC Public KeyCKA_CLASS *
CKA_KEY_TYPE *
CKA_EC_PARAMS *
CKA_EC_POINT *
RSA Private KeyCKA_CLASS *
CKA_KEY_TYPE *
RSA Public KeyCKA_CLASS *
CKA_KEY_TYPE *
* * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_getattributevalue] */ CK_DECLARE_FUNCTION( CK_RV, C_GetAttributeValue )( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xIsPrivate = ( CK_BBOOL ) CK_TRUE; CK_ULONG iAttrib; mbedtls_pk_context xKeyContext = { 0 }; mbedtls_x509_crt xMbedX509Context = { 0 }; mbedtls_pk_type_t xKeyType; const mbedtls_ecp_keypair * pxKeyPair; CK_KEY_TYPE xPkcsKeyType = ( CK_KEY_TYPE ) ~0UL; CK_OBJECT_CLASS xClass = ~0UL; CK_BYTE_PTR pxObjectValue = NULL; CK_ULONG ulLength = 0; const CK_BYTE ucP256Oid[] = pkcs11DER_ENCODED_OID_P256; int32_t lMbedTLSResult = 0; CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; CK_ULONG xSize = 0; size_t xMbedSize = 0; CK_BYTE_PTR pcLabel = NULL; const P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); if( ( CKR_OK == xResult ) && ( ( ( NULL == pTemplate ) ) || ( 0UL == ulCount ) ) ) { LogError( ( "Failed to get attribute. The template was a NULL pointer " "or the attribute count was 0." ) ); xResult = CKR_ARGUMENTS_BAD; } if( ( CKR_OK == xResult ) && ( CK_INVALID_HANDLE == hObject ) ) { LogError( ( "Failed to get attribute. The object handle was invalid." ) ); xResult = CKR_OBJECT_HANDLE_INVALID; } if( xResult == CKR_OK ) { /* * Copy the object into a buffer. */ prvFindObjectInListByHandle( hObject, &xPalHandle, &pcLabel, &xSize ); /*pcLabel and xSize are ignored. */ if( xPalHandle != CK_INVALID_HANDLE ) { xResult = PKCS11_PAL_GetObjectValue( xPalHandle, &pxObjectValue, &ulLength, &xIsPrivate ); } else { LogError( ( "Failed to get attribute. Could not find a valid " "PKCS #11 PAL handle." ) ); xResult = CKR_OBJECT_HANDLE_INVALID; } } /* Determine what kind of object we are dealing with. */ if( xResult == CKR_OK ) { /* Initialize mbed TLS key context. */ mbedtls_pk_init( &xKeyContext ); /* Initialize mbed TLS x509 context. */ mbedtls_x509_crt_init( &xMbedX509Context ); #if MBEDTLS_VERSION_NUMBER < 0x03000000 lMbedTLSResult = mbedtls_pk_parse_key( &xKeyContext, pxObjectValue, ulLength, NULL, 0 ); #else lMbedTLSResult = mbedtls_pk_parse_key( &xKeyContext, pxObjectValue, ulLength, NULL, 0, mbedtls_ctr_drbg_random, &xP11Context.xMbedDrbgCtx ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ if( lMbedTLSResult == 0 ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_TRUE ) { LogDebug( ( "Object was a private key." ) ); xClass = CKO_PRIVATE_KEY; } else { LogDebug( ( "Object was a public key." ) ); xClass = CKO_PUBLIC_KEY; } } else if( 0 == mbedtls_pk_parse_public_key( &xKeyContext, pxObjectValue, ulLength ) ) { LogDebug( ( "Object was a public key." ) ); xClass = CKO_PUBLIC_KEY; } else if( 0 == mbedtls_x509_crt_parse( &xMbedX509Context, pxObjectValue, ulLength ) ) { LogDebug( ( "Object was a certificate." ) ); xClass = CKO_CERTIFICATE; } else { LogDebug( ( "Object handle was invalid." ) ); xResult = CKR_OBJECT_HANDLE_INVALID; } } if( xResult == CKR_OK ) { for( iAttrib = 0; iAttrib < ulCount; iAttrib++ ) { if( xResult != CKR_OK ) { break; } switch( pTemplate[ iAttrib ].type ) { case CKA_CLASS: if( pTemplate[ iAttrib ].pValue == NULL ) { pTemplate[ iAttrib ].ulValueLen = sizeof( CK_OBJECT_CLASS ); } else { if( pTemplate[ iAttrib ].ulValueLen == sizeof( CK_OBJECT_CLASS ) ) { ( void ) memcpy( pTemplate[ iAttrib ].pValue, &xClass, sizeof( CK_OBJECT_CLASS ) ); } else { LogError( ( "Failed to parse attribute template. " "Received a buffer smaller than CK_OBJECT_CLASS." ) ); xResult = CKR_BUFFER_TOO_SMALL; } } break; case CKA_PUBLIC_KEY_INFO: case CKA_VALUE: /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate == ( CK_BBOOL ) CK_TRUE ) { pTemplate[ iAttrib ].ulValueLen = CK_UNAVAILABLE_INFORMATION; LogError( ( "Failed to parse attribute. This data is " "sensitive and the value will not be returned." ) ); xResult = CKR_ATTRIBUTE_SENSITIVE; } else { if( pTemplate[ iAttrib ].pValue == NULL ) { pTemplate[ iAttrib ].ulValueLen = ulLength; } else if( pTemplate[ iAttrib ].ulValueLen < ulLength ) { LogError( ( "Failed to parse attribute. Buffer was " "too small to contain data. Expected %lu " "but got %lu.", ( unsigned long int ) ulLength, ( unsigned long int ) pTemplate[ iAttrib ].ulValueLen ) ); xResult = CKR_BUFFER_TOO_SMALL; } else { ( void ) memcpy( pTemplate[ iAttrib ].pValue, pxObjectValue, ulLength ); } } break; case CKA_KEY_TYPE: if( pTemplate[ iAttrib ].pValue == NULL ) { pTemplate[ iAttrib ].ulValueLen = sizeof( CK_KEY_TYPE ); } else if( pTemplate[ iAttrib ].ulValueLen < sizeof( CK_KEY_TYPE ) ) { LogError( ( "Failed to parse attribute. Expected buffer " "of size CK_KEY_TYPE." ) ); xResult = CKR_BUFFER_TOO_SMALL; } 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: LogError( ( "Failed to parse attribute. " "Could not parse key type." ) ); xResult = CKR_ATTRIBUTE_VALUE_INVALID; break; } ( void ) memcpy( pTemplate[ iAttrib ].pValue, &xPkcsKeyType, sizeof( CK_KEY_TYPE ) ); } break; case CKA_PRIVATE_EXPONENT: LogError( ( "Failed to parse attribute. " "CKA_PRIVATE_EXPONENT is private data." ) ); xResult = CKR_ATTRIBUTE_SENSITIVE; break; case CKA_EC_PARAMS: if( pTemplate[ iAttrib ].pValue == NULL ) { pTemplate[ iAttrib ].ulValueLen = sizeof( ucP256Oid ); } else { if( pTemplate[ iAttrib ].ulValueLen < sizeof( ucP256Oid ) ) { LogError( ( "Failed to parse attribute. " "CKA_EC_PARAMS buffer too small." ) ); xResult = CKR_BUFFER_TOO_SMALL; } else { ( void ) memcpy( pTemplate[ iAttrib ].pValue, ucP256Oid, sizeof( ucP256Oid ) ); } } break; case CKA_EC_POINT: if( pTemplate[ iAttrib ].pValue == NULL ) { pTemplate[ iAttrib ].ulValueLen = pkcs11EC_POINT_LENGTH; } else { if( pTemplate[ iAttrib ].ulValueLen == pkcs11EC_POINT_LENGTH ) { pxKeyPair = ( mbedtls_ecp_keypair * ) xKeyContext.pk_ctx; *( ( uint8_t * ) pTemplate[ iAttrib ].pValue ) = 0x04; /* Mark the point as uncompressed. */ /* Copy xSize value to avoid casting a CK_ULONG size pointer * to a size_t sized pointer. */ xMbedSize = xSize; lMbedTLSResult = mbedtls_ecp_tls_write_point( &pxKeyPair->grp, &pxKeyPair->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &xMbedSize, ( uint8_t * ) pTemplate[ iAttrib ].pValue + 1, pTemplate[ iAttrib ].ulValueLen - 1UL ); xSize = xMbedSize; } else { xResult = CKR_BUFFER_TOO_SMALL; } if( ( xResult == CKR_OK ) && ( lMbedTLSResult < 0 ) ) { if( lMbedTLSResult == MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ) { LogError( ( "Failed to extract EC point. " "CKA_EC_POINT buffer was too small." ) ); xResult = CKR_BUFFER_TOO_SMALL; } else { LogError( ( "Failed to extract EC point. " "mbedtls_ecp_tls_write_point failed: " "mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } } else { pTemplate[ iAttrib ].ulValueLen = xSize + 1UL; } } break; default: LogError( ( "Failed to parse attribute. Received unknown " "attribute type." ) ); xResult = CKR_ATTRIBUTE_TYPE_INVALID; break; } } /* 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 ); /* Free the mbedTLS structure used to parse the certificate. */ mbedtls_x509_crt_free( &xMbedX509Context ); } return xResult; } /* @[declare_pkcs11_mbedtls_c_getattributevalue] */ /** * @brief Initializes an object search operation. * * \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] hSession Handle of a valid PKCS #11 session. * @param[in] pTemplate 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 pTemplate. * * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_findobjectsinit] */ CK_DECLARE_FUNCTION( CK_RV, C_FindObjectsInit )( CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount ) { P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); CK_BYTE * pxFindObjectLabel = NULL; uint32_t ulIndex; CK_ATTRIBUTE xAttribute; if( NULL == pTemplate ) { xResult = CKR_ARGUMENTS_BAD; } if( ( ulCount != 1UL ) && ( ulCount != 2UL ) ) { xResult = CKR_ARGUMENTS_BAD; LogError( ( "Failed to initialize find object operation. Find objects " "does not support searching by %lu attributes. Expected to " "search with either 1 or 2 attributes.", ( unsigned long int ) ulCount ) ); } if( xResult == CKR_OK ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( prvOperationActive( pxSession ) == ( CK_BBOOL ) CK_TRUE ) { xResult = CKR_OPERATION_ACTIVE; LogError( ( "Failed to initialize find object operation. Find " "object operation was already in progress." ) ); } } /* 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++ ) { xAttribute = pTemplate[ ulIndex ]; if( ( xAttribute.type == CKA_LABEL ) && ( xAttribute.ulValueLen <= pkcs11configMAX_LABEL_LENGTH ) ) { /* Plus one to leave room for a NULL terminator. */ pxFindObjectLabel = mbedtls_calloc( 1, xAttribute.ulValueLen + 1UL ); if( pxFindObjectLabel != NULL ) { pxSession->xFindObjectLabelLen = xAttribute.ulValueLen; pxSession->pxFindObjectLabel = pxFindObjectLabel; ( void ) memcpy( pxSession->pxFindObjectLabel, xAttribute.pValue, xAttribute.ulValueLen ); xResult = CKR_OK; } else { LogError( ( "Failed to initialize find object operation. Failed to " "allocate %lu bytes.", ( unsigned long int ) xAttribute.ulValueLen + 1UL ) ); xResult = CKR_HOST_MEMORY; } } else { LogDebug( ( "Search parameters other than label are ignored." ) ); } } } /* Clean up memory if there was an error parsing the template. */ if( ( pxSession != NULL ) && ( xResult != CKR_OK ) && ( xResult != CKR_OPERATION_ACTIVE ) ) { mbedtls_free( pxFindObjectLabel ); pxSession->pxFindObjectLabel = NULL; pxSession->xFindObjectLabelLen = 0; } return xResult; } /* @[declare_pkcs11_mbedtls_c_findobjectsinit] */ /** * @brief Initializes an object search operation. * * \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] hSession Handle of a valid PKCS #11 session. * @param[out] phObject Points to the handle of the object to * be found. * @param[in] ulMaxObjectCount The size of the phObject 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. */ /* @[declare_pkcs11_mbedtls_c_findobjects] */ CK_DECLARE_FUNCTION( CK_RV, C_FindObjects )( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount ) { P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; /* * Check parameters. */ if( ( NULL == phObject ) || ( NULL == pulObjectCount ) ) { LogError( ( "Failed to find objects. The object handle or the object " "count pointer was NULL." ) ); xResult = CKR_ARGUMENTS_BAD; } if( xResult == CKR_OK ) { if( pxSession->pxFindObjectLabel == NULL ) { LogError( ( "Failed to find objects. The PKCS #11 stack must be " "initialized before any operations." ) ); xResult = CKR_OPERATION_NOT_INITIALIZED; } if( 1u != ulMaxObjectCount ) { xResult = CKR_ARGUMENTS_BAD; LogError( ( "Failed to find objects. Searching for anything other " "than 1 object at a time is not supported." ) ); } } if( xResult == CKR_OK ) { /* Try to find the object in module's list first. */ prvFindObjectInListByLabel( pxSession->pxFindObjectLabel, pxSession->xFindObjectLabelLen, &xPalHandle, phObject ); /* Check with the PAL if the object was previously stored. */ if( *phObject == CK_INVALID_HANDLE ) { LogDebug( ( "Could not find the object handle in the list. " "Trying to search PKCS #11 PAL for object." ) ); xPalHandle = PKCS11_PAL_FindObject( pxSession->pxFindObjectLabel, pxSession->xFindObjectLabelLen ); } if( xPalHandle != CK_INVALID_HANDLE ) { LogDebug( ( "Found object in PAL. Adding object handle to list." ) ); xResult = prvAddObjectToList( xPalHandle, phObject, pxSession->pxFindObjectLabel, pxSession->xFindObjectLabelLen ); *pulObjectCount = 1; } 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; } } /* Clean up memory if there was an error finding the object. */ if( xResult != CKR_OK ) { if( pxSession != NULL ) { mbedtls_free( pxSession->pxFindObjectLabel ); pxSession->pxFindObjectLabel = NULL; pxSession->xFindObjectLabelLen = 0; } } return xResult; } /* @[declare_pkcs11_mbedtls_c_findobjects] */ /** * @brief Finishes 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] hSession Handle of a valid PKCS #11 session. * * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_findobjectsfinal] */ CK_DECLARE_FUNCTION( CK_RV, C_FindObjectsFinal )( CK_SESSION_HANDLE hSession ) { P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); /* * Check parameters. */ if( xResult == CKR_OK ) { if( pxSession->pxFindObjectLabel == NULL ) { LogError( ( "Failed to end find objects operation. Find operation " "must be initialized." ) ); xResult = CKR_OPERATION_NOT_INITIALIZED; } } if( xResult == CKR_OK ) { /* * Clean-up find objects state. */ mbedtls_free( pxSession->pxFindObjectLabel ); pxSession->pxFindObjectLabel = NULL; pxSession->xFindObjectLabelLen = 0; } return xResult; } /* @[declare_pkcs11_mbedtls_c_findobjectsfinal] */ /** * @brief Initializes a message-digesting 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] hSession 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. */ /* @[declare_pkcs11_mbedtls_c_digestinit] */ CK_DECLARE_FUNCTION( CK_RV, C_DigestInit )( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism ) { P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); int32_t lMbedTLSResult = 0; if( pMechanism == NULL ) { LogError( ( "Failed to initialize digest operation. Mechanism pointer " "was NULL." ) ); xResult = CKR_ARGUMENTS_BAD; } if( xResult == CKR_OK ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( prvOperationActive( pxSession ) == ( CK_BBOOL ) CK_TRUE ) { LogError( ( "Failed to initialize digest operation. An operation " "was already active." ) ); xResult = CKR_OPERATION_ACTIVE; } } if( xResult == CKR_OK ) { if( pMechanism->mechanism != CKM_SHA256 ) { LogError( ( "Failed to initialize digest operation. Currently only " "the CKM_SHA256 mechanism is supported." ) ); xResult = CKR_MECHANISM_INVALID; } } /* * Initialize the requested hash type */ if( xResult == CKR_OK ) { mbedtls_sha256_init( &pxSession->xSHA256Context ); #if MBEDTLS_VERSION_NUMBER < 0x03000000 lMbedTLSResult = mbedtls_sha256_starts_ret( &pxSession->xSHA256Context, 0 ); #else lMbedTLSResult = mbedtls_sha256_starts( &pxSession->xSHA256Context, 0 ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ if( 0 != lMbedTLSResult ) { LogError( ( "Failed to initialize digest operation. " "mbedtls_sha256_starts_ret failed with: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } else { pxSession->xOperationDigestMechanism = pMechanism->mechanism; } } return xResult; } /* @[declare_pkcs11_mbedtls_c_digestinit] */ /** * @brief Continues a multiple-part digesting 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] hSession 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. */ /* @[declare_pkcs11_mbedtls_c_digestupdate] */ CK_DECLARE_FUNCTION( CK_RV, C_DigestUpdate )( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen ) { P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); int32_t lMbedTLSResult = 0; if( pPart == NULL ) { LogError( ( "Failed to start digest operation. Received a NULL pointer " "in digest request." ) ); xResult = CKR_ARGUMENTS_BAD; } if( xResult == CKR_OK ) { if( pxSession->xOperationDigestMechanism != CKM_SHA256 ) { LogError( ( "Failed to start digest operation. CKM_SHA256 is the " "expected digest mechanism." ) ); xResult = CKR_OPERATION_NOT_INITIALIZED; } } if( xResult == CKR_OK ) { #if MBEDTLS_VERSION_NUMBER < 0x03000000 lMbedTLSResult = mbedtls_sha256_update_ret( &pxSession->xSHA256Context, pPart, ulPartLen ); #else lMbedTLSResult = mbedtls_sha256_update( &pxSession->xSHA256Context, pPart, ulPartLen ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ if( 0 != lMbedTLSResult ) { LogError( ( "Failed to perform digest operation. " "mbedtls_sha256_update_ret failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); pxSession->xOperationDigestMechanism = pkcs11NO_OPERATION; xResult = CKR_FUNCTION_FAILED; } } if( ( xResult != CKR_OK ) && ( xResult != CKR_SESSION_HANDLE_INVALID ) && ( xResult != CKR_OPERATION_NOT_INITIALIZED ) ) { LogDebug( ( "Tearing down operation due to errors." ) ); pxSession->xOperationDigestMechanism = pkcs11NO_OPERATION; mbedtls_sha256_free( &pxSession->xSHA256Context ); } return xResult; } /* @[declare_pkcs11_mbedtls_c_digestupdate] */ /** * @brief Finishes a multiple-part digesting 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] hSession 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. */ /* @[declare_pkcs11_mbedtls_c_digestfinal] */ CK_DECLARE_FUNCTION( CK_RV, C_DigestFinal )( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen ) { P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); int32_t lMbedTLSResult = 0; if( pulDigestLen == NULL ) { LogError( ( "Failed to finish digest operation. Digest Length pointer " "was NULL." ) ); xResult = CKR_ARGUMENTS_BAD; } if( xResult == CKR_OK ) { if( pxSession->xOperationDigestMechanism != CKM_SHA256 ) { LogError( ( "Failed to finish digest operation. Digest operation " "was not initialized." ) ); xResult = CKR_OPERATION_NOT_INITIALIZED; pxSession->xOperationDigestMechanism = pkcs11NO_OPERATION; } } if( xResult == CKR_OK ) { if( pDigest == NULL ) { /* Supply the required buffer size. */ *pulDigestLen = ( CK_ULONG ) pkcs11SHA256_DIGEST_LENGTH; } else { if( *pulDigestLen == ( CK_ULONG ) pkcs11SHA256_DIGEST_LENGTH ) { #if MBEDTLS_VERSION_NUMBER < 0x03000000 lMbedTLSResult = mbedtls_sha256_finish_ret( &pxSession->xSHA256Context, pDigest ); #else lMbedTLSResult = mbedtls_sha256_finish( &pxSession->xSHA256Context, pDigest ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ if( 0 != lMbedTLSResult ) { LogError( ( "Failed to finish digest operation. " "mbedtls_sha256_finish_ret failed: mbed TLS " "error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } pxSession->xOperationDigestMechanism = pkcs11NO_OPERATION; } else { LogError( ( "Failed to finish digest operation. Received a " "buffer that was an unexpected size. Expected %lu and " "received %lu.", ( unsigned long int ) pkcs11SHA256_DIGEST_LENGTH, ( unsigned long int ) *pulDigestLen ) ); xResult = CKR_BUFFER_TOO_SMALL; } } } if( ( xResult != CKR_OK ) && ( xResult != CKR_BUFFER_TOO_SMALL ) && ( xResult != CKR_SESSION_HANDLE_INVALID ) && ( xResult != CKR_OPERATION_NOT_INITIALIZED ) ) { LogDebug( ( "Error occurred, tearing down digest operation." ) ); pxSession->xOperationDigestMechanism = pkcs11NO_OPERATION; mbedtls_sha256_free( &pxSession->xSHA256Context ); } return xResult; } /* @[declare_pkcs11_mbedtls_c_digestfinal] */ /** * @brief Helper function for cleaning up a HMAC operation. * @param[in] pxSession Pointer to a valid PKCS #11 session. */ static void prvHMACCleanUp( P11Session_t * pxSession ) { pxSession->xHMACKeyHandle = CK_INVALID_HANDLE; mbedtls_md_free( &pxSession->xHMACSecretContext ); } /** * @brief Helper function for initializing a SHA256-HMAC operation. * @param[in] pxSession Pointer to a valid PKCS #11 session. * @param[in] hKey HMAC secret key handle. * @param[in] pucKeyData HMAC secret key data. * @param[in] ulKeyDataLength HMAC key Size. */ static CK_RV prvInitSHA256HMAC( P11Session_t * pxSession, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pucKeyData, CK_ULONG ulKeyDataLength ) { CK_RV xResult = CKR_OK; int32_t lMbedTLSResult = 0; const mbedtls_md_info_t * pxMdInfo = NULL; mbedtls_md_init( &pxSession->xHMACSecretContext ); pxMdInfo = mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); if( pxMdInfo == NULL ) { LogError( ( "Failed to initialize SHA256HMAC operation. " "mbedtls_md_info_from_type failed. Consider " "double checking the mbedtls_md_type_t object " "that was used." ) ); xResult = CKR_FUNCTION_FAILED; prvHMACCleanUp( pxSession ); } if( xResult == CKR_OK ) { lMbedTLSResult = mbedtls_md_setup( &pxSession->xHMACSecretContext, pxMdInfo, PKCS11_USING_HMAC ); if( lMbedTLSResult != 0 ) { LogError( ( "Failed to initialize SHA256HMAC operation. " "mbedtls_md_setup failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); prvHMACCleanUp( pxSession ); xResult = CKR_KEY_HANDLE_INVALID; } } if( xResult == CKR_OK ) { lMbedTLSResult = mbedtls_md_hmac_starts( &pxSession->xHMACSecretContext, pucKeyData, ulKeyDataLength ); if( lMbedTLSResult != 0 ) { LogError( ( "Failed to initialize SHA256HMAC operation. " "mbedtls_md_setup failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); prvHMACCleanUp( pxSession ); xResult = CKR_KEY_HANDLE_INVALID; } } if( xResult == CKR_OK ) { pxSession->xHMACKeyHandle = hKey; } return xResult; } /** * @brief Helper function for initializing a sign operation for SHA256-HMAC. * @param[in] pxSession Pointer to a valid PKCS #11 session. * @param[in] hKey HMAC secret key handle. * @param[in] pucKeyData HMAC secret key data. * @param[in] ulKeyDataLength HMAC key Size. */ static CK_RV prvSignInitSHA256HMAC( P11Session_t * pxSession, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pucKeyData, CK_ULONG ulKeyDataLength ) { CK_RV xResult = CKR_OK; xResult = prvInitSHA256HMAC( pxSession, hKey, pucKeyData, ulKeyDataLength ); return xResult; } /** * @brief Helper function for cleaning up an CMAC operation. * @param[in] pxSession Pointer to a valid PKCS #11 session. */ static void prvCMACCleanUp( P11Session_t * pxSession ) { pxSession->xCMACKeyHandle = CK_INVALID_HANDLE; mbedtls_cipher_free( &pxSession->xCMACSecretContext ); } /** * @brief Helper function for initializing a AES-CMAC operation. * @param[in] pxSession Pointer to a valid PKCS #11 session. * @param[in] hKey CMAC secret key handle. * @param[in] pucKeyData CMAC secret key data. * @param[in] ulKeyDataLength CMAC key Size. */ static CK_RV prvInitAESCMAC( P11Session_t * pxSession, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pucKeyData, CK_ULONG ulKeyDataLength ) { CK_RV xResult = CKR_OK; int32_t lMbedTLSResult = -1; const mbedtls_cipher_info_t * pxCipherInfo = NULL; size_t ulKeyDataBitLength = 8UL * ulKeyDataLength; mbedtls_cipher_init( &pxSession->xCMACSecretContext ); pxCipherInfo = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_AES_128_ECB ); if( pxCipherInfo == NULL ) { LogError( ( "Failed to initialize AES-CMAC operation. " "mbedtls_cipher_info_from_type failed. Consider " "double checking the mbedtls_md_type_t object " "that was used." ) ); xResult = CKR_FUNCTION_FAILED; prvCMACCleanUp( pxSession ); } if( xResult == CKR_OK ) { lMbedTLSResult = mbedtls_cipher_setup( &pxSession->xCMACSecretContext, pxCipherInfo ); if( lMbedTLSResult != 0 ) { LogError( ( "Failed to initialize AES-CMAC operation. " "mbedtls_cipher_setup failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); prvCMACCleanUp( pxSession ); xResult = CKR_KEY_HANDLE_INVALID; } } if( xResult == CKR_OK ) { lMbedTLSResult = mbedtls_cipher_cmac_starts( &pxSession->xCMACSecretContext, pucKeyData, ulKeyDataBitLength ); if( lMbedTLSResult != 0 ) { LogError( ( "Failed to initialize AES-CMAC operation. " "mbedtls_md_setup failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); prvCMACCleanUp( pxSession ); xResult = CKR_KEY_HANDLE_INVALID; } } if( xResult == CKR_OK ) { pxSession->xCMACKeyHandle = hKey; } return xResult; } /** * @brief Helper function for initializing a sign operation for AES-CMAC. * @param[in] pxSession Pointer to a valid PKCS #11 session. * @param[in] hKey CMAC secret key handle. * @param[in] pucKeyData CMAC secret key data. * @param[in] ulKeyDataLength CMAC key Size. */ static CK_RV prvSignInitAESCMAC( P11Session_t * pxSession, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pucKeyData, CK_ULONG ulKeyDataLength ) { CK_RV xResult = CKR_OK; xResult = prvInitAESCMAC( pxSession, hKey, pucKeyData, ulKeyDataLength ); return xResult; } /** * @brief Helper function for cleaning up a sign operation for an EC or RSA key. * @param[in] pxSession Pointer to a valid PKCS #11 session. */ static void prvSignInitEC_RSACleanUp( P11Session_t * pxSession ) { mbedtls_pk_free( &pxSession->xSignKey ); pxSession->xSignKeyHandle = CK_INVALID_HANDLE; } /** * @brief Helper function for initializing a sign operation for an EC or RSA key. * @param[in] pxSession Pointer to a valid PKCS #11 session. * @param[in] pMechanism EC/RSA mechanism. * @param[in] hKey EC/RSA private key handle. * @param[in] pucKeyData EC/RSA public key data. * @param[in] ulKeyDataLength EC/RSA public key size. */ static CK_RV prvSignInitEC_RSAKeys( P11Session_t * pxSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pucKeyData, CK_ULONG ulKeyDataLength ) { mbedtls_pk_type_t xKeyType; int32_t lMbedTLSResult = 0; CK_RV xResult = CKR_KEY_HANDLE_INVALID; mbedtls_pk_init( &pxSession->xSignKey ); #if MBEDTLS_VERSION_NUMBER < 0x03000000 lMbedTLSResult = mbedtls_pk_parse_key( &pxSession->xSignKey, pucKeyData, ulKeyDataLength, NULL, 0 ); #else lMbedTLSResult = mbedtls_pk_parse_key( &pxSession->xSignKey, pucKeyData, ulKeyDataLength, NULL, 0, mbedtls_ctr_drbg_random, &xP11Context.xMbedDrbgCtx ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ if( 0 == lMbedTLSResult ) { pxSession->xSignKeyHandle = hKey; xResult = CKR_OK; } else { LogError( ( "Failed to initialize sign operation. " "mbedtls_pk_parse_key failed: mbed TLS " "error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); prvSignInitEC_RSACleanUp( pxSession ); } /* Check that the mechanism and key type are compatible, supported. */ if( xResult == CKR_OK ) { xKeyType = mbedtls_pk_get_type( &pxSession->xSignKey ); if( ( pMechanism->mechanism == CKM_RSA_PKCS ) && ( xKeyType == MBEDTLS_PK_RSA ) ) { /* Mechanisms align with the port. */ } else if( ( pMechanism->mechanism == CKM_ECDSA ) && ( ( xKeyType == MBEDTLS_PK_ECDSA ) || ( xKeyType == MBEDTLS_PK_ECKEY ) ) ) { /* Mechanisms align with the port. */ } else { LogError( ( "Failed to initialize sign operation. " "Signing key type (0x%0lX) does not match " "RSA or EC mechanism.", ( unsigned long int ) xKeyType ) ); xResult = CKR_KEY_TYPE_INCONSISTENT; prvSignInitEC_RSACleanUp( pxSession ); } } return xResult; } /** * @brief Initializes a signature operation. * * \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] hSession Handle of a valid PKCS #11 session. * @param[in] pMechanism 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] hKey The handle of the private key to be used for * signature. Key must be compatible with the * mechanism chosen by pMechanism. * * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_signinit] */ CK_DECLARE_FUNCTION( CK_RV, C_SignInit )( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xIsPrivate = ( CK_BBOOL ) CK_TRUE; CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; CK_BYTE_PTR pxLabel = NULL; CK_ULONG xLabelLength = 0; CK_BYTE_PTR pucKeyData = NULL; CK_ULONG ulKeyDataLength = 0; P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); if( NULL == pMechanism ) { LogError( ( "Failed to initialize sign operation. NULL pointer to " "signing mechanism provided." ) ); xResult = CKR_ARGUMENTS_BAD; } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( ( xResult == CKR_OK ) && ( prvOperationActive( pxSession ) == ( CK_BBOOL ) CK_TRUE ) ) { LogError( ( "Failed to initialize sign operation. Operation already active." ) ); xResult = CKR_OPERATION_ACTIVE; } /* Retrieve key value from storage. */ if( xResult == CKR_OK ) { prvFindObjectInListByHandle( hKey, &xPalHandle, &pxLabel, &xLabelLength ); if( xPalHandle != CK_INVALID_HANDLE ) { xResult = PKCS11_PAL_GetObjectValue( xPalHandle, &pucKeyData, &ulKeyDataLength, &xIsPrivate ); if( xResult != CKR_OK ) { LogError( ( "Failed to initialize sign operation. Unable to " "retrieve value of private key for signing 0x%0lX.", ( unsigned long int ) xResult ) ); xResult = CKR_KEY_HANDLE_INVALID; } } else { LogDebug( ( "Could not find PKCS #11 PAL Handle." ) ); xResult = CKR_KEY_HANDLE_INVALID; } } /* Check that a private key was retrieved. */ if( xResult == CKR_OK ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate != ( CK_BBOOL ) CK_TRUE ) { LogError( ( "Failed to initialize sign operation. Sign operation " "attempted with public key." ) ); xResult = CKR_KEY_TYPE_INCONSISTENT; } } /* Convert the private key from storage format to mbedTLS usable format. */ if( xResult == CKR_OK ) { if( 0 == mbedtls_mutex_lock( &pxSession->xSignMutex ) ) { switch( pMechanism->mechanism ) { case CKM_RSA_PKCS: case CKM_ECDSA: if( ( pxSession->xSignKeyHandle == CK_INVALID_HANDLE ) || ( pxSession->xSignKeyHandle != hKey ) ) { xResult = prvSignInitEC_RSAKeys( pxSession, pMechanism, hKey, pucKeyData, ulKeyDataLength ); } else { /* The correct credentials are already initialized. */ } break; case CKM_SHA256_HMAC: if( ( pxSession->xHMACKeyHandle == CK_INVALID_HANDLE ) || ( pxSession->xHMACKeyHandle != hKey ) ) { xResult = prvSignInitSHA256HMAC( pxSession, hKey, pucKeyData, ulKeyDataLength ); } else { /* The correct credentials are already initialized. */ } break; case CKM_AES_CMAC: if( ( pxSession->xCMACKeyHandle == CK_INVALID_HANDLE ) || ( pxSession->xCMACKeyHandle != hKey ) ) { xResult = prvSignInitAESCMAC( pxSession, hKey, pucKeyData, ulKeyDataLength ); } else { /* The correct credentials are already initialized. */ } break; default: LogError( ( "Failed to initialize sign operation. Received " "an unknown or invalid mechanism." ) ); xResult = CKR_MECHANISM_INVALID; break; } ( void ) mbedtls_mutex_unlock( &pxSession->xSignMutex ); } else { LogError( ( "Failed sign operation. Could not take sign mutex." ) ); xResult = CKR_CANT_LOCK; } } if( xPalHandle != CK_INVALID_HANDLE ) { PKCS11_PAL_GetObjectValueCleanup( pucKeyData, ulKeyDataLength ); } if( xResult == CKR_OK ) { LogDebug( ( "Sign mechanism set to 0x%0lX.", ( unsigned long int ) pMechanism->mechanism ) ); pxSession->xOperationSignMechanism = pMechanism->mechanism; } return xResult; } /* @[declare_pkcs11_mbedtls_c_signinit] */ /** * @brief Signs single-part data. * * \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] hSession Handle of a valid PKCS #11 session. * @param[in] pData 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] pSignature 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. */ /* @[declare_pkcs11_mbedtls_c_sign] */ CK_DECLARE_FUNCTION( CK_RV, C_Sign )( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen ) { P11Session_t * pxSessionObj = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSessionObj ); size_t xSignatureLength = 0; size_t xExpectedInputLength = 0; size_t xSignatureBufferLength = 0; CK_BYTE_PTR pucSignatureBuffer = pSignature; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xSignatureGenerated = ( CK_BBOOL ) CK_FALSE; /* 8 bytes added to hold ASN.1 encoding information. */ /* MISRA Ref 12.1.1 [Operator precedence] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-121 */ /* coverity[misra_c_2012_rule_12_1_violation] */ uint8_t ecSignature[ MBEDTLS_ECDSA_MAX_SIG_LEN( 256 ) ]; int32_t lMbedTLSResult = -1; mbedtls_md_type_t xHashType = MBEDTLS_MD_NONE; if( ( NULL == pulSignatureLen ) || ( NULL == pData ) ) { LogError( ( "Failed sign operation. Received a NULL pointer." ) ); xResult = CKR_ARGUMENTS_BAD; } if( CKR_OK == xResult ) { /* Update the signature length. */ if( pxSessionObj->xOperationSignMechanism == CKM_RSA_PKCS ) { xSignatureLength = pkcs11RSA_2048_SIGNATURE_LENGTH; xSignatureBufferLength = pkcs11RSA_2048_SIGNATURE_LENGTH; xExpectedInputLength = pkcs11RSA_SIGNATURE_INPUT_LENGTH; } else if( pxSessionObj->xOperationSignMechanism == CKM_ECDSA ) { xSignatureLength = pkcs11ECDSA_P256_SIGNATURE_LENGTH; /* MISRA Ref 12.1.1 [Operator precedence] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-121 */ /* coverity[misra_c_2012_rule_12_1_violation] */ xSignatureBufferLength = MBEDTLS_ECDSA_MAX_SIG_LEN( 256 ); pucSignatureBuffer = ecSignature; xExpectedInputLength = pkcs11SHA256_DIGEST_LENGTH; xHashType = MBEDTLS_MD_SHA256; } else if( pxSessionObj->xOperationSignMechanism == CKM_SHA256_HMAC ) { xSignatureLength = pkcs11SHA256_DIGEST_LENGTH; /* At least 32 bytes, can be longer. */ xExpectedInputLength = pkcs11SHA256_DIGEST_LENGTH; xHashType = MBEDTLS_MD_SHA256; } else if( pxSessionObj->xOperationSignMechanism == CKM_AES_CMAC ) { xSignatureLength = pkcs11AES_CMAC_SIGNATURE_LENGTH; xExpectedInputLength = pkcs11AES_CMAC_SIGNATURE_LENGTH; } else { LogError( ( "Failed sign operation. The sign operation was not " "initialized with a call to C_SignInit." ) ); xResult = CKR_OPERATION_NOT_INITIALIZED; } } if( xResult == CKR_OK ) { /* Calling application is trying to determine length needed for signature buffer. */ if( NULL != pSignature ) { /* Check that the signature buffer is long enough. */ if( *pulSignatureLen < xSignatureLength ) { LogError( ( "Failed sign operation. The signature buffer was " "too small. Expected: %lu bytes and received %lu " "bytes.", ( unsigned long int ) xSignatureLength, ( unsigned long int ) *pulSignatureLen ) ); xResult = CKR_BUFFER_TOO_SMALL; } if( CKR_OK == xResult ) { if( 0 == mbedtls_mutex_lock( &pxSessionObj->xSignMutex ) ) { if( pxSessionObj->xOperationSignMechanism == CKM_SHA256_HMAC ) { lMbedTLSResult = mbedtls_md_hmac_update( &pxSessionObj->xHMACSecretContext, pData, ulDataLen ); if( lMbedTLSResult == 0 ) { lMbedTLSResult = mbedtls_md_hmac_finish( &pxSessionObj->xHMACSecretContext, pSignature ); } prvHMACCleanUp( pxSessionObj ); } else if( pxSessionObj->xOperationSignMechanism == CKM_AES_CMAC ) { lMbedTLSResult = mbedtls_cipher_cmac_update( &pxSessionObj->xCMACSecretContext, pData, ulDataLen ); if( lMbedTLSResult == 0 ) { lMbedTLSResult = mbedtls_cipher_cmac_finish( &pxSessionObj->xCMACSecretContext, pSignature ); } prvCMACCleanUp( pxSessionObj ); } else { /* Check that input data to be signed is the expected length. */ if( xExpectedInputLength > ulDataLen ) { LogError( ( "Failed sign operation. The data buffer was " "too small. Expected at least %lu bytes and received " "%lu bytes.", ( unsigned long int ) xExpectedInputLength, ( unsigned long int ) ulDataLen ) ); xResult = CKR_DATA_LEN_RANGE; } else { LogDebug( ( "Ready to sign: xSignatureLength=%ld *pulSignatureLen=%ld", xSignatureLength, *pulSignatureLen ) ); /* Per mbed TLS documentation, if using RSA, md_alg should * be MBEDTLS_MD_NONE. If ECDSA, md_alg should never be * MBEDTLS_MD_NONE. SHA-256 will be used for ECDSA for * consistency with the rest of the port. */ #if MBEDTLS_VERSION_NUMBER < 0x03000000 lMbedTLSResult = mbedtls_pk_sign( &pxSessionObj->xSignKey, xHashType, pData, ulDataLen, pucSignatureBuffer, &xSignatureBufferLength, mbedtls_ctr_drbg_random, &xP11Context.xMbedDrbgCtx ); #else lMbedTLSResult = mbedtls_pk_sign( &pxSessionObj->xSignKey, xHashType, pData, ulDataLen, pucSignatureBuffer, xSignatureBufferLength, &xSignatureBufferLength, mbedtls_ctr_drbg_random, &xP11Context.xMbedDrbgCtx ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ } prvSignInitEC_RSACleanUp( pxSessionObj ); } if( ( xResult == CKR_OK ) && ( lMbedTLSResult != 0 ) ) { LogError( ( "Failed sign operation. mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } ( void ) mbedtls_mutex_unlock( &pxSessionObj->xSignMutex ); /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ xSignatureGenerated = ( CK_BBOOL ) CK_TRUE; } else { LogError( ( "Failed sign operation. Could not take xSignMutex." ) ); xResult = CKR_CANT_LOCK; } } } else { *pulSignatureLen = xSignatureLength; } } if( xResult == CKR_OK ) { /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( ( pxSessionObj->xOperationSignMechanism == CKM_ECDSA ) && ( xSignatureGenerated == ( CK_BBOOL ) CK_TRUE ) ) { /* If this an EC signature, reformat from ASN.1 encoded to 64-byte R & S components */ lMbedTLSResult = PKI_mbedTLSSignatureToPkcs11Signature( pSignature, ecSignature ); if( lMbedTLSResult != 0 ) { LogError( ( "Failed sign operation. Failed to convert from " "ASN.1 encoding to 64 byte R & S components." ) ); 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 ) && ( xResult != CKR_SESSION_HANDLE_INVALID ) ) { LogDebug( ( "Ended Sign operation." ) ); pxSessionObj->xOperationSignMechanism = pkcs11NO_OPERATION; } return xResult; } /* @[declare_pkcs11_mbedtls_c_sign] */ /** * @brief Helper function for initializing a verify operation for SHA256-HMAC. * @param[in] pxSession Pointer to a valid PKCS #11 session. * @param[in] hKey HMAC secret key handle. * @param[in] pucKeyData HMAC secret key data. * @param[in] ulKeyDataLength HMAC key Size. */ static CK_RV prvVerifyInitSHA256HMAC( P11Session_t * pxSession, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pucKeyData, CK_ULONG ulKeyDataLength ) { CK_RV xResult = CKR_OK; xResult = prvInitSHA256HMAC( pxSession, hKey, pucKeyData, ulKeyDataLength ); return xResult; } /** * @brief Helper function for initializing a verify operation for AES-CMAC. * @param[in] pxSession Pointer to a valid PKCS #11 session. * @param[in] hKey CMAC secret key handle. * @param[in] pucKeyData CMAC secret key data. * @param[in] ulKeyDataLength CMAC key Size. */ static CK_RV prvVerifyInitAESCMAC( P11Session_t * pxSession, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pucKeyData, CK_ULONG ulKeyDataLength ) { CK_RV xResult = CKR_OK; xResult = prvInitAESCMAC( pxSession, hKey, pucKeyData, ulKeyDataLength ); return xResult; } /** * @brief Helper function for cleaning up a verify operation for an EC or RSA key. * @param[in] pxSession Pointer to a valid PKCS #11 session. */ static void prvVerifyInitEC_RSACleanUp( P11Session_t * pxSession ) { mbedtls_pk_free( &pxSession->xVerifyKey ); pxSession->xVerifyKeyHandle = CK_INVALID_HANDLE; } /** * @brief Helper function for initializing a verify operation for an EC or RSA key. * @param[in] pxSession Pointer to a valid PKCS #11 session. * @param[in] pMechanism EC/RSA mechanism. * @param[in] hKey EC/RSA public key handle. * @param[in] pucKeyData EC/RSA public key data. * @param[in] ulKeyDataLength EC/RSA public key size. */ static CK_RV prvVerifyInitEC_RSAKeys( P11Session_t * pxSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pucKeyData, CK_ULONG ulKeyDataLength ) { mbedtls_pk_type_t xKeyType; int32_t lMbedTLSResult = 1; CK_RV xResult = CKR_KEY_HANDLE_INVALID; mbedtls_pk_init( &pxSession->xVerifyKey ); lMbedTLSResult = mbedtls_pk_parse_public_key( &pxSession->xVerifyKey, pucKeyData, ulKeyDataLength ); if( 0 == lMbedTLSResult ) { pxSession->xVerifyKeyHandle = hKey; xResult = CKR_OK; } /* If we fail to parse the public key, try again as a private key. */ if( xResult != CKR_OK ) { #if MBEDTLS_VERSION_NUMBER < 0x03000000 lMbedTLSResult = mbedtls_pk_parse_key( &pxSession->xVerifyKey, pucKeyData, ulKeyDataLength, NULL, 0 ); #else lMbedTLSResult = mbedtls_pk_parse_key( &pxSession->xVerifyKey, pucKeyData, ulKeyDataLength, NULL, 0, mbedtls_ctr_drbg_random, &xP11Context.xMbedDrbgCtx ); #endif /* MBEDTLS_VERSION_NUMBER < 0x03000000 */ if( 0 == lMbedTLSResult ) { pxSession->xVerifyKeyHandle = hKey; xResult = CKR_OK; } else { LogError( ( "Verification operation failed. " "mbedtls_pk_parse_key failed: mbed TLS " "error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); prvVerifyInitEC_RSACleanUp( pxSession ); } } /* Check that the mechanism and key type are compatible and supported. */ if( xResult == CKR_OK ) { xKeyType = mbedtls_pk_get_type( &pxSession->xVerifyKey ); if( ( pMechanism->mechanism == CKM_RSA_X_509 ) && ( xKeyType == MBEDTLS_PK_RSA ) ) { /* Mechanisms align with the port. */ } else if( ( pMechanism->mechanism == CKM_ECDSA ) && ( ( xKeyType == MBEDTLS_PK_ECDSA ) || ( xKeyType == MBEDTLS_PK_ECKEY ) ) ) { /* Mechanisms align with the port. */ } else { LogError( ( "Failed to initialize verify operation. " "Verification key type (0x%0lX) does not match " "RSA or EC mechanism.", ( unsigned long int ) xKeyType ) ); xResult = CKR_KEY_TYPE_INCONSISTENT; prvVerifyInitEC_RSACleanUp( pxSession ); } } return xResult; } /** * @brief Initializes a verification operation. * * \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] hSession Handle of a valid PKCS #11 session. * @param[in] pMechanism 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] hKey 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. */ /* @[declare_pkcs11_mbedtls_c_verifyinit] */ CK_DECLARE_FUNCTION( CK_RV, C_VerifyInit )( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey ) { P11Session_t * pxSession; CK_RV xResult = CKR_OK; CK_OBJECT_HANDLE xPalHandle = CK_INVALID_HANDLE; CK_BYTE_PTR pxLabel = NULL; CK_ULONG xLabelLength = 0; CK_BYTE_PTR pucKeyData = NULL; CK_ULONG ulKeyDataLength = 0; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xIsPrivate = ( CK_BBOOL ) CK_TRUE; pxSession = prvSessionPointerFromHandle( hSession ); xResult = prvCheckValidSessionAndModule( pxSession ); if( NULL == pMechanism ) { LogError( ( "Failed to initialize verify operation. Null verification " "mechanism provided." ) ); xResult = CKR_ARGUMENTS_BAD; } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( ( xResult == CKR_OK ) && ( prvOperationActive( pxSession ) == ( CK_BBOOL ) CK_TRUE ) ) { LogError( ( "Failed to initialize verify operation. An operation was " "already active." ) ); xResult = CKR_OPERATION_ACTIVE; } if( xResult == CKR_OK ) { prvFindObjectInListByHandle( hKey, &xPalHandle, &pxLabel, &xLabelLength ); if( xPalHandle != CK_INVALID_HANDLE ) { xResult = PKCS11_PAL_GetObjectValue( xPalHandle, &pucKeyData, &ulKeyDataLength, &xIsPrivate ); if( xResult != CKR_OK ) { LogError( ( "Failed to initialize verify operation. Unable to " "retrieve value of public key for verification 0x%0lX.", ( unsigned long int ) xResult ) ); xResult = CKR_KEY_HANDLE_INVALID; } } else { LogError( ( "Failed to initialize verify operation. Couldn't find " "a valid PKCS #11 PAL Handle." ) ); xResult = CKR_KEY_HANDLE_INVALID; } } /* Retrieve key value from storage. */ if( xResult == CKR_OK ) { /* Mutex is used to protect the verification keys and contexts. */ if( 0 == mbedtls_mutex_lock( &pxSession->xVerifyMutex ) ) { switch( pMechanism->mechanism ) { case CKM_RSA_X_509: case CKM_ECDSA: /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xIsPrivate != ( CK_BBOOL ) CK_FALSE ) { LogError( ( "Failed to initialize verify operation. Verify " "operation attempted with private key." ) ); xResult = CKR_KEY_TYPE_INCONSISTENT; } else if( ( pxSession->xVerifyKeyHandle == CK_INVALID_HANDLE ) || ( pxSession->xVerifyKeyHandle != hKey ) ) { xResult = prvVerifyInitEC_RSAKeys( pxSession, pMechanism, hKey, pucKeyData, ulKeyDataLength ); } else { /* The correct credentials are already Initialized. */ } break; case CKM_SHA256_HMAC: if( ( pxSession->xHMACKeyHandle == CK_INVALID_HANDLE ) || ( pxSession->xHMACKeyHandle != hKey ) ) { xResult = prvVerifyInitSHA256HMAC( pxSession, hKey, pucKeyData, ulKeyDataLength ); } break; case CKM_AES_CMAC: if( ( pxSession->xCMACKeyHandle == CK_INVALID_HANDLE ) || ( pxSession->xCMACKeyHandle != hKey ) ) { xResult = prvVerifyInitAESCMAC( pxSession, hKey, pucKeyData, ulKeyDataLength ); } break; default: LogError( ( "Failed to initialize verify operation. Received " "an unknown or invalid mechanism." ) ); xResult = CKR_MECHANISM_INVALID; break; } ( void ) mbedtls_mutex_unlock( &pxSession->xVerifyMutex ); } else { LogError( ( "Verify operation failed. Could not take verify mutex." ) ); xResult = CKR_CANT_LOCK; } } if( xPalHandle != CK_INVALID_HANDLE ) { PKCS11_PAL_GetObjectValueCleanup( pucKeyData, ulKeyDataLength ); } if( xResult == CKR_OK ) { LogDebug( ( "Verify mechanism set to 0x%0lX.", ( unsigned long int ) pMechanism->mechanism ) ); pxSession->xOperationVerifyMechanism = pMechanism->mechanism; } return xResult; } /* @[declare_pkcs11_mbedtls_c_verifyinit] */ /** * @brief Verifies a signature on single-part data. * * \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] hSession Handle of a valid PKCS #11 session. * @param[in] pData 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] pSignature The signature to be verified. * @param[in] ulSignatureLen Length of pucSignature in bytes. * * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_verify] */ CK_DECLARE_FUNCTION( CK_RV, C_Verify )( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen ) { P11Session_t * pxSessionObj; int32_t lMbedTLSResult; CK_RV xResult = CKR_OK; /* If using SHA512 a larger buffer is needed for the call to mbedtls_md_hmac_finish */ #if defined( MBEDTLS_SHA512_C ) CK_BYTE pxHMACBuffer[ pkcs11SHA256_DIGEST_LENGTH * 2 ] = { 0 }; #else CK_BYTE pxHMACBuffer[ pkcs11SHA256_DIGEST_LENGTH ] = { 0 }; #endif CK_BYTE pxCMACBuffer[ MBEDTLS_AES_BLOCK_SIZE ] = { 0 }; pxSessionObj = prvSessionPointerFromHandle( hSession ); xResult = prvCheckValidSessionAndModule( pxSessionObj ); /* Check parameters. */ if( ( NULL == pData ) || ( NULL == pSignature ) ) { LogError( ( "Failed verify operation. Received a NULL pointer." ) ); 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->xOperationVerifyMechanism == CKM_RSA_X_509 ) { if( ulDataLen != pkcs11RSA_2048_SIGNATURE_LENGTH ) { LogError( ( "Failed verify operation. Data Length was too " "short for pkcs11RSA_2048_SIGNATURE_LENGTH." ) ); xResult = CKR_DATA_LEN_RANGE; } if( ulSignatureLen != pkcs11RSA_2048_SIGNATURE_LENGTH ) { LogError( ( "Failed verify operation. Signature Length was too " "short for pkcs11RSA_2048_SIGNATURE_LENGTH." ) ); xResult = CKR_SIGNATURE_LEN_RANGE; } } else if( pxSessionObj->xOperationVerifyMechanism == CKM_ECDSA ) { if( ulDataLen != pkcs11SHA256_DIGEST_LENGTH ) { LogError( ( "Failed verify operation. Data Length was too " "short for pkcs11SHA256_DIGEST_LENGTH." ) ); xResult = CKR_DATA_LEN_RANGE; } if( ulSignatureLen != pkcs11ECDSA_P256_SIGNATURE_LENGTH ) { LogError( ( "Failed verify operation. Data Length was too " "short for pkcs11ECDSA_P256_SIGNATURE_LENGTH." ) ); xResult = CKR_SIGNATURE_LEN_RANGE; } } else if( pxSessionObj->xOperationVerifyMechanism == CKM_SHA256_HMAC ) { if( ulSignatureLen != pkcs11SHA256_DIGEST_LENGTH ) { LogError( ( "Failed verify operation. Data Length was too " "short for pkcs11SHA256_DIGEST_LENGTH." ) ); xResult = CKR_SIGNATURE_LEN_RANGE; } } else if( pxSessionObj->xOperationVerifyMechanism == CKM_AES_CMAC ) { if( ulSignatureLen != PKCS11_AES_CMAC_MIN_SIZE ) { LogError( ( "Failed verify operation. Data Length was too " "short for PKCS11_AES_CMAC_MIN_SIZE." ) ); xResult = CKR_SIGNATURE_LEN_RANGE; } } else { LogError( ( "Failed verify operation. A C_Verify operation must be " "initialized by a preceding call to C_VerifyInit. " "This must happen before every call to C_Verify." ) ); xResult = CKR_OPERATION_NOT_INITIALIZED; } } /* Verification step. */ if( xResult == CKR_OK ) { if( 0 == mbedtls_mutex_lock( &pxSessionObj->xVerifyMutex ) ) { /* Perform an RSA verification. */ if( pxSessionObj->xOperationVerifyMechanism == CKM_RSA_X_509 ) { /* Verify the signature. If a public key is present, use it. */ if( NULL != pxSessionObj->xVerifyKey.pk_ctx ) { lMbedTLSResult = mbedtls_pk_verify( &pxSessionObj->xVerifyKey, MBEDTLS_MD_SHA256, pData, ulDataLen, pSignature, ulSignatureLen ); if( 0 != lMbedTLSResult ) { LogError( ( "Failed verify operation. mbedtls_pk_verify " "failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_SIGNATURE_INVALID; } } else { LogError( ( "Failed verify operation. Verify Key was not " "present in session context." ) ); xResult = CKR_SIGNATURE_INVALID; } prvVerifyInitEC_RSACleanUp( pxSessionObj ); } /* Perform an ECDSA verification. */ else if( pxSessionObj->xOperationVerifyMechanism == CKM_ECDSA ) { /* 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, &pSignature[ 0 ], 32 ); if( lMbedTLSResult != 0 ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. Failed to parse R in EC " "signature: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } else { lMbedTLSResult = mbedtls_mpi_read_binary( &xS, &pSignature[ 32 ], 32 ); if( lMbedTLSResult != 0 ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. Failed to parse S in " "EC signature: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } } if( xResult == CKR_OK ) { /* 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, pData, ulDataLen, &pxEcdsaContext->Q, &xR, &xS ); } if( lMbedTLSResult != 0 ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. " "mbedtls_ecdsa_verify failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } } mbedtls_mpi_free( &xR ); mbedtls_mpi_free( &xS ); prvVerifyInitEC_RSACleanUp( pxSessionObj ); } else if( pxSessionObj->xOperationVerifyMechanism == CKM_SHA256_HMAC ) { lMbedTLSResult = mbedtls_md_hmac_update( &pxSessionObj->xHMACSecretContext, pData, ulDataLen ); if( lMbedTLSResult != 0 ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. " "mbedtls_md_hmac_update failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } else { lMbedTLSResult = mbedtls_md_hmac_finish( &pxSessionObj->xHMACSecretContext, pxHMACBuffer ); if( lMbedTLSResult != 0 ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. " "mbedtls_md_hmac_finish failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } else { if( 0 != memcmp( pxHMACBuffer, pSignature, pkcs11SHA256_DIGEST_LENGTH ) ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. Signature was invalid." ) ); } } } prvHMACCleanUp( pxSessionObj ); } else if( pxSessionObj->xOperationVerifyMechanism == CKM_AES_CMAC ) { lMbedTLSResult = mbedtls_cipher_cmac_update( &pxSessionObj->xCMACSecretContext, pData, ulDataLen ); if( lMbedTLSResult != 0 ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. " "mbedtls_md_hmac_update failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } else { lMbedTLSResult = mbedtls_cipher_cmac_finish( &pxSessionObj->xCMACSecretContext, pxCMACBuffer ); if( lMbedTLSResult != 0 ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. " "mbedtls_md_hmac_finish failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); } else { if( 0 != memcmp( pxCMACBuffer, pSignature, MBEDTLS_AES_BLOCK_SIZE ) ) { xResult = CKR_SIGNATURE_INVALID; LogError( ( "Failed verify operation. Signature was invalid." ) ); } } } prvCMACCleanUp( pxSessionObj ); } else { LogError( ( "Failed verify operation. Received an unexpected mechanism." ) ); } ( void ) mbedtls_mutex_unlock( &pxSessionObj->xVerifyMutex ); } else { LogError( ( "Failed to initialize verify operation. Could not " "take xVerifyMutex." ) ); xResult = CKR_CANT_LOCK; } } if( xResult != CKR_SESSION_HANDLE_INVALID ) { LogDebug( ( "Reset Verify mechanism to pkcs11NO_OPERATION." ) ); pxSessionObj->xOperationVerifyMechanism = pkcs11NO_OPERATION; } /* Return the signature verification result. */ return xResult; } /* @[declare_pkcs11_mbedtls_c_verify] */ /** * @brief Checks that the private key template provided for C_GenerateKeyPair * contains all necessary attributes, and does not contain any invalid * attributes. * * @param[out] ppxLabel Pointer to PKCS #11 label. * @param[in] pxAttribute PKCS #11 attribute to search. * @param[in] pulAttributeMap Flag to track whether all required attribute * are in the key generation template. * @return CKR_OK if successful. */ static CK_RV prvCheckGenerateKeyPairPrivateTemplate( CK_ATTRIBUTE ** ppxLabel, CK_ATTRIBUTE * pxAttribute, uint32_t * pulAttributeMap ) { CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_FALSE; CK_ULONG xTemp = 0; switch( pxAttribute->type ) { case ( CKA_LABEL ): *ppxLabel = pxAttribute; *pulAttributeMap |= LABEL_IN_TEMPLATE; break; case ( CKA_KEY_TYPE ): if( pxAttribute->ulValueLen == sizeof( CK_ULONG ) ) { ( void ) memcpy( &xTemp, pxAttribute->pValue, sizeof( CK_ULONG ) ); } if( xTemp != CKK_EC ) { LogError( ( "Failed parsing private key template. Only EC key " "pair generation is supported." ) ); xResult = CKR_TEMPLATE_INCONSISTENT; } break; case ( CKA_SIGN ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { LogError( ( "Failed parsing private key template. Generating " "private keys that cannot sign is not supported." ) ); xResult = CKR_TEMPLATE_INCONSISTENT; } LogDebug( ( "CKA_SIGN was in template." ) ); *pulAttributeMap |= SIGN_IN_TEMPLATE; break; case ( CKA_PRIVATE ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { LogError( ( "Failed parsing private key template. Private must " "be set to true in order to generate a private key." ) ); xResult = CKR_TEMPLATE_INCONSISTENT; } LogDebug( ( "CKA_PRIVATE was in template." ) ); *pulAttributeMap |= PRIVATE_IN_TEMPLATE; break; case ( CKA_TOKEN ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { LogError( ( "Failed parsing private key template. Generating " "private keys that are false for attribute CKA_TOKEN " "is not supported." ) ); xResult = CKR_TEMPLATE_INCONSISTENT; } break; default: LogError( ( "Failed parsing private key template. Found an unknown " "attribute type." ) ); xResult = CKR_ATTRIBUTE_TYPE_INVALID; break; } return xResult; } /** * @brief Checks that the public key template provided for C_GenerateKeyPair * contains all necessary attributes, and does not contain any invalid * attributes. * * @param[out] ppxLabel Pointer to PKCS #11 label. * @param[in] pxAttribute PKCS #11 attribute to search. * @param[in] pulAttributeMap Flag to track whether all required attribute * are in the key generation template. * * @return CKR_OK if successful. */ static CK_RV prvCheckGenerateKeyPairPublicTemplate( CK_ATTRIBUTE ** ppxLabel, CK_ATTRIBUTE * pxAttribute, uint32_t * pulAttributeMap ) { CK_RV xResult = CKR_OK; /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ CK_BBOOL xBool = ( CK_BBOOL ) CK_TRUE; CK_KEY_TYPE xKeyType = 0xFFFFFFFFUL; const CK_BYTE pxEcParams[] = pkcs11DER_ENCODED_OID_P256; const CK_BYTE * pxEcAttVal = NULL; switch( pxAttribute->type ) { case ( CKA_LABEL ): *ppxLabel = pxAttribute; *pulAttributeMap |= LABEL_IN_TEMPLATE; break; case ( CKA_KEY_TYPE ): if( pxAttribute->ulValueLen == sizeof( CK_KEY_TYPE ) ) { ( void ) memcpy( &xKeyType, ( CK_KEY_TYPE * ) pxAttribute->pValue, sizeof( CK_KEY_TYPE ) ); } if( xKeyType != CKK_EC ) { LogError( ( "Failed parsing public key template. Only EC key " "pair generation is supported." ) ); xResult = CKR_TEMPLATE_INCONSISTENT; } break; case ( CKA_EC_PARAMS ): pxEcAttVal = ( CK_BYTE * ) pxAttribute->pValue; if( pxAttribute->ulValueLen == sizeof( pxEcParams ) ) { if( memcmp( pxEcParams, pxEcAttVal, sizeof( pxEcParams ) ) != 0 ) { LogError( ( "Failed parsing public key template. Only P-256 key " "generation is supported." ) ); xResult = CKR_TEMPLATE_INCONSISTENT; } } *pulAttributeMap |= EC_PARAMS_IN_TEMPLATE; break; case ( CKA_VERIFY ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { LogError( ( "Failed parsing public key template. Generating public " "keys that have a value of CK_FALSE for attribute " "CKA_VERIFY is not supported." ) ); xResult = CKR_TEMPLATE_INCONSISTENT; } *pulAttributeMap |= VERIFY_IN_TEMPLATE; break; case ( CKA_TOKEN ): if( pxAttribute->ulValueLen == sizeof( CK_BBOOL ) ) { ( void ) memcpy( &xBool, pxAttribute->pValue, sizeof( CK_BBOOL ) ); } /* MISRA Ref 10.5.1 [Essential type casting] */ /* More details at: https://github.com/FreeRTOS/corePKCS11/blob/main/MISRA.md#rule-105 */ /* coverity[misra_c_2012_rule_10_5_violation] */ if( xBool != ( CK_BBOOL ) CK_TRUE ) { xResult = CKR_TEMPLATE_INCONSISTENT; } break; default: xResult = CKR_TEMPLATE_INCONSISTENT; break; } return xResult; } /** * @brief Generates a public-key/private-key pair. * * This port only supports generating elliptic curve P-256 * key pairs. * * @param[in] hSession Handle of a valid PKCS #11 session. * @param[in] pMechanism Pointer to a mechanism. At this time, * CKM_EC_KEY_PAIR_GEN is the only supported mechanism. * @param[in] pPublicKeyTemplate 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 pPublicKeyTemplate. * @param[in] pPrivateKeyTemplate 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 pPrivateKeyTemplate. * @param[out] phPublicKey Pointer to the handle of the public key to be created. * @param[out] phPrivateKey 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. */ /* @[declare_pkcs11_mbedtls_c_generatekeypair] */ CK_DECLARE_FUNCTION( CK_RV, C_GenerateKeyPair )( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey ) { uint8_t * pucDerFile = mbedtls_calloc( 1, pkcs11KEY_GEN_MAX_DER_SIZE ); int32_t lMbedTLSResult = 0; uint32_t ulIndex = 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; uint32_t xPublicRequiredAttributeMap = ( LABEL_IN_TEMPLATE | EC_PARAMS_IN_TEMPLATE | VERIFY_IN_TEMPLATE ); uint32_t xPrivateRequiredAttributeMap = ( LABEL_IN_TEMPLATE | PRIVATE_IN_TEMPLATE | SIGN_IN_TEMPLATE ); uint32_t xAttributeMap = 0; CK_RV xAddObjectListResult = CKR_OK; const P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); CK_RV xResult = prvCheckValidSessionAndModule( pxSession ); #ifdef pkcs11configSUPPRESS_ECDSA_MECHANISM if( xResult == CKR_OK ) { LogDebug( ( "ECDSA Mechanism is suppressed on this port." ) ); xResult = CKR_MECHANISM_INVALID; } #endif if( xResult == CKR_OK ) { if( ( pPublicKeyTemplate == NULL ) || ( pPrivateKeyTemplate == NULL ) || ( phPublicKey == NULL ) || ( phPrivateKey == NULL ) || ( pMechanism == NULL ) ) { LogError( ( "Failed generating a key pair. One of the arguments " "was NULL." ) ); xResult = CKR_ARGUMENTS_BAD; } } if( xResult == CKR_OK ) { if( pucDerFile == NULL ) { LogError( ( "Failed generating a key pair. Could not allocated a " "buffer of size %u bytes.", ( unsigned int ) pkcs11KEY_GEN_MAX_DER_SIZE ) ); xResult = CKR_HOST_MEMORY; } } if( xResult == CKR_OK ) { if( CKM_EC_KEY_PAIR_GEN != pMechanism->mechanism ) { LogError( ( "Failed generating a key pair. CKM_EC_KEY_PAIR_GEN is " "the only valid key generation mechanism currently." ) ); xResult = CKR_MECHANISM_INVALID; } } if( xResult == CKR_OK ) { for( ulIndex = 0; ulIndex < ulPrivateKeyAttributeCount; ++ulIndex ) { xResult = prvCheckGenerateKeyPairPrivateTemplate( &pxPrivateLabel, &pPrivateKeyTemplate[ ulIndex ], &xAttributeMap ); if( xResult != CKR_OK ) { break; } } if( ( xResult == CKR_OK ) && ( ( xAttributeMap & xPrivateRequiredAttributeMap ) != xPrivateRequiredAttributeMap ) ) { LogError( ( "Failed generating a key pair. Attributes were missing " "in the private key template." ) ); xResult = CKR_TEMPLATE_INCOMPLETE; } } if( xResult == CKR_OK ) { xAttributeMap = 0; for( ulIndex = 0; ulIndex < ulPublicKeyAttributeCount; ++ulIndex ) { xResult = prvCheckGenerateKeyPairPublicTemplate( &pxPublicLabel, &pPublicKeyTemplate[ ulIndex ], &xAttributeMap ); if( xResult != CKR_OK ) { break; } } if( ( xResult == CKR_OK ) && ( ( xAttributeMap & xPublicRequiredAttributeMap ) != xPublicRequiredAttributeMap ) ) { LogError( ( "Failed generating a key pair. Attributes were missing " "in the public key template." ) ); xResult = CKR_TEMPLATE_INCOMPLETE; } } if( xResult == CKR_OK ) { mbedtls_pk_init( &xCtx ); lMbedTLSResult = mbedtls_pk_setup( &xCtx, mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ); if( lMbedTLSResult != 0 ) { LogError( ( "Failed generating a key pair. mbedtls_pk_setup failed: " "mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } else { LogDebug( ( "mbedtls_pk_setup was successful." ) ); } } if( xResult == CKR_OK ) { lMbedTLSResult = mbedtls_ecp_gen_key( MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec( xCtx ), mbedtls_ctr_drbg_random, &xP11Context.xMbedDrbgCtx ); if( 0 != lMbedTLSResult ) { LogError( ( "Failed generating a key pair. mbedtls_ecp_gen_key " "failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } } if( xResult == CKR_OK ) { lMbedTLSResult = mbedtls_pk_write_pubkey_der( &xCtx, pucDerFile, pkcs11KEY_GEN_MAX_DER_SIZE ); if( ( lMbedTLSResult > 0 ) && ( lMbedTLSResult <= pkcs11KEY_GEN_MAX_DER_SIZE ) ) { xPalPublic = PKCS11_PAL_SaveObject( pxPublicLabel, pucDerFile + pkcs11KEY_GEN_MAX_DER_SIZE - lMbedTLSResult, ( uint32_t ) lMbedTLSResult ); LogDebug( ( "PKCS11_PAL_SaveObject returned a %lu PAL handle value " "for the public key.", ( unsigned long int ) xPalPublic ) ); } else { LogError( ( "Failed generating a key pair. " "mbedtls_pk_write_pubkey_der failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_GENERAL_ERROR; } } if( xResult == CKR_OK ) { lMbedTLSResult = mbedtls_pk_write_key_der( &xCtx, pucDerFile, pkcs11KEY_GEN_MAX_DER_SIZE ); if( ( lMbedTLSResult > 0 ) && ( lMbedTLSResult <= pkcs11KEY_GEN_MAX_DER_SIZE ) ) { xPalPrivate = PKCS11_PAL_SaveObject( pxPrivateLabel, pucDerFile + pkcs11KEY_GEN_MAX_DER_SIZE - lMbedTLSResult, ( uint32_t ) lMbedTLSResult ); LogDebug( ( "PKCS11_PAL_SaveObject returned a %lu PAL handle value " "for the private key.", ( unsigned long int ) xPalPrivate ) ); } else { LogError( ( "Failed generating a key pair. mbedtls_pk_write_key_der " "failed: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_GENERAL_ERROR; } } if( ( xPalPublic != CK_INVALID_HANDLE ) && ( xPalPrivate != CK_INVALID_HANDLE ) ) { xAddObjectListResult = prvAddObjectToList( xPalPrivate, phPrivateKey, pxPrivateLabel->pValue, pxPrivateLabel->ulValueLen ); if( xAddObjectListResult == CKR_OK ) { xAddObjectListResult = prvAddObjectToList( xPalPublic, phPublicKey, pxPublicLabel->pValue, pxPublicLabel->ulValueLen ); } if( xAddObjectListResult != CKR_OK ) { LogError( ( "Could not add private key to object list failed with (0x%0lX). Cleaning up PAL objects.", xResult ) ); xResult = PKCS11_PAL_DestroyObject( xPalPrivate ); if( xResult != CKR_OK ) { LogError( ( "Could not clean up private key. PKCS11_PAL_DestroyObject failed with (0x%0lX).", xResult ) ); } xResult = prvDeleteObjectFromList( xPalPrivate ); if( xResult != CKR_OK ) { LogError( ( "Could not remove private key object from internal list. Failed with (0x%0lX).", xResult ) ); } xResult = PKCS11_PAL_DestroyObject( xPalPublic ); if( xResult != CKR_OK ) { LogError( ( "Could not clean up public key. PKCS11_PAL_DestroyObject failed with (0x%0lX).", xResult ) ); } xResult = prvDeleteObjectFromList( xPalPublic ); if( xResult != CKR_OK ) { LogError( ( "Could not remove private key object from internal list. Failed with (0x%0lX).", xResult ) ); } if( xResult == CKR_OK ) { xResult = xAddObjectListResult; } } } /* Clean up. */ mbedtls_free( pucDerFile ); mbedtls_pk_free( &xCtx ); return xResult; } /* @[declare_pkcs11_mbedtls_c_generatekeypair] */ /** * @brief Generates random data. * * @param[in] hSession Handle of a valid PKCS #11 session. * @param[out] RandomData Pointer to location that random data will be placed. * It is the responsibility of the application to allocate * this memory. * @param[in] ulRandomLen Length of data (in bytes) to be generated. * * @return CKR_OK if successful. */ /* @[declare_pkcs11_mbedtls_c_generate_random] */ CK_DECLARE_FUNCTION( CK_RV, C_GenerateRandom )( CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData, CK_ULONG ulRandomLen ) { CK_RV xResult = CKR_OK; int32_t lMbedTLSResult = 0; const P11Session_t * pxSession = prvSessionPointerFromHandle( hSession ); xResult = prvCheckValidSessionAndModule( pxSession ); if( ( NULL == RandomData ) || ( ulRandomLen == 0UL ) ) { LogError( ( "Failed to generate random bytes. The buffer to store " "random numbers in was NULL or the length of the buffer was 0." ) ); xResult = CKR_ARGUMENTS_BAD; } if( xResult == CKR_OK ) { lMbedTLSResult = mbedtls_ctr_drbg_random( &xP11Context.xMbedDrbgCtx, RandomData, ulRandomLen ); if( lMbedTLSResult != 0 ) { LogError( ( "Failed to generate random bytes. mbed TLS DRBG failed " "to generate a random number: mbed TLS error = %s : %s.", mbedtlsHighLevelCodeOrDefault( lMbedTLSResult ), mbedtlsLowLevelCodeOrDefault( lMbedTLSResult ) ) ); xResult = CKR_FUNCTION_FAILED; } else { LogDebug( ( "Successfully generated %lu random bytes.", ( unsigned long int ) ulRandomLen ) ); } } return xResult; } /* @[declare_pkcs11_mbedtls_c_generate_random] */