Untitled
user_5822903
plain_text
2 months ago
16 kB
5
Indexable
""" /*********************************************************************************/ Copyright © 2025 Volvo Car Corporation. All rights reserved. NOTICE: This file contains material that is confidential and confidential to Volvo Cars and/or other developers. No license is granted under any intellectual or industrial property rights of Volvo Cars except as may be provided in an agreement with Volvo Cars. Any unauthorized copying or distribution of content from this file is prohibited. /*********************************************************************************/ reqprod: 398360 version: 4 title: Format of the Verification Block Table purpose: > Define the format of the verification block table description: > The verification block table, encoded with big endian, shall have the following format: Verification Block Table Format Identifier. The verification block will start with most significant byte of this format identifier. It defines the version of the verification block table, mainly intended for tool parsing and format checks in the ECU, i.e. it shall not be used to configure e.g. the actual algorithm to be used by the bootloader. Size 16 bits. Number of data blocks. This shall be identical to the number of data blocks included in the software part. The data block containing the verification block table itself shall not be included. Size 16 bits. StartAddress [size 32 bits], Length [size 32 bits], Hash value. Every data blocks shall be defined, except the block table itself. The size of the hash is dependent of the hash function used and is specified elsewhere. The Length is the unprocessed length (see other requirements for more details). The data blocks shall be sorted according to the order the data blocks are being programmed to the ECU. Example. SHA-256 hash function is used, i.e. each hash value is 256 bits. Number of data blocks are two, i.e. the total length of the verification block table, in octets, will be (16+16+2x(256+32+32))/8=84 octets. The data shown belongs to the verification block. The Verification block starts at address 0x0007FF00, i.e. it is the third data block in the figure: 0000 0002 00060000 00000013 D78ECD62C62CF1F575D7DEC6D2FD57DA066554FD42EEE5C867E70083BC942262 00060100 0001EF00 E6027B3F959FAF231B382FFDC64EB23825E6B7CCEA47F5196D02CA2AFDF44188 The format identifier is 0x0000 Number of data blocks are two (0x0002) Data block 1: Start address 0x00060000 and length 0x00000013. Hash 0xD78ECD... Data block 2: Start address 0x00060100 and length 0x0001EF00. Hash 0xE6027B... details: > Verify first 6 bytes of VBT block(manipulated format identifier, data blocks, start address) and also verify software download (SWDL) of ESS VBF with manipulated format identifier present in verification block table fails. """ import logging from glob import glob from hilding.dut import Dut from hilding.dut import DutTestError from supportfunctions.support_lzma import LzmaEncoder from supportfunctions.support_lzss import LzssEncoder from supportfunctions.support_sec_acc import SupportSecurityAccess LZMA = LzmaEncoder() LZSS = LzssEncoder() SSA = SupportSecurityAccess() def verify_correct_vbt_start_address(dut, vbf_header, vbf_data, vbf_block_details, vbf_offset): """ Validate the start address and data format identifier of VBT with VBF header values Args: dut (Dut): An instance of Dut vbf_header (dict): VBF file header vbf_data (bytes): VBF data vbf_block_details (list): VBF block data, VBF block details vbf_offset (int): VBF offset Returns: bool: Returns true when respective VBT data block condition is matched """ # Get start address from vbf_header for key in vbf_header.keys(): if key == 'erase': vbfhdblock= vbf_header['erase'] vbfhdblock_list= list(vbfhdblock) vbf_offset = dut.SSBL.block_data_extract(vbf_data, vbf_offset) # VBT data block dut.SSBL.vbf_header_convert(vbf_header) vbt = vbf_block_details[-1]['vbf_block_data'] # Initialize decompressed data decompr_data = b"" vbfhdblock_list = [] # Retrieve decompressed data if vbf_header['data_format_identifier'] == 0: # format '0x00': decompr_data = vbt elif vbf_header['data_format_identifier'] == 16: # format '0x10': decompr_data = LZSS.decode_barray(vbt) elif vbf_header['data_format_identifier'] == 32: # format '0x20': decompr_data = LZMA.decode_barray(vbt) else: logging.warning("Unknown compression format for data format identifier: " "%0.02X", vbf_header['data_format_identifier']) # Convert decompressed VBT data to list of hex vbt_hex = decompr_data.hex() vbt_list = list(vbt_hex) # Validate verification block table(start address) and VBF header values if vbfhdblock_list[15:19] == vbt_list[4:8]: logging.info("Successfully verified VBT start address and format identifier as expected") return True logging.error("Test Failed: Received incorrect VBT start address %s ", vbt_list[4:8]) return False def manipulated_vbt(vbf_block_details, vbf_header): """ Manipulating the first 6 bytes of verification block table Args: vbf_block_details (list): VBF block data, VBF block details vbf_header (dict): VBF file header Returns: vbf_block_details(list): Manipulated verification block table i.e last VBF block data """ # Getting VBT vbt = vbf_block_details[-1]['vbf_block_data'] decompr_data = b"" # Retrieve decompressed data if vbf_header['data_format_identifier'] == 0: # format '0x00': decompr_data = vbt elif vbf_header['data_format_identifier'] == 16: # format '0x10': logging.info("Compression method 1: LZSS") decompr_data = LZSS.decode_barray(vbt) elif vbf_header['data_format_identifier'] == 32: # format '0x20': logging.info("Compression method 2: LZMA") decompr_data = LZMA.decode_barray(vbt) else: logging.warning("Unknown compression format for data format identifier: " "%0.02X", vbf_header['data_format_identifier']) if decompr_data: vbt_hex = str(SSA.sa_key_calculated_distort(decompr_data)) vbf_block_details[-1]['vbf_block_data'] = bytearray(vbt_hex, 'utf-8') return vbf_block_details def block_wise_software_download_ess(dut, vbf_header, vbf_blocks_details, vbf_offset): """ Blockwise software download(SWDL) for ESS VBF file Args: dut (Dut): An instance of Dut vbf_header (dict): VBF file header vbf_blocks_details (list): VBF block and VBF block data vbf_offset Returns: (bool): Returns true when software download of ESS VBF file is successful """ # Software download(SWDL) for blocks of ESS VBF file for block_id, block_details in enumerate(vbf_blocks_details): logging.info("SWDL on %s of ESS VBF", block_id+1) result = dut.SSBL.transfer_data_block(dut, vbf_header, block_details["vbf_block_data"], vbf_offset) if not result: logging.error("Test Failed: Block %s failed", block_id+1) return False logging.info("Software download for ESS VBF completed") return True def extract_vbf_details_vbt(dut, vbf_data, vbf_offset): """ Extracting VBF parameters from ESS VBFs file Args: dut (Dut): An instance of Dut vbf_data (bytes): VBF data vbf_offset (int): VBF offset Returns: vbf_blocks_details (list): VBF block and VBF block data """ vbf_blocks_details = [] # Extract first VBF block vbf_offset, vbf_block, vbf_block_data = dut.SSBL.block_data_extract(vbf_data, vbf_offset) vbf_blocks_details.append({'vbf_block': vbf_block, 'vbf_block_data': vbf_block_data}) # Extract remaining VBF blocks while vbf_block['StartAddress'] != 0: vbf_offset, vbf_block, vbf_block_data = dut.SSBL.block_data_extract(vbf_data, vbf_offset) # Break if no more blocks found if vbf_block['StartAddress'] != 0: # Preparing VBF blocks details list vbf_blocks_details.append({'vbf_block': vbf_block, 'vbf_block_data': vbf_block_data}) return vbf_blocks_details def extract_vbt(dut, vbf_data, vbf_offset): """ Extracting VBF data block from VBF parameters Args: dut (Dut): An instance of Dut vbf_data (str): VBF data block vbf_offset (int): VBF offset Returns: data_block (str): VBT data in hex """ data_block = '' # To extract VBT data, we need to extract last block of VBF file # So we are iterating through the loop and extracting every block # And in the last iteration of the loop, we receive VBT data block. while True: vbf_offset, vbf_block, vbf_block_data = dut.SSBL.block_data_extract(vbf_data, vbf_offset) if vbf_block['StartAddress'] == 0: logging.debug("No more blocks") break data_block = LZMA.decode_barray(vbf_block_data) return data_block.hex() def software_download_manipulated_ess_vbt(dut): """ Software download(SWDL) for SBL and manipulated ESS VBFs file type Args: dut (Dut): An instance of Dut Returns: (bool): Returns true when software download of ESS VBF file with manipulated VBT is failed """ # Activate SBL sbl_result = dut.SSBL.sbl_activation(dut, sa_keys=dut.conf.default_rig_config) logging.info("Software download (downloading and activating sbl) completed." " Result: %s", sbl_result) if sbl_result is False: logging.error("Test Failed: Aborting software download due to problems when " "activating SBL") return False # Download ESS _, vbf_header, vbf_data, vbf_offset = dut.SSBL.read_vbf_file(dut.SSBL.get_ess_filename()) # Convert VBF header so values can be used directly dut.SSBL.vbf_header_convert(vbf_header) # Erase memory result = dut.SSBL.flash_erase(dut, vbf_header, stepno=2) # Manipulating the VBT vbf_blocks_details = manipulated_vbt(extract_vbf_details_vbt(dut, vbf_data, vbf_offset), vbf_header) swdl_result = result and block_wise_software_download_ess(dut, vbf_header, vbf_blocks_details, vbf_offset) if not swdl_result: logging.info("SWDL ESS VBF file fails with manipulated VBT as expected") return True logging.error("Test Failed: Unexpected result for ESS VBF file") return False def extract_vbf_params(dut, vbf_path): """ Extracting VBF parameters from VBF file Args: dut (Dut): An instance of Dut vbf_path (dict): VBF file path Returns: vbf_params (dict): VBF data, VBF root hash and file name """ vbf_params = {'vbf_data': '', 'vbf_root_hash': '', 'file_name': ''} _, vbf_header, vbf_data, vbf_offset = dut.SSBL.read_vbf_file(vbf_path) vbt = extract_vbt(dut, vbf_data, vbf_offset) vbf_params["vbf_root_hash"] = vbf_header['verification_block_root_hash'] # Used [2:] to remove '0x' from the hex string vbf_params["vbf_data"] = (vbf_header["verification_block_start"][2:] + vbf_header["verification_block_length"][2:] + vbt) vbf_params["file_name"] = vbf_path.split('/')[-1] return vbf_params def step_1(dut: Dut): """ action: Validate the format identifier and start address of VBT blocks with VBF header expected_result: Format identifier and start address of VBT blocks should match with VBF header """ # pylint: disable=unused-argument result = dut.SSBL.get_vbf_files() _, vbf_header, vbf_data, vbf_offset = dut.SSBL.read_vbf_file(dut.SSBL.get_ess_filename()) # Extract VBF blocks vbf_blocks_details = extract_vbf_details_vbt(dut, vbf_data, vbf_offset) # Verifying the VBT format identifier vbt_result = verify_correct_vbt_start_address(dut, vbf_header, vbf_data, vbf_blocks_details, vbf_offset) if result and vbt_result: logging.info("Successfully validated format identifier and start address of VBT blocks" " with VBF header as expected") return True logging.error("Test Failed: VBT verification failed for format identifier and start address") return False def step_2(dut: Dut): """ action: Calculate root hash from VBF data and compare with the value present in VBF header expected_result: Calculated root hash value and root hash value present in VBF header should be equal """ vbf_params_list =[] rig_vbf_path = dut.conf.rig.vbf_path vbf_paths = glob(str(rig_vbf_path) + "/*.vbf") if len(vbf_paths) == 0: logging.error("Test Failed: No VBF file found in path: %s", rig_vbf_path) return False for path in vbf_paths: vbf_params_list.append(extract_vbf_params(dut, path)) result = dut.SSBL.compare_root_hash(vbf_params_list) if result: logging.info("Calculated root hash value and the root hash value present in " "VBF are equal as expected") return True logging.error("Test Failed: Calculated root hash value and the root hash value present in VBF " "header are not equal") return False def step_3(dut: Dut): """ action: Verify software download(SWDL) request for VBF file of ESS software part type with manipulated format identifier, data blocks, start address of verification block table. expected_result: Software download(SWDL) should fail for manipulated VBT of ESS VBF file """ # Software download with SBL and manipulated ESS VBT result = software_download_manipulated_ess_vbt(dut) if result: logging.info("ESS software download fails with manipulated format identifier, data blocks," " start address of VBT as expected ") return True logging.error("Test Failed: ESS software download with manipulated VBT is successful") return False def run(): """ Verify first 6 bytes of VBT block(manipulated format identifier, data blocks, start address) and also verify software download (SWDL) of ESS VBF with manipulated format identifier present in verification block table fails. """ dut = Dut() start_time = dut.start() result = False result_step = False try: dut.precondition(timeout=300) result_step = dut.step(step_1, purpose="Validate the format identifier and start address " "of VBT blocks with VBF header") if result_step: result_step = dut.step(step_2, purpose="Calculate root hash from VBF data and " "compare with the value present in VBF header") if result_step: result_step = dut.step(step_3, purpose="Verify Software download(SWDL) request for " "VBF file of ESS software part type with " "manipulated format identifier, data blocks, " "start address of verification block table") result = result_step except DutTestError as error: logging.error("Test Failed: %s", error) finally: dut.postcondition(start_time, result) if __name__ == '__main__': run()
Editor is loading...
Leave a Comment