Example #1
0
    def build(self, target, source, sign_id, config, target_base_dir, chipset,
              sec_image_policy, image_entry, relocatable):

        #import pdb; pdb.set_trace()
        self.builderutil.printinfo(
            "sectools_signer_builder: SECTOOLS_DIR = %s" % SECTOOLS_DIR)

        if sign_id == "mba_ewm":
            c_path.create_dir(target_base_dir)
            generated_config = os.path.join(target_base_dir,
                                            "generated_config.xml")
            self._generate_config_file(config, generated_config, image_entry,
                                       relocatable)
            config_used = generated_config
        else:
            config_used = config

        # Issuing sectools command
        cmds = [
            "python",
            os.path.join(SECTOOLS_DIR, "sectools.py"), "secimage", "-i",
            source, "-o", target_base_dir, "-g", sign_id, "-c", config_used
        ]

        cmds.append(sec_image_policy.cmd_options)

        self.builderutil.printinfo("sectools_signer_builder: %s" %
                                   " ".join(cmds))
        self.builderutil.execcmds(cmds, target=target)

        return self.builderutil.getReturnValueInBuilder(target)
    def build(self,
                target,
                source,
                sign_id,
                config,
                target_base_dir,
                chipset,
                sec_image_policy,
                image_entry,
                relocatable):

        #import pdb; pdb.set_trace()
        self.builderutil.printinfo("sectools_signer_builder: SECTOOLS_DIR = %s" % SECTOOLS_DIR)

        if sign_id == "mba_ewm":
            c_path.create_dir(target_base_dir)
            generated_config = os.path.join(target_base_dir, "generated_config.xml")
            self._generate_config_file(config, generated_config, image_entry, relocatable)
            config_used = generated_config
        else:
            config_used = config

        # Issuing sectools command
        cmds = ["python", os.path.join(SECTOOLS_DIR, "sectools.py"), "secimage", "-i", source,
                "-o", target_base_dir, "-g", sign_id, "-c", config_used]

        cmds.append(sec_image_policy.cmd_options)

        self.builderutil.printinfo("sectools_signer_builder: %s" % " ".join(cmds))
        self.builderutil.execcmds(cmds, target=target)

        return self.builderutil.getReturnValueInBuilder(target)
    def _sign(self, binary_to_sign, image_tosign_filename, cert_folder):

        c_path.create_dir(cert_folder)

        c_misc.store_data_to_file(image_tosign_filename, binary_to_sign)
        sig_package = signerutils.getSigPackage(cert_folder)
        if sig_package is not None:
            [signature, cert_chain_list] = signerutils.\
                                        readSigFromZip(sig_package)
            if self.validate_sig(binary_to_sign, signature,
                                 cert_chain_list) is False:
                raise ExternalSignerError(
                    self.MESG_INVALID_SIG.format(image_tosign_filename,
                                                 sig_package))

        else:
            raise ExternalSignerError(
                self.MESG_ASKUSERTOSIGN.format(image_tosign_filename,
                                               cert_folder))

        signer_output = self._get_signer_output(signature, cert_chain_list)

        self._cleanup(cert_folder)

        return signer_output
    def _sign(self, binary_to_sign,
                    image_tosign_filename, cert_folder):

        c_path.create_dir(cert_folder)

        c_misc.store_data_to_file(image_tosign_filename, binary_to_sign)
        sig_package = signerutils.getSigPackage(cert_folder)
        if sig_package is not None:
            [signature, cert_chain_list] = signerutils.\
                                        readSigFromZip(sig_package)
            if self.validate_sig(binary_to_sign, signature,
                                        cert_chain_list) is False:
                raise ExternalSignerError(
                        self.MESG_INVALID_SIG.
                                    format(image_tosign_filename, sig_package))

        else:
            raise ExternalSignerError(
                    self.MESG_ASKUSERTOSIGN.
                                format(image_tosign_filename, cert_folder))

        signer_output = self._get_signer_output(signature, cert_chain_list)

        self._cleanup(cert_folder)

        return signer_output
def validate_dir(path, var_name, error_list):
    if path:
        path = c_path.normalize(path)
        try:
            c_path.create_dir(path)
        except RuntimeError:
            error_list.append("Provided {0} \"{1}\" is not a valid path or does not have read/write access.".format(var_name, path))
    def _execute_install(self, policy):
        logger.debug("\nInstalling Sectools's output file...")
        if self.input.sectools_install_base_dir:
            path, filename = os.path.split(self.input.source)
            chipset = ConfigParser(
                self.input.config).root.metadata.get_chipset()
            src = c_path.normalize(
                c_path.join(self.input.target_base_dir, policy.id, chipset,
                            self.input.sign_id, filename))
            for install_location in policy.install_locations:
                if self.input.install_file_name:
                    dest = c_path.join(install_location,
                                       self.input.install_file_name)
                else:
                    dest = c_path.join(install_location, filename)

                # Attempt installation 3 times before failing
                installation_successful = False
                for i in range(3):
                    try:
                        c_path.create_dir(install_location)
                        copy_successful, error = c_path.copyFile(
                            src, dest, None, True)
                        if not copy_successful:
                            continue
                    except:
                        # Installation failed so retry installation
                        continue
                    installation_successful = True
                    logger.info("Installed \"{0}\" to \"{1}\"".format(
                        src, dest))
                    break
                if not installation_successful:
                    error_message = "Failed to install \"{0}\" to \"{1}\"".format(
                        src, dest)
                    logger.error(error_message)
                    raise RuntimeError(error_message)

                # pilsplit sectools's output file
                pilsplit_subdirectory = ""
                if install_location != self.input.sectools_install_base_dir:
                    pilsplit_subdirectory = install_location.replace(
                        os.path.join(self.input.sectools_install_base_dir, "",
                                     ""), "")
                pilsplit_prefix = self.input.install_file_name.split(
                    "."
                )[0] if self.input.install_file_name else filename.split(
                    ".")[0]
                self._execute_pilsplit(dest, pilsplit_prefix,
                                       pilsplit_subdirectory)
        else:
            logger.info(
                "Installation was skipped because a value for sectools_install_base_dir was not provided"
            )
            if self.input.pilsplitter_target_base_dir:
                logger.info(
                    "Pilsplitting was skipped because a value for sectools_install_base_dir was not provided"
                )
def validate_args(arguments, err_strings, init_logging):

    # configure logger to log to filesystem
    if init_logging:
        if arguments.target_base_dir:
            folder = c_path.normalize(arguments.target_base_dir)
            try:
                c_path.create_dir(folder)
            except Exception as e:
                raise RuntimeError('Unable to create directory for logging: ' +
                                   folder + '\n' + 'Error: ' + str(e))
            if arguments.sign_id:
                logging_file_name = SECTOOLS_BUILDER_TOOL_NAME.replace(
                    " ", "_") + "_" + arguments.sign_id
            else:
                logging_file_name = SECTOOLS_BUILDER_TOOL_NAME.replace(
                    " ", "_")
            logger.enable_file_logging(logging_file_name,
                                       num_logs=1,
                                       log_dir=folder)
        else:
            raise RuntimeError(err_strings[0])

    err = []
    # validate that the required fields were provided
    if not arguments.target_base_dir:
        err.append(err_strings[0])
    if not arguments.source:
        err.append(err_strings[1])
    if not arguments.sign_id:
        err.append(err_strings[2])
    if arguments.jtag_id and arguments.soc_hw_version:
        err.append(err_strings[3])
    if hasattr(arguments, "config_type") and arguments.config_type is not None:
        logger.info("Sectools Builder config was provided using new api")
        config = c_path.normalize(arguments.config_type)
        if config not in CONFIGS:
            err.append(err_strings[8])
    else:
        logger.info(
            "Sectools Builder config was provided using deprecated api")
        config = c_path.normalize(arguments.config)
        if config not in CONFIGS:
            logger.warning(
                "Sectools Builder received custom Secimage config file")
    sectools_builder_core.validate_file(config, err_strings[4], err)
    validate_bool(arguments.qti_sign, err_strings[5], err)
    validate_bool(arguments.relocatable, err_strings[6], err)
    if hasattr(
            arguments, "target_image_type_filter"
    ) and arguments.target_image_type_filter is not None and arguments.target_image_type_filter not in [
            sectools_builder_core.INTEGRITY, sectools_builder_core.SIGN,
            sectools_builder_core.ENCRYPT,
            sectools_builder_core.SIGN_AND_ENCRYPT
    ]:
        err.append(err_strings[7])
    return error_list_to_str(err)
    def generate(self):
        """Generate the secdat file based on the configs which have been setup.

        :param str secdat: the path to the secdat file to be generated.
        """
        retval_gen, reterr_gen = self._verify_generate()
        if not retval_gen:
            raise RuntimeError(reterr_gen)

        # Get the version from config file
        ucp = self._config_parser
        ucp_file_version = ucp.get_secdat_file_version()
        ucp_fuse_version = ucp.get_secdat_fuse_version()
        ucp_file_info = ucp.get_secdat_file_info()
        version_dir = self.get_version_dir(ucp_file_version)

        #--------------------------------------------------------------------------------------------------------
        # Setting input_secdat path:
        #            @ if input given as -s
        #            @ if sec.dat exists in the keyprovision_output
        #--------------------------------------------------------------------------------------------------------
        in_secdat = None

        # Checking self secdat
        if in_secdat is None:
            try:
                in_secdat = self.secdat
            except Exception:
                pass

        # Checking common secdat
        if in_secdat is None:
            common_secdat = c_path.join(self.output_dir, defines.COMMON_DIR, version_dir, defines.SEC_DAT)
            if os.path.isfile(common_secdat):
                in_secdat = common_secdat

        # Create list of output secdat
        out_secdats = []
        IO = namedtuple('IO', 'in_data out_path')

        out_secdats.append(IO(None, c_path.join(self.output_dir, self.FEATURE_DIR, version_dir, defines.SEC_DAT)))
        out_secdats.append(IO(load_data_from_file(in_secdat) if in_secdat else None,
                              c_path.join(self.output_dir, defines.COMMON_DIR, version_dir, defines.SEC_DAT)))

        # Generate the secdats:
        for secdat in out_secdats:
            out_dir = os.path.dirname(secdat.out_path)
            c_path.create_dir(out_dir)
            secdat_obj = secdat_pg(self.SECDAT_SEGMENT_TYPE, secdat.in_data)
            secdat_obj.data_model = self.data_model
            secdat_obj.write(secdat.out_path, ucp_file_version, ucp_fuse_version, ucp_file_info)
            self.dump_debug_data_model(self.data_model, out_dir)
            self.dump_debug_secdat(secdat_obj, out_dir)
            logger.info('Secdat generated at: ' + secdat.out_path)

        self.secdat = c_path.join(self.output_dir, self.FEATURE_DIR, version_dir, defines.SEC_DAT)
Example #9
0
    def _initialize(self, to_sign, image_path, signing_package_file,
                    signing_attributes):
        pathname, fname = os.path.split(signing_package_file)
        c_path.create_dir(pathname)

        self.request = get_signing_request_class(
            signing_attributes.cass_capability)(
                to_sign, "image_to_sign={0}".format(image_path),
                signing_attributes)
        self._convert_to_xml()
Example #10
0
 def output_dir(self, output_dir):
     output_dir = c_path.normalize(output_dir)
     try:
         c_path.create_dir(output_dir)
     except Exception as e:
         raise RuntimeError('Cannot write in the given output_dir: ' +
                            output_dir + '\n'
                            '    ' + 'Error: ' + str(e))
     self._output_dir = output_dir
     logger.info('Output dir is set to: ' + output_dir)
Example #11
0
 def _initialize(self, hash_to_sign, data_to_sign, image_path,
                 signing_package_file, signing_attributes):
     pathname, fname = os.path.split(signing_package_file)
     c_path.create_dir(pathname)
     self.request = get_signing_request_class(
         signing_attributes.cass_capability,
         signing_attributes.secboot_version,
         signing_attributes.sw_id)(hash_to_sign, data_to_sign, image_path,
                                   signing_attributes)
     self._convert_to_xml()
Example #12
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 not args.image_file:
            err.append('Provide an image_file for processing.')

        if args.chipset is None:
            err.append('Provide chipset to process the image.')

        if args.integrity_check or args.sign or args.validate:
            # Validate the output image resulting from all operations
            args.validate = True
        else:
            err.append('Specify one or more operations to perform.')

        # Check root certificate and key
        if args.sign:
            if not args.root_cert:
                err.append('Provide a root certificate file.')
            if not args.root_key:
                err.append('Provide a root private key file.')

        # Check and sanitize any paths for read access
        for path in ['image_file', 'root_cert', 'root_key']:
            path_val = getattr(args, path, None)
            # the file path is normalized earlier as part of its callback
            if args.sign:
                if getattr(args, path) and not c_path.validate_file(path_val):
                    err.append('Cannot access %s at: %s' % (path, path_val))

        # Check and sanitize paths for write access
        for path in ['output-dir']:
            path_val = getattr(args, path.replace('-', '_'), None)
            try:
                c_path.create_dir(path_val)
            except Exception as e:
                err.append('Cannot write at: %s\n    Error: %s' %
                           (path_val, e))

        # 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)
Example #13
0
    def create_chipset_dir(self, chipset):
        """Creates the directory in the config dir for the chipset

        :param str chipset: The chipset for which directory needs to be
            created
        :raises: RuntimeError - If directory creation fails
        """
        try:
            c_path.create_dir(self.get_chipset_dir(chipset))
        except Exception as e:
            raise RuntimeError('Failed to create directory for chipset: ' + chipset + '\n'
                               '    ' + 'Error: ' + str(e))
Example #14
0
    def process_file(self, input_file=None):
        if self.args.validate or self.serialnum is None:
            input_filename = input_file if input_file is not None else self.args.image_file
            path, filename = os.path.split(input_filename)
            signed_filename = filename
            if path != self.args.output_dir or self.args.validate is True:
                output_filename = signed_filename
            else:
                name, ext = os.path.splitext(signed_filename)
                output_filename = name + "_signed" + ext
        else:
            input_filename = TESTSIG_PATH
            output_filename = "{0}{1}.so".format(TESTSIG_PREFIX,
                                                 self.serialnum.unpadded_str)
            signed_filename = TESTSIG_FILENAME

        c_path.create_dir(self.args.output_dir)

        output_filename_base, ext = os.path.splitext(output_filename)
        self.generated_config = os.path.join(
            self.args.output_dir,
            output_filename_base + "_" + GENERATED_CONFIG)
        src_config = self.args.config if self.args.config else DEFAULT_SRC_CONFIG
        logger.debug("Source config file: {0}".format(src_config))
        self.generate_config_file(src_config, self.generated_config, self.args)

        image_info_list = self.invokeSecImage(self.args, input_filename,
                                              self.generated_config)

        #Post processing
        retValue = False if len(image_info_list) == 0 else True
        for image_info in image_info_list:
            if self.args.validate:
                if image_info.status.validate_sign.state == StatusInfo.SUCCESS:
                    logger.info("Input file is signed and valid!")
                elif image_info.status.validate_sign.state == StatusInfo.ERROR:
                    if self.log_contains(STR_OUTPUT_UNSIGNED_VALID):
                        logger.info(self.ERR_FILE_NOT_SIGNED)
                    elif self.log_contains(STR_OUTPUT_SIGNED_INVALID):
                        logger.info(self.ERR_FILE_SIG_INVALID)
                    else:
                        logger.error(self.ERR_FILE_INVALID)
                    retValue = False
            else:
                if image_info.status.sign.state == StatusInfo.SUCCESS and \
                    image_info.status.validate_sign.state == StatusInfo.SUCCESS:
                    self.postProcess(signed_filename, output_filename,
                                     self.generated_config)
                else:
                    logger.error("Signing failed!")
                    retValue = False

        return retValue
    def create_chipset_dir(self, chipset):
        """Creates the directory in the config dir for the chipset

        :param str chipset: The chipset for which directory needs to be
            created
        :raises: RuntimeError - If directory creation fails
        """
        try:
            c_path.create_dir(self.get_chipset_dir(chipset))
        except Exception as e:
            raise RuntimeError('Failed to create directory for chipset: ' + chipset + '\n'
                               '    ' + 'Error: ' + str(e))
Example #16
0
def log_to_file(folder):
    """Configures the logger to log to filesystem

    :param str folder: Directory to generate the logs in.
    """
    folder = c_path.normalize(folder)
    try:
        c_path.create_dir(folder)
    except Exception as e:
        raise RuntimeError('Unable to create directory for logging: ' + folder + '\n'
                           '    ' + 'Error: ' + str(e))
    logger.enable_file_logging(FUSEBLOWER_TOOL_NAME, num_logs=1, log_dir=folder)
Example #17
0
    def _generate_signing_package(self, hash_to_sign, signing_attributes, cass_signer_attributes,
                                image_path, signingpackage_fname, binary_to_sign):

        signingpackage = SigningPackage(secimage.__version__)
        signingrequest = signingpackage.createSigningRequest("image_to_sign=%s" % image_path)

        hexbindigest = binascii.b2a_hex(hash_to_sign)
        logger.debug("Digest to sign (hexbinary)= [%s]" % hexbindigest)
        signingrequest.setDigest(hexbindigest)
        signingrequest.setCapability(signing_attributes.cass_capability)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SW_SIZE, "0x%.8X" % len(binary_to_sign))

        hmac_params = signerutils.get_hmac_params_from_config(signing_attributes)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_HW_ID, "0x%s" % hmac_params.msm_id_str)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SW_ID, signing_attributes.sw_id)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_MODEL_ID, signing_attributes.model_id)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_OEM_ID, signing_attributes.oem_id)
        if signing_attributes.debug:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_DEBUG, signing_attributes.debug)
        if signing_attributes.app_id:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_APP_ID, signing_attributes.app_id)
        if signing_attributes.crash_dump:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_CRASH_DUMP, signing_attributes.crash_dump)

        if self._is_oid_supported(signing_attributes) is True:
            attr_min, attr_max = Certificate.GetOIDAttrName(signing_attributes.object_id.name)
            #Min/max can be supplied by CASS server and is optional
            if signing_attributes.object_id.min:
                signingrequest.setSigningAttribute(attr_min, signing_attributes.object_id.min)
            if signing_attributes.object_id.max:
                signingrequest.setSigningAttribute(attr_max, signing_attributes.object_id.max)
        else:
            #opendsp does not CASS_SIGNATTR_USE_EXP3 currently
            if signing_attributes.exponent == 3:
                signingrequest.setSigningAttribute(self.CASS_SIGNATTR_USE_EXP3, 'TRUE')
            elif signing_attributes.exponent == 65537:
                signingrequest.setSigningAttribute(self.CASS_SIGNATTR_USE_EXP3, 'FALSE')
            else:
                raise RuntimeError, "Exponent value of {0} is invalid!".format(signing_attributes.exponent)

        # Set signature algorithm to SHA256 by default
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SHA256, 'TRUE')

        pathname, fname = os.path.split(signingpackage_fname)
        c_path.create_dir(pathname)

        signingpackage.toxml()
        signingpackage.saveToFile(signingpackage_fname)
        logger.info("Signing package created. Digest = [%s]" % signingpackage.getDigest())
        return signingpackage
    def build(self, target, source, sign_id, jtag_id, soc_hw_version, config,
              target_base_dir, sec_image_policy, image_entry, relocatable):

        if jtag_id is not None and soc_hw_version is not None:
            self.builderutil.printinfo(
                'both JTAG_ID and SOC_HW_VERSION are provided: jtag_id = ' +
                str(jtag_id) + ' soc_hw_version = ' + str(soc_hw_version))
            raise RuntimeError(
                'please specify only one, JTAG_ID or SOC_HW_VERSION')

        self.builderutil.printinfo("sectools_builder: SECTOOLS_DIR = %s" %
                                   SECTOOLS_DIR)

        if sign_id.endswith("ewm"):
            c_path.create_dir(target_base_dir)
            generated_config = c_path.join(target_base_dir,
                                           "generated_config.xml")
            self._generate_config_file(config, generated_config, image_entry,
                                       relocatable)
            config = generated_config

        # Issuing sectools command
        cmds = [
            "python",
            c_path.join(SECTOOLS_DIR, "sectools.py"), "secimage", "-i", source,
            "-o", target_base_dir, "-g", sign_id, "-c", config
        ]
        """
            FR 27556: Test keys to sign CRM builds
            if both jtag_id and soc_hw_version are provided, return error and exit;
            if one is provided, use that to sign the image;
            if neither is provided, use jtag_id=0 to sign the image.
        """
        if jtag_id is not None:
            jtag_id_arg = ["--cfg_msm_part", jtag_id]
            cmds = cmds + jtag_id_arg
        elif soc_hw_version is not None:
            soc_hw_version_arg = [
                "--cfg_soc_hw_version", soc_hw_version,
                "--cfg_in_use_soc_hw_version", "1", "--cfg_msm_part", ""
            ]
            cmds = cmds + soc_hw_version_arg

        cmds.append(sec_image_policy.cmd_options)

        self.builderutil.printinfo("sectools_builder: %s" % " ".join(cmds))
        self.builderutil.execcmds(cmds, target=target)

        return self.builderutil.getReturnValueInBuilder(target)
    def dump_debug_secdat(self, secdat_parser, path):
        """Dumps the secdat related debug data into the output directory.

        :param obj secdat_parser: Parser to dump debug info for
        """
        if not self.debug:
            return

        try:
            debug_dir = c_path.join(path, defines.DEST_DEBUG_DIR)
            c_path.create_dir(debug_dir)
            secdat_repr_log = c_path.join(debug_dir, defines.DEST_DEBUG_FILE_SECDAT_REPR)
            store_data_to_file(secdat_repr_log, repr(secdat_parser))
            logger.info('Dumped debug secdat repr at: ' + secdat_repr_log  + ', date & time: ' + datetime.datetime.now().strftime('%c'))
        except Exception as e:
            logger.warning('Failed to store debug logs: ' + str(e))
    def dump_debug_data_model(self, data_model, path):
        """Dumps the data model related debug data into the output directory.

        :param obj data_model: Data model to dump debug info for
        """
        if not self.debug:
            return

        try:
            debug_dir = c_path.join(path, defines.DEST_DEBUG_DIR)
            c_path.create_dir(debug_dir)
            debug_file = c_path.join(debug_dir, defines.DEST_DEBUG_FILE_DATA_MODEL_REPR.format(self.TOOL_NAME))
            store_data_to_file(debug_file, repr(data_model))
            logger.info('Dumped debug data model repr at: ' + debug_file + ', date & time: ' + datetime.datetime.now().strftime('%c'))
        except Exception as e:
            logger.warning('Failed to store debug logs: ' + str(e))
    def _generate_signing_package(self, hash_to_sign, signing_attributes, cass_signer_attributes,
                                image_path, signingpackage_fname, binary_to_sign):

        signingpackage = SigningPackage(secimage.__version__)
        signingrequest = signingpackage.createSigningRequest("image_to_sign=%s" % image_path)

        hexbindigest = binascii.b2a_hex(hash_to_sign)
        logger.debug("Digest to sign (hexbinary)= [%s]" % hexbindigest)
        signingrequest.setDigest(hexbindigest)
        signingrequest.setCapability(cass_signer_attributes.capability)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SW_SIZE, "0x%.8X" % len(binary_to_sign))

        hmac_params = signerutils.get_hmac_params_from_config(signing_attributes)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_HW_ID, "0x%s" % hmac_params.msm_id_str)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SW_ID, signing_attributes.sw_id)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_MODEL_ID, signing_attributes.model_id)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_OEM_ID, signing_attributes.oem_id)
        if signing_attributes.debug:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_DEBUG, signing_attributes.debug)
        if signing_attributes.app_id:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_APP_ID, signing_attributes.app_id)
        if signing_attributes.crash_dump:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_CRASH_DUMP, signing_attributes.crash_dump)

        if self._is_tcg_supported(signing_attributes) is True:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_TCG_MIN, signing_attributes.tcg_min)
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_TCG_MAX, signing_attributes.tcg_max)
        else:
            #opendsp does not CASS_SIGNATTR_USE_EXP3 currently
            if signing_attributes.exponent == 3:
                signingrequest.setSigningAttribute(self.CASS_SIGNATTR_USE_EXP3, 'TRUE')
            elif signing_attributes.exponent == 65537:
                signingrequest.setSigningAttribute(self.CASS_SIGNATTR_USE_EXP3, 'FALSE')
            else:
                raise RuntimeError, "Exponent value of {0} is invalid!".format(signing_attributes.exponent)

        # Set signature algorithm to SHA256 by default
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SHA256, 'TRUE')

        pathname, fname = os.path.split(signingpackage_fname)
        c_path.create_dir(pathname)

        signingpackage.toxml()
        signingpackage.saveToFile(signingpackage_fname)
        logger.info("Signing package created. Digest = [%s]" % signingpackage.getDigest())
        return signingpackage
def generatesigned(chipset, output_dir, sig_package, sign_id=None,
                   imagefile=None, metabuild=None, verbose=False, debug=False,
                   quiet=False):
    """Returns the signed image file.
    """
    retcode = 0
    errstr = ''
    signed_image = ''
    expected_path = ''

    # Launch secimage once to get the image info list
    il = launch_secimage(chipset=chipset, output_dir=output_dir,
                         sign_id=sign_id, imagefile=imagefile,
                         metabuild=metabuild, signer=SIGNER_REMOTE,
                         sign=True, verbose=verbose, debug=debug,
                         quiet=(False if verbose else True))

    # Copy the zip to where its expected in the output directory
    sig_package_exp = SecimageRemoteClientSigner.get_signature_package_path(il[0])
    if (sig_package != sig_package_exp):
        c_path.create_dir(os.path.dirname(sig_package_exp))
        ret, err = copyFile(sig_package, sig_package_exp)
        if not ret:
            raise RuntimeError(err)

    try:
        # Launch secimage
        il = launch_secimage(chipset=chipset, output_dir=output_dir,
                             sign_id=sign_id, imagefile=imagefile,
                             metabuild=metabuild, signer=SIGNER_REMOTE,
                             sign=True, verbose=verbose, debug=debug, quiet=quiet)

        # Verify the signed image was generated
        signed_image = il[0].dest_image.image_path
        if not c_path.validate_file(signed_image):
            retcode = 1
            errstr = 'Failed to generate the signed image. ' + str(il[0].status.sign.error)
        else:
            expected_path = il[0].src_image.image_path

    except Exception as e:
        retcode = 1
        errstr = 'Exception occurred while running secimage. Exception - ' + str(e)

    return retcode, errstr, signed_image, expected_path
Example #23
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 #24
0
    def __init__(self, workspace_path):
        """Initializations and checks"""
        # Create the workspace dir
        try:
            c_path.create_dir(workspace_path)
        except Exception as e:
            raise RuntimeError('No write access to workspace dir: ' + workspace_path + '\n'
                               '    ' + 'Error: ' + e)

        # Create the config folder
        config_dir = c_path.join(workspace_path, defines.CONFIG_DIR_BASENAME)
        try:
            c_path.create_dir(config_dir)
        except Exception as e:
            raise RuntimeError('No write access to config dir: ' + config_dir + '\n'
                               '    ' + 'Error: ' + e)

        # Pass the workspace dir to ConfigDir obj
        ConfigDir.__init__(self, workspace_path)
Example #25
0
    def copyMetaBuild(self, exclusion=None, force=False, timer=3600, interval=5):
        """ copy meta build to dest directory with UFC
        :param str build_path: meta build directory, require read access
        :param str output_dir: destination directory, require write access
        :param str exclusion: file extension in semicolon separated list (e.g. .o;.lib)
        :param bool force: if enabled, will force the meta build copy even if it already exists

        :return str dest meta build directory
        """
        if self.run:
            self.retcode = ''
            # get build id from build_path as it is the directory name in dest
            build_id = getBuildIDfrompath(self.meta_build_path)

            # check if meta build is already copied to dest directory
            dest_val = c_path.normalize(self.output_dir)
            dest_dir = c_path.join(dest_val, build_id)
            UFC_complete_flag = c_path.join(dest_dir, UFC_COMPLETE_STR)
            self.log = c_path.join(dest_dir, UFC_LOG)

            if c_path.validate_file(UFC_complete_flag) and force == False:
                self.logging_state_info('meta build exists in destination directory: ' + dest_dir)
                self.logging_state_info('meta build copy is skipped')

            else:
                c_path.create_dir(dest_dir)
                cmd = [UFC_EXE, self.meta_build_path, dest_val, '-e', exclusion] if exclusion else [UFC_EXE, self.meta_build_path, dest_val]

                self.logging_state_info(getCurrentTime() + ' start meta build copy, please wait and do not interrupt ...')
                self.logging_state_info('UFC command: ' + " ".join(cmd))
                self.run = False
                self.retcode = self.execute(cmd, self.log, dest_val, timer, interval)
                self.logging_state_info(getCurrentTime() + ' UFC return code: ' + str(self.retcode))
                self.logging_state_info('UFC log can be found at: ' + self.log)
                if self.retcode == 0:
                    open(UFC_complete_flag,'a').close()
                    self.run = True
                self.logging_state_info(SECTION_BREAK)
        else:
            self.logging_state_info('skip meta build copying')

        return dest_dir
 def _execute_pilsplit(self, file_to_pilsplit, pilsplit_prefix, subdirectory):
     logger.debug("\nPilsplitting Sectools's output file...")
     if self.input.pilsplitter_target_base_dir:
         try:
             if subdirectory:
                 subdir = c_path.join(self.input.pilsplitter_target_base_dir, subdirectory)
                 c_path.create_dir(subdir)
                 prefix = c_path.join(subdir, pilsplit_prefix)
             else:
                 subdir = self.input.pilsplitter_target_base_dir
                 prefix = c_path.join(self.input.pilsplitter_target_base_dir, pilsplit_prefix)
             SecImageCore.pil_split(file_to_pilsplit, prefix)
             logger.info("Pilsplitted \"{0}\" into directory \"{1}\"".format(file_to_pilsplit, subdir))
         except Exception as e:
             logger.error(str(e))
             error_message = "Failed to pilsplit \"{0}\"".format(file_to_pilsplit)
             logger.error(error_message)
             raise RuntimeError(error_message)
     else:
         logger.info("Pilsplit was skipped because a value for pilsplitter_target_base_dir was not provided")
    def _execute_pilsplit(self, file_to_pilsplit, pilsplit_prefix,
                          subdirectory):
        logger.debug("\nPilsplitting Sectools's output file...")
        if self.input.pilsplitter_target_base_dir:
            # Attempt pilsplit 3 times before failing
            pilsplit_successful = False
            for i in range(3):
                try:
                    if subdirectory:
                        subdir = c_path.join(
                            self.input.pilsplitter_target_base_dir,
                            subdirectory)
                        c_path.create_dir(subdir)
                        prefix = c_path.join(subdir, pilsplit_prefix)
                    else:
                        subdir = self.input.pilsplitter_target_base_dir
                        prefix = c_path.join(
                            self.input.pilsplitter_target_base_dir,
                            pilsplit_prefix)

                    SecImageCore.pil_split(file_to_pilsplit, prefix)
                except:
                    # Pilsplitting failed so retry pilsplit
                    continue
                pilsplit_successful = True
                logger.info(
                    "Pilsplitted \"{0}\" into directory \"{1}\"".format(
                        file_to_pilsplit, subdir))
                break
            if not pilsplit_successful:
                error_message = "Failed to pilsplit \"{0}\"".format(
                    file_to_pilsplit)
                logger.error(error_message)
                raise RuntimeError(error_message)
        else:
            logger.info(
                "Pilsplit was skipped because a value for pilsplitter_target_base_dir was not provided"
            )
Example #28
0
        def _process(idx, image, integrity_check, sign,
                     val_image, val_integrity_check, val_sign):
            assert isinstance(image, ImageInfoIot)

            logger.info('------------------------------------------------------')
            status_string = ('Processing: ' + 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, 'IoT_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:
                    parsegen = self._process_secure_operation(
                        image, progress, security_policy_list, integrity_check, sign,
                        parsegens=parsegens.get(image.chipset, list()))

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

                # 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)):
                    image.status.overall.state = StatusInfo.SUCCESS

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

        # Check the operations
        if not (args.integrity_check or args.sign or args.encrypt
                or args.decrypt or args.validate or args.verify_inputs):
            err.append('Specify one or more operations to perform.')

        # 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)
Example #30
0
    def c_validate(self):
        """Validates the command line args provided by the user.

        :raises: RuntimeError
        """
        args = self.parsed_args
        err = []

        if not args.platform:
            # Check the config paths
            if args.user_config_path and not args.keymap_config_path:
                err.append(
                    'Please provide the keymap config files using '
                    '--oem_config_path along with the user config file.')
            if not (args.keymap_config_path):
                err.append(
                    'Please provide the config files using '
                    '--user_config_path, --keymap_config_path, '
                    'or provide the platform details using -p <platform> ')

            # Check and sanitize any paths for read access
            for path in ['user_config_path', 'keymap_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)

        if args.platform and (args.keymap_config_path
                              or args.user_config_path):
            err.append(
                'Please provide either config files or platform as a input. '
                'Please do not provide both types of input for generation of sec.dat'
            )

        # Check the operations
        if not (args.generate or args.validate or args.verify_inputs):
            err.append('Please specify one or more operations to perform.')
        if args.validate and not args.generate:
            if not args.secdat:
                err.append(
                    'Please provide path to the secdat file using -s for validation.'
                )

        # Check and sanitize any paths for read access
        for path in ['secdat']:
            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 paths for write access
        for path in ['output_dir']:
            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)
Example #31
0
        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')
Example #32
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)
                    \"""
                    ...

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

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

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

                # 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 #33
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)
    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 #35
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,
                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 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
            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)

        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)

                # 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, 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 RemoteSignerNote as e:
                logger.info('NOTE: ' + str(e), color=logger.YELLOW)

            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()