test_ukify: apply "ruff format"

Also drops unnecessary noqa attribute for importing pefile.
This commit is contained in:
Yu Watanabe
2026-05-18 02:44:46 +09:00
parent d86df93f96
commit 58aa8824f3
+319 -226
View File
@@ -33,8 +33,7 @@ except ImportError as e:
sys.exit(77)
try:
# pyflakes: noqa
import pefile # noqa
import pefile
except ImportError as e:
print(str(e), file=sys.stderr)
sys.exit(77)
@@ -59,42 +58,51 @@ except ValueError:
slow_tests = True
arg_tools = ['--tools', build_root] if build_root else []
if build_root and (
p := pathlib.Path(f"{build_root}/linux{ukify.guess_efi_arch()}.efi.stub")
).exists():
if (
build_root
and (p := pathlib.Path(f'{build_root}/linux{ukify.guess_efi_arch()}.efi.stub')).exists()
): # fmt: skip
arg_tools += ['--stub', p]
def systemd_measure():
opts = ukify.create_parser().parse_args(arg_tools)
return ukify.find_tool('systemd-measure', opts=opts)
def test_guess_efi_arch():
arch = ukify.guess_efi_arch()
assert arch in ukify.EFI_ARCHES
def test_shell_join():
assert ukify.shell_join(['a', 'b', ' ']) == "a b ' '"
def test_round_up():
assert ukify.round_up(0) == 0
assert ukify.round_up(4095) == 4096
assert ukify.round_up(4096) == 4096
assert ukify.round_up(4097) == 8192
def test_namespace_creation():
ns = ukify.create_parser().parse_args(())
assert ns.linux is None
assert ns.initrd is None
def test_config_example():
ex = ukify.config_example()
assert '[UKI]' in ex
assert 'Splash = BMP' in ex
def test_apply_config(tmp_path):
config = tmp_path / 'config1.conf'
config.write_text(textwrap.dedent(
f'''
config.write_text(
textwrap.dedent(
f'''
[UKI]
Linux = LINUX
Initrd = initrd1 initrd2
@@ -117,7 +125,9 @@ def test_apply_config(tmp_path):
PCRPrivateKey = some/path7
PCRPublicKey = some/path8
Phases = {':'.join(ukify.KNOWN_PHASES)}
'''))
'''
)
)
ns = ukify.create_parser().parse_args(['build'])
ns.linux = None
@@ -125,9 +135,11 @@ def test_apply_config(tmp_path):
ukify.apply_config(ns, config)
assert ns.linux == pathlib.Path('LINUX')
assert ns.initrd == [pathlib.Path('initrd1'),
pathlib.Path('initrd2'),
pathlib.Path('initrd3')]
assert ns.initrd == [
pathlib.Path('initrd1'),
pathlib.Path('initrd2'),
pathlib.Path('initrd3'),
]
assert ns.cmdline == '1 2 3 4 5\n6 7 8'
assert ns.os_release == '@some/path1'
assert ns.devicetree == pathlib.Path('some/path2')
@@ -148,9 +160,11 @@ def test_apply_config(tmp_path):
ukify.finalize_options(ns)
assert ns.linux == pathlib.Path('LINUX')
assert ns.initrd == [pathlib.Path('initrd1'),
pathlib.Path('initrd2'),
pathlib.Path('initrd3')]
assert ns.initrd == [
pathlib.Path('initrd1'),
pathlib.Path('initrd2'),
pathlib.Path('initrd3'),
]
assert ns.cmdline == '1 2 3 4 5 6 7 8'
assert ns.os_release == pathlib.Path('some/path1')
assert ns.devicetree == pathlib.Path('some/path2')
@@ -168,6 +182,7 @@ def test_apply_config(tmp_path):
assert ns.pcr_public_keys == ['some/path8']
assert ns.phase_path_groups == [['enter-initrd:leave-initrd:sysinit:ready:shutdown:final']]
def test_parse_args_minimal():
with pytest.raises(ValueError):
ukify.parse_args([])
@@ -175,32 +190,39 @@ def test_parse_args_minimal():
opts = ukify.parse_args('arg1 arg2'.split())
assert opts.linux == pathlib.Path('arg1')
assert opts.initrd == [pathlib.Path('arg2')]
assert opts.os_release in (pathlib.Path('/etc/os-release'),
pathlib.Path('/usr/lib/os-release'))
assert opts.os_release in (
pathlib.Path('/etc/os-release'),
pathlib.Path('/usr/lib/os-release'),
)
def test_parse_args_many_deprecated():
opts = ukify.parse_args(
['/ARG1', '///ARG2', '/ARG3 WITH SPACE',
'--cmdline=a b c',
'--os-release=K1=V1\nK2=V2',
'--devicetree=DDDDTTTT',
'--splash=splash',
'--pcrpkey=PATH',
'--uname=1.2.3',
'--stub=STUBPATH',
'--pcr-private-key=PKEY1',
'--pcr-public-key=PKEY2',
'--pcr-banks=SHA1,SHA256',
'--signing-engine=ENGINE',
'--secureboot-private-key=SBKEY',
'--secureboot-certificate=SBCERT',
'--sign-kernel',
'--no-sign-kernel',
'--tools=TOOLZ///',
'--output=OUTPUT',
'--measure',
'--no-measure',
])
[
'/ARG1',
'///ARG2',
'/ARG3 WITH SPACE',
'--cmdline=a b c',
'--os-release=K1=V1\nK2=V2',
'--devicetree=DDDDTTTT',
'--splash=splash',
'--pcrpkey=PATH',
'--uname=1.2.3',
'--stub=STUBPATH',
'--pcr-private-key=PKEY1',
'--pcr-public-key=PKEY2',
'--pcr-banks=SHA1,SHA256',
'--signing-engine=ENGINE',
'--secureboot-private-key=SBKEY',
'--secureboot-certificate=SBCERT',
'--sign-kernel',
'--no-sign-kernel',
'--tools=TOOLZ///',
'--output=OUTPUT',
'--measure',
'--no-measure',
]
)
assert opts.linux == pathlib.Path('/ARG1')
assert opts.initrd == [pathlib.Path('/ARG2'), pathlib.Path('/ARG3 WITH SPACE')]
assert opts.cmdline == 'a b c'
@@ -221,34 +243,37 @@ def test_parse_args_many_deprecated():
assert opts.output == pathlib.Path('OUTPUT')
assert opts.measure is False
def test_parse_args_many():
opts = ukify.parse_args(
['build',
'--linux=/ARG1',
'--initrd=///ARG2',
'--initrd=/ARG3 WITH SPACE',
'--cmdline=a b c',
'--os-release=K1=V1\nK2=V2',
'--devicetree=DDDDTTTT',
'--splash=splash',
'--pcrpkey=PATH',
'--uname=1.2.3',
'--stub=STUBPATH',
'--pcr-private-key=PKEY1',
'--pcr-public-key=PKEY2',
'--pcr-banks=SHA1,SHA256',
'--signing-engine=ENGINE',
'--secureboot-private-key=SBKEY',
'--secureboot-certificate=SBCERT',
'--sign-kernel',
'--no-sign-kernel',
'--tools=TOOLZ///',
'--output=OUTPUT',
'--measure',
'--no-measure',
'--policy-digest',
'--no-policy-digest',
])
[
'build',
'--linux=/ARG1',
'--initrd=///ARG2',
'--initrd=/ARG3 WITH SPACE',
'--cmdline=a b c',
'--os-release=K1=V1\nK2=V2',
'--devicetree=DDDDTTTT',
'--splash=splash',
'--pcrpkey=PATH',
'--uname=1.2.3',
'--stub=STUBPATH',
'--pcr-private-key=PKEY1',
'--pcr-public-key=PKEY2',
'--pcr-banks=SHA1,SHA256',
'--signing-engine=ENGINE',
'--secureboot-private-key=SBKEY',
'--secureboot-certificate=SBCERT',
'--sign-kernel',
'--no-sign-kernel',
'--tools=TOOLZ///',
'--output=OUTPUT',
'--measure',
'--no-measure',
'--policy-digest',
'--no-policy-digest',
]
)
assert opts.linux == pathlib.Path('/ARG1')
assert opts.initrd == [pathlib.Path('/ARG2'), pathlib.Path('/ARG3 WITH SPACE')]
assert opts.cmdline == 'a b c'
@@ -270,14 +295,17 @@ def test_parse_args_many():
assert opts.measure is False
assert opts.policy_digest is False
def test_parse_sections():
opts = ukify.parse_args(
['build',
'--linux=/ARG1',
'--initrd=/ARG2',
'--section=test:TESTTESTTEST',
'--section=test2:@FILE',
])
[
'build',
'--linux=/ARG1',
'--initrd=/ARG2',
'--section=test:TESTTESTTEST',
'--section=test2:@FILE',
]
)
assert opts.linux == pathlib.Path('/ARG1')
assert opts.initrd == [pathlib.Path('/ARG2')]
@@ -293,11 +321,13 @@ def test_parse_sections():
assert opts.sections[1].tmpfile is None
assert opts.sections[1].measure is False
def test_config_priority(tmp_path):
config = tmp_path / 'config1.conf'
# config: use pesign and give certdir + certname
config.write_text(textwrap.dedent(
f'''
config.write_text(
textwrap.dedent(
f'''
[UKI]
Linux = LINUX
Initrd = initrd1 initrd2
@@ -321,44 +351,50 @@ def test_config_priority(tmp_path):
PCRPrivateKey = some/path7
PCRPublicKey = some/path8
Phases = {':'.join(ukify.KNOWN_PHASES)}
'''))
'''
)
)
# args: use sbsign and give key + cert, should override pesign
opts = ukify.parse_args(
['build',
'--linux=/ARG1',
'--initrd=///ARG2',
'--initrd=/ARG3 WITH SPACE',
'--cmdline= a b c ',
'--os-release=K1=V1\nK2=V2',
'--devicetree=DDDDTTTT',
'--splash=splash',
'--pcrpkey=PATH',
'--uname=1.2.3',
'--stub=STUBPATH',
'--pcr-private-key=PKEY1',
'--pcr-public-key=PKEY2',
'--pcr-banks=SHA1,SHA256',
'--signing-engine=ENGINE',
'--signtool=sbsign',
'--secureboot-private-key=SBKEY',
'--secureboot-certificate=SBCERT',
'--sign-kernel',
'--no-sign-kernel',
'--tools=TOOLZ///',
'--output=OUTPUT',
'--measure',
])
[
'build',
'--linux=/ARG1',
'--initrd=///ARG2',
'--initrd=/ARG3 WITH SPACE',
'--cmdline= a b c ',
'--os-release=K1=V1\nK2=V2',
'--devicetree=DDDDTTTT',
'--splash=splash',
'--pcrpkey=PATH',
'--uname=1.2.3',
'--stub=STUBPATH',
'--pcr-private-key=PKEY1',
'--pcr-public-key=PKEY2',
'--pcr-banks=SHA1,SHA256',
'--signing-engine=ENGINE',
'--signtool=sbsign',
'--secureboot-private-key=SBKEY',
'--secureboot-certificate=SBCERT',
'--sign-kernel',
'--no-sign-kernel',
'--tools=TOOLZ///',
'--output=OUTPUT',
'--measure',
]
)
ukify.apply_config(opts, config)
ukify.finalize_options(opts)
assert opts.linux == pathlib.Path('/ARG1')
assert opts.initrd == [pathlib.Path('initrd1'),
pathlib.Path('initrd2'),
pathlib.Path('initrd3'),
pathlib.Path('/ARG2'),
pathlib.Path('/ARG3 WITH SPACE')]
assert opts.initrd == [
pathlib.Path('initrd1'),
pathlib.Path('initrd2'),
pathlib.Path('initrd3'),
pathlib.Path('/ARG2'),
pathlib.Path('/ARG3 WITH SPACE'),
]
assert opts.cmdline == 'a b c'
assert opts.os_release == 'K1=V1\nK2=V2'
assert opts.devicetree == pathlib.Path('DDDDTTTT')
@@ -370,16 +406,17 @@ def test_config_priority(tmp_path):
assert opts.pcr_public_keys == ['PKEY2', 'some/path8']
assert opts.pcr_banks == ['SHA1', 'SHA256']
assert opts.signing_engine == 'ENGINE'
assert opts.signtool == 'sbsign' # from args
assert opts.sb_key == 'SBKEY' # from args
assert opts.sb_cert == pathlib.Path('SBCERT') # from args
assert opts.sb_certdir == 'some/path5' # from config
assert opts.sb_cert_name == 'some/name1' # from config
assert opts.signtool == 'sbsign' # from args
assert opts.sb_key == 'SBKEY' # from args
assert opts.sb_cert == pathlib.Path('SBCERT') # from args
assert opts.sb_certdir == 'some/path5' # from config
assert opts.sb_cert_name == 'some/name1' # from config
assert opts.sign_kernel is False
assert opts.tools == [pathlib.Path('TOOLZ/')]
assert opts.output == pathlib.Path('OUTPUT')
assert opts.measure is True
def test_help(capsys):
with pytest.raises(SystemExit):
ukify.parse_args(['--help'])
@@ -387,6 +424,7 @@ def test_help(capsys):
assert '--section' in out.out
assert not out.err
def test_help_display(capsys):
with pytest.raises(SystemExit):
ukify.parse_args(['inspect', '--help'])
@@ -394,6 +432,7 @@ def test_help_display(capsys):
assert '--section' in out.out
assert not out.err
def test_help_error_deprecated(capsys):
with pytest.raises(SystemExit):
ukify.parse_args(['a', 'b', '--no-such-option'])
@@ -402,6 +441,7 @@ def test_help_error_deprecated(capsys):
assert '--no-such-option' in out.err
assert len(out.err.splitlines()) == 1
def test_help_error(capsys):
with pytest.raises(SystemExit):
ukify.parse_args(['build', '--no-such-option'])
@@ -410,6 +450,7 @@ def test_help_error(capsys):
assert '--no-such-option' in out.err
assert len(out.err.splitlines()) == 1
@pytest.fixture(scope='session')
def kernel_initrd():
items = sorted(glob.glob('/lib/modules/*/vmlinuz'))
@@ -426,6 +467,7 @@ def kernel_initrd():
# We don't look _into_ the initrd. Any file is OK.
return ['--linux', linux, '--initrd', ukify.__file__]
def test_check_splash():
try:
# pyflakes: noqa
@@ -436,16 +478,19 @@ def test_check_splash():
with pytest.raises(OSError):
ukify.check_splash(os.devnull)
def test_basic_operation(kernel_initrd, tmp_path):
if kernel_initrd is None:
pytest.skip('linux+initrd not found')
output = f'{tmp_path}/basic.efi'
opts = ukify.parse_args([
'build',
*kernel_initrd,
f'--output={output}',
])
opts = ukify.parse_args(
[
'build',
*kernel_initrd,
f'--output={output}',
]
)
try:
ukify.check_inputs(opts)
except OSError as e:
@@ -458,20 +503,23 @@ def test_basic_operation(kernel_initrd, tmp_path):
shutil.rmtree(tmp_path)
def test_sections(kernel_initrd, tmp_path):
if kernel_initrd is None:
pytest.skip('linux+initrd not found')
output = f'{tmp_path}/basic.efi'
opts = ukify.parse_args([
'build',
*kernel_initrd,
f'--output={output}',
'--uname=1.2.3',
'--cmdline=ARG1 ARG2 ARG3',
'--os-release=K1=V1\nK2=V2\n',
'--section=.test:CONTENTZ',
])
opts = ukify.parse_args(
[
'build',
*kernel_initrd,
f'--output={output}',
'--uname=1.2.3',
'--cmdline=ARG1 ARG2 ARG3',
'--os-release=K1=V1\nK2=V2\n',
'--section=.test:CONTENTZ',
]
)
try:
ukify.check_inputs(opts)
@@ -484,24 +532,25 @@ def test_sections(kernel_initrd, tmp_path):
dump = subprocess.check_output(['objdump', '-h', output], text=True)
for sect in 'text osrel cmdline linux initrd uname test'.split():
assert re.search(fr'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE)
assert re.search(rf'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE)
shutil.rmtree(tmp_path)
def test_addon(tmp_path):
output = f'{tmp_path}/addon.efi'
args = [
'build',
f'--output={output}',
'--cmdline=ARG1 ARG2 ARG3',
"""--sbat=sbat,1,foo
'''--sbat=sbat,1,foo
foo,1
bar,2
""",
''',
'--section=.test:CONTENTZ',
"""--sbat=sbat,1,foo
'''--sbat=sbat,1,foo
baz,3
"""
''',
]
if stub := os.getenv('EFI_ADDON'):
args += [f'--stub={stub}']
@@ -521,26 +570,33 @@ baz,3
dump = subprocess.check_output(['objdump', '-h', output], text=True)
for sect in 'text cmdline test sbat'.split():
assert re.search(fr'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE)
assert re.search(rf'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE)
pe = pefile.PE(output, fast_load=True)
found = False
for section in pe.sections:
if section.Name.rstrip(b"\x00").decode() == ".sbat":
if section.Name.rstrip(b'\x00').decode() == '.sbat':
assert found is False
split = section.get_data().rstrip(b"\x00").decode().splitlines()
assert split == ["sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md", "foo,1", "bar,2", "baz,3"]
split = section.get_data().rstrip(b'\x00').decode().splitlines()
assert split == [
'sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md',
'foo,1',
'bar,2',
'baz,3',
]
found = True
assert found is True
def unbase64(filename):
tmp = tempfile.NamedTemporaryFile()
base64.decode(filename.open('rb'), tmp)
tmp.flush()
return tmp
def test_uname_scraping(kernel_initrd):
if kernel_initrd is None:
pytest.skip('linux+initrd not found')
@@ -549,8 +605,9 @@ def test_uname_scraping(kernel_initrd):
uname = ukify.Uname.scrape(kernel_initrd[1])
assert re.match(r'\d+\.\d+\.\d+', uname)
@pytest.mark.skipif(not slow_tests, reason='slow')
@pytest.mark.parametrize("days", [365*10, None])
@pytest.mark.parametrize('days', [365 * 10, None])
def test_efi_signing_sbsign(days, kernel_initrd, tmp_path):
if kernel_initrd is None:
pytest.skip('linux+initrd not found')
@@ -585,16 +642,20 @@ def test_efi_signing_sbsign(days, kernel_initrd, tmp_path):
if shutil.which('sbverify'):
# let's check that sbverify likes the resulting file
dump = subprocess.check_output([
'sbverify',
'--cert', cert.name,
output,
], text=True)
dump = subprocess.check_output(
[
'sbverify',
'--cert', cert.name,
output,
],
text=True,
) # fmt: skip
assert 'Signature verification OK' in dump
shutil.rmtree(tmp_path)
@pytest.mark.skipif(not slow_tests, reason='slow')
def test_efi_signing_pesign(kernel_initrd, tmp_path):
if kernel_initrd is None:
@@ -613,16 +674,18 @@ def test_efi_signing_pesign(kernel_initrd, tmp_path):
subprocess.check_call(cmd)
output = f'{tmp_path}/signed.efi'
opts = ukify.parse_args([
'build',
*kernel_initrd,
f'--output={output}',
'--uname=1.2.3',
'--signtool=pesign',
'--cmdline=ARG1 ARG2 ARG3',
f'--secureboot-certificate-name={name}',
f'--secureboot-certificate-dir={nss_db}',
])
opts = ukify.parse_args(
[
'build',
*kernel_initrd,
f'--output={output}',
'--uname=1.2.3',
'--signtool=pesign',
'--cmdline=ARG1 ARG2 ARG3',
f'--secureboot-certificate-name={name}',
f'--secureboot-certificate-dir={nss_db}',
]
)
try:
ukify.check_inputs(opts)
@@ -632,15 +695,20 @@ def test_efi_signing_pesign(kernel_initrd, tmp_path):
ukify.make_uki(opts)
# let's check that pesign likes the resulting file
dump = subprocess.check_output([
'pesign', '-S',
'-i', output,
], text=True)
dump = subprocess.check_output(
[
'pesign',
'-S',
'-i', output,
],
text=True,
) # fmt: skip
assert f"The signer's common name is {author}" in dump
shutil.rmtree(tmp_path)
def test_inspect(kernel_initrd, tmp_path, capsys, osrel=True):
if kernel_initrd is None:
pytest.skip('linux+initrd not found')
@@ -652,9 +720,9 @@ def test_inspect(kernel_initrd, tmp_path, capsys, osrel=True):
key = unbase64(ourdir / 'example.signing.key.base64')
output = f'{tmp_path}/signed2.efi'
uname_arg='1.2.3'
osrel_arg='Linux' if osrel else ''
cmdline_arg='ARG1 ARG2 ARG3'
uname_arg = '1.2.3'
osrel_arg = 'Linux' if osrel else ''
cmdline_arg = 'ARG1 ARG2 ARG3'
args = [
'build',
@@ -698,9 +766,11 @@ def test_inspect(kernel_initrd, tmp_path, capsys, osrel=True):
shutil.rmtree(tmp_path)
def test_inspect_no_osrel(kernel_initrd, tmp_path, capsys):
test_inspect(kernel_initrd, tmp_path, capsys, osrel=False)
@pytest.mark.skipif(not slow_tests, reason='slow')
def test_pcr_signing(kernel_initrd, tmp_path):
if kernel_initrd is None:
@@ -722,7 +792,7 @@ def test_pcr_signing(kernel_initrd, tmp_path):
'--uname=1.2.3',
'--cmdline=ARG1 ARG2 ARG3',
'--os-release=ID=foobar\n',
'--pcr-banks=sha384', # sha1 might not be allowed, use something else
'--pcr-banks=sha384', # sha1 might not be allowed, use something else
f'--pcr-private-key={priv.name}',
] + arg_tools
@@ -743,21 +813,25 @@ def test_pcr_signing(kernel_initrd, tmp_path):
dump = subprocess.check_output(['objdump', '-h', output], text=True)
for sect in 'text osrel cmdline linux initrd uname pcrsig'.split():
assert re.search(fr'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE)
assert re.search(rf'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE)
# objcopy fails when called without an output argument (EPERM).
# It also fails when called with /dev/null (file truncated).
# It also fails when called with /dev/zero (because it reads the
# output file, infinitely in this case.)
# So let's just call it with a dummy output argument.
subprocess.check_call([
'objcopy',
*(f'--dump-section=.{n}={tmp_path}/out.{n}' for n in (
'pcrpkey', 'pcrsig', 'osrel', 'uname', 'cmdline')),
output,
tmp_path / 'dummy',
],
text=True)
subprocess.check_call(
[
'objcopy',
*(
f'--dump-section=.{n}={tmp_path}/out.{n}'
for n in ('pcrpkey', 'pcrsig', 'osrel', 'uname', 'cmdline')
),
output,
tmp_path / 'dummy',
],
text=True,
)
assert open(tmp_path / 'out.pcrpkey').read() == open(pub.name).read()
assert open(tmp_path / 'out.osrel').read() == 'ID=foobar\n'
@@ -766,10 +840,11 @@ def test_pcr_signing(kernel_initrd, tmp_path):
sig = open(tmp_path / 'out.pcrsig').read()
sig = json.loads(sig)
assert list(sig.keys()) == ['sha384']
assert len(sig['sha384']) == 4 # four items for four phases
assert len(sig['sha384']) == 4 # four items for four phases
shutil.rmtree(tmp_path)
@pytest.mark.skipif(not slow_tests, reason='slow')
def test_pcr_signing2(kernel_initrd, tmp_path):
if kernel_initrd is None:
@@ -791,24 +866,27 @@ def test_pcr_signing2(kernel_initrd, tmp_path):
output = f'{tmp_path}/signed.efi'
assert kernel_initrd[0] == '--linux'
opts = ukify.parse_args([
'build',
*kernel_initrd[:2],
f'--initrd={microcode.name}',
*kernel_initrd[2:],
f'--output={output}',
'--uname=1.2.3',
'--cmdline=ARG1 ARG2 ARG3',
'--os-release=ID=foobar\n',
'--pcr-banks=sha384',
f'--pcrpkey={pub2.name}',
f'--pcr-public-key={pub.name}',
f'--pcr-private-key={priv.name}',
'--phases=enter-initrd enter-initrd:leave-initrd',
f'--pcr-public-key={pub2.name}',
f'--pcr-private-key={priv2.name}',
'--phases=sysinit ready shutdown final', # yes, those phase paths are not reachable
] + arg_tools)
opts = ukify.parse_args(
[
'build',
*kernel_initrd[:2],
f'--initrd={microcode.name}',
*kernel_initrd[2:],
f'--output={output}',
'--uname=1.2.3',
'--cmdline=ARG1 ARG2 ARG3',
'--os-release=ID=foobar\n',
'--pcr-banks=sha384',
f'--pcrpkey={pub2.name}',
f'--pcr-public-key={pub.name}',
f'--pcr-private-key={priv.name}',
'--phases=enter-initrd enter-initrd:leave-initrd',
f'--pcr-public-key={pub2.name}',
f'--pcr-private-key={priv2.name}',
'--phases=sysinit ready shutdown final', # yes, those phase paths are not reachable
]
+ arg_tools
)
try:
ukify.check_inputs(opts)
@@ -821,16 +899,20 @@ def test_pcr_signing2(kernel_initrd, tmp_path):
dump = subprocess.check_output(['objdump', '-h', output], text=True)
for sect in 'text osrel cmdline linux initrd uname pcrsig'.split():
assert re.search(fr'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE)
assert re.search(rf'^\s*\d+\s+\.{sect}\s+[0-9a-f]+', dump, re.MULTILINE)
subprocess.check_call([
'objcopy',
*(f'--dump-section=.{n}={tmp_path}/out.{n}' for n in (
'pcrpkey', 'pcrsig', 'osrel', 'uname', 'cmdline', 'initrd')),
output,
tmp_path / 'dummy',
],
text=True)
subprocess.check_call(
[
'objcopy',
*(
f'--dump-section=.{n}={tmp_path}/out.{n}'
for n in ('pcrpkey', 'pcrsig', 'osrel', 'uname', 'cmdline', 'initrd')
),
output,
tmp_path / 'dummy',
],
text=True,
)
assert open(tmp_path / 'out.pcrpkey').read() == open(pub2.name).read()
assert open(tmp_path / 'out.osrel').read() == 'ID=foobar\n'
@@ -841,22 +923,25 @@ def test_pcr_signing2(kernel_initrd, tmp_path):
sig = open(tmp_path / 'out.pcrsig').read()
sig = json.loads(sig)
assert list(sig.keys()) == ['sha384']
assert len(sig['sha384']) == 6 # six items for six phases paths
assert len(sig['sha384']) == 6 # six items for six phases paths
shutil.rmtree(tmp_path)
def test_key_cert_generation(tmp_path):
opts = ukify.parse_args([
'genkey',
f"--pcr-public-key={tmp_path / 'pcr1.pub.pem'}",
f"--pcr-private-key={tmp_path / 'pcr1.priv.pem'}",
'--phases=enter-initrd enter-initrd:leave-initrd',
f"--pcr-public-key={tmp_path / 'pcr2.pub.pem'}",
f"--pcr-private-key={tmp_path / 'pcr2.priv.pem'}",
'--phases=sysinit ready',
f"--secureboot-private-key={tmp_path / 'sb.priv.pem'}",
f"--secureboot-certificate={tmp_path / 'sb.cert.pem'}",
])
opts = ukify.parse_args(
[
'genkey',
f'--pcr-public-key={tmp_path / "pcr1.pub.pem"}',
f'--pcr-private-key={tmp_path / "pcr1.priv.pem"}',
'--phases=enter-initrd enter-initrd:leave-initrd',
f'--pcr-public-key={tmp_path / "pcr2.pub.pem"}',
f'--pcr-private-key={tmp_path / "pcr2.priv.pem"}',
'--phases=sysinit ready',
f'--secureboot-private-key={tmp_path / "sb.priv.pem"}',
f'--secureboot-certificate={tmp_path / "sb.cert.pem"}',
]
)
assert opts.verb == 'genkey'
ukify.check_cert_and_keys_nonexistent(opts)
@@ -867,39 +952,46 @@ def test_key_cert_generation(tmp_path):
if not shutil.which('openssl'):
return
for key in (tmp_path / 'pcr1.priv.pem',
tmp_path / 'pcr2.priv.pem',
tmp_path / 'sb.priv.pem'):
out = subprocess.check_output([
'openssl', 'rsa',
'-in', key,
'-text',
'-noout',
], text = True)
for key in (tmp_path / 'pcr1.priv.pem', tmp_path / 'pcr2.priv.pem', tmp_path / 'sb.priv.pem'):
out = subprocess.check_output(
[
'openssl', 'rsa',
'-in', key,
'-text',
'-noout',
],
text=True,
) # fmt: skip
assert 'Private-Key' in out
assert '2048 bit' in out
for pub in (tmp_path / 'pcr1.pub.pem',
tmp_path / 'pcr2.pub.pem'):
out = subprocess.check_output([
'openssl', 'rsa',
'-pubin',
'-in', pub,
'-text',
'-noout',
], text = True)
for pub in (tmp_path / 'pcr1.pub.pem', tmp_path / 'pcr2.pub.pem'):
out = subprocess.check_output(
[
'openssl', 'rsa',
'-pubin',
'-in', pub,
'-text',
'-noout',
],
text=True,
) # fmt: skip
assert 'Public-Key' in out
assert '2048 bit' in out
out = subprocess.check_output([
'openssl', 'x509',
'-in', tmp_path / 'sb.cert.pem',
'-text',
'-noout',
], text = True)
out = subprocess.check_output(
[
'openssl', 'x509',
'-in', tmp_path / 'sb.cert.pem',
'-text',
'-noout',
],
text=True,
) # fmt: skip
assert 'Certificate' in out
assert re.search(r'Issuer: CN\s?=\s?SecureBoot signing key on host', out)
@pytest.mark.skipif(not slow_tests, reason='slow')
def test_join_pcrsig(capsys, kernel_initrd, tmp_path):
if kernel_initrd is None:
@@ -965,5 +1057,6 @@ def test_join_pcrsig(capsys, kernel_initrd, tmp_path):
shutil.rmtree(tmp_path)
if __name__ == '__main__':
sys.exit(pytest.main(sys.argv))