Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mkosi: add support for PKCS7 signed images #798

Merged
merged 9 commits into from
Oct 7, 2021

Conversation

poettering
Copy link
Member

This adds support for PKCS7 signed Verity disk images, compatible with the kernel's logic for that.

mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
Copy link
Member

@keszybz keszybz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very reasonable.

mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
@poettering
Copy link
Member Author

poettering commented Sep 9, 2021

systemd side for picking up these embedded signatures is in systemd/systemd#20691

@poettering poettering changed the title mkosi: add support for PKCS7 signed images (WIP) mkosi: add support for PKCS7 signed images Sep 10, 2021
@poettering
Copy link
Member Author

this is no longer wip. Should be good for review/merge. PTAL!

mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi.md Outdated Show resolved Hide resolved
mkosi.md Outdated Show resolved Hide resolved
mkosi.md Outdated Show resolved Hide resolved
mkosi.md Outdated Show resolved Hide resolved
mkosi.md Outdated Show resolved Hide resolved
Copy link
Contributor

@behrmann behrmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@poettering could you add types-openssl-python to ci-unit-test.yml, so that

    - name: Install
      run: |
-       python3 -m pip install pytest mypy isort pyflakes
+       python3 -m pip install pytest mypy types-openssl-python isort pyflakes
        npm install -g pyright

I've only quickly ran mypy with this and will probably not manage to have a further look at this before next week, but here are the easy to fix typing changes (I have never used the openssl API, though, so beware, I don't know whether the typing information is correct). Beyond that, mypy mostly stumbles over all the typing for internal functions that it doesn't have. For now the easiest solution would be to smother all of this with type ignore hints, but we can probably add some typing later and maybe upstream that to typeshed.

mkosi/__init__.py Outdated Show resolved Hide resolved
mkosi/__init__.py Outdated Show resolved Hide resolved
@keszybz
Copy link
Member

keszybz commented Sep 13, 2021

This needs another round…

@behrmann
Copy link
Contributor

I've opened poettering#4, since this was a bit easier than doing this via the review interface. I think exchanging pyopenssl for cryptography is were the ecosystem is going and what upstream itself recommends. The backend is, as far as I understand, openssl, too, but the API seems a lot nicer and it is already fully typed.

With that the typing checks run through, but for some reason the unit tests are still borked.

@poettering
Copy link
Member Author

I force pushed a new version, still using the OpenSSL thing, but with all issues supposedly fixed.

Using the OpenSSL module indeed seems a bit awkward, if there's now something more pythonic, that's great. I was wondering about that when I picked OpenSSL — which I picked simply for the reason it has the most hits on google.

(the "genkey" code should be ported over too btw)

@poettering
Copy link
Member Author

not sure i grok the import ordering thing? is it that isort doesn't like imports inside of functions?

@behrmann
Copy link
Contributor

not sure i grok the import ordering thing? is it that isort doesn't like imports inside of functions?

No, that is isort pedantically disliking the empty line (line 40)

@behrmann
Copy link
Contributor

I force pushed a new version, still using the OpenSSL thing, but with all issues supposedly fixed.

There will be a few others. mypy will still stumble over the internals of OpenSSL (which could be silenced, with poettering#4 being the alternative), but there's also errors in the CLI unit tests I haven't yet looked at (and which are also present in poettering#4).

mkosi/__init__.py Outdated Show resolved Hide resolved
@poettering
Copy link
Member Author

Force pushed a new version now, incorporating @behrmann's work on python-cryptography. Alas, it doesn't work anymore. Something is broken with inserting the verity-sig partition after we put it together. I have the strong suspicion that #791 is at fault for that.

@keszybz
Copy link
Member

keszybz commented Sep 13, 2021

I have the strong suspicion that #791 is at fault for that.

I'll take a look tomorrow.

@keszybz
Copy link
Member

keszybz commented Sep 16, 2021

Sorry for the delay. I made a huge refactoring of the sfdisk code, but it still needs some debugging. I'm not working today, but hopefully it'll be ready on Monday.

@lgtm-com
Copy link

lgtm-com bot commented Sep 28, 2021

This pull request fixes 1 alert when merging f5eccf9 into f0f67d4 - view on LGTM.com

fixed alerts:

  • 1 for Clear-text logging of sensitive information

@poettering
Copy link
Member Author

Hmm, if I run this on the systemd main repo then it still doesn#t work: (i.e. mkosi -i -f -f boot)

‣ Running second (final) stage to generate cached copy…
Traceback (most recent call last):
  File "/usr/lib64/python3.9/runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib64/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/lennart/projects/mkosi/mkosi/__main__.py", line 32, in <module>
    main()
  File "/home/lennart/projects/mkosi/mkosi/__main__.py", line 26, in main
    run_verb(a)
  File "/home/lennart/projects/mkosi/mkosi/__init__.py", line 7204, in run_verb
    manifest = build_stuff(args)
  File "/home/lennart/projects/mkosi/mkosi/__init__.py", line 6619, in build_stuff
    image = build_image(args, root, do_run_build_script=False, for_cache=True)
  File "/home/lennart/projects/mkosi/mkosi/__init__.py", line 6339, in build_image
    raw = create_image(args, for_cache)
  File "/home/lennart/projects/mkosi/mkosi/__init__.py", line 608, in create_image
    assert args.partition_table is None
AssertionError

I think we should split out utils.py or something later on. But let's
at least move it out of the main file.
keszybz added a commit to poettering/mkosi that referenced this pull request Oct 5, 2021
@lgtm-com
Copy link

lgtm-com bot commented Oct 5, 2021

This pull request fixes 1 alert when merging 4774cf3 into 2e35cde - view on LGTM.com

fixed alerts:

  • 1 for Clear-text logging of sensitive information

@keszybz
Copy link
Member

keszybz commented Oct 5, 2021

Hmm, it now builds, but doesn't boot. I need to investigate more.

keszybz added a commit to poettering/mkosi that referenced this pull request Oct 5, 2021
@keszybz
Copy link
Member

keszybz commented Oct 5, 2021

I dropped a not in one of the conditionals… Let's see if it passes now.

@lgtm-com
Copy link

lgtm-com bot commented Oct 5, 2021

This pull request fixes 1 alert when merging dcc68e8 into 2e35cde - view on LGTM.com

fixed alerts:

  • 1 for Clear-text logging of sensitive information

poettering and others added 8 commits October 6, 2021 08:40
This adds support for creating signed GPT disk images. If Verity=signed
is set this will not only generate and insert Verity data into the
image, but then use the resulting root hash, sign it and include it in
an additional partition. It will also write the resulting PKCS7
signature out into a new .roothash.p7s file.

This scheme is compatible with kernel 5.4's PKCS7 signature logic for
dm-verity: the resulting .p7s file can be passed as-is to the kernel (or
systemd's RootHashSignature= setting).

The partition this embedds contains a simple JSON object containing
three fields. The verity root hash, the PKCS7 data (i.e. the same data
as in the .p7s file, but in base64), and SHA256 fingerprint of the
signing key. This partition is supposed to be read by the image
dissection logic of systemd, to implement signed single-file images.
(The corresponding PR for systemd I am still working on).

This opens up two avenues for image verification:

1. Everything in one file: the single, "unified" GPT disk image contains
   three partitions, for payload data, verity data and verity signature.

2. Split out: root hash and its signature are stored in two "sidecar"
   files.

(Of course I'd personally always go the "unified" way, but given the
RootHashSignature= logic exists already, and it's easy to support, let's
support it.)

This uses the key already used for doing secureboot image signing.
Conceptually this makes a ton of sense: we sign the same stuff here
after all: the contents of the image, supporting two different
entrypoints to the image: one via UEFI booting the image, and once for
attaching directly to an image from a running system. Admittedly, the
"mkosi.secure-boot.key" and "mkosi.secure-boot.certificate" monikers for
this key pair might be a bit suprising though.

Corresponding PR in systemd is:

systemd/systemd#20691
This is mostly based on Jörg Behrmann's (@behrmann) work.
The general idea is that those closes collect attributes and information
about the abstract partition table, but are independent of any underlying
block device. The definitions exists indendependently of a block device
and can be applied later on.

Partitions are referred to by enum PartitionIdentifier.

The calculation of the space necessary for those partitions is centralized
in the class, so we don't have multiplace places where we arrive at slightly
different formulas for the expected disk size.
We would have two conditions joined by 'and', and we would have
the first operand and half of the second on the first line, and
the remainder of the second operand on multiple lines.
@lgtm-com
Copy link

lgtm-com bot commented Oct 6, 2021

This pull request fixes 1 alert when merging e4996c9 into 2e35cde - view on LGTM.com

fixed alerts:

  • 1 for Clear-text logging of sensitive information

@keszybz
Copy link
Member

keszybz commented Oct 6, 2021

The only failure is:

Error: Failed to download metadata for repo 'AppStream': Cannot prepare internal mirrorlist: Status code: 503 for https://mirrors.rockylinux.org/mirrorlist?arch=x86_64&repo=AppStream-8 (IP: 151.101.186.132)

Yay!

@keszybz
Copy link
Member

keszybz commented Oct 6, 2021

@poettering merge this now?

@poettering
Copy link
Member Author

I think something is wrong with the partition size calculations. If I built an image with pkcs7 signature and look at the signature data it appears that it overlaps with the GPT footer, i.e. if you dump partition contents with xxd then you see something that looks a ton like the GPT partition list.

@poettering
Copy link
Member Author

lgtm, otherwise

@keszybz
Copy link
Member

keszybz commented Oct 7, 2021

(As discussed in the chat, we'll deal with the gpt header corruption later.)

@keszybz keszybz merged commit af4b9f1 into systemd:main Oct 7, 2021
keszybz added a commit to keszybz/mkosi that referenced this pull request Oct 7, 2021
We would create a file with 0 padding to force it to a certain size.
This seems fairly ugly, in particular when we later want to use the
blob in other contexts. Also, this embedded the assumption that padding
to 4096 is always appropriate in the function that generates the signature.
Let's just calculate the right amount when writing to the target partition.

Incidentally, this seems to fix the issue where we'd the backup LBA
header inserted over the output partition, as discussed in
systemd#798 (comment).
But I don't entirely understand the issue, so maybe this change is only
hiding the bug.
keszybz added a commit to keszybz/mkosi that referenced this pull request Oct 8, 2021
We would create a file with 0 padding to force it to a certain size.
This seems fairly ugly, in particular when we later want to use the
blob in other contexts. Also, this embedded the assumption that padding
to 4096 is always appropriate in the function that generates the signature.
Let's just calculate the right amount when writing to the target partition.

Incidentally, this seems to fix the issue where we'd the backup LBA
header inserted over the output partition, as discussed in
systemd#798 (comment).
But I don't entirely understand the issue, so maybe this change is only
hiding the bug.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants