Skip to content

Commit

Permalink
tests/uefi_sb: Add Windows key upgrade tests
Browse files Browse the repository at this point in the history
Signed-off-by: Tu Dinh <ngoc-tu.dinh@vates.tech>
  • Loading branch information
dinhngtu committed Feb 21, 2025
1 parent 2c56b12 commit 039235e
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "contrib/secureboot_objects"]
path = contrib/secureboot_objects
url = https://github.com/microsoft/secureboot_objects.git
1 change: 1 addition & 0 deletions contrib/secureboot_objects
Submodule secureboot_objects added at 058c7e
31 changes: 29 additions & 2 deletions lib/efi.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ def getfile(self, suffix=None, prefix=None):
_tempdir = _EfiGlobalTempdir()


class _SecureBootCertList:
_prefix = Path(__file__).parent / '../contrib/secureboot_objects/PreSignedObjects'

def kek_ms_2011(self):
return str(self._prefix / "KEK/Certificates/MicCorKEKCA2011_2011-06-24.der")

def kek_ms_2023(self):
return str(self._prefix / "KEK/Certificates/microsoft corporation kek 2k ca 2023.der")

def db_win_2011(self):
return str(self._prefix / "DB/Certificates/MicWinProPCA2011_2011-10-19.der")

def db_uefi_2011(self):
return str(self._prefix / "DB/Certificates/MicCorUEFCA2011_2011-06-27.der")

def db_win_2023(self):
return str(self._prefix / "DB/Certificates/windows uefi ca 2023.der")

def db_uefi_2023(self):
return str(self._prefix / "DB/Certificates/microsoft uefi ca 2023.der")

def db_oprom_2023(self):
return str(self._prefix / "DB/Certificates/microsoft option rom uefi ca 2023.der")


ms_certs = _SecureBootCertList()


class GUID(UUID):
def as_bytes(self):
return self.bytes_le
Expand Down Expand Up @@ -371,8 +399,7 @@ def __init__(
owner_cert: Optional[Certificate] = None,
other_certs: Iterable[Union[Certificate, str]] = None):
assert name in SECURE_BOOT_VARIABLES
# No point having an owner cert without a matching private key
assert owner_cert is None or owner_cert.key is not None
assert owner_cert is None or owner_cert.key is not None, "owner cert must have private key"
self.name = name
self.guid = get_secure_boot_guid(self.name)
self._owner_cert = owner_cert
Expand Down
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[pytest]
addopts = -ra --maxfail=1
addopts = -ra --maxfail=1 --ignore=contrib/
markers =
# *** Markers that change test behaviour ***
default_vm: mark a test with a default VM in case no --vm parameter was given.
Expand Down
94 changes: 94 additions & 0 deletions tests/uefi_sb/test_varstored_sb.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import logging
import pytest

from lib.efi import EFIAuth, ms_certs
from lib.vm import VM

from .utils import _test_key_exchanges, boot_and_check_no_sb_errors, boot_and_check_sb_failed, \
boot_and_check_sb_succeeded, generate_keys, revert_vm_state, sign_efi_bins

Expand Down Expand Up @@ -153,3 +156,94 @@ def test_key_exchanges(self, uefi_vm):
vm.set_uefi_setup_mode()

_test_key_exchanges(vm)

@pytest.mark.small_vm
@pytest.mark.usefixtures("host_at_least_8_3")
@pytest.mark.usefixtures("windows_vm")
class TestGuestWindowsUEFIKeyUpgrade:
@pytest.fixture(autouse=True)
def setup_and_cleanup(self, uefi_vm_and_snapshot):
vm, snapshot = uefi_vm_and_snapshot
yield
revert_vm_state(vm, snapshot)

def install_old_certs(self, vm: VM):
"""Populate a key set that looks like the old defaults."""

PK = EFIAuth.self_signed("PK")
KEK = EFIAuth.self_signed("KEK", other_certs=[ms_certs.kek_ms_2011()])
db = EFIAuth("db", other_certs=[ms_certs.db_uefi_2011(), ms_certs.db_win_2011()])
# Some test VMs don't like an empty dbx when their own dbx is empty, so just put whatever in there
dbx = EFIAuth.self_signed("dbx")

PK.sign_auth(PK)
PK.sign_auth(KEK)
KEK.sign_auth(db)
KEK.sign_auth(dbx)

vm.install_uefi_certs([PK, KEK, db, dbx])
return [PK, KEK, db, dbx]

def install_new_certs(self, vm: VM, signer: EFIAuth):
"""Populate a key set that looks like the new defaults with 2023 MS keys."""

newPK = EFIAuth.self_signed("PK")
newKEK = EFIAuth("KEK", other_certs=[ms_certs.kek_ms_2011(), ms_certs.kek_ms_2023()])
newdb = EFIAuth(
"db",
other_certs=[
ms_certs.db_win_2011(),
ms_certs.db_win_2023(),
ms_certs.db_uefi_2011(),
ms_certs.db_uefi_2023(),
ms_certs.db_oprom_2023(),
],
)
newdbx = EFIAuth("dbx")

newPK.sign_auth(newPK)
# Technically, there's no need to sign the other databases since we're setting them from Dom0.
# If signing with the old PK works, there'd be no need to test signing with the new PK.
# We use an invalid signer to test scenarios where the user mixes and matches default and custom keys.
signer.sign_auth(newKEK)
signer.sign_auth(newdb)
signer.sign_auth(newdbx)

vm.install_uefi_certs([newPK, newKEK, newdb, newdbx])

def test_key_upgrade(self, uefi_vm: VM):
vm = uefi_vm
vm.param_set("platform", True, key="secureboot")
assert not vm.get_vtpm_uuid()
vm.create_vtpm()

PK, _, _, _ = self.install_old_certs(vm)
boot_and_check_sb_succeeded(vm)

vm.shutdown(verify=True)

self.install_new_certs(vm, PK)
boot_and_check_sb_succeeded(vm)

def test_key_upgrade_bitlocker(self, uefi_vm: VM):
vm = uefi_vm
vm.param_set("platform", True, key="secureboot")
assert not vm.get_vtpm_uuid()
vm.create_vtpm()

PK, _, _, _ = self.install_old_certs(vm)
boot_and_check_sb_succeeded(vm)

vm.execute_powershell_script("Add-WindowsFeature BitLocker,EnhancedStorage")
vm.reboot(verify=True)

vm.execute_powershell_script(
"Enable-BitLocker $Env:SystemDrive -TpmProtector -UsedSpaceOnly; Suspend-BitLocker $Env:SystemDrive"
)
vm.shutdown(verify=True)

self.install_new_certs(vm, PK)
boot_and_check_sb_succeeded(vm)
# After Enable-BitLocker, Windows would boot into encryption test.
# If the test failed, Windows would cancel the encryption and give the status FullyDecrypted.
assert vm.execute_powershell_script("(Get-BitLockerVolume $Env:SystemDrive).VolumeStatus") != "FullyDecrypted"

0 comments on commit 039235e

Please sign in to comment.