def _process_validation(self, image, progress, security_policy_list, i_val_image, i_val_integrity_check, i_val_sign, i_val_encrypt, idx=0, prefix_override=None): # TODO: Need to figure how to do this #image.dest_image._mid = 'validation' # Check bounds if len(security_policy_list) == 0: raise RuntimeError('Security policy list must not be empty.') elif len(security_policy_list) <= idx: raise RuntimeError( 'Security policy list length must be more than index.') # Get the current security policy file_type = security_policy_list[idx].file_type val_image = i_val_image val_integrity_check = security_policy_list[ idx].integrity_check and i_val_integrity_check val_sign = security_policy_list[idx].sign and i_val_sign val_encrypt = security_policy_list[idx].encrypt and i_val_encrypt # Backup the source path here src_image_dir_base = image.src_image.image_dir_base src_image_dir_ext = image.src_image.image_dir_ext src_image_name = image.src_image.image_name # Update the souce image path image.src_image.image_dir_base = os.path.dirname( image.image_under_operation) image.src_image.image_dir_ext = '' image.src_image.image_name = os.path.basename( image.image_under_operation) try: # Create the encryptor object encdec = None if image.general_properties.selected_encryptor: c_path.create_debug_dir(image.dest_image.debug_dir_encdec) encdec = get_encdec(image, True) # Create the parsegen object file_type_backup = image.image_type.file_type encdec_backup = image.encdec image.image_type.file_type = file_type image.encdec = encdec try: parsegen = self._status_updater(self._create_parsegen_obj, image.status.validate_parsegen, progress, True, image, True, False, prefix_override) finally: image.image_type.file_type = file_type_backup image.encdec = encdec_backup # Validate the authority settings self.validate_authority_settings( self.authority, image.general_properties.secboot_version, image.general_properties.qti_sign, image.general_properties.oem_sign, image.general_properties.num_root_certs, parsegen.is_encrypted()) # Prevent validation when using an encrypted key provider from sectools.features.isc.encryption_service.unified import encrypted_key_provider_id_supported encrypted_key_provider_id = image.signing_attributes.UIE_key if parsegen.is_encrypted() and encrypted_key_provider_id_supported( encrypted_key_provider_id): raise RuntimeError( "The image is encrypted. Validation is not supported when using an encrypted key provider.\n" "Try again with validation disabled.") # Set the security mechanisms parsegen.integrity_check = parsegen.contains_integrity_check() parsegen.sign = parsegen.is_signed() parsegen.encrypt = parsegen.is_encrypted() # Validate parsegen if val_image: self._status_updater(self._validate_parsegen, image.status.validate_parsegen, progress, False, image, parsegen) # Validate integrity check if val_integrity_check: self._status_updater(self._validate_integrity_check, image.status.validate_integrity_check, progress, False, image, parsegen) # Validate sign if val_sign: self._status_updater(self._validate_sign, image.status.validate_sign, progress, False, image, parsegen) # Validate encrypt if val_encrypt: self._status_updater(self._validate_encrypt, image.status.validate_encrypt, progress, False, image, parsegen) # Dump any debug data self.dump_parsegen_debug_data(image, parsegen) # If the security policy list contains more formats, call them if idx < len(security_policy_list) - 1: data = parsegen.get_wrapped_data() import tempfile tmp_fd = tempfile.NamedTemporaryFile( prefix=security_policy_list[idx + 1].file_type, delete=False) tmp_fd.close() store_data_to_file(tmp_fd.name, data) # Backup the image_under_operation here image_under_operation_int = image.image_under_operation image.image_under_operation = tmp_fd.name # Override debug dumped file prefix prefix_override = SecImageCore._get_prefix_override( prefix_override, file_type) try: self._process_validation(image, progress, security_policy_list, i_val_image, i_val_integrity_check, i_val_sign, i_val_encrypt, idx + 1, prefix_override) finally: image.image_under_operation = image_under_operation_int os.remove(tmp_fd.name) finally: image.src_image.image_dir_base = src_image_dir_base image.src_image.image_dir_ext = src_image_dir_ext image.src_image.image_name = src_image_name return parsegen
def __init__(self, data, imageinfo=None, elf_properties=None, general_properties=None, encdec=None, debug_dir=None, debug_prefix=None, debug_suffix=None, validating=False, signing=False, sign_attr=False): SecParseGenBase.__init__(self, data, imageinfo, general_properties, encdec, debug_dir, debug_prefix, debug_suffix, validating, signing, sign_attr) # Check the arguments if imageinfo is not None: elf_properties = imageinfo.image_type.elf_properties general_properties = imageinfo.general_properties if elf_properties is None: raise RuntimeError('ELF properties must not be None.') # Initialize internal properties self._image_type = 0 self._serial_num = None self._max_elf_segments = MAX_PHDR_COUNT self._validate_ph_addrs = True self._validate_vir_addrs = False # Set properties from the config file self.has_license_manager_segment = False self.lib_id = general_properties.lib_id self.client_id = general_properties.client_id self.image_type = elf_properties.image_type self.hash_seg_placement = elf_properties.hash_seg_placement self.serial_num = general_properties.testsig_serialnum self.signer = general_properties.selected_signer if elf_properties.max_elf_segments is not None: self.max_elf_segments = elf_properties.max_elf_segments if elf_properties.validate_ph_addrs is not None: self.validate_ph_addrs = elf_properties.validate_ph_addrs if elf_properties.validate_vir_addrs is not None: self.validate_vir_addrs = elf_properties.validate_vir_addrs if elf_properties.has_license_manager_segment is not None: self.has_license_manager_segment = elf_properties.has_license_manager_segment self._license_manager_segment = None # Initialize the elf parsegen self._elf_parsegen = elf.ParseGenElf(data, self.debug_dir, self.debug_prefix, self.debug_suffix) self._elf_parsegen.stabilize_phdrs() # Remove the prog header and hash segment phdr_segment, hash_segment = self.extract_phdr_hash(self._elf_parsegen) self.store_debug_data(FILE_PROG_SEG_IN, phdr_segment) self.store_debug_data(FILE_HASH_SEG_IN, hash_segment) self.store_debug_data(FILE_PROG_HASH_REMOVED_IN, self._elf_parsegen.get_data()) self.hash_segment = hash_segment # Extract the hash table from the extracted hash segment if hash_segment: extracted_hash_table_size = SecParseGenMbn(data=hash_segment, imageinfo=None, mbn_properties=self._get_sec_parsegen_mbn_properties(), general_properties=general_properties, encdec=self.encdec, debug_dir=debug_dir, debug_prefix=debug_prefix, debug_suffix=debug_suffix, validating=validating, signing=signing).code_size else: extracted_hash_table_size = 0 # If hash_segment is empty, create dummy hash_segment hash_segment = self._generate_default_hash_segment(self.secboot_version) # Initialize the base now SecParseGenMbn.__init__(self, data=hash_segment, imageinfo=None, mbn_properties=self._get_sec_parsegen_mbn_properties(), general_properties=general_properties, encdec=self.encdec, debug_dir=debug_dir, debug_prefix=debug_prefix, debug_suffix=debug_suffix, validating=validating, signing=signing, sign_attr=sign_attr) if self._elf_parsegen.ehdr.e_ident_class == ELFCLASS64 or self.secboot_version in [SECBOOT_VERSION_2_0, SECBOOT_VERSION_3_0]: self._mbn_parsegen.invalidate_pointers = True # Extract the hash algorithm that was used to generate the extracted hash table self._extract_hash_segment_algorithm(extracted_hash_table_size) # Set the elf parsegen delegate delegate = SecParseGenElfDelegate(self._elf_parsegen, self.validate_ph_addrs, self.validate_vir_addrs) self._elf_parsegen.delegate = delegate # Check if the file is encrypted if self.is_encrypted(): if encrypted_key_provider_id_supported(general_properties.UIE_key): raise RuntimeError("Cannot decrypt an encrypted image when encrypted key provider is configured as UIE server") self._decrypt_data() self.store_debug_data(FILE_DECRYPTED_IN, self._elf_parsegen.get_data()) # Get the original data self._elf_parsegen = elf.ParseGenElf(self._elf_parsegen.get_data(), self.debug_dir, self.debug_prefix, self.debug_suffix) # Ensure that hashes match. If they don't we can assume that decryption failed if self._mbn_parsegen.code[SecParseGenElf.HASH_ALGO_TO_SIZE_MAP[self._mbn_parsegen.extracted_segment_hash_algorithm]*2:] != self.get_hash_table(): raise RuntimeError("Decryption of image failed. This can be caused by:" "\n\t1) use of an invalid L3 key" "\n\t2) use of an incorrect segment hash algorithm") # Set the elf parsegen delegate delegate = SecParseGenElfDelegate(self._elf_parsegen, self.validate_ph_addrs, self.validate_vir_addrs) self._elf_parsegen.delegate = delegate # Perform license manager segment operations self.add_or_update_license_manager_segment()
def _process(idx, image, sign_attr, integrity_check, sign, encrypt, decrypt, val_image, val_integrity_check, val_sign, val_encrypt): assert isinstance(image, ImageInfo) logger.info( '------------------------------------------------------') status_string = ('Processing ' + str(idx + 1) + '/' + str(total_image_count) + ': ' + image.image_under_operation) logger.info(status_string + '\n') # Send a progress notification to the toplevel progress.status = status_string progress.cur = idx progress.cur_stage = 0 file_logger_id = None image.authority = self.authority try: # Create the required directory structure for this image image_output_dir = image.dest_image.image_dir try: c_path.create_dir(image_output_dir) except Exception as e: raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n' ' ' + 'Error: ' + str(e)) # Enable/Disable debug image.dest_image.debug_enable = self.debug c_path.create_debug_dir(image.dest_image.debug_dir) # Set the root cert hash image.validation_root_cert_hash = root_cert_hash # Enable file logging to the directory file_logger_id = logger.add_file_logger( c_path.join(image_output_dir, 'SecImage_log.txt'), logger.verbosity) # Create the security policies list for this image security_policy_list = create_security_policy_list(image) # Parsegen object parsegen = None # For secure operations if integrity_check or sign or encrypt or decrypt: parsegen = self._process_secure_operation( image, progress, security_policy_list, sign_attr, integrity_check, sign, encrypt, decrypt) # For validation if val_image or val_integrity_check or val_sign or val_encrypt: # Bypass validation when encrypted key provide is configured as UIE server because decryption will always fail if parsegen is not None and parsegen.is_encrypted( ) and encrypted_key_provider_id_supported( image.general_properties.UIE_key): logger.warning( "Skipping validation because encrypted key provider is configured as UIE server" ) else: parsegen = self._process_validation( image, progress, security_policy_list, val_image, val_integrity_check, val_sign, val_encrypt) # Print the image data if parsegen is not None: logger.info('\n' + str(parsegen)) # Set overall processing to true if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or (val_sign and image.status.validate_sign.state == StatusInfo.ERROR) or (val_encrypt and image.status.validate_encrypt.state == StatusInfo.ERROR)): image.status.overall.state = StatusInfo.SUCCESS except RemoteSignerNote as e: logger.info('NOTE: ' + str(e), color=logger.YELLOW) except Exception: logger.error(traceback.format_exc()) logger.error(sys.exc_info()[1]) finally: if file_logger_id is not None: logger.removeFileLogger(file_logger_id) logger.info( '------------------------------------------------------\n')
def using_encrypted_key_provider(self): from sectools.features.isc.encryption_service.unified import encrypted_key_provider_id_supported return encrypted_key_provider_id_supported(self.UIE_key)