Пример #1
0
    def __init__(self, debug_dir, hash_algorithm, data=None, images=None):
        self.debug_dir = debug_dir
        self._initialize(hash_algorithm, images)

        # Validate hash algorithm
        if self.hash_algorithm not in ENCODE_HASH_ALGO:
            raise RuntimeError(multi_image_string() + " segment does not support configured segment_hash_algorithm {0}".format(self.hash_algorithm))

        # Validate that required information is provided
        if data is None and not images:
            raise RuntimeError("When creating a " + multi_image_string() + " segment at least one of the following must be provided:\n"
                               "\t1) An existing " + multi_image_string() + " segment\n"
                               "\t2) Images to add to (or update) in the " + multi_image_string() + " segment")

        if data:
            self._unpack(data)
        if images:
            self._update()
Пример #2
0
 def __repr__(self):
     def segment_properties(seg, segment_name):
         if seg:
             return segment_name + ' Segment Properties: ' + '\n' + repr(seg) + '\n'
         else:
             return ''
     return ('Base Properties: ' + '\n' + properties_repr(self._repr_properties()) + '\n'
             'ELF Properties: ' + '\n' + repr(self._elf_parsegen) + '\n'
             'Hash Segment Properties: ' + '\n' + repr(self._mbn_parsegen) + '\n' +
             segment_properties(self._multi_image_segment, multi_image_string()))
Пример #3
0
    def _update(self):
        def get_hash(data):
            from sectools.features.isc.signer.utils.hmac import HMAC
            h = HMAC.HASH_ALGO_MAP[self.hash_algorithm]()
            h.update(data)
            return h.digest()

        for image in self.images_to_add_or_update:
            sw_id = int(image.imageinfo.sw_id, 16)
            app_id = image.imageinfo.app_id
            app_id_normalized = int(app_id, 16) if app_id is not None else 0
            data = image.get_multi_image_entry_data(image.authority)
            if not data:
                raise RuntimeError("Cannot add image entry to " + multi_image_string() + " segment for image with SW_ID={0} because it has no hash segment.".format(hex(sw_id)))
            # Update existing hash entry
            if (sw_id, app_id_normalized) in self.image_hash_dict.keys():
                if app_id is None:
                    logger.info("Updated " + multi_image_string() + " entry for image with SW_ID={0}".format(hex(sw_id)))
                else:
                    logger.info("Updated " + multi_image_string() + " entry for image with SW_ID={0} and APP_ID={1}".format(hex(sw_id), hex(app_id_normalized)))
            # Add new hash entry
            else:
                if app_id is None:
                    logger.info("Added " + multi_image_string() + " entry for image with SW_ID={0}".format(hex(sw_id)))
                else:
                    logger.info("Added " + multi_image_string() + " entry for image with SW_ID={0} and APP_ID={1}".format(hex(sw_id), hex(app_id_normalized)))
            self.image_hash_dict[(sw_id, app_id_normalized)] = get_hash(data)
        if len(self.image_hash_dict) > MAX_NUM_IMAGES:
            raise RuntimeError(multi_image_string() + " segment cannot contains {0} image entries."
                               "\nMaximum allowed number of images entries is {1}.".format(len(self.image_hash_dict), MAX_NUM_IMAGES))
Пример #4
0
    def _unpack(self, data):
        # Validate size of segment is not smaller than allowed minimum
        min_size_of_hash_entry = min(HASH_ALGO_TO_SIZE_MAP.values())
        min_size = self._get_fixed_size() + self._get_id_size() + min_size_of_hash_entry
        if len(data) < min_size:
            raise RuntimeError(multi_image_string() + " segment is of invalid size {0} bytes."
                               "\nMinimum allowed size is {1} bytes.".format(len(data), min_size))

        # Extract segment header
        offset = 0
        end = self._get_fixed_size()
        (self.magic_number,
         self.version,
         self.res0, self.res1, self.res2, self.res3, self.res4, self.res5, self.res6, self.res7, self.res8, self.res9,
         self.res10, self.res11, self.res12, self.res13, self.res14, self.res15, self.res16, self.res17, self.res18, self.res19, self.res20,
         self.res21, self.res22, self.res23, self.res24, self.res25, self.res26, self.res27, self.res28, self.res29, self.res30, self.res31,
         num_images,
         hash_algorithm,) = struct.unpack(self._get_fixed_format(), data[offset:end])

        # Validate extracted values
        if self.magic_number != MAGIC_NUM:
            raise RuntimeError(multi_image_string() + " segment contains invalid magic number {0}."
                               "\nMagic number must be {1}.".format(self.magic_number, MAGIC_NUM))
        if self.version != MULT_IMAGE_VERSION_0:
            raise RuntimeError(multi_image_string() + " segment contains invalid version number {0}."
                               "\nSupported version are: {1}.".format(self.version, SUPPORTED_VERSIONS))
        if num_images > MAX_NUM_IMAGES:
            raise RuntimeError(multi_image_string() + " segment contains {0} image entries."
                               "\nMaximum allowed number of images entries is {1}.".format(num_images, MAX_NUM_IMAGES))
        if hash_algorithm not in DECODE_HASH_ALGO:
            raise RuntimeError(multi_image_string() + " segment contains invalid hash algorithm value {0}."
                               "\nAllowed hash algorithm values are {1}.".format(hash_algorithm, DECODE_HASH_ALGO.keys()))
        elif DECODE_HASH_ALGO[hash_algorithm] != self.hash_algorithm:
            raise RuntimeError(multi_image_string() + " segment was created using {0} but segment_hash_algorithm is configured to {1}."
                               "\nChange configured segment_hash_algorithm value to {0}.".format(DECODE_HASH_ALGO[hash_algorithm], self.hash_algorithm))
        # Validate segment size
        expected_size = self._get_fixed_size() + (self._get_id_size() + HASH_ALGO_TO_SIZE_MAP[self.hash_algorithm]) * num_images
        if expected_size < len(data):
            raise RuntimeError(multi_image_string() + " segment is of invalid size {0} bytes."
                               "\nSegment containing {1} {2} image entries should be {} bytes.".format(len(data), num_images, self.hash_algorithm, expected_size))

        # Extract sw_id/app_id and hash values
        for i in range(num_images):
            offset = end
            end += self._get_id_size()
            (sw_id, app_id,) = struct.unpack(self._get_id_format(), data[offset:end])
            hash_size = HASH_ALGO_TO_SIZE_MAP[self.hash_algorithm]
            offset = end
            end += hash_size
            image_hash = data[offset:end]
            self.image_hash_dict[(sw_id, app_id)] = image_hash

        store_debug_data_to_file(FILE_EXTRACTED, data[0:end], self.debug_dir)
        store_debug_data_to_file(FILE_EXTRACTED_READABLE, str(self), self.debug_dir)
Пример #5
0
 def get_multi_image_entry_data(self, authority):
     logger.debug("Getting data to hash for " + authority + " " +
                  multi_image_string() + " entry")
     try:
         if self.is_signed():
             return self.data_to_sign
         else:
             header = self._mbn_parsegen.header
             # Copy the MBN header so that masking doesn't alter original header
             header = copy_header(header)
             # Mask metadata and sig/cert sizes of other authority
             header = self.utils.mask_header_values(header, self.authority)
             return header.pack() + self._mbn_parsegen.code
     except:
         return None
Пример #6
0
    def _extract_existing_multi_image_segment(self):
        multi_image_segment, multi_image_entry = None, None
        # Find the phdr entry for the multi image segment
        for phdr in self._elf_parsegen.phdrs:
            if phdr.p_type == PT_LOAD:
                if multi_image_entry is None:
                    multi_image_entry = phdr
                    self.mem_size = phdr.p_memsz
                else:
                    raise RuntimeError(multi_image_string() + " image contains "
                                       "multiple LOAD segments.\n       "
                                       "Only 1 LOAD segment is allowed to exist.")

        # Extract segment data and remove segment
        if multi_image_entry:
            multi_image_segment = self._elf_parsegen.get_segment_data(multi_image_entry)
            self._elf_parsegen.remove_segment(multi_image_entry)
        return multi_image_segment
Пример #7
0
    def _validate_properties(self):
        self.errors = []
        sa = self.signing_attributes

        if not POLICY_OEM_ID_0.is_ignore():
            if int(sa.oem_id, 16) == 0:
                POLICY_OEM_ID_0.run('OEM ID is set to 0 for sign_id "' +
                                    str(self.sign_id) + '"')

        # Secboot v1 requires oem permissions only
        if sa.secboot_version == SECBOOT_VERSION_1_0:
            if not sa.oem_sign:
                # oem_sign cannot be false for secboot v1
                self._add_error(
                    'OEM operations cannot be disabled for a Secure Boot ' +
                    str(SECBOOT_VERSION_1_0) + ' image.')
            if sa.qti_sign:
                # qti_sign cannot be true for secboot v1
                self._add_error(
                    'Cannot perform QTI operations on a Secure Boot ' +
                    str(SECBOOT_VERSION_1_0) + ' image.')
        # If all authority permissions are disabled, throw error
        elif not sa.qti_sign and not sa.oem_sign:
            self._add_error(
                'Cannot perform image operations because OEM and QTI operations are disabled for image.'
            )

        # Raise warnings for Secboot v2.1 and greater chipsets
        if self.chipset in SECBOOT_2_0_DOUBLE_SIGN_CHIPSETS + SECBOOT_3_0_DOUBLE_SIGN_CHIPSETS:
            if int(sa.rot_en, 16) == 1:
                logger.warning(
                    "rot_en should not be set to \"{0}\" for chipset \"{1}\".".
                    format(sa.rot_en, self.chipset))
            if sa.hash_algorithm == "sha1":
                logger.warning(
                    "hash_algorithm should not be set to \"{0}\" for chipset \"{1}\"."
                    .format(sa.hash_algorithm, self.chipset))
            if sa.exponent == 3:
                logger.warning(
                    "exponent should not be set to \"{0}\" for chipset \"{1}\"."
                    .format(sa.exponent, self.chipset))

            if sa.dsa_type == "ecdsa":
                sa.rsa_padding = None
            else:
                if sa.rsa_padding == "pkcs":
                    logger.warning(
                        "rsa_padding should not be set to RSAPKCS for chipset \"{0}\"."
                        .format(self.chipset))

        # Ignore max_num_root_certs value if target is not MRC v2.0 double sign target
        if not (self.chipset in MRC_2_0_CHIPSETS and sa.qti_sign
                and sa.oem_sign):
            sa.max_num_root_certs = None

        # Ignore max_num_certs_in_certchain if image is not double signable
        if not (sa.qti_sign and sa.oem_sign):
            sa.max_num_certs_in_certchain = None

        if self.is_multi_image and sa.multi_image_segment_addr is None:
            self._add_error(
                advanced_defines.multi_image_string() +
                " operation requires multi_image_segment_addr config value.")

        if sa.secboot_version == SECBOOT_VERSION_3_0:
            # Secboot 3 only support sha256 and sha384
            for attr_name in ["hash_algorithm", "segment_hash_algorithm"]:
                if getattr(sa, attr_name) not in ["sha256", "sha384"]:
                    self._add_error(
                        "Secure Boot {0} requires 'sha256' or 'sha384' {1}.".
                        format(sa.secboot_version, attr_name))

        multi_serial_numbers = sa.multi_serial_numbers.serial if sa.multi_serial_numbers is not None else []

        self._validate_serial_bound_value(sa.crash_dump,
                                          "crash_dump",
                                          chipset=self.chipset,
                                          ignore_num_root_certs=True,
                                          allowed_lsb_values=[0, 1])

        self._validate_serial_bound_value(
            sa.rot_en,
            "rot_en",
            chipset=self.chipset,
            ignore_num_root_certs=True,
            disable_in_value_binding=sa.secboot_version == SECBOOT_VERSION_3_0,
            additional_serials_are_bindable=len(multi_serial_numbers) > 0,
            allowed_lsb_values=[0, 1])

        # Validate uie_key_switch_enable
        self._validate_serial_bound_value(
            sa.uie_key_switch_enable,
            "uie_key_switch_enable",
            chipset=self.chipset,
            ignore_num_root_certs=True,
            disable_in_value_binding=sa.secboot_version == SECBOOT_VERSION_3_0,
            additional_serials_are_bindable=len(multi_serial_numbers) > 0)

        # MRC 1.0 use case
        # Validate revocation_enablement
        self._validate_serial_bound_value(sa.revocation_enablement,
                                          "revocation_enablement",
                                          chipset=self.chipset,
                                          allowed_chipsets=MRC_1_0_CHIPSETS,
                                          num_root_certs=sa.num_root_certs)
        # Validate activation_enablement
        self._validate_serial_bound_value(sa.activation_enablement,
                                          "activation_enablement",
                                          chipset=self.chipset,
                                          allowed_chipsets=MRC_1_0_CHIPSETS,
                                          num_root_certs=sa.num_root_certs)
        # MRC 2.0 use case
        # Validate root_revoke_activate_enable
        self._validate_serial_bound_value(
            sa.root_revoke_activate_enable,
            "root_revoke_activate_enable",
            chipset=self.chipset,
            allowed_chipsets=MRC_2_0_CHIPSETS,
            num_root_certs=sa.num_root_certs,
            disable_in_value_binding=sa.secboot_version == SECBOOT_VERSION_3_0,
            additional_serials_are_bindable=len(multi_serial_numbers) > 0)

        self._validate_serial_bound_value(
            sa.debug,
            "debug",
            chipset=self.chipset,
            ignore_num_root_certs=True,
            disable_in_value_binding=sa.secboot_version == SECBOOT_VERSION_3_0,
            additional_serials_are_bindable=len(multi_serial_numbers) > 0,
            allowed_lsb_values=[0, 2, 3]
            if sa.secboot_version != SECBOOT_VERSION_3_0 else None,
            require_serial_number=(self.verbatim_config
                                   or len(self.valid_serial_numbers) == 0))

        if self.errors:
            raise RuntimeError("".join(self.errors))
Пример #8
0
from sectools.features.isc.encryption_service.unified.encdec import UIE_2_0_L2_1_2_IDENT
from sectools.features.isc.encryption_service.unified.encdec import UNIFIED_ENCRYPTION_IDENT
from .imageinfo_base import DestImagePathBase
from .imageinfo_base import ImageInfoBase
from .imageinfo_base import ImageStatusBase
from .imageinfo_base import debug_only
from .imageinfo_utils import StatusInfo
from .imageinfo_utils import resolve_enumerated
from .serial_binding_features import MAX_NUM_SERIALS_MAP
from .serial_binding_features import SerialBoundFeatureSetContextManager
from ..cfgparser import auto_gen_obj_config as agoc
from ..cfgparser import defines as cfgdef
from ..parsegen.config import auto_gen_obj_config as pgagoc

POLICY_OEM_ID_0 = ValPolicy(ValPolicy.WARN)
MULTI_IMAGE_FILENAME = advanced_defines.multi_image_string() + " image"
OEM_MULTI_IMAGE_SIGN_ID = "multi_image"
QTI_MULTI_IMAGE_SIGN_ID = "multi_image_qti"
MULTI_IMAGE_SIGN_ID = {
    defines.AUTHORITY_OEM: OEM_MULTI_IMAGE_SIGN_ID,
    advanced_defines.AUTHORITY_QTI: QTI_MULTI_IMAGE_SIGN_ID,
}

MAX_NUM_SOC_VERS_10 = 10
MAX_NUM_SOC_VERS_12 = 12
MAX_NUM_SOC_VERS_MAP = {
    SECBOOT_VERSION_1_0: MAX_NUM_SOC_VERS_10,
    SECBOOT_VERSION_2_0: MAX_NUM_SOC_VERS_10,
    SECBOOT_VERSION_3_0: MAX_NUM_SOC_VERS_12
}
Пример #9
0
    def __init__(self,
                 image_path,
                 img_config_parser,
                 parsegen_config,
                 authority,
                 sign_id=None,
                 gen_multi_image=False,
                 multi_image_path=None,
                 crypto_params={},
                 imageinfo_class=None,
                 verbatim_config=False,
                 disable_serial_binding=False,
                 platform_binding=None):

        assert isinstance(image_path, str)
        assert isinstance(img_config_parser, ConfigParser)
        assert isinstance(parsegen_config, ParsegenCfgParser)
        if sign_id is not None: assert isinstance(sign_id, str)

        # Initialize the BaseStager
        super(ImagePathsStager, self).__init__(authority)

        # Validate that the image path exists
        image_path = c_path.normalize(image_path)
        if not c_path.validate_file(image_path):
            raise RuntimeError('No read access to the image path: ' +
                               image_path)
        # Put the image info object into the list
        imageinfo = self._create_imageinfo(
            img_config_parser,
            parsegen_config,
            sign_id,
            image_path,
            gen_multi_image=False,
            crypto_params=crypto_params,
            imageinfo_class=imageinfo_class,
            verbatim_config=verbatim_config,
            disable_serial_binding=disable_serial_binding,
            platform_binding=platform_binding)
        self._image_info_list.append(imageinfo)

        # Validate that the Multi-Image Sign & Integrity image path exists
        if multi_image_path is not None:
            multi_image_path = c_path.normalize(multi_image_path)
            if not c_path.validate_file(multi_image_path):
                raise RuntimeError('No read access to the ' +
                                   multi_image_string() + ' image path: ' +
                                   multi_image_path)
            # Set sign id to Multi-Image image's sign id
            sign_id = MULTI_IMAGE_SIGN_ID[authority]
            # Set the Multi-Image Signing & Integrity image's imageinfo
            multi_image_imageinfo = self._create_imageinfo(
                img_config_parser,
                parsegen_config,
                sign_id=sign_id,
                image_path=multi_image_path,
                gen_multi_image=False,
                imageinfo_class=imageinfo_class,
                platform_binding=platform_binding)
            self._multi_image_imageinfo_dict[
                multi_image_imageinfo.chipset] = multi_image_imageinfo
        # Create image info object for to-be-created Multi-Image Signing and Integrity image
        elif gen_multi_image:
            # Set sign id to Multi-Image Sign & Integrity image's sign id
            sign_id = MULTI_IMAGE_SIGN_ID[authority]
            # Set the Multi-Image Signing & Integrity image's imageinfo
            multi_image_imageinfo = self._create_imageinfo(
                img_config_parser,
                parsegen_config,
                sign_id,
                None,
                gen_multi_image,
                imageinfo_class=imageinfo_class,
                platform_binding=platform_binding)
            self._multi_image_imageinfo_dict[
                multi_image_imageinfo.chipset] = multi_image_imageinfo
Пример #10
0
def print_summary(args, image_info_list, multi_image_imageinfo_list):
    """Prints the summary of the actions performed by SecImage"""

    if not image_info_list:
        return

    # Check which actions were performed
    actions = []
    multi_image_actions = []

    if args.no_op:
        actions.append('parse')
    if args.integrity_check:
        actions.append('integrity_check')
    if args.sign:
        actions.append('sign')
    if args.encrypt:
        actions.append('encrypt')
    if args.validate:
        actions.append('validate')

    if multi_image_imageinfo_list:
        if args.m_integrity_check:
            multi_image_actions.append('integrity_check')
        if args.m_sign:
            multi_image_actions.append('sign')
        if args.m_encrypt:
            multi_image_actions.append('encrypt')
        if args.m_validate:
            multi_image_actions.append('validate')

    if not (actions + multi_image_actions):
        return

    # Figure out the output directory
    output_print = (('Output is saved at: ' + args.output_dir +
                     '\n') if args.output_dir else
                    ('Minimized build was updated at: ' + args.mini_build +
                     '\n') if args.mini_build else '\n')

    # Log the actions and output directory
    actions_str = ('Following actions were performed: "' + ', '.join(actions) +
                   '"' + '\n') if actions else ''
    multi_image_actions_str = ('Following ' + multi_image_string() +
                               ' actions were performed: "' +
                               ', '.join(multi_image_actions) + '"' +
                               '\n') if multi_image_actions else ''
    logger.info('SUMMARY:' + '\n' + actions_str + multi_image_actions_str +
                output_print)

    # Table information
    summary_table = TablePrinter([1])
    # summary_table = TablePrinter([0])
    COLUMN_IDX = 0
    COLUMN_SIGN_ID = 1
    COLUMN_PARSE = 2
    COLUMN_INTEGRITY_CHECK = 3
    COLUMN_SIGN = 4
    COLUMN_ENCRYPT = 5
    COLUMN_VAL_PARSE = 6
    COLUMN_VAL_INTEGRITY_CHECK = 7
    COLUMN_VAL_SIGN = 8
    COLUMN_VAL_ENCRYPT = 9

    # First row
    summary_table.insert_data(0, COLUMN_IDX, 'Idx')
    summary_table.insert_data(0, COLUMN_SIGN_ID, 'SignId')
    summary_table.insert_data(0, COLUMN_PARSE, 'Parse')
    summary_table.insert_data(0, COLUMN_INTEGRITY_CHECK, 'Integrity')
    summary_table.insert_data(0, COLUMN_SIGN, 'Sign')
    summary_table.insert_data(0, COLUMN_ENCRYPT, 'Encrypt')
    summary_table.insert_data(0,
                              COLUMN_VAL_PARSE,
                              'Validate',
                              column_end=COLUMN_VAL_ENCRYPT)

    # Second row
    summary_table.insert_data(1, COLUMN_VAL_PARSE, 'Parse')
    summary_table.insert_data(1, COLUMN_VAL_INTEGRITY_CHECK, 'Integrity')
    summary_table.insert_data(1, COLUMN_VAL_SIGN, 'Sign')
    summary_table.insert_data(1, COLUMN_VAL_ENCRYPT, 'Encrypt')

    # Data rows
    for idx, image in enumerate(image_info_list +
                                list(multi_image_imageinfo_list)):
        idx += 2
        summary_table.insert_data(idx, COLUMN_IDX, str(idx - 1) + '.')
        summary_table.insert_data(idx, COLUMN_SIGN_ID, image.sign_id)
        summary_table.insert_data(idx, COLUMN_PARSE,
                                  image.status.parsegen.state)
        summary_table.insert_data(idx, COLUMN_INTEGRITY_CHECK,
                                  image.status.integrity_check.state)
        summary_table.insert_data(idx, COLUMN_SIGN, image.status.sign.state)
        summary_table.insert_data(idx, COLUMN_ENCRYPT,
                                  image.status.encrypt.state)
        summary_table.insert_data(idx, COLUMN_VAL_PARSE,
                                  image.status.validate_parsegen.state)
        summary_table.insert_data(idx, COLUMN_VAL_INTEGRITY_CHECK,
                                  image.status.validate_integrity_check.state)
        summary_table.insert_data(idx, COLUMN_VAL_SIGN,
                                  image.status.validate_sign.state)
        summary_table.insert_data(idx, COLUMN_VAL_ENCRYPT,
                                  image.status.validate_encrypt.state)

    logger.info(summary_table.get_data())
Пример #11
0
    def c_validate(self):
        """Validates the command line args provided by the user.

        :raises: RuntimeError if any error occurs.
        """
        args = self.parsed_args
        err = []

        # Check the input files
        if ((args.image_file and args.meta_build)
                or (not args.image_file and not args.meta_build)):
            err.append(
                'Provide either image_file or a meta_build for processing.')

        # Check that m_image_file and meta_build are not both provided
        if args.meta_build and args.m_image_file:
            err.append('--m_image_file cannot be provided with meta_build.')
            err.append('Provide --m_gen flag if ' + multi_image_string() +
                       ' file generation is desired.')

        # Check that m_gen and m_image_file are not both provided
        if args.m_gen and args.m_image_file:
            err.append('Provide either --m_image_file or --m_gen.')

        # Check that --override flag is not given without help flag
        if args.overrides and not args.help:
            err.append(
                '-h flag must accompany --overrides flag to view overridable properties'
            )

        # Check if the meta build supports sign id
        meta_supports_sign_id = False
        if args.meta_build:
            meta_supports_sign_id = SecImageCore.meta_supports_sign_id(
                args.meta_build)

        # Check the configuration option and output dir
        if args.image_file or (args.meta_build and not meta_supports_sign_id):
            if ((args.chipset and args.config_path)
                    or (not args.chipset and not args.config_path)):
                err.append(
                    'Provide either chipset or a config_path to process images.'
                )
            if not args.output_dir:
                err.append('Provide the output_dir for storing the output.')
        elif args.meta_build and not meta_supports_sign_id:
            if not args.output_dir and not args.mini_build:
                err.append(
                    'Provide either output_dir or mini_build for storing the output.'
                )

        if args.integrity_check or args.sign or args.encrypt:
            args.validate = True
        elif not (args.decrypt or args.validate or args.verify_inputs
                  or args.no_op):
            err.append('Specify one or more operations to perform.')

        # Check that multi-image operations are enabled when m_gen or m_image_file are provided
        if args.m_image_file and not (args.m_integrity_check or args.m_sign
                                      or args.m_encrypt or args.m_decrypt
                                      or args.m_validate):
            err.append('Specify one or more ' + multi_image_string() +
                       ' image operations to perform.')
        if args.m_gen and not (args.m_integrity_check or args.m_sign
                               or args.m_encrypt):
            err.append('Specify one or more ' + multi_image_string() +
                       ' image operations to perform.')

        # Check that multi-image operations are not enabled when m_gen and m_image_file are missing
        if not (args.m_gen or args.m_image_file) and (
                args.m_integrity_check or args.m_sign or args.m_encrypt
                or args.m_decrypt or args.m_validate):
            err.append(
                'Provide either --m_image_file or --m_gen when performing ' +
                multi_image_string() + ' image operations.')

        # When m_gen, m_integrity_check, m_sign or m_encrypt is enabled, enforce m_validate
        if args.m_integrity_check or args.m_sign or args.m_encrypt:
            args.m_validate = True

        # Check that no_op operation is only enabled when m_gen or m_image_file are provided
        if args.no_op and not (args.m_gen or args.m_image_file):
            err.append(
                'Provide either --m_image_file or --m_gen when adding image entry to '
                + multi_image_string() + ' image.')

        # Check that no_op operation is not provided with any other individual image operations
        if args.no_op and (args.integrity_check or args.sign or args.encrypt
                           or args.decrypt or args.validate):
            err.append(
                'no_op operation cannot be performed alongside other image operations'
            )

        if args.rch in rch_string and not args.qti_signing:
            err.append(
                comma_separated_string(rch_string, final_separator='and') +
                ' root certificate hash validation is not supported for OEM signatures'
            )

        # Check sign_attr is only set when adding hash table
        if args.sign_attr and not (args.integrity_check or args.sign):
            err.append(
                'sign_attr operation can only be performed when integrity_check or sign are being performed.'
            )

        # Check m_sign_attr is only set when adding hash table
        if args.m_sign_attr and not (args.m_integrity_check or args.m_sign):
            err.append(
                'm_sign_attr operation can only be performed when m_integrity_check or m_sign are being performed.'
            )

        # --verbatim_config and --serial_numbers are mutually exclusive.
        if args.verbatim_config and args.serial_numbers:
            err.append(
                '--verbatim_config cannot be provided with --serial_numbers.')

        # Check and sanitize any paths for read access
        for path in ['image_file', 'config_path']:
            path_val = getattr(args, path, None)
            if path_val:
                path_val = c_path.normalize(path_val)
                if not c_path.validate_file(path_val):
                    err.append('Cannot access ' + path + ' at: ' + path_val)
                setattr(args, path, path_val)

        # Check and sanitize any paths for read dir access
        for path in ['meta_build']:
            path_val = getattr(args, path, None)
            if path_val:
                path_val = c_path.normalize(path_val)
                if not c_path.validate_dir(path_val):
                    err.append('Cannot access ' + path + ' at: ' + path_val)
                setattr(args, path, path_val)

        # Check and sanitize paths for write access
        for path in ['output_dir', 'mini_build']:
            path_val = getattr(args, path, None)
            if path_val:
                path_val = c_path.normalize(path_val)
                try:
                    c_path.create_dir(path_val)
                except Exception as e:
                    err.append('Cannot write at: ' + path_val + '\n'
                               '    ' + 'Error: ' + str(e))
                setattr(args, path, path_val)

        # Raise error if any
        if err:
            if len(err) > 1:
                err = [('  ' + str(idx + 1) + '. ' + error)
                       for idx, error in enumerate(err)]
                err = 'Please check the command line args:\n\n' + '\n'.join(
                    err)
            else:
                err = err[0]
            raise RuntimeError(err)
Пример #12
0
    def c_add_options(self):
        """Adds the command line args supported by secimage."""
        # Signing individual image
        img_group = self.add_option_group('Signing individual image')
        img_group.add_option('--overrides',
                             action='store_true',
                             help=optparse.SUPPRESS_HELP)
        img_group.add_option('-i',
                             '--image_file',
                             metavar='<file>',
                             help='path to the image file.')
        img_group.add_option(
            '-g',
            '--sign_id',
            metavar='<id>',
            help='sign id corresponding to the image_file provided.')
        img_group.add_option(
            '-p',
            '--chipset',
            metavar='<id>',
            help='id of the chipset corresponding to the image_file.')
        img_group.add_option('-c',
                             '--config_path',
                             metavar='<file>',
                             help='path to the secimage config file.')
        img_group.add_option('--qti',
                             '--qti_signing',
                             action='store_true',
                             dest="qti_signing",
                             default=False,
                             help=optparse.SUPPRESS_HELP)
        img_group.add_option('--verbatim_config',
                             action='store_true',
                             default=False,
                             help=optparse.SUPPRESS_HELP)

        # Signing metabuild
        meta_group = self.add_option_group('Signing images from metabuild')
        meta_group.add_option(
            '-m',
            '--meta_build',
            metavar='<dir>',
            help=
            'path to the meta-build to be used for obtaining the images to sign.'
        )

        # Specifying the output location
        output_group = self.add_option_group('Specifying output location')
        output_group.add_option(
            '-o',
            '--output_dir',
            metavar='<dir>',
            help='directory to store output files. DEFAULT: "./' +
            DEF_SECIMAGE_OUTPUT_DIR_NAME + '"',
            default=DEF_SECIMAGE_OUTPUT_DIR_PATH)
        output_group.add_option(
            '-n',
            '--mini_build',
            metavar='<dir>',
            help='path to the minimized build to store the signed images to. '
            'This option works with the meta_build option.')

        # Specifying the operation
        operations_group = self.add_option_group(
            'Operations for individual images')
        operations_group.add_option('-t',
                                    '--integrity_check',
                                    action='store_true',
                                    default=False,
                                    help='add hash table segment.')
        operations_group.add_option(
            '-r',
            '--sign_attr',
            action='store_true',
            default=False,
            help=
            'add signing attributes to hash table segment of unsigned Secboot 3.0 image.'
        )
        operations_group.add_option('-s',
                                    '--sign',
                                    action='store_true',
                                    default=False,
                                    help='sign the image.')
        operations_group.add_option('-e',
                                    '--encrypt',
                                    action='store_true',
                                    default=False,
                                    help='encrypt the image.')
        operations_group.add_option('--decrypt',
                                    action='store_true',
                                    default=False,
                                    help=optparse.SUPPRESS_HELP)
        operations_group.add_option('-a',
                                    '--validate',
                                    action='store_true',
                                    default=False,
                                    help='validate the image.')
        operations_group.add_option(
            '--no_op',
            action='store_true',
            default=False,
            help=
            'perform no operations on individual image when adding entry to ' +
            multi_image_string() + ' image.')
        operations_group.add_option('-l',
                                    '--verify_inputs',
                                    action='store_true',
                                    default=False,
                                    help='verify the command line options.')
        operations_group.add_option(
            "--enforce_signed",
            action="store_true",
            default=False,
            help="raise an error if an image is unsigned.")
        operations_group.add_option(
            "--enforce_encrypted",
            action="store_true",
            default=False,
            help="raise an error if an image is unencrypted.")

        # Multi-Image Sign & Integrity image operations
        multi_image_group = self.add_option_group(
            'Operations for ' + multi_image_string() + ' images\n' +
            '  (to be used when adding or updating image entries in ' +
            multi_image_string() + ' image)')
        multi_image_group.add_option('--m_gen',
                                     action='store_true',
                                     default=False,
                                     help='generate a new ' +
                                     multi_image_string() + ' image.')
        multi_image_group.add_option('--m_image_file',
                                     metavar='<file>',
                                     help='path to an existing ' +
                                     multi_image_string() + ' image file.')
        multi_image_group.add_option('--m_integrity_check',
                                     action='store_true',
                                     default=False,
                                     help='add hash table segment to ' +
                                     multi_image_string() + ' image.')
        multi_image_group.add_option(
            '--m_sign_attr',
            action='store_true',
            default=False,
            help='add signing attributes to hash table segment of unsigned ' +
            multi_image_string() + ' image.')
        multi_image_group.add_option('--m_sign',
                                     action='store_true',
                                     default=False,
                                     help='sign the ' + multi_image_string() +
                                     ' image.')
        multi_image_group.add_option('--m_encrypt',
                                     action='store_true',
                                     default=False,
                                     help='encrypt the ' +
                                     multi_image_string() + ' image.')
        multi_image_group.add_option('--m_decrypt',
                                     action='store_true',
                                     default=False,
                                     help=optparse.SUPPRESS_HELP)
        multi_image_group.add_option('--m_validate',
                                     action='store_true',
                                     default=False,
                                     help='validate the ' +
                                     multi_image_string() + ' image.')

        # Other options
        other_group = self.add_option_group('Other options')
        other_group.add_option(
            '--rch',
            '--root_cert_hash',
            metavar='<root_cert_hash>',
            dest="rch",
            type="str",
            action="callback",
            callback=self.sanitize_root_cert_hash,
            help=
            'root cert hash to validate the signed image against. root cert hash '
            'is hex string of SHA256/SHA384 or it can be string ' +
            comma_separated_string(rch_string) + ' to '
            'detect if image is ' + comma_separated_string(rch_string) +
            ' signed. ' +
            comma_separated_string(rch_string, final_separator='and') +
            ' are only applicable for ' + AUTHORITY_QTI + ' signed images.')
        other_group.add_option(
            "--" + SERIAL_NUMBERS,
            metavar="<%s>" % SERIAL_NUMBERS,
            dest=SERIAL_NUMBERS,
            help=
            "Serial numbers of devices on which image(s) will authenticate. Serial "
            "numbers are space-separated 32-bit hex strings. Use 'ALL' by itself "
            "to enable image authentication on devices of any serial number.")

        other_group.add_option(
            "--platform_binding",
            metavar="<" + comma_separated_string(PLATFORM_BINDINGS) + ">",
            dest="platform_binding",
            type="str",
            action="callback",
            callback=self.sanitize_platform_binding,
            help=
            "Specifies whether image(s) should be bound to JTAG ID (msm_part), SOC HW Version "
            "(soc_hw_version/soc_vers), or neither. If provided, takes precedence over "
            "in_use_soc_hw_version value. " + PLATFORM_BINDING_INDEPENDENT +
            " only applies to "
            "Trusted Applications.")

        # Populate override options
        for tag, override in self.overrides.get_properties().items():
            operations_group.add_option('--' + self.override_prefix + tag,
                                        metavar='<' + override.type_str +
                                        '_value>',
                                        help=optparse.SUPPRESS_HELP)

        # Populate special override options
        for tag, override in self.spec_overrides.get_properties().items():
            operations_group.add_option('--' + self.spec_override_prefix + tag,
                                        metavar='<' + override.type_str +
                                        '_value>',
                                        help=optparse.SUPPRESS_HELP)
Пример #13
0
    def _create_imageinfo(self,
                          img_config_parser,
                          parsegen_config,
                          sign_id,
                          image_path,
                          gen_multi_image=False,
                          src_image=None,
                          dest_image=None,
                          crypto_params={},
                          imageinfo_class=ImageInfo,
                          verbatim_config=False,
                          disable_serial_binding=False,
                          platform_binding=None):
        """
        The same dest_image object should not be used by two or more image_info
        objects. It results in destination image path cross contamination.
        For example, image_info objects A and B use the same dest_image.
        If A.dest_image is updated with a new output_dir, then B.dest_image
        is changed as well, because they are the same object and share the same
        attributes.
        """
        if not gen_multi_image and sign_id not in MULTI_IMAGE_SIGN_ID.values():
            # Validate the sign_id
            sign_id = self._get_sign_id(img_config_parser,
                                        os.path.basename(image_path), sign_id)
            # Get the config block for the sign id
            img_config_block = img_config_parser.get_config_for_sign_id(
                sign_id)
        else:
            try:
                # Get the config block for the Multi-Image Sign & Integrity image
                img_config_block = img_config_parser.get_config_for_sign_id(
                    sign_id)
            except RuntimeError:
                prefix = "QTI " if sign_id == QTI_MULTI_IMAGE_SIGN_ID else ""
                raise RuntimeError(prefix + multi_image_string() +
                                   " image is not supported for chipset {0}".
                                   format(img_config_parser.chipset))

        # Create the image info object
        image_info = imageinfo_class(
            image_path,
            sign_id,
            img_config_block,
            img_config_parser,
            parsegen_config,
            gen_multi_image=gen_multi_image,
            authority=self.authority,
            crypto_params=crypto_params,
            verbatim_config=verbatim_config,
            disable_serial_binding=disable_serial_binding,
            platform_binding=platform_binding)
        image_info.dest_image.image_name = image_info.src_image.image_name

        # Set src_image
        if src_image is not None:
            image_info.src_image = src_image
            image_info.image_under_operation = image_info.src_image.image_path

        # Set dest_image
        if dest_image is not None:
            image_info.dest_image = dest_image

        # Check if the dest image name should be overridden
        if img_config_block.output_file_name is not None:
            image_info.dest_image.image_name = img_config_block.output_file_name

        return image_info