def test_construct_from_params_and_sign(self): """ Gracefully constructs an init packet protobuffer from parameters without bytes, then signs it """ i = InitPacketPB( from_bytes = None, hash_bytes = b"", hash_type = HashTypes.SHA256, dfu_type = DFUType.APPLICATION, is_debug=False, fw_version=0xffffffff, hw_version=0xffffffff, sd_size=0, app_size=1234, bl_size=0, sd_req=[0xffffffff] ) i.set_signature(b"signature bytes go here", SigningTypes.ECDSA_P256_SHA256) protobuf_bytes = i.get_init_packet_pb_bytes(); # Bytes for the whole Packet hex_bytes = protobuf_bytes.encode('hex_codec'); self.assertEqual(hex_bytes, "12450a280801122408ffffffff0f10ffffffff0f1a" "05ffffffff0f20002800300038d209420408031200480010001a177369676e61747572" "6520627974657320676f2068657265")
def test_construct_from_params_and_sign(self): """ Gracefully constructs an init packet protobuffer from parameters without bytes, then signs it """ i = InitPacketPB( from_bytes = None, hash_bytes = b"", hash_type = HashTypes.SHA256, dfu_type = DFUType.APPLICATION, is_debug=False, fw_version=0xffffffff, hw_version=0xffffffff, sd_size=0, app_size=1234, bl_size=0, sd_req=[0xffffffff] ) i.set_signature(b"signature bytes go here", SigningTypes.ECDSA_P256_SHA256) protobuf_bytes = i.get_init_packet_pb_bytes() # Bytes for the whole Packet hex_bytes = protobuf_bytes.encode('hex_codec') self.assertEqual(hex_bytes, "12450a280801122408ffffffff0f10ffffffff0f1a" "05ffffffff0f20002800300038d209420408031200480010001a177369676e61747572" "6520627974657320676f2068657265")
def generate_package(self, filename, preserve_work_dir=False): """ Generates a Nordic DFU package. The package is a zip file containing firmware(s) and metadata required for Nordic DFU applications to perform DFU onn nRF5X devices. :param str filename: Filename for generated package. :param bool preserve_work_dir: True to preserve the temporary working directory. Useful for debugging of a package, and if the user wants to look at the generated package without having to unzip it. :return: None """ self.zip_file = filename self.work_dir = self.__create_temp_workspace() sd_bin_created = False if Package._is_bootloader_softdevice_combination(self.firmwares_data): # Removing softdevice and bootloader data from dictionary and adding the combined later softdevice_fw_data = self.firmwares_data.pop(HexType.SOFTDEVICE) bootloader_fw_data = self.firmwares_data.pop(HexType.BOOTLOADER) softdevice_fw_name = softdevice_fw_data[ FirmwareKeys.FIRMWARE_FILENAME] bootloader_fw_name = bootloader_fw_data[ FirmwareKeys.FIRMWARE_FILENAME] new_filename = "sd_bl.bin" sd_bl_file_path = os.path.join(self.work_dir, new_filename) nrf_hex = nRFHex(softdevice_fw_name, bootloader_fw_name) nrf_hex.tobinfile(sd_bl_file_path) softdevice_size = nrf_hex.size() bootloader_size = nrf_hex.bootloadersize() boot_validation_type = [] boot_validation_type.extend( softdevice_fw_data[FirmwareKeys.BOOT_VALIDATION_TYPE]) boot_validation_type.extend( bootloader_fw_data[FirmwareKeys.BOOT_VALIDATION_TYPE]) self.__add_firmware_info( firmware_type=HexType.SD_BL, firmware_version=bootloader_fw_data[ FirmwareKeys.INIT_PACKET_DATA] [PacketField. FW_VERSION], # use bootloader version in combination with SD filename=sd_bl_file_path, init_packet_data=softdevice_fw_data[ FirmwareKeys.INIT_PACKET_DATA], boot_validation_type=boot_validation_type, sd_size=softdevice_size, bl_size=bootloader_size) # Need to generate SD only bin for boot validation signature sd_bin = Package.normalize_firmware_to_bin( self.work_dir, softdevice_fw_data[FirmwareKeys.FIRMWARE_FILENAME]) sd_bin_path = os.path.join(self.work_dir, sd_bin) sd_bin_created = True for key, firmware_data in self.firmwares_data.items(): # Normalize the firmware file and store it in the work directory firmware_data[FirmwareKeys.BIN_FILENAME] = \ Package.normalize_firmware_to_bin(self.work_dir, firmware_data[FirmwareKeys.FIRMWARE_FILENAME]) # Calculate the hash for the .bin file located in the work directory bin_file_path = os.path.join( self.work_dir, firmware_data[FirmwareKeys.BIN_FILENAME]) firmware_hash = Package.calculate_sha256_hash(bin_file_path) bin_length = int(Package.calculate_file_size(bin_file_path)) sd_size = 0 bl_size = 0 app_size = 0 if key in [HexType.APPLICATION, HexType.EXTERNAL_APPLICATION]: app_size = bin_length elif key == HexType.SOFTDEVICE: sd_size = bin_length elif key == HexType.BOOTLOADER: bl_size = bin_length elif key == HexType.SD_BL: bl_size = firmware_data[FirmwareKeys.BL_SIZE] sd_size = firmware_data[FirmwareKeys.SD_SIZE] boot_validation_type_array = firmware_data[ FirmwareKeys.BOOT_VALIDATION_TYPE] boot_validation_bytes_array = [] for x in boot_validation_type_array: if x == ValidationTypes.VALIDATE_ECDSA_P256_SHA256: if key == HexType.SD_BL: boot_validation_bytes_array.append( Package.sign_firmware(self.key_file, sd_bin_path)) else: boot_validation_bytes_array.append( Package.sign_firmware(self.key_file, bin_file_path)) else: boot_validation_bytes_array.append(b'') init_packet = InitPacketPB( from_bytes=None, hash_bytes=firmware_hash, hash_type=HashTypes.SHA256, boot_validation_type=boot_validation_type_array, boot_validation_bytes=boot_validation_bytes_array, dfu_type=HexTypeToInitPacketFwTypemap[key], is_debug=firmware_data[FirmwareKeys.INIT_PACKET_DATA][ PacketField.DEBUG_MODE], fw_version=firmware_data[FirmwareKeys.INIT_PACKET_DATA][ PacketField.FW_VERSION], hw_version=firmware_data[FirmwareKeys.INIT_PACKET_DATA][ PacketField.HW_VERSION], sd_size=sd_size, app_size=app_size, bl_size=bl_size, sd_req=firmware_data[FirmwareKeys.INIT_PACKET_DATA][ PacketField.REQUIRED_SOFTDEVICES_ARRAY]) if (self.key_file is not None): signer = Signing() signer.load_key(self.key_file) signature = signer.sign(init_packet.get_init_command_bytes()) init_packet.set_signature(signature, SigningTypes.ECDSA_P256_SHA256) # Store the .dat file in the work directory init_packet_filename = firmware_data[ FirmwareKeys.BIN_FILENAME].replace(".bin", ".dat") with open(os.path.join(self.work_dir, init_packet_filename), 'wb') as init_packet_file: init_packet_file.write(init_packet.get_init_packet_pb_bytes()) firmware_data[FirmwareKeys.DAT_FILENAME] = \ init_packet_filename if self.is_zigbee: firmware_version = firmware_data[ FirmwareKeys.INIT_PACKET_DATA][PacketField.FW_VERSION] file_name = firmware_data[FirmwareKeys.BIN_FILENAME] self.zigbee_ota_file = OTA_file( firmware_version, len(init_packet.get_init_packet_pb_bytes()), binascii.crc32(init_packet.get_init_packet_pb_bytes()) & 0xFFFFFFFF, init_packet.get_init_packet_pb_bytes(), os.path.getsize(file_name), self.calculate_crc(32, file_name) & 0xFFFFFFFF, bytes(open(file_name, 'rb').read()), self.manufacturer_id, self.image_type, self.comment, self.zigbee_ota_min_hw_version, self.zigbee_ota_max_hw_version) ota_file_handle = open(self.zigbee_ota_file.filename, 'wb') ota_file_handle.write(self.zigbee_ota_file.binary) ota_file_handle.close() # Remove SD binary file created for boot validation if sd_bin_created: os.remove(sd_bin_path) # Store the manifest to manifest.json manifest = self.create_manifest() with open(os.path.join(self.work_dir, Package.MANIFEST_FILENAME), "w") as manifest_file: manifest_file.write(manifest) # Package the work_dir to a zip file Package.create_zip_package(self.work_dir, filename) # Delete the temporary directory self.rm_work_dir(preserve_work_dir)