]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
stub: add new special PE sections ".pcrsig" and ".pcrpkey" in unified kernels
authorLennart Poettering <lennart@poettering.net>
Thu, 25 Aug 2022 14:55:01 +0000 (16:55 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 9 Sep 2022 09:28:38 +0000 (11:28 +0200)
These aren't wired up yet to do anything useful. For now we just define
them.

This sections are supposed to carry a signature for expected
measurements on PCR 11 if this kernel is booted, in the JSON format
"systemd-measure sign" generates, and the public key used for the
signature.

The idea is to embedd the signature and the public key in unified
kernels and making them available to userspace, so that userspace can
easily access them and enroll (for which the public key is needed) or
unlock (for which the PCR signature is needed) LUKS2 volumes and
credentials that are bound to the currently used kernel version stream.

Why put these files in PE sections rather than just into simple files in
the initrd or into the host fs?

The signature cannot be in the initrd, since it is after all covering
the initrd, and thus the initrd as input for the calculation cannot
carry the result of the calculation. Putting the signature onto the root
fs sucks too, since we typically want to unlock the root fs with it,
hence it would be inaccessible for it's primary purpose then.

The public key could be in the initrd or in the root fs, there's no
technical restriction for that. However, I still think it's a good idea
to put it in a PE section as well, because this means the piece of code
that attaches the signature can also attach the public key easily in one
step, which is nice since it allows separating the roles of the
kernel/initrd/root fs builder, and the role of the signer, and the
former doesn't have to have knowledge about what the latter is going to
add to the image.

Note that the signature section is excluded from the TPM measurements
sd-stub does about its resource sections, since – as mentioned – it's
the expected output of the signing operation whose input are the
measurements, hence it cannot also be input to them. The public key
section is included in the measurements however.

src/boot/efi/stub.c
src/boot/measure.c
src/fundamental/tpm-pcr.c
src/fundamental/tpm-pcr.h

index 3f6832e0c2d082cbde186f51139cba786def47e8..a00892718ec6df886a863b6b848cc97d5861b44a 100644 (file)
@@ -190,11 +190,15 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
          * into so far), so that we have one PCR that we can nicely write policies against because it
          * contains all static data of this image, and thus can be easily be pre-calculated. */
         for (UnifiedSection section = 0; section < _UNIFIED_SECTION_MAX; section++) {
-                m = false;
+
+                if (!unified_section_measure(section)) /* shall not measure? */
+                        continue;
 
                 if (szs[section] == 0) /* not found */
                         continue;
 
+                m = false;
+
                 /* First measure the name of the section */
                 (void) tpm_log_event_ascii(
                                 TPM_PCR_INDEX_KERNEL_IMAGE,
index e8404026cbeb9304fed56a7168d3d5f3f72b0e55..bc8f720514bed15d5d21c2e328245a48d09a388a 100644 (file)
@@ -68,6 +68,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --initrd=PATH       Path to initrd image\n"
                "     --splash=PATH       Path to splash bitmap\n"
                "     --dtb=PATH          Path to Devicetree file\n"
+               "     --pcrpkey=PATH      Path to public key for PCR signatures in DER format\n"
                "  -c --current           Use current PCR values\n"
                "     --bank=DIGEST       Select TPM bank (SHA1, SHA256)\n"
                "     --tpm2-device=PATH  Use specified TPM2 device\n"
@@ -96,8 +97,10 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_CMDLINE,
                 ARG_INITRD,
                 ARG_SPLASH,
+                ARG_DTB,
+                _ARG_PCRSIG, /* the .pcrsig section is not input for signing, hence not actually an argument here */
                 _ARG_SECTION_LAST,
-                ARG_DTB = _ARG_SECTION_LAST,
+                ARG_PCRPKEY = _ARG_SECTION_LAST,
                 ARG_BANK,
                 ARG_PRIVATE_KEY,
                 ARG_PUBLIC_KEY,
@@ -115,6 +118,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "initrd",      required_argument, NULL, ARG_INITRD      },
                 { "splash",      required_argument, NULL, ARG_SPLASH      },
                 { "dtb",         required_argument, NULL, ARG_DTB         },
+                { "pcrpkey",     required_argument, NULL, ARG_PCRPKEY     },
                 { "current",     no_argument,       NULL, 'c'             },
                 { "bank",        required_argument, NULL, ARG_BANK        },
                 { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
index 97b3c7b9d2aaa49e00cb1b6dab0ac61dada4e30a..7609d83c2ef237bd719be9a83f9d3cb5cb82a3c4 100644 (file)
@@ -11,5 +11,7 @@ const char* const unified_sections[_UNIFIED_SECTION_MAX + 1] = {
         [UNIFIED_SECTION_INITRD]  = ".initrd",
         [UNIFIED_SECTION_SPLASH]  = ".splash",
         [UNIFIED_SECTION_DTB]     = ".dtb",
+        [UNIFIED_SECTION_PCRSIG]  = ".pcrsig",
+        [UNIFIED_SECTION_PCRPKEY] = ".pcrpkey",
         NULL,
 };
index fb0774f70d133247fa08fb22755fac4f03aa3b53..235d4841b00cefa4d2e6a3b36ad20d002c74a337 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include "macro-fundamental.h"
+
 /* The various TPM PCRs we measure into from sd-stub and sd-boot. */
 
 /* This TPM PCR is where we extend the sd-stub "payloads" into, before using them. i.e. the kernel ELF image,
@@ -32,7 +34,15 @@ typedef enum UnifiedSection {
         UNIFIED_SECTION_INITRD,
         UNIFIED_SECTION_SPLASH,
         UNIFIED_SECTION_DTB,
+        UNIFIED_SECTION_PCRSIG,
+        UNIFIED_SECTION_PCRPKEY,
         _UNIFIED_SECTION_MAX,
 } UnifiedSection;
 
 extern const char* const unified_sections[_UNIFIED_SECTION_MAX + 1];
+
+static inline bool unified_section_measure(UnifiedSection section) {
+        /* Don't include the PCR signature in the PCR measurements, since they sign the expected result of
+         * the measurement, and hence shouldn't be input to it. */
+        return section >= 0 && section < _UNIFIED_SECTION_MAX && section != UNIFIED_SECTION_PCRSIG;
+}