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