/*! \file 
**********************************************************************************
*Title:                         Discretix Toolkit Certificate Handling ATP Test source file
*
* Filename:                     CERT_TLK_ATP_util.c
*
* 
* Created:                      27.05.2008
*
* \Author                       SagitB
*
* \Remarks
*           Copyright (C) 2008 by Discretix Technologies Ltd. All Rights reserved.
**********************************************************************************/
/************* Include Files ***********************************/
#include "DX_VOS_BaseTypes.h"
#include "CRYS_RSA_Types.h"
#include "CRYS_RSA_BUILD.h"
#include "DX_VOS_Mem.h"
#include "CRYS_RSA_SCHEMES.h"
#include "DX_VOS_File.h"
#include "MW_ATP_UTIL_funcs.h"
#if CERT_API_SST
#include "sst.h"
#endif
#include "CERT_TLK_ATP_data.h"
#ifndef TLK_CERT_NO_SCLK
#include "tlk_sclk_api_types.h"
#include "tlk_sclk_api.h"
#else
#include "tlk_cert_sclk_api_stub_types.h"
#endif
#include "MW_ATP_UTIL_funcs.h"

/***** Global Variables **************/


#if TLK_SCLK_VNVS_SST_ON_SEP

  #define TLK_SCLK_TEST_DB_FILENAME "TST_DX_TLK_CERT_DB"
  #define TLK_SCLK_TEST_DB_FILENAME_SIZE_BYTES  14
  #define TLK_SCLK_TEST_DB_FILENAME_SECOND "TST_DX_TLK_CERT_DB_SECOND"
  #define NVS_MEMORY_DATA_POOL_SIZE_IN_BYTES (1024UL)
 #ifndef DX_NVS_RAM
    DxVosFile               g_MainDBFileHandle;
    DxVosFile               g_SecondaryDBFileHandle;
 #else
    DxChar TST_MainTLK_CERT_DBPool[NVS_MEMORY_DATA_POOL_SIZE_IN_BYTES];
    DxChar TST_SecondaryTLK_CERT_DBPool[NVS_MEMORY_DATA_POOL_SIZE_IN_BYTES];
  #endif

 #endif

#ifndef TLK_CERT_NO_SCLK


/*****************************************************************************
* Function Name:                                                           
*  TST_ATP_TLK_CERT_INIT
* 
* Inputs:
*  None
*
* Outputs:
*  DxError_t - Function error return                                        
*
* Description:                                                                 
*    open the database for the secure clock and the secure clock toolkit
* Algorithm:
* 1. Crate the DB.
* 2. If working with SST call SST_Init.
* 3. Initialize the new master clock descriptor.
* 4. Generate a new descriptor for secured service clock
*******************************************************************************/ 

DxError_t TST_ATP_TLK_CERT_INIT(void)
{
  DxError_t                     TST_Status;
  DxUint32_t                    maxAllowedDriftIn0_1Seconds;
  DxUint32_t                    readPermission;
  DxUint32_t                    maximumRevalidationPeriod;
  TLK_SCLK_ServiceClockTime_t   expectedTimeInSeconds;

#ifdef SCLK_ON_SEP
  DxUint32_t 						   timeAddress;
#endif


  /************************************************************************/
  /*  Init VNVS for TLK SCLK                                              */
  /************************************************************************/ 

#if TLK_SCLK_ATP_VNVS_SST_ON_SEP
#ifndef DX_NVS_RAM  

  
  TST_Status = DX_VOS_FOpen(&g_MainDBFileHandle,TLK_SCLK_TEST_DB_FILENAME ,"w+b");
  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"DX_VOS_FOpen main", "g_MainDBFileHandle", "TST_ATP_TLK_CERT_INIT");

  TST_Status = DX_VOS_FOpen(&g_SecondaryDBFileHandle,TLK_SCLK_TEST_DB_FILENAME_SECOND ,"w+b");
  if(TST_ATP_CheckErrorReturn(TST_Status,"DX_VOS_FOpen Second", "g_SecondaryDBFileHandle", "!TST_ATP_TLK_CERT_INIT") != TST_PASS)
    return TST_FAIL;
#else
  g_MainDBFileHandle        = (DxVosFile)TST_MainTLK_CERT_DBPool;
  g_SecondaryDBFileHandle   = (DxVosFile)TST_SecondaryTLK_CERT_DBPool;
#endif
  TST_Status = SST_Init((DxNvsMemoryId_t)g_MainDBFileHandle,
                       (DxNvsMemoryId_t)g_SecondaryDBFileHandle,
                       DX_NULL,
                       TST_gCWorkspace,
                       TST_gCWorkspaceSizeInBytes); 
  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"SST_Init", "!!!!!!!!!", "TST_ATP_TLK_CERT_INIT");
#endif

  /************************************************************************/
  /*  Init VNVS for TLK SCLK                                              */
  /************************************************************************/ 
  TST_Status = TLK_SCLK_Init(TST_gCWorkspace,
                            TST_gCWorkspaceSizeInBytes);
  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"TLK_SCLK_Init", "!!!!!!!!!", "TST_ATP_TLK_CERT_INIT")
  maxAllowedDriftIn0_1Seconds     = 0x1000;
  readPermission                  = TLK_SCLK_WORLD_READABLE;
  maximumRevalidationPeriod       = 60;

  TST_gServiceClockPwd.buff_ptr                  = TST_gServiceClockPwdBuffer;
  TST_gServiceClockPwd.buffSizeInBytes           = TST_gServiceClockPwdLength;

  TST_gServClkDescNonceValidPwd.buff_ptr         = TST_gServClkDescNonceValidPwdBuffer;
  TST_gServClkDescNonceValidPwd.buffSizeInBytes  = TST_gServClkDescNonceValidPwdLength;

  TST_Status = TLK_SCLK_ServiceClkGen(&TST_gServiceClockDesc,
                                      DX_NULL,
                                      maxAllowedDriftIn0_1Seconds,
                                      maximumRevalidationPeriod,
                                      readPermission,
                                      TST_gServiceClockPwd.buff_ptr,
                                      TST_gServiceClockPwd.buffSizeInBytes,
                                      TST_gCWorkspace,
                                      TST_gCWorkspaceSizeInBytes);
  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"TLK_SCLK_ServiceClkGen", "!!!!!!!!!", "TST_ATP_TLK_CERT_INIT");
  
  MW_TST_Util_GetTime(&expectedTimeInSeconds.secondsSinceFormat);


  TST_Status = TLK_SCLK_ServiceClkRevalidate(&TST_gServiceClockDesc,
                                            DX_NULL,
                                            &expectedTimeInSeconds,
                                            TLK_SCLK_SECONDS_SINCE_FORMAT,
                                            TST_gServiceClockPwd.buff_ptr,
                                            TST_gServiceClockPwd.buffSizeInBytes,
                                            TST_gCWorkspace,
                                            TST_gCWorkspaceSizeInBytes);

  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"TLK_SCLK_ServiceClkRevalidate", "TST_ATP_TLK_CERT_INIT", "TST_ATP_TLK_CERT_INIT");

  return TST_PASS;
  EXIT_ON_ERROR:
  {
    return DX_FAILURE;
  }
}


/*****************************************************************************
* Function Name:                                                           
*  TST_ATP_TLK_CERT_Terminate        
* 
* Outputs:
*  DxError_t - Function error return                                        
*
* Description:                                                                 
* this function Terminate the secure clock and the SST 
*
******************************************************************************/
DxError_t TST_ATP_TLK_CERT_Terminate(void)
{
  DxError_t TST_Status;
  DxChar_t * TST_SubTestName = "TST_ATP_TLK_CERT_Terminate";
  DxChar_t * TST_MasterTestName = "main";

  TST_Status = TLK_SCLK_Terminate(TST_gCWorkspace,TST_gCWorkspaceSizeInBytes);
  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"TLK_SCLK_Terminate",TST_SubTestName,TST_MasterTestName);
  

#if TLK_SCLK_VNVS_SST_ON_SEP 
  TST_Status = SST_Terminate();
  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"SST_Terminate",TST_SubTestName,TST_MasterTestName);
  
  
 
#ifndef DX_NVS_RAM  
  TST_Status = DX_VOS_FClose(g_MainDBFileHandle);
  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"DX_VOS_FClose - TST_gMainDBFileHandle",TST_SubTestName,TST_MasterTestName);
 

  TST_Status = DX_VOS_FClose(g_SecondaryDBFileHandle);
  TST_ATP_CHECK_ERROR_RETURN(TST_Status,"DX_VOS_FClose - TST_gSecondaryDBFileHandle",TST_SubTestName,TST_MasterTestName);
  
#endif

#endif
  return TST_PASS;
  EXIT_ON_ERROR:
  {
    return DX_FAILURE;
  }

}
#endif

/**
****************************************************************
* Function Name: 
*  UpdateResponseSignature
*
* @param aResponsePtr      [in/out] - Pointer to the OCSP response
*        object buffer in DER format to be processed;
* @param aResponseLength   [in]     - OCSP response length;
* @param aRSAPrivateKeyPtr [in]     - Pointer to the RSA private
*        key object in DER format;
* @param aRSAPrivateKeyDataLength [in] - RSA private key buffer size;
* @param aNoncePtr         [in]     - Pointer to the nonce buffer
*        that'll be written to current OCSP response overriding old;
* @param aNonceLength   [in]     - OCSP response length;
*
*
* @returns \b
*  bool 
*  - true  - The operation completed successfully;
*  - false - The operation failed.
*
* \brief \b 
* Description:
*  This function gets OCSP response in DER format, private RSA key
*  with using which response was signed (or another RSA key to be
*  used), nonce buffer that contains new nonce and nonce size to
*  replace old nonce value and than signs modified OCSP response.
*
* \note
*  Function fails when:
*  - OCSP response ASN1 object structure is invalid:
*    - corrupted;
*    - doesn't contains response data that is optional;
*    - doesn't contains signature;
*    - doesn't contains nonce extension;
*  - OCSP contains not supported data: HASH and key type;
*  - OCSP response nonce extension data size doesn't match input
*    nonce size;
*
* \b 
* Algorithm:
*  -# Validate input pointers;
*  -# Validate RSA private key ASN1 object and build using CRYS
*     function CRYS_RSA_Build_PrivKey;
*  -# Validate OCSP response ASN1 object;
*  -# Find and replace nonce extension value;
*  -# Validate signature algorithm: HASH and key type:
*     supported only (CRYS) SHA1, MD5 and RSA key encryption;
*  -# Sign OCSP response using CRYS function _DX_RSA_Sign.
***************************************************************/
DxUint32_t UpdateResponseSignature(
                                   DxUint8_t	*aResponsePtr,
                                   DxUint8_t	*aRSAPrivateKeyPtr,
                                   DxUint8_t	*aNoncePtr,
                                   DxUint32_t	aNonceLength)
{
  /* Internal defines */
  /* Definitions of the ASN1 object ID */
#define ASN1_INTEGER_ID			0x02
#define ASN1_BIT_STRING_ID		0x03
#define ASN1_OCTET_STRING_ID	0x04
#define ASN1_OBJECT_ID			0x06
#define ASN1_ENUMERATED_ID		0x0A
#define ASN1_GENERALIZEDTIME_ID	0x18
#define ASN1_CONSTRUCTED_ID		0x20
#define ASN1_SEQUENCE_ID		0x80

  /* Macro that gets length of the ASN1 object length */
#define ASN1_CONTEXT_LENGTH_LENGTH(aBytePtr) \
  ((*aBytePtr & 0x80) ? ((*aBytePtr & 0x7f) + 1) : (1))

  /* Macro that gets length of the ASN1 object */
#define ASN1_CONTEXT_LENGTH(aBytePtr, aLengthReturnPtr) \
  { \
  const DxUint8_t	*_vBytePtr	= aBytePtr; \
  unsigned int	_vLength	= (*_vBytePtr & 0x7f); \
  \
  if (*_vBytePtr & 0x80) \
  { \
  unsigned int vCount = _vLength; \
  \
  for (_vLength = 0; vCount > 0; --vCount) \
  { \
  _vLength <<= 8L; \
  _vLength |= *(++_vBytePtr); \
} \
} \
  \
  *aLengthReturnPtr = _vLength; \
}

  /* ASN1 IOD constants */
  static DxUint32_t OID_Length				= 9;
  static DxUint8_t OID_BasicResponse[]		= { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 };
  static DxUint8_t OID_RSAEncryption[]		= { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
  static DxUint8_t OID_md5withRSAEncryption[]	= { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04 };
  static DxUint8_t OID_sha1withRSAEncryption[]= { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 };
  static DxUint8_t OID_OCSP_Nonce[]			= { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 };

  /* CRYS methods parameters definition */
  CRYS_RSAPrivUserContext_t	vUserContext_ptr= { 0 };
  CRYS_RSAUserPrivKey_t		vUserPrivKey_ptr= { 0 };
  CRYS_RSA_HASH_OpMode_t		vhashFunc		= CRYS_RSA_HASH_MD5_mode;

  /* Variables */
  DxUint32_t	vPrivExponentSize;
  DxUint8_t	*vPrivExponent_ptr;
  DxUint32_t	vPubExponentSize;
  DxUint8_t	*vPubExponent_ptr;
  DxUint32_t	vModulusSize;
  DxUint8_t	*vModulus_ptr;

  DxUint32_t	vResponseLength;
  DxUint8_t	*vResponseDataPtr;
  DxUint32_t	vResponseDataLength;
  DxUint8_t	*vOutput_ptr = DX_NULL;
  DxUint16_t	vOutputSize;

  DxUint32_t	vSignatureDataLength;
  DxUint8_t	*vSignatureDataPtr;
  DxUint32_t	vSignatureAlgorithmLength;
  DxUint8_t	*vSignatureAlgorithmPtr;
  DxUint8_t	*vNoncePtr	= DX_NULL;
  DxUint8_t	*vPtr		= DX_NULL;

  CRYSError_t vError		= CRYS_OK;
  DxBool_t		vResult		= DX_TRUE;
  DxUint32_t	vLength		= 0;
  DxUint32_t	i			= 0;

  /* Simple validation */
  if (aResponsePtr == DX_NULL ||
    aRSAPrivateKeyPtr == DX_NULL ||
    aNoncePtr == DX_NULL)
    goto error;

  /* Parse ASN1 RSA private key */
  vPtr = aRSAPrivateKeyPtr;

  /* Check RSA private key ASN1 structure */
  if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
  {
    vError = 100;
    goto error;
  }

  ++vPtr;
  ASN1_CONTEXT_LENGTH(vPtr, &vLength);
  vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

  /* Version */
  if (vPtr[0] != ASN1_INTEGER_ID)
  {
    vError = 101;
    goto error;
  }

  ++vPtr;
  ASN1_CONTEXT_LENGTH(vPtr, &vLength);
  vPtr += vLength + 1;

  /* N */
  if (vPtr[0] != ASN1_INTEGER_ID)
  {
    vError = 102;
    goto error;
  }

  ++vPtr;
  ASN1_CONTEXT_LENGTH(vPtr, &vModulusSize);
  vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);
  vModulus_ptr = vPtr;
  vPtr += vModulusSize;

  /* E */
  if (vPtr[0] != ASN1_INTEGER_ID)
  {
    vError = 103;
    goto error;
  }

  ++vPtr;
  ASN1_CONTEXT_LENGTH(vPtr, &vPubExponentSize);
  vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);
  vPubExponent_ptr = vPtr;
  vPtr += vPubExponentSize;

  /* D */
  if (vPtr[0] != ASN1_INTEGER_ID)
  {
    vError = 104;
    goto error;
  }

  ++vPtr;
  ASN1_CONTEXT_LENGTH(vPtr, &vPrivExponentSize);
  vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);
  vPrivExponent_ptr = vPtr;

  /* Build RSA private key */
  vError =
    CRYS_RSA_Build_PrivKey(
    &vUserPrivKey_ptr,
    vPrivExponent_ptr,
    (DxUint16_t)vPrivExponentSize,
    vPubExponent_ptr,
    (DxUint16_t)vPubExponentSize,
    vModulus_ptr,
    (DxUint16_t)vModulusSize);

  if (vError != CRYS_OK)
  {
    vError = 105;
    goto error;
  }

  /* Parse ASN1 OCSP response */
  vPtr = aResponsePtr;

  /* Check OCSP response ASN1 structure */
  if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
  {
    vError = 200;
    goto error;
  }

  ++vPtr;
  ASN1_CONTEXT_LENGTH(vPtr, &vResponseLength);
  vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

  /* Response status */
  if (vPtr[0] != ASN1_ENUMERATED_ID)
  {
    vError = 201;
    goto error;
  }

  ++vPtr;
  ASN1_CONTEXT_LENGTH(vPtr, &vLength);
  vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr) + vLength;

  /*
  If response data is not present it is valid situation
  because no signature is present because of response bytes
  data block is optional
  */
  if (vPtr >= aResponsePtr + vResponseLength + 3)
  {
    /*
    But in this case there is an error because of nonce
    extension is missing
    */
    vError = 202;
    goto error;
  }

  /* Response bytes context */
  if (!(vPtr[0] & ASN1_SEQUENCE_ID) ||
    !(vPtr[0] & ASN1_CONSTRUCTED_ID))
  {
    vError = 203;
    goto error;
  }

  ++vPtr;
   vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

  /* Response bytes sequence */
  if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
  {
    vError = 204;
    goto error;
  }

  ++vPtr;
   vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

  /* Response type object: must be OCSP_BASICRESP */
  if (vPtr[0] != ASN1_OBJECT_ID)
  {
    vError = 205;
    goto error;
  }

  ++vPtr;
  ASN1_CONTEXT_LENGTH(vPtr, &vLength);

  /* Validate with OCSP_BASICRESP OID */
  if (vLength != OID_Length)
  {
    vError = 206;
    goto error;
  }

  vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

  for (i = 0; i < OID_Length; ++i)
    if (vPtr[i] != OID_BasicResponse[i])
    {
      vError = 206;
      goto error;
    }

    vPtr += vLength;

    /* Response bytes: octet string data */
    if (vPtr[0] != ASN1_OCTET_STRING_ID)
    {
      vError = 207;
      goto error;
    }

    ++vPtr;
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

    /* Check for OCSP_BASICRESP sequence */
    if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
    {
      vError = 208;
      goto error;
    }

    ++vPtr;
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

    /* Check for OCSP_RESPDATA sequence */
    if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
    {
      vError = 209;
      goto error;
    }

    vResponseDataPtr = vPtr;
    ++vPtr;
    ASN1_CONTEXT_LENGTH(vPtr, &vLength);
    vResponseDataLength = ASN1_CONTEXT_LENGTH_LENGTH(vPtr) + vLength + 1;

    /*
    Search for nonce extension
    Move to first item:
    probably response data (its optional) version
    */
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

    /* Check for response data version (optional) */
    if (vPtr[0] == ASN1_INTEGER_ID)
    {
      /* Move to response data responder id context */
      ++vPtr;
      ASN1_CONTEXT_LENGTH(vPtr, &vLength);
      vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr) + vLength;
    }

    /* Check for response data responder id context */
    if (!(vPtr[0] & ASN1_SEQUENCE_ID) ||
      !(vPtr[0] & ASN1_CONSTRUCTED_ID))
    {
      vError = 210;
      goto error;
    }

    /* Move to response data produce at time */
    ++vPtr;
    ASN1_CONTEXT_LENGTH(vPtr, &vLength);
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr) + vLength;

    /* Check for response data produce at time */
    if (vPtr[0] != ASN1_GENERALIZEDTIME_ID)
    {
      vError = 210;
      goto error;
    }

    /* Move to response data single response sequence */
    ++vPtr;
    ASN1_CONTEXT_LENGTH(vPtr, &vLength);
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr) + vLength;

    /* Check for response data single response sequence */
    if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
    {
      vError = 210;
      goto error;
    }

    /* Move to response data extensions context */
    ++vPtr;
    ASN1_CONTEXT_LENGTH(vPtr, &vLength);
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr) + vLength;

    /* Check if response data extension context present */
    if (vResponseDataPtr + vResponseDataLength <= vPtr)
    {
      vError = 210;
      goto error;
    }

    /* Check for response data extensions context */
    if (!(vPtr[0] & ASN1_SEQUENCE_ID) ||
      !(vPtr[0] & ASN1_CONSTRUCTED_ID))
    {
      vError = 210;
      goto error;
    }

    /* Move to response data extensions sequence */
    ++vPtr;
    ASN1_CONTEXT_LENGTH(vPtr, &vLength);
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

    /* Check for response data extensions sequence */
    if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
    {
      vError = 210;
      goto error;
    }

    /* Move to first response data extension */
    ++vPtr;
    ASN1_CONTEXT_LENGTH(vPtr, &vLength);
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

    /* Search for nonce extension in extensions sequence */
    {
      DxUint32_t vExtensionsLength = vLength;

      for (;;)
      {
        /* Check for response data extensions sequence */
        if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
        {
          vError = 210;
          goto error;
        }

        /* Check for nonce extension match */
        ++vPtr;
        ASN1_CONTEXT_LENGTH(vPtr, &vLength);

        {
          DxUint8_t *vExtensionPtr = vPtr + ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

          /* Check for nonce extension object: must be id_pkix_OCSP_Nonce */
          if (vExtensionPtr[0] == ASN1_OBJECT_ID)
          {
            DxUint32_t vCurrLength = 0;

            ++vExtensionPtr;
            ASN1_CONTEXT_LENGTH(vExtensionPtr, &vCurrLength)

              /* Validate with OCSP_Nonce OID */
              if (vCurrLength != OID_Length)
                goto next_extension;

            vExtensionPtr += ASN1_CONTEXT_LENGTH_LENGTH(vExtensionPtr);

            for (i = 0; i < OID_Length; ++i, ++vExtensionPtr)
              if (*vExtensionPtr != OID_OCSP_Nonce[i])
                break;

            /* Check whether OCSP_Nonce object found */
            if (i < OID_Length)
              goto next_extension;

            /*
            Check for nonce extension data: now return error because of
            nonce extension doesn't match expected
            */
            if (vExtensionPtr[0] != ASN1_OCTET_STRING_ID)
            {
              vError = 210;
              goto error;
            }

            /* Move to extension octet string data */
            ++vExtensionPtr;
            vExtensionPtr += ASN1_CONTEXT_LENGTH_LENGTH(vExtensionPtr);

            /* Check extension data */
            if (vExtensionPtr[0] != ASN1_OCTET_STRING_ID)
            {
              vError = 210;
              goto error;
            }

            /* Validate extension data length with Nonce length */
            ++vExtensionPtr;
            ASN1_CONTEXT_LENGTH(vExtensionPtr, &vCurrLength);

            if (vCurrLength != aNonceLength)
            {
              vError = 210;
              goto error;
            }

            /* Extension found and its valid: save it pointer */
            vExtensionPtr += ASN1_CONTEXT_LENGTH_LENGTH(vExtensionPtr);
            vNoncePtr = vExtensionPtr;
            break;
          }
        }

next_extension:
        /* Move to next response data extension */
        vLength += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);
        vPtr += vLength;
        ++vLength;

        /* Check for extensions end */
        if (vExtensionsLength <= vLength)
        {
          vError = 210;
          goto error;
        }

        vExtensionsLength -= vLength;
      }
    }

    /* Move to signature algorithm sequence */
    vPtr = vResponseDataPtr + vResponseDataLength;

    /* Check for Signature algorithm sequence */
    if (!(vPtr[0] & ASN1_CONSTRUCTED_ID))
    {
      vError = 210;
      goto error;
    }

    ++vPtr;
    ASN1_CONTEXT_LENGTH(vPtr, &vLength);
    vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);
    vSignatureAlgorithmPtr = vPtr;
    vPtr += vLength;

    /* Algorithm object: sha1 or md5 with RSA encryption only */
    if (vSignatureAlgorithmPtr[0] != ASN1_OBJECT_ID)
    {
      vError = 210;
      goto error;
    }

    ++vSignatureAlgorithmPtr;
    ASN1_CONTEXT_LENGTH(vSignatureAlgorithmPtr, &vSignatureAlgorithmLength);
    vSignatureAlgorithmPtr += ASN1_CONTEXT_LENGTH_LENGTH(vSignatureAlgorithmPtr);

    /* Validate HASH and Engine OID */
    if (vSignatureAlgorithmLength != OID_Length)
    {
      vError = 210;
      goto error;
    }

    for (i = 0; i < OID_Length - 1; ++i)
      if (vSignatureAlgorithmPtr[i] != OID_RSAEncryption[i])
      {
        vError = 210;
        goto error;
      }

      if (vSignatureAlgorithmPtr[i] == OID_sha1withRSAEncryption[i])
      {
        vhashFunc = CRYS_RSA_HASH_SHA1_mode;
      }
      else if (vSignatureAlgorithmPtr[i] == OID_md5withRSAEncryption[i])
      {
        vhashFunc = CRYS_RSA_HASH_MD5_mode;
      }
      else
      {
        vError = 210;
        goto error;
      }

      /* Response signature bit string */
      if (vPtr[0] != ASN1_BIT_STRING_ID)
      {
        vError = 211;
        goto error;
      }

      ++vPtr;
      ASN1_CONTEXT_LENGTH(vPtr, &vLength);
      vPtr += ASN1_CONTEXT_LENGTH_LENGTH(vPtr);

      /* Skip first byte that contains unused bits count */
      --vLength;
      ++vPtr;

      vSignatureDataPtr = vPtr;
      vSignatureDataLength = vLength;

      /* Output */
      vOutputSize = (DxUint16_t)vSignatureDataLength;
      vOutput_ptr = vSignatureDataPtr;

      /* Everything pass - update nonce extension data */
        DX_VOS_FastMemCpy(
        vNoncePtr,		
        aNoncePtr,	
        aNonceLength	
        );

      /* Sign OCSP response data */
      vError = CRYS_RSA_PKCS1v15_Sign(&vUserContext_ptr,
                                      &vUserPrivKey_ptr,
                                      vhashFunc,
                                      vResponseDataPtr,
                                      vResponseDataLength,
                                      vOutput_ptr,
                                      &vOutputSize);
    if(CRYS_OK != vError )
     return vError;


      vResult = (DxBool_t)(vOutputSize == vSignatureDataLength);

error:
      vResult = (DxBool_t)vError;
      return vResult;

      /* Undef internal */
#undef ASN1_INTEGER_ID
#undef ASN1_BIT_STRING_ID
#undef ASN1_OCTET_STRING_ID
#undef ASN1_OBJECT_ID
#undef ASN1_ENUMERATED_ID
#undef ASN1_GENERALIZEDTIME_ID
#undef ASN1_CONSTRUCTED_ID
#undef ASN1_SEQUENCE_ID

#undef ASN1_CONTEXT_LENGTH_LENGTH

#undef ASN1_CONTEXT_LENGTH
}



