From: Lennart Poettering Date: Thu, 25 Aug 2022 14:55:01 +0000 (+0200) Subject: stub: add new special PE sections ".pcrsig" and ".pcrpkey" in unified kernels X-Git-Tag: v252-rc1~217^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=df7ee6f8b0c73ecd4d9f042482b894ebb5b71353;p=thirdparty%2Fsystemd.git stub: add new special PE sections ".pcrsig" and ".pcrpkey" in unified kernels 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. --- diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 3f6832e0c2d..a00892718ec 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -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, diff --git a/src/boot/measure.c b/src/boot/measure.c index e8404026cbe..bc8f720514b 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -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 }, diff --git a/src/fundamental/tpm-pcr.c b/src/fundamental/tpm-pcr.c index 97b3c7b9d2a..7609d83c2ef 100644 --- a/src/fundamental/tpm-pcr.c +++ b/src/fundamental/tpm-pcr.c @@ -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, }; diff --git a/src/fundamental/tpm-pcr.h b/src/fundamental/tpm-pcr.h index fb0774f70d1..235d4841b00 100644 --- a/src/fundamental/tpm-pcr.h +++ b/src/fundamental/tpm-pcr.h @@ -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; +}