'--cmdline=ARG1 ARG2 ARG3',
'--os-release=ID=foobar\n',
'--pcr-banks=sha1', # use sha1 because it doesn't really matter
- f'--pcrpkey={pub.name}',
- f'--pcr-public-key={pub.name}',
f'--pcr-private-key={priv.name}',
])
- try:
- ukify.check_inputs(opts)
- except OSError as e:
- pytest.skip(str(e))
-
- ukify.make_uki(opts)
-
- # let's check that objdump likes the resulting file
- 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', 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}={tmpdir}/out.{n}' for n in (
- 'pcrpkey', 'pcrsig', 'osrel', 'uname', 'cmdline')),
- output,
- tmpdir / 'dummy',
- ],
- text=True)
-
- assert open(tmpdir / 'out.pcrpkey').read() == open(pub.name).read()
- assert open(tmpdir / 'out.osrel').read() == 'ID=foobar\n'
- assert open(tmpdir / 'out.uname').read() == '1.2.3'
- assert open(tmpdir / 'out.cmdline').read() == 'ARG1 ARG2 ARG3'
- sig = open(tmpdir / 'out.pcrsig').read()
- sig = json.loads(sig)
- assert list(sig.keys()) == ['sha1']
- assert len(sig['sha1']) == 4 # four items for four phases
+ # If the public key is not explicitly specified, it is derived automatically. Let's make sure everything
+ # works as expected both when the public keys is specified explicitly and when it is derived from the
+ # private key.
+ for extra in ([f'--pcrpkey={pub.name}', f'--pcr-public-key={pub.name}'], []):
+ try:
+ ukify.check_inputs(opts + extra)
+ except OSError as e:
+ pytest.skip(str(e))
+
+ ukify.make_uki(opts + extra)
+
+ # let's check that objdump likes the resulting file
+ 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', 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}={tmpdir}/out.{n}' for n in (
+ 'pcrpkey', 'pcrsig', 'osrel', 'uname', 'cmdline')),
+ output,
+ tmpdir / 'dummy',
+ ],
+ text=True)
+
+ assert open(tmpdir / 'out.pcrpkey').read() == open(pub.name).read()
+ assert open(tmpdir / 'out.osrel').read() == 'ID=foobar\n'
+ assert open(tmpdir / 'out.uname').read() == '1.2.3'
+ assert open(tmpdir / 'out.cmdline').read() == 'ARG1 ARG2 ARG3'
+ sig = open(tmpdir / 'out.pcrsig').read()
+ sig = json.loads(sig)
+ assert list(sig.keys()) == ['sha1']
+ assert len(sig['sha1']) == 4 # four items for four phases
def test_pcr_signing2(kernel_initrd, tmpdir):
if kernel_initrd is None:
uki = UKI(opts.stub)
initrd = join_initrds(opts.initrd)
- # TODO: derive public key from opts.pcr_private_keys?
pcrpkey = opts.pcrpkey
if pcrpkey is None:
if opts.pcr_public_keys and len(opts.pcr_public_keys) == 1:
pcrpkey = opts.pcr_public_keys[0]
+ elif opts.pcr_private_keys and len(opts.pcr_private_keys) == 1:
+ import cryptography.hazmat.primitives.serialization as serialization
+ privkey = serialization.load_pem_private_key(opts.pcr_private_keys[0].read_bytes(), password=None)
+ pcrpkey = privkey.public_key().public_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
+ )
sections = [
# name, content, measure?