Пример #1
0
    def load_from_config(
        cls, config: Dict[str, Any]
    ) -> Union["CmdLoad", "CmdLoadHashLocking", "CmdLoadCmac"]:
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        :raises SPSDKError: Invalid configuration field.
        """
        authentication = config.get("authentication")
        address = value_to_int(config["address"], 0)
        memory_id = value_to_int(config.get("memoryId", "0"), 0)
        if authentication == "hashlocking":
            data = load_binary(config["file"])
            return CmdLoadHashLocking.load_from_config(config)  # Backward compatibility
        if authentication == "cmac":
            data = load_binary(config["file"])
            return CmdLoadCmac.load_from_config(config)  # Backward compatibility
        # general non-authenticated load command
        if config.get("file"):
            data = load_binary(config["file"])
            return CmdLoad(address=address, data=data, memory_id=memory_id)
        if config.get("values"):
            values = [value_to_int(s, 0) for s in config["values"].split(",")]
            data = pack(f"<{len(values)}L", *values)
            return CmdLoad(address=address, data=data, memory_id=memory_id)

        raise SPSDKError(f"Unsupported LOAD command args: {config}")
Пример #2
0
    def from_xml_element(cls, xml_element: ET.Element) -> "RegsRegister":
        """Initialization register by XML ET element.

        :param xml_element: Input XML subelement with register data.
        :return: The instance of this class.
        """
        name = xml_element.attrib[
            "name"] if "name" in xml_element.attrib else "N/A"
        offset = value_to_int(xml_element.attrib["offset"]
                              ) if "offset" in xml_element.attrib else 0
        width = value_to_int(xml_element.attrib["width"]
                             ) if "width" in xml_element.attrib else 0
        descr = xml_element.attrib[
            "description"] if "description" in xml_element.attrib else "N/A"
        reverse = (xml_element.attrib["reversed"]
                   if "reversed" in xml_element.attrib else "False") == "True"
        access = xml_element.attrib[
            "access"] if "access" in xml_element.attrib else "N/A"

        reg = cls(name, offset, width, descr, reverse, access)
        if xml_element.text:
            xml_bitfields = xml_element.findall("bit_field")
            xml_bitfields.extend(xml_element.findall("reserved_bit_field"))
            xml_bitfields_len = len(xml_bitfields)
            for xml_bitfield in xml_bitfields:
                bitfield = RegsBitField.from_xml_element(xml_bitfield, reg)
                if xml_bitfields_len == 1 and bitfield.width == reg.width:
                    if len(reg.description) < len(bitfield.description):
                        reg.description = bitfield.description
                    reg.access = bitfield.access
                else:
                    if reg.access == "N/A":
                        reg.access = "Bitfields depended"
                    reg.add_bitfield(bitfield)
        return reg
Пример #3
0
    def from_xml_element(cls, xml_element: ET.Element,
                         parent: "RegsRegister") -> "RegsBitField":
        """Initialization register by XML ET element.

        :param xml_element: Input XML subelement with register data.
        :param parent: Reference to parent RegsRegister object.
        :return: The instance of this class.
        """
        name = xml_element.attrib[
            "name"] if "name" in xml_element.attrib else "N/A"
        offset = value_to_int(xml_element.attrib["offset"]
                              ) if "offset" in xml_element.attrib else 0
        width = value_to_int(xml_element.attrib["width"]
                             ) if "width" in xml_element.attrib else 0
        descr = xml_element.attrib[
            "description"] if "description" in xml_element.attrib else "N/A"
        access = xml_element.attrib[
            "access"] if "access" in xml_element.attrib else "R/W"
        reset_value = (value_to_int(xml_element.attrib["reset_value"])
                       if "reset_value" in xml_element.attrib else 0)
        hidden = False if xml_element.tag == "bit_field" else True
        bitfield = cls(parent, name, offset, width, descr, reset_value, access,
                       hidden)

        if xml_element.text:
            xml_enums = xml_element.findall("bit_field_value")
            for xml_enum in xml_enums:
                bitfield.add_enum(RegsEnum.from_xml_element(xml_enum, width))
        return bitfield
Пример #4
0
def test_value_to_int(value, res, exc):
    """Test of value_to_int function"""
    if not exc:
        assert res == value_to_int(value)
    else:
        with pytest.raises(SPSDKError):
            value_to_int(value)
Пример #5
0
    def load_from_config(cls, config: Dict[str, Any]) -> "SecureBinary31":
        """Creates instantion of SecureBinary31 from configuration.

        :param config: Input standard configuration.
        :return: Instantion of Secure Binary V3.1 class
        """
        container_keyblob_enc_key_path = config.get(
            "containerKeyBlobEncryptionKey")
        is_nxp_container = config.get("isNxpContainer", False)
        description = config.get("description")
        kdk_access_rights = value_to_int(config.get("kdkAccessRights", 0))
        container_configuration_word = value_to_int(
            config.get("containerConfigurationWord", 0))
        firmware_version = value_to_int(config.get("firmwareVersion", 1))

        commands = config["commands"]
        is_encrypted = config.get("isEncrypted", True)
        timestamp = config.get("timestamp")
        if timestamp:  # re-format it
            timestamp = value_to_int(timestamp)

        cert_block = CertBlockV31.from_config(config)

        # if use_isk is set, we use for signing the ISK certificate instead of root
        signing_key_path = (config.get("signingCertificatePrivateKeyFile")
                            if cert_block.isk_certificate else
                            config.get("mainRootCertPrivateKeyFile"))
        curve_name = (config.get("iskCertificateEllipticCurve")
                      if cert_block.isk_certificate else
                      config.get("rootCertificateEllipticCurve"))
        assert curve_name and isinstance(curve_name, str)
        assert signing_key_path
        signing_key = load_binary(
            signing_key_path) if signing_key_path else None
        assert signing_key

        pck = None
        if is_encrypted:
            assert container_keyblob_enc_key_path
            pck = bytes.fromhex(load_text(container_keyblob_enc_key_path))

        # Create SB3 object
        sb3 = SecureBinary31(
            pck=pck,
            cert_block=cert_block,
            curve_name=curve_name,
            kdk_access_rights=kdk_access_rights,
            firmware_version=firmware_version,
            description=description,
            is_nxp_container=is_nxp_container,
            flags=container_configuration_word,
            signing_key=signing_key,
            timestamp=timestamp,
            is_encrypted=is_encrypted,
        )

        # Add commands into the SB3 object
        sb3.sb_commands.load_from_config(commands)

        return sb3
Пример #6
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdProgFuses":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        address = value_to_int(config["address"], 0)
        fuses = [value_to_int(fuse, 0) for fuse in config["values"].split(",")]
        data = pack(f"<{len(fuses)}L", *fuses)
        return CmdProgFuses(address=address, data=data)
Пример #7
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdErase":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        address = value_to_int(config["address"], 0)
        length = value_to_int(config["size"], 0)
        memory_id = value_to_int(config.get("memoryId", "0"), 0)
        return CmdErase(address=address, length=length, memory_id=memory_id)
Пример #8
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdConfigureMemory":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        memory_id = value_to_int(config["memoryId"], 0)
        return CmdConfigureMemory(
            address=value_to_int(config["configAddress"], 0), memory_id=memory_id
        )
Пример #9
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdFillMemory":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        address = value_to_int(config["address"], 0)
        length = value_to_int(config["size"], 0)
        pattern = value_to_int(config["pattern"], 0)
        return CmdFillMemory(address=address, length=length, pattern=pattern)
Пример #10
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdLoadHashLocking":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        :raises SPSDKError: Invalid configuration field.
        """
        address = value_to_int(config["address"], 0)
        memory_id = value_to_int(config.get("memoryId", "0"), 0)

        data = load_binary(config["file"])
        return CmdLoadHashLocking(address=address, data=data, memory_id=memory_id)
Пример #11
0
def _is_number(param: Any) -> bool:
    """Checks whether the input represents a number.

    :param param: Input to analyze
    :raises SPSDKError: Input doesn't represent a number
    :return: True if input represents a number
    """
    try:
        value_to_int(param)
        return True
    except SPSDKError:
        return False
Пример #12
0
    def mix_load_from_config(self, config: Dict[str, Any]) -> None:
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        """
        super().mix_load_from_config(config)
        self.firmware_version = value_to_int(config.get("firmwareVersion", 0))
        sign_hash_len_raw = config.get("manifestSigningHashLength", None)
        sign_hash_len = value_to_int(
            sign_hash_len_raw) if sign_hash_len_raw else None
        self.manifest = MasterBootImageManifest(self.firmware_version,
                                                self.tz,
                                                sign_hash_len=sign_hash_len)
Пример #13
0
    def load_registers_from_xml(self,
                                xml: str,
                                filter_reg: List[str] = None,
                                grouped_regs: List[dict] = None) -> None:
        """Function loads the registers from the given XML.

        :param xml: Input XML data in string format.
        :param filter_reg: List of register names that should be filtered out.
        :param grouped_regs: List of register prefixes names to be grouped int one.
        :raises SPSDKRegsError: XML parse problem occuress.
        """
        def is_reg_in_group(reg: str) -> Union[dict, None]:
            """Help function to recognize if the register should be part of group."""
            if grouped_regs:
                for group in grouped_regs:
                    if reg.startswith(group["name"]):
                        return group
            return None

        try:
            xml_elements = ET.parse(xml)
        except ET.ParseError as exc:
            raise SPSDKRegsError(f"Cannot Parse XML data: {str(exc)}") from exc
        xml_registers = xml_elements.findall("register")
        xml_registers = self._filter_by_names(xml_registers, filter_reg or [])
        # Load all registers into the class
        for xml_reg in xml_registers:
            group = is_reg_in_group(xml_reg.attrib["name"])
            if group:
                try:
                    group_reg = self.find_reg(group["name"])
                except SPSDKRegsErrorRegisterNotFound:
                    group_reg = RegsRegister(
                        name=group["name"],
                        offset=value_to_int(group.get("offset", 0)),
                        width=value_to_int(group.get("width", 0)),
                        description=group.get(
                            "description",
                            f"Group of {group['name']} registers."),
                        reverse=value_to_bool(group.get("reverse", False)),
                        access=group.get("access", None),
                        config_as_hexstring=group.get("config_as_hexstring",
                                                      False),
                    )

                    self.add_register(group_reg)
                group_reg.add_group_reg(RegsRegister.from_xml_element(xml_reg))
            else:
                self.add_register(RegsRegister.from_xml_element(xml_reg))
Пример #14
0
    def from_xml_element(cls,
                         xml_element: ET.Element,
                         maxwidth: int = 0) -> "RegsEnum":
        """Initialization Enum by XML ET element.

        :param xml_element: Input XML subelement with enumeration data.
        :param maxwidth: The maximal width of bitfield for this enum (used for formating).
        :return: The instance of this class.
        :raises SPSDKRegsError: Error during enum XML parsing.
        """
        name = xml_element.attrib[
            "name"] if "name" in xml_element.attrib else "N/A"
        if "value" not in xml_element.attrib:
            raise SPSDKRegsError(f"Missing Enum Value Key for {name}.")

        raw_val = xml_element.attrib["value"]
        try:
            value = value_to_int(raw_val)
        except (TypeError, ValueError, SPSDKError) as exc:
            raise SPSDKRegsError(f"Invalid Enum Value: {raw_val}") from exc

        descr = xml_element.attrib[
            "description"] if "description" in xml_element.attrib else "N/A"

        return cls(name, value, descr, maxwidth)
Пример #15
0
    def set_value(self, val: Any, raw: bool = False) -> None:
        """Set the new value of register.

        :param val: The new value to set.
        :param raw: Do not use any modification hooks.
        :raises SPSDKError: When invalid values is loaded into register
        """
        try:
            value = value_to_int(val)
            if not raw and len(self._set_value_hooks) > 0:
                for hook in self._set_value_hooks:
                    value = hook[0](value, hook[1])

            self._value = value

            if self.has_group_registers():
                # Update also values in sub registers
                subreg_width = self.sub_regs[0].width
                for index, sub_reg in enumerate(self.sub_regs, start=1):
                    # sub_reg.set_value((value >> (index * subreg_width)) & ((1 << subreg_width) - 1))
                    sub_reg.set_value((value >>
                                       (self.width - index * subreg_width))
                                      & ((1 << subreg_width) - 1))

        except SPSDKError:
            logger.error(f"Loaded invalid value {str(val)}")
            raise SPSDKError(f"Loaded invalid value {str(val)}")
Пример #16
0
    def load_yml_config(
        self,
        yml_data: Any,
        exclude_regs: List[str] = None,
        exclude_fields: Dict[str, Dict[str, str]] = None,
    ) -> None:
        """The function loads the configuration from YML file.

        :param yml_data: The YAML commented data with register values.
        :param exclude_regs: List of excluded registers
        :param exclude_fields: Dictionary with lists of excluded bitfields
        """
        for reg_name in yml_data.keys():
            reg_dict = yml_data[reg_name]
            register = self.find_reg(reg_name, include_group_regs=True)
            if "value" in reg_dict.keys():
                raw_val = reg_dict["value"]
                val = int(
                    raw_val, 16
                ) if register.config_as_hexstring else value_to_int(raw_val)
                register.set_value(val, True)
            elif "bitfields" in reg_dict.keys():
                for bitfield_name in reg_dict["bitfields"]:
                    bitfield_val = reg_dict["bitfields"][bitfield_name]
                    bitfield = register.find_bitfield(bitfield_name)
                    if (exclude_fields and reg_name in exclude_fields.keys()
                            and bitfield_name in exclude_fields[reg_name]):
                        continue

                    bitfield.set_enum_value(bitfield_val, True)
            else:
                logger.error(f"There are no data for {reg_name} register.")

            logger.debug(
                f"The register {reg_name} has been loaded from configuration.")
Пример #17
0
    def __init__(
        self,
        parent: "RegsRegister",
        name: str,
        offset: int,
        width: int,
        description: str = None,
        reset_val: Any = "0",
        access: str = "RW",
        hidden: bool = False,
    ) -> None:
        """Constructor of RegsBitField class. Used to store bitfield information.

        :param parent: Parent register of bitfield.
        :param name: Name of bitfield.
        :param offset: Bit offset of bitfield.
        :param width: Bit width of bitfield.
        :param description: Text description of bitfield.
        :param reset_val: Reset value of bitfield.
        :param access: Access type of bitfield.
        :param hidden: The bitfield will be hidden from standard searches.
        """
        self.parent = parent
        self.name = name or "N/A"
        self.offset = offset
        self.width = width
        self.description = description or "N/A"
        self.reset_value = value_to_int(reset_val, 0)
        self.access = access
        self.hidden = hidden
        self._enums: List[RegsEnum] = []
        self._update_reset_value()
        self.set_value(self.reset_value, raw=True)
Пример #18
0
    def mix_load_from_config(self, config: Dict[str, Any]) -> None:
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        """
        value = config.get("outputImageExecutionAddress")
        assert value is not None
        self.load_address = value_to_int(value)
Пример #19
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdCall":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        address = value_to_int(config["address"], 0)
        return CmdCall(address=address)
Пример #20
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdCopy":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        address = value_to_int(config["addressFrom"], 0)
        length = value_to_int(config["size"], 0)
        destination_address = value_to_int(config["addressTo"], 0)
        memory_id_from = value_to_int(config["memoryIdFrom"], 0)
        memory_id_to = value_to_int(config["memoryIdTo"], 0)
        return CmdCopy(
            address=address,
            length=length,
            destination_address=destination_address,
            memory_id_from=memory_id_from,
            memory_id_to=memory_id_to,
        )
Пример #21
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdProgIfr":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        address = value_to_int(config["address"], 0)
        data = load_binary(config["file"])
        return CmdProgIfr(address=address, data=data)
Пример #22
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdFwVersionCheck":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        value = value_to_int(config["value"], 0)
        counter_id_str = config["counterId"]
        counter_id = CmdFwVersionCheck.CounterID[counter_id_str]
        return CmdFwVersionCheck(value=value, counter_id=counter_id)
Пример #23
0
    def _get_seal_count(self) -> int:
        """Function returns seal count for the device.

        :return: Count of seals fields.
        :raises SPSDKError: When 'seal_count' in database.json can not be found
        """
        count = self.config.get_seal_count(self.device)
        if not count:
            raise SPSDKError("Can't find 'seal_count' in database.json")
        return value_to_int(count)
Пример #24
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdLoadKeyBlob":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        data = load_binary(config["file"])
        offset = value_to_int(config["offset"], 0)
        key_wrap_name = config["wrappingKeyId"]
        key_wrap_id = CmdLoadKeyBlob.KeyWraps[key_wrap_name]
        return CmdLoadKeyBlob(offset=offset, data=data, key_wrap_id=key_wrap_id)
Пример #25
0
def parse_property_tag(property_tag: str) -> int:
    """Convert the property as name or stringified number into integer.

    :param property_tag: Name or number of the property tag
    :return: Property integer tag
    """
    try:
        value = value_to_int(property_tag)
        return value if value in PROPERTIES_NAMES.values() else 0xFF
    except SPSDKError:
        return PROPERTIES_NAMES.get(property_tag, 0xFF)
Пример #26
0
def _parse_key_type(user_input: str,
                    collection: Any,
                    default: int = None) -> int:
    try:
        return value_to_int(user_input)
    except SPSDKError:
        key_type = user_input.upper()
        key_type_int = collection.get(key_type, default)
        if key_type_int is None:
            raise SPSDKError(  # pylint: disable=raise-missing-from
                f"Unable to find '{user_input}' in '{collection.__name__}'")
        return key_type_int
Пример #27
0
    def from_config(cls, config: Dict[str, Any]) -> "CertBlockV31":
        """Creates instantion of CertBlockV31 from configuration.

        :param config: Input standard configuration.
        :return: Instantion of CertBlockV3.1
        :raises SPSDKError: If found gap in certificates from config file.
        """
        root_certificates_loaded: List[Optional[str]] = [
            config.get(f"rootCertificate{idx}File") for idx in range(4)
        ]
        # filter out None and empty values
        root_certificates = list(filter(None, root_certificates_loaded))
        for org, filtered in zip(root_certificates_loaded, root_certificates):
            if org != filtered:
                raise SPSDKError(
                    "There are gaps in rootCertificateXFile definition")

        main_root_cert_id = config.get("mainRootCertId", 0)
        main_root_private_key_file = config.get("mainRootCertPrivateKeyFile")
        use_isk = config.get("useIsk", False)
        isk_certificate = config.get("signingCertificateFile")
        isk_constraint = value_to_int(
            config.get("signingCertificateConstraint", "0"))
        isk_sign_data_path = config.get("signCertData")

        root_certs = [
            misc.load_binary(cert_file) for cert_file in root_certificates
        ]
        user_data = None
        isk_private_key = None
        isk_cert = None

        if use_isk:
            assert isk_certificate and main_root_private_key_file
            if isk_sign_data_path:
                user_data = misc.load_binary(isk_sign_data_path)
            isk_private_key = misc.load_binary(main_root_private_key_file)
            isk_cert = misc.load_binary(isk_certificate)

        cert_block = CertBlockV31(
            root_certs=root_certs,
            used_root_cert=main_root_cert_id,
            user_data=user_data,
            constraints=isk_constraint,
            isk_cert=isk_cert,
            ca_flag=not use_isk,
            isk_private_key=isk_private_key,
        )

        return cert_block
Пример #28
0
 def _custom_export(self) -> bytes:
     if self.presets is None:
         raise SPSDKError("Preset data not present")
     if self.customs is None:
         raise SPSDKError("Data not present")
     logger.info(f"{len(self.presets)} registers loaded from defaults")
     logger.debug(self.presets)
     logger.info(f"{len(self.customs)} modifications provided")
     logger.debug(self.customs)
     data = self.presets
     data.update(self.customs)
     registers = [value_to_int(item) for item in data.values()]
     # transform data into binary format (little endian, 32b per register)
     return struct.pack(f"<{len(registers)}I", *registers)
Пример #29
0
    def set_value(self, new_val: Any, raw: bool = False) -> None:
        """Updates the value of the bitfield.

        :param new_val: New value of bitfield.
        :param raw: If set, no automatic modification of value is applied.
        :raises SPSDKError: The input value is out of range.
        """
        new_val_int = value_to_int(new_val)
        if new_val_int > 1 << self.width:
            raise SPSDKError("The input value is out of bitfield range")
        reg_val = self.parent.get_value()
        mask = ((1 << self.width) - 1) << self.offset
        reg_val = reg_val & ~mask
        value = (new_val_int << self.offset) & mask
        reg_val = reg_val | value
        self.parent.set_value(reg_val, raw)
Пример #30
0
    def set_enum_value(self, new_val: str, raw: bool = False) -> None:
        """Updates the value of the bitfield by its enum value.

        :param new_val: New enum value of bitfield.
        :param raw: If set, no automatic modification of value is applied.
        :raises SPSDKRegsErrorEnumNotFound: Input value cannot be decoded.
        """
        try:
            val_int = self.get_enum_constant(new_val)
        except SPSDKRegsErrorEnumNotFound as exc:
            # Try to decode standard input
            try:
                val_int = value_to_int(new_val)
            except TypeError:
                raise exc
        self.set_value(val_int, raw)