def c_validate(self): """Validates the command line args provided by the user.""" # configure verbosity level if self.parsed_args.quiet == 1: logger.verbosity = logger.WARN elif self.parsed_args.quiet > 1: logger.verbosity = logger.ERROR elif self.parsed_args.verbose == 0: logger.verbosity = logger.INFO else: logger.verbosity = logger.DEBUG err_strings = [ "--target_base_dir (-t) is a required option and must be provided.", "--source (-i) is a required option and must be provided.", "--sign_id (-g) is a required option and must be provided.", "--jtag_id and --soc_hw_version are mutually exclusive options and cannot both be provided. Provide neither or provide only one.", "config", "qti_sign", "relocatable" ] init_logging = True err_message = validate_args(self.parsed_args, err_strings, init_logging) if err_message: logger.error(err_message) self.error(err_message)
def restartDevice(self): """ Returns true if device restarted and connected """ logger.info('Sending reboot command') if self.getDeviceStatus(): process = subprocess.Popen('adb reboot && adb wait-for-device', stdout=subprocess.PIPE, stderr=subprocess.PIPE) elif self.checkFastboot(): process = subprocess.Popen('fastboot reboot', stdout=subprocess.PIPE, stderr=subprocess.PIPE) else: raise RuntimeError( 'device is not boot up and not in fastboot mode, please reboot the device manually' ) stdout, stderr = process.communicate() retcode = process.returncode if retcode != 0: logger.error(ensure_str(stderr)) return False else: logger.info( 'reboot command completed, wait for 30 seconds to check if device boot up' ) time.sleep(30) return self.getDeviceStatus()
def get_env_build_policy(environment): # get the supported build policies from the policy file supported_build_policies = sectools_builder_core.BuildPolicy.get_supported_build_policies(DEFAULT_POLICY_FILE) enabled_env_build_policies = [] # get the enabled build policy from the environment using the ids from the supported build policies for policy in supported_build_policies: if environment.get("USES_SEC_POLICY_" + policy.upper()): logger.debug("Found build policy environment variable {0}".format("USES_SEC_POLICY_" + policy.upper())) enabled_env_build_policies.append(policy) elif environment.get("SEC_POLICY_" + policy.upper()): logger.debug("Found build policy environment variable {0}".format("SEC_POLICY_" + policy.upper())) enabled_env_build_policies.append(policy) elif environment.get(policy.upper()): logger.debug("Found build policy environment variable {0}".format(policy.upper())) enabled_env_build_policies.append(policy) elif environment.get(policy): logger.debug("Found build policy environment variable {0}".format(policy)) enabled_env_build_policies.append(policy) if not enabled_env_build_policies: logger.info("No environmental build policy variable was enabled nor was one provided as a command line argument. Sectools will not be executed.") logger.info("If execution of Sectools is desired, a build policy must be set in the environment or passed as a command line argument. Supported build policies are: {0}".format(", ".join(supported_build_policies).upper())) return None elif len(enabled_env_build_policies) > 1: error_message = "The following environmental build policy variables are enabled: {0}. Only one build policy can be enabled at a time.".format(", ".join(enabled_env_build_policies).upper()) logger.error(error_message) raise RuntimeError(error_message) else: logger.debug("Successfully retrieved build policy {0} from environment".format(enabled_env_build_policies[0].upper())) return enabled_env_build_policies[0]
def get_env_args(environment, init_logging, **kwargs): for key, val in kwargs.items(): kwargs[key] = resolve(environment, val) kwargs["build_policy_id"] = get_env_build_policy(environment) kwargs["additional_secimage_policy_ids"] = get_env_secimage_policies( environment) arg_package = BuilderInputPackage(False, environment, **kwargs) err_strings = [ "target_base_dir is a required value and must be provided.", "source is a required value and must be provided.", "sign_id is a required value and must be provided", "jtag_id and soc_hw_version are mutually exclusive values and cannot both be provided. Provide neither or provide only one.", "config", "qti_sign", "relocatable", "Provided target_image_type_filter value is invalid." "Provided config_type value is invalid." ] err_message = validate_args(arg_package, err_strings, init_logging) if err_message: logger.error(err_message) raise RuntimeError(err_message) else: logger.debug("Completed argument parsing") logger.debug("Wrapping parsed inputs into a package") return arg_package
def build(self): logger.debug("Executing SectoolsBuilderCore.build()") # construct build policy object based on selected build_policy_id if self.input.build_policy is None and self.input.build_policy_id is None: logger.error("A build policy was not provided. Sectools execution, installation, and pilsplitting will be skipped.") elif self.input.build_policy is None: logger.debug("Constructing BuildPolicy based on selected build_policy_id...") self.input.build_policy = BuildPolicy(self.input.policy_file, self.input.build_policy_id, self.input.sign_id, self.input.sectools_install_base_dir, self.input.additional_secimage_policy_ids) logger.debug("\n\nConstructed BuildPolicy:\n" + str(self.input.build_policy) + "\n") # either call sectools and proceed with installation and pilsplitting or return SCons callback to build method if self.input.execute_sectools: # update config file with relocatable value self._generate_config_file() # validate files and paths errors = [] validate_file(self.input.source, "source", errors) validate_dir(self.input.target_base_dir, "target_base_dir", errors) validate_dir(self.input.sectools_install_base_dir, "sectools_install_base_dir", errors) validate_dir(self.input.pilsplitter_target_base_dir, "pilsplitter_target_base_dir", errors) if errors: err_string = "\n".join(errors) logger.error(err_string) raise RuntimeError(err_string) # drive sign, install, and pilsplit sequence self._execute_sign() else: # return SCons callback to build method return self._scons_callback()
def discover(self): """Searches for the ecies binary in the predefined packaged path. :returns str: Path to the ecies binary. """ module_name = BINARY_NAME.title() filenames = bin_names(BINARY_NAME) filenames += alternate_bin_names(BINARY_NAME) module = ModuleNotFound for filename in filenames: file_path = c_path.join(packaged_bin_folder, filename) if c_path.validate_file(file_path): module = file_path logger.debug2(module_name + ': Found at - ' + module) break else: logger.debug2(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 _executeCmds(self, cmds, verbose): image_info_list = [] from sectools.features.isc.parsegen.elf import NON_HASHABLE_SEGMENTS, \ NON_ENCAP_SEGMENTS, PT_PHDR, set_non_hashable_segments, \ set_non_encap_segments try: parsed_args = secimage.parse_args(cmds) #Suppress secimage log level backup_verbosity = self.update_secimage_verbosity( self.args.verbose) #Include phdr for hashing backup_non_hashable_segments = NON_HASHABLE_SEGMENTS set_non_hashable_segments([]) #Incluse phdr as non-encap segment backup_non_encap_segments = NON_ENCAP_SEGMENTS set_non_encap_segments(backup_non_encap_segments + [PT_PHDR]) # Call sectools image_info_list = secimage.main(parsed_args) except Exception: logger.debug(traceback.format_exc()) logger.error(sys.exc_info()[1]) finally: set_non_encap_segments(backup_non_encap_segments) set_non_hashable_segments(backup_non_hashable_segments) logger.verbosity = backup_verbosity return image_info_list
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 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 for filename in filenames: # Using the environment if OPENSSL_ENV_DIR_TAG in os.environ: env_module = c_path.join(os.environ[OPENSSL_ENV_DIR_TAG], filename) if not c_path.validate_file(env_module): logger.debug2( module_name + ': File from environment does not exist at - ' + env_module) elif not self.is_supported_version(env_module): logger.debug2( 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 modules_found = c_path.which(filename, paths=[folder]) for module_found in modules_found: if not self.is_supported_version(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 else: logger.debug2(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 __init__(self, meta_build_path, config_dir_obj, sign_id_list=[]): assert isinstance(meta_build_path, str) assert isinstance(config_dir_obj, ConfigDir) # Initialize the BaseStager BaseStager.__init__(self) self.config_dir_obj = config_dir_obj # Create internal attributes self._meta_build_path = meta_build_path # Validate that the meta_build path exists meta_build_path = c_path.normalize(meta_build_path) if not c_path.validate_dir(meta_build_path): raise RuntimeError('No read access to the meta build path: ' + meta_build_path) # Get the meta lib module from the metabuild meta_info = self.get_meta_info(meta_build_path) # Create the image info list based on the meta data for sign_id, chipset, image_src_path, image_dest_path in self.get_image_info_from_meta(meta_info): # Filer on the sign id if sign_id_list: if sign_id not in sign_id_list: continue try: img_config_parser = self.get_image_config_parser(chipset) # Validate the sign_id sign_id = self._get_sign_id(img_config_parser, os.path.basename(image_src_path.image_path), sign_id) # Get the config block for the sign id img_config_block = img_config_parser.get_config_for_sign_id(sign_id) # Create the one image info object image_info = ImageInfo('', sign_id, img_config_block, img_config_parser) # Set the src path image_info.src_image = image_src_path image_info.image_under_operation = image_info.src_image.image_path # Set the dest path image_info.dest_image = image_dest_path # Put the image info object into the list self._image_info_list.append(image_info) except Exception as e: logger.error(str(e)) if not self._image_info_list: raise RuntimeError('No images found from the meta build.')
def get_data(self, sign=None, encrypt=None): # Resolve the operation sign = self.sign if sign is None else sign encrypt = self.encrypt if encrypt is None else encrypt # Allow base to do any checks SecParseGenBase.get_data(self, sign, encrypt) if encrypt: logger.error('Mbn Images do not support encryption. Returning the ' + ('signed' if sign else 'raw') + ' image.') return self._get_data_int(sign, False)
def checkFastboot(self): process = subprocess.Popen('fastboot devices', stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() if process.returncode == 0 and stdout != '': return True else: logger.error(ensure_str(stderr)) return False
def get_data(self, sign=None, encrypt=None): # Resolve the operation sign = self.sign if sign is None else sign encrypt = self.encrypt if encrypt is None else encrypt # Allow base to do any checks SecParseGenBase.get_data(self, sign, encrypt) if sign: logger.error('Bin Images do not support signing. Returning the raw image.') return self._get_data_int(False, encrypt)
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 _decrypt_data(self): if self.encdec is None: logger.error("Input image is encrypted but decryption of image failed. There are two possible causes:\n" + "\t1) Selected_encryptor is not set in config file or command line args.\n" + "\t2) You are attempting to sign but not encrypt a previously encrypted image. This is not allowed.") raise RuntimeError('Image is encrypted. Cannot proceed without a decryptor.') decryptor = self.encdec.get_decryptor(encryption_parameters_blob=self.encryption_params, key=self.encdec.get_dummy_key()) parsegen_updater = ParseGenEncDec(self.store_debug_data, self.encrypt_segment) parsegen_updater.decrypt(self.encdec.get_segment_num_scheme(), self._elf_parsegen, decryptor)
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 fastbootDevice(self): """ Returns true if device is in fastboot mode """ process = subprocess.Popen('adb reboot bootloader', stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() if process.returncode == 0: time.sleep(5) return self.checkFastboot() else: logger.error(ensure_str(stderr)) return False
def get_data(self, integrity_check=None, sign=None, encrypt=None): # Resolve the operation integrity_check = self.integrity_check if integrity_check is None else integrity_check sign = self.sign if sign is None else sign encrypt = self.encrypt if encrypt is None else encrypt # Allow base to do any checks SecParseGenBase.get_data(self, integrity_check, sign, encrypt) if integrity_check: logger.error('Mbn Images do not support integrity check.') if encrypt: logger.error('Mbn Images do not support encryption.') return self._get_data_int(sign, False)
def _status_updater(self, method, status, progress, raise_err, *args, **kwargs): try: retval = method(*args, **kwargs) status.state = StatusInfo.SUCCESS progress.push() return retval except Exception as e: status.state = StatusInfo.ERROR status.error = str(e) progress.push() if raise_err: raise else: logger.error(status.error)
def __init__(self, policy_file, build_policy_id, sign_id, install_base_dir, additional_secimage_policy_ids): root = CoreConfig(policy_parser, policy_file).root self.install_base_dir = install_base_dir # get all the supported build policies supported_build_policies = root.build_policy.policy_enable # loop through supported build policies and check that build_policy_id corresponds to one of the supported build policies self.policy = None supported_build_policy_ids = [] # get build policy based on provided build_policy_id for build_policy in supported_build_policies: supported_build_policy_ids.append(build_policy.id) if build_policy.id == build_policy_id or build_policy.feature_flag.lower() == build_policy_id or "sec_policy_" + build_policy.id == build_policy_id: # found build policy matching specified policy self.policy = build_policy if self.policy is None: # raise error because the provided build_policy_id is not one of the ids specified in the sectools_policy.xml file error_message = "Provided build_policy_id \"{0}\" does not match one of the supported build policy ids: {1}".format(build_policy_id, ", ".join(supported_build_policy_ids)) logger.error(error_message) raise RuntimeError(error_message) # get the sec image policies logger.debug("Getting secimage policies for \"{0}\" build policy...".format(build_policy_id)) self.sec_image_policies, self.sec_image_policy_ids = BuildPolicy._get_policies(root.sec_image_policy.policy, self.policy.sec_image_policy) logger.debug("Secimage policies retrieved for \"{0}\" build policy: {1}".format(build_policy_id, ", ".join(self.sec_image_policy_ids))) # get the sec image policies specified by additional_secimage_policy_ids if additional_secimage_policy_ids: logger.debug("Adding additional secimage policies specified in the environment to the build policy...") additional_secimage_policies, additional_secimage_policy_ids = BuildPolicy._get_policies(root.sec_image_policy.policy, additional_secimage_policy_ids, self.sec_image_policy_ids) # add the additional sec image policies and their ids to the existing sec image lists if additional_secimage_policy_ids: logger.debug("Additional secimage policies added to \"{0}\" build policy: {1}".format(build_policy_id, ", ".join(additional_secimage_policy_ids))) self.sec_image_policies += additional_secimage_policies self.sec_image_policy_ids += additional_secimage_policy_ids # filter out sec image policies that specify an excluded sign_id that matches the provided sign_id BuildPolicy._remove_policies_for_excluded_sign_ids(self.sec_image_policies, self.sec_image_policy_ids, sign_id) # get the install policies logger.debug("Getting install policies for \"{0}\" build policy...".format(build_policy_id)) self.install_policies, self.install_policy_ids = BuildPolicy._get_policies(root.install_policy.policy, self.policy.install_policy) logger.debug("Install policies retrieved for \"{0}\" build policy: {1}".format(build_policy_id, ", ".join(self.install_policy_ids))) # initialize install locations for sec image policies if installation should be performed if self.install_base_dir: BuildPolicy._set_install_locations_for_sec_image_policies(self.install_policies, self.sec_image_policies, self.install_base_dir)
def get_data(self, integrity_check=None, sign=None, encrypt=None): # Resolve the operation integrity_check = self.integrity_check if integrity_check is None else integrity_check sign = self.sign if sign is None else sign encrypt = self.encrypt if encrypt is None else encrypt if integrity_check: logger.error('Bin Images do not support integrity check.') if sign: logger.error('Bin Images do not support signing.') data = self.data if encrypt: data = self.encryption_params + self.encrypt_segment(data, 0) return data
def _validate_oid_raw(self, min_attest, max_attest, min_ca, max_ca): tcg_ok = False if min_attest is not None: assert isinstance(min_attest, BaseAttribute) if max_attest is not None: assert isinstance(max_attest, BaseAttribute) if min_ca is not None: assert isinstance(min_ca, BaseAttribute) if max_ca is not None: assert isinstance(max_ca, BaseAttribute) if ((min_attest is None) and (max_attest is None) and (min_ca is None) and (max_ca is None)): # This is ok. No TCGs in attest cert. tcg_ok = True logger.debug( "\nNo TCGs found in Attestation cert or CA cert. This is OK.") elif (min_attest is not None) and (max_attest is not None) and ( min_ca is None) and (max_ca is None): logger.error( "\nTCGs found in Attestation cert, but not in CA cert. This is invalid." ) elif (min_attest is None) and (max_attest is None) and ( min_ca is not None) and (max_ca is not None): logger.error( "\nNo TCGs found in Attestation cert, but there are TCGs in CA cert. This is invalid." ) elif (min_attest is not None) and (max_attest is not None) and ( min_ca is not None) and (max_ca is not None): if (min_ca.value <= min_attest.value <= max_attest.value <= max_ca.value): tcg_ok = True logger.debug("\nTCG values fall within CA constraints.") else: logger.error("\nTCG values are outside the CA constraints.") else: logger.error("\nInvalid TCG values") tcg_log_mesg = "\nAttestation cert : tcg_min={0} tcg_max={1}".format(min_attest, max_attest) + \ "\nCA cert (allowed): tcg_min={0} tcg_max={1}\n".format(min_ca, max_ca) if tcg_ok is False: logger.error(tcg_log_mesg) else: logger.debug(tcg_log_mesg) return tcg_ok
def _status_updater(self, method, status, progress, raise_err, *args, **kwargs): try: retval = method(*args, **kwargs) status.state = StatusInfo.SUCCESS return retval except CustomError as e: # No change in imageinfo status. logger.info(str(e)) except Exception as e: status.state = StatusInfo.ERROR status.error = str(e) if raise_err: raise else: logger.error(status.error) finally: progress.push()
def _status_updater(self, method, status, progress, raise_err, *args, **kwargs): from imageinfo import ImageInfo, StatusInfo try: retval = method(*args, **kwargs) status.state = StatusInfo.SUCCESS progress.push() return retval except Exception as e: status.state = StatusInfo.ERROR status.error = str(e) progress.push() if raise_err: raise else: if isinstance (e, CustomError): logger.info(status.error) else: logger.error(status.error)
def get_image_info_from_meta(cls, meta_info): # Get a list of all files tagged with sign_id meta_images_list = meta_info.get_files_detailed('sign_id') for image in meta_images_list: try: logger.debug('Found image from meta_build for signing: ' + image.sign_id) source_path = None dest_path = None for each_path in image.file_path: if source_path is None: if getattr(each_path, 'sign_source', False): source_path = each_path.value if dest_path is None: if getattr(each_path, 'sign_dest', False): dest_path = each_path.value if source_path and dest_path: break if source_path is None or dest_path is None: raise RuntimeError( 'SourcePath, DestPath should not be missing.') sign_id = image.sign_id chipset = image.chipset image_src_path = ImagePath() image_dest_path = DestImagePath() image_src_path.image_dir_base = image.image_dir_base image_src_path.image_dir_ext = source_path image_src_path.image_name = image.file_name[0].value image_dest_path.image_dir_base = image.image_dir_base image_dest_path.image_dir_ext = dest_path image_dest_path.image_name = image.file_name[0].value except Exception as e: logger.error(str(e)) continue yield (sign_id, chipset, image_src_path, image_dest_path, MetaError.SUCCESS)
def _decode_binary_blob(self, binary_blob, validating): if len(binary_blob) != EncryptionParamsSectionBody.L2AssociatedData.SPEC_SIZE_BYTES: raise RuntimeError("L2 Associated Data blob is of the wrong size") string_offset = 0 string_end = EncryptionParamsSectionBody.L2AssociatedData.L2_ASSOCIATED_DATA_SIZE_FLD_LEN_BYTES self.l2_associated_data_size, = struct.unpack(">H", binary_blob[string_offset:string_end]) string_offset = string_end + EncryptionParamsSectionBody.RSVD_BYTE_LEN_BYTES * 2 string_end = string_offset + EncryptionParamsSectionBody.L2AssociatedData.MAJOR_VERSION_FLD_LEN_BYTES + \ EncryptionParamsSectionBody.L2AssociatedData.MINOR_VERSION_FLD_LEN_BYTES + \ EncryptionParamsSectionBody.L2AssociatedData.KEY_LADDER_LEN_FLD_LEN_BYTES + \ EncryptionParamsSectionBody.RSVD_BYTE_LEN_BYTES major_version, minor_version, self.key_ladder_length, tmp = struct.unpack("=BBBB", binary_blob[string_offset:string_end]) string_offset = string_end if (major_version, minor_version) != (self.major_version, self.minor_version): raise RuntimeError(("Encryption Parameters L2 Associated Data version \"{0}.{1}\" does not match expected version \"{2}.{3}\"" "\n Ensure that the correct encryptor value is set.").format(major_version, minor_version, self.major_version, self.minor_version)) if (major_version, minor_version) == (EncryptionParamsSectionBody.L2AssociatedData.MAJOR_VERSION_FLD_VAL_1, EncryptionParamsSectionBody.L2AssociatedData.MINOR_VERSION_FLD_VAL_0): string_end = string_offset + EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID_BITMAP_FLD_VERSION_1_0_LEN_BYTES image_id_bitmap, = struct.unpack("=I", binary_blob[string_offset:string_end]) elif (major_version, minor_version) == (EncryptionParamsSectionBody.L2AssociatedData.MAJOR_VERSION_FLD_VAL_1, EncryptionParamsSectionBody.L2AssociatedData.MINOR_VERSION_FLD_VAL_1): string_end = string_offset + EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID_BITMAP_FLD_VERSION_1_1_LEN_BYTES image_id_bitmap_upper, image_id_bitmap_lower = struct.unpack("=QQ", binary_blob[string_offset:string_end]) image_id_bitmap = image_id_bitmap_lower * (2 ** 64) + image_id_bitmap_upper else: raise RuntimeError("Configured Encryption Parameters L2 Associated Data version \"{0}.{1}\" is invalid.".format(self.major_version, self.minor_version)) image_id = int(math.log(image_id_bitmap, 2)) if image_id != self.image_id: if validating: errstr = list() mismatches = list() mismatches.append((EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID, "0x%X" % image_id, "0x%X" % self.image_id)) create_mismatch_table(mismatches, errstr, operation="encryption", data_type_to_compare="Attribute", image_region="Encryption Parameters") logger.error('Following validations failed for the image:\n ' + '\n '.join([(str(i + 1) + '. ' + e) for i, e in enumerate(errstr)])) else: logger.warning(("Extracted Encryption Parameters " + EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID + " value \"{0}\" does not match config value \"{1}\"" "\n\t Encryption Parameters " + EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID + " value will be updated with value \"{1}\"").format(hex(image_id), hex(self.image_id)))
def execute(self, cmd, logfile, work_dir=None, timer=900, interval=5): fd = open(logfile, 'w+') p = subprocess.Popen(r" ".join(cmd), cwd=work_dir, shell=False, stdout=fd, stderr=fd) self.pid = p.pid # set timer and start polling process status # kill the test process and cleanup upon timeout import time count = int(timer / interval) while count > 0: time.sleep(interval) if p.poll() is not None: break count -= 1 if p.poll() is None: p.terminate() logger.error('process is terminiated due to timeout after ' + str(timer) + ' seconds') fd.close() return p.returncode
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 get_image_info_from_meta(cls, meta_info): # Get a list of all files tagged with sign_id meta_images_list = meta_info.get_files_detailed('sign_id') for image in meta_images_list: try: logger.debug('Found image from meta_build for signing: ' + image.sign_id) source_path = None dest_path = None for each_path in image.file_path: if source_path is None: if getattr(each_path, 'sign_source', False): source_path = each_path.value if dest_path is None: if getattr(each_path, 'sign_dest', False): dest_path = each_path.value if source_path and dest_path: break if source_path is None or dest_path is None: raise RuntimeError('SourcePath, DestPath should not be missing.') sign_id = image.sign_id chipset = image.chipset image_src_path = ImagePath() image_dest_path = DestImagePath() image_src_path.image_dir_base = image.image_dir_base image_src_path.image_dir_ext = source_path image_src_path.image_name = image.file_name[0].value image_dest_path.image_dir_base = image.image_dir_base image_dest_path.image_dir_ext = dest_path image_dest_path.image_name = image.file_name[0].value except Exception as e: logger.error(str(e)) continue yield (sign_id, chipset, image_src_path, image_dest_path)
def _validate_certificate_params_dict(self, certificate_params_dict): certificate_params_is_valid = False generate_new_certificate = False for key in certificate_params_dict: if key not in ['C', 'CN', 'L', 'O', 'ST', 'OU']: if key not in ['private_key_path', 'certificate_path']: logger.error("Invalid Key is being passed in configuration!" + repr(key)) raise RuntimeError("Invalid Key is being passed in configuration!") else: if os.path.exists(certificate_params_dict['private_key_path']) is False: err_str = "private_key_path does not exist: {0}!".format(certificate_params_dict['private_key_path']) logger.error(err_str) certificate_params_is_valid = False raise RuntimeError(err_str) if os.path.exists(certificate_params_dict['certificate_path']) is False: err_str = "certificate_path does not exist: {0}!".format(certificate_params_dict['certificate_path']) logger.error(err_str) certificate_params_is_valid = False raise RuntimeError(err_str) generate_new_certificate = False certificate_params_is_valid = True else: certificate_params_is_valid = True generate_new_certificate = True return certificate_params_is_valid, generate_new_certificate
def loadMetaBuild(self, keyword=None, timer=1200, interval=5): """ load meta build with fastboot_complete.py :param str meta_build_path: meta build directory, require read access """ if self.run: self.retcode = '' # meta build path validation meta_path_val = c_path.normalize(self.meta_build_path) if not c_path.validate_dir_write(meta_path_val): raise RuntimeError('Cannot write at: ' + meta_path_val) # check device status (put device to fastboot mode) if AndroidDevice.checkFastboot(): enable_buildloading = True else: enable_buildloading = AndroidDevice.fastbootDevice() if enable_buildloading: cmd = ['python', BUILDLOAD_PY] cwd = c_path.join(meta_path_val, BUILD_SCRIPTS_DIR) self.logging_state_info(getCurrentTime() + ' start meta build loading, please wait and do not interrupt ...') self.logging_state_info('Set current working directory: ' + cwd) self.logging_state_info('Meta build loading command: ' + " ".join(cmd)) self.log = c_path.join(meta_path_val, FASTBOOT_COMPLETE_LOG) self.run = False self.retcode = self.execute(cmd, self.log, cwd, timer, interval) self.logging_state_info(getCurrentTime() +' meta build loading return code: ' + str(self.retcode)) self.logging_state_info('meta build loading log can be found at: ' + self.log) if self.retcode == 0: self.run = True self.logging_state_info(SECTION_BREAK) if AndroidDevice.restartDevice(): self.logging_state_info('device reboot completed') else: self.logging_state_info('device reboot failed, please reboot the device manually') else: self.retcode = 1 logger.error('device cannot be set in fastboot mode, please set manually') else: self.logging_state_info('skip meta build loading')
def __init__(self, meta_build_path, config_dir_obj, sign_id_list=[]): assert isinstance(meta_build_path, str) assert isinstance(config_dir_obj, ConfigDir) # Initialize the BaseStager BaseStager.__init__(self) self.config_dir_obj = config_dir_obj # Create internal attributes self._meta_build_path = meta_build_path # Validate that the meta_build path exists meta_build_path = c_path.normalize(meta_build_path) if not c_path.validate_dir(meta_build_path): raise RuntimeError('No read access to the meta build path: ' + meta_build_path) # Get the meta lib module from the metabuild meta_info = self.get_meta_info(meta_build_path) # Create the image info list based on the meta data for sign_id, chipset, image_src_path, image_dest_path in self.get_image_info_from_meta(meta_info): # Filer on the sign id if sign_id_list: if sign_id not in sign_id_list: continue try: img_config_parser = self.get_image_config_parser(chipset) # Validate the sign_id sign_id = self._get_sign_id(img_config_parser, os.path.basename(image_src_path.image_path), sign_id) # Get the config block for the sign id img_config_block = img_config_parser.get_config_for_sign_id(sign_id) # Create the one image info object image_info = ImageInfo('', sign_id, img_config_block, img_config_parser) # Set the src path image_info.src_image = image_src_path image_info.image_under_operation = image_info.src_image.image_path # Set the dest path image_info.dest_image = image_dest_path # Check if the dest image name should be overriden if img_config_block.output_file_name is not None: image_info.dest_image.image_name = img_config_block.output_file_name # Put the image info object into the list self._image_info_list.append(image_info) except Exception as e: logger.error(str(e)) if not self._image_info_list: raise RuntimeError('No images found from the meta build.')
if len(args) > 1: feature = args[1] for supported_feature in FEATURES_LIST: if feature == supported_feature.CMD_ARG_TOOL_NAME: supported_feature.main(supported_feature.parse_args(sys.argv[1:])) break else: raise RuntimeError('Feature provided from command line: "' + feature + '" is invalid.' + '\n' ' ' + 'Please choose from : ' + str([f.CMD_ARG_TOOL_NAME for f in FEATURES_LIST])) if __name__ == '__main__': try: # Check that the command line are valid and are normalized. args = SectoolsParser().pos_args main(args) except Exception: logger.debug(traceback.format_exc()) logger.error(sys.exc_info()[1]) sys.exit(1) except KeyboardInterrupt: print logger.error('Keyboard Interrupt Received. Exiting!') sys.exit(1) sys.exit(0)
def _sign(self, hash_to_sign, cert_config, signing_attributes, general_properties, binary_to_sign): openssl_config_file_paths = self.config.signing.signer_attributes.local_signer_attributes.openssl_config_inputs self._validate_config(cert_config, general_properties, openssl_config_file_paths) # Obtain all the information from the signing_attributes debug_val = int(signing_attributes.debug, 16) if signing_attributes.debug is not None else None msm_part = int(signing_attributes.msm_part, 16) oem_id = int(signing_attributes.oem_id, 16) model_id = int(signing_attributes.model_id, 16) num_certs_in_certchain = general_properties.num_certs_in_certchain app_id = int(signing_attributes.app_id, 16) if signing_attributes.app_id is not None else None crash_dump = int(signing_attributes.crash_dump, 16) if signing_attributes.crash_dump is not None else None rot_en = int(signing_attributes.rot_en, 16) if signing_attributes.rot_en is not None else None # Create the crypto_params_dict self.certconfig_parser = CertConfigParser(cert_config, signing_attributes, general_properties) crypto_params_dict = self.certconfig_parser.get_crypto_params() hmac_params = signerutils.get_hmac_params_from_config(signing_attributes) # Create the attestation_certificate_key_pair attestation_certificate_key_pair = None root_certificate_params = crypto_params_dict['root_certificate_properties'] root_certificate_params_is_valid, generate_new_root_certificate = self._validate_certificate_params_dict(root_certificate_params) if root_certificate_params_is_valid: if generate_new_root_certificate: logger.info('Generating new Root certificate and a random key') generated_root_key_pair = crypto_functions.gen_rsa_key_pair(general_properties.key_size, key_exponent=signing_attributes.exponent) root_cert, root_key_pair = crypto_functions.create_root_certficate(root_certificate_params, generated_root_key_pair, 7300, openssl_config_file_paths.openssl_configfile_path, 1) else: logger.info('Using a predefined Root certificate and a predefined key') logger.info('Key Used: '+ root_certificate_params['private_key_path']) logger.info('Certificate Used: '+ root_certificate_params['certificate_path']) root_cert, root_key_pair = self._get_certificate_and_key_pair_from_files(root_certificate_params) else: logger.error("Root certificate params are invalid! Please check config file.") raise RuntimeError("Root certificate params are invalid! Please check config file.") if num_certs_in_certchain > 2: logger.debug("Generating Attestation CA certificate, since certchain size is greater than 2") attestation_ca_certificate_params = crypto_params_dict['attest_ca_certificate_properties'] attestation_ca_params_is_valid, generate_new_attestation_ca = self._validate_certificate_params_dict(attestation_ca_certificate_params) if attestation_ca_params_is_valid: if generate_new_attestation_ca: logger.info('Generating new Attestation CA certificate and a random key') generated_attestation_ca__key_pair = crypto_functions.gen_rsa_key_pair(general_properties.key_size, key_exponent=signing_attributes.exponent) attestation_ca_certificate, attestation_ca_certificate_key_pair = \ crypto_functions.create_certificate(attestation_ca_certificate_params, generated_attestation_ca__key_pair, root_cert, root_key_pair, days=7300, configfile=openssl_config_file_paths.openssl_configfile_path, serial_num=1, extfile_name=openssl_config_file_paths.ca_certificate_extensions_path) else: logger.info('Using a predefined Attestation CA certificate and a predefined key') logger.info('Key Used: '+ attestation_ca_certificate_params['private_key_path']) logger.info('Certificate Used: '+ attestation_ca_certificate_params['certificate_path']) attestation_ca_certificate, attestation_ca_certificate_key_pair = self._get_certificate_and_key_pair_from_files(attestation_ca_certificate_params) else: logger.error("Attestation CA certificate params are invalid! Please check config file.") raise RuntimeError("Attestation CA certificate params are invalid! Please check config file.") attestation_certificate_params = crypto_params_dict['attest_certificate_properties'] attestation_certificate_params_is_valid, generate_new_attestation_certificate = self._validate_certificate_params_dict(attestation_certificate_params) if attestation_certificate_params_is_valid: if generate_new_attestation_certificate: #TCG support if self._is_tcg_supported(signing_attributes) is True: if self.validate_tcg_from_config(attestation_ca_certificate_params['certificate_path'], signing_attributes) is False: raise ConfigError("tcg_min and tcg_max are not set correctly in configuration."\ "Signing will not continue." ) attestation_certificate_extensions_path = self._generate_attestation_certificate_extensions( openssl_config_file_paths.attestation_certificate_extensions_path, signing_attributes.tcg_min, signing_attributes.tcg_max) else: attestation_certificate_extensions_path = openssl_config_file_paths.attestation_certificate_extensions_path logger.info('Generating new Attestation certificate and a random key') certificate_ou_sw_id ="01 " + hmac_params.sw_id_str + " SW_ID" certificate_ou_hw_id ="02 " + hmac_params.msm_id_str + " HW_ID" certificate_ou_oem_id ="04 " + "%0.4X" % oem_id + " OEM_ID" certificate_ou_sw_size ="05 " + "%0.8X" % len(binary_to_sign) + " SW_SIZE" certificate_ou_model_id ="06 " + "%0.4X" % model_id + " MODEL_ID" certificate_hash_alg = "07 0001 SHA256" certificate_ou = [ certificate_ou_sw_id, certificate_ou_hw_id, certificate_ou_oem_id, certificate_ou_sw_size, certificate_ou_model_id, certificate_hash_alg ] #Optional attributes if debug_val is not None: certificate_ou_debug_id ="03 " + "%0.16X" % debug_val + " DEBUG" certificate_ou.append(certificate_ou_debug_id) if app_id is not None: certificate_app_id = "08 " + "%0.16X" % app_id + " APP_ID" certificate_ou.append(certificate_app_id) if crash_dump is not None: certificate_crash_dump = "09 " + "%0.16X" % crash_dump + " CRASH_DUMP" certificate_ou.append(certificate_crash_dump) if rot_en is not None: certificate_rot_en = "10 " + "%0.16X" % rot_en + " ROT_EN" certificate_ou.append(certificate_rot_en) if 'OU' in attestation_certificate_params.keys(): if type(attestation_certificate_params['OU'])==list: for item in attestation_certificate_params['OU']: certificate_ou.append(item) else: certificate_ou.append(attestation_certificate_params['OU']) attestation_certificate_params['OU']=certificate_ou if attestation_certificate_key_pair is None: attestation_certificate_key_pair = crypto_functions.gen_rsa_key_pair(key_exponent=signing_attributes.exponent, key_size_in_bits = general_properties.key_size) if num_certs_in_certchain > 2: #sign the attestation cert with the attestation_ca_cert attestation_certificate, attestation_certificate_key_pair = \ crypto_functions.create_certificate(attestation_certificate_params, attestation_certificate_key_pair, attestation_ca_certificate, attestation_ca_certificate_key_pair, days=7300, configfile=openssl_config_file_paths.openssl_configfile_path, serial_num=1, extfile_name=attestation_certificate_extensions_path) else: #sign the attestation cert with the root cert attestation_certificate, attestation_certificate_key_pair = \ crypto_functions.create_certificate(attestation_certificate_params, attestation_certificate_key_pair, root_cert, root_key_pair, days=7300, configfile=openssl_config_file_paths.openssl_configfile_path, serial_num=1, extfile_name=attestation_certificate_extensions_path) attestation_certificate = crypto_functions.cert_pem_to_der(attestation_certificate) #Clean temp file if self._is_tcg_supported(signing_attributes) is True: c_path.clean_file(attestation_certificate_extensions_path) else: #generate_new_attestation_certificate == False logger.info('Using a predefined Attestation certificate and a predefined key') logger.info('Key Used: '+ attestation_certificate_params['private_key_path']) logger.info('Certificate Used: '+ attestation_certificate_params['certificate_path']) attestation_certificate, attestation_certificate_key_pair = self._get_certificate_and_key_pair_from_files(attestation_certificate_params) attestation_certificate = crypto_functions.cert_pem_to_der(attestation_certificate) # Since the get_hmac_params_from_certificate_chain always works with the first cert in the cert chain, # this function will work for a single der certificate as well. hmac_params = crypto_functions.get_hmacparams_from_certificate_chain(attestation_certificate) hasher = Hasher() hash_to_sign=hasher.qcom_hmac(binary_to_sign, hmac_params) signature = crypto_functions.encrypt_with_private_key(hash_to_sign, attestation_certificate_key_pair['private_key']) else: logger.error("Attestation certificate params are invalid! Please check config file.") raise RuntimeError("Attestation certificate params are invalid! Please check config file.") if num_certs_in_certchain > 2: attestation_ca_certificate = crypto_functions.cert_pem_to_der(attestation_ca_certificate) else: attestation_ca_certificate = None root_cert = crypto_functions.cert_pem_to_der(root_cert) root_cert_list = self.certconfig_parser.get_rootcerts() certificate_list = self._get_certificate_list(general_properties.num_root_certs, num_certs_in_certchain, attestation_certificate, attestation_ca_certificate, root_cert, root_cert_list) cert_chain=crypto_functions.create_certificate_chain(certificate_list) signer_output = SignerOutput() signer_output.root_cert = root_cert signer_output.attestation_ca_cert = attestation_ca_certificate signer_output.attestation_cert = attestation_certificate signer_output.signature = signature signer_output.cert_chain = cert_chain signer_output.root_cert_list = root_cert_list signer_output.attestation_key = attestation_certificate_key_pair['private_key'] return signer_output
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 get_image_info_from_meta(self, meta_info): # Cache dicts build_paths = dict() attrs = dict() file_types = dict() for sign_id in self.img_config_parser.sign_id_list: try: logger.debug('Searching metabuild for ' + sign_id) image = self.img_config_parser.get_config_for_sign_id(sign_id) image_path = image.meta_build_location # Replace any tags re_match = re.match('\$\((.*?)\)', image_path) if re_match: tags = re_match.group(1) tags_dict = {} for tag in tags.split(','): tag = tag.strip().split(':') tags_dict[tag[0]] = tag[1] replacement = None if self.TAG_BUILD_PATH in tags_dict: build = tags_dict[self.TAG_BUILD_PATH] paths_data = build_paths.get(build, None) if paths_data is None: paths_data = meta_info.get_build_path(build) build_paths[build] = paths_data replacement = paths_data elif self.TAG_ATTR in tags_dict: attr = tags_dict[self.TAG_ATTR] file_type = tags_dict[self.TAG_FILE_TYPE] paths_data = attrs.get((attr, file_type), None) if paths_data is None: paths_data = meta_info.get_file_vars(attr, file_type) attrs[(attr, file_type)] = paths_data if tags_dict[self.TAG_VAR] in paths_data: replacement = paths_data[tags_dict[self.TAG_VAR]][0] elif self.TAG_FILE_TYPE in tags_dict: file_type = tags_dict[self.TAG_FILE_TYPE] paths_data = file_types.get(file_type, None) if paths_data is None: paths_data = meta_info.get_files(file_type) file_types[file_type] = paths_data if paths_data: for each_path in paths_data: if each_path.lower().endswith(image.name.lower()): replacement = each_path break else: raise RuntimeError('Unknown image type') if replacement: image_path = image_path.replace(re_match.group(0), replacement) else: logger.warning('File not found in meta build: ' + sign_id) continue image_path = image_path.replace(self.REPL_META_PATH, self._meta_build_path) image_src_path = ImagePath() image_dest_path = DestImagePath() image_src_path.image_dir_base = os.path.dirname(image_path) image_src_path.image_dir_ext = '' image_src_path.image_name = os.path.basename(image_path) image_dest_path.image_dir_base = os.path.dirname(image_path) image_dest_path.image_dir_ext = '' image_dest_path.image_name = os.path.basename(image_path) except Exception as e: logger.error(str(e)) continue yield (sign_id, self.chipset, image_src_path, image_dest_path)