예제 #1
0
    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))
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
    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_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_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
예제 #9
0
    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()