예제 #1
0
    def __init__(self,
                 image_path,
                 img_config_parser,
                 parsegen_config,
                 authority,
                 sign_id=None,
                 gen_multi_image=False,
                 multi_image_path=None):
        from sectools.features.isc.parsegen.config.parser import ParsegenCfgParser
        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
        BaseStager.__init__(self, 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, False)
        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, multi_image_path,
                False)
            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)
            self._multi_image_imageinfo_dict[
                multi_image_imageinfo.chipset] = multi_image_imageinfo
예제 #2
0
    def _create_imageinfo(self,
                          img_config_parser,
                          parsegen_config,
                          sign_id,
                          image_path,
                          gen_multi_image,
                          src_image=None,
                          dest_image=None):

        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:
                raise RuntimeError(multi_image_string() +
                                   " images are not supported for chipset {0}".
                                   format(img_config_parser.chipset))

        # Create the image info object
        image_info = ImageInfo(image_path,
                               sign_id,
                               img_config_block,
                               img_config_parser,
                               parsegen_config,
                               gen_multi_image=gen_multi_image,
                               authority=self.authority)
        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
예제 #3
0
    def __init__(self, hash_algorithm, data=None, images=None):
        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()
예제 #4
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 = mask_header_values(header, self.authority)
             return header.pack() + self._mbn_parsegen.code
     except:
         return None
예제 #5
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))
예제 #6
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)
예제 #7
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 + 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())
예제 #8
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 not (args.integrity_check or args.sign or args.encrypt
                or 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.')

        # 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'
            )

        # 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.'
            )

        # Check other options:
        if args.rch and not args.validate:
            err.append(
                'Root Cert Hash can only be given when "--validate" operation is provided.'
            )

        # 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)
예제 #9
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_signing',
                             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.')

        # 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='<hash>',
            help=
            'root cert hash to validate the signed image cert chain against. '
            'This option can only be used with the validate operation.')

        # 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)
예제 #10
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 secboot version '
                    + 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 secboot version ' +
                    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 sa.rot_en is not None and 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":
                if sa.rsa_padding is not None:
                    logger.warning(
                        "rsa_padding should not be set for chipset \"{0}\" when ECDSA signing."
                        .format(self.chipset))
                    logger.warning(
                        "rsa_padding and hmac will be ignored.".format(
                            self.chipset))
                    sa.rsa_padding = None
                    sa.hmac = None
            else:
                if sa.rsa_padding is None or 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

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

        # Based on secboot_version allowed formats differ for sw_id, anti_rollback_version, rot_en, uie_key_switch_enable, root_revoke_activate_enable, & debug.
        # Validation must happen outside of rule.py because images of different secboot versions can coexist in the same config file.

        # Only Secboot 3 supports anti_rollback_version as its own value
        if sa.secboot_version == SECBOOT_VERSION_3_0:
            if sa.anti_rollback_version is None:
                self._add_error(
                    "Secboot {0} requires anti_rollback_version field.".format(
                        sa.secboot_version))
            if (int(sa.sw_id, 16) & 0xFFFFFFFF00000000) != 0:
                self._add_error(
                    "Provide anti-rollback version in anti_rollback_version field for secboot {0} chipset."
                    .format(sa.secboot_version))
                self._add_error(
                    "sw_id value {0} exceeds maximum allowed length of 10 characters."
                    .format(sa.sw_id))
            if sa.anti_rollback_version is not None and (int(
                    sa.anti_rollback_version, 16) & 0xFFFFFFFF00000000) != 0:
                self._add_error(
                    "anti_rollback_version value {0} exceeds maximum allowed length of 10 characters."
                    .format(sa.anti_rollback_version))
            # sha1 is disallowed for Secboot 3
            if sa.hash_algorithm == "sha1":
                self._add_error(
                    "sha1 hash_algorithm is not allowed for secboot {0} images."
                    .format(sa.secboot_version))
            if sa.segment_hash_algorithm == "sha1":
                self._add_error(
                    "sha1 segment_hash_algorithm is not allowed for secboot {0} images."
                    .format(sa.secboot_version))

        # rot_en rule, LSB 32bits must not be greater than 1
        multi_serial_numbers = sa.multi_serial_numbers.serial if sa.multi_serial_numbers is not None else []
        self._validate_serial_bound_value(
            sa.rot_en,
            "rot_en",
            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",
            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",
                                          self.chipset, MRC_1_0_CHIPSETS,
                                          sa.num_root_certs)
        # Validate activation_enablement
        self._validate_serial_bound_value(sa.activation_enablement,
                                          "activation_enablement",
                                          self.chipset, MRC_1_0_CHIPSETS,
                                          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",
            self.chipset,
            MRC_2_0_CHIPSETS,
            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",
            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)

        if self.errors:
            raise RuntimeError("".join(self.errors))
예제 #11
0
import os

import defines
from cfgparser import ConfigParser
from cfgparser import defines as cfgdef
from sectools.common.utils import c_path
from sectools.common.utils.c_base import ValPolicy
from sectools.common.utils.c_logging import logger
from sectools.common.utils.c_misc import multi_image_string
from sectools.features.isc import defines
from sectools.features.isc.cfgparser.defines import JTAGID_SIGN_IDS, MRC_1_0_CHIPSETS, MRC_2_0_CHIPSETS, SECBOOT_2_0_DOUBLE_SIGN_CHIPSETS, SECBOOT_3_0_DOUBLE_SIGN_CHIPSETS, SECBOOT_1_IMAGE_TYPES
from sectools.features.isc.defines import SECBOOT_VERSION_1_0, SECBOOT_VERSION_3_0

POLICY_OEM_ID_0 = ValPolicy(ValPolicy.WARN)
MULTI_IMAGE_FILENAME = 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,
    defines.AUTHORITY_QTI: QTI_MULTI_IMAGE_SIGN_ID,
}


class ImagePath(object):
    def __init__(self, image_path=''):
        self._image_dir_base = os.path.dirname(image_path)
        self._image_dir_ext = ''
        self._image_name = os.path.basename(image_path)

    @property