text: /*
   * FreeRTOS PKCS #11 PAL for STM32L4 Discovery kit IoT node V1.0.3
   * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy of
   * this software and associated documentation files (the "Software"), to deal in
   * the Software without restriction, including without limitation the rights to
   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
   * the Software, and to permit persons to whom the Software is furnished to do so,
   * subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in all
   * copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
   * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
   * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   *
   * http://aws.amazon.com/freertos
   * http://www.FreeRTOS.org
   */
  
  
  /**
   * @file iot_pkcs11_pal.c
   * @brief FreeRTOS device specific helper functions for
   * PKCS#11 implementation based on mbedTLS.  This
   * file deviates from the FreeRTOS style standard for some function names and
   * data types in order to maintain compliance with the PKCS#11 standard.
   */
  
  /* FreeRTOS includes. */
  #include "FreeRTOS.h"
  #include "FreeRTOSIPConfig.h"
  #include "task.h"
  #include "iot_pkcs11.h"
  #include "iot_pkcs11_config.h"
  
  /* C runtime includes. */
  #include <stdio.h>
  #include <string.h>
  
  /* flash driver includes. */
  #include "flash.h"
  
  /* WiFi includes. */
  #ifdef USE_OFFLOAD_SSL
      #include "iot_wifi.h"
  /* mbedTLS includes. */
      #include "mbedtls/pk.h"
      #include "mbedtls/base64.h"
      #include "mbedtls/platform.h"
  
  /* The maximum lengths (in bytes) that the Inventek
   * module has for credential storage. */
      #define pkcs11ROOT_CA_MAX_LENGTH            1792
      #define pkcs11CLIENT_CERT_MAX_LENGTH        1408
      #define pkcs11CLIENT_PRIV_KEY_MAX_LENGTH    1792
  #endif /* ifdef USE_OFFLOAD_SSL */
  
  #define pkcs11OBJECT_MAX_SIZE                   1800
  #define pkcs11OBJECT_PRESENT_MAGIC              ( 0xABCD0000uL )
  #define pkcs11OBJECT_LENGTH_MASK                ( 0x0000FFFFuL )
  #define pkcs11OBJECT_PRESENT_MASK               ( 0xFFFF0000uL )
  
  enum eObjectHandles
  {
      eInvalidHandle = 0, /* From PKCS #11 spec: 0 is never a valid object handle.*/
      eAwsDevicePrivateKey = 1,
      eAwsDevicePublicKey,
      eAwsDeviceCertificate,
      eAwsCodeSigningKey
  };
  
  /**
   * @brief Structure for certificates/key storage.
   */
  typedef struct
  {
      CK_CHAR cDeviceCertificate[ pkcs11OBJECT_MAX_SIZE ];
      CK_CHAR cDeviceKey[ pkcs11OBJECT_MAX_SIZE ];
      CK_CHAR cDevicePubKey[ pkcs11OBJECT_MAX_SIZE ];
      CK_CHAR cCodeSignKey[ pkcs11OBJECT_MAX_SIZE ];
      uint32_t ulDeviceCertificateMark;
      uint32_t ulDeviceKeyMark;
      uint32_t ulCodeSignKeyMark;
      uint32_t ulDevicePubKeyMark;
  } P11KeyConfig_t;
  
  
  /**
   * @brief Certificates/key storage in flash.
   */
  P11KeyConfig_t P11KeyConfig __attribute__( ( section( "UNINIT_FIXED_LOC" ) ) );
  /*-----------------------------------------------------------*/
  
  #ifdef USE_OFFLOAD_SSL
  
  /* Exported from iot_wifi.c */
      extern WIFIReturnCode_t WIFI_StoreCertificate( uint8_t * pucCertificate,
                                                     uint16_t usCertificateLength );
      extern WIFIReturnCode_t WIFI_StoreKey( uint8_t * pucKey,
                                             uint16_t usKeyLength );
  
      #define BEGIN_EC_PRIVATE_KEY     "-----BEGIN EC PRIVATE KEY-----\n"
      #define END_EC_PRIVATE_KEY       "-----END EC PRIVATE KEY-----\n"
      #define BEGIN_RSA_PRIVATE_KEY    "-----BEGIN RSA PRIVATE KEY-----\n"
      #define END_RSA_PRIVATE_KEY      "-----END RSA PRIVATE KEY-----\n"
      #define BEGIN_CERTIFICATE        "-----BEGIN CERTIFICATE-----\n"
      #define END_CERTIFICATE          "-----END CERTIFICATE-----\n"
      #define NUM_CHAR_PER_PEM_LINE    64
  
  /*
   * @brief Converts DER objects to PEM objects.
   *
   * \note Only elliptic curve and RSA private keys are supported.
   *
   * \param[in]   pDerBuffer      A pointer the DER object.
   * \param[in]   xDerLength      The length of the DER object (bytes)
   * \param[out]  ppcPemBuffer    A pointer to the buffer that will be allocated
   *                              for the PEM object.  This function performs
   *                              a memory allocation for this buffer, and the
   *                              caller MUST free the buffer.
   * \param[out]  pPemLength      Length of the PEM object
   * \param[in]   xObjectType     Type of object being converted to PEM.
   *                              Valid values are CKO_PRIVATE_KEY and
   *                              CKO_CERTIFICATE.
   */
      static CK_RV prvDerToPem( uint8_t * pDerBuffer,
                                size_t xDerLength,
                                char ** ppcPemBuffer,
                                size_t * pPemLength,
                                CK_OBJECT_CLASS xObjectType )
      {
          CK_RV xReturn = CKR_OK;
          size_t xTotalPemLength = 0;
          mbedtls_pk_context pk;
          mbedtls_pk_type_t xKeyType;
          char * pcHeader;
          char * pcFooter;
          unsigned char * pemBodyBuffer;
          uint8_t * pFinalBufferPlaceholder;
          int ulLengthOfContentsCopiedSoFar = 0;
          int ulBytesInLine = 0;
          int ulBytesRemaining;
  
          if( xObjectType == CKO_PRIVATE_KEY )
          {
              mbedtls_pk_init( &pk );
              /* Parse key. */
              xReturn = mbedtls_pk_parse_key( &pk, pDerBuffer, xDerLength, NULL, 0 );
  
              if( xReturn != 0 )
              {
                  xReturn = CKR_ATTRIBUTE_VALUE_INVALID;
              }
  
              /* Get key algorithm. */
              xKeyType = mbedtls_pk_get_type( &pk );
  
              switch( xKeyType )
              {
                  case ( MBEDTLS_PK_RSA ):
                  case ( MBEDTLS_PK_RSA_ALT ):
                      pcHeader = BEGIN_RSA_PRIVATE_KEY;
                      pcFooter = END_RSA_PRIVATE_KEY;
                      xTotalPemLength = strlen( BEGIN_RSA_PRIVATE_KEY ) + strlen( END_RSA_PRIVATE_KEY );
                      break;
  
                  case ( MBEDTLS_PK_ECKEY ):
                  case ( MBEDTLS_PK_ECKEY_DH ):
                  case ( MBEDTLS_PK_ECDSA ):
                      pcHeader = BEGIN_EC_PRIVATE_KEY;
                      pcFooter = END_EC_PRIVATE_KEY;
                      xTotalPemLength = strlen( BEGIN_EC_PRIVATE_KEY ) + strlen( END_EC_PRIVATE_KEY );
                      break;
  
                  default:
                      xReturn = CKR_ATTRIBUTE_VALUE_INVALID;
                      break;
              }
  
              mbedtls_pk_free( &pk );
          }
          else /* Certificate object. */
          {
              pcHeader = BEGIN_CERTIFICATE;
              pcFooter = END_CERTIFICATE;
              xTotalPemLength = strlen( BEGIN_CERTIFICATE ) + strlen( END_CERTIFICATE );
          }
  
          if( xReturn == CKR_OK )
          {
              /* A PEM object has a header, body, and footer. */
  
              /*
               * ------- BEGIN SOMETHING --------\n
               * BODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODY\n
               * BODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODY\n
               * BODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODYBODY\n
               * ....
               * ------- END SOMETHING ---------\n
               */
  
              /* Determine the length of the Base 64 encoded body. */
              xReturn = mbedtls_base64_encode( NULL, 0, pPemLength, pDerBuffer, xDerLength );
  
              if( xReturn != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL )
              {
                  xReturn = CKR_ATTRIBUTE_VALUE_INVALID;
              }
              else
              {
                  xReturn = 0;
              }
  
              if( xReturn == 0 )
              {
                  /* Allocate memory for the PEM contents (excluding header, footer, newlines). */
                  pemBodyBuffer = pvPortMalloc( *pPemLength );
  
                  if( pemBodyBuffer == NULL )
                  {
                      xReturn = CKR_HOST_MEMORY;
                  }
              }
  
              if( xReturn == 0 )
              {
                  /* Convert the body contents from DER to PEM. */
                  xReturn = mbedtls_base64_encode( pemBodyBuffer,
                                                   *pPemLength,
                                                   pPemLength,
                                                   pDerBuffer,
                                                   xDerLength );
              }
  
              if( xReturn == 0 )
              {
                  /* Calculate the length required for the entire PEM object. */
                  xTotalPemLength += *pPemLength;
                  /* Add in space for the newlines. */
                  xTotalPemLength += ( *pPemLength ) / NUM_CHAR_PER_PEM_LINE;
  
                  if( ( *pPemLength ) % NUM_CHAR_PER_PEM_LINE != 0 )
                  {
                      xTotalPemLength += 1;
                  }
  
                  /* Allocate space for the full PEM certificate, including header, footer, and newlines.
                   * This space must be freed by the application. */
                  *ppcPemBuffer = pvPortMalloc( xTotalPemLength );
  
                  if( *ppcPemBuffer == NULL )
                  {
                      xReturn = CKR_HOST_MEMORY;
                  }
              }
  
              if( xReturn == 0 )
              {
                  /* Copy the header. */
                  pFinalBufferPlaceholder = ( uint8_t * ) *ppcPemBuffer;
                  memcpy( pFinalBufferPlaceholder, pcHeader, strlen( pcHeader ) );
                  pFinalBufferPlaceholder += strlen( pcHeader );
  
                  /* Copy the Base64 encoded contents into the final buffer 64 bytes at a time, adding newlines */
                  while( ulLengthOfContentsCopiedSoFar < *pPemLength )
                  {
                      ulBytesRemaining = *pPemLength - ulLengthOfContentsCopiedSoFar;
                      ulBytesInLine = ( ulBytesRemaining > NUM_CHAR_PER_PEM_LINE ) ? NUM_CHAR_PER_PEM_LINE : ulBytesRemaining;
                      memcpy( pFinalBufferPlaceholder,
                              pemBodyBuffer + ulLengthOfContentsCopiedSoFar,
                              ulBytesInLine );
                      pFinalBufferPlaceholder += ulBytesInLine;
                      *pFinalBufferPlaceholder = '\n';
                      pFinalBufferPlaceholder++;
  
                      ulLengthOfContentsCopiedSoFar += ulBytesInLine;
                  }
              }
  
              if( pemBodyBuffer != NULL )
              {
                  vPortFree( pemBodyBuffer );
              }
  
              /* Copy the footer. */
              memcpy( pFinalBufferPlaceholder, pcFooter, strlen( pcFooter ) );
  
              /* Update the total length of the PEM object returned by the function. */
              *pPemLength = xTotalPemLength;
          }
  
          return xReturn;
      }
  
  #endif /* ifdef USE_OFFLOAD_SSL */
  /*-----------------------------------------------------------*/
  
  CK_RV PKCS11_PAL_Initialize( void )
  {
      return CKR_OK;
  }
  
  /**
   * @brief Saves an object in non-volatile storage.
   *
   * Port-specific file write for cryptographic information.
   *
   * @param[in] pxLabel       The label of the object to be stored.
   * @param[in] pucData       The object data to be saved
   * @param[in] pulDataSize   Size (in bytes) of object data.
   *
   * @return The object handle if successful.
   * eInvalidHandle = 0 if unsuccessful.
   */
  int saveObjRetCert = -100;
  int saveObjRetKey = -100;
  CK_OBJECT_HANDLE PKCS11_PAL_SaveObject( CK_ATTRIBUTE_PTR pxLabel,
                                          CK_BYTE_PTR pucData,
                                          CK_ULONG ulDataSize )
  
  {
      CK_OBJECT_HANDLE xHandle = eInvalidHandle;
      CK_RV xBytesWritten = 0;
      CK_RV xReturn = CKR_OK;
      uint32_t ulFlashMark = ( pkcs11OBJECT_PRESENT_MAGIC | ( ulDataSize ) );
      uint8_t * pemBuffer = NULL;
      size_t pemLength = 0;
      CK_BBOOL xIsDestroy = CK_TRUE;
      int temp;
  
      #ifdef USE_OFFLOAD_SSL
          for( int i = 0; i < ulDataSize; i++ )
          {
              if( pucData[ i ] != 0 )
              {
                  xIsDestroy = CK_FALSE;
                  break;
              }
          }
      #endif
  
      if( ulDataSize <= pkcs11OBJECT_MAX_SIZE )
      {
          /*
           * write client certificate.
           */
          if( strcmp( pxLabel->pValue,
                      pkcs11configLABEL_DEVICE_CERTIFICATE_FOR_TLS ) == 0 )
          {
              saveObjRetCert = 0;
              xBytesWritten = FLASH_update( ( uint32_t ) P11KeyConfig.cDeviceCertificate,
                                            pucData,
                                            ( ulDataSize ) );
  
              saveObjRetCert = xBytesWritten;
              if( xBytesWritten == 0 /*( ulDataSize ) */ )
              {
                  xHandle = eAwsDeviceCertificate;
  
                  /*change flash written mark'*/
                  FLASH_update( ( uint32_t ) &P11KeyConfig.ulDeviceCertificateMark,
                                &ulFlashMark,
                                sizeof( uint32_t ) );
              }
  
              #ifdef USE_OFFLOAD_SSL
  
                  /* If we are using offload SSL, write the certificate to the
                   * WiFi module as well. */
                  if( xIsDestroy == CK_FALSE )
                  {
                      /* WiFi module needs PEM format. */
                      xReturn = prvDerToPem( pucData,
                                             ulDataSize,
                                             ( char ** ) &pemBuffer,
                                             &pemLength,
                                             CKO_CERTIFICATE );
                  }
                  else
                  {
                      pemBuffer = pvPortMalloc( pkcs11CLIENT_CERT_MAX_LENGTH );
  
                      if( pemBuffer == NULL )
                      {
                          xReturn = CKR_HOST_MEMORY;
                      }
                      else
                      {
                          memset( pemBuffer, 0x00, pkcs11CLIENT_CERT_MAX_LENGTH );
                          pemLength = pkcs11CLIENT_CERT_MAX_LENGTH;
                      }
                  }
  
                  if( xReturn != CKR_OK )
                  {
                      xHandle = eInvalidHandle;
                  }
  
                  if( xHandle == eAwsDeviceCertificate )
                  {
                      if( ( temp = WIFI_StoreCertificate( pemBuffer, ( uint16_t ) pemLength ) ) != eWiFiSuccess )
                      {
                          xHandle = eInvalidHandle;
                      }
                  }
  
                  if( xReturn == CKR_OK )
                  {
                      vPortFree( pemBuffer );
                  }
              #endif /* USE_OFFLOAD_SSL */
          }
  
          /*
           * write client key.
           */
  
          else if( strcmp( pxLabel->pValue,
                           pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS ) == 0 )
          {
              saveObjRetKey = 0;
              xBytesWritten = FLASH_update( ( uint32_t ) P11KeyConfig.cDevicePubKey,
                                            pucData,
                                            ulDataSize );
  
              saveObjRetKey = xBytesWritten;
              if( xBytesWritten == 0 /*( ulDataSize ) */ )
              {
                  xHandle = eAwsDevicePublicKey;
                  /*change flash written mark'*/
                  FLASH_update( ( uint32_t ) &P11KeyConfig.ulDevicePubKeyMark,
                                &ulFlashMark,
                                sizeof( uint32_t ) );
              }
          }
  
          else if( strcmp( pxLabel->pValue,
                           pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS ) == 0 )
          {
              saveObjRetKey = 0;
              xBytesWritten = FLASH_update( ( uint32_t ) P11KeyConfig.cDeviceKey,
                                            pucData,
                                            ulDataSize );
              saveObjRetKey = xBytesWritten;
              if( xBytesWritten == 0 /*( ulDataSize ) */ )
              {
                  xHandle = eAwsDevicePrivateKey;
                  /*change flash written mark'*/
                  FLASH_update( ( uint32_t ) &P11KeyConfig.ulDeviceKeyMark,
                                &ulFlashMark,
                                sizeof( uint32_t ) );
              }
  
              #ifdef USE_OFFLOAD_SSL
  
                  /* If we are using offload SSL, write the private key to the
                   * WiFi module as well. */
                  if( xIsDestroy == CK_FALSE )
                  {
                      /* WiFi module needs PEM format. */
                      xReturn = prvDerToPem( pucData,
                                             ulDataSize,
                                             ( char ** ) &pemBuffer,
                                             &pemLength,
                                             CKO_PRIVATE_KEY );
                  }
                  else
                  {
                      pemBuffer = pvPortMalloc( pkcs11CLIENT_PRIV_KEY_MAX_LENGTH );
  
                      if( pemBuffer == NULL )
                      {
                          xReturn = CKR_HOST_MEMORY;
                      }
                      else
                      {
                          memset( pemBuffer, 0x00, pkcs11CLIENT_PRIV_KEY_MAX_LENGTH );
                          pemLength = pkcs11CLIENT_PRIV_KEY_MAX_LENGTH;
                      }
                  }
  
                  if( xReturn != CKR_OK )
                  {
                      xHandle = eInvalidHandle;
                  }
  
                  if( xHandle == eAwsDevicePrivateKey )
                  {
                      if( ( temp = WIFI_StoreKey( pemBuffer, ( uint16_t ) pemLength ) ) != eWiFiSuccess )
                      {
                          xHandle = eInvalidHandle;
                      }
                  }
  
                  if( xReturn == CKR_OK )
                  {
                      vPortFree( pemBuffer );
                  }
              #endif /* USE_OFFLOAD_SSL */
          }
  
          else if( strcmp( pxLabel->pValue,
                           pkcs11configLABEL_CODE_VERIFICATION_KEY ) == 0 )
          {
              xBytesWritten = FLASH_update( ( uint32_t ) P11KeyConfig.cCodeSignKey,
                                            pucData,
                                            ulDataSize );
  
              if( xBytesWritten == 0 /*( ulDataSize ) */ )
              {
                  xHandle = eAwsCodeSigningKey;
  
                  /*change flash written mark'*/
                  FLASH_update( ( uint32_t ) &P11KeyConfig.ulCodeSignKeyMark,
                                &ulFlashMark,
                                sizeof( uint32_t ) );
              }
          }
      }
  
      return xHandle;
  }
  
  
  
  /*-----------------------------------------------------------*/
  
  /**
   * @brief Translates a PKCS #11 label into an object handle.
   *
   * Port-specific object handle retrieval.
   *
   *
   * @param[in] pxLabel         Pointer to the label of the object
   *                           who's handle should be found.
   * @param[in] usLength       The length of the label, in bytes.
   *
   * @return The object handle if operation was successful.
   * Returns eInvalidHandle if unsuccessful.
   */
  
  CK_OBJECT_HANDLE PKCS11_PAL_FindObject( CK_BYTE_PTR pxLabel,
                                          CK_ULONG usLength )
  {
      CK_OBJECT_HANDLE xHandle = eInvalidHandle;
  
      if( ( 0 == memcmp( pxLabel, pkcs11configLABEL_DEVICE_CERTIFICATE_FOR_TLS, usLength ) ) &&
          ( ( P11KeyConfig.ulDeviceCertificateMark & pkcs11OBJECT_PRESENT_MASK ) == pkcs11OBJECT_PRESENT_MAGIC ) )
      {
          xHandle = eAwsDeviceCertificate;
      }
      else if( ( 0 == memcmp( pxLabel, pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS, usLength ) ) &&
               ( ( P11KeyConfig.ulDeviceKeyMark & pkcs11OBJECT_PRESENT_MASK ) == pkcs11OBJECT_PRESENT_MAGIC ) )
      {
          xHandle = eAwsDevicePrivateKey;
      }
      else if( ( 0 == memcmp( pxLabel, pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS, usLength ) ) &&
               ( ( P11KeyConfig.ulDevicePubKeyMark & pkcs11OBJECT_PRESENT_MASK ) == pkcs11OBJECT_PRESENT_MAGIC ) )
      {
          xHandle = eAwsDevicePublicKey;
      }
      else if( ( 0 == memcmp( pxLabel, pkcs11configLABEL_CODE_VERIFICATION_KEY, usLength ) ) &&
               ( ( P11KeyConfig.ulCodeSignKeyMark & pkcs11OBJECT_PRESENT_MASK ) == pkcs11OBJECT_PRESENT_MAGIC ) )
      {
          xHandle = eAwsCodeSigningKey;
      }
  
      return xHandle;
  }
  
  /**
   * @brief Gets the value of an object in storage, by handle.
   *
   * Port-specific file access for cryptographic information.
   *
   * This call dynamically allocates the buffer which object value
   * data is copied into.  PKCS11_PAL_GetObjectValueCleanup()
   * should be called after each use to free the dynamically allocated
   * buffer.
   *
   * @sa PKCS11_PAL_GetObjectValueCleanup
   *
   * @param[in] pcFileName    The name of the file to be read.
   * @param[out] ppucData     Pointer to buffer for file data.
   * @param[out] pulDataSize  Size (in bytes) of data located in file.
   * @param[out] pIsPrivate   Boolean indicating if value is private (CK_TRUE)
   *                          or exportable (CK_FALSE)
   *
   * @return CKR_OK if operation was successful.  CKR_KEY_HANDLE_INVALID if
   * no such object handle was found, CKR_DEVICE_MEMORY if memory for
   * buffer could not be allocated, CKR_FUNCTION_FAILED for device driver
   * error.
   */
  
  CK_RV PKCS11_PAL_GetObjectValue( CK_OBJECT_HANDLE xHandle,
                                        CK_BYTE_PTR * ppucData,
                                        CK_ULONG_PTR pulDataSize,
                                        CK_BBOOL * pIsPrivate )
  
  {
      CK_RV ulReturn = CKR_OBJECT_HANDLE_INVALID;
  
      /*
       * Read client certificate.
       */
  
      if( xHandle == eAwsDeviceCertificate )
      {
          /*
           * return reference and size only if certificates are present in flash
           */
          if( ( P11KeyConfig.ulDeviceCertificateMark & pkcs11OBJECT_PRESENT_MASK ) == pkcs11OBJECT_PRESENT_MAGIC )
          {
              *ppucData = P11KeyConfig.cDeviceCertificate;
              *pulDataSize = ( uint32_t ) P11KeyConfig.ulDeviceCertificateMark & pkcs11OBJECT_LENGTH_MASK;
              *pIsPrivate = CK_FALSE;
              ulReturn = CKR_OK;
          }
      }
  
      /*
       * Read client key.
       */
  
      else if( xHandle == eAwsDevicePrivateKey )
      {
          /*
           * return reference and size only if certificates are present in flash
           */
          if( ( P11KeyConfig.ulDeviceKeyMark & pkcs11OBJECT_PRESENT_MASK ) == pkcs11OBJECT_PRESENT_MAGIC )
          {
              *ppucData = P11KeyConfig.cDeviceKey;
              *pulDataSize = ( uint32_t ) ( P11KeyConfig.ulDeviceKeyMark & pkcs11OBJECT_LENGTH_MASK );
              *pIsPrivate = CK_TRUE;
              ulReturn = CKR_OK;
          }
      }
  
      else if( xHandle == eAwsDevicePublicKey )
      {
          /*
           * return reference and size only if certificates are present in flash
           */
          if( ( P11KeyConfig.ulDevicePubKeyMark & pkcs11OBJECT_PRESENT_MASK ) == pkcs11OBJECT_PRESENT_MAGIC )
          {
              *ppucData = P11KeyConfig.cDevicePubKey;
              *pulDataSize = ( uint32_t ) P11KeyConfig.ulDevicePubKeyMark & pkcs11OBJECT_LENGTH_MASK;
              *pIsPrivate = CK_FALSE;
              ulReturn = CKR_OK;
          }
      }
  
      else if( xHandle == eAwsCodeSigningKey )
      {
          if( ( P11KeyConfig.ulCodeSignKeyMark & pkcs11OBJECT_PRESENT_MASK ) == pkcs11OBJECT_PRESENT_MAGIC )
          {
              *ppucData = P11KeyConfig.cCodeSignKey;
              *pulDataSize = ( uint32_t ) P11KeyConfig.ulCodeSignKeyMark & pkcs11OBJECT_LENGTH_MASK;
              *pIsPrivate = CK_FALSE;
              ulReturn = CKR_OK;
          }
      }
  
      return ulReturn;
  }
  
  /*-----------------------------------------------------------*/
  
  /**
   * @brief Cleanup after PKCS11_GetObjectValue().
   *
   * @param[in] pucData       The buffer to free.
   *                          (*ppucData from PKCS11_PAL_GetObjectValue())
   * @param[in] ulDataSize    The length of the buffer to free.
   *                          (*pulDataSize from PKCS11_PAL_GetObjectValue())
   */
  void PKCS11_PAL_GetObjectValueCleanup( CK_BYTE_PTR pucData,
                                         CK_ULONG ulDataSize )
  {
      /* Unused parameters. */
      ( void ) pucData;
      ( void ) ulDataSize;
  
      /* Since no buffer was allocated on heap, there is no cleanup
       * to be done. */
  }
  /*-----------------------------------------------------------*/
  