From 4b5d6c035bf808fc4689f7db958c3ce15e534d73 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Mon, 5 Oct 2026 23:06:19 +0200 Subject: Testsuite: T861: boot VyOS CA signed images as-is in Secure Boot test The Secure Boot test always disabled Secure Boot in the UEFI and enrolled a Machine Owner Key. That only applies to images signed with a custom certificate - an image signed by the VyOS CA is already trusted and must boot without any firmware changes. If the custom signing key pair is present in the build tree, the MOK workflow is used as before. Otherwise the image boots with Secure Boot enabled from the start, and the Kernel signature is verified against the VyOS CA issuer and signer via "show secure-boot detail", which requires a matching vyos-1x. The make target is renamed from testsb to test-secure-boot. --- scripts/check-qemu-install | 63 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 15 deletions(-) (limited to 'scripts') diff --git a/scripts/check-qemu-install b/scripts/check-qemu-install index cbb2c964..a9a5aa97 100755 --- a/scripts/check-qemu-install +++ b/scripts/check-qemu-install @@ -108,6 +108,16 @@ KEY_Y = chr(121) mok_password = '1234' +# Custom Secure Boot signing material (see docs.vyos.io installation/secure-boot). +# If present, the image was signed with a custom CA and the MOK must be enrolled. +# If absent, the image is expected to be signed by the VyOS CA and boots as-is. +SB_CERT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'certificates') +SB_CUSTOM_KEY = os.path.join(SB_CERT_DIR, 'vyos-dev-2025-linux.key') +SB_CUSTOM_CERT = os.path.join(SB_CERT_DIR, 'vyos-dev-2025-linux.pem') +# Expected Linux Kernel signature certificate of a VyOS CA signed image +SB_VYOS_ISSUER = '/CN=VyOS Networks Secure Boot CA' +SB_VYOS_SUBJECT = '/CN=VyOS Networks Secure Boot Signer 2025 - linux' + # Map QEMU arch QEMU_CONFIG = { 'amd64': { @@ -146,7 +156,8 @@ parser.add_argument('--tpmtest', help='Execute TPM encrypted config tests', action='store_true', default=False) parser.add_argument('--ifnametest', help='Execute interface naming/hw-id persistence tests', action='store_true', default=False) -parser.add_argument('--sbtest', help='Execute Secure Boot tests', +parser.add_argument('--secure-boot-test', help='Execute Secure Boot tests (enrolls MOK only if custom ' + 'signing certificates exist in data/certificates)', action='store_true', default=False) parser.add_argument('--cloud-init', help='Execute cloud-init tests', action='store_true', default=False) @@ -417,20 +428,20 @@ if args.smoketest: _primary_modes.append('--smoketest') if args.configtest: _primary_modes.append('--configtest') -if args.sbtest: - _primary_modes.append('--sbtest') +if args.secure_boot_test: + _primary_modes.append('--secure-boot-test') if len(_primary_modes) > 1: log.error('Incompatible combination of testcase flags (%s): only one of ' '--cloud-init, --test-image-update, --tpmtest, --ifnametest, --raid, ' - '--smoketest, --configtest, --sbtest may be set.', ', '.join(_primary_modes)) + '--smoketest, --configtest, --secure-boot-test may be set.', ', '.join(_primary_modes)) sys.exit(1) if args.no_interfaces and not args.smoketest: log.error('--no-interfaces requires --smoketest') sys.exit(1) -if args.sbtest and not args.uefi: - log.error('--sbtest requires --uefi') +if args.secure_boot_test and not args.uefi: + log.error('--secure-boot-test requires --uefi') sys.exit(1) if args.logfile: @@ -466,9 +477,16 @@ if args.test_image_update and not args.iso: OVMF_CODE = '/usr/share/OVMF/OVMF_CODE_4M.secboot.fd' OVMF_VARS_TMP = args.disk.replace(DISK_IMAGE_EXTENSION, '.efivars') -if args.sbtest: +if args.secure_boot_test: shutil.copy('/usr/share/OVMF/OVMF_VARS_4M.ms.fd', OVMF_VARS_TMP) +sb_custom_ca = args.secure_boot_test and os.path.isfile(SB_CUSTOM_KEY) and os.path.isfile(SB_CUSTOM_CERT) +if args.secure_boot_test: + if sb_custom_ca: + log.info('Secure Boot test: custom signing certificate found - enrolling MOK') + else: + log.info('Secure Boot test: no custom signing certificate - expecting VyOS CA signed image') + # Creating diskimage!! diskname_raid = None def gen_disk(name): @@ -950,7 +968,7 @@ def _image_update_cli_sequence(c, log, new_image_name, server_bind_host='127.0.0 if args.qemu_cmd: tmp = get_qemu_cmd(qemu_name, args.uefi, args.disk, raid=diskname_raid, - iso_img=args.iso, vnc_enabled=args.vnc, secure_boot=args.sbtest, + iso_img=args.iso, vnc_enabled=args.vnc, secure_boot=args.secure_boot_test, nested_cdrom_iso=nested_payload_iso_path) os.system(tmp) exit(0) @@ -1010,20 +1028,26 @@ try: log.info('Installing system') cmd = get_qemu_cmd(qemu_name, args.uefi, args.disk, raid=diskname_raid, tpm=args.tpmtest, iso_img=args.iso, vnc_enabled=args.vnc, - secure_boot=args.sbtest, nested_cdrom_iso=nested_payload_iso_path) + secure_boot=args.secure_boot_test, nested_cdrom_iso=nested_payload_iso_path) log.debug(f'Executing command: {cmd}') c = pexpect.spawn(cmd, logfile=stl, timeout=60) ################################################# # Logging into VyOS system ################################################# - if args.sbtest: + if sb_custom_ca: log.info('Disable UEFI Secure Boot for initial installation') toggleUEFISecureBoot(c) BOOTLOADERchooseSerialConsole(c, live=(not args.cloud_init), log=log) loginVM(c, log) + if args.secure_boot_test and not sb_custom_ca: + log.info('Verify live system booted with UEFI Secure Boot enabled') + c.sendline('show secure-boot') + c.expect('SecureBoot enabled') + c.expect(op_mode_prompt) + ################################################# # Cloud-Init comes with a pre-assembled ISO - just boot and test it ################################################# @@ -1122,7 +1146,7 @@ try: c.expect(op_mode_prompt) - if args.sbtest: + if sb_custom_ca: c.sendline('install mok') c.expect('input password:.*') c.sendline(mok_password) @@ -1136,7 +1160,7 @@ try: ################################################# # SHIM Mok Manager ################################################# - if args.sbtest: + if sb_custom_ca: log.info('Install Secure Boot Machine Owner Key') MOK_SLEEP = 0.5 c.expect('BdsDxe: starting Boot00.*') @@ -1174,7 +1198,7 @@ try: ################################################# # Re-Enable Secure Boot ################################################# - if args.sbtest: + if sb_custom_ca: log.info('Enable UEFI Secure Boot for initial installation') toggleUEFISecureBoot(c) @@ -1804,10 +1828,19 @@ try: c.sendline(f'sudo umount {NESTED_HTTP_MOUNT_POINT}') c.expect(op_mode_prompt) log.info('Nested installer ISO testcase complete') - elif args.sbtest: + elif args.secure_boot_test: c.sendline('show secure-boot') c.expect('SecureBoot enabled') c.expect(op_mode_prompt) + + c.sendline('show secure-boot detail') + if sb_custom_ca: + c.expect('Issuer: ') + else: + log.info('Verify Linux Kernel is signed by the VyOS Secure Boot CA') + c.expect(re.escape(f'Issuer: {SB_VYOS_ISSUER}')) + c.expect(re.escape(f'Subject: {SB_VYOS_SUBJECT}')) + c.expect(op_mode_prompt) else: log.info('No testcase selected!') @@ -1858,7 +1891,7 @@ if not args.keep: os.remove(args.disk) if diskname_raid: os.remove(diskname_raid) - if args.sbtest: + if args.secure_boot_test: os.remove(OVMF_VARS_TMP) except Exception: log.error('Exception while removing diskimage!') -- cgit v1.2.3