Example #1
0
    def extract_elf_wrapper(self, data):
        updated_data = data

        try:
            elf_hdr = Elf32_Ehdr(updated_data[:Elf32_Ehdr.get_size()])
        except Exception:
            logger.note('EWM file is not wrapped')
        else:
            updated_data = updated_data[Elf32_Ehdr.get_size():]

            elf_phdr = Elf32_Phdr(updated_data[:Elf32_Phdr.get_size()])
            updated_data = updated_data[Elf32_Phdr.get_size():]

            offset = elf_phdr.p_offset - Elf32_Phdr.get_size(
            ) - Elf32_Ehdr.get_size()
            padding = updated_data[:offset]
            updated_data = updated_data[offset:]

            logger.debug('Elf Wrapper Info:' + '\n' + repr(elf_hdr) + '\n' +
                         repr(elf_phdr) + '\n' + 'Padding: ' + '\n' + padding +
                         '\n')

            self.store_debug_data('ewm_elf_header', elf_hdr.pack())
            self.store_debug_data('ewm_elf_pheader', elf_phdr.pack())
            self.store_debug_data('ewm_elf_wrapper',
                                  (elf_hdr.pack() + elf_phdr.pack() + padding))
            self.store_debug_data('ewm_mbn', updated_data)

        return updated_data
    def chipset(self, chipset):
        # Check that the workspace is set
        if self._workspace_dir_obj is None:
            raise RuntimeError('Please set workspace before setting the chipset.')

        # Log if the chipset is changed
        try:
            selected_chipset = self.chipset
            if selected_chipset:
                logger.note('Switching chipset from "' + selected_chipset + '" to "' + chipset + '"')
        except Exception:
            pass

        # Update the workspace
        self._update_workspace(chipset)

        # Set the config paths
        self.set_config_paths(*self._workspace_dir_obj.get_chipset_config_paths(chipset))

        # Set the ouput dir
        self.output_dir = c_path.join(os.path.dirname(self._workspace_dir_obj.config_dir),
                                      'secdat/' + chipset)

        # Add the existing secdat
        secdat = c_path.join(self.output_dir, 'sec.dat')
        if c_path.validate_file(secdat):
            self.secdat = secdat
        else:
            self.secdat = None
Example #3
0
    def process(self,
                verify_setup=False,
                generate=False,
                sign=False,
                validate=False,
                progress_cb=PROGRESS_CB_PYPASS):
        """Performs the debugpolicy operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object
            is correct and return. This will ignore any other params.
        :param bool generate: Generate the debugpolicy elf using the config files.
        :param bool validate: Validate the debugpolicy elf
        :param cb progress_cb: Callback method to get a status update during
            processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...

        """
        # Verify setup
        if verify_setup:
            self.verify_setup(generate, sign, validate)
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Total number of stages. This is used for progress notification via the
        # callback.
        _PROGRESS_TOTAL_STAGES = 3

        # Start processing debugpolicy
        progress = ProgressNotifier(1, progress_cb, _PROGRESS_TOTAL_STAGES)
        progress.status = 'Processing..'

        # Create debug dirs
        self.create_debug_dir(self.output_dir)

        # Generate debugpolicy elf
        if generate:
            self.generate()
            progress.push()

        # Sign debugpolicy elf
        if sign:
            self.sign(self.input_file_list[0])
            progress.push()

        # Validate debugpolicy file
        if validate:
            self.validate()
            progress.push()

        # End processing
        progress.complete()
Example #4
0
    def generate(self, file_path=None):
        """Generates the config file with the current configuration of the root
        node.

        :param str file_path: path to the config file that should be generated
            with the current data
        """
        logger.note('Generating config file...')
        CoreConfig.generate(self, file_path, defines.XML_ROOTNODE,
                            defines.XML_NAMESPACE, defines.XML_PREPEND_LINES)
        logger.note('Generated config file at: ' + file_path)
Example #5
0
    def process(self,
                verify_setup=False,
                generate=False,
                validate=False,
                progress_cb=PROGRESS_CB_PYPASS):
        """Performs the fuse blowing operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object
            is correct and return. This will ignore any other params.
        :param bool generate: Generate the sec.dat using the config files.
        :param bool validate: Validate the sec.dat
        :param cb progress_cb: Callback method to get a status update during
            processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...

        """
        # Verify setup
        if verify_setup:
            self.verify_setup(generate, validate)
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Total number of stages. This is used for progress notification via the
        # callback.
        _PROGRESS_TOTAL_STAGES = 3

        # Start processing images
        progress = ProgressNotifier(1, progress_cb, _PROGRESS_TOTAL_STAGES)

        # Send a progress notification to the toplevel
        progress.status = 'Processing..'
        progress.cur_stage = 0
        progress.push()

        # Generate the secdat
        if generate:
            self.generate()
        progress.push()

        # Validate the secdat
        if validate:
            self.validate(self.secdat)
        progress.push()

        # End processing
        progress.complete()
    def generate(self, file_path):
        """Generates the secimage config file with the current configuration
        of the root node.

        :param str file_path: path to the config file that should be generated
            with the current data
        """
        logger.note('Generating config file...')
        c_config.CoreConfig.generate(self, file_path,
                                     defines.XML_ROOTNODE,
                                     defines.XML_NAMESPACE,
                                     defines.XML_PREPEND_LINES)
        logger.note('Generated config file at: ' + str(file_path))
Example #7
0
    def chipset(self, chipset):
        # Log if the chipset is changed
        try:
            selected_chipset = self.chipset
            if selected_chipset:
                logger.note('Switching chipset from "' + selected_chipset +
                            '" to "' + chipset + '"')
        except Exception:
            pass

        # Update the config path based on the given chipset
        self.config_path = self._config_dir_obj.get_chipset_config_path(
            chipset)
        logger.info('Chipset is set to: ' + chipset)
Example #8
0
    def output_dir(self, output_dir):
        # Log if the output_dir is changed
        try:
            selected_output_dir = self.output_dir
            if selected_output_dir:
                logger.note('Switching output_dir: ' + '\n'
                            '    ' + 'from: ' + selected_output_dir + '\n'
                            '    ' + ' to: ' + output_dir)
        except Exception:
            pass

        # Update the output_dir
        self._stager.output_dir = output_dir
        logger.debug('Output dir is set to: ' + output_dir)
Example #9
0
    def set_chipset(self, chipset, overrides=None):
        # Log if the chipset is changed
        try:
            selected_chipset = self.chipset
            if selected_chipset:
                logger.note('Switching chipset from "' + selected_chipset + '" to "' + chipset + '"')
        except Exception:
            pass

        # Update the config path based on the given chipset
        config_path = self._config_dir_obj.get_chipset_config_path(chipset)
        if config_path is None:
            raise RuntimeError('Config file is not found for chipset: ' + str(chipset))
        self.set_config_path(config_path, overrides)
        logger.debug('Chipset is set to: ' + chipset)
    def chipset(self, chipset):
        # Log if the chipset is changed
        try:
            selected_chipset = self.chipset
            if selected_chipset:
                logger.note('Switching chipset from "' + selected_chipset + '" to "' + chipset + '"')
        except Exception:
            pass

        # Update the config path based on the given chipset
        config_path = self._config_dir_obj.get_chipset_config_path(chipset)
        if config_path is None:
            raise RuntimeError('Config file is not found for chipset: ' + str(chipset))
        self.config_path = config_path
        logger.info('Chipset is set to: ' + chipset)
    def mini_build_path(self, mini_build_path):
        # Log if the mini_build_path is changed
        selected_mini_build_path = self.mini_build_path
        if selected_mini_build_path:
            logger.note('Switching mini_build_path: ' + '\n'
                        '    ' + 'from: ' + selected_mini_build_path + '\n'
                        '    ' + ' to: ' + mini_build_path)

        # Update the mini_build_path
        self._stager.mini_build_path = mini_build_path
        logger.info('Minimized Build is set to: ' + mini_build_path)

        # Clear the output dir setting
        try:
            self._stager.output_dir = ''
        except Exception:
            pass
Example #12
0
    def mini_build_path(self, mini_build_path):
        # Log if the mini_build_path is changed
        selected_mini_build_path = self.mini_build_path
        if selected_mini_build_path:
            logger.note('Switching mini_build_path: ' + '\n'
                        '    ' + 'from: ' + selected_mini_build_path + '\n'
                        '    ' + ' to: ' + mini_build_path)

        # Update the mini_build_path
        self._stager.mini_build_path = mini_build_path
        logger.info('Minimized Build is set to: ' + mini_build_path)

        # Clear the output dir setting
        try:
            self._stager.output_dir = ''
        except Exception:
            pass
Example #13
0
    def create_debug_dir(self, output_dir):
        """Creates the debug directory structure.
        """
        if not self.debug:
            return

        if not output_dir:
            logger.note('Output directory not available to dump debug logs')
            return

        try:
            debug_dir = c_path.join(output_dir, defines.DEST_DEBUG_DIR)
            try:
                c_path.create_dir(debug_dir)
            except Exception as e:
                raise RuntimeError('Failed to create debug dir: ' + str(e))

        except Exception as e:
            logger.warning('Failed to store debug logs: ' + str(e))
Example #14
0
    def set_config_path(self, config_path, overrides=None):
        # Log if the config_path is changed
        try:
            selected_config_path = self.config_path
            if selected_config_path:
                logger.note('Switching config_path: ' + '\n'
                            '    ' + 'from: ' + selected_config_path + '\n'
                            '    ' + ' to: ' + config_path)
        except Exception:
            pass

        # Update the config_path
        self._img_config_parser = ConfigParser(config_path, overrides)
        logger.info('Config path is set to: ' + config_path)

        # Reset the stager at this point
        if self._stager is not None:
            logger.note('Resetting image list due to config path change.')
            self._stager = None
    def config_path(self, config_path):
        # Log if the config_path is changed
        try:
            selected_config_path = self.config_path
            if selected_config_path:
                logger.note('Switching config_path: ' + '\n'
                            '    ' + 'from: ' + selected_config_path + '\n'
                            '    ' + ' to: ' + config_path)
        except Exception:
            pass

        # Update the config_path
        self._img_config_parser = ConfigParser(config_path)
        logger.info('Config path is set to: ' + config_path)

        # Reset the stager at this point
        if self._stager is not None:
            logger.note('Resetting image list due to config path change.')
            self._stager = None
    def reset_workspace(self, chipset=None, oem=True, qc=True, ui=True, user=True):
        """Resets the :meth:`workspace` for the chipset that is provided.
        :meth:`config_dir` is searched for the files for the chipset. If the
        files are found in the config_dir, they are copied to the workspace,
        otherwise an exception is raised.

        :param str chipset: The chipset to reset in the workspace.
        :param bool oem: If the oem file should be updated.
        :param bool qc: If the qc file should be updated.
        :param bool ui: If the ui file should be updated.
        :param bool user: If the user file should be updated.
        :raise RuntimeError: If files for the chipset are not found in the
            the config_dir
        """
        if chipset is None:
            chipset = self.chipset

        # Look for the config files in the config_dir
        try:
            template_oem, template_qc, template_ui, template_user = self._config_dir_obj.get_chipset_config_paths(chipset)
        except Exception as e:
            logger.warning('Template config files not found for copying to workspace for chipset: ' + chipset + '\n'
                           '    ' + 'Error: ' + str(e))
            raise

        # Create the directory in the workspace for this chipset
        self._workspace_dir_obj.create_chipset_dir(chipset)
        workspace_chipset_dir = self._workspace_dir_obj.get_chipset_dir(chipset)

        if not oem:
            # Copy the OEM template file
            logger.info('Copying template OEM config file to workspace for chipset: ' + chipset)
            shutil.copy(template_oem, workspace_chipset_dir)
            logger.note('OEM config file created at: ' + workspace_chipset_dir)

        if not qc:
            # Copy the QC template file
            logger.info('Copying template QC config file to workspace for chipset: ' + chipset)
            shutil.copy(template_qc, workspace_chipset_dir)
            logger.note('QC config file created at: ' + workspace_chipset_dir)

        if not ui:
            # Copy the UI template file
            logger.info('Copying template UI config file to workspace for chipset: ' + chipset)
            shutil.copy(template_ui, workspace_chipset_dir)
            logger.note('UI config file created at: ' + workspace_chipset_dir)

        if not user:
            # Copy the USER template file
            logger.info('Copying template USER config file to workspace for chipset: ' + chipset)
            shutil.copy(template_user, workspace_chipset_dir)
            logger.note('USER config file created at: ' + workspace_chipset_dir)
    def output_dir(self, output_dir):
        # Log if the output_dir is changed
        try:
            selected_output_dir = self.output_dir
            if selected_output_dir:
                logger.note('Switching output_dir: ' + '\n'
                            '    ' + 'from: ' + selected_output_dir + '\n'
                            '    ' + ' to: ' + output_dir)
        except Exception:
            pass

        # Update the output_dir
        self._stager.output_dir = output_dir
        logger.info('Output dir is set to: ' + output_dir)

        # Clear the minimized build setting
        try:
            self._stager.mini_build_path = ''
        except Exception:
            pass
Example #18
0
    def output_dir(self, output_dir):
        # Log if the output_dir is changed
        try:
            selected_output_dir = self.output_dir
            if selected_output_dir:
                logger.note('Switching output_dir: ' + '\n'
                            '    ' + 'from: ' + selected_output_dir + '\n'
                            '    ' + ' to: ' + output_dir)
        except Exception:
            pass

        # Update the output_dir
        self._stager.output_dir = output_dir
        logger.info('Output dir is set to: ' + output_dir)

        # Clear the minimized build setting
        try:
            self._stager.mini_build_path = ''
        except Exception:
            pass
Example #19
0
def initialize():
    """Imports all the modules in the chain in the correct order for the
    generation of the singletons and discovery of plugins.
    """
    # Initialize the feature manager
    logger.debug('Initializing the feature manager')
    import sectools.common.core.feature

    # Initialize the interfaces
    logger.debug('Initializing all interfaces')
    try:
        import sectools.intf.ui.manager
    except ImportError:
        logger.debug('UI interface is unavailable.')
    except Exception:
        logger.note('UI interface implementation crashed:' + '\n'
                    '' + traceback.format_exc())
    else:
        logger.debug('UI interface is available.')

    # Initialize the features
    logger.debug('Initializing all features')
    try:
        import sectools.features.fbc.fbc
    except ImportError:
        logger.debug('FuseBlower is unavailable.')
    except Exception:
        logger.note('FuseBlower implementation crashed:' + '\n'
                    '' + traceback.format_exc())
    else:
        logger.debug('FuseBlower is available.')

    try:
        import sectools.features.isc
    except ImportError:
        logger.debug('SecImage is unavailable.')
    except Exception:
        logger.note('SecImage implementation crashed:' + '\n'
                    '' + traceback.format_exc())
    else:
        logger.debug('SecImage is available.')

    try:
        import sectools.features.ltf
    except ImportError:
        logger.debug('LocalTF is unavailable.')
    except Exception:
        logger.note('LocalTF implementation crashed:' + '\n'
                    '' + traceback.format_exc())
    else:
        logger.debug('LocalTF is available.')
Example #20
0
    def process(self,
                verify_setup=False,
                integrity_check=False,
                sign=False,
                encrypt=False,
                decrypt=False,
                val_image=False,
                val_integrity_check=False,
                val_sign=False,
                val_encrypt=False,
                progress_cb=PROGRESS_CB_PYPASS):
        """Performs the secure-image related operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object
            is correct and return. This will ignore any other params.
        :param bool integrity_check: Add integrity check to the image.
        :param bool sign: Sign the images. (Re-sign if image is already signed)
        :param bool encrypt: Encrypt the images. (Re-encrypt if image is already
            encrypted)
        :param bool val_image: Validate the integrity of the image against the
            config file.
        :param bool val_integrity_check: Validate the integrity check in the image.
        :param bool val_sign: Validate that the image is signed and validate the
            integrity of the signing related data.
        :param bool val_encrypt: Validate that the image is encrypted and
            validate the integrity of the encryption related data.
        :param cb progress_cb: Callback method to get a status update during
            processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...

        """
        from imageinfo import ImageInfo, StatusInfo
        # Ensure that one or more image files is provided for processing
        if self._stager is None or not self.image_path_list:
            raise RuntimeError(
                'Please specify one or more images for processing')

        # Ensure the correct set of operations is provided
        if not (verify_setup or integrity_check or sign or encrypt or decrypt
                or val_image or val_integrity_check or val_sign
                or val_encrypt):
            raise RuntimeError(
                'Please specify one or more operations to perform.')

        if verify_setup:
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Print the openssl path
        version = ''
        path_info = 'is unavailable. Please run "which openssl" and "openssl version" to check openssl version info, and upgrade to required version'
        try:
            from sectools.common import crypto
            from sectools.common.crypto import crypto_functions
            version = 'v' + crypto.discovery.openssl.OPENSSL_VERSION_MIN + ' or greater '
            crypto_functions.are_available([crypto_functions.MOD_OPENSSL])
            path_info = 'is available at: "' + crypto.openssl_binary_implementation.openssl_binary_path + '"'
        except Exception as e:
            pass
        logger.info('Openssl ' + version + path_info)

        # Start processing images
        total_images = len(self.image_info_list)
        progress = ProgressNotifier(total_images, progress_cb,
                                    PROGRESS_TOTAL_STAGES)

        for idx, image in enumerate(self.image_info_list):
            assert isinstance(image, ImageInfo)

            logger.info(
                '------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' +
                             str(total_images) + ': ' +
                             image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            file_logger_id = None

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' +
                                       image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Enable file logging to the directory
                file_logger_id = logger.add_file_logger(
                    c_path.join(image_output_dir, 'SecImage_log.txt'),
                    logger.verbosity)

                # Create the security policies list for this image
                security_policy_list = create_security_policy_list(image)

                # Parsegen object
                parsegen = None

                # For secure operations
                if integrity_check or sign or encrypt or decrypt:
                    parsegen = self._process_secure_operation(
                        image, progress, security_policy_list, integrity_check,
                        sign, encrypt, decrypt)

                # For validation
                if val_image or val_integrity_check or val_sign or val_encrypt:
                    parsegen = self._process_validation(
                        image, progress, security_policy_list, val_image,
                        val_integrity_check, val_sign, val_encrypt)

                # Print the image data
                if parsegen is not None:
                    logger.info('\n' + str(parsegen))

                # Set overall processing to true
                if not ((val_image and image.status.validate_parsegen.state
                         == StatusInfo.ERROR) or
                        (val_integrity_check
                         and image.status.validate_integrity_check.state
                         == StatusInfo.ERROR) or
                        (val_sign and image.status.validate_sign.state
                         == StatusInfo.ERROR) or
                        (val_encrypt and image.status.validate_encrypt.state
                         == StatusInfo.ERROR)):
                    image.status.overall.state = StatusInfo.SUCCESS

            except Exception:
                logger.error(traceback.format_exc())
                logger.error(sys.exc_info()[1])

            if file_logger_id is not None:
                logger.removeFileLogger(file_logger_id)

            logger.info(
                '------------------------------------------------------\n')
        progress.complete()
Example #21
0
    def process(
        self,
        verify_setup=False,
        sign_attr=False,
        integrity_check=False,
        sign=False,
        encrypt=False,
        decrypt=False,
        val_image=False,
        val_integrity_check=False,
        val_sign=False,
        val_encrypt=False,
        root_cert_hash=None,
        progress_cb=PROGRESS_CB_PYPASS,
    ):
        """Performs the secure-image related operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object is correct and return. This will ignore any other params.
        :param bool sign_attr: Add signing attributes to hash segment of images.
        :param bool integrity_check: Add integrity check to the image.
        :param bool sign: Sign the images. (Re-sign if image is already signed)
        :param bool encrypt: Encrypt the images. (Re-encrypt if image is already encrypted)
        :param bool val_image: Validate the integrity of the image against the config file.
        :param bool val_integrity_check: Validate the integrity check in the image.
        :param bool val_sign: Validate that the image is signed and validate the integrity of the signing related data.
        :param bool val_encrypt: Validate that the image is encrypted and validate the integrity of the encryption related data.
        :param cb progress_cb: Callback method to get a status update during processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...


        """
        from imageinfo import ImageInfo, StatusInfo
        from sectools.features.isc.signer.remote import RemoteSignerNote

        # Ensure that one or more image files is provided for processing
        if self._stager is None or not self.image_path_list:
            raise RuntimeError(
                'Please specify one or more images for processing')

        # Ensure the correct set of operations is provided
        if not (verify_setup or integrity_check or sign or encrypt or decrypt
                or val_image or val_integrity_check or val_sign
                or val_encrypt):
            raise RuntimeError(
                'Please specify one or more operations to perform.')

        # Print the openssl path
        version = ''
        path_info = 'is unavailable. Please run "which openssl" and "openssl version" to check openssl version info, and upgrade to required version'
        try:
            from sectools.common import crypto
            version = 'v' + '.'.join(
                tuple(str(x) for x in
                      crypto.openssl.OPENSSL_VERSION_MIN)) + ' or greater '
            path_info = 'is available at: "' + crypto.discovery_factory.get_impl(
                crypto.modules.MOD_OPENSSL) + '"'
        except Exception as e:
            pass
        logger.info('Openssl ' + version + path_info)

        if verify_setup:
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Start processing images
        individual_image_count = len(self.image_info_list)
        total_image_count = individual_image_count
        progress = ProgressNotifier(total_image_count, progress_cb,
                                    PROGRESS_TOTAL_STAGES)

        def _process(idx, image, sign_attr, integrity_check, sign, encrypt,
                     decrypt, val_image, val_integrity_check, val_sign,
                     val_encrypt):
            assert isinstance(image, ImageInfo)

            logger.info(
                '------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' +
                             str(total_image_count) + ': ' +
                             image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            file_logger_id = None
            image.authority = self.authority

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' +
                                       image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Set the root cert hash
                image.validation_root_cert_hash = root_cert_hash

                # Enable file logging to the directory
                file_logger_id = logger.add_file_logger(
                    c_path.join(image_output_dir, 'SecImage_log.txt'),
                    logger.verbosity)

                # Create the security policies list for this image
                security_policy_list = create_security_policy_list(image)

                # Parsegen object
                parsegen = None

                # For secure operations
                if integrity_check or sign or encrypt or decrypt:
                    parsegen = self._process_secure_operation(
                        image, progress, security_policy_list, sign_attr,
                        integrity_check, sign, encrypt, decrypt)

                # For validation
                if val_image or val_integrity_check or val_sign or val_encrypt:
                    # Bypass validation when encrypted key provide is configured as UIE server because decryption will always fail
                    if parsegen is not None and parsegen.is_encrypted(
                    ) and encrypted_key_provider_id_supported(
                            image.general_properties.UIE_key):
                        logger.warning(
                            "Skipping validation because encrypted key provider is configured as UIE server"
                        )
                    else:
                        parsegen = self._process_validation(
                            image, progress, security_policy_list, val_image,
                            val_integrity_check, val_sign, val_encrypt)

                # Print the image data
                if parsegen is not None:
                    logger.info('\n' + str(parsegen))

                # Set overall processing to true
                if not ((val_image and image.status.validate_parsegen.state
                         == StatusInfo.ERROR) or
                        (val_integrity_check
                         and image.status.validate_integrity_check.state
                         == StatusInfo.ERROR) or
                        (val_sign and image.status.validate_sign.state
                         == StatusInfo.ERROR) or
                        (val_encrypt and image.status.validate_encrypt.state
                         == StatusInfo.ERROR)):
                    image.status.overall.state = StatusInfo.SUCCESS

            except RemoteSignerNote as e:
                logger.info('NOTE: ' + str(e), color=logger.YELLOW)
            except Exception:
                logger.error(traceback.format_exc())
                logger.error(sys.exc_info()[1])
            finally:
                if file_logger_id is not None:
                    logger.removeFileLogger(file_logger_id)

            logger.info(
                '------------------------------------------------------\n')

        for idx, image in enumerate(self.image_info_list):
            _process(idx, image, sign_attr, integrity_check, sign, encrypt,
                     decrypt, val_image, val_integrity_check, val_sign,
                     val_encrypt)

        progress.complete()
    def process(self,
                verify_setup=False,
                integrity_check=False,
                sign=False,
                encrypt=False,
                decrypt=False,
                val_image=False,
                val_integrity_check=False,
                val_sign=False,
                val_encrypt=False,
                progress_cb=PROGRESS_CB_PYPASS):
        """Performs the secure-image related operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object
            is correct and return. This will ignore any other params.
        :param bool integrity_check: Add integrity check to the image.
        :param bool sign: Sign the images. (Re-sign if image is already signed)
        :param bool encrypt: Encrypt the images. (Re-encrypt if image is already
            encrypted)
        :param bool val_image: Validate the integrity of the image against the
            config file.
        :param bool val_integrity_check: Validate the integrity check in the image.
        :param bool val_sign: Validate that the image is signed and validate the
            integrity of the signing related data.
        :param bool val_encrypt: Validate that the image is encrypted and
            validate the integrity of the encryption related data.
        :param cb progress_cb: Callback method to get a status update during
            processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...

        """
        # Ensure that one or more image files is provided for processing
        if self._stager is None or not self.image_path_list:
            raise RuntimeError('Please specify one or more images for processing')

        # Ensure the correct set of operations is provided
        if not (verify_setup or integrity_check or sign or encrypt or decrypt or
                val_image or val_integrity_check or val_sign or val_encrypt):
            raise RuntimeError('Please specify one or more operations to perform.')

        if verify_setup:
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Start processing images
        total_images = len(self.image_info_list)
        progress = ProgressNotifier(total_images, progress_cb, PROGRESS_TOTAL_STAGES)

        for idx, image in enumerate(self.image_info_list):
            assert isinstance(image, ImageInfo)

            logger.info('------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' + str(total_images) + ': ' + image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            file_logger_id = None

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Enable file logging to the directory
                file_logger_id = logger.add_file_logger(c_path.join(image_output_dir, 'SecImage_log.txt'), logger.verbosity)

                # Create the security policies list for this image
                security_policy_list = create_security_policy_list(image)

                # Parsegen object
                parsegen = None

                # For secure operations
                if integrity_check or sign or encrypt or decrypt:
                    parsegen = self._process_secure_operation(image, progress, security_policy_list, integrity_check, sign, encrypt, decrypt)

                # For validation
                if val_image or val_integrity_check or val_sign or val_encrypt:
                    parsegen = self._process_validation(image, progress, security_policy_list, val_image, val_integrity_check, val_sign, val_encrypt)

                # Print the image data
                if parsegen is not None:
                    logger.info('\n' + str(parsegen))

                # Set overall processing to true
                if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or
                        (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or
                        (val_sign and image.status.validate_sign.state == StatusInfo.ERROR) or
                        (val_encrypt and image.status.validate_encrypt.state == StatusInfo.ERROR)):
                    image.status.overall.state = StatusInfo.SUCCESS

            except Exception:
                logger.debug(traceback.format_exc())
                logger.error(sys.exc_info()[1])

            if file_logger_id is not None:
                logger.removeFileLogger(file_logger_id)

            logger.info('------------------------------------------------------\n')
        progress.complete()
Example #23
0
    def process(self,
                verify_setup=False,
                sign=False,
                encrypt=False,
                decrypt=False,
                val_image=False,
                val_sign=False,
                val_encrypt=False,
                progress_cb=PROGRESS_CB_PYPASS):
        """Performs the secure-image related operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object
            is correct and return. This will ignore any other params.
        :param bool sign: Sign the images. (Re-sign if image is already signed)
        :param bool encrypt: Encrypt the images. (Re-encrypt if image is already
            encrypted)
        :param bool val_image: Validate the integrity of the image against the
            config file.
        :param bool val_sign: Validate that the image is signed and validate the
            integrity of the signing related data.
        :param bool val_encrypt: Validate that the image is encrypted and
            validate the integrity of the encryption related data.
        :param cb progress_cb: Callback method to get a status update during
            processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...

        """
        # Ensure that one or more image files is provided for processing
        if self._stager is None or not self.image_path_list:
            raise RuntimeError(
                'Please specify one or more images for processing')

        # Ensure the correct set of operations is provided
        if not (verify_setup or sign or encrypt or val_image or val_sign
                or val_encrypt or decrypt):
            raise RuntimeError(
                'Please specify one or more operations to perform.')

        if verify_setup:
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Start processing images
        total_images = len(self.image_info_list)
        progress = ProgressNotifier(total_images, progress_cb,
                                    PROGRESS_TOTAL_STAGES)

        for idx, image in enumerate(self.image_info_list):
            assert isinstance(image, ImageInfo)

            logger.info(
                '------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' +
                             str(total_images) + ': ' +
                             image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' +
                                       image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Create the encryptor object
                if encrypt or decrypt or val_encrypt:
                    try:
                        c_path.create_debug_dir(
                            image.dest_image.debug_dir_encdec)
                        encdec = get_encdec(image)
                    except Exception:
                        if not val_encrypt:
                            raise
                else:
                    encdec = None

                # Create the parsegen object
                image.encdec = encdec
                parsegen = self._status_updater(self._create_parsegen_obj,
                                                image.status.parsegen, image)
                progress.push()

                # Set the security mechanisms
                parsegen.sign = parsegen.is_signed() or sign
                parsegen.encrypt = parsegen.is_encrypted() or encrypt

                # If encrypt:
                if encrypt:
                    parsegen.encryption_params = encdec.get_encryption_parameters_blob(
                    )

                # Dump any debug data
                self.dump_parsegen_debug_data(image, parsegen)

                # Sign the image
                if sign:
                    self._status_updater(self._sign_image, image.status.sign,
                                         image, parsegen)
                progress.push()

                # Package and generate the output file
                if sign or encrypt:
                    store_data_to_file(image.dest_image.image_path,
                                       parsegen.get_data())
                    if encrypt:
                        image.status.encrypt.state = StatusInfo.SUCCESS

                    logger.info(('Signed ' if sign else '') +
                                ('& ' if sign and encrypt else '') +
                                ('Encrypted ' if encrypt else '') +
                                'image is stored at ' +
                                image.dest_image.image_path)
                    image.image_under_operation = image.dest_image.image_path

                    # Do any post processing
                    self._status_updater(
                        self._post_process, image.status.postprocess, image,
                        image.config.post_process.pil_splitter,
                        getattr(self._stager, '_meta_build_path', None))
                    progress.push()

                # Print the image data
                logger.info('\n' + str(parsegen))

                # Decrypt the image
                if decrypt:
                    store_data_to_file(image.dest_image.decrypted_file,
                                       parsegen.get_data(encrypt=False))

                # Validate parsegen
                if val_image:
                    self._validate_parsegen(image, parsegen)
                progress.push()

                # Validate sign
                if val_sign:
                    self._validate_sign(image, parsegen)
                progress.push()

                # Validate encrypt
                if val_encrypt:
                    self._validate_encrypt(image, parsegen)
                progress.push()

                # Set overall processing to true
                image.status.overall.state = StatusInfo.SUCCESS

            except Exception:
                logger.debug(traceback.format_exc())
                logger.error(sys.exc_info()[1])

            logger.info(
                '------------------------------------------------------\n')
        progress.complete()