def _get_config_path(self, chipset_dir): """Returns the config found in the chipset dir matching the naming conventions. If the config file is not found in the dir, None is returned. :param str chipset_dir: The directory in which to look for config path. :returns: config_file :rtype: (str) """ config = None chipset_from_dir_name = os.path.basename(chipset_dir) for entry in os.listdir(chipset_dir): path = c_path.join(chipset_dir, entry) if c_path.validate_file(path) and entry.endswith(defines.XML_NAME_ENDING): # Extract the chipset from the file try: chipset_from_file = ConfigParser.get_chipset_from_file(path) except Exception as e: logger.warning('Skipping file: ' + entry + '\n' ' ' + 'Failed to load the file: ' + str(e)) continue # Check the naming conventions if chipset_from_file == chipset_from_dir_name: config = path else: logger.warning('Skipping file: ' + entry + '\n' ' ' + 'Chipset from file: "' + chipset_from_file + '" does not match chipset from dir name: "' + chipset_from_dir_name + '"') else: logger.debug2('Skipping file: ' + entry + '\n' ' ' + 'Name does not match any of the naming convention patters') logger.debug2('Config path found for chipset_dir: ' + chipset_dir + '\n' ' ' + 'config: ' + str(config)) return config
def getSigPackage(cert_folder): sig_package = None zipfiles = glob.glob(c_path.join(cert_folder, '*.zip')) if len(zipfiles) == 1: sig_package = zipfiles[0] elif len(zipfiles) > 1: raise ExternalSignerError(MESG_MULTIPLE_ZIP.format(cert_folder)) return sig_package
def get_chipset_config_path(self, chipset): """ :param str chipset: chipset to return config file for :returns: config path corresponding to the given chipset :rtype: str """ logger.debug('Searching configs corresponding to chipset: ' + chipset) chipset_dir = c_path.join(self.config_dir, chipset) if c_path.validate_dir(chipset_dir): return self._get_config_path(chipset_dir) raise RuntimeError('Did not find config for chipset: "' + chipset + '"')
def __init__(self, config_dir): """Initializations and checks""" if not c_path.validate_dir(config_dir): raise RuntimeError('Directory doesnt exist: ' + config_dir) # First level of directory that is expected sub_config_dir = c_path.join(config_dir, defines.CONFIG_DIR_BASENAME) try: c_path.validate_dir(sub_config_dir) except Exception as e: raise RuntimeError('Directory ' + config_dir + '\n' ' ' + 'must contain configs sub directory: ' + defines.CONFIG_DIR_BASENAME) self.config_dir = sub_config_dir
def config_paths(self): """(list[tuple(str)]) List of the config paths found in the workspace conforming to the naming structure. """ config_dir = self.config_dir config_paths = [] logger.debug('Searching config path sets in dir: ' + config_dir) for entry in os.listdir(config_dir): path = c_path.join(config_dir, entry) if c_path.validate_dir(path): config = self._get_config_path(path) if config: config_paths.append(config) else: logger.debug2('Skipping dir: ' + entry + '\n' ' ' + 'Does not contain any configs') else: logger.debug2('Skipping file in first level: ' + entry) logger.debug('Config paths found from the config dir: ' + str(config_paths)) return config_paths
# Absolute path of the package PACKAGE_PATH = DIR_PATH # Name of the root node of any config related objects ROOTNODE_NAME = 'keyprovision' # Name of the directory containing chip specific folders CONFIG_DIR_BASENAME = 'config' #------------------------------------------------------------------------------ # Auto-generated XML Parser related information #------------------------------------------------------------------------------ # XML - Basic information XML_PY_FILE_NAME = 'auto_gen_fb_config.py' XML_PY_FILE_NAME_USER = '******' XML_PY_PATH = c_path.join(PACKAGE_PATH, XML_PY_FILE_NAME) XML_PY_PATH_USER = c_path.join(PACKAGE_PATH, XML_PY_FILE_NAME_USER) XML_NAME_ENDING_OEM = '_' + ROOTNODE_NAME + '_KEYMAP' + '.xml' XML_NAME_ENDING_QC = '_' + ROOTNODE_NAME + '_QC' + '.xml' XML_NAME_ENDING_UI = '_' + ROOTNODE_NAME + '_UI' + '.xml' XML_NAME_ENDING_USER = '******' + ROOTNODE_NAME + '_USER' + '.xml' # XML - lines at the beginning of the file XML_PREPEND_LINES = '<?xml version="1.0" encoding="UTF-8"?>\n' # XML - rootnode related constants XML_ROOTNODE_NAMESPACE = 'tns:' XML_ROOTNODE_NAME = ROOTNODE_NAME XML_ROOTNODE = XML_ROOTNODE_NAMESPACE + XML_ROOTNODE_NAME
def generate(self): """Generate the debugpolicy elf file based on the configs which have been setup. """ # Set the debug params if self.debug: debug_dir = c_path.join(self.output_dir, defines.DEST_DEBUG_DIR) debug_prefix, debug_suffix = os.path.splitext( os.path.basename(c_path.join(self.output_dir, 'dp.dat'))) else: debug_dir, debug_prefix, debug_suffix = None, None, None dbgpelfparser = ParseGenDbgpElf( version=self._config_parser.root.file_properties.revision, debug_dir=debug_dir, debug_prefix=debug_prefix, debug_suffix=debug_suffix, elf_class=self._config_parser.root.file_properties.elf.elf_class) # Set version number to be revision number dbgpelfparser.dbgpparser.header.version = self._config_parser.root.file_properties.revision # Set serial number start and end values if not (self._config_parser.root.file_properties.serial_number_start is None or \ self._config_parser.root.file_properties.serial_number_end is None): self.versionAttrCheck(dbgpelfparser.dbgpparser.header, "set_sernum", ["serial_number_start", "serial_number_end"]) dbgpelfparser.dbgpparser.header.set_sernum( self._config_parser.root.file_properties.serial_number_start, self._config_parser.root.file_properties.serial_number_end) # Validate flag bits and set flags self.flagBitsCheck(dbgpelfparser.dbgpparser.header.INVALID_FLAG_BITS, self._config_parser.root.file_properties.flags) dbgpelfparser.dbgpparser.header.flags = self._config_parser.root.file_properties.flags # Set imagebit_map if self._config_parser.root.file_properties.image_bit_map is not None: self.versionAttrCheck(dbgpelfparser.dbgpparser.header, "imagebit_map", "image_bit_map") dbgpelfparser.dbgpparser.header.imagebit_map = self._config_parser.root.file_properties.image_bit_map # Set Image ID Info if self._config_parser.root.file_properties.image_id_list is not None: self.versionAttrCheck(dbgpelfparser.dbgpparser.header, "imgid_array", "image_id_list") dbgpelfparser.dbgpparser.header.imgid_array = self._config_parser.root.file_properties.image_id_list.image_id # Initialize rootcerthash array dbgpelfparser.dbgpparser.header.rootcerthash_array = self._config_parser.root.file_properties.root_cert_hash_list.root_cert_hash # Set Serial Num List if self._config_parser.root.file_properties.serial_num_list is not None: self.versionAttrCheck(dbgpelfparser.dbgpparser.header, "serial_num_array", "serial_num_list") dbgpelfparser.dbgpparser.header.serial_num_array = self._config_parser.root.file_properties.serial_num_list.serial_num # Set physical address dbgpelfparser.phys_addr = self._config_parser.root.file_properties.elf.phys_addr # Validate header version contents dbgpelfparser.dbgpparser.header.validate_ranges() dbgpelf_data = dbgpelfparser.get_data() dp_unsigned = c_path.join(self.output_dir, 'dp_unsigned.mbn') store_data_to_file(dp_unsigned, dbgpelf_data) logger.info('Generated unsigned debugpolicy elf file at: ' + dp_unsigned + ', date & time: ' + datetime.datetime.now().strftime('%c')) dp_unsigned_repr = c_path.join(self.output_dir, 'dbgpelf_repr.txt') store_data_to_file(dp_unsigned_repr, repr(dbgpelfparser)) logger.info('Dumped debugpolicy elf repr at: ' + dp_unsigned_repr + ', date & time: ' + datetime.datetime.now().strftime('%c')) self.sign(dp_unsigned)
def generate(self, args): infile = open(args.input_file, "rb") infile_data = infile.read() infile.close() if self.is_mbn_file(infile_data, args.input_file) is not None: logger.warning("WARNING! {0} appears to already have an MBN header!".format(args.input_file)) # sectools will update these values when it inputs the cert chain and sig # but in this feature just set them to zero code_size = ALIGNED_IMAGE_SIZE(os.path.getsize(args.input_file)) signature_size = 0 signature_ptr = 0 cert_chain_ptr = 0 cert_chain_size = 0 image_size = code_size + signature_size + cert_chain_size header = None if args.header_length == 40: header = MbnHdr40B() header._unpack_data_list([args.image_id, args.header_version, args.image_src, args.image_dest_ptr, image_size, code_size, signature_ptr, signature_size, cert_chain_ptr, cert_chain_size]) elif args.header_length == 80: header = MbnHdr80B() # todo: verify magic and codeword are correct header._unpack_data_list([MBN_80_CODEWORD, # codeword I pulled from given file MBN_80_MAGIC, # magic I pulled from given file args.image_id, 0xffffffff, 0xffffffff, args.image_src, args.image_dest_ptr, image_size, code_size, signature_ptr, signature_size, cert_chain_ptr, cert_chain_size, 0, # this has a value of 1 in a file I was given. what does it mean? 0, 0, 0, 0, 0, 0]) else: raise RuntimeError("received invalid MBN header length in generate. This should never happen") outfile_name = os.path.basename(args.input_file) + ".mbn" if not c_path.validate_dir_write(args.output_dir): os.makedirs(args.output_dir) outfile = open(c_path.join(args.output_dir, outfile_name), "wb") outfile.write(header.pack()) outfile.write(infile_data) outfile.close() infile.close() logger.info("output \"{0}\" has been successfully generated".format(c_path.join(args.output_dir, outfile_name)))
def image_path(self): return c_path.join(self.image_dir, self.image_name)
# =============================================================================== # # Copyright (c) 2013-2016 Qualcomm Technologies, Inc. # All Rights Reserved. # Confidential and Proprietary - Qualcomm Technologies, Inc. # # =============================================================================== from __secfile__ import DIR_PATH from sectools.common.builder.builderutils import BuilderUtil from sectools.features.isc.cfgparser import ConfigParser from sectools.common.utils import c_path SECTOOLS_DIR = c_path.join(DIR_PATH, "..", "..", "..", "..") EWM_TYPE = "elf_wrapped_mbn" class GenericSecImageBuilder(object): def __init__(self, env): self.env = env self.builderutil = BuilderUtil(env) def _generate_config_file(self, src_config, dest_config, image_entry, relocatable): config = ConfigParser(src_config) image_type_list = config.root.parsegen.get_image_types_list() for image_type in image_type_list.get_image_type(): if image_type.id == EWM_TYPE: #Override relocatable setting image_type.ewm_properties.relocatable = relocatable
def cert_folder(self): dir_name = defines.DEST_DIR_CERT_FOLDER return c_path.join(self.image_dir, dir_name)
def debug_dir_encdec(self): return c_path.join(self.debug_dir, self._mid, defines.DEST_DEBUG_DIR_ENCDEC) if self._debug_enable else None
def debug_file_parsegen_encrypted(self): file_name = (self.image_name_base + defines.DEST_DEBUG_FILE_PARSEGEN_ENCRYPTED + self.image_name_ext) return c_path.join(self.debug_dir_parsegen, file_name) if self._debug_enable else None
def debug_file_signer_root_key(self): return c_path.join(self.debug_dir_signer, defines.DEST_DEBUG_FILE_SIGNER_ROOT_KEY) if self._debug_enable else None
def debug_file_parsegen_signature(self): file_name = (self.image_name_base + defines.DEST_DEBUG_FILE_PARSEGEN_SIGNATURE + self.image_name_ext) return c_path.join(self.debug_dir_parsegen, file_name) if self._debug_enable else None
def debug_file_parsegen_integrity_check(self): file_name = (self.image_name_base + defines.DEST_DEBUG_FILE_PARSEGEN_INTEGRITY_CHECK + self.image_name_ext) return c_path.join(self.debug_dir_parsegen, file_name) if self._debug_enable else None
def debug_file_parsegen_cert_chain(self): file_name = (self.image_name_base + defines.DEST_DEBUG_FILE_PARSEGEN_CERT_CHAIN + self.image_name_ext) return c_path.join(self.debug_dir_parsegen, file_name) if self._debug_enable else None
def debug_dir_signer(self): return c_path.join(self.debug_dir, self._mid, defines.DEST_DEBUG_DIR_SIGNER) if self._debug_enable else None
#------------------------------------------------------------------------------ # Common constants #------------------------------------------------------------------------------ # Absolute path of the package PACKAGE_PATH = DIR_PATH # Name of the root node of any config related objects ROOTNODE_NAME = 'SSD_METADATA' #------------------------------------------------------------------------------ # Auto-generated XML Parser related information #------------------------------------------------------------------------------ # XML - Basic information XML_PY_FILE_NAME = 'auto_gen_ssd_xml_config.py' XML_PY_PATH = c_path.join(PACKAGE_PATH, XML_PY_FILE_NAME) # XML - lines at the beginning of the file XML_PREPEND_LINES = '<?xml version="1.0" encoding="UTF-8"?>\n' # XML - rootnode related constants XML_ROOTNODE_NAMESPACE = 'xs:' XML_ROOTNODE_NAME = ROOTNODE_NAME XML_ROOTNODE = XML_ROOTNODE_NAMESPACE + XML_ROOTNODE_NAME # XML - namespace related constants XML_NAMESPACE_SSD = 'xmlns:tns="http://www.qualcomm.com/ssd_enc_param"' XML_NAMESPACE_W3 = 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' XML_NAMESPACE_SCHEMA = 'xsi:schemaLocation="http://www.qualcomm.com/fuseblower ../xsd/fuseblower.xsd"' XML_NAMESPACE_SCHEMA_USER = '******'
def debug_file_signer_attestation_key(self): return c_path.join(self.debug_dir_signer, defines.DEST_DEBUG_FILE_SIGNER_ATTESTATION_KEY) if self._debug_enable else None
def decrypted_file(self): file_name = (self.image_name_base + defines.DEST_FILE_DECRYPTED + self.image_name_ext) return c_path.join(self.image_dir, file_name)
def debug_file_signer_signature(self): return c_path.join(self.debug_dir_signer, defines.DEST_DEBUG_FILE_SIGNER_SIGNATURE) if self._debug_enable else None
def debug_dir_parsegen(self): return c_path.join(self.debug_dir, self._mid, defines.DEST_DEBUG_DIR_PARSEGEN) if self._debug_enable else None
def debug_file_signer_cert_chain(self): return c_path.join(self.debug_dir_signer, defines.DEST_DEBUG_FILE_SIGNER_CERT_CHAIN) if self._debug_enable else None
def image_dir(self): return c_path.join(self.image_dir_base, self.image_dir_ext)
def get_meta_info(cls, meta_build_path): sys.path.append(c_path.join(meta_build_path, cls.META_LIB_PATH_REL)) import meta_lib return meta_lib.meta_info(meta_build_path)
def build(self, target, source, sign_id, signer, qc_sign, jtag_id, soc_hw_version, soc_vers, app_id, 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 and soc_hw_version is None: jtag_id_arg = ["--cfg_msm_part", jtag_id] cmds = cmds + jtag_id_arg elif soc_hw_version is not None and jtag_id is None: soc_hw_version_arg = [ "--cfg_soc_hw_version", soc_hw_version, "--cfg_in_use_soc_hw_version", "1" ] cmds = cmds + soc_hw_version_arg """ FR34970: Signing software for multiple SOC HW Versions """ if soc_vers is not None: soc_vers_arg = ["--cfg_soc_vers", soc_vers] cmds = cmds + soc_vers_arg """ CR : support passing app_id for TZapps image signing """ if app_id is not None: app_id_arg = ["--cfg_app_id", app_id] cmds += app_id_arg """ 8998 TZ QC signing with CASS """ if signer: signer_arg = ["--cfg_selected_signer", signer] cmds = cmds + signer_arg if qc_sign: cmds = cmds + ["--qc_signing"] 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 get_chipset_dir(self, chipset): """Returns the expected path within the config dir for the chipset :param str chipset: The chipset for which directory path is queried. """ return c_path.join(self.config_dir, chipset)
def _validate_generation(self, dp_file): """Validate the generation """ reterr = [] # Set the debug params if self.debug: debug_dir = c_path.join(self.output_dir, defines.DEST_DEBUG_DIR) debug_prefix, debug_suffix = os.path.splitext( os.path.basename(c_path.join(self.output_dir, 'dp.dat'))) else: debug_dir, debug_prefix, debug_suffix = None, None, None dbgpelfparser = ParseGenDbgpElf( data=load_data_from_file(dp_file), version=self._config_parser.root.file_properties.revision, debug_dir=debug_dir, debug_prefix=debug_prefix, debug_suffix=debug_suffix, elf_class=None) # Validate against the debugpolicy config file if self._config_parser: if dbgpelfparser.dbgpparser.header.version != self._config_parser.root.file_properties.revision: reterr.append( 'Revision mismatch ' '' + 'Debugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.version) + '' + ' Config File: ' + str(self._config_parser.root.file_properties.revision)) logger.error(reterr) return if getattr(dbgpelfparser.dbgpparser.header, 'sernum_start', None) is not None and \ dbgpelfparser.dbgpparser.header.sernum_start != self._config_parser.root.file_properties.serial_number_start: reterr.append( 'Serial Number Start mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.sernum_start) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. serial_number_start)) if getattr(dbgpelfparser.dbgpparser.header, 'sernum_end', None) is not None and \ dbgpelfparser.dbgpparser.header.sernum_end != self._config_parser.root.file_properties.serial_number_end: reterr.append('Serial Number End mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.sernum_end) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. serial_number_end)) if dbgpelfparser.dbgpparser.header.flags != self._config_parser.root.file_properties.flags: reterr.append( 'Flags mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.flags) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties.flags)) if self._config_parser.root.file_properties.image_bit_map is not None: if dbgpelfparser.dbgpparser.header.imagebit_map != self._config_parser.root.file_properties.image_bit_map: reterr.append( 'Image Bit Map mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.imagebit_map) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. image_bit_map)) if self._config_parser.root.file_properties.image_bit_map is None: if getattr(dbgpelfparser.dbgpparser.header, 'imagebit_map', None) is not None: if dbgpelfparser.dbgpparser.header.imagebit_map != 0: if dbgpelfparser.dbgpparser.header.imagebit_map != self._config_parser.root.file_properties.image_bit_map: reterr.append('Image Bit Map mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header. imagebit_map) + '' + '\nConfig File: ' + str(self._config_parser.root. file_properties.image_bit_map)) if self._config_parser.root.file_properties.image_id_list is not None: if len(self._config_parser.root.file_properties.image_id_list. image_id) == 0: for i in range( len( list(dbgpelfparser.dbgpparser.header. imgid_array))): if list(dbgpelfparser.dbgpparser.header.imgid_array )[i] != 0: reterr.append( 'Image ID Array mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.imgid_array ) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. image_id_list.image_id + list([0] * (32 - len(self._config_parser.root. file_properties. image_id_list.image_id))))) break else: for i in range( len(self._config_parser.root.file_properties. image_id_list.image_id)): if list( dbgpelfparser.dbgpparser.header.imgid_array )[i] != self._config_parser.root.file_properties.image_id_list.image_id[ i]: reterr.append( 'Image ID Array mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.imgid_array ) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. image_id_list.image_id + list([0] * (32 - len(self._config_parser.root. file_properties. image_id_list.image_id))))) if self._config_parser.root.file_properties.image_id_list is None: if getattr(dbgpelfparser.dbgpparser.header, 'imgid_count', None) is not None: if dbgpelfparser.dbgpparser.header.imgid_count != 0: reterr.append( 'Image ID Array mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.imgid_array) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. image_id_list)) if dbgpelfparser.dbgpparser.header.rootcerthash_array[:dbgpelfparser.dbgpparser.header.rootcerthash_count] != \ [x.lower() for x in self._config_parser.root.file_properties.root_cert_hash_list.root_cert_hash]: reterr.append( 'Root Certificate Hash Array mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.rootcerthash_array) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. root_cert_hash_list.root_cert_hash)) if getattr(dbgpelfparser.dbgpparser.header, 'serial_num_array', None) is not None: if len(self._config_parser.root.file_properties. serial_num_list.serial_num) == 0: reterr.append( 'Serial Number Array mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header.serial_num_array) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. serial_num_list.serial_num + list([0] * (200 - len(self._config_parser.root.file_properties. serial_num_list.serial_num))))) else: for i in range( len(self._config_parser.root.file_properties. serial_num_list.serial_num)): if list( dbgpelfparser.dbgpparser.header. serial_num_array )[i] != self._config_parser.root.file_properties.serial_num_list.serial_num[ i]: reterr.append( 'Serial Number Array mismatch ' '' + ':- \nDebugpolicy File: ' + str(dbgpelfparser.dbgpparser.header. serial_num_array) + '' + '\nConfig File: ' + str(self._config_parser.root.file_properties. serial_num_list.serial_num + list([0] * (200 - len(self._config_parser.root. file_properties.serial_num_list. serial_num))))) if reterr: if len(reterr) > 1: reterr = [(' ' + str(idx + 1) + '. ' + error) for idx, error in enumerate(reterr)] reterr = 'Following errors were found during validation:\n\n' + '\n'.join( reterr) else: reterr = reterr[0] logger.error(reterr) else: logger.info( 'Validation of debugpolicy file against debugpolicy config file is Successful!' )
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 to_sign(self): file_name = (self.image_name_base + defines.DEST_FILE_TO_SIGN + self.image_name_ext) return c_path.join(self.image_dir, file_name)
"""Contains constants related to the isc package.""" from __secfile__ import DIR_PATH from sectools.common.utils import c_path #------------------------------------------------------------------------------ # Common constants #------------------------------------------------------------------------------ # Absolute path of the package PACKAGE_PATH = DIR_PATH # Default config directory (relative path) DEFAULT_CONFIG_DIR_REL = '../../..' # Default config directory (absolute path) DEFAULT_CONFIG_DIR = c_path.join(PACKAGE_PATH, DEFAULT_CONFIG_DIR_REL) #------------------------------------------------------------------------------ # ImageInfo Dest Dir constants #------------------------------------------------------------------------------ DEST_DEBUG_DIR = 'debug' DEST_DEBUG_DIR_PARSEGEN = 'parsegen' DEST_DEBUG_DIR_SIGNER = 'signer' DEST_DEBUG_DIR_ENCDEC = 'encdec' DEST_DEBUG_FILE_PARSEGEN_UNSIGNED = '_unsigned' DEST_DEBUG_FILE_PARSEGEN_TOSIGN = '_tosign' DEST_DEBUG_FILE_PARSEGEN_CERT_CHAIN = '_cert_chain' DEST_DEBUG_FILE_PARSEGEN_SIGNATURE = '_signature' DEST_DEBUG_FILE_PARSEGEN_INTEGRITY_CHECK = '_integrity_check' DEST_DEBUG_FILE_PARSEGEN_SIGNED = '_signed'
def debug_dir(self): return c_path.join(self.image_dir, defines.DEST_DEBUG_DIR) if self._debug_enable else None
import os from sectools.common.utils import c_path #------------------------------------------------------------------------------ # Common constants #------------------------------------------------------------------------------ # Absolute path of the package PACKAGE_PATH = os.path.dirname(os.path.realpath(__file__)) # Default config directory (relative path) DEFAULT_CONFIG_DIR_REL = '../../..' # Default config directory (absolute path) DEFAULT_CONFIG_DIR = c_path.join(PACKAGE_PATH, DEFAULT_CONFIG_DIR_REL) #------------------------------------------------------------------------------ # ImageInfo Dest Dir constants #------------------------------------------------------------------------------ DEST_DEBUG_DIR = 'debug' DEST_DEBUG_DIR_PARSEGEN = 'parsegen' DEST_DEBUG_DIR_SIGNER = 'signer' DEST_DEBUG_DIR_ENCDEC = 'encdec' DEST_DEBUG_FILE_PARSEGEN_UNSIGNED = '_unsigned' DEST_DEBUG_FILE_PARSEGEN_TOSIGN = '_tosign' DEST_DEBUG_FILE_PARSEGEN_CERT_CHAIN = '_cert_chain' DEST_DEBUG_FILE_PARSEGEN_SIGNATURE = '_signature' DEST_DEBUG_FILE_PARSEGEN_INTEGRITY_CHECK = '_integrity_check' DEST_DEBUG_FILE_PARSEGEN_SIGNED = '_signed'
def discover(self): """Searches for the openssl binary in: #. The environment using the openssl tag #. Prepackaged binary folder #. Current path #. System path :returns str: Path to the openssl binary. """ module_name = BINARY_NAME.title() filenames = bin_names(BINARY_NAME) module = ModuleNotFound logger.debug2('module_name: ' + str(module_name) + ', filenames: ' + str(filenames)) for filename in filenames: # Using the environment if OPENSSL_ENV_DIR_TAG in os.environ: logger.debug2( str(OPENSSL_ENV_DIR_TAG) + ' tag found in environment') env_module = c_path.join(os.environ[OPENSSL_ENV_DIR_TAG], filename) logger.debug2('Looking for: ' + str(env_module)) if not c_path.validate_file(env_module): logger.warning( module_name + ': File from environment does not exist at - ' + env_module) elif not self.is_supported_version(env_module): logger.warning( module_name + ': File from environment is not the correct version - ' + env_module) else: module = env_module logger.debug2(module_name + ': Found from environment at - ' + env_module) break # Searching in prepacked dir, current dir and system paths else: folder = packaged_bin_folder logger.debug2('Looking for: ' + str(filename) + ' in folder: ' + str(folder)) for module_found in c_path.which_generator(filename, paths=[folder], find_one=False): if not self.is_supported_version(module_found): logger.debug2('Incorrect version: ' + str(module_found)) continue module = module_found conf_file = c_path.join(folder, OPENSSL_CONF_FILE) if c_path.validate_file(conf_file): os.environ[OPENSSL_ENV_CONF_TAG] = conf_file logger.debug2(module_name + ': Found at - ' + module) break # Check if module is found if module != ModuleNotFound: break else: logger.error(module_name + ': Not Found') # Log if permissions are not correct if module != ModuleNotFound and not os.access(module, os.X_OK): logger.error(module_name + ': Cannot execute. Missing execution permission.') return module
def generatehash(chipset, output_dir, sign_id=None, imagefile=None, metabuild=None, send_signattrs=False, verbose=False, debug=False, quiet=False): """Returns the hash for the image file that should be signed. """ retcode = 0 errstr = '' hash_package = '' try: # 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_LOCAL, verify_input=True, verbose=verbose, debug=debug, quiet=(False if verbose else True)) # Check that the signature package isnt already present signature_package = SecimageRemoteClientSigner.get_signature_package_path( il[0]) if c_path.validate_file(signature_package): retcode = 1 errstr = ('Signature package ' + signature_package + ' is present. ' 'Please remove to generate hash.') # Continue if no error if retcode == 0: # Check that the hash package isnt already present hash_package = SecimageRemoteClientSigner.get_to_sign_package_path( il[0]) if c_path.validate_file(hash_package): retcode = 1 errstr = ('Hash package ' + hash_package + ' is already present. ' 'Please remove to re-generate hash.') # Continue if no error if retcode == 0: # Create new config file to update the send signing attribute temp_config_file = None if send_signattrs: def update_cfg_cb(config): remote_config = auto_gen_xml_config.complex_remote_client_signer_attributes( ) remote_config.send_signing_overrides = send_signattrs config.root.signing.signer_attributes.remote_client_signer_attributes = remote_config temp_config_file = c_path.join(output_dir, 'hash_package_config.xml') update_config(chipset, update_cfg_cb, temp_config_file) chipset = None try: # Launch secimage to generate the hash package 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, config=temp_config_file) finally: if not debug: try: os.remove(temp_config_file) except Exception as e: pass # Verify the hash package was generated hash_package = SecimageRemoteClientSigner.get_to_sign_package_path( il[0]) if not c_path.validate_file(hash_package): retcode = 1 errstr = 'Failed to generate the hash package. ' + str( il[0].status.sign.error) except Exception as e: retcode = 1 errstr = 'Exception occurred while running secimage. Exception - ' + str( e) return retcode, errstr, hash_package
def generatesigpack(output_dir, hash_package, accept_signattrs=False, verbose=False, debug=False, quiet=False): """Returns the signature/certs package for the hash provided. """ retcode = 0 errstr = '' sig_package = '' # Objects to be cleaned at the end to_sign_file = None temp_config_file = None copied_sig_file = None try: # Unzip the hash package def get_hash_package_data(package): to_sign_package = Package( None, SecimageRemoteClientSigner.get_class_ToSignPackageFiles(), package=package) to_sign_package.update_data() return SecimageRemoteClientSigner.use_tosign_data( to_sign_package.pf) to_sign, signing_config = get_hash_package_data(hash_package) # Extract the signing info signing_config = json.loads(signing_config) chipset = str(signing_config['chipset']) sign_id = str(signing_config['sign_id']) # Save to_sign to a temp file to_sign_file_path = c_path.join(output_dir, 'hash_to_sign.bin') store_data_to_file(to_sign_file_path, to_sign) to_sign_file = to_sign_file_path if retcode == 0: # Create new config file to update the allow signing attribute & # the file type def update_cfg_cb(config): remote_config = auto_gen_xml_config.complex_remote_signer_attributes( ) remote_config.allow_signing_overrides = accept_signattrs config.root.signing.signer_attributes.remote_signer_attributes = remote_config sign_id_config = config.get_config_for_sign_id(sign_id) sign_id_config.pil_split = False sign_id_config.image_type = 'hash_to_sign' temp_config_file = c_path.join(output_dir, 'signature_package_config.xml') update_config(chipset, update_cfg_cb, temp_config_file) # Launch secimage once to get the image info list il = launch_secimage(config=temp_config_file, output_dir=output_dir, sign_id=sign_id, imagefile=to_sign_file, signer=SIGNER_LOCAL, verify_input=True, verbose=verbose, debug=debug, quiet=(False if verbose else True)) # Copy the zip to where its expected in the output directory hash_package_exp = SecimageRemoteClientSigner.get_to_sign_package_path( il[0]) if (hash_package != hash_package_exp): c_path.create_dir(os.path.dirname(hash_package_exp)) ret, err = copy_file(hash_package, hash_package_exp) copied_sig_file = hash_package_exp if not ret: raise RuntimeError(err) # Launch secimage il = launch_secimage(config=temp_config_file, output_dir=output_dir, sign_id=sign_id, imagefile=to_sign_file, signer=SIGNER_LOCAL, sign=True, verbose=verbose, debug=debug, quiet=quiet) # Verify the signature package was generated sig_package = SecimageRemoteClientSigner.get_signature_package_path( il[0]) if not c_path.validate_file(sig_package): retcode = 1 errstr = 'Failed to generate the signature package. ' + str( il[0].status.sign.error) except Exception as e: retcode = 1 errstr = 'Exception occurred while running secimage. Exception - ' + str( e) finally: if not debug: if to_sign_file is not None: try: os.remove(to_sign_file) except Exception: pass if temp_config_file is not None: try: os.remove(temp_config_file) except Exception: pass if copied_sig_file is not None: try: os.remove(copied_sig_file) except Exception: pass return retcode, errstr, sig_package
from sectools.features.isc import SecImageCore from sectools.features.isc.cfgparser.auto_gen_xml_config import complex_multi_serial_numbers from sectools.features.isc.cfgparser.defines import \ CONFIG_STRUCTURE_GENERAL_PROPERTIES, SPECIAL_OVERRIDES from sectools.features.isc.defines import AUTHORITY_QTI # Tool name for command arg CMD_ARG_TOOL_NAME = 'secimage' # Name & version of the tool SECIMAGE_TOOL_NAME = 'SecImage' SECIMAGE_TOOL_VERSION = '5.0' # Path definitions DEF_SECIMAGE_OUTPUT_DIR_NAME = CMD_ARG_TOOL_NAME + '_output' DEF_SECIMAGE_OUTPUT_DIR_PATH = c_path.join(dynamicToolStatus.toolDir, DEF_SECIMAGE_OUTPUT_DIR_NAME) __version__ = SECIMAGE_TOOL_NAME + ' ' + SECIMAGE_TOOL_VERSION class SecImageParser(CoreOptionParser): """Parser for command line arguments supported by SecImage.""" _LIST_TAG = 'LIST' @property def c_description(self): """(str) Returns the description of the program.""" return 'This program signs, encrypts & validates images' @property
#------------------------------------------------------------------------------ # Common constants #------------------------------------------------------------------------------ # Absolute path of the package PACKAGE_PATH = os.path.dirname(os.path.realpath(__file__)) # Name of the root node of any config related objects ROOTNODE_NAME = 'sectools_policy' #------------------------------------------------------------------------------ # Auto-generated XML Parser related information #------------------------------------------------------------------------------ # XML - Basic information XML_PY_FILE_NAME = 'auto_gen_policy_parser.py' XML_PY_PATH = c_path.join(PACKAGE_PATH, XML_PY_FILE_NAME) # XML - lines at the beginning of the file XML_PREPEND_LINES = '<?xml version="1.0" encoding="UTF-8"?>\n' # XML - rootnode related constants XML_ROOTNODE_NAMESPACE = 'tns:' XML_ROOTNODE_NAME = ROOTNODE_NAME XML_ROOTNODE = XML_ROOTNODE_NAMESPACE + XML_ROOTNODE_NAME # XML - namespace related constants XML_NAMESPACE_TNS = 'xmlns:tns="http://www.qualcomm.com/sectools_policy"' XML_NAMESPACE_W3 = 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' XML_NAMESPACE_SCHEMA = 'xsi:schemaLocation="http://www.qualcomm.com/sectools_policy ../xsd/sectools_policy.xsd"' XML_NAMESPACE = XML_NAMESPACE_TNS + '\n\t' + XML_NAMESPACE_W3 + '\n\t' + XML_NAMESPACE_SCHEMA