From: Ana Bobillo <[email protected]> Add a Secure Boot test with two signed images whose first certificate has an invalid length: zero, which made efi_image_authenticate() loop forever, and one larger than the certificate table. Both images must be rejected.
Signed-off-by: Ana Bobillo <[email protected]> --- test/py/tests/test_efi_secboot/conftest.py | 31 ++++++++++++++++ test/py/tests/test_efi_secboot/test_signed.py | 36 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py index 0755497d46d..9858dd36f17 100644 --- a/test/py/tests/test_efi_secboot/conftest.py +++ b/test/py/tests/test_efi_secboot/conftest.py @@ -4,11 +4,36 @@ """Fixture for UEFI secure boot test.""" +import struct from subprocess import call, check_call, CalledProcessError from tests import fs_helper import pytest from defs import * + +def set_cert_length(src, dst, length): + """Copy a signed image, setting the length of its first certificate. + + Args: + src: Path of the signed image. + dst: Path of the image to write. + length: dwLength to set, or None for one past the certificate table. + """ + with open(src, 'rb') as inf: + data = bytearray(inf.read()) + pe_off = struct.unpack_from('<I', data, 0x3c)[0] + opt_off = pe_off + 24 + magic = struct.unpack_from('<H', data, opt_off)[0] + # The data directories follow the PE32+ or the PE32 optional header + dirs_off = opt_off + (112 if magic == 0x20b else 96) + # The certificate table is data directory 4 + cert_off, cert_size = struct.unpack_from('<II', data, dirs_off + 4 * 8) + if length is None: + length = cert_size + 8 + struct.pack_into('<I', data, cert_off, length) + with open(dst, 'wb') as outf: + outf.write(data) + @pytest.fixture(scope='function') def efi_boot_env(request, ubman): """Set up a file system to be used in UEFI secure boot test. @@ -118,6 +143,12 @@ def efi_boot_env(request, ubman): # Create a corrupted signed image check_call('cd %s; sh %s/test/py/tests/test_efi_secboot/forge_image.sh helloworld.efi.signed helloworld_forged.efi.signed' % (mnt_point, ubman.config.source_dir), shell=True) + # Create signed images with an invalid certificate length + set_cert_length('%s/helloworld.efi.signed' % mnt_point, + '%s/helloworld_certlen0.efi.signed' % mnt_point, 0) + set_cert_length('%s/helloworld.efi.signed' % mnt_point, + '%s/helloworld_certlen_long.efi.signed' % mnt_point, + None) # Digest image check_call('cd %s; %shash-to-efi-sig-list helloworld.efi db_hello.hash; %ssign-efi-sig-list -t "2020-04-07" -c KEK.crt -k KEK.key db db_hello.hash db_hello.auth' % (mnt_point, EFITOOLS_PATH, EFITOOLS_PATH), diff --git a/test/py/tests/test_efi_secboot/test_signed.py b/test/py/tests/test_efi_secboot/test_signed.py index 9e6d3fdf8d8..d14f9b795d5 100644 --- a/test/py/tests/test_efi_secboot/test_signed.py +++ b/test/py/tests/test_efi_secboot/test_signed.py @@ -378,3 +378,39 @@ class TestEfiSignedImage(object): 'printenv -e -n PK']) assert 'Failed to set EFI variable' not in ''.join(output) assert '\"PK\" not defined' in ''.join(output) + + def test_efi_signed_image_auth9(self, ubman, efi_boot_env): + """ + Test Case 9 - Secure boot is in force, + the length of the certificate in the signed image + is invalid. + Must be rejected. + """ + ubman.restart_uboot() + disk_img = efi_boot_env + with ubman.log.section('Test Case 9a'): + # Test Case 9a, certificate length of zero + output = ubman.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = ubman.run_command_list([ + 'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld_certlen0.efi.signed -s ""', + 'efidebug boot order 1', + 'efidebug test bootmgr']) + assert '\'HELLO1\' failed' in ''.join(output) + assert 'efi_bootmgr_load() returned: 26' in ''.join(output) + + with ubman.log.section('Test Case 9b'): + # Test Case 9b, certificate longer than the certificate table + output = ubman.run_command_list([ + 'efidebug boot add -b 2 HELLO2 host 0:1 /helloworld_certlen_long.efi.signed -s ""', + 'efidebug boot order 2', + 'efidebug test bootmgr']) + assert '\'HELLO2\' failed' in ''.join(output) + assert 'efi_bootmgr_load() returned: 26' in ''.join(output)
