[PATCH v16 31/33] tests/functional/s390x: Add secure IPL functional test

2026-07-07 Thread Zhuoying Cai
Add functional test for secure IPL.

Signed-off-by: Zhuoying Cai 
Reviewed-by: Matthew Rosato 
---
 tests/functional/s390x/meson.build|   2 +
 tests/functional/s390x/test_secure_ipl.py | 172 ++
 2 files changed, 174 insertions(+)
 create mode 100755 tests/functional/s390x/test_secure_ipl.py

diff --git a/tests/functional/s390x/meson.build 
b/tests/functional/s390x/meson.build
index b065b666bc..16da5f0054 100644
--- a/tests/functional/s390x/meson.build
+++ b/tests/functional/s390x/meson.build
@@ -2,6 +2,7 @@
 
 test_s390x_timeouts = {
   'ccw_virtio' : 420,
+  'secure_ipl' : 360,
 }
 
 tests_s390x_system_quick = [
@@ -14,6 +15,7 @@ tests_s390x_system_thorough = [
   'ccw_virtio',
   'pxelinux',
   'replay',
+  'secure_ipl',
   'topology',
   'tuxrun',
 ]
diff --git a/tests/functional/s390x/test_secure_ipl.py 
b/tests/functional/s390x/test_secure_ipl.py
new file mode 100755
index 00..06fc93e404
--- /dev/null
+++ b/tests/functional/s390x/test_secure_ipl.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+"""
+s390x Secure IPL functional test.
+
+Validates s390x secure boot by preparing a signed guest image, booting with
+secure-boot enabled, and verifying cryptographic validation results.
+"""
+
+from subprocess import check_call, DEVNULL
+
+from qemu_test import QemuSystemTest, Asset, get_qemu_img
+from qemu_test import exec_command_and_wait_for_pattern, exec_command
+from qemu_test import wait_for_console_pattern, skipBigDataTest
+
+class S390xSecureIpl(QemuSystemTest):
+"""Test s390x Secure IPL (secure boot) functionality."""
+ASSET_F40_QCOW2 = Asset(
+('https://archives.fedoraproject.org/pub/archive/'
+ 'fedora-secondary/releases/40/Server/s390x/images/'
+ 'Fedora-Server-KVM-40-1.14.s390x.qcow2'),
+'091c232a7301be14e19c76ce9a0c1cbd2be2c4157884a731e1fc4f89e7455a5f')
+
+def __init__(self, *args, **kwargs):
+super().__init__(*args, **kwargs)
+self.root_password = None
+self.qcow2_path = None
+self.cert_path = None
+self.prompt = None
+
+def _create_certificate(self, vm):
+"""Generate x509 certificate"""
+exec_command_and_wait_for_pattern(self,
+  'openssl version', 'OpenSSL 3.2.1 
30',
+  vm=vm)
+exec_command_and_wait_for_pattern(self,
+'openssl req -new -x509 -newkey rsa:2048 '
+'-keyout mykey.pem -outform PEM -out mycert.pem '
+'-days 36500 -subj "/CN=My Name/" -nodes -verbose',
+'Writing private key to \'mykey.pem\'', vm=vm)
+
+def _sign_binaries(self, vm):
+"""Sign stage3 binary and kernel"""
+# Install kernel-devel (needed for sign-file)
+exec_command_and_wait_for_pattern(self,
+'sudo dnf install kernel-devel-$(uname -r) -y',
+'Complete!', vm=vm)
+wait_for_console_pattern(self, self.prompt, vm=vm)
+exec_command_and_wait_for_pattern(self,
+'ls /usr/src/kernels/$(uname -r)/scripts/',
+'sign-file', vm=vm)
+
+# Sign stage3 binary and kernel
+exec_command(self, '/usr/src/kernels/$(uname -r)/scripts/sign-file '
+'sha256 mykey.pem mycert.pem /lib/s390-tools/stage3.bin',
+vm=vm)
+wait_for_console_pattern(self, self.prompt, vm=vm)
+exec_command(self, '/usr/src/kernels/$(uname -r)/scripts/sign-file '
+'sha256 mykey.pem mycert.pem /boot/vmlinuz-$(uname -r)',
+vm=vm)
+wait_for_console_pattern(self, self.prompt, vm=vm)
+
+def _run_zipl_secure(self, vm):
+"""Run zipl to prepare for secure boot"""
+exec_command_and_wait_for_pattern(self, 'zipl --secure 1 -VV', 'Done.',
+  vm=vm)
+
+def _extract_certificate(self, vm):
+"""Extract certificate from VM to host filesystem"""
+out = exec_command_and_wait_for_pattern(self, 'cat mycert.pem',
+'-END CERTIFICATE-',
+vm=vm)
+# strip first line to avoid console echo artifacts
+cert = "\n".join(out.decode("utf-8").splitlines()[1:])
+self.log.info("%s", cert)
+
+self.cert_path = self.scratch_file("mycert.pem")
+
+with open(self.cert_path, 'w', encoding="utf-8") as file_object:
+file_object.write(cert)
+
+def setup_s390x_secure_ipl(self):
+"""
+Prepare a secure boot-enabled guest image.
+
+Boots a temporary VM to generate a certificate, sign boot components
+(stage3 and kernel), run zipl, and extract the certificate to host.
+"""
+

[PATCH v16 31/33] tests/functional/s390x: Add secure IPL functional test

2026-07-07 Thread Zhuoying Cai
Add functional test for secure IPL.

Signed-off-by: Zhuoying Cai 
Reviewed-by: Matthew Rosato 
---
 tests/functional/s390x/meson.build|   2 +
 tests/functional/s390x/test_secure_ipl.py | 172 ++
 2 files changed, 174 insertions(+)
 create mode 100755 tests/functional/s390x/test_secure_ipl.py

diff --git a/tests/functional/s390x/meson.build 
b/tests/functional/s390x/meson.build
index b065b666bc..16da5f0054 100644
--- a/tests/functional/s390x/meson.build
+++ b/tests/functional/s390x/meson.build
@@ -2,6 +2,7 @@
 
 test_s390x_timeouts = {
   'ccw_virtio' : 420,
+  'secure_ipl' : 360,
 }
 
 tests_s390x_system_quick = [
@@ -14,6 +15,7 @@ tests_s390x_system_thorough = [
   'ccw_virtio',
   'pxelinux',
   'replay',
+  'secure_ipl',
   'topology',
   'tuxrun',
 ]
diff --git a/tests/functional/s390x/test_secure_ipl.py 
b/tests/functional/s390x/test_secure_ipl.py
new file mode 100755
index 00..06fc93e404
--- /dev/null
+++ b/tests/functional/s390x/test_secure_ipl.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+"""
+s390x Secure IPL functional test.
+
+Validates s390x secure boot by preparing a signed guest image, booting with
+secure-boot enabled, and verifying cryptographic validation results.
+"""
+
+from subprocess import check_call, DEVNULL
+
+from qemu_test import QemuSystemTest, Asset, get_qemu_img
+from qemu_test import exec_command_and_wait_for_pattern, exec_command
+from qemu_test import wait_for_console_pattern, skipBigDataTest
+
+class S390xSecureIpl(QemuSystemTest):
+"""Test s390x Secure IPL (secure boot) functionality."""
+ASSET_F40_QCOW2 = Asset(
+('https://archives.fedoraproject.org/pub/archive/'
+ 'fedora-secondary/releases/40/Server/s390x/images/'
+ 'Fedora-Server-KVM-40-1.14.s390x.qcow2'),
+'091c232a7301be14e19c76ce9a0c1cbd2be2c4157884a731e1fc4f89e7455a5f')
+
+def __init__(self, *args, **kwargs):
+super().__init__(*args, **kwargs)
+self.root_password = None
+self.qcow2_path = None
+self.cert_path = None
+self.prompt = None
+
+def _create_certificate(self, vm):
+"""Generate x509 certificate"""
+exec_command_and_wait_for_pattern(self,
+  'openssl version', 'OpenSSL 3.2.1 
30',
+  vm=vm)
+exec_command_and_wait_for_pattern(self,
+'openssl req -new -x509 -newkey rsa:2048 '
+'-keyout mykey.pem -outform PEM -out mycert.pem '
+'-days 36500 -subj "/CN=My Name/" -nodes -verbose',
+'Writing private key to \'mykey.pem\'', vm=vm)
+
+def _sign_binaries(self, vm):
+"""Sign stage3 binary and kernel"""
+# Install kernel-devel (needed for sign-file)
+exec_command_and_wait_for_pattern(self,
+'sudo dnf install kernel-devel-$(uname -r) -y',
+'Complete!', vm=vm)
+wait_for_console_pattern(self, self.prompt, vm=vm)
+exec_command_and_wait_for_pattern(self,
+'ls /usr/src/kernels/$(uname -r)/scripts/',
+'sign-file', vm=vm)
+
+# Sign stage3 binary and kernel
+exec_command(self, '/usr/src/kernels/$(uname -r)/scripts/sign-file '
+'sha256 mykey.pem mycert.pem /lib/s390-tools/stage3.bin',
+vm=vm)
+wait_for_console_pattern(self, self.prompt, vm=vm)
+exec_command(self, '/usr/src/kernels/$(uname -r)/scripts/sign-file '
+'sha256 mykey.pem mycert.pem /boot/vmlinuz-$(uname -r)',
+vm=vm)
+wait_for_console_pattern(self, self.prompt, vm=vm)
+
+def _run_zipl_secure(self, vm):
+"""Run zipl to prepare for secure boot"""
+exec_command_and_wait_for_pattern(self, 'zipl --secure 1 -VV', 'Done.',
+  vm=vm)
+
+def _extract_certificate(self, vm):
+"""Extract certificate from VM to host filesystem"""
+out = exec_command_and_wait_for_pattern(self, 'cat mycert.pem',
+'-END CERTIFICATE-',
+vm=vm)
+# strip first line to avoid console echo artifacts
+cert = "\n".join(out.decode("utf-8").splitlines()[1:])
+self.log.info("%s", cert)
+
+self.cert_path = self.scratch_file("mycert.pem")
+
+with open(self.cert_path, 'w', encoding="utf-8") as file_object:
+file_object.write(cert)
+
+def setup_s390x_secure_ipl(self):
+"""
+Prepare a secure boot-enabled guest image.
+
+Boots a temporary VM to generate a certificate, sign boot components
+(stage3 and kernel), run zipl, and extract the certificate to host.
+"""
+