def test_construct_from_params_and_not_sign(self):
        """
        Gracefully constructs an init packet protobuffer from parameters without bytes,
        skipping the signature process
        """

        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]
            )

        protobuf_bytes = i.get_init_packet_pb_bytes(); # Bytes for the whole Packet
        hex_bytes = protobuf_bytes.encode('hex_codec');

        self.assertEqual(hex_bytes, "0a280801122408ffffffff0f10ffffffff0f1a"
        "05ffffffff0f20002800300038d2094204080312004800")
    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(self):
        """
        Gracefully constructs an init packet protobuffer from parameters without bytes
        """

        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]
            )

        protobuf_bytes = i.get_init_command_bytes(); # bytes only for the InitCommand
        hex_bytes = protobuf_bytes.encode('hex_codec');

        self.assertEqual(hex_bytes, "08ffffffff0f10ffffffff0f1a05ffffffff0f20002800"
                         "300038d2094204080312004800")
示例#4
0
    def test_construct_from_params_and_not_sign(self):
        """
        Gracefully constructs an init packet protobuffer from parameters without bytes,
        skipping the signature process
        """

        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]
            )

        protobuf_bytes = i.get_init_packet_pb_bytes() # Bytes for the whole Packet
        hex_bytes = protobuf_bytes.encode('hex_codec')

        self.assertEqual(hex_bytes, "0a280801122408ffffffff0f10ffffffff0f1a"
        "05ffffffff0f20002800300038d2094204080312004800")
示例#5
0
    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")
示例#6
0
    def test_construct_from_params(self):
        """
        Gracefully constructs an init packet protobuffer from parameters without bytes
        """

        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]
            )

        protobuf_bytes = i.get_init_command_bytes() # bytes only for the InitCommand
        hex_bytes = protobuf_bytes.encode('hex_codec')

        self.assertEqual(hex_bytes, "08ffffffff0f10ffffffff0f1a05ffffffff0f20002800"
                         "300038d2094204080312004800")
示例#7
0
    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)
示例#8
0
    def image_str(self, index, hex_type, img):
        type_strs = {
            HexType.SD_BL: "sd_bl",
            HexType.SOFTDEVICE: "softdevice",
            HexType.BOOTLOADER: "bootloader",
            HexType.APPLICATION: "application",
            HexType.EXTERNAL_APPLICATION: "external application"
        }

        # parse init packet
        with open(os.path.join(self.zip_dir, img.dat_file), "rb") as imgf:
            initp_bytes = imgf.read()

        initp = InitPacketPB(from_bytes=initp_bytes)

        sd_req = ""
        for x in initp.init_command.sd_req:
            sd_req = sd_req + "0x{0:02X}, ".format(x)

        if len(sd_req) != 0:
            sd_req = sd_req[:-2]

        if (initp.packet.HasField('signed_command')):
            cmd = initp.packet.signed_command.command
            signature_type = SigningTypes(
                initp.packet.signed_command.signature_type).name
            signature_hex = binascii.hexlify(
                initp.packet.signed_command.signature)
        else:
            cmd = initp.packet.command
            signature_type = 'UNSIGNED'
            signature_hex = 'N/A'

        boot_validation_type = []
        boot_validation_bytes = []
        for x in cmd.init.boot_validation:
            boot_validation_type.append(ValidationTypes(x.type).name)
            boot_validation_bytes.append(binascii.hexlify(x.bytes))

        s = """|
|- Image #{0}:
   |- Type: {1}
   |- Image file: {2}
   |- Init packet file: {3}
      |
      |- op_code: {4}
      |- signature_type: {5}
      |- signature (little-endian): {6}
      |
      |- fw_version: 0x{7:08X} ({7})
      |- hw_version 0x{8:08X} ({8})
      |- sd_req: {9}
      |- type: {10}
      |- sd_size: {11}
      |- bl_size: {12}
      |- app_size: {13}
      |
      |- hash_type: {14}
      |- hash (little-endian): {15}
      |
      |- boot_validation_type: {16}
      |- boot_validation_signature (little-endian): {17}
      |
      |- is_debug: {18}

""".format(
            index,
            type_strs[hex_type],
            img.bin_file,
            img.dat_file,
            CommandTypes(cmd.op_code).name,
            signature_type,
            signature_hex,
            cmd.init.fw_version,
            cmd.init.hw_version,
            sd_req,
            DFUType(cmd.init.type).name,
            cmd.init.sd_size,
            cmd.init.bl_size,
            cmd.init.app_size,
            HashTypes(cmd.init.hash.hash_type).name,
            binascii.hexlify(cmd.init.hash.hash),
            boot_validation_type,
            boot_validation_bytes,
            cmd.init.is_debug,
        )

        return s