FLEX-FORD-OBC-BM/Source/bsw/Fbl/fbl_valstruct.c

1172 lines
56 KiB
C

/***********************************************************************************************************************
* FILE DESCRIPTION
* ------------------------------------------------------------------------------------------------------------------*/
/** \file
* \brief Implementation of a download check by using an embedded validation structure
* Declaration of functions, variables and constants
*
* --------------------------------------------------------------------------------------------------------------------
* COPYRIGHT
* --------------------------------------------------------------------------------------------------------------------
* \par Copyright
* \verbatim
* Copyright (c) 2023 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
*/
/**********************************************************************************************************************/
/***********************************************************************************************************************
* REVISION HISTORY
* --------------------------------------------------------------------------------------------------------------------
* Version Date Author Change Id Description
* --------------------------------------------------------------------------------------------------------------------
* 01.00.00 2016-07-01 visci - Initial version
* 01.01.00 2017-02-03 visci ESCAN00093858 Added support for compatibility check
* vacel Added blank check functionality
* Added API for external public key
* Reworked return value handling
* 01.01.01 2017-11-09 visci ESCAN00096836 Compiler warning: Function declared but not used
* 01.01.02 2018-03-23 visdkl ESCAN00097287 Bootloader does not properly use configuration of CLASS_DDD
* 01.02.00 2018-06-15 visci ESCAN00098963 Corrected return value for public key read failure
* 2018-09-24 visrr ESCAN00100838 Added user callout for different erase values in OTA use case
* 01.03.00 2019-01-25 visci ESCAN00098904 Improved verification sequence
* ESCAN00101065 Alignment for Blank Check is not applied correctly
* ESCAN00101321 Added option to skip download segment check
* 01.03.01 2019-02-06 visci ESCAN00102005 Signature is not taken into account when comparing segments
* 01.04.00 2019-06-14 visci ESCAN00102956 Internal checksum option fails if validation structure is not the
* last segment
* ESCAN00102957 Potential buffer overflow during internal checksum calculation
* 01.05.00 2019-06-25 visdlm ESCAN00103492 Added gap fill mechanism
* 01.05.01 2021-01-18 visjdn ESCAN00107640 Memory read error leads always to invalid format error
* 01.05.02 2021-06-01 vishor ESCAN00109198 The verification key will not be cleared from memory (RAM) after usage
* 01.06.00 2022-04-28 visstn FBL-4366 Perform MISRA 2012 migration
* 01.07.00 2022-10-12 visjdn FBL-5694 Support of Xiaomi validation structure
* 01.08.00 2022-11-25 vistbe FBL-6055 Extend configurability of checksum and signature
* 01.08.01 2023-02-02 vistbe ESCAN00113401 No changes
**********************************************************************************************************************/
#define FBL_VALSTRUCT_SOURCE
/***********************************************************************************************************************
* INCLUDES
**********************************************************************************************************************/
#include "fbl_inc.h"
#include "fbl_valstruct.h"
/***********************************************************************************************************************
* VERSION
**********************************************************************************************************************/
#if ( FBLVALSTRUCT_VERSION != 0x0108u ) || \
( FBLVALSTRUCT_RELEASE_VERSION != 0x01u )
# error "Error in fbl_valstruct.c: Source and header file are inconsistent!"
#endif
#if ( FBLVALSTRUCT_VERSION != _FBLVALSTRUCT_VERSION ) || \
( FBLVALSTRUCT_RELEASE_VERSION != _FBLVALSTRUCT_RELEASE_VERSION )
# error "Error in fbl_valstruct.c: Source and v_ver.h are inconsistent!"
#endif
/***********************************************************************************************************************
* DEFINES
**********************************************************************************************************************/
#if defined( FBL_ENABLE_VALSTRUCT )
/*** Validation structure defines ***/
# define FBL_VALSTRUCT_PROLOG_SIZE (FBL_VALSTRUCT_TAG_SIZE + FBL_VALSTRUCT_VERSION_SIZE + FBL_VALSTRUCT_BLOCKCOUNT_SIZE + FBL_VALSTRUCT_ALFI_SIZE)
# define FBL_VALSTRUCT_BLOCKINFO_SIZE (FBL_VALSTRUCT_BLOCKADDRESS_SIZE + FBL_VALSTRUCT_BLOCKLENGTH_SIZE + FBL_VALSTRUCT_BLOCKCHECKSUM_SIZE)
# define FBL_VALSTRUCT_EPILOG_SIZE (FBL_VALSTRUCT_TAG_SIZE + FBL_VALSTRUCT_VALIDATESUM_SIZE)
# define FBL_VALSTRUCT_MAX_SIZE (FBL_VALSTRUCT_PROLOG_SIZE + (FBL_VALSTRUCT_BLOCKCOUNT_MAX * FBL_VALSTRUCT_BLOCKINFO_SIZE) + FBL_VALSTRUCT_EPILOG_SIZE)
/* Offset values for validation struct members */
# define FBL_VALSTRUCT_TAGBEGIN_OFFSET (0x00u)
# define FBL_VALSTRUCT_VERSION_OFFSET (FBL_VALSTRUCT_TAGBEGIN_OFFSET + FBL_VALSTRUCT_TAG_SIZE)
# define FBL_VALSTRUCT_BLOCKCOUNT_OFFSET (FBL_VALSTRUCT_VERSION_OFFSET + FBL_VALSTRUCT_VERSION_SIZE)
# define FBL_VALSTRUCT_ALFI_OFFSET (FBL_VALSTRUCT_BLOCKCOUNT_OFFSET + FBL_VALSTRUCT_BLOCKCOUNT_SIZE)
# define FBL_VALSTRUCT_BLOCKADDRESS_OFFSET(index) (FBL_VALSTRUCT_ALFI_OFFSET + FBL_VALSTRUCT_ALFI_SIZE + ((index) * FBL_VALSTRUCT_BLOCKINFO_SIZE))
# define FBL_VALSTRUCT_BLOCKLENGTH_OFFSET(index) (FBL_VALSTRUCT_BLOCKADDRESS_OFFSET(index) + FBL_VALSTRUCT_BLOCKADDRESS_SIZE)
# define FBL_VALSTRUCT_BLOCKCHECKSUM_OFFSET(index) (FBL_VALSTRUCT_BLOCKLENGTH_OFFSET(index) + FBL_VALSTRUCT_BLOCKLENGTH_SIZE)
# define FBL_VALSTRUCT_TAGEND_OFFSET(blockcount) (FBL_VALSTRUCT_BLOCKADDRESS_OFFSET(0u) + ((blockcount) * FBL_VALSTRUCT_BLOCKINFO_SIZE))
# define FBL_VALSTRUCT_VALIDATESUM_OFFSET(blockcount) (FBL_VALSTRUCT_TAGEND_OFFSET(blockcount) + FBL_VALSTRUCT_TAG_SIZE)
/* Access macros to extract validation struct information from a RAM buffer */
/* Note: this macro requires that the validation structure is built in big-endian mode! */
# define FblValStructGetUint32(buffer) FblMemGetInteger(sizeof(vuint32), (buffer))
# define FblValStructGetUint16(buffer) ((vuint16)(FblMemGetInteger(sizeof(vuint16), (buffer)) & 0xFFFFu))
# define FblValStructGetUint8(buffer) ((vuint8)(FblMemGetInteger(sizeof(vuint8), (buffer)) & 0xFFu))
# define FblValStructGetTagBegin(buffer) FblValStructGetUint32(&(buffer)[FBL_VALSTRUCT_TAGBEGIN_OFFSET])
# define FblValStructGetVersion(buffer) FblValStructGetUint16(&(buffer)[FBL_VALSTRUCT_VERSION_OFFSET])
# if (FBL_VALSTRUCT_BLOCKCOUNT_SIZE == 1u)
# define FblValStructGetBlockCount(buffer) FblValStructGetUint8(&(buffer)[FBL_VALSTRUCT_BLOCKCOUNT_OFFSET])
# elif (FBL_VALSTRUCT_BLOCKCOUNT_SIZE == 2u)
# define FblValStructGetBlockCount(buffer) FblValStructGetUint16(&(buffer)[FBL_VALSTRUCT_BLOCKCOUNT_OFFSET])
# endif
# if (FBL_VALSTRUCT_ALFI_SIZE == 1u)
# define FblValStructGetAlfi(buffer) FblValStructGetUint8(&(buffer)[FBL_VALSTRUCT_ALFI_OFFSET])
# endif
# define FblValStructGetBlockAddress(buffer, index) FblValStructGetUint32(&(buffer)[FBL_VALSTRUCT_BLOCKADDRESS_OFFSET(index)])
# define FblValStructGetBlockLength(buffer, index) FblValStructGetUint32(&(buffer)[FBL_VALSTRUCT_BLOCKLENGTH_OFFSET(index)])
# define FblValStructGetBlockChecksum(buffer, index, cs) (void)MEMCPY(cs, &(buffer)[FBL_VALSTRUCT_BLOCKCHECKSUM_OFFSET(index)], FBL_VALSTRUCT_BLOCKCHECKSUM_SIZE)
# define FblValStructGetTagEnd(buffer, blockcount) FblValStructGetUint32(&(buffer)[FBL_VALSTRUCT_TAGEND_OFFSET(blockcount)])
# define FblValStructGetValidateSum(buffer, blockcount) FblValStructGetUint16(&(buffer)[FBL_VALSTRUCT_VALIDATESUM_OFFSET(blockcount)])
/* Calculate the actual size of the validation structure based on the given block count */
# define FblValStructGetTotalSize(blockcount) (FBL_VALSTRUCT_PROLOG_SIZE + ((blockcount) * FBL_VALSTRUCT_BLOCKINFO_SIZE) + FBL_VALSTRUCT_EPILOG_SIZE)
/* Macros used to retrieve the requested ValStruct processing options */
# define FblValStructOptionChecksumInternal(opt) (((opt) & FBL_VALSTRUCT_OPTION_CHECKSUM_INTERNAL) == FBL_VALSTRUCT_OPTION_CHECKSUM_INTERNAL)
# define FblValStructOptionBlankCheck(opt) (((opt) & FBL_VALSTRUCT_OPTION_BLANKCHECK) == FBL_VALSTRUCT_OPTION_BLANKCHECK)
# define FblValStructOptionGapFill(opt) (((opt) & FBL_VALSTRUCT_OPTION_GAP_FILL) == FBL_VALSTRUCT_OPTION_GAP_FILL)
/* Configuration specific definition of output buffer size for verification */
# if defined( SEC_ENABLE_SECURITY_CLASS_DDD )
# if defined( SEC_ENABLE_CRC_WRITTEN_CLASS_DDD )
# define FBL_VALSTRUCT_VERIFY_SIZE (FBL_VALSTRUCT_BLOCKCHECKSUM_SIZE + SEC_SIZE_CHECKSUM_CRC)
# else
# define FBL_VALSTRUCT_VERIFY_SIZE (FBL_VALSTRUCT_BLOCKCHECKSUM_SIZE)
# endif
# endif
# if !defined( FBL_VALSTRUCT_GAP_FILL_SEGMENTATION )
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
# define FBL_VALSTRUCT_GAP_FILL_SEGMENTATION FBL_MAX_SEGMENT_SIZE
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
# endif
/* If signature support is not explictily enabled or disabled set it based on the security class */
# if !defined( FBL_VALSTRUCT_ENABLE_SIGNATURE ) && !defined( FBL_VALSTRUCT_DISABLE_SIGNATURE )
# if (SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC)
# define FBL_VALSTRUCT_ENABLE_SIGNATURE
# endif /* SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC */
# endif /* !FBL_VALSTRUCT_ENABLE_SIGNATURE */
# if defined( FBL_VALSTRUCT_ENABLE_SIGNATURE ) && defined( FBL_VALSTRUCT_ENABLE_EXTERNAL_KEY )
# if !defined( FblValStructClrPublicKey )
# define FblValStructClrPublicKey(x)
# endif /* FblValStructClrPublicKey */
# endif /* SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC */
#endif /* FBL_ENABLE_VALSTRUCT */
/* Evaluate size of common buffer which is used for memory read/write operations. */
#if !defined( FBL_VALSTRUCT_READ_BUFFER_SIZE )
# if defined( FBL_ENABLE_VALSTRUCT )
# if ((defined(FBL_VALSTRUCT_ENABLE_SIGNATURE)) && (FBL_VALSTRUCT_SIGNATURE_SIZE > FBL_VALSTRUCT_MAX_SIZE))
/* Set buffer size to signature size */
# define FBL_VALSTRUCT_READ_BUFFER_SIZE FBL_VALSTRUCT_SIGNATURE_SIZE
# else
/* Set buffer size to maximum possible size of validation structure */
# define FBL_VALSTRUCT_READ_BUFFER_SIZE FBL_VALSTRUCT_MAX_SIZE
# endif
# endif /* FBL_ENABLE_VALSTRUCT */
#endif
/***********************************************************************************************************************
* TYPEDEFS
**********************************************************************************************************************/
#if defined( FBL_ENABLE_VALSTRUCT )
typedef struct
{
vuintx alignDummy;
vuint8 data[FBL_VALSTRUCT_READ_BUFFER_SIZE];
} tAlignedReadBuffer;
/** Structure which keeps segment information */
typedef tDiagSegmentList tVsSegInfo;
/** Structure which keeps information about/from the validation structure */
typedef struct
{
tFblAddress address; /**< Start address of validation structure */
tFblLength length; /**< Total length of validation structure */
tVsSegInfo segInfo; /**< Segment information contained in validation structure */
vuint8 vsSeg; /**< Index of segment which keeps the validation structure */
} tVsInfo;
#endif /* FBL_ENABLE_VALSTRUCT */
/***********************************************************************************************************************
* LOCAL DATA
**********************************************************************************************************************/
#if defined( FBL_ENABLE_VALSTRUCT )
# define FBL_VALSTRUCT_START_SEC_VAR
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
V_MEMRAM0 static V_MEMRAM1 tAlignedReadBuffer V_MEMRAM2 readBuffer; /* PRQA S 3218 */ /* MD_FblValStruct_3218 */
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 gapFillBuffer[FBL_VALSTRUCT_GAP_FILL_SEGMENTATION];
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
# define FBL_VALSTRUCT_STOP_SEC_VAR
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
#endif /* FBL_ENABLE_VALSTRUCT */
/***********************************************************************************************************************
* PROTOTYPES
**********************************************************************************************************************/
#if defined( FBL_ENABLE_VALSTRUCT )
# define FBL_VALSTRUCT_START_SEC_CODE
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
# if ( FBL_VALSTRUCT_VALIDATESUM_SIZE > 0u )
static vuint16 FblValStructCalculateByteChecksum( const vuint8* address, tFblLength size );
# endif
static tFblValStructResult FblValStructGetSegmentInfo( tVsInfo * vsInfo );
static void FblValStructRemoveStructSegment( const tVsInfo * vsInfo, tDiagSegmentList * blockSegInfo );
# if defined ( FBL_VALSTRUCT_ENABLE_SIGNATURE )
static tFblValStructResult FblValStructVerification( const tVsInfo * vsInfo,
SecM_ByteType * verifyData );
# endif /* FBL_VALSTRUCT_ENABLE_SIGNATURE */
# if defined( FBL_VALSTRUCT_ENABLE_CHECKSUM_INTERNAL )
static void FblValStructLocateStructSegment( tVsInfo * vsInfo );
static tFblValStructResult FblValStructChecksumInternal( tVsInfo * vsInfo,
tDiagSegmentList * blockSegInfo );
# endif
static tFblValStructResult FblValStructChecksumExternal( const tBlockDescriptor * blockDescriptor,
tVsInfo * vsInfo,
tDiagSegmentList * blockSegInfo);
static tFblValStructResult FblValStructCompareSegmentLocation( tVsInfo * vsInfo,
const tDiagSegmentList * blockSegInfo);
static tFblValStructResult FblValStructCompareSegmentChecksum( const tVsSegInfo * vsSegInfo,
const tDiagSegmentList * blockSegInfo );
# if defined( FBL_VALSTRUCT_ENABLE_BLANK_CHECK )
static tFblValStructResult FblValStructBlankCheck( tFblAddress memAddress, tFblLength memLength );
# endif /* FBL_VALSTRUCT_ENABLE_BLANK_CHECK */
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
static tFblValStructResult FblValStructGapFill( tFblAddress memAddress, tFblLength memLength );
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
# if defined( FBL_VALSTRUCT_ENABLE_BLANK_CHECK ) || \
defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
static tFblAddress FblValStructSkipFilledArea( tFblAddress address, vsint16 memSeg );
static tFblValStructResult FblValStructGapProcessing( const tBlockDescriptor * blockDescriptor,
const tDiagSegmentList * blockSegInfo );
# endif
# define FBL_VALSTRUCT_STOP_SEC_CODE
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
#endif /* FBL_ENABLE_VALSTRUCT */
/***********************************************************************************************************************
* LOCAL FUNCTIONS
**********************************************************************************************************************/
#if defined( FBL_ENABLE_VALSTRUCT )
# define FBL_VALSTRUCT_START_SEC_CODE
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
# if ( FBL_VALSTRUCT_VALIDATESUM_SIZE > 0u )
/***********************************************************************************************************************
* FblValStructCalculateByteChecksum
**********************************************************************************************************************/
/*! \brief Calculate a 16-bit sized byte checksum over the buffer content.
* \param[in] address Pointer to data buffer in RAM
* \param[in] size Size of data in buffer
* \return Calculated checksum value
**********************************************************************************************************************/
static vuint16 FblValStructCalculateByteChecksum( const vuint8 * address, tFblLength size )
{
const vuint8 * bytePtr = address;
vuint16 byteChecksum = 0u;
while (bytePtr < (&address[size]))
{
byteChecksum += *bytePtr;
bytePtr = &bytePtr[1u];
/* Keep up bootloader timing and watchdog service */
if (((tFblAddress)bytePtr & 0xFu) == 0u) /* PRQA S 0306 */ /* MD_FblValStruct_0306 */
{
/* Call service function every 16th loop cycle */
(void)FblLookForWatchdog();
}
}
return byteChecksum;
}
# endif /* FBL_VALSTRUCT_VALIDATESUM_SIZE > 0u */
/***********************************************************************************************************************
* FblValStructGetSegmentInfo
**********************************************************************************************************************/
/*! \brief Check presence and integrity of the validation structure and extract the segment information.
* \param[in,out] vsInfo Start address (in) and length (out) of validation structure, segment information (out)
* \return kFblValStructOk = validation structure has been read successfully
* other value = reading of validation structure failed
**********************************************************************************************************************/
/* PRQA S 6010, 6030 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC */
static tFblValStructResult FblValStructGetSegmentInfo( tVsInfo * vsInfo )
{
tFblValStructResult result;
tFblLength vsTotalSize;
vuint16 segIndex, vsSegCount;
# if ( FBL_VALSTRUCT_VALIDATESUM_SIZE > 0u )
vuint16 validateSum;
# endif
/* Initialize return value */
result = kFblValStructOk;
/* Initialize total size */
vsTotalSize = 0u;
/* Read begin tag, version and block count of validation structure */
if (FblReadProm(vsInfo->address, readBuffer.data, FBL_VALSTRUCT_PROLOG_SIZE) != FBL_VALSTRUCT_PROLOG_SIZE)
{
/* Memory read error (e.g. invalid memory region) */
result = kFblValStructMemoryReadError;
}
# if ( FBL_VALSTRUCT_TAG_SIZE > 0u )
if (kFblValStructOk == result)
{
/* Check begin tag */
if (FblValStructGetTagBegin(readBuffer.data) != FBL_VALSTRUCT_TAGBEGIN_PATTERN)
{
/* Begin tag invalid */
result = kFblValStructInvalidFormat;
}
}
# endif
# if ( FBL_VALSTRUCT_VERSION_SIZE > 0u )
if (kFblValStructOk == result)
{
/* Check if structure version is supported */
if (FblValStructIsVersionSupported(FblValStructGetVersion(readBuffer.data)) != kFblValStructOk)
{
/* Begin tag invalid */
result = kFblValStructInvalidFormat;
}
}
# endif
if (kFblValStructOk == result)
{
/* Check block count */
vsSegCount = FblValStructGetBlockCount(readBuffer.data);
if (vsSegCount <= FBL_VALSTRUCT_BLOCKCOUNT_MAX)
{
vsInfo->segInfo.nrOfSegments = (vuint8)vsSegCount;
}
else
{
/* Maximum block count exceeded */
result = kFblValStructInvalidFormat;
}
}
# if (FBL_VALSTRUCT_ALFI_SIZE == 1u)
if (kFblValStructOk == result)
{
/* Check ALFI */
if (FblValStructGetAlfi(readBuffer.data) != (FBL_VALSTRUCT_BLOCKADDRESS_SIZE + (FBL_VALSTRUCT_BLOCKLENGTH_SIZE << 4u)))
{
/* ALFI is invalid */
result = kFblValStructInvalidFormat;
}
}
# endif
if (kFblValStructOk == result)
{
/* Calculate total validation struct size */
vsTotalSize = FblValStructGetTotalSize((vuint32) vsInfo->segInfo.nrOfSegments); /* PRQA S 2985 */ /* MD_FblValStruct_2985 */
/* Block count value OK, read the rest of the validation structure */
if (FblReadProm((vsInfo->address + FBL_VALSTRUCT_PROLOG_SIZE),
&(readBuffer.data[FBL_VALSTRUCT_PROLOG_SIZE]),
(vsTotalSize - FBL_VALSTRUCT_PROLOG_SIZE)) != (vsTotalSize - FBL_VALSTRUCT_PROLOG_SIZE))
{
/* Memory read error (e.g. invalid memory region) */
result = kFblValStructMemoryReadError;
}
}
# if ( FBL_VALSTRUCT_TAG_SIZE > 0u )
if (kFblValStructOk == result)
{
/* Check end tag */
if (FblValStructGetTagEnd(readBuffer.data, vsInfo->segInfo.nrOfSegments) != FBL_VALSTRUCT_TAGEND_PATTERN)
{
/* End tag invalid */
result = kFblValStructInvalidFormat;
}
}
# endif
# if ( FBL_VALSTRUCT_VALIDATESUM_SIZE > 0u )
if (kFblValStructOk == result)
{
/* Check integrity of validation structure (verify byte checksum) */
validateSum = FblValStructCalculateByteChecksum(readBuffer.data, (vsTotalSize - FBL_VALSTRUCT_VALIDATESUM_SIZE));
if (validateSum != FblValStructGetValidateSum(readBuffer.data, vsInfo->segInfo.nrOfSegments))
{
/* Validation information corrupt */
result = kFblValStructInvalidFormat;
}
}
# endif
if (kFblValStructOk == result)
{
/* Extract block information. This separate step ensures correct data */
/* interpretation regardless of endianess and structure alignment. */
for (segIndex = 0; segIndex < vsInfo->segInfo.nrOfSegments; segIndex++)
{
vsInfo->segInfo.segmentInfo[segIndex].targetAddress = FblValStructGetBlockAddress(readBuffer.data, segIndex);
vsInfo->segInfo.segmentInfo[segIndex].length = FblValStructGetBlockLength(readBuffer.data, segIndex);
/* PRQA S 0314 1 */ /* MD_FblValStruct_0314 */
FblValStructGetBlockChecksum(readBuffer.data, segIndex, vsInfo->segInfo.segmentInfo[segIndex].checksum);
}
}
/* Return total length of structure */
vsInfo->length = vsTotalSize;
return result;
}
/***********************************************************************************************************************
* FblValStructRemoveStructSegment
**********************************************************************************************************************/
/*! \brief Determine download segment which keeps the validation structure and remove it from the list
* \pre vsInfo->vsSeg has to be set before (validation structure segment)
* \param[in] vsInfo Structure which keeps information about validation structure (out: vsSeg)
* \param[in,out] blockSegInfo Output segment list which contains the newly calculated checksum values
* \return kFblValStructOk = validation structure identified and removed
* other value = validation structure not found
**********************************************************************************************************************/
static void FblValStructRemoveStructSegment( const tVsInfo * vsInfo, tDiagSegmentList * blockSegInfo )
{
vuint8 segIdx;
/* Remove ValStruct segment from list */
for (segIdx = vsInfo->vsSeg + 1u; segIdx < blockSegInfo->nrOfSegments; segIdx++)
{
blockSegInfo->segmentInfo[segIdx - 1u] = blockSegInfo->segmentInfo[segIdx];
}
/* Fix number of segments */
blockSegInfo->nrOfSegments--;
}
# if defined( FBL_VALSTRUCT_ENABLE_SIGNATURE )
/***********************************************************************************************************************
* FblValStructVerification
**********************************************************************************************************************/
/*! \brief The flash memory content is verified according to the configured CCC algorithm
* \param[in] vsInfo Structure which keeps information about validation structure
* \param[in] verifyData Input buffer which keeps the signature data for comparison with the calculated value
* \return kFblValStructOk = Authentication succeeded
* other value = Authentication failed (or memory access error)
**********************************************************************************************************************/
static tFblValStructResult FblValStructVerification( const tVsInfo * vsInfo, SecM_ByteType * verifyData )
{
# if defined( FBL_VALSTRUCT_ENABLE_EXTERNAL_KEY )
SecM_AsymKeyType publicKey;
# endif
SecM_VerifyParamType verifyParam;
FL_SegmentInfoType verifySegmentInfo[1u];
SecM_StatusType secStatus;
tFblValStructResult result;
result = kFblValStructOk;
/* Configure segment which shall be verified */
verifySegmentInfo[0u].targetAddress = vsInfo->address;
verifySegmentInfo[0u].transferredAddress = verifySegmentInfo[0u].targetAddress;
verifySegmentInfo[0u].length = vsInfo->length;
verifyParam.segmentList.segmentInfo = verifySegmentInfo;
verifyParam.segmentList.nrOfSegments = 1u;
verifyParam.blockStartAddress = verifySegmentInfo[0u].targetAddress;
verifyParam.blockLength = verifySegmentInfo[0u].length;
verifyParam.verificationData = verifyData;
verifyParam.wdTriggerFct = (FL_WDTriggerFctType)FblRealTimeSupport; /* PRQA S 0313 */ /* MD_FblValStruct_0313_WDTriggerFctType */
verifyParam.readMemory = (FL_ReadMemoryFctType)FblReadProm;
# if defined( FBL_VALSTRUCT_ENABLE_EXTERNAL_KEY )
publicKey.shared.size = sizeof(SecM_RsaMod);
publicKey.individual.size = sizeof(SecM_RsaExp);
if (kFblOk == FblValStructGetPublicKey(&publicKey))
{
verifyParam.key = &publicKey; /* PRQA S 0315 */ /* MD_FblValStruct_0315 */
}
else
{
/* An error occured and the key was not able to be retrieved */
result = kFblValStructKeyError;
}
# else
/* Use the internal key */
verifyParam.key = SEC_VERIFY_KEY_NULL;
# endif /* FBL_VALSTRUCT_ENABLE_EXTERNAL_KEY */
if (kFblValStructOk == result) /* PRQA S 2991, 2995 */ /* MD_FblValStruct_2991_2995 */
{
/* Perform hash calculation and compare with decrypted signature */
secStatus = FblValStructSignatureVerification(&verifyParam);
if (SECM_VER_OK != secStatus)
{
/* An error occurred during signature verification or the signature check failed */
result = kFblValStructNotAuthentic;
}
}
# if defined( FBL_VALSTRUCT_ENABLE_EXTERNAL_KEY )
FblValStructClrPublicKey(&publicKey);
# endif /* FBL_VALSTRUCT_ENABLE_EXTERNAL_KEY */
return result;
}
# endif /* FBL_VALSTRUCT_ENABLE_SIGNATURE */
# if defined( FBL_VALSTRUCT_ENABLE_CHECKSUM_INTERNAL )
/***********************************************************************************************************************
* FblValStructLocateStructSegment
**********************************************************************************************************************/
/*! \brief Locate the position of the validation structure in the segment list of the validation structure
* \param[in,out] vsInfo Structure which keeps information about validation structure (out: vsSeg)
**********************************************************************************************************************/
static void FblValStructLocateStructSegment( tVsInfo * vsInfo )
{
vuint8 segIdx;
vuint8 vsFound;
/* Locate validation structure segment in segment list */
segIdx = vsInfo->segInfo.nrOfSegments;
vsFound = 0u;
while (segIdx > 0u)
{
segIdx--;
if (vsInfo->address > vsInfo->segInfo.segmentInfo[segIdx].targetAddress)
{
/* Validation structure located above the current segment */
vsInfo->vsSeg = segIdx + 1u;
vsFound = 1u;
break;
}
}
if (vsFound == 0u)
{
/* Validation structure must be located in front of the first entry */
vsInfo->vsSeg = 0u;
}
}
/***********************************************************************************************************************
* FblValStructChecksumInternal
**********************************************************************************************************************/
/*! \brief Calculate the checksum (or CRC/hash) values for all segments in the validation structure
* \param[in,out] vsInfo Structure which keeps information about validation structure (out: vsSeg)
* \param[in,out] blockSegInfo Output segment list which contains the newly calculated checksum values
* \return kFblValStructOk = Checksum calculation successfully finished, information in blockSegInfo is valid
* other value = Error during checksum calculation, information in blockSegInfo is not valid
**********************************************************************************************************************/
static tFblValStructResult FblValStructChecksumInternal( tVsInfo * vsInfo, tDiagSegmentList * blockSegInfo )
{
static SecM_ByteType verifyOutputBuf[FBL_VALSTRUCT_VERIFY_SIZE];
tFblValStructResult result;
SecM_VerifyParamType localVerifyParam;
FL_SegmentInfoType verifySegmentInfo[1];
vuint8 segIdx;
vuint8 vsInserted;
result = kFblValStructOk;
/* Locate validation structure segment (required for blank check!) */
FblValStructLocateStructSegment(vsInfo);
/* Add one segment for validation structure */
blockSegInfo->nrOfSegments = vsInfo->segInfo.nrOfSegments + 1u;
/* Iterate over all segments which are defined in the validation structure */
vsInserted = 0u;
for (segIdx = 0u; segIdx < blockSegInfo->nrOfSegments; segIdx++)
{
if (segIdx == vsInfo->vsSeg)
{
/* Insert validation structure */
blockSegInfo->segmentInfo[segIdx].targetAddress = vsInfo->address;
blockSegInfo->segmentInfo[segIdx].length = vsInfo->length;
vsInserted = 1u;
}
else
{
/* Copy address/length information */
blockSegInfo->segmentInfo[segIdx].targetAddress = vsInfo->segInfo.segmentInfo[segIdx - vsInserted].targetAddress;
blockSegInfo->segmentInfo[segIdx].length = vsInfo->segInfo.segmentInfo[segIdx - vsInserted].length;
}
/* Prepare input data for checksum calculation */
verifySegmentInfo[0].length = blockSegInfo->segmentInfo[segIdx].length;
verifySegmentInfo[0].targetAddress = blockSegInfo->segmentInfo[segIdx].targetAddress;
verifySegmentInfo[0].transferredAddress = blockSegInfo->segmentInfo[segIdx].targetAddress;
localVerifyParam.segmentList.nrOfSegments = 1u;
localVerifyParam.segmentList.segmentInfo = verifySegmentInfo;
localVerifyParam.verificationData = verifyOutputBuf;
localVerifyParam.crcTotal = 0u;
localVerifyParam.wdTriggerFct = (FL_WDTriggerFctType)FblRealTimeSupport; /* PRQA S 0313 */ /* MD_FblValStruct_0313_WDTriggerFctType */
localVerifyParam.readMemory = (FL_ReadMemoryFctType)FblReadProm;
/* Do checksum verification */
if (FblValStructChecksumVerification(&localVerifyParam) == SECM_VER_OK)
{
/* Copy checksum into segment list */
(void)MEMCPY(blockSegInfo->segmentInfo[segIdx].checksum, /* PRQA S 0314 */ /* MD_FblValStruct_0314 */
&verifyOutputBuf[FBL_VALSTRUCT_BLOCKCHECKSUM_VERIFY_OFFSET],
FBL_VALSTRUCT_BLOCKCHECKSUM_SIZE);
}
else
{
result = kFblValStructMemoryReadError;
break;
}
}
return result;
}
# endif /* FBL_VALSTRUCT_ENABLE_CHECKSUM_INTERNAL */
/***********************************************************************************************************************
* FblValStructChecksumExternal
**********************************************************************************************************************/
/*! \brief Request segment information from external instance and check against validation structure
* \param[in] blockDescriptor Block descriptor structure
* \param[in,out] vsInfo Structure which keeps information about validation structure
* \param[in,out] blockSegInfo Download segment list
* \return kFblValStructOk = Passed segment information matches the information in the validation structure
* other value = Invalid number of segments passed or segment locations don't match
**********************************************************************************************************************/
/* PRQA S 3673 3 */ /* MD_MSR_Rule8.13 */
static tFblValStructResult FblValStructChecksumExternal( const tBlockDescriptor * blockDescriptor,
tVsInfo * vsInfo,
tDiagSegmentList * blockSegInfo )
{
tFblValStructResult result;
# if defined( V_ENABLE_USE_DUMMY_STATEMENT )
/* Parameter not used (configuration dependent): avoid compiler warning */
(void)blockDescriptor; /* PRQA S 3112 */ /* MD_MSR_DummyStmt */
# endif /* V_ENABLE_USE_DUMMY_STATEMENT */
/* Get download segments which are associated with this logical block */
(void)FblValStructGetSegmentList(blockDescriptor->blockNr, blockSegInfo);
/* Check the amount of segments which have been downloaded */
if (blockSegInfo->nrOfSegments == (vsInfo->segInfo.nrOfSegments + 1u))
{
/* Number of downloaded segments (excluding the ValStruct segment) matches the number in the ValStruct */
result = FblValStructCompareSegmentLocation(vsInfo, blockSegInfo);
}
else
{
/* Mismatch between number of downloaded segments and blocks in validation structure; abort verification */
result = kFblValStructBlockNumberMismatch;
}
return result;
}
/***********************************************************************************************************************
* FblValStructCompareSegmentLocation
**********************************************************************************************************************/
/*! \brief Compare the segment information from download and validation structure, remove ValStruct from list
* \param[in,out] vsInfo Structure which keeps information about validation structure (out: vsSeg)
* \param[in] blockSegInfo Download segment list
* \return kFblValStructOk = all segments are identical
* other value = address or length differences detected
**********************************************************************************************************************/
static tFblValStructResult FblValStructCompareSegmentLocation( tVsInfo * vsInfo,
const tDiagSegmentList * blockSegInfo)
{
tFblValStructResult result;
vuint8 segIdx, vsFound;
result = kFblValStructOk;
vsInfo->vsSeg = 0u;
vsFound = 0u;
for (segIdx = 0u; segIdx < blockSegInfo->nrOfSegments; segIdx++)
{
/* Check address and length against block info in validation structure */
if ((blockSegInfo->segmentInfo[segIdx].targetAddress != vsInfo->segInfo.segmentInfo[segIdx - vsFound].targetAddress) ||
(blockSegInfo->segmentInfo[segIdx].length != vsInfo->segInfo.segmentInfo[segIdx - vsFound].length))
{
/* Check if the mismatch is caused by the segment which keeps the validation structure */
if ((vsFound == 0u) && (blockSegInfo->segmentInfo[segIdx].targetAddress == vsInfo->address))
{
if (blockSegInfo->segmentInfo[segIdx].length == vsInfo->length)
{
/* Validation structure segment found */
vsInfo->vsSeg = segIdx;
vsFound = 1u;
}
else
{
/* Invalid length of validation structure */
result = kFblValStructInvalidFormat;
}
}
else
{
/* Address/or length mismatch between download and validation structure */
result = kFblValStructBlockMismatch;
}
}
if (result != kFblValStructOk)
{
break;
}
}
return result;
}
/***********************************************************************************************************************
* FblValStructCompareSegmentChecksum
**********************************************************************************************************************/
/*! \brief Compare the segment information from download and validation structure
* \param[in] vsSegInfo Segment list from validation structure
* \param[in] blockSegInfo Download segment list
* \return kFblValStructOk = all segments are identical
* other value = checksum differences detected
**********************************************************************************************************************/
static tFblValStructResult FblValStructCompareSegmentChecksum( const tVsSegInfo * vsSegInfo, const tDiagSegmentList * blockSegInfo )
{
tFblValStructResult result;
vuint8 segIdx, csIdx;
result = kFblValStructOk;
for (segIdx = 0; segIdx < vsSegInfo->nrOfSegments; segIdx++)
{
/* Compare calculated checksum/hash with value from validation structure */
for (csIdx = 0; csIdx < FBL_VALSTRUCT_BLOCKCHECKSUM_SIZE; csIdx++)
{
if (vsSegInfo->segmentInfo[segIdx].checksum[csIdx] != blockSegInfo->segmentInfo[segIdx].checksum[csIdx])
{
/* Checksum values differ, abort verification */
result = kFblValStructChecksumValueMismatch;
break;
}
}
}
return result;
}
# if defined( FBL_VALSTRUCT_ENABLE_BLANK_CHECK )
/***********************************************************************************************************************
* FblValStructBlankCheck
**********************************************************************************************************************/
/*! \brief Check whether the given memory area is erased (contains the respective erased value)
* \param[in] memAddress Start address of the memory area
* \param[in] memLength Length of the memory area
* \return kFblValStructOk = inter-segment memory areas are in state 'erased'
* kFblValStructBlankCheckFailed = non-erased memory area detected
**********************************************************************************************************************/
/* PRQA S 6080 1 */ /* MD_MSR_STMIF */
static tFblValStructResult FblValStructBlankCheck( tFblAddress memAddress, tFblLength memLength )
{
tFblValStructResult result;
tFblLength readLength;
IO_ErrorType memDrvResult;
vuint16 bufIdx;
vuint8 erasedVal;
tFblAddress localMemAddress = memAddress;
tFblLength localMemLength = memLength;
/* Note: By definition, a logical block must be homogeneous (single memory device) and contiguous (no gaps) */
memSegment = FblMemSegmentNrGet(localMemAddress);
if (memSegment >= 0)
{
result = kFblValStructOk;
erasedVal = memDrvLst[FlashBlock[memSegment].device].erasedValue;
while ((localMemLength > 0u) && (kFblValStructOk == result))
{
readLength = (localMemLength >= FBL_VALSTRUCT_READ_BUFFER_SIZE) ? FBL_VALSTRUCT_READ_BUFFER_SIZE : localMemLength;
memDrvResult = MemDriver_RReadSync(readBuffer.data, readLength, localMemAddress);
if ((IO_E_OK == memDrvResult) || (IO_E_ERASED == memDrvResult))
{
for (bufIdx = 0u; bufIdx < readLength; bufIdx++)
{
/* Check if the pattern is in its initial state (i. e. the memory at the
pattern address is erased) */
if (readBuffer.data[bufIdx] != (vuint8)erasedVal)
{
/* Memory content has been modified - return with negative result */
result = kFblValStructBlankCheckFailed;
break;
}
}
localMemAddress += readLength;
localMemLength -= readLength;
}
else
{
/* Failure reported by read function */
result = kFblValStructBlankCheckFailed;
}
}
}
else
{
/* Invalid memory segment */
result = kFblValStructBlankCheckFailed;
}
return result;
}
# endif /* FBL_VALSTRUCT_ENABLE_BLANK_CHECK */
# if defined ( FBL_VALSTRUCT_ENABLE_GAP_FILL )
/***********************************************************************************************************************
* FblValStructGapFill
**********************************************************************************************************************/
/*! \brief Fill gaps between programmed segments with kFillChar
* \param[in] memAddress Start address of the memory area
* \param[in] memLength Length of the memory area
* \return kFblValStructOk = inter-segment memory areas are filled successfully
* kFblValStructGapFillFailed = gap filling failed
**********************************************************************************************************************/
static tFblValStructResult FblValStructGapFill(tFblAddress memAddress, tFblLength memLength)
{
tFblValStructResult result;
tFblLength writeLength;
tFblAddress localMemAddress = memAddress;
tFblLength localMemLength = memLength;
result = kFblValStructOk;
while (localMemLength > 0u)
{
writeLength = (localMemLength >= FBL_VALSTRUCT_GAP_FILL_SEGMENTATION) ? FBL_VALSTRUCT_GAP_FILL_SEGMENTATION : localMemLength;
if (kFblMemStatus_Ok == FblMemProgramBuffer(localMemAddress, &writeLength, gapFillBuffer))
{
localMemAddress += writeLength;
localMemLength -= writeLength;
}
else
{
result = kFblValStructGapFillFailed;
break;
}
}
return result;
}
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
# if defined( FBL_VALSTRUCT_ENABLE_BLANK_CHECK ) || \
defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
/***********************************************************************************************************************
* FblValStructSkipFilledArea
**********************************************************************************************************************/
/*! \brief Skip memory area at segment end which has been filled with kFillChar
* \param[in] address Start address of the memory area
* \param[in] memSeg Index of memory segment in flash block table which relates to the specified address
* \return Aligned address
**********************************************************************************************************************/
static tFblAddress FblValStructSkipFilledArea( tFblAddress address, vsint16 memSeg )
{
vuint16 segSize;
tFblLength unalignedLength;
tFblAddress alignedAddress = address;
/* Retrieve write segment size of the respective memory device */
segSize = memDrvLst[FlashBlock[memSeg].device].segmentSize;
/* ESCAN00101065: Check alignment of read address */
if ((address & (segSize - 1uL)) != 0uL)
{
/* Skip data which has been filled with kFillChar */
unalignedLength = segSize - (address & (segSize - 1uL));
alignedAddress += unalignedLength;
}
return alignedAddress;
}
/***********************************************************************************************************************
* FblValStructGapProcessing
**********************************************************************************************************************/
/*! \brief Depending on the configuration either blank check or gap filling will be executed
* \param[in] blockDescriptor Block descriptor structure
* \param[in] blockSegInfo Download segment list
* \return kFblValStructOk = processing successfully performed
* other value = either blank check or gap filling failed
**********************************************************************************************************************/
static tFblValStructResult FblValStructGapProcessing( const tBlockDescriptor * blockDescriptor,
const tDiagSegmentList * blockSegInfo )
{
tFblValStructResult result;
tFblAddress procAddress;
tFblLength remainingLength;
vuint8 segIdx;
tBlockDescriptor localBlockDescriptor;
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
tFblLength idx;
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
localBlockDescriptor = *blockDescriptor;
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
/* Fill gap fill buffer with fill character */
for (idx = 0u; idx < FBL_VALSTRUCT_GAP_FILL_SEGMENTATION; idx++)
{
gapFillBuffer[idx] = kFillChar;
}
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
/* Adjust the size of the logical block according to presence pattern size */
(void)ApplFblAdjustLbtBlockData(&localBlockDescriptor);
procAddress = localBlockDescriptor.blockStartAddress;
/* Note: By definition, a logical block must be homogeneous (single memory device) and contiguous (no gaps) */
memSegment = FblMemSegmentNrGet(procAddress);
if (memSegment >= 0)
{
result = kFblValStructOk;
for (segIdx = 0; segIdx < blockSegInfo->nrOfSegments; segIdx++)
{
/* Skip memory area at segment end which has been filled with kFillChar */
procAddress = FblValStructSkipFilledArea(procAddress, memSegment);
if (procAddress < blockSegInfo->segmentInfo[segIdx].targetAddress)
{
remainingLength = blockSegInfo->segmentInfo[segIdx].targetAddress - procAddress;
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
result = FblValStructGapFill(procAddress, remainingLength);
# else /* FBL_VALSTRUCT_ENABLE_BLANK_CHECK */
result = FblValStructBlankCheck(procAddress, remainingLength);
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
if (kFblValStructOk != result)
{
break;
}
}
procAddress = blockSegInfo->segmentInfo[segIdx].targetAddress +
blockSegInfo->segmentInfo[segIdx].length;
}
if (kFblValStructOk == result)
{
/* Skip memory area at segment end which has been filled with kFillChar */
procAddress = FblValStructSkipFilledArea(procAddress, memSegment);
/* Check remaining part of logical block */
if (procAddress < (localBlockDescriptor.blockStartAddress + localBlockDescriptor.blockLength))
{
remainingLength = (localBlockDescriptor.blockStartAddress + localBlockDescriptor.blockLength) - procAddress;
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
result = FblValStructGapFill(procAddress, remainingLength);
# else /* FBL_VALSTRUCT_ENABLE_BLANK_CHECK */
result = FblValStructBlankCheck(procAddress, remainingLength);
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
}
}
}
else
{
/* Invalid memory segment */
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
result = kFblValStructGapFillFailed;
# else /* FBL_VALSTRUCT_ENABLE_BLANK_CHECK */
result = kFblValStructBlankCheckFailed;
# endif /* FBL_VALSTRUCT_ENABLE_GAP_FILL */
}
return result;
}
# endif /* FBL_VALSTRUCT_ENABLE_BLANK_CHECK || FBL_VALSTRUCT_ENABLE_GAP_FILL */
/***********************************************************************************************************************
* GLOBAL FUNCTIONS
**********************************************************************************************************************/
/***********************************************************************************************************************
* FblValStructValidateBlockExtended
**********************************************************************************************************************/
/*! \brief The flash memory content is verified according to the information in the validation structure
* \pre Complete file must be successfully downloaded
* \param[in] blockDescriptor Block descriptor structure
* \param[in] option Parameter to influence the execution sequence
* \return kFblValStructOk = verification successfully performed
* other value = verification failed
**********************************************************************************************************************/
/* PRQA S 6050 1 */ /* MD_MSR_STCAL */
tFblValStructResult FblValStructValidateBlockExtended( const tBlockDescriptor * blockDescriptor,
const tFblValStructOption option )
{
static tVsInfo vsInfo;
static tDiagSegmentList blockSegInfo;
tFblValStructResult result;
# if defined( V_ENABLE_USE_DUMMY_STATEMENT )
/* Parameters not used: avoid compiler warning */
(void)option;
# endif
/* Check if requested options can be handled with current pre-compile config */
# if defined( FBL_VALSTRUCT_ENABLE_CHECKSUM_INTERNAL )
# else
assertFblUser(! FblValStructOptionChecksumInternal(option), kFblSysAssertParameterOutOfRange);
# endif
# if defined( FBL_VALSTRUCT_ENABLE_BLANK_CHECK )
# else
assertFblUser(! FblValStructOptionBlankCheck(option), kFblSysAssertParameterOutOfRange);
# endif
# if defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
# else
assertFblUser(! FblValStructOptionGapFill(option), kFblSysAssertParameterOutOfRange);
# endif
vsInfo.address = FblValStructGetVsAddress(blockDescriptor);
/* Extract the block information from the validation structure */
result = FblValStructGetSegmentInfo(&vsInfo);
# if defined( FBL_VALSTRUCT_ENABLE_SIGNATURE )
if (kFblValStructOk == result)
{
/* Read verification data from downloaded logical block */
result = FblValStructGetSignature(blockDescriptor, readBuffer.data); /* PRQA S 0306 */ /* MD_FblValStruct_0306 */
if (kFblValStructOk == result)
{
/* Check integrity and authenticity of validation structure */
result = FblValStructVerification(&vsInfo, readBuffer.data);
}
}
# endif /* FBL_VALSTRUCT_ENABLE_SIGNATURE */
if (kFblValStructOk == result)
{
/* ESCAN00102005: Adapt validation structure dimension to match the respective data segment
* (required if signature is attached to validation structure segment) */
vsInfo.address = FblValStructGetVsSegAddress(blockDescriptor);
vsInfo.length = FblValStructGetVsSegLength(vsInfo.length);
# if defined( FBL_VALSTRUCT_ENABLE_CHECKSUM_INTERNAL )
/* Decide whether the segment checksums shall be calculated internally or requested externally */
if (FblValStructOptionChecksumInternal(option))
{
/* Calculate the checksum of all segments and fill blockSegInfo structure */
result = FblValStructChecksumInternal(&vsInfo, &blockSegInfo);
}
else
# endif /* FBL_VALSTRUCT_ENABLE_CHECKSUM_INTERNAL */
{
/* Request segment information from external instance and check against validation structure */
result = FblValStructChecksumExternal(blockDescriptor, &vsInfo, &blockSegInfo);
}
}
# if defined( FBL_VALSTRUCT_ENABLE_BLANK_CHECK ) || \
defined( FBL_VALSTRUCT_ENABLE_GAP_FILL )
if (kFblValStructOk == result)
{
if ((FblValStructOptionBlankCheck(option)) || (FblValStructOptionGapFill(option)))
{
/* Perform gap processing (blank check or gap fill) */
result = FblValStructGapProcessing(blockDescriptor, &blockSegInfo);
}
}
# endif /* FBL_VALSTRUCT_ENABLE_BLANK_CHECK || FBL_VALSTRUCT_ENABLE_GAP_FILL */
if (kFblValStructOk == result)
{
/* Remove validation structure segment */
FblValStructRemoveStructSegment(&vsInfo, &blockSegInfo);
/* Proceed with checking the checksum/hash of all blocks in the structure */
result = FblValStructCompareSegmentChecksum(&vsInfo.segInfo, &blockSegInfo);
}
return result;
}
/***********************************************************************************************************************
* FblValStructValidateBlock
**********************************************************************************************************************/
/*! \brief The flash memory content is verified according to the information in the validation structure
* \pre Complete file must be successfully downloaded
* \param[in] blockDescriptor Block descriptor structure
* \return kFblValStructOk = verification successfully performed
* other value = verification failed
**********************************************************************************************************************/
tFblValStructResult FblValStructValidateBlock( const tBlockDescriptor * blockDescriptor )
{
return FblValStructValidateBlockExtended(blockDescriptor, FBL_VALSTRUCT_OPTION_DEFAULT);
}
# define FBL_VALSTRUCT_STOP_SEC_CODE
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
#endif /* FBL_ENABLE_VALSTRUCT */
/***********************************************************************************************************************
* MISRA DEVIATIONS
**********************************************************************************************************************/
/* module specific MISRA deviations:
MD_FblValStruct_0306:
Reason: Address conversion between integer values and pointers is required to allow for hardware independent
configuration and address range checks.
Risk: The size of integer required to hold the result of a pointer cast is implementation-defined.
Prevention: The size of the respective integer data type which holds the address value is adapted on a hardware
specific basis.
MD_FblValStruct_0314:
Reason: The copy function have a void pointer as a function parameter and an integer is casted to pointer void.
Risk: No risk, because the underlying pointer type is known and the cast is safe.
Prevention: No prevention necessary.
MD_FblValStruct_0315:
Reason: The underling type of verifyParam.key is pointer to void. As the type is defined outside the package, the
implicit conversion is necessary.
Risk: No identifiable risk.
Prevention: No prevention required.
MD_FblValStruct_0313_WDTriggerFctType:
Reason: Security module expects a watchdog handler with return type 'void'. The usage of a wrapper function is
avoided due to higher voted requirements for minimized stack and runtime usage applied on the code.
Risk: Potentially undefined behavior of the used compiler which usually leads to a warning or error during
compilation.
Prevention: The respective functionality is part of integration testing and will hence be verified before delivery.
MD_FblValStruct_2985:
Reason: Based on the configuration, some constants are zero, which leads to constant control expression.
Risk: No identifiable risk.
Prevention: No prevention required.
MD_FblValStruct_2991_2995:
Reason: The value of the if-controlling expression depends on the configuration.
Risk: No risk.
Prevention: No prevention necessary.
MD_FblValStruct_3218:
Reason: Variable is accessed from multiple functions (configuration dependent).
Risk: Scope is larger than required (whole file instead of one function). Some other function could access
the variable.
Prevention: Restrict the functionality in this module to the intended purpose. Don't add functions which shall not
be able to access the local data buffers.
*/
/***********************************************************************************************************************
* END OF FILE: FBL_VALSTRUCT.C
**********************************************************************************************************************/