def export(self, padding: bytes = None) -> bytes: """Serialize object into bytes. :param padding: header padding 8 bytes (for testing purposes); None to use random value :return: binary representation :raise AttributeError: raised when format is incorrect """ if not isinstance(self.nonce, bytes) or len(self.nonce) != 16: raise AttributeError() major_version, minor_version = [ int(v) for v in self.version.split('.') ] product_version_words = [swap16(v) for v in self.product_version.nums] component_version_words = [ swap16(v) for v in self.product_version.nums ] if padding is None: padding = crypto_backend().random_bytes(8) else: assert len(padding) == 8 result = pack( self.FORMAT, self.nonce, # padding 8 bytes padding, self.SIGNATURE1, # header version major_version, minor_version, self.flags, self.image_blocks, self.first_boot_tag_block, self.first_boot_section_id, self.offset_to_certificate_block, self.header_blocks, self.key_blob_block, self.key_blob_block_count, self.max_section_mac_count, self.SIGNATURE2, pack_timestamp(self.timestamp), # product version product_version_words[0], 0, product_version_words[1], 0, product_version_words[2], 0, # component version component_version_words[0], 0, component_version_words[1], 0, component_version_words[2], 0, self.build_number, # padding[4] padding[4:]) assert len(result) == self.SIZE return result
def export(self, padding8: Optional[bytes] = None, dbg_info: DebugInfo = DebugInfo.disabled()) -> bytes: """Serialization to binary form. :param padding8: 8 padding bytes used for in the header, None to use random bytes This value shall be used only for regression testing to generate same results :param dbg_info: class allowing to debug output from the export :return: Serialize object into bytes """ major_version, minor_version = [int(v) for v in self.version.split('.')] product_version_words = [swap16(n) for n in self.product_version.nums] component_version_words = [swap16(n) for n in self.component_version.nums] signature2 = crypto_backend().random_bytes(4) padding = padding8 if padding8 else crypto_backend().random_bytes(8) if (major_version > 1) or ((major_version == 1) and (minor_version >= 2)): signature2 = self._SIGNATURE2 dbg_info.append_section('SB-file-Header') result = pack( self._FORMAT, self.digest, self._SIGNATURE1, # header version major_version, minor_version, self.flags, self.image_blocks, self.first_boot_tag_block, self.first_boot_section_id, self.key_count, self.key_dictionary_block, self.header_blocks, self.section_count, self.section_header_size, padding[0:2], signature2, pack_timestamp(self.timestamp), # product version product_version_words[0], 0, product_version_words[1], 0, product_version_words[2], 0, # component version component_version_words[0], 0, component_version_words[1], 0, component_version_words[2], 0, self.drive_tag, padding[2:] ) result = result[len(self.digest):] self.digest = crypto_backend().hash(result, 'sha1') dbg_info.append_binary_section('digest', self.digest) dbg_info.append_binary_section('attrs', result) return self.digest + result
def parse(cls, data: bytes, offset: int = 0) -> 'CmdMemEnable': """Parse command from bytes. :param data: Input data as bytes :param offset: The offset of input data :return: Command Memory Enable object """ header = CmdHeader.parse(data, offset) assert header.tag == EnumCmdTag.MEM_ENABLE return cls(header.address, header.count, ExtMemId.from_int(swap16(header.flags)))
def parse(cls, data: bytes, offset: int = 0) -> "CmdMemEnable": """Parse command from bytes. :param data: Input data as bytes :param offset: The offset of input data :return: Command Memory Enable object :raises SPSDKError: If incorrect header tag """ header = CmdHeader.parse(data, offset) if header.tag != EnumCmdTag.MEM_ENABLE: raise SPSDKError("Invalid header tag") return cls(header.address, header.count, MemId.from_int(swap16(header.flags)))
def mem_type(self, value: MemId) -> None: """Setter. :param value: memory to be enabled """ self._header.flags = swap16(value)
def mem_type(self) -> MemId: """Return memory to be enabled.""" return MemId.from_int(swap16(self._header.flags))
def test_swap16_invalid(): with pytest.raises(SPSDKError, match="Incorrect number to be swapped"): swap16(0xFFFFA)
def parse(cls, data: bytes, offset: int = 0) -> "SecureBootHeaderV1": """Convert binary data into the instance (deserialization). :param data: given binary data to be decoded :param offset: to start parsing binary data; 0 by default :return: the instance of secure boot header v1 :raises SPSDKError: Raised when there is insufficient size :raises SPSDKError: Raised when there is invalid signature :raises SPSDKError: Raised when there is unexpected signature """ if SecureBootHeaderV1._SIZE > len(data) - offset: raise SPSDKError("Insufficient size") ( digest, signature1, # header version major_version, minor_version, flags, image_blocks, _first_boot_tag_block, first_boot_section_id, key_count, _key_dictionary_block, header_blocks, section_count, section_header_size, _, # padding 2 signature2, timestamp, pv0, _, pv1, _, pv2, _, # product version cv0, _, cv1, _, cv2, _, # component version drive_tag, _, # padding 6 ) = unpack_from(SecureBootHeaderV1._FORMAT, data, offset) # check header signature 1 if signature1 != SecureBootHeaderV1._SIGNATURE1: raise SPSDKError("Invalid signature") # check header signature 2 for version 1.1 and greater if (major_version > 1) or ((major_version == 1) and (minor_version >= 2)): if signature2 != SecureBootHeaderV1._SIGNATURE2: raise SPSDKError("Unexpected signature") product_version = BcdVersion3(swap16(pv0), swap16(pv1), swap16(pv2)) component_version = BcdVersion3(swap16(cv0), swap16(cv1), swap16(cv2)) obj = SecureBootHeaderV1( digest=digest, version=f"{major_version}.{minor_version}", flags=flags, product_version=product_version, component_version=component_version, drive_tag=drive_tag, ) obj.image_blocks = image_blocks obj.first_boot_section_id = first_boot_section_id obj.key_count = key_count # key_blob_block = key_count obj.header_blocks = header_blocks obj.section_count = section_count obj.section_header_size = section_header_size obj.timestamp = unpack_timestamp(timestamp) return obj