def get_scons_targets(input):
    # initialize target lists
    integrity_targets = list()
    sign_targets = list()
    encrypt_targets = list()
    sign_and_encrypt_targets = list()
    scons_targets = [integrity_targets, sign_targets, encrypt_targets, sign_and_encrypt_targets]
    pilsplit_files_to_clean = list()
    # get chipset and filename of input file
    chipset = SecImageConfigParser(input.config).root.metadata.get_chipset()
    path, filename = os.path.split(input.source)
    if input.build_policy:
        for policy in input.build_policy.sec_image_policies:
            target_list_to_append_to = scons_targets[target_map[policy.cmd_options]]
            # get path to installed image
            if input.sectools_install_base_dir:
                for install_location in policy.install_locations:
                    if input.install_file_name:
                        target = c_path.join(install_location, input.install_file_name)
                    else:
                        target = c_path.join(install_location, filename)
                    logger.debug("Added to-be-installed file \"{0}\" to SCons target list".format(target))
                    target_list_to_append_to.append(target)
                    # determine pilsplit images to cleanup
                    if input.pilsplitter_target_base_dir:
                        if install_location != input.sectools_install_base_dir:
                            pilsplit_directory = c_path.join(input.pilsplitter_target_base_dir, install_location.replace(os.path.join(input.sectools_install_base_dir, "", ""), ""))
                        else:
                            pilsplit_directory = input.pilsplitter_target_base_dir
                        if c_path.validate_dir_write(pilsplit_directory):
                            pilsplit_filename = input.install_file_name.split(".")[0] if input.install_file_name else filename.split(".")[0]
                            # get all pil files in pilsplit target directory
                            regex = r"^" + re.escape(pilsplit_filename) + r"\.((mdt)|(b[0-9][0-9]))$"
                            pil_files = [c_path.join(pilsplit_directory, f) for f in os.listdir(pilsplit_directory) if re.match(regex, f)]
                            for pil_file in pil_files:
                                logger.debug("Added pilsplit file \"{0}\" to SCons clean list".format(pil_file))
                                pilsplit_files_to_clean.append(pil_file)
            # get path to uninstalled image if no installation is requested
            else:
                uninstalled_target = c_path.normalize(c_path.join(input.target_base_dir, policy.id, chipset, input.sign_id, filename))
                target_list_to_append_to.append(uninstalled_target)
                logger.debug("Added file \"{0}\" to SCons target list".format(uninstalled_target))
    # remove duplicates from lists
    for i, targets in enumerate(scons_targets):
        scons_targets[i] = remove_duplicates(targets)
    pilsplit_files_to_clean = remove_duplicates(pilsplit_files_to_clean)
    # clean pilsplit files
    input.environment.Clean(scons_targets, pilsplit_files_to_clean)
    # return target list
    return scons_targets
Exemplo n.º 2
0
 def __init__(self, binary_data, binary_data_format):
     self._data = binary_data
     self._format = binary_data_format[0]
     self._fields = list(binary_data_format[1])
     if len(self.fields) != len(remove_duplicates(self.fields)):
         raise RuntimeError("Fields must not contain duplicates")
     if len(self.fields) != len(re.sub("[@=<>!0-9]", "", self.format)):
         raise RuntimeError("Number of fields must match the number of structures defined by format string")
     if len(self.binary_data) < calcsize(self.format):
         raise RuntimeError("Length of data must be greater than or equal to length specified by format string")
     super(StructDynamic, self).__init__(self.format)
Exemplo n.º 3
0
    def validate(self, images, *args):
        assert(isinstance(images, complex_images_list))

        image_list = images.get_image()
        retval = [True]
        errors = []

        def add_error(sign_id, error):
            retval[0] = False
            errors.append("\nsign_id={0}: ".format(sign_id) + error)

        # expect args[0] to be instance of signing
        assert(isinstance(args[0], complex_general_properties))
        assert(isinstance(args[1], complex_metadata))

        general_properties = args[0]

        # Not Overridable
        use_serial_number_in_signing =\
            general_properties.get_use_serial_number_in_signing()

        attributes = dict(
            hash_algorithm=general_properties.get_hash_algorithm(),
            hmac=general_properties.get_hmac(),
            rsa_padding=general_properties.get_rsa_padding(),
            num_root_certs=general_properties.get_num_root_certs(),
            secboot_version=general_properties.get_secboot_version(),
            dsa_type=general_properties.get_dsa_type(),
            key_size=general_properties.get_key_size(),
            exponent=general_properties.get_exponent())

        # Overridable
        default_debug = general_properties.get_debug()
        default_sw_id = general_properties.get_sw_id()
        default_oem_id = general_properties.get_oem_id()
        default_model_id = general_properties.get_model_id()
        default_msm_part = general_properties.get_msm_part()
        default_soc_hw_version = general_properties.get_soc_hw_version()
        default_in_use_soc_hw_version = general_properties.get_in_use_soc_hw_version()

        for image in image_list:
            sign_id = image.get_sign_id()
            overrides = image.get_general_properties_overrides()

            # Update all the overridable attributes
            for attr in defines.CONFIG_STRUCTURE["images_list"]["image"][0][
                                        "general_properties_overrides"].keys():
                attr_override = getattr(overrides, "get_" + attr)()
                if attr_override is None:
                    attributes[attr] = locals()["default_" + attr]
                else:
                    attributes[attr] = attr_override

        return retval[0], "".join(remove_duplicates(errors))
Exemplo n.º 4
0
    def compare_lists(self, config_attr, attr, dup_in_cert_is_error,
                      missing_is_error):
        is_multi_serial_numbers = attr == 'multi_serial_numbers'
        if is_multi_serial_numbers:
            config_list = getattr(config_attr, attr).serial if getattr(
                config_attr, attr) is not None else []
        else:
            config_list = getattr(config_attr, attr) if getattr(
                config_attr, attr) is not None else []
        cert_list = getattr(self, attr) if getattr(self,
                                                   attr) is not None else []

        # Lower case config items to match case of extracted subject returned by get_subject_list_from_text
        for index, item in enumerate(config_list):
            config_list[index] = item.lower()

        # Lists are empty so they match
        if config_list == cert_list == []:
            return True, None, None

        # Items in config match those in cert
        cert_without_duplicates = remove_duplicates(cert_list)
        if len(cert_list) == len(cert_without_duplicates) and set(
                config_list) == set(cert_without_duplicates):
            return True, None, None

        # Lists don't match. Determine which items are duplicated or missing

        cert_errors = []
        config_errors = []

        # Determine if duplicates exist in certificate
        if dup_in_cert_is_error:
            duplicates = get_duplicates(cert_list)
            if len(duplicates) > 0:
                for item in duplicates:
                    config_errors.append('No duplicate')
                    cert_errors.append('Duplicate: ' + item)

        if missing_is_error:
            # Determine items in cert that are missing from config
            for item in cert_list:
                if item not in config_list:
                    config_errors.append('Missing')
                    cert_errors.append(item)

            # Determine items in config that are missing from cert
            for item in config_list:
                if item not in cert_list:
                    config_errors.append(item)
                    cert_errors.append('Missing')

        return False, cert_errors, config_errors
Exemplo n.º 5
0
    def validate(self, images, *args):
        assert (isinstance(images, complex_images_list))

        image_list = images.get_image()
        retval = [True]
        errors = []

        def add_error(sign_id, error):
            retval[0] = False
            errors.append("\nsign_id={0}: ".format(sign_id) + error)

        def validate_hex_list(sign_id, hex_list, max_num_allowed, list_name,
                              item_name, length_of_item):
            if len(hex_list) > max_num_allowed:
                add_error(
                    sign_id,
                    "{0} provided {1}s exceeds allowed maximum of {2}".format(
                        len(hex_list), item_name, max_num_allowed))

            for val in hex_list:
                try:
                    if val[:2] != "0x" or len(val) != length_of_item or (int(
                            val, 16) == 0):
                        raise ValueError("malformed")
                    int(val, 16)
                except ValueError:
                    add_error(
                        sign_id,
                        "Provided {0} value \"{1}\" is not a valid {2}".format(
                            list_name, val, item_name))

            duplicates = get_duplicates(hex_list)
            if len(duplicates) > 0:
                if len(duplicates) == 1:
                    error_str = "{0} contains a duplicate of the following value: {1}".format(
                        list_name, ", ".join(duplicates))
                else:
                    error_str = "{0} contains duplicates of the following values: ".format(
                        list_name, ", ".join(duplicates))
                add_error(sign_id, error_str)

        # expect args[0] to be instance of signing
        # the following default signing attributes are checked if signing is TCG
        assert (isinstance(args[0], complex_general_properties))
        general_properties = args[0]
        default_sw_id = general_properties.get_sw_id()
        default_app_id = general_properties.get_app_id()
        default_crash_dump = general_properties.get_crash_dump()
        default_msm_part = general_properties.get_msm_part()
        default_soc_hw_version = general_properties.get_soc_hw_version()
        default_soc_vers = general_properties.get_soc_vers()
        default_mask_soc_hw_version = general_properties.get_mask_soc_hw_version(
        )
        default_in_use_soc_hw_version = general_properties.get_in_use_soc_hw_version(
        )
        default_use_serial_number_in_signing = general_properties.get_use_serial_number_in_signing(
        )
        default_serial_number = general_properties.get_serial_number()
        default_oem_id = general_properties.get_oem_id()
        default_model_id = general_properties.get_model_id()
        default_debug = general_properties.get_debug()
        default_multi_serial_numbers = general_properties.get_multi_serial_numbers(
        ).get_serial() if general_properties.get_multi_serial_numbers(
        ) is not None else []
        default_oid = general_properties.get_object_id()
        default_oid_min = default_oid.min if default_oid is not None else None
        default_oid_max = default_oid.max if default_oid is not None else None
        default_hash_algorithm = general_properties.get_hash_algorithm()
        default_hmac = general_properties.get_hmac()
        default_rsa_padding = general_properties.get_rsa_padding()
        default_num_root_certs = general_properties.get_num_root_certs()
        default_max_num_root_certs = general_properties.get_max_num_root_certs(
        )
        default_mrc_index = general_properties.get_mrc_index()
        default_secboot_version = general_properties.get_secboot_version()
        default_dsa_type = general_properties.get_dsa_type()
        default_ecdsa_curve = general_properties.get_ecdsa_curve()
        default_key_size = general_properties.get_key_size()
        default_exponent = general_properties.get_exponent()
        default_client_id = general_properties.get_client_id()
        default_lib_id = general_properties.get_lib_id()
        default_UIE_server_cert_path = general_properties.get_UIE_server_cert_path(
        )

        assert (isinstance(args[1], complex_metadata))
        metadata = args[1]
        chipset = metadata.get_chipset()

        for image in image_list:
            sign_id = image.get_sign_id()
            image_type = image.get_image_type()
            overrides = image.get_general_properties_overrides()

            sw_id = overrides.get_sw_id() if overrides.get_sw_id(
            ) is not None else default_sw_id
            app_id = overrides.get_app_id() if overrides.get_app_id(
            ) is not None else default_app_id
            crash_dump = overrides.get_crash_dump(
            ) if overrides.get_crash_dump() is not None else default_crash_dump
            msm_part = overrides.get_msm_part() if overrides.get_msm_part(
            ) is not None else default_msm_part
            soc_hw_version = overrides.get_soc_hw_version(
            ) if overrides.get_soc_hw_version(
            ) is not None else default_soc_hw_version
            soc_vers = overrides.get_soc_vers() if overrides.get_soc_vers(
            ) is not None else default_soc_vers
            mask_soc_hw_version = overrides.get_mask_soc_hw_version(
            ) if overrides.get_mask_soc_hw_version(
            ) is not None else default_mask_soc_hw_version
            in_use_soc_hw_version = overrides.get_in_use_soc_hw_version(
            ) if overrides.get_in_use_soc_hw_version(
            ) is not None else default_in_use_soc_hw_version
            use_serial_number_in_signing = overrides.get_use_serial_number_in_signing(
            ) if overrides.get_use_serial_number_in_signing(
            ) is not None else default_use_serial_number_in_signing
            serial_number = overrides.get_serial_number(
            ) if overrides.get_serial_number(
            ) is not None else default_serial_number
            oem_id = overrides.get_oem_id() if overrides.get_oem_id(
            ) is not None else default_oem_id
            model_id = overrides.get_model_id() if overrides.get_model_id(
            ) is not None else default_model_id
            debug = overrides.get_debug() if overrides.get_debug(
            ) is not None else default_debug
            multi_serial_numbers = list(overrides.get_multi_serial_numbers(
            ).get_serial() if overrides.get_multi_serial_numbers(
            ) is not None else default_multi_serial_numbers)
            override_oid = overrides.get_object_id(
            ) if overrides.get_object_id() is not None else default_oid
            oid_min = override_oid.min if override_oid is not None else default_oid_min
            oid_max = override_oid.max if override_oid is not None else default_oid_max
            hmac = overrides.get_hmac() if overrides.get_hmac(
            ) is not None else default_hmac
            hmac = hmac or hmac is None
            rsa_padding = overrides.get_rsa_padding(
            ) if overrides.get_rsa_padding(
            ) is not None else default_rsa_padding
            hash_algorithm = overrides.get_hash_algorithm(
            ) if overrides.get_hash_algorithm(
            ) is not None else default_hash_algorithm
            num_root_certs = overrides.get_num_root_certs(
            ) if overrides.get_num_root_certs(
            ) is not None else default_num_root_certs
            max_num_root_certs = overrides.get_max_num_root_certs(
            ) if overrides.get_max_num_root_certs(
            ) is not None else default_max_num_root_certs
            mrc_index = overrides.get_mrc_index() if overrides.get_mrc_index(
            ) is not None else default_mrc_index
            secboot_version = overrides.get_secboot_version(
            ) if overrides.get_secboot_version(
            ) is not None else default_secboot_version
            dsa_type = overrides.get_dsa_type() if overrides.get_dsa_type(
            ) is not None else default_dsa_type
            ecdsa_curve = overrides.get_ecdsa_curve(
            ) if overrides.get_ecdsa_curve(
            ) is not None else default_ecdsa_curve
            key_size = overrides.get_key_size() if overrides.get_key_size(
            ) is not None else default_key_size
            exponent = overrides.get_exponent() if overrides.get_exponent(
            ) is not None else default_exponent
            client_id = overrides.get_client_id() if overrides.get_client_id(
            ) is not None else default_client_id
            lib_id = overrides.get_lib_id() if overrides.get_lib_id(
            ) is not None else default_lib_id
            UIE_server_cert_path = overrides.get_UIE_server_cert_path(
            ) if overrides.get_UIE_server_cert_path(
            ) is not None else default_UIE_server_cert_path

            # Secboot version checking
            if secboot_version is None or (
                    image_type in SECBOOT_1_IMAGE_TYPES
                    and secboot_version != SECBOOT_VERSION_1_0):
                # general properties update occurs in imageinfo's _sanitize_general_properties (like for all other config value updates)
                secboot_version = SECBOOT_VERSION_1_0
            if num_root_certs > 1 and secboot_version != SECBOOT_VERSION_1_0 and chipset not in (
                    SECBOOT_2_0_CHIPSETS + SECBOOT_3_0_CHIPSETS):
                # Multiple root certs not allowed with secboot 2.0 and greater multi-party signing
                add_error(
                    sign_id,
                    "Multiple root certs are not supported for secboot {0} chipset {1}."
                    .format(str(secboot_version), chipset))

            # Default hash algorithm to sha256
            if hash_algorithm is None:
                hash_algorithm = "sha256"

            # Backward compatibility: dsa_type is optional, so if it does not exist assume RSA
            if dsa_type is None:
                dsa_type = "rsa"

            # Manually check that ecdsa / rsa arguments exist when the corresponding
            if dsa_type == "rsa":
                if exponent is None or key_size is None:
                    add_error(
                        sign_id,
                        "You must specify exponent and key size when using RSA."
                    )
            if dsa_type == "ecdsa":
                general_properties.exponent = None
                general_properties.key_size = None
                if ecdsa_curve is None:
                    add_error(
                        sign_id,
                        "You must specify the ecdsa curve when using ECDSA.")

                # Check that ecdsa value is only used with supported chipset
                if chipset not in ECDSA_CHIPSETS:
                    add_error(
                        sign_id,
                        "ECDSA is not supported for chipset {0}.".format(
                            chipset))
            else:
                # RSAPSS requires SHA256 or SHA384
                if rsa_padding == "pss":
                    if hash_algorithm not in ["sha256", "sha384"]:
                        add_error(
                            sign_id,
                            "RSAPSS requires SHA256 or SHA384 hash. hash_algorithm={0}."
                            .format(hash_algorithm))
                    if hmac:
                        add_error(
                            sign_id,
                            "RSAPSS cannot be used with HMAC. hmac must be set as False. hmac={0}."
                            .format(hmac))
                else:
                    if not hmac:
                        add_error(sign_id, "RSAPKCS should be used with HMAC.")

            if secboot_version == SECBOOT_VERSION_3_0:
                # Secboot 3 only support sha256 and sha384
                if hash_algorithm not in ["sha256", "sha384"]:
                    add_error(
                        sign_id,
                        "Secboot {0} requires SHA256 or SHA384 hash.".format(
                            secboot_version))
                # Secboot 3 HMAC has restriction due to soc_hw_version and other values being removed from MBN header
                if hmac:
                    if mask_soc_hw_version is not None:
                        add_error(
                            sign_id,
                            "Secboot {0} requires that mask_soc_hw_version not be set when HMAC is set."
                            .format(secboot_version))
                    if in_use_soc_hw_version == 1:
                        add_error(
                            sign_id,
                            "Secboot {0} requires in_use_soc_hw_version to be set to 0 when HMAC is set."
                            .format(secboot_version))
                    if use_serial_number_in_signing == 1:
                        if serial_number is None or not multi_serial_numbers:
                            add_error(
                                sign_id,
                                "Secboot {0} requires that serial_number and first serial in multi_serial_numbers match when HMAC and use_serial_number_in_signing are set."
                                .format(secboot_version))
                        if serial_number is not None and multi_serial_numbers and serial_number != multi_serial_numbers[
                                0]:
                            add_error(
                                sign_id,
                                "Secboot {0} requires that serial_number and first serial in multi_serial_numbers match when HMAC and use_serial_number_in_signing are set.\n\t"
                                "serial_number={1} serial={2}".format(
                                    secboot_version, serial_number,
                                    multi_serial_numbers[0]))

            # TZ apps rule, must have app_id set
            if (int(sw_id, 16) & 0xFFFFFFFF) == 0xC:
                if app_id is None or int(app_id, 16) == 0:
                    add_error(
                        sign_id,
                        "app_id is not set for TZ apps: sw_id={0}.".format(
                            sw_id))
            #TODO: app_id is image specific, current rule checking will cover all the images in the config file
            """
            # other than tz, app_id must not be present
            else:
                if app_id is not None:
                    retval = False
                    error_str += '\n app_id is set for Non-TZ image: sign_id=%s, sw_id=%s, app_id=%s' % (sign_id, sw_id, app_id)
            """

            # crash_dump rule, LSB 32bits must not be greater than 1
            if crash_dump is not None and (int(crash_dump, 16)
                                           & 0xFFFFFFFF) > 1:
                add_error(
                    sign_id,
                    "crash_dump 32bit LSB must be 0 or 1: crash_dump={0}.".
                    format(crash_dump))

            if secboot_version == SECBOOT_VERSION_3_0:
                # msm_part must be provided for secboot 3 images
                if msm_part is None:
                    add_error(
                        sign_id,
                        "MSM_PART must be used to sign Secboot {0} images but MSM_PART is missing."
                        .format(secboot_version))

                # Make sure soc_vers is provided when in_use_soc_hw_version is set to 1
                if in_use_soc_hw_version == 1 and soc_vers is None:
                    add_error(
                        sign_id,
                        "IN_USE_SOC_HW_VERSION specifies SOC_VERS is used but SOC_VERS tag is missing."
                    )
            else:
                # At least one of MSM_PART or SOC_HW_VERSION must be specified
                if msm_part is None and soc_hw_version is None:
                    add_error(
                        sign_id,
                        "MSM_PART and SOC_HW_VERSION are missing from config. At least one must exist."
                    )

                # Only use Family and Device number for soc_hw_version:
                if soc_hw_version is not None and len(soc_hw_version) != 10:
                    add_error(
                        sign_id,
                        "soc_hw_version value {0} is not valid. Value must start with 0x and be 8 bytes."
                        .format(soc_hw_version))

                # Check if any sign_ids in SOC-chipset need to sign with JTAG ID
                if (soc_hw_version
                        is not None) and (chipset in JTAGID_SIGN_IDS) and (
                            sign_id in JTAGID_SIGN_IDS[chipset]) and (msm_part
                                                                      is None):
                    add_error(
                        sign_id,
                        "MSM_PART must be used to sign this image but MSM_PART is missing."
                    )

                # Assure in_use_soc_hw_version exists if both msm_part and soc_hw_version are given
                if soc_hw_version is not None and msm_part is not None and in_use_soc_hw_version is None:
                    add_error(
                        sign_id,
                        "IN_USE_SOC_HW_VERSION must exist to chose between MSM_PART and SOC_HW_VERSION."
                    )

                # in_use_soc_hw_version must exist with soc_hw_version
                if soc_hw_version is not None and in_use_soc_hw_version is None:
                    add_error(
                        sign_id,
                        "IN_USE_SOC_HW_VERSION must be set when using SOC_HW_VERSION."
                    )

                # Make sure in_use_soc_hw_version's specification exists
                if in_use_soc_hw_version == 1 and soc_hw_version is None:
                    add_error(
                        sign_id,
                        "IN_USE_SOC_HW_VERSION specifies SOC_HW_VERSION is used but SOC_HW_VERSION tag is missing."
                    )
                elif in_use_soc_hw_version == 0 and msm_part is None:
                    add_error(
                        sign_id,
                        "IN_USE_SOC_HW_VERSION specifies SOC_HW_VERSION is NOT used but MSM_PART tag is missing."
                    )

                # mask_soc_hw_version may only exist if soc_hw_version exists
                if soc_hw_version is None:
                    if mask_soc_hw_version is not None:
                        add_error(
                            sign_id,
                            "MASK_SOC_HW_VERSION can not exist without the SOC_HW_VERSION tag."
                        )

                if mask_soc_hw_version is not None and in_use_soc_hw_version == 1 and self.mask_warning is True:
                    logger.warning(
                        "The mask_soc_hw_version field is set and will mask the soc_hw_version during signing. Please ensure this is the desired result."
                    )
                    self.mask_warning = False

            # Validate soc_vers
            if soc_vers is not None:
                soc_vers_list = soc_vers.split()
                validate_hex_list(sign_id, soc_vers_list,
                                  MAX_NUM_SOC_VERS_MAP[secboot_version],
                                  "soc_vers", "soc_ver", 6)

            # use_serial_number_in_signing rule: serial number must be set
            if use_serial_number_in_signing == 1:
                if serial_number is None or int(serial_number, 16) == 0:
                    add_error(
                        sign_id,
                        "serial_number must be set when use_serial_number_in_signing is enabled."
                    )
                elif len(serial_number) > 10:
                    add_error(
                        "sign_id={0}: serial_number value must be 10 characters or less in length"
                        .format(sign_id))

            # Ensure MRC targets are properly configured to avoid OU field conflicts
            misconfigured_mrc_chipsets = get_duplicates(MRC_1_0_CHIPSETS +
                                                        MRC_2_0_CHIPSETS)
            if misconfigured_mrc_chipsets:
                raise RuntimeError(
                    "MRC 1.0 and MRC 2.0 chipsets must be mutually exclusive. The following chipsets are configured incorrectly: {0}."
                    .format(", ".join(misconfigured_mrc_chipsets)))

            # Validate MRC cert values
            if chipset in MRC_2_0_CHIPSETS and chipset in SECBOOT_2_0_DOUBLE_SIGN_CHIPSETS + SECBOOT_3_0_DOUBLE_SIGN_CHIPSETS and max_num_root_certs is None:
                add_error(
                    sign_id,
                    "max_num_root_certs must be provided for chipset \"{0}\".".
                    format(chipset))

            # MRC 1.0 support up to 4 roots, MRC 2.0 supports 1 or 4 roots
            if chipset in MRC_1_0_CHIPSETS + MRC_2_0_CHIPSETS:
                if max_num_root_certs is not None and num_root_certs > max_num_root_certs:
                    add_error(
                        sign_id,
                        "num_root_certs must be less than or equal to max_num_root_certs: num_root_certs={0}, max_num_root_certs={1}."
                        .format(num_root_certs, max_num_root_certs))
                if num_root_certs not in [1, 2, 3, 4]:
                    add_error(sign_id,
                              "num_root_certs must be in range [1-4].")
            # Legacy MRC supports up to 16 roots
            elif num_root_certs < 1 or num_root_certs > 16:
                add_error(sign_id, "num_root_certs must be in range [1-16].")

            if num_root_certs > 1 and mrc_index is None:
                add_error(
                    sign_id,
                    "mrc_index must be provided when num_root_certs is greater than 1."
                )

            if mrc_index is not None and mrc_index >= num_root_certs:
                add_error(
                    sign_id,
                    "Index out of range: mrc_index={0}, num_root_certs={1}.".
                    format(mrc_index, num_root_certs))

            # Format and validate debug
            if debug is not None:
                if len(debug) > 18:
                    add_error(
                        sign_id,
                        "Debug value must be 18 characters or less in length.")
                elif secboot_version != SECBOOT_VERSION_3_0 and len(
                        debug) < 18:
                    padding_len = 18 - len(debug)
                    debug = debug[:2] + "0" * padding_len + debug[2:]

            # Validate the multi_serial_numbers
            if len(multi_serial_numbers) > 0:
                if secboot_version == SECBOOT_VERSION_2_0:
                    if debug is None:
                        add_error(
                            sign_id,
                            "Debug serials were provides but debug field was not provided."
                        )
                    elif debug[:-8] in multi_serial_numbers:
                        add_error(
                            sign_id,
                            "Duplicate serial value of {0} in debug and multi_serial_numbers."
                            .format(debug[:-8]))
                    elif int(debug[:-8], 16) != 0:
                        multi_serial_numbers.append(debug[:-8])
                validate_hex_list(sign_id, multi_serial_numbers,
                                  MAX_NUM_SERIALS_MAP[secboot_version],
                                  "multi_serial_numbers", "serial", 10)

            # TCG rules
            if oid_min is not None and oid_max is None:
                add_error(
                    sign_id, "{0} min is set, must also set max.".format(
                        default_oid.name))
            elif oid_max is not None and oid_min is None:
                add_error(
                    sign_id, "{0} max is set, must also set min.".format(
                        default_oid.name))
            elif default_oid is not None:
                # Move the min > max checking to signer. It should be validated after valid 32
                # bit integer is checked. Otherwise, int() conversion will throw an exception

                oid_min_config_str = oid_min
                oid_max_config_str = oid_max
                if oid_min_config_str and oid_max_config_str:
                    oid_min = int(oid_min,
                                  16) if "0x" in oid_min else int(oid_min)
                    oid_max = int(oid_max,
                                  16) if "0x" in oid_max else int(oid_max)

                    if oid_min > oid_max:
                        add_error(
                            sign_id,
                            "{0} min must be less than max, min={1} max={2}.".
                            format(default_oid.name, oid_min_config_str,
                                   oid_max_config_str))
                if int(sw_id, 16) != 0:
                    add_error(
                        sign_id,
                        "For {0}, sw_id must be 0, sw_id = {1}.".format(
                            default_oid.name, sw_id))
                if int(msm_part, 16) != 0:
                    add_error(
                        sign_id,
                        "For {0}, msm_part must be 0, msm_part = {1}.".format(
                            default_oid.name, msm_part))
                if int(oem_id, 16) != 0:
                    add_error(
                        sign_id,
                        "For {0}, oem_id must be 0, oem_id = {1}.".format(
                            default_oid.name, oem_id))
                if int(model_id, 16) != 0:
                    add_error(
                        sign_id,
                        "For {0}, model_id must be 0, model_id = {1}.".format(
                            default_oid.name, model_id))
                if int(debug, 16) != 2:
                    add_error(
                        sign_id,
                        "For {0}, debug must be 2, debug = {1}.".format(
                            default_oid.name, debug))

            if client_id is not None and int(client_id, 16) == 0:
                add_error(
                    sign_id,
                    "client_id must be a non-zero value, client_id={0}.".
                    format(client_id))
            if lib_id is not None and int(lib_id, 16) == 0:
                add_error(
                    sign_id,
                    "lib_id must be a non-zero value, lib_id={0}.".format(
                        lib_id))

            if UIE_server_cert_path and c_path.validate_file(
                    UIE_server_cert_path) is False:
                add_error(
                    sign_id,
                    "UIE_server_cert_path is invalid, path={0}".format(
                        UIE_server_cert_path))

        return retval[0], "".join(remove_duplicates(errors))
Exemplo n.º 6
0
    def validate(self, images, *args):
        def add_error(sign_id_, error):
            retval[0] = False
            errors.append("\nsign_id={0}: ".format(sign_id_) + error)

        assert (isinstance(images, complex_images_list))

        retval = [True]
        errors = []

        # expect args[0] to be instance of signing
        # the following default signing attributes are checked if signing is TCG
        assert (isinstance(args[0], complex_general_properties))
        general_properties = args[0]
        defaults = Attributes()
        for gp_name, gp_instance in vars(defaults).items():
            if not isinstance(gp_instance, StandardAttribute):
                continue
            setattr(defaults, gp_name,
                    getattr(general_properties, "get_" + gp_name)())

        resolve_enumerated(defaults, DEBUG_TAG)

        default_oid_min = None if defaults.object_id is None else defaults.object_id.min
        default_oid_max = None if defaults.object_id is None else defaults.object_id.max

        assert (isinstance(args[1], complex_metadata))
        chipset = args[1].get_chipset()

        for image in images.get_image():
            sign_id = image.get_sign_id()
            overrides = image.get_general_properties_overrides()
            attributes = Attributes()

            for gp_name, gp_instance in vars(attributes).items():
                if not isinstance(gp_instance, StandardAttribute):
                    continue
                value = getattr(overrides, "get_" + gp_name)()
                setattr(attributes, gp_name,
                        getattr(defaults, gp_name) if value is None else value)

            resolve_enumerated(attributes, DEBUG_TAG)

            if attributes.object_id is None:
                oid_min = default_oid_min
                oid_max = default_oid_max
            else:
                oid = attributes.object_id
                oid_min = oid.min
                oid_max = oid.max

            # Sanitize secboot_version
            if (attributes.secboot_version is None
                    or image.get_image_type() in SECBOOT_1_IMAGE_TYPES):
                attributes.secboot_version = SECBOOT_VERSION_1_0

            self.sanitize_soc_vers(sign_id, attributes, add_error)

            if (attributes.num_root_certs > 1
                    and attributes.secboot_version != SECBOOT_VERSION_1_0
                    and chipset
                    not in (SECBOOT_2_0_CHIPSETS + SECBOOT_3_0_CHIPSETS)):
                # Multiple root certs not allowed with secboot 2.0 and greater multi-party signing
                add_error(
                    sign_id,
                    "Multiple root certs are not supported for Secure Boot {0} chipset {1}."
                    .format(str(attributes.secboot_version), chipset))

            if attributes.dsa_type == "ecdsa":
                # Check that ecdsa value is only used with supported chipset
                if chipset not in ECDSA_CHIPSETS:
                    add_error(
                        sign_id,
                        "ecdsa is not supported for chipset {0}.".format(
                            chipset))
            else:
                # RSAPSS requires SHA256 or SHA384
                if attributes.rsa_padding == "pss":
                    if attributes.hash_algorithm not in ["sha256", "sha384"]:
                        add_error(
                            sign_id,
                            "rsapss requires 'sha256' or 'sha384' hash. hash_algorithm={0}."
                            .format(attributes.hash_algorithm))
                    if attributes.hmac:
                        add_error(
                            sign_id,
                            "rsapss cannot be used with hmac. hmac must be set as False. hmac={0}."
                            .format(attributes.hmac))
                else:
                    if not attributes.hmac:
                        add_error(sign_id, "rsapkcs should be used with hmac.")

            # TZ apps rule, must have app_id set
            if is_TA(attributes.sw_id):
                if int(attributes.app_id, 16) == 0:
                    add_error(
                        sign_id,
                        "app_id is not set for TZ apps: sw_id={0}.".format(
                            attributes.sw_id))

            # Ensure MRC targets are properly configured to avoid OU field conflicts
            misconfigured_mrc_chipsets = get_duplicates(MRC_1_0_CHIPSETS +
                                                        MRC_2_0_CHIPSETS)
            if misconfigured_mrc_chipsets:
                raise RuntimeError(
                    "MRC 1.0 and MRC 2.0 chipsets must be mutually exclusive. The following chipsets "
                    "are configured incorrectly: {0}.".format(
                        ", ".join(misconfigured_mrc_chipsets)))

            # MRC 1.0 support up to 4 roots, MRC 2.0 supports 1 or 4 roots
            if chipset in MRC_1_0_CHIPSETS + MRC_2_0_CHIPSETS:
                if attributes.num_root_certs > attributes.max_num_root_certs:
                    add_error(
                        sign_id,
                        "num_root_certs must be less than or equal to max_num_root_certs: "
                        "num_root_certs={0}, max_num_root_certs={1}.".format(
                            attributes.num_root_certs,
                            attributes.max_num_root_certs))
                if attributes.num_root_certs not in [1, 2, 3, 4]:
                    add_error(sign_id,
                              "num_root_certs must be in range [1-4].")
            # Legacy MRC supports up to 16 roots
            elif attributes.num_root_certs < 1 or attributes.num_root_certs > 16:
                add_error(sign_id, "num_root_certs must be in range [1-16].")

            if attributes.mrc_index >= attributes.num_root_certs:
                add_error(
                    sign_id,
                    "Index out of range: mrc_index={0}, num_root_certs={1}.".
                    format(attributes.mrc_index, attributes.num_root_certs))

            # Ensure num_certs_in_certchain does not exceed max_num_certs_in_certchain
            if attributes.num_certs_in_certchain > attributes.max_num_certs_in_certchain:
                add_error(
                    sign_id,
                    "num_certs_in_certchain must be less than or equal to max_num_certs_in_certchain: "
                    "num_certs_in_certchain={0}, max_num_certs_in_certchain={1}."
                    .format(attributes.num_certs_in_certchain,
                            attributes.max_num_certs_in_certchain))

            # TCG rules
            if oid_min is not None and oid_max is None:
                add_error(
                    sign_id, "{0} min is set, must also set max.".format(
                        defaults.object_id.name))
            elif oid_max is not None and oid_min is None:
                add_error(
                    sign_id, "{0} max is set, must also set min.".format(
                        defaults.object_id.name))
            elif defaults.object_id is not None:
                # Move the min > max checking to signer. It should be validated after valid 32
                # bit integer is checked. Otherwise, int() conversion will throw an exception

                oid_min_config_str = oid_min
                oid_max_config_str = oid_max
                if oid_min_config_str and oid_max_config_str:
                    oid_min = int(
                        oid_min,
                        16) if oid_min.startswith("0x") else int(oid_min)
                    oid_max = int(
                        oid_max,
                        16) if oid_max.startswith("0x") else int(oid_max)

                    if oid_min > oid_max:
                        add_error(
                            sign_id,
                            "{0} min must be less than max, min={1} max={2}.".
                            format(defaults.object_id.name, oid_min_config_str,
                                   oid_max_config_str))
                if int(attributes.sw_id, 16) != 0:
                    add_error(
                        sign_id,
                        "For {0}, sw_id must be 0, sw_id = {1}.".format(
                            defaults.object_id.name, attributes.sw_id))
                if int(attributes.msm_part, 16) != 0:
                    add_error(
                        sign_id,
                        "For {0}, msm_part must be 0, msm_part = {1}.".format(
                            defaults.object_id.name, attributes.msm_part))
                if int(attributes.oem_id, 16) != 0:
                    add_error(
                        sign_id,
                        "For {0}, oem_id must be 0, oem_id = {1}.".format(
                            defaults.object_id.name, attributes.oem_id))
                if int(attributes.model_id, 16) != 0:
                    add_error(
                        sign_id,
                        "For {0}, model_id must be 0, model_id = {1}.".format(
                            defaults.object_id.name, attributes.model_id))
                if int(attributes.debug, 16) != 2:
                    add_error(
                        sign_id,
                        "For {0}, debug must be 2, debug = {1}.".format(
                            defaults.object_id.name, attributes.debug))

            if attributes.client_id and int(attributes.client_id, 16) == 0:
                add_error(
                    sign_id,
                    "client_id must be a non-zero value, client_id={0}.".
                    format(attributes.client_id))
            if attributes.lib_id and int(attributes.lib_id, 16) == 0:
                add_error(
                    sign_id,
                    "lib_id must be a non-zero value, lib_id={0}.".format(
                        attributes.lib_id))

            if (attributes.UIE_server_cert_path and c_path.validate_file(
                    attributes.UIE_server_cert_path) is False):
                add_error(
                    sign_id,
                    "UIE_server_cert_path is invalid, path={0}".format(
                        attributes.UIE_server_cert_path))

        return retval[0], "".join(sorted(remove_duplicates(errors)))