mirror of
https://git.proxmox.com/git/pve-edk2-firmware
synced 2025-10-04 13:51:43 +00:00
debian: sync tests with packaging upstream
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
5b38a120b6
commit
d7274593bf
28
debian/python/UEFI/Filesystems.py
vendored
28
debian/python/UEFI/Filesystems.py
vendored
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2019-2021 Canonical Ltd.
|
# Copyright 2019-2022 Canonical Ltd.
|
||||||
# Authors:
|
# Authors:
|
||||||
# - dann frazier <dann.frazier@canonical.com>
|
# - dann frazier <dann.frazier@canonical.com>
|
||||||
#
|
#
|
||||||
@ -87,35 +87,15 @@ class EfiBootableIsoImage:
|
|||||||
|
|
||||||
|
|
||||||
class GrubShellBootableIsoImage(EfiBootableIsoImage):
|
class GrubShellBootableIsoImage(EfiBootableIsoImage):
|
||||||
def __init__(self, efi_arch, use_signed):
|
def __init__(self, efi_arch, shim_path, grub_path):
|
||||||
EfiArchToGrubArch = {
|
|
||||||
'X64': "x86_64",
|
|
||||||
'AA64': "arm64",
|
|
||||||
}
|
|
||||||
efi_img = FatFsImage(64)
|
efi_img = FatFsImage(64)
|
||||||
efi_img.makedirs(os.path.join('EFI', 'BOOT'))
|
efi_img.makedirs(os.path.join('EFI', 'BOOT'))
|
||||||
removable_media_path = os.path.join(
|
removable_media_path = os.path.join(
|
||||||
'EFI', 'BOOT', 'BOOT%s.EFI' % (efi_arch.upper())
|
'EFI', 'BOOT', 'BOOT%s.EFI' % (efi_arch.upper())
|
||||||
)
|
)
|
||||||
efi_ext = 'efi'
|
|
||||||
grub_subdir = "%s-efi" % EfiArchToGrubArch[efi_arch.upper()]
|
|
||||||
if use_signed:
|
|
||||||
efi_ext = "%s.signed" % (efi_ext)
|
|
||||||
grub_subdir = "%s-signed" % (grub_subdir)
|
|
||||||
|
|
||||||
shim_src = os.path.join(
|
|
||||||
os.path.sep, 'usr', 'lib', 'shim',
|
|
||||||
'shim%s.%s' % (efi_arch.lower(), efi_ext)
|
|
||||||
)
|
|
||||||
grub_src = os.path.join(
|
|
||||||
os.path.sep, 'usr', 'lib', 'grub',
|
|
||||||
'%s' % (grub_subdir),
|
|
||||||
"" if use_signed else "monolithic",
|
|
||||||
'grub%s.%s' % (efi_arch.lower(), efi_ext)
|
|
||||||
)
|
|
||||||
grub_dest = os.path.join(
|
grub_dest = os.path.join(
|
||||||
'EFI', 'BOOT', 'GRUB%s.EFI' % (efi_arch.upper())
|
'EFI', 'BOOT', 'GRUB%s.EFI' % (efi_arch.upper())
|
||||||
)
|
)
|
||||||
efi_img.insert_file(shim_src, removable_media_path)
|
efi_img.insert_file(shim_path, removable_media_path)
|
||||||
efi_img.insert_file(grub_src, grub_dest)
|
efi_img.insert_file(grub_path, grub_dest)
|
||||||
super().__init__(efi_img)
|
super().__init__(efi_img)
|
||||||
|
3
debian/python/UEFI/Qemu.py
vendored
3
debian/python/UEFI/Qemu.py
vendored
@ -43,11 +43,10 @@ class QemuEfiFlashSize(enum.Enum):
|
|||||||
|
|
||||||
|
|
||||||
class QemuCommand:
|
class QemuCommand:
|
||||||
# Based on the args used by ovmf-vars-generator
|
|
||||||
Qemu_Common_Params = [
|
Qemu_Common_Params = [
|
||||||
'-no-user-config', '-nodefaults',
|
'-no-user-config', '-nodefaults',
|
||||||
'-m', '256',
|
'-m', '256',
|
||||||
'-smp', '2,sockets=2,cores=1,threads=1',
|
'-smp', '1,sockets=1,cores=1,threads=1',
|
||||||
'-display', 'none',
|
'-display', 'none',
|
||||||
'-serial', 'stdio',
|
'-serial', 'stdio',
|
||||||
]
|
]
|
||||||
|
52
debian/python/UEFI/SignedBinary.py
vendored
Normal file
52
debian/python/UEFI/SignedBinary.py
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Canonical Ltd.
|
||||||
|
# Authors:
|
||||||
|
# - dann frazier <dann.frazier@canonical.com>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License version 3, as published
|
||||||
|
# by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
|
||||||
|
# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
|
class SignedBinary:
|
||||||
|
def __init__(self, binary_path, key_path, cert_path, password=None):
|
||||||
|
openssl_password_args = []
|
||||||
|
if password:
|
||||||
|
openssl_password_args = [
|
||||||
|
"-passin", f"pass:{password}"
|
||||||
|
]
|
||||||
|
with tempfile.NamedTemporaryFile() as keytmp:
|
||||||
|
subprocess.check_call(
|
||||||
|
[
|
||||||
|
"openssl", "rsa",
|
||||||
|
] + openssl_password_args + [
|
||||||
|
"-in", f"{key_path}",
|
||||||
|
"-out", f"{keytmp.name}",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||||
|
self.path = f.name
|
||||||
|
|
||||||
|
subprocess.check_call(
|
||||||
|
[
|
||||||
|
"sbsign", "--key", f"{keytmp.name}",
|
||||||
|
"--cert", f"{cert_path}",
|
||||||
|
binary_path, "--output", f"{self.path}"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
os.unlink(self.path)
|
2
debian/tests/control
vendored
2
debian/tests/control
vendored
@ -5,6 +5,7 @@ Depends:
|
|||||||
grub-efi-amd64-signed [amd64],
|
grub-efi-amd64-signed [amd64],
|
||||||
grub-efi-arm64-signed [arm64],
|
grub-efi-arm64-signed [arm64],
|
||||||
mtools [amd64 arm64],
|
mtools [amd64 arm64],
|
||||||
|
openssl [amd64 arm64],
|
||||||
ovmf,
|
ovmf,
|
||||||
ovmf-ia32,
|
ovmf-ia32,
|
||||||
python3-pexpect,
|
python3-pexpect,
|
||||||
@ -12,5 +13,6 @@ Depends:
|
|||||||
qemu-efi-arm,
|
qemu-efi-arm,
|
||||||
qemu-system-arm,
|
qemu-system-arm,
|
||||||
qemu-system-x86,
|
qemu-system-x86,
|
||||||
|
sbsigntool [amd64 arm64],
|
||||||
shim-signed [amd64 arm64],
|
shim-signed [amd64 arm64],
|
||||||
xorriso [amd64 arm64],
|
xorriso [amd64 arm64],
|
||||||
|
133
debian/tests/shell.py
vendored
133
debian/tests/shell.py
vendored
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# Copyright 2019-2021 Canonical Ltd.
|
# Copyright 2019-2022 Canonical Ltd.
|
||||||
# Authors:
|
# Authors:
|
||||||
# - dann frazier <dann.frazier@canonical.com>
|
# - dann frazier <dann.frazier@canonical.com>
|
||||||
#
|
#
|
||||||
@ -18,12 +18,15 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import enum
|
import enum
|
||||||
|
import os
|
||||||
import pexpect
|
import pexpect
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from UEFI.Filesystems import GrubShellBootableIsoImage
|
from UEFI.Filesystems import GrubShellBootableIsoImage
|
||||||
|
from UEFI.SignedBinary import SignedBinary
|
||||||
from UEFI.Qemu import QemuEfiMachine, QemuEfiVariant, QemuEfiFlashSize
|
from UEFI.Qemu import QemuEfiMachine, QemuEfiVariant, QemuEfiFlashSize
|
||||||
from UEFI import Qemu
|
from UEFI import Qemu
|
||||||
|
|
||||||
@ -31,15 +34,56 @@ DPKG_ARCH = subprocess.check_output(
|
|||||||
['dpkg', '--print-architecture']
|
['dpkg', '--print-architecture']
|
||||||
).decode().rstrip()
|
).decode().rstrip()
|
||||||
|
|
||||||
|
EfiArchToGrubArch = {
|
||||||
|
'X64': "x86_64",
|
||||||
|
'AA64': "arm64",
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_TIMEOUT = 120
|
||||||
|
|
||||||
|
|
||||||
|
def get_local_grub_path(efi_arch, signed=False):
|
||||||
|
grub_subdir = "%s-efi" % EfiArchToGrubArch[efi_arch.upper()]
|
||||||
|
ext = "efi"
|
||||||
|
if signed:
|
||||||
|
grub_subdir = f"{grub_subdir}-signed"
|
||||||
|
ext = f"{ext}.signed"
|
||||||
|
|
||||||
|
grub_path = os.path.join(
|
||||||
|
os.path.sep, 'usr', 'lib', 'grub',
|
||||||
|
'%s' % (grub_subdir),
|
||||||
|
"" if signed else "monolithic",
|
||||||
|
'grub%s.%s' % (efi_arch.lower(), ext)
|
||||||
|
)
|
||||||
|
return grub_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_local_shim_path(efi_arch, signed=False):
|
||||||
|
ext = 'efi'
|
||||||
|
if signed:
|
||||||
|
ext = f"{ext}.signed"
|
||||||
|
shim_path = os.path.join(
|
||||||
|
os.path.sep, 'usr', 'lib', 'shim',
|
||||||
|
'shim%s.%s' % (efi_arch.lower(), ext)
|
||||||
|
)
|
||||||
|
return shim_path
|
||||||
|
|
||||||
|
|
||||||
class BootToShellTest(unittest.TestCase):
|
class BootToShellTest(unittest.TestCase):
|
||||||
debug = True
|
debug = True
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.startTime = time.time()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
t = time.time() - self.startTime
|
||||||
|
sys.stdout.write("%s runtime: %.3fs\n" % (self.id(), t))
|
||||||
|
|
||||||
def run_cmd_check_shell(self, cmd):
|
def run_cmd_check_shell(self, cmd):
|
||||||
child = pexpect.spawn(' '.join(cmd))
|
child = pexpect.spawn(' '.join(cmd), encoding='UTF-8')
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
child.logfile = sys.stdout.buffer
|
child.logfile = sys.stdout
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
i = child.expect(
|
i = child.expect(
|
||||||
@ -47,7 +91,7 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
'Press .* or any other key to continue',
|
'Press .* or any other key to continue',
|
||||||
'Shell> '
|
'Shell> '
|
||||||
],
|
],
|
||||||
timeout=60,
|
timeout=TEST_TIMEOUT,
|
||||||
)
|
)
|
||||||
if i == 0:
|
if i == 0:
|
||||||
child.sendline('\x1b')
|
child.sendline('\x1b')
|
||||||
@ -56,7 +100,9 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
child.sendline('reset -s\r')
|
child.sendline('reset -s\r')
|
||||||
continue
|
continue
|
||||||
except pexpect.EOF:
|
except pexpect.EOF:
|
||||||
return
|
child.close()
|
||||||
|
if child.exitstatus != 0:
|
||||||
|
self.fail("ERROR: exit code %d\n" % (child.exitstatus))
|
||||||
except pexpect.TIMEOUT as err:
|
except pexpect.TIMEOUT as err:
|
||||||
self.fail("%s\n" % (err))
|
self.fail("%s\n" % (err))
|
||||||
|
|
||||||
@ -65,10 +111,10 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
PRE_EXEC = 1
|
PRE_EXEC = 1
|
||||||
POST_EXEC = 2
|
POST_EXEC = 2
|
||||||
|
|
||||||
child = pexpect.spawn(' '.join(cmd))
|
child = pexpect.spawn(' '.join(cmd), encoding='UTF-8')
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
child.logfile = sys.stdout.buffer
|
child.logfile = sys.stdout
|
||||||
try:
|
try:
|
||||||
state = State.PRE_EXEC
|
state = State.PRE_EXEC
|
||||||
while True:
|
while True:
|
||||||
@ -80,7 +126,7 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
'grub> ',
|
'grub> ',
|
||||||
'Command Error Status: Access Denied',
|
'Command Error Status: Access Denied',
|
||||||
],
|
],
|
||||||
timeout=60,
|
timeout=TEST_TIMEOUT,
|
||||||
)
|
)
|
||||||
if i == 0:
|
if i == 0:
|
||||||
child.sendline('\x1b')
|
child.sendline('\x1b')
|
||||||
@ -102,10 +148,12 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
if i == 4:
|
if i == 4:
|
||||||
verified = False
|
verified = False
|
||||||
continue
|
continue
|
||||||
|
except pexpect.EOF:
|
||||||
|
child.close()
|
||||||
|
if child.exitstatus != 0:
|
||||||
|
self.fail("ERROR: exit code %d\n" % (child.exitstatus))
|
||||||
except pexpect.TIMEOUT as err:
|
except pexpect.TIMEOUT as err:
|
||||||
self.fail("%s\n" % (err))
|
self.fail("%s\n" % (err))
|
||||||
except pexpect.EOF:
|
|
||||||
pass
|
|
||||||
self.assertEqual(should_verify, verified)
|
self.assertEqual(should_verify, verified)
|
||||||
|
|
||||||
def test_aavmf(self):
|
def test_aavmf(self):
|
||||||
@ -113,12 +161,20 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
self.run_cmd_check_shell(q.command)
|
self.run_cmd_check_shell(q.command)
|
||||||
|
|
||||||
@unittest.skipUnless(DPKG_ARCH == 'arm64', "Requires grub-efi-arm64")
|
@unittest.skipUnless(DPKG_ARCH == 'arm64', "Requires grub-efi-arm64")
|
||||||
|
@unittest.skipUnless(
|
||||||
|
subprocess.run(
|
||||||
|
['dpkg-vendor', '--derives-from', 'Ubuntu']
|
||||||
|
).returncode == 0,
|
||||||
|
"Debian does not provide a signed shim for arm64, see #992073"
|
||||||
|
)
|
||||||
def test_aavmf_ms_secure_boot_signed(self):
|
def test_aavmf_ms_secure_boot_signed(self):
|
||||||
q = Qemu.QemuCommand(
|
q = Qemu.QemuCommand(
|
||||||
QemuEfiMachine.AAVMF,
|
QemuEfiMachine.AAVMF,
|
||||||
variant=QemuEfiVariant.MS,
|
variant=QemuEfiVariant.MS,
|
||||||
)
|
)
|
||||||
iso = GrubShellBootableIsoImage('AA64', use_signed=True)
|
grub = get_local_grub_path('AA64', signed=True)
|
||||||
|
shim = get_local_shim_path('AA64', signed=True)
|
||||||
|
iso = GrubShellBootableIsoImage('AA64', shim, grub)
|
||||||
q.add_disk(iso.path)
|
q.add_disk(iso.path)
|
||||||
self.run_cmd_check_secure_boot(q.command, 'aa64', True)
|
self.run_cmd_check_secure_boot(q.command, 'aa64', True)
|
||||||
|
|
||||||
@ -128,7 +184,9 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
QemuEfiMachine.AAVMF,
|
QemuEfiMachine.AAVMF,
|
||||||
variant=QemuEfiVariant.MS,
|
variant=QemuEfiVariant.MS,
|
||||||
)
|
)
|
||||||
iso = GrubShellBootableIsoImage('AA64', use_signed=False)
|
grub = get_local_grub_path('AA64', signed=False)
|
||||||
|
shim = get_local_shim_path('AA64', signed=False)
|
||||||
|
iso = GrubShellBootableIsoImage('AA64', shim, grub)
|
||||||
q.add_disk(iso.path)
|
q.add_disk(iso.path)
|
||||||
self.run_cmd_check_secure_boot(q.command, 'aa64', False)
|
self.run_cmd_check_secure_boot(q.command, 'aa64', False)
|
||||||
|
|
||||||
@ -178,7 +236,9 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
variant=QemuEfiVariant.MS,
|
variant=QemuEfiVariant.MS,
|
||||||
flash_size=QemuEfiFlashSize.SIZE_2MB,
|
flash_size=QemuEfiFlashSize.SIZE_2MB,
|
||||||
)
|
)
|
||||||
iso = GrubShellBootableIsoImage('X64', use_signed=True)
|
grub = get_local_grub_path('X64', signed=True)
|
||||||
|
shim = get_local_shim_path('X64', signed=True)
|
||||||
|
iso = GrubShellBootableIsoImage('X64', shim, grub)
|
||||||
q.add_disk(iso.path)
|
q.add_disk(iso.path)
|
||||||
self.run_cmd_check_secure_boot(q.command, 'x64', True)
|
self.run_cmd_check_secure_boot(q.command, 'x64', True)
|
||||||
|
|
||||||
@ -189,7 +249,9 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
variant=QemuEfiVariant.MS,
|
variant=QemuEfiVariant.MS,
|
||||||
flash_size=QemuEfiFlashSize.SIZE_2MB,
|
flash_size=QemuEfiFlashSize.SIZE_2MB,
|
||||||
)
|
)
|
||||||
iso = GrubShellBootableIsoImage('X64', use_signed=False)
|
grub = get_local_grub_path('X64', signed=False)
|
||||||
|
shim = get_local_shim_path('X64', signed=False)
|
||||||
|
iso = GrubShellBootableIsoImage('X64', shim, grub)
|
||||||
q.add_disk(iso.path)
|
q.add_disk(iso.path)
|
||||||
self.run_cmd_check_secure_boot(q.command, 'x64', False)
|
self.run_cmd_check_secure_boot(q.command, 'x64', False)
|
||||||
|
|
||||||
@ -230,7 +292,9 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
variant=QemuEfiVariant.MS,
|
variant=QemuEfiVariant.MS,
|
||||||
flash_size=QemuEfiFlashSize.SIZE_4MB,
|
flash_size=QemuEfiFlashSize.SIZE_4MB,
|
||||||
)
|
)
|
||||||
iso = GrubShellBootableIsoImage('X64', use_signed=True)
|
grub = get_local_grub_path('X64', signed=True)
|
||||||
|
shim = get_local_shim_path('X64', signed=True)
|
||||||
|
iso = GrubShellBootableIsoImage('X64', shim, grub)
|
||||||
q.add_disk(iso.path)
|
q.add_disk(iso.path)
|
||||||
self.run_cmd_check_secure_boot(q.command, 'x64', True)
|
self.run_cmd_check_secure_boot(q.command, 'x64', True)
|
||||||
|
|
||||||
@ -241,7 +305,44 @@ class BootToShellTest(unittest.TestCase):
|
|||||||
variant=QemuEfiVariant.MS,
|
variant=QemuEfiVariant.MS,
|
||||||
flash_size=QemuEfiFlashSize.SIZE_4MB,
|
flash_size=QemuEfiFlashSize.SIZE_4MB,
|
||||||
)
|
)
|
||||||
iso = GrubShellBootableIsoImage('X64', use_signed=False)
|
grub = get_local_grub_path('X64', signed=False)
|
||||||
|
shim = get_local_shim_path('X64', signed=False)
|
||||||
|
iso = GrubShellBootableIsoImage('X64', shim, grub)
|
||||||
|
q.add_disk(iso.path)
|
||||||
|
self.run_cmd_check_secure_boot(q.command, 'x64', False)
|
||||||
|
|
||||||
|
@unittest.skipUnless(DPKG_ARCH == 'amd64', "amd64-only")
|
||||||
|
def test_ovmf_snakeoil_secure_boot_signed(self):
|
||||||
|
q = Qemu.QemuCommand(
|
||||||
|
QemuEfiMachine.OVMF_Q35,
|
||||||
|
variant=QemuEfiVariant.SNAKEOIL,
|
||||||
|
)
|
||||||
|
shim = SignedBinary(
|
||||||
|
get_local_shim_path('X64', signed=False),
|
||||||
|
"/usr/share/ovmf/PkKek-1-snakeoil.key",
|
||||||
|
"/usr/share/ovmf/PkKek-1-snakeoil.pem",
|
||||||
|
"snakeoil",
|
||||||
|
)
|
||||||
|
grub = SignedBinary(
|
||||||
|
get_local_grub_path('X64', signed=False),
|
||||||
|
"/usr/share/ovmf/PkKek-1-snakeoil.key",
|
||||||
|
"/usr/share/ovmf/PkKek-1-snakeoil.pem",
|
||||||
|
"snakeoil",
|
||||||
|
)
|
||||||
|
iso = GrubShellBootableIsoImage('X64', shim.path, grub.path)
|
||||||
|
q.add_disk(iso.path)
|
||||||
|
self.run_cmd_check_secure_boot(q.command, 'x64', True)
|
||||||
|
|
||||||
|
@unittest.skipUnless(DPKG_ARCH == 'amd64', "amd64-only")
|
||||||
|
def test_ovmf_snakeoil_secure_boot_unsigned(self):
|
||||||
|
q = Qemu.QemuCommand(
|
||||||
|
QemuEfiMachine.OVMF_Q35,
|
||||||
|
variant=QemuEfiVariant.SNAKEOIL,
|
||||||
|
flash_size=QemuEfiFlashSize.DEFAULT,
|
||||||
|
)
|
||||||
|
grub = get_local_grub_path('X64', signed=False)
|
||||||
|
shim = get_local_shim_path('X64', signed=False)
|
||||||
|
iso = GrubShellBootableIsoImage('X64', shim, grub)
|
||||||
q.add_disk(iso.path)
|
q.add_disk(iso.path)
|
||||||
self.run_cmd_check_secure_boot(q.command, 'x64', False)
|
self.run_cmd_check_secure_boot(q.command, 'x64', False)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user