def _process_secure_operation(self, image, progress, integrity_check, sign, encrypt, decrypt): # Create the encryptor object encdec = None if encrypt or decrypt: c_path.create_debug_dir(image.dest_image.debug_dir_encdec) encdec = get_encdec(image) # Create the parsegen object image.encdec = encdec parsegen = self._status_updater(self._create_parsegen_obj, image.status.parsegen, progress, True, image) # Set the security mechanisms parsegen.integrity_check = parsegen.contains_integrity_check() or integrity_check parsegen.sign = parsegen.is_signed() or sign parsegen.encrypt = parsegen.is_encrypted() or encrypt # If encrypt: if encrypt: parsegen.encryption_params = encdec.get_encryption_parameters_blob() # Dump any debug data self.dump_parsegen_debug_data(image, parsegen) # Sign the image if sign: self._status_updater(self._sign_image, image.status.sign, progress, True, image, parsegen) # Package and generate the output image file if integrity_check or sign or encrypt: store_data_to_file(image.dest_image.image_path, parsegen.get_data()) if integrity_check: image.status.integrity_check.state = StatusInfo.SUCCESS if encrypt: image.status.encrypt.state = StatusInfo.SUCCESS logger.info(('Signed ' if sign else '') + ('& ' if sign and encrypt else '') + ('Encrypted ' if encrypt else '') + 'image is stored at ' + image.dest_image.image_path) image.image_under_operation = image.dest_image.image_path # Do any post processing self._status_updater(self._post_process, image.status.postprocess, progress, True, image, image.config.post_process.pil_splitter, getattr(self._stager, '_meta_build_path', None)) # Print the image data logger.info('\n' + str(parsegen)) # Decrypt the image if decrypt: store_data_to_file(image.dest_image.decrypted_file, parsegen.get_data(encrypt=False))
def dump_signer_debug_data(self, image, sign_assets): if image.dest_image.debug_dir_signer is None: return c_path.create_debug_dir(image.dest_image.debug_dir_signer) sa = sign_assets fp = image.dest_image from imageinfo import DestImagePath assert isinstance(fp, DestImagePath) debug_logs = [ (sa.root_cert, fp.debug_file_signer_root_cert), (sa.attestation_ca_cert, fp.debug_file_signer_attestation_ca_cert), (sa.attestation_cert, fp.debug_file_signer_attestation_cert), (sa.signature, fp.debug_file_signer_signature), (sa.cert_chain, fp.debug_file_signer_cert_chain) ] # Save the private attributes too debug_logs += [ (sa.root_key, fp.debug_file_signer_root_key), (sa.attestation_ca_key, fp.debug_file_signer_attestation_ca_key), (sa.attestation_key, fp.debug_file_signer_attestation_key) ] for data, debug_file in debug_logs: try: store_data_to_file(debug_file, data) except Exception: logger.debug2('Failed to save debug file ' + debug_file + '\n' ' ' + str(sys.exc_info()[1]))
def _create_parsegen_obj(self, image): c_path.create_debug_dir(image.dest_image.debug_dir_parsegen) from sectools.features.isc.parsegen import get_parser parsegen = get_parser(image) # Check if parsegen authority settings are correct parsegen.authority = self.authority parsegen.validate_authority() return parsegen
def _sign_image(self, image, parsegen): logger.info('Resigning signed' if parsegen.is_signed() else 'Signing' ' image: ' + image.image_under_operation) c_path.create_debug_dir(image.dest_image.debug_dir_signer) signer = Signer(image.config) sign_assets = signer.sign(parsegen.data_to_sign, image) # Dump any debug information self.dump_signer_debug_data(image, sign_assets) parsegen.data_signature = sign_assets.signature parsegen.cert_chain = sign_assets.cert_chain
def dump_signer_debug_data(self, image, sign_assets, parsegen): if image.dest_image.debug_dir_signer is None: return c_path.create_debug_dir(image.dest_image.debug_dir_signer) sa = sign_assets fp = image.dest_image from imageinfo import DestImagePath assert isinstance(fp, DestImagePath) # Backup parsegen authority authority = parsegen.authority # QTI Signature and Cert Chain parsegen.authority = defines.AUTHORITY_QTI data_signature_qti = parsegen.data_signature cert_chain_qti = parsegen.cert_chain # OEM Signature and Cert Chain parsegen.authority = defines.AUTHORITY_OEM data_signature = parsegen.data_signature cert_chain = parsegen.cert_chain # Restore authority parsegen.authority = authority debug_logs = [ (sa.root_cert, fp.debug_file_signer_root_cert), (sa.attestation_ca_cert, fp.debug_file_signer_attestation_ca_cert), (sa.attestation_cert, fp.debug_file_signer_attestation_cert), (data_signature, fp.debug_file_signer_signature), (cert_chain, fp.debug_file_signer_cert_chain), (data_signature_qti, fp.debug_file_signer_qti_signature), (cert_chain_qti, fp.debug_file_signer_qti_cert_chain) ] # Save the private attributes too debug_logs += [ (sa.root_key, fp.debug_file_signer_root_key), (sa.attestation_ca_key, fp.debug_file_signer_attestation_ca_key), (sa.attestation_key, fp.debug_file_signer_attestation_key) ] for data, debug_file in debug_logs: try: store_data_to_file(debug_file, data) except Exception: logger.debug2('Failed to save debug file ' + debug_file + '\n' ' ' + str(sys.exc_info()[1]))
def _create_parsegen_obj(self, image, validating=False, signing=False, prefix_override=None, sign_attr=False): c_path.create_debug_dir(image.dest_image.debug_dir_parsegen) from sectools.features.isc.parsegen import get_parser parsegen = get_parser(image, validating, signing, prefix_override, sign_attr) # Check if parsegen authority settings are correct parsegen.authority = self.authority parsegen.validate_authority() return parsegen
def _sign_image(self, image, parsegen): logger.info('Resigning signed' if parsegen.is_signed() else 'Signing' ' image: ' + image.image_under_operation) c_path.create_debug_dir(image.dest_image.debug_dir_signer) signer = Signer(image.config) # TODO: a sanity check here # data_to_sign = parsegen.data_to_sign # if data_to_sign != parsegen.data_to_sign: # raise RuntimeError('Data to sign is changing') sign_assets = signer.sign(parsegen.data_to_sign, image, image.dest_image.debug_dir_signer) # Dump any debug information self.dump_signer_debug_data(image, sign_assets) parsegen.data_signature = sign_assets.signature parsegen.cert_chain = sign_assets.cert_chain
def dump_signer_debug_data(self, image, sign_assets, parsegen, more_debug_logs=[]): if image.dest_image.debug_dir_signer is None: return c_path.create_debug_dir(image.dest_image.debug_dir_signer) sa = sign_assets fp = image.dest_image assert isinstance(fp, self.dest_image_path_class) # Backup parsegen authority authority = parsegen.authority # OEM Signature and Cert Chain parsegen.authority = AUTHORITY_OEM data_signature = parsegen.data_signature cert_chain = parsegen.cert_chain # Restore authority parsegen.authority = authority debug_logs = [(sa.root_cert, fp.debug_file_signer_root_cert), (sa.attestation_ca_cert, fp.debug_file_signer_attestation_ca_cert), (sa.attestation_cert, fp.debug_file_signer_attestation_cert), (data_signature, fp.debug_file_signer_signature), (cert_chain, fp.debug_file_signer_cert_chain)] for dbg_log in more_debug_logs: debug_logs.append((dbg_log[0], getattr(fp, dbg_log[1]))) # Save the private attributes too debug_logs += [(sa.root_key, fp.debug_file_signer_root_key), (sa.attestation_ca_key, fp.debug_file_signer_attestation_ca_key), (sa.attestation_key, fp.debug_file_signer_attestation_key)] for data, debug_file in debug_logs: try: store_data_to_file(debug_file, data) except Exception: logger.debug2('Failed to save debug file ' + debug_file + '\n' ' ' + str(sys.exc_info()[1]))
def _create_parsegen_obj(self, image, validating=False, signing=False, file_exists=True, parsegens=None, sign_attr=False): c_path.create_debug_dir(image.dest_image.debug_dir_parsegen) image_path = image.src_image.image_path image_name = os.path.basename(image_path) image_base, image_ext = os.path.splitext(image_name) data = load_data_from_file(image_path) if file_exists else None parsegen = ElfMbnV3Base(data, imageinfo=image, debug_dir=image.dest_image.debug_dir_parsegen, debug_prefix=image_base, debug_suffix=image_ext, validating=validating, signing=signing, parsegens=parsegens, sign_attr=sign_attr) # Check if parsegen authority settings are correct parsegen.authority = self.authority parsegen.validate_authority() return parsegen
def _create_parsegen_obj(self, image): c_path.create_debug_dir(image.dest_image.debug_dir_parsegen) parsegen = get_parser(image) return parsegen
def _create_parsegen_obj(self, image): c_path.create_debug_dir(image.dest_image.debug_dir_parsegen) from sectools.features.isc.parsegen import get_parser parsegen = get_parser(image) return parsegen
def _process_validation(self, image, progress, security_policy_list, i_val_image, i_val_integrity_check, i_val_sign, i_val_encrypt, idx=0): # 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 val_encrypt and image.general_properties.selected_encryptor: c_path.create_debug_dir(image.dest_image.debug_dir_encdec) encdec = get_encdec(image) # 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) finally: image.image_type.file_type = file_type_backup image.encdec = encdec_backup # Set the security mechanisms parsegen.integrity_check = parsegen.contains_integrity_check() parsegen.sign = parsegen.is_signed() parsegen.encrypt = parsegen.is_encrypted() # Dump any debug data self.dump_parsegen_debug_data(image, parsegen) # 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) # 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(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 try: self._process_validation(image, progress, security_policy_list, i_val_image, i_val_integrity_check, i_val_sign, i_val_encrypt, idx + 1) 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 _process_secure_operation(self, image, progress, security_policy_list, i_integrity_check, i_sign, i_encrypt, i_decrypt, idx=0): # 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 integrity_check = security_policy_list[idx].integrity_check and i_integrity_check sign = security_policy_list[idx].sign and i_sign encrypt = security_policy_list[idx].encrypt and i_encrypt decrypt = security_policy_list[idx].encrypt and i_decrypt # Create the encryptor object encdec = None if encrypt or decrypt: c_path.create_debug_dir(image.dest_image.debug_dir_encdec) encdec = get_encdec(image) # 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.parsegen, progress, True, image) finally: image.image_type.file_type = file_type_backup image.encdec = encdec_backup # Do not allow signed unencrypted elf images to be encrypted as the # Sign will not longer match the encrypted image's tosign if parsegen.file_type() == 'elf' and parsegen.is_signed() and not sign and not parsegen.is_encrypted() and encrypt: raise RuntimeError('Cannot encrypt a signed unencrypted image without resigning ' 'as the sign no longer matches the format change.') # Set the security mechanisms parsegen.integrity_check = security_policy_list[idx].integrity_check and (parsegen.contains_integrity_check() or integrity_check) parsegen.sign = security_policy_list[idx].sign and (parsegen.is_signed() or sign) parsegen.encrypt = security_policy_list[idx].encrypt and (False if decrypt else (parsegen.is_encrypted() or encrypt)) # If encrypt: if encrypt: parsegen.encryption_params = encdec.get_encryption_parameters_blob() # 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(delete=False) tmp_fd.close() store_data_to_file(tmp_fd.name, data) # 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 image.src_image.image_dir_base = os.path.dirname(tmp_fd.name) image.src_image.image_dir_ext = '' image.src_image.image_name = os.path.basename(tmp_fd.name) try: data = self._process_secure_operation(image, progress, security_policy_list, i_integrity_check, i_sign, i_encrypt, i_decrypt, idx + 1) 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 os.remove(tmp_fd.name) parsegen.set_wrapped_data(data) # Sign the image if sign: self._status_updater(self._sign_image, image.status.sign, progress, True, image, parsegen) # Package and generate the output image file data = parsegen.get_data() if integrity_check: image.status.integrity_check.state = StatusInfo.SUCCESS if encrypt: image.status.encrypt.state = StatusInfo.SUCCESS if idx != 0: return data if decrypt: store_data_to_file(image.dest_image.decrypted_file, data) else: store_data_to_file(image.dest_image.image_path, data) logger.info(('Signed ' if sign else '') + ('& ' if sign and encrypt else '') + ('Encrypted ' if encrypt else '') + 'image is stored at ' + image.dest_image.image_path) image.image_under_operation = image.dest_image.image_path # Do any post processing self._status_updater(self._post_process, image.status.postprocess, progress, True, image, image.config.post_process.pil_splitter, getattr(self._stager, '_meta_build_path', None)) return parsegen
def _process_secure_operation(self, image, progress, security_policy_list, sign_attr, i_integrity_check, i_sign, i_encrypt, i_decrypt, idx=0, prefix_override=None): from imageinfo import ImageInfo, StatusInfo # 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 integrity_check = security_policy_list[ idx].integrity_check and i_integrity_check sign = security_policy_list[idx].sign and i_sign encrypt = security_policy_list[idx].encrypt and i_encrypt decrypt = security_policy_list[idx].encrypt and i_decrypt # 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, False) # 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.parsegen, progress, True, image, False, sign, prefix_override, sign_attr) 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, encrypt) # Do not allow signed unencrypted elf images to be encrypted as the # Sign will not longer match the encrypted image's tosign if parsegen.file_type() == 'elf' and parsegen.is_signed( ) and not sign and not parsegen.is_encrypted() and encrypt: raise RuntimeError( 'Cannot encrypt a signed unencrypted image without resigning ' 'as the sign no longer matches the format change.') # Set the security mechanisms parsegen.integrity_check = security_policy_list[ idx].integrity_check and (parsegen.contains_integrity_check() or integrity_check) parsegen.sign = security_policy_list[idx].sign and ( parsegen.is_signed() or sign) parsegen.encrypt = security_policy_list[idx].encrypt and ( False if decrypt else (parsegen.is_encrypted() or encrypt)) # Get blob if populating encryption parameters: if encrypt: if encdec is None: raise RuntimeError('Encryptor is not set') parsegen.encryption_params = encdec.get_encryption_parameters_blob( ) # check if input image is a TA, if yes re-initialize encdec object with updated bitmap for manifest segment if is_TA(image.signing_attributes.sw_id): non_encrypt_segment_found, encrypted_segments_indices = self._get_encrypted_segments_index_list( parsegen._elf_parsegen.phdrs) if non_encrypt_segment_found and len( encrypted_segments_indices) > 0: logger.info( "Re-initializing encdec object for updated segment bitmap" ) encdec = get_encdec(image, False, encrypted_segments_indices) parsegen.encryption_params = encdec.get_encryption_parameters_blob( ) parsegen.encdec = encdec elif parsegen.encryption_params and parsegen.encdec is not None: parsegen.encdec.update_encryption_parameters( parsegen.encryption_params) # 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(delete=False) tmp_fd.close() store_data_to_file(tmp_fd.name, data) # 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 image.src_image.image_dir_base = os.path.dirname(tmp_fd.name) image.src_image.image_dir_ext = '' image.src_image.image_name = os.path.basename(tmp_fd.name) # Override debug dumped file prefix prefix_override = SecImageCore._get_prefix_override( prefix_override, file_type) try: data = self._process_secure_operation( image, progress, security_policy_list, sign_attr, i_integrity_check, i_sign, i_encrypt, i_decrypt, idx + 1, prefix_override) 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 os.remove(tmp_fd.name) parsegen.set_wrapped_data(data) # Sign the image if sign: self._status_updater(self._sign_image, image.status.sign, progress, True, image, parsegen) # Package and generate the output image file data = parsegen.get_data() if integrity_check: image.status.integrity_check.state = StatusInfo.SUCCESS if encrypt: image.status.encrypt.state = StatusInfo.SUCCESS if idx != 0: return data if decrypt: encryption_params_backup = parsegen.encryption_params parsegen.encryption_params = '' try: store_data_to_file(image.dest_image.decrypted_file, parsegen.get_data()) finally: parsegen.encryption_params = encryption_params_backup else: store_data_to_file(image.dest_image.image_path, data) logger.info(('Signed ' if sign else '') + ('& ' if sign and encrypt else '') + ('Encrypted ' if encrypt else '') + 'image is stored at ' + image.dest_image.image_path) image.image_under_operation = image.dest_image.image_path # Do any post processing self._status_updater(self._post_process, image.status.postprocess, progress, True, image, image.config.post_process.pil_splitter, getattr(self._stager, '_meta_build_path', None)) return parsegen
def _process_validation(self, image, progress, val_image, val_integrity_check, val_sign, val_encrypt): # TODO: Need to figure how to do this #image.dest_image._mid = 'validation' # 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 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 val_encrypt: try: c_path.create_debug_dir(image.dest_image.debug_dir_encdec) encdec = get_encdec(image) except Exception: pass # Create the parsegen object image.encdec = encdec parsegen = self._status_updater(self._create_parsegen_obj, image.status.validate_parsegen, progress, True, image) # Set the security mechanisms parsegen.integrity_check = parsegen.contains_integrity_check() parsegen.sign = parsegen.is_signed() parsegen.encrypt = parsegen.is_encrypted() # Dump any debug data self.dump_parsegen_debug_data(image, parsegen) # 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) except Exception: 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 raise else: 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
def process(self, verify_setup=False, integrity_check=False, sign=False, encrypt=False, decrypt=False, val_image=False, val_integrity_check=False, val_sign=False, val_encrypt=False, progress_cb=PROGRESS_CB_PYPASS): """Performs the secure-image related operations specified from the params. :param bool verify_setup: Verify that the configuration of the object is correct and return. This will ignore any other params. :param bool integrity_check: Add integrity check to the image. :param bool sign: Sign the images. (Re-sign if image is already signed) :param bool encrypt: Encrypt the images. (Re-encrypt if image is already encrypted) :param bool val_image: Validate the integrity of the image against the config file. :param bool val_integrity_check: Validate the integrity check in the image. :param bool val_sign: Validate that the image is signed and validate the integrity of the signing related data. :param bool val_encrypt: Validate that the image is encrypted and validate the integrity of the encryption related data. :param cb progress_cb: Callback method to get a status update during processing. Callback method should have this format: :: def progress_cb(status_string, progress_percent): \""" :param str status_string: the current status. :param int progress_percent: the progress (in percent) \""" ... """ # Ensure that one or more image files is provided for processing if self._stager is None or not self.image_path_list: raise RuntimeError('Please specify one or more images for processing') # Ensure the correct set of operations is provided if not (verify_setup or integrity_check or sign or encrypt or decrypt or val_image or val_integrity_check or val_sign or val_encrypt): raise RuntimeError('Please specify one or more operations to perform.') if verify_setup: logger.note('The inputs provided (config, cmd args) are valid.') return # Start processing images total_images = len(self.image_info_list) progress = ProgressNotifier(total_images, progress_cb, PROGRESS_TOTAL_STAGES) for idx, image in enumerate(self.image_info_list): assert isinstance(image, ImageInfo) logger.info('------------------------------------------------------') status_string = ('Processing ' + str(idx + 1) + '/' + str(total_images) + ': ' + image.image_under_operation) logger.info(status_string + '\n') # Send a progress notification to the toplevel progress.status = status_string progress.cur = idx progress.cur_stage = 0 file_logger_id = None try: # Create the required directory structure for this image image_output_dir = image.dest_image.image_dir try: c_path.create_dir(image_output_dir) except Exception as e: raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n' ' ' + 'Error: ' + str(e)) # Enable/Disable debug image.dest_image.debug_enable = self.debug c_path.create_debug_dir(image.dest_image.debug_dir) # Enable file logging to the directory file_logger_id = logger.add_file_logger(c_path.join(image_output_dir, 'SecImage_log.txt'), logger.verbosity) # For secure operations if integrity_check or sign or encrypt or decrypt: self._process_secure_operation(image, progress, integrity_check, sign, encrypt, decrypt) # For validation if val_image or val_integrity_check or val_sign or val_encrypt: self._process_validation(image, progress, val_image, val_integrity_check, val_sign, val_encrypt) # Set overall processing to true if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or (val_sign and image.status.validate_sign.state == StatusInfo.ERROR) or (val_encrypt and image.status.validate_encrypt.state == StatusInfo.ERROR)): image.status.overall.state = StatusInfo.SUCCESS except Exception: logger.debug(traceback.format_exc()) logger.error(sys.exc_info()[1]) if file_logger_id is not None: logger.removeFileLogger(file_logger_id) logger.info('------------------------------------------------------\n') progress.complete()
def _process_validation(self, image, progress, security_policy_list, i_val_image, i_val_integrity_check, i_val_sign, i_val_encrypt, idx=0): # 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 val_encrypt: c_path.create_debug_dir(image.dest_image.debug_dir_encdec) encdec = get_encdec(image) # 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) finally: image.image_type.file_type = file_type_backup image.encdec = encdec_backup # Set the security mechanisms parsegen.integrity_check = parsegen.contains_integrity_check() parsegen.sign = parsegen.is_signed() parsegen.encrypt = parsegen.is_encrypted() # Dump any debug data self.dump_parsegen_debug_data(image, parsegen) # 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) # 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(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 try: self._process_validation(image, progress, security_policy_list, i_val_image, i_val_integrity_check, i_val_sign, i_val_encrypt, idx + 1) 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 process(self, verify_setup=False, sign=False, encrypt=False, decrypt=False, val_image=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 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_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 sign or encrypt or val_image or val_sign or val_encrypt or decrypt): 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 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) # Create the encryptor object if encrypt or decrypt or val_encrypt: try: c_path.create_debug_dir( image.dest_image.debug_dir_encdec) encdec = get_encdec(image) except Exception: if not val_encrypt: raise else: encdec = None # Create the parsegen object image.encdec = encdec parsegen = self._status_updater(self._create_parsegen_obj, image.status.parsegen, image) progress.push() # Set the security mechanisms parsegen.sign = parsegen.is_signed() or sign parsegen.encrypt = parsegen.is_encrypted() or encrypt # If encrypt: if encrypt: parsegen.encryption_params = encdec.get_encryption_parameters_blob( ) # Dump any debug data self.dump_parsegen_debug_data(image, parsegen) # Sign the image if sign: self._status_updater(self._sign_image, image.status.sign, image, parsegen) progress.push() # Package and generate the output file if sign or encrypt: store_data_to_file(image.dest_image.image_path, parsegen.get_data()) if encrypt: image.status.encrypt.state = StatusInfo.SUCCESS logger.info(('Signed ' if sign else '') + ('& ' if sign and encrypt else '') + ('Encrypted ' if encrypt else '') + 'image is stored at ' + image.dest_image.image_path) image.image_under_operation = image.dest_image.image_path # Do any post processing self._status_updater( self._post_process, image.status.postprocess, image, image.config.post_process.pil_splitter, getattr(self._stager, '_meta_build_path', None)) progress.push() # Print the image data logger.info('\n' + str(parsegen)) # Decrypt the image if decrypt: store_data_to_file(image.dest_image.decrypted_file, parsegen.get_data(encrypt=False)) # Validate parsegen if val_image: self._validate_parsegen(image, parsegen) progress.push() # Validate sign if val_sign: self._validate_sign(image, parsegen) progress.push() # Validate encrypt if val_encrypt: self._validate_encrypt(image, parsegen) progress.push() # Set overall processing to true image.status.overall.state = StatusInfo.SUCCESS except Exception: logger.debug(traceback.format_exc()) logger.error(sys.exc_info()[1]) logger.info( '------------------------------------------------------\n') progress.complete()
def _process(idx, image, sign_attr, integrity_check, sign, encrypt, decrypt, val_image, val_integrity_check, val_sign, val_encrypt): assert isinstance(image, ImageInfo) logger.info( '------------------------------------------------------') status_string = ('Processing ' + str(idx + 1) + '/' + str(total_image_count) + ': ' + image.image_under_operation) logger.info(status_string + '\n') # Send a progress notification to the toplevel progress.status = status_string progress.cur = idx progress.cur_stage = 0 file_logger_id = None image.authority = self.authority try: # Create the required directory structure for this image image_output_dir = image.dest_image.image_dir try: c_path.create_dir(image_output_dir) except Exception as e: raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n' ' ' + 'Error: ' + str(e)) # Enable/Disable debug image.dest_image.debug_enable = self.debug c_path.create_debug_dir(image.dest_image.debug_dir) # Set the root cert hash image.validation_root_cert_hash = root_cert_hash # Enable file logging to the directory file_logger_id = logger.add_file_logger( c_path.join(image_output_dir, 'SecImage_log.txt'), logger.verbosity) # Create the security policies list for this image security_policy_list = create_security_policy_list(image) # Parsegen object parsegen = None # For secure operations if integrity_check or sign or encrypt or decrypt: parsegen = self._process_secure_operation( image, progress, security_policy_list, sign_attr, integrity_check, sign, encrypt, decrypt) # For validation if val_image or val_integrity_check or val_sign or val_encrypt: # Bypass validation when encrypted key provide is configured as UIE server because decryption will always fail if parsegen is not None and parsegen.is_encrypted( ) and encrypted_key_provider_id_supported( image.general_properties.UIE_key): logger.warning( "Skipping validation because encrypted key provider is configured as UIE server" ) else: parsegen = self._process_validation( image, progress, security_policy_list, val_image, val_integrity_check, val_sign, val_encrypt) # Print the image data if parsegen is not None: logger.info('\n' + str(parsegen)) # Set overall processing to true if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or (val_sign and image.status.validate_sign.state == StatusInfo.ERROR) or (val_encrypt and image.status.validate_encrypt.state == StatusInfo.ERROR)): image.status.overall.state = StatusInfo.SUCCESS except RemoteSignerNote as e: logger.info('NOTE: ' + str(e), color=logger.YELLOW) except Exception: logger.error(traceback.format_exc()) logger.error(sys.exc_info()[1]) finally: if file_logger_id is not None: logger.removeFileLogger(file_logger_id) logger.info( '------------------------------------------------------\n')
def _process_secure_operation(self, image, progress, security_policy_list, i_integrity_check, i_sign, i_encrypt, i_decrypt, idx=0): from imageinfo import ImageInfo, StatusInfo # 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 integrity_check = security_policy_list[ idx].integrity_check and i_integrity_check sign = security_policy_list[idx].sign and i_sign encrypt = security_policy_list[idx].encrypt and i_encrypt decrypt = security_policy_list[idx].encrypt and i_decrypt # Create the encryptor object encdec = None if encrypt or decrypt: c_path.create_debug_dir(image.dest_image.debug_dir_encdec) encdec = get_encdec(image) # 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.parsegen, progress, True, image) finally: image.image_type.file_type = file_type_backup image.encdec = encdec_backup # Do not allow signed unencrypted elf images to be encrypted as the # Sign will not longer match the encrypted image's tosign if parsegen.file_type() == 'elf' and parsegen.is_signed( ) and not sign and not parsegen.is_encrypted() and encrypt: raise RuntimeError( 'Cannot encrypt a signed unencrypted image without resigning ' 'as the sign no longer matches the format change.') # Set the security mechanisms parsegen.integrity_check = security_policy_list[ idx].integrity_check and (parsegen.contains_integrity_check() or integrity_check) parsegen.sign = security_policy_list[idx].sign and ( parsegen.is_signed() or sign) parsegen.encrypt = security_policy_list[idx].encrypt and ( False if decrypt else (parsegen.is_encrypted() or encrypt)) # If encrypt: if encrypt: parsegen.encryption_params = encdec.get_encryption_parameters_blob( ) # 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(delete=False) tmp_fd.close() store_data_to_file(tmp_fd.name, data) # 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 image.src_image.image_dir_base = os.path.dirname(tmp_fd.name) image.src_image.image_dir_ext = '' image.src_image.image_name = os.path.basename(tmp_fd.name) try: data = self._process_secure_operation(image, progress, security_policy_list, i_integrity_check, i_sign, i_encrypt, i_decrypt, idx + 1) 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 os.remove(tmp_fd.name) parsegen.set_wrapped_data(data) # Sign the image if sign: self._status_updater(self._sign_image, image.status.sign, progress, True, image, parsegen) # Package and generate the output image file data = parsegen.get_data() if integrity_check: image.status.integrity_check.state = StatusInfo.SUCCESS if encrypt: image.status.encrypt.state = StatusInfo.SUCCESS if idx != 0: return data if decrypt: ecryption_params_backup = parsegen.encryption_params parsegen.encryption_params = '' try: store_data_to_file(image.dest_image.decrypted_file, parsegen.get_data()) finally: parsegen.encryption_params = ecryption_params_backup else: store_data_to_file(image.dest_image.image_path, data) logger.info(('Signed ' if sign else '') + ('& ' if sign and encrypt else '') + ('Encrypted ' if encrypt else '') + 'image is stored at ' + image.dest_image.image_path) image.image_under_operation = image.dest_image.image_path # Do any post processing self._status_updater(self._post_process, image.status.postprocess, progress, True, image, image.config.post_process.pil_splitter, getattr(self._stager, '_meta_build_path', None)) return parsegen
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 process(self, verify_setup=False, integrity_check=False, sign=False, encrypt=False, decrypt=False, val_image=False, val_integrity_check=False, val_sign=False, val_encrypt=False, progress_cb=PROGRESS_CB_PYPASS): """Performs the secure-image related operations specified from the params. :param bool verify_setup: Verify that the configuration of the object is correct and return. This will ignore any other params. :param bool integrity_check: Add integrity check to the image. :param bool sign: Sign the images. (Re-sign if image is already signed) :param bool encrypt: Encrypt the images. (Re-encrypt if image is already encrypted) :param bool val_image: Validate the integrity of the image against the config file. :param bool val_integrity_check: Validate the integrity check in the image. :param bool val_sign: Validate that the image is signed and validate the integrity of the signing related data. :param bool val_encrypt: Validate that the image is encrypted and validate the integrity of the encryption related data. :param cb progress_cb: Callback method to get a status update during processing. Callback method should have this format: :: def progress_cb(status_string, progress_percent): \""" :param str status_string: the current status. :param int progress_percent: the progress (in percent) \""" ... """ # Ensure that one or more image files is provided for processing if self._stager is None or not self.image_path_list: raise RuntimeError('Please specify one or more images for processing') # Ensure the correct set of operations is provided if not (verify_setup or integrity_check or sign or encrypt or decrypt or val_image or val_integrity_check or val_sign or val_encrypt): raise RuntimeError('Please specify one or more operations to perform.') if verify_setup: logger.note('The inputs provided (config, cmd args) are valid.') return # Start processing images total_images = len(self.image_info_list) progress = ProgressNotifier(total_images, progress_cb, PROGRESS_TOTAL_STAGES) for idx, image in enumerate(self.image_info_list): assert isinstance(image, ImageInfo) logger.info('------------------------------------------------------') status_string = ('Processing ' + str(idx + 1) + '/' + str(total_images) + ': ' + image.image_under_operation) logger.info(status_string + '\n') # Send a progress notification to the toplevel progress.status = status_string progress.cur = idx progress.cur_stage = 0 file_logger_id = None try: # Create the required directory structure for this image image_output_dir = image.dest_image.image_dir try: c_path.create_dir(image_output_dir) except Exception as e: raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n' ' ' + 'Error: ' + str(e)) # Enable/Disable debug image.dest_image.debug_enable = self.debug c_path.create_debug_dir(image.dest_image.debug_dir) # Enable file logging to the directory file_logger_id = logger.add_file_logger(c_path.join(image_output_dir, 'SecImage_log.txt'), logger.verbosity) # Create the security policies list for this image security_policy_list = create_security_policy_list(image) # Parsegen object parsegen = None # For secure operations if integrity_check or sign or encrypt or decrypt: parsegen = self._process_secure_operation(image, progress, security_policy_list, integrity_check, sign, encrypt, decrypt) # For validation if val_image or val_integrity_check or val_sign or val_encrypt: parsegen = self._process_validation(image, progress, security_policy_list, val_image, val_integrity_check, val_sign, val_encrypt) # Print the image data if parsegen is not None: logger.info('\n' + str(parsegen)) # Set overall processing to true if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or (val_sign and image.status.validate_sign.state == StatusInfo.ERROR) or (val_encrypt and image.status.validate_encrypt.state == StatusInfo.ERROR)): image.status.overall.state = StatusInfo.SUCCESS except Exception: logger.debug(traceback.format_exc()) logger.error(sys.exc_info()[1]) if file_logger_id is not None: logger.removeFileLogger(file_logger_id) logger.info('------------------------------------------------------\n') progress.complete()
def _process(idx, image, integrity_check, sign, val_image, val_integrity_check, val_sign): assert isinstance(image, ImageInfoIot) logger.info('------------------------------------------------------') status_string = ('Processing: ' + image.image_under_operation) logger.info(status_string + '\n') # Send a progress notification to the toplevel progress.status = status_string progress.cur = idx progress.cur_stage = 0 file_logger_id = None image.authority = self.authority try: # Create the required directory structure for this image image_output_dir = image.dest_image.image_dir try: c_path.create_dir(image_output_dir) except Exception as e: raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n' ' ' + 'Error: ' + str(e)) # Enable/Disable debug image.dest_image.debug_enable = self.debug c_path.create_debug_dir(image.dest_image.debug_dir) # Set the root cert hash image.validation_root_cert_hash = root_cert_hash # Enable file logging to the directory file_logger_id = logger.add_file_logger(c_path.join(image_output_dir, 'IoT_log.txt'), logger.verbosity) # Create the security policies list for this image security_policy_list = create_security_policy_list(image) # Parsegen object parsegen = None # For secure operations if integrity_check or sign: parsegen = self._process_secure_operation( image, progress, security_policy_list, integrity_check, sign, parsegens=parsegens.get(image.chipset, list())) # For validation if val_image or val_integrity_check or val_sign: parsegen = self._process_validation( image, progress, security_policy_list, val_image, val_integrity_check, val_sign) # Print the image data if parsegen is not None: logger.info('\n' + str(parsegen)) # Set overall processing to true if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or (val_sign and image.status.validate_sign.state == StatusInfo.ERROR)): image.status.overall.state = StatusInfo.SUCCESS except Exception: logger.error(traceback.format_exc()) logger.error(sys.exc_info()[1]) finally: if file_logger_id is not None: logger.removeFileLogger(file_logger_id) logger.info('------------------------------------------------------\n')
def process(self, verify_setup=False, integrity_check=False, sign=False, encrypt=False, decrypt=False, val_image=False, val_integrity_check=False, val_sign=False, val_encrypt=False, root_cert_hash=None, progress_cb=PROGRESS_CB_PYPASS): """Performs the secure-image related operations specified from the params. :param bool verify_setup: Verify that the configuration of the object is correct and return. This will ignore any other params. :param bool integrity_check: Add integrity check to the image. :param bool sign: Sign the images. (Re-sign if image is already signed) :param bool encrypt: Encrypt the images. (Re-encrypt if image is already encrypted) :param bool val_image: Validate the integrity of the image against the config file. :param bool val_integrity_check: Validate the integrity check in the image. :param bool val_sign: Validate that the image is signed and validate the integrity of the signing related data. :param bool val_encrypt: Validate that the image is encrypted and validate the integrity of the encryption related data. :param cb progress_cb: Callback method to get a status update during processing. Callback method should have this format: :: def progress_cb(status_string, progress_percent): \""" :param str status_string: the current status. :param int progress_percent: the progress (in percent) \""" ... """ from imageinfo import ImageInfo, StatusInfo from sectools.features.isc.signer.remote import RemoteSignerNote # Ensure that one or more image files is provided for processing if self._stager is None or not self.image_path_list: raise RuntimeError( 'Please specify one or more images for processing') # Ensure the correct set of operations is provided if not (verify_setup or integrity_check or sign or encrypt or decrypt or val_image or val_integrity_check or val_sign or val_encrypt): raise RuntimeError( 'Please specify one or more operations to perform.') # Print the openssl path version = '' path_info = 'is unavailable. Please run "which openssl" and "openssl version" to check openssl version info, and upgrade to required version' try: from sectools.common import crypto from sectools.common.crypto import crypto_functions version = 'v' + crypto.discovery.openssl.OPENSSL_VERSION_MIN + ' or greater ' crypto_functions.are_available([crypto_functions.MOD_OPENSSL]) path_info = 'is available at: "' + crypto.openssl_binary_implementation.openssl_binary_path + '"' except Exception as e: pass logger.info('Openssl ' + version + path_info) if verify_setup: logger.note('The inputs provided (config, cmd args) are valid.') return # Start processing images total_images = len(self.image_info_list) progress = ProgressNotifier(total_images, progress_cb, PROGRESS_TOTAL_STAGES) for idx, image in enumerate(self.image_info_list): assert isinstance(image, ImageInfo) logger.info( '------------------------------------------------------') status_string = ('Processing ' + str(idx + 1) + '/' + str(total_images) + ': ' + image.image_under_operation) logger.info(status_string + '\n') # Send a progress notification to the toplevel progress.status = status_string progress.cur = idx progress.cur_stage = 0 file_logger_id = None try: # Create the required directory structure for this image image_output_dir = image.dest_image.image_dir try: c_path.create_dir(image_output_dir) except Exception as e: raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n' ' ' + 'Error: ' + str(e)) # Enable/Disable debug image.dest_image.debug_enable = self.debug c_path.create_debug_dir(image.dest_image.debug_dir) # Set the root cert hash image.validation_root_cert_hash = root_cert_hash # Enable file logging to the directory file_logger_id = logger.add_file_logger( c_path.join(image_output_dir, 'SecImage_log.txt'), logger.verbosity) # Create the security policies list for this image security_policy_list = create_security_policy_list(image) # Parsegen object parsegen = None # For secure operations if integrity_check or sign or encrypt or decrypt: parsegen = self._process_secure_operation( image, progress, security_policy_list, integrity_check, sign, encrypt, decrypt) # For validation if val_image or val_integrity_check or val_sign or val_encrypt: parsegen = self._process_validation( image, progress, security_policy_list, val_image, val_integrity_check, val_sign, val_encrypt) # Print the image data if parsegen is not None: logger.info('\n' + str(parsegen)) # Set overall processing to true if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or (val_sign and image.status.validate_sign.state == StatusInfo.ERROR) or (val_encrypt and image.status.validate_encrypt.state == StatusInfo.ERROR)): image.status.overall.state = StatusInfo.SUCCESS except RemoteSignerNote as e: logger.info('NOTE: ' + str(e), color=logger.YELLOW) except Exception: logger.error(traceback.format_exc()) logger.error(sys.exc_info()[1]) if file_logger_id is not None: logger.removeFileLogger(file_logger_id) logger.info( '------------------------------------------------------\n') progress.complete()