- Add support-ecc-srk.patch to support ECC SRK

- Add fix-testcase-empty-efi-variables.patch to fix the testcase
  playback on empty EFI variables

OBS-URL: https://build.opensuse.org/package/show/Base:System/pcr-oracle?expand=0&rev=32
This commit is contained in:
Alberto Planas 2024-08-07 06:20:05 +00:00 committed by Git OBS Bridge
commit 48bd67e6f2
12 changed files with 1780 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.osc

17
_service Normal file
View File

@ -0,0 +1,17 @@
<!-- See https://en.opensuse.org/openSUSE:Build_Service_Concept_SourceService -->
<!-- for more details on the syntax -->
<services>
<service name="tar_scm" mode="disabled">
<param name="scm">git</param>
<param name="url">https://github.com/okirch/pcr-oracle.git</param>
<param name="filename">pcr-oracle</param>
<param name="versionformat">@PARENT_TAG@</param>
<param name="revision">refs/tags/0.5.4</param>
</service>
<service name="recompress" mode="disabled">
<param name="file">pcr-oracle*.tar</param>
<param name="compression">xz</param>
</service>
<service mode="disabled" name="set_version" />
</services>

View File

@ -0,0 +1,58 @@
From 61f9b77634578c0bf0c3bf6c4b386057e8661a1c Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 12 Jun 2024 14:41:38 +0800
Subject: [PATCH] testcase: fix playback on empty EFI variables
For systems in UEFI Setup mode, there is no PK, KEK, or db. However,
those variables are still recorded in the TPM event log with zero
length. To avoid failing on reading those files, this commit changes the
file reading flag so that testcase playback won't stop on those EFI
variables.
Signed-off-by: Gary Lin <glin@suse.com>
---
src/testcase.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/testcase.c b/src/testcase.c
index f74238b..998aedd 100644
--- a/src/testcase.c
+++ b/src/testcase.c
@@ -224,12 +224,18 @@ testcase_write_file(const char *directory, const char *name, const buffer_t *bp)
}
static buffer_t *
-testcase_read_file(const char *directory, const char *name)
+__testcase_read_file(const char *directory, const char *name, int flags)
{
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", directory, name);
- return runtime_read_file(path, 0);
+ return runtime_read_file(path, flags);
+}
+
+static buffer_t *
+testcase_read_file(const char *directory, const char *name)
+{
+ return __testcase_read_file(directory, name, 0);
}
testcase_t *
@@ -314,7 +320,12 @@ testcase_record_efi_variable(testcase_t *tc, const char *name, const buffer_t *d
buffer_t *
testcase_playback_efi_variable(testcase_t *tc, const char *name)
{
- return testcase_read_file(tc->efi_directory, name);
+ /* For systems in UEFI Setup mode, there is no PK, KEK, or db, but those
+ * variables are still recorded in the TPM event log with zero length.
+ * Set the file reading flag to skip those EFI variable files.
+ */
+ return __testcase_read_file(tc->efi_directory, name,
+ RUNTIME_MISSING_FILE_OKAY);
}
void
--
2.35.3

View File

@ -0,0 +1,412 @@
From 9489d98463a596ec8e4ba9f1f4a2b2af91c0968b Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Wed, 10 Jan 2024 15:32:07 +0100
Subject: [PATCH 1/8] Print the measured kernel
The debug output can be missleading, as print information about the
current event log, but not about the measured element, that can be
different as in the kernel case.
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/efi-application.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/efi-application.c b/src/efi-application.c
index 3e80083..2fd33ec 100644
--- a/src/efi-application.c
+++ b/src/efi-application.c
@@ -292,6 +292,12 @@ __tpm_event_efi_bsa_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *pars
/* The next boot can have a different kernel */
if (sdb_is_kernel(evspec->efi_application) && ctx->boot_entry) {
+ /* TODO: the parsed data type did not change, so all
+ * the description correspond to the current event
+ * log, and not the asset that has been measured. The
+ * debug output can then be missleading.
+ */
+ debug("Measuring %s\n", ctx->boot_entry->image_path);
new_application = ctx->boot_entry->image_path;
if (new_application) {
evspec_clone = *evspec;
From d8d97a3c233e326e0b1836b77fa08f483ea8f410 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Wed, 10 Jan 2024 15:51:45 +0100
Subject: [PATCH 2/8] Rename variable to cmdline
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/eventlog.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/eventlog.c b/src/eventlog.c
index 4277d42..377f4d6 100644
--- a/src/eventlog.c
+++ b/src/eventlog.c
@@ -790,8 +790,8 @@ static const tpm_evdigest_t *
__tpm_event_systemd_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *parsed, tpm_event_log_rehash_ctx_t *ctx)
{
const uapi_boot_entry_t *boot_entry = ctx->boot_entry;
- char initrd[2048];
- char initrd_utf16[4096];
+ char cmdline[2048];
+ char cmdline_utf16[4096];
unsigned int len;
/* If no --next-kernel option was given, do not rehash anything */
@@ -804,15 +804,16 @@ __tpm_event_systemd_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *pars
}
debug("Next boot entry expected from: %s %s\n", boot_entry->title, boot_entry->version? : "");
- snprintf(initrd, sizeof(initrd), "initrd=%s %s",
+ snprintf(cmdline, sizeof(cmdline), "initrd=%s %s",
path_unix2dos(boot_entry->initrd_path),
boot_entry->options? : "");
+ debug("Measuring Kernel command line: %s\n", cmdline);
- len = (strlen(initrd) + 1) << 1;
- assert(len <= sizeof(initrd_utf16));
- __convert_to_utf16le(initrd, strlen(initrd) + 1, initrd_utf16, len);
+ len = (strlen(cmdline) + 1) << 1;
+ assert(len <= sizeof(cmdline_utf16));
+ __convert_to_utf16le(cmdline, strlen(cmdline) + 1, cmdline_utf16, len);
- return digest_compute(ctx->algo, initrd_utf16, len);
+ return digest_compute(ctx->algo, cmdline_utf16, len);
}
/*
From 4f8e3f4760ff7fe97df1e6af569d049e30f3ee06 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Wed, 10 Jan 2024 15:55:41 +0100
Subject: [PATCH 3/8] Add debug output for initrd
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/eventlog.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/eventlog.c b/src/eventlog.c
index 377f4d6..3574a4d 100644
--- a/src/eventlog.c
+++ b/src/eventlog.c
@@ -877,6 +877,7 @@ __tpm_event_tag_initrd_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *p
}
debug("Next boot entry expected from: %s %s\n", boot_entry->title, boot_entry->version? : "");
+ debug("Measuring initrd: %s\n", boot_entry->initrd_path);
return runtime_digest_efi_file(ctx->algo, boot_entry->initrd_path);
}
From 90ee8dab9d972b741bc0c27a04a872afbecdef82 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Wed, 10 Jan 2024 18:54:04 +0100
Subject: [PATCH 4/8] Add debug output during extension
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/oracle.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/oracle.c b/src/oracle.c
index 1cafafc..0afd910 100644
--- a/src/oracle.c
+++ b/src/oracle.c
@@ -366,6 +366,7 @@ pcr_bank_extend_register(tpm_pcr_bank_t *bank, unsigned int pcr_index, const tpm
static void
predictor_extend_hash(struct predictor *pred, unsigned int pcr_index, const tpm_evdigest_t *d)
{
+ debug("Extend PCR#%d: %s\n", pcr_index, digest_print(d));
pcr_bank_extend_register(&pred->prediction, pcr_index, d);
}
From 5133fe6f3c00a41aee362a51621a278dd472497e Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Thu, 11 Jan 2024 14:09:03 +0100
Subject: [PATCH 5/8] Update the EFI image info before rehash
If the new EFI image is in a new place, the image information stored in
the parsed event should be updated, so the rehash will use this
information instead of the one from the event log.
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/efi-application.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/efi-application.c b/src/efi-application.c
index 2fd33ec..842bca6 100644
--- a/src/efi-application.c
+++ b/src/efi-application.c
@@ -40,7 +40,7 @@
*/
static const tpm_evdigest_t * __tpm_event_efi_bsa_rehash(const tpm_event_t *, const tpm_parsed_event_t *, tpm_event_log_rehash_ctx_t *);
static bool __tpm_event_efi_bsa_extract_location(tpm_parsed_event_t *parsed);
-static bool __tpm_event_efi_bsa_inspect_image(tpm_parsed_event_t *parsed);
+static bool __tpm_event_efi_bsa_inspect_image(struct efi_bsa_event *evspec);
static void
__tpm_event_efi_bsa_destroy(tpm_parsed_event_t *parsed)
@@ -111,7 +111,7 @@ __tpm_event_parse_efi_bsa(tpm_event_t *ev, tpm_parsed_event_t *parsed, buffer_t
assign_string(&ctx->efi_partition, evspec->efi_partition);
else
assign_string(&evspec->efi_partition, ctx->efi_partition);
- __tpm_event_efi_bsa_inspect_image(parsed);
+ __tpm_event_efi_bsa_inspect_image(evspec);
}
return true;
@@ -150,9 +150,8 @@ __tpm_event_efi_bsa_extract_location(tpm_parsed_event_t *parsed)
}
static bool
-__tpm_event_efi_bsa_inspect_image(tpm_parsed_event_t *parsed)
+__tpm_event_efi_bsa_inspect_image(struct efi_bsa_event *evspec)
{
- struct efi_bsa_event *evspec = &parsed->efi_bsa_event;
char path[PATH_MAX];
const char *display_name;
buffer_t *img_data;
@@ -302,6 +301,7 @@ __tpm_event_efi_bsa_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *pars
if (new_application) {
evspec_clone = *evspec;
evspec_clone.efi_application = strdup(new_application);
+ __tpm_event_efi_bsa_inspect_image(&evspec_clone);
evspec = &evspec_clone;
}
}
From 93cbe02ca05297c638b1ac7f32b3da3a6cd2f684 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Thu, 11 Jan 2024 14:35:07 +0100
Subject: [PATCH 6/8] Bump version to 0.5.5
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
configure | 2 +-
microconf/version | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/configure b/configure
index 1dccbdc..854cc0a 100755
--- a/configure
+++ b/configure
@@ -12,7 +12,7 @@
# Invoke with --help for a description of options
#
# microconf:begin
-# version 0.5.4
+# version 0.5.5
# require libtss2
# require json
# disable debug-authenticode
diff --git a/microconf/version b/microconf/version
index 7e913d9..591473f 100644
--- a/microconf/version
+++ b/microconf/version
@@ -1 +1 @@
-uc_version=0.5.4
+uc_version=0.5.5
From e622620a8de5eaf499265adf6c5e8d2ecdaa295b Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Mon, 26 Feb 2024 13:34:13 +0100
Subject: [PATCH 7/8] Add secure boot detector
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
Makefile.in | 3 ++-
src/eventlog.h | 2 ++
src/secure_boot.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 48 insertions(+), 1 deletion(-)
create mode 100644 src/secure_boot.c
diff --git a/Makefile.in b/Makefile.in
index 02a915b..9698253 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34,7 +34,8 @@ ORACLE_SRCS = oracle.c \
store.c \
util.c \
sd-boot.c \
- uapi.c
+ uapi.c \
+ secure_boot.c
ORACLE_OBJS = $(addprefix build/,$(patsubst %.c,%.o,$(ORACLE_SRCS)))
all: $(TOOLS) $(MANPAGES)
diff --git a/src/eventlog.h b/src/eventlog.h
index 3741b58..8af5eb0 100644
--- a/src/eventlog.h
+++ b/src/eventlog.h
@@ -323,4 +323,6 @@ extern bool shim_variable_name_valid(const char *name);
extern const char * shim_variable_get_rtname(const char *name);
extern const char * shim_variable_get_full_rtname(const char *name);
+extern bool secure_boot_enabled();
+
#endif /* EVENTLOG_H */
diff --git a/src/secure_boot.c b/src/secure_boot.c
new file mode 100644
index 0000000..215baa6
--- /dev/null
+++ b/src/secure_boot.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 SUSE LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Written by Alberto Planas <aplanas@suse.com>
+ */
+
+#include <stdio.h>
+#include "bufparser.h"
+#include "runtime.h"
+
+#define SECURE_BOOT_EFIVAR_NAME "SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c"
+
+
+bool
+secure_boot_enabled()
+{
+ buffer_t *data;
+ uint8_t enabled;
+
+ data = runtime_read_efi_variable(SECURE_BOOT_EFIVAR_NAME);
+ if (data == NULL) {
+ return false;
+ }
+
+ if (!buffer_get_u8(data, &enabled)) {
+ return false;
+ }
+
+ return enabled == 1;
+}
From 211502ec5cac7e252f8af251ee34872f7adae9ca Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Mon, 26 Feb 2024 14:52:37 +0100
Subject: [PATCH 8/8] Detect when device path is missing for kernel
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/efi-application.c | 48 ++++++++++++++++++++++++++++++++++++++++---
src/sd-boot.c | 3 +++
2 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/src/efi-application.c b/src/efi-application.c
index 842bca6..1f434fc 100644
--- a/src/efi-application.c
+++ b/src/efi-application.c
@@ -42,6 +42,8 @@ static const tpm_evdigest_t * __tpm_event_efi_bsa_rehash(const tpm_event_t *, co
static bool __tpm_event_efi_bsa_extract_location(tpm_parsed_event_t *parsed);
static bool __tpm_event_efi_bsa_inspect_image(struct efi_bsa_event *evspec);
+static bool __is_shim_issue(const tpm_event_t *ev, const struct efi_bsa_event *evspec);
+
static void
__tpm_event_efi_bsa_destroy(tpm_parsed_event_t *parsed)
{
@@ -114,6 +116,15 @@ __tpm_event_parse_efi_bsa(tpm_event_t *ev, tpm_parsed_event_t *parsed, buffer_t
__tpm_event_efi_bsa_inspect_image(evspec);
}
+ /* When the shim issue is present the efi_application will be
+ * empty. The binary path will be reconstructed with the
+ * --next-kernel parameter, but to generate the full path the
+ * `efi_partition` is needed.
+ */
+ if (__is_shim_issue(ev, evspec))
+ assign_string(&evspec->efi_partition, ctx->efi_partition);
+
+
return true;
}
@@ -273,6 +284,31 @@ efi_application_extract_signer(const tpm_parsed_event_t *parsed)
return authenticode_get_signer(evspec->img_info);
}
+static bool __is_shim_issue(const tpm_event_t *ev, const struct efi_bsa_event *evspec)
+{
+ /* When secure boot is enabled and shim is installed,
+ * systemd-boot installs some security overrides that will
+ * delegate into shim (via shim_validate from systemd-boot)
+ * the validation of the kernel signature.
+ *
+ * The shim_validate function receives the device path from
+ * the firmware, and is used to load the kernel into memory.
+ * At the end call shim_verify from shim, but pass only the
+ * buffer with the loaded image.
+ *
+ * The net result is that the event log
+ * EV_EFI_BOOT_SERVICES_APPLICATION registered by shim_verify
+ * will not contain the device path that pcr-oracle requires
+ * to rehash the binary.
+ *
+ * So far only the kernel is presenting this issue (when
+ * systemd-boot is used, GRUB2 needs to be evaluated), so this
+ * can be detected if there is an event registered in PCR 4
+ * without path.
+ */
+ return (secure_boot_enabled() && ev->pcr_index == 4 && !evspec->efi_application);
+}
+
static const tpm_evdigest_t *
__tpm_event_efi_bsa_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *parsed, tpm_event_log_rehash_ctx_t *ctx)
{
@@ -284,13 +320,19 @@ __tpm_event_efi_bsa_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *pars
* We're not yet prepared to handle these, so we hope the user doesn't mess with them, and
* return the original digest from the event log.
*/
- if (!evspec->efi_application) {
- debug("Unable to locate boot service application - probably not a file\n");
+ if (!evspec->efi_application && !(__is_shim_issue(ev, evspec) && ctx->boot_entry)) {
+ if (__is_shim_issue(ev, evspec) && !ctx->boot_entry)
+ debug("Unable to locate boot service application - missing device path because shim issue");
+ else
+ debug("Unable to locate boot service application - probably not a file\n");
return tpm_event_get_digest(ev, ctx->algo);
}
/* The next boot can have a different kernel */
- if (sdb_is_kernel(evspec->efi_application) && ctx->boot_entry) {
+ if ((sdb_is_kernel(evspec->efi_application) || __is_shim_issue(ev, evspec)) && ctx->boot_entry) {
+ if (__is_shim_issue(ev, evspec))
+ debug("Empty device path for the kernel - building one based on next kernel\n");
+
/* TODO: the parsed data type did not change, so all
* the description correspond to the current event
* log, and not the asset that has been measured. The
diff --git a/src/sd-boot.c b/src/sd-boot.c
index cbdaa49..ede2569 100644
--- a/src/sd-boot.c
+++ b/src/sd-boot.c
@@ -138,6 +138,9 @@ sdb_is_kernel(const char *application)
char *path_copy;
int found = 0;
+ if (!application)
+ return false;
+
match = get_valid_kernel_entry_tokens();
path_copy = strdup(application);

335
fix_grub_bls_cmdline.patch Normal file
View File

@ -0,0 +1,335 @@
From fca4a51b9aac712b3adc5b6b187cc31a8391bcf6 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Fri, 22 Mar 2024 22:44:41 +0100
Subject: [PATCH] GRUB: predict cmdline, linux and initrd lines
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/eventlog.c | 195 ++++++++++++++++++++++++++++++++++++++-----------
src/eventlog.h | 26 ++++---
2 files changed, 169 insertions(+), 52 deletions(-)
diff --git a/src/eventlog.c b/src/eventlog.c
index db18f41..727f6a9 100644
--- a/src/eventlog.c
+++ b/src/eventlog.c
@@ -549,14 +549,66 @@ tpm_event_decode_uuid(const unsigned char *data)
return uuid;
}
+/*
+ * For files residing on the EFI partition, grub usually formats these as
+ * (hdX,gptY)/EFI/BOOT/some.file
+ * Once it has determined the final root device, the device part will be
+ * omitted (eg for kernel and initrd).
+ */
+static bool
+__grub_file_parse(grub_file_t *grub_file, const char *value)
+{
+ if (value[0] == '/') {
+ grub_file->device = NULL;
+ grub_file->path = strdup(value);
+ } else if (value[0] == '(') {
+ char *copy = strdup(value);
+ char *path;
+
+ if ((path = strchr(copy, ')')) == NULL) {
+ free(copy);
+ return false;
+ }
+
+ *path++ = '\0';
+
+ grub_file->device = strdup(copy + 1);
+ grub_file->path = strdup(path);
+ free(copy);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+static const char *
+__grub_file_join(grub_file_t grub_file)
+{
+ static char path[PATH_MAX];
+
+ if (grub_file.device == NULL)
+ snprintf(path, sizeof(path), "%s", grub_file.path);
+ else
+ snprintf(path, sizeof(path), "(%s)%s", grub_file.device, grub_file.path);
+
+ return path;
+}
+
+static void
+__grub_file_destroy(grub_file_t *grub_file)
+{
+ drop_string(&grub_file->device);
+ drop_string(&grub_file->path);
+}
+
/*
* Handle IPL events, which grub2 and sd-boot uses to hide its stuff in
*/
static void
__tpm_event_grub_file_destroy(tpm_parsed_event_t *parsed)
{
- drop_string(&parsed->grub_file.device);
- drop_string(&parsed->grub_file.path);
+ __grub_file_destroy(&parsed->grub_file);
}
const char *
@@ -564,10 +616,7 @@ __tpm_event_grub_file_describe(const tpm_parsed_event_t *parsed)
{
static char buffer[1024];
- if (parsed->grub_file.device == NULL)
- snprintf(buffer, sizeof(buffer), "grub2 file load from %s", parsed->grub_file.path);
- else
- snprintf(buffer, sizeof(buffer), "grub2 file load from (%s)%s", parsed->grub_file.device, parsed->grub_file.path);
+ snprintf(buffer, sizeof(buffer), "grub2 file load from %s", __grub_file_join(parsed->grub_file));
return buffer;
}
@@ -575,7 +624,7 @@ __tpm_event_grub_file_describe(const tpm_parsed_event_t *parsed)
static const tpm_evdigest_t *
__tpm_event_grub_file_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *parsed, tpm_event_log_rehash_ctx_t *ctx)
{
- const struct grub_file_event *evspec = &parsed->grub_file;
+ const grub_file_event *evspec = &parsed->grub_file;
const tpm_evdigest_t *md = NULL;
debug(" re-hashing %s\n", __tpm_event_grub_file_describe(parsed));
@@ -606,35 +655,11 @@ __tpm_event_grub_file_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *pa
return md;
}
-/*
- * For files residing on the EFI partition, grub usually formats these as
- * (hdX,gptY)/EFI/BOOT/some.file
- * Once it has determined the final root device, the device part will be
- * omitted (eg for kernel and initrd).
- */
static bool
__tpm_event_grub_file_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed, const char *value)
{
- if (value[0] == '/') {
- parsed->grub_file.device = NULL;
- parsed->grub_file.path = strdup(value);
- } else if (value[0] == '(') {
- char *copy = strdup(value);
- char *path;
-
- if ((path = strchr(copy, ')')) == NULL) {
- free(copy);
- return false;
- }
-
- *path++ = '\0';
-
- parsed->grub_file.device = strdup(copy + 1);
- parsed->grub_file.path = strdup(path);
- free(copy);
- } else {
+ if (!__grub_file_parse(&parsed->grub_file, value))
return false;
- }
parsed->event_subtype = GRUB_EVENT_FILE;
parsed->destroy = __tpm_event_grub_file_destroy;
@@ -658,21 +683,87 @@ static const char *
__tpm_event_grub_command_describe(const tpm_parsed_event_t *parsed)
{
static char buffer[128];
+ static char *topic = NULL;
+
+ switch (parsed->event_subtype) {
+ case GRUB_EVENT_COMMAND:
+ topic = "grub2 command";
+ break;
+ case GRUB_EVENT_COMMAND_LINUX:
+ topic = "grub2 linux command";
+ break;
+ case GRUB_EVENT_COMMAND_INITRD:
+ topic = "grub2 initrd command";
+ break;
+ case GRUB_EVENT_KERNEL_CMDLINE:
+ topic = "grub2 kernel cmdline";
+ break;
+ }
+
+ snprintf(buffer, sizeof(buffer), "%s \"%s\"", topic, parsed->grub_command.string);
- if (parsed->event_subtype == GRUB_EVENT_COMMAND)
- snprintf(buffer, sizeof(buffer), "grub2 command \"%s\"", parsed->grub_command.string);
- else
- snprintf(buffer, sizeof(buffer), "grub2 kernel cmdline \"%s\"", parsed->grub_command.string);
return buffer;
}
static const tpm_evdigest_t *
__tpm_event_grub_command_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *parsed, tpm_event_log_rehash_ctx_t *ctx)
{
- if (parsed->grub_command.string == NULL)
- return NULL;
+ char *str = NULL;
+ size_t sz = 0;
+ const tpm_evdigest_t *digest = NULL;
+ grub_file_t file;
+
+ switch (parsed->event_subtype) {
+ case GRUB_EVENT_COMMAND:
+ str = strdup(parsed->grub_command.string);
+ break;
+ case GRUB_EVENT_COMMAND_LINUX:
+ if (ctx->boot_entry && parsed->grub_command.file.path) {
+ file = (grub_file_t) {
+ .device = parsed->grub_command.file.device,
+ .path = ctx->boot_entry->image_path,
+ };
+ sz = snprintf(NULL, 0, "linux %s %s", __grub_file_join(file), ctx->boot_entry->options);
+ str = malloc(sz + 1);
+ snprintf(str, sz + 1, "linux %s %s", __grub_file_join(file), ctx->boot_entry->options);
+ debug("Hashed linux command: %s\n", str);
+ } else
+ str = strdup(parsed->grub_command.string);
+ break;
+ case GRUB_EVENT_COMMAND_INITRD:
+ if (ctx->boot_entry && parsed->grub_command.file.path) {
+ file = (grub_file_t) {
+ .device = parsed->grub_command.file.device,
+ .path = ctx->boot_entry->initrd_path,
+ };
+ sz = snprintf(NULL, 0, "initrd %s", __grub_file_join(file));
+ str = malloc(sz + 1);
+ snprintf(str, sz + 1, "initrd %s", __grub_file_join(file));
+ debug("Hashed initrd command: %s\n", str);
+ } else
+ str = strdup(parsed->grub_command.string);
+ break;
+ case GRUB_EVENT_KERNEL_CMDLINE:
+ if (ctx->boot_entry && parsed->grub_command.file.path) {
+ file = (grub_file_t) {
+ .device = parsed->grub_command.file.device,
+ .path = ctx->boot_entry->image_path,
+ };
+ sz = snprintf(NULL, 0, "%s %s", __grub_file_join(file), ctx->boot_entry->options);
+ str = malloc(sz + 1);
+ snprintf(str, sz + 1, "%s %s", __grub_file_join(file), ctx->boot_entry->options);
+ debug("Hashed kernel cmdline: %s\n", str);
+ } else
+ str = strdup(parsed->grub_command.string);
+ break;
+ }
+
+ if (str) {
+ digest = digest_compute(ctx->algo, str, strlen(str));
+ free(str);
+ }
- return digest_compute(ctx->algo, parsed->grub_command.string, strlen(parsed->grub_command.string));
+ return digest;
}
/*
@@ -703,15 +794,29 @@ __tpm_event_grub_command_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed
keyword = copy;
arg = copy + wordlen;
+ if (!strcmp(keyword, "grub_cmd") && !strncmp(arg, "linux", strlen("linux"))) {
+ for (wordlen = 0; (cc = arg[wordlen]) && (cc != ' '); ++wordlen)
+ ;
+ if (arg[wordlen] == ' ' && !__grub_file_parse(&parsed->grub_command.file, arg + wordlen + 1))
+ goto failed;
+ parsed->event_subtype = GRUB_EVENT_COMMAND_LINUX;
+ } else
+ if (!strcmp(keyword, "grub_cmd") && !strncmp(arg, "initrd", strlen("initrd"))) {
+ for (wordlen = 0; (cc = arg[wordlen]) && (cc != ' '); ++wordlen)
+ ;
+ if (arg[wordlen] == ' ' && !__grub_file_parse(&parsed->grub_command.file, arg + wordlen + 1))
+ goto failed;
+ parsed->event_subtype = GRUB_EVENT_COMMAND_INITRD;
+ } else
if (!strcmp(keyword, "grub_cmd")) {
parsed->event_subtype = GRUB_EVENT_COMMAND;
} else
if (!strcmp(keyword, "kernel_cmdline")) {
+ if (!__grub_file_parse(&parsed->grub_command.file, arg))
+ goto failed;
parsed->event_subtype = GRUB_EVENT_KERNEL_CMDLINE;
- } else {
- free(copy);
- return false;
- }
+ } else
+ goto failed;
parsed->grub_command.string = strdup(arg);
for (argc = 0, s = strtok(arg, " \t"); s && argc < GRUB_COMMAND_ARGV_MAX - 1; s = strtok(NULL, " \t")) {
@@ -725,6 +830,10 @@ __tpm_event_grub_command_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed
free(copy);
return true;
+
+failed:
+ free(copy);
+ return false;
}
static void
diff --git a/src/eventlog.h b/src/eventlog.h
index d142744..6a8c3a4 100644
--- a/src/eventlog.h
+++ b/src/eventlog.h
@@ -89,10 +89,12 @@ enum {
enum {
/* IPL subtypes for grub */
GRUB_EVENT_COMMAND = 0x0001,
- GRUB_EVENT_FILE = 0x0002,
- GRUB_EVENT_KERNEL_CMDLINE = 0x0003,
- SHIM_EVENT_VARIABLE = 0x0004,
- SYSTEMD_EVENT_VARIABLE = 0x0005,
+ GRUB_EVENT_COMMAND_LINUX = 0x0002,
+ GRUB_EVENT_COMMAND_INITRD = 0x0003,
+ GRUB_EVENT_FILE = 0x0004,
+ GRUB_EVENT_KERNEL_CMDLINE = 0x0005,
+ SHIM_EVENT_VARIABLE = 0x0006,
+ SYSTEMD_EVENT_VARIABLE = 0x0007,
};
enum {
@@ -208,6 +210,13 @@ typedef struct tpm_event_log_rehash_ctx {
#define GRUB_COMMAND_ARGV_MAX 32
+typedef struct grub_file {
+ char * device;
+ char * path;
+} grub_file_t;
+
+typedef grub_file_t grub_file_event;
+
/*
* Parsed event types
*/
@@ -247,13 +256,12 @@ typedef struct tpm_parsed_event {
/* for GRUB_COMMAND, GRUB_KERNEL_CMDLINE */
struct grub_command_event {
char * string;
- char * argv[GRUB_COMMAND_ARGV_MAX];
+ char * argv[GRUB_COMMAND_ARGV_MAX];
+ grub_file_t file;
} grub_command;
- struct grub_file_event {
- char * device;
- char * path;
- } grub_file;
+ /* for GRUB_FILE */
+ grub_file_event grub_file;
struct shim_event {
char * string;

188
fix_grub_bls_entry.patch Normal file
View File

@ -0,0 +1,188 @@
From b0c4c5fbdcc89b44cee2300c5a12cb5e8de0e446 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Wed, 13 Mar 2024 22:57:17 +0100
Subject: [PATCH] GRUB with BLS measure boot entries
This includes the boot entry file, the kernel and the initrd specified
in the entry file.
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/eventlog.c | 21 +++++++++++++++++++--
src/eventlog.h | 1 +
src/oracle.c | 12 +++++++++---
src/sd-boot.c | 28 ++++++++++++++++++++++++----
src/sd-boot.h | 2 ++
src/uapi.h | 3 ++-
6 files changed, 57 insertions(+), 10 deletions(-)
diff --git a/src/eventlog.c b/src/eventlog.c
index 3574a4d..db18f41 100644
--- a/src/eventlog.c
+++ b/src/eventlog.c
@@ -33,6 +33,7 @@
#include "digest.h"
#include "util.h"
#include "uapi.h"
+#include "sd-boot.h"
#define TPM_EVENT_LOG_MAX_ALGOS 64
@@ -582,8 +583,24 @@ __tpm_event_grub_file_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *pa
debug(" assuming the file resides on system partition\n");
md = runtime_digest_rootfs_file(ctx->algo, evspec->path);
} else {
- debug(" assuming the file resides on EFI boot partition\n");
- md = runtime_digest_efi_file(ctx->algo, evspec->path);
+ if (sdb_is_boot_entry(evspec->path) && ctx->boot_entry_path) {
+ debug(" getting different boot entry file from EFI boot partition: %s\n",
+ ctx->boot_entry_path);
+ md = runtime_digest_rootfs_file(ctx->algo, ctx->boot_entry_path);
+ } else
+ if (sdb_is_kernel(evspec->path) && ctx->boot_entry) {
+ debug(" getting different kernel from EFI boot partition: %s\n",
+ ctx->boot_entry->image_path);
+ md = runtime_digest_efi_file(ctx->algo, ctx->boot_entry->image_path);
+ } else
+ if (sdb_is_initrd(evspec->path) && ctx->boot_entry) {
+ debug(" getting different initrd from EFI boot partition: %s\n",
+ ctx->boot_entry->initrd_path);
+ md = runtime_digest_efi_file(ctx->algo, ctx->boot_entry->initrd_path);
+ } else {
+ debug(" assuming the file resides on EFI boot partition\n");
+ md = runtime_digest_efi_file(ctx->algo, evspec->path);
+ }
}
return md;
diff --git a/src/eventlog.h b/src/eventlog.h
index 8af5eb0..d142744 100644
--- a/src/eventlog.h
+++ b/src/eventlog.h
@@ -202,6 +202,7 @@ typedef struct tpm_event_log_rehash_ctx {
const pecoff_image_info_t *next_stage_img;
/* This get set when the user specifies --next-kernel */
+ char * boot_entry_path;
uapi_boot_entry_t * boot_entry;
} tpm_event_log_rehash_ctx_t;
diff --git a/src/oracle.c b/src/oracle.c
index 0afd910..ac48823 100644
--- a/src/oracle.c
+++ b/src/oracle.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <limits.h>
#include "oracle.h"
#include "util.h"
@@ -653,6 +654,7 @@ predictor_update_eventlog(struct predictor *pred)
tpm_event_log_rehash_ctx_t rehash_ctx;
tpm_event_t *ev, *stop_event = NULL;
bool okay = true;
+ char boot_entry_path[PATH_MAX];
predictor_pre_scan_eventlog(pred, &stop_event);
@@ -663,9 +665,13 @@ predictor_update_eventlog(struct predictor *pred)
* systemd ID of the next kernel entry to be booted.
* FIXME: we should probably hide this behind a target_platform function.
*/
- if (pred->boot_entry_id != NULL
- && !(rehash_ctx.boot_entry = sdb_identify_boot_entry(pred->boot_entry_id)))
- fatal("unable to identify next kernel \"%s\"\n", pred->boot_entry_id);
+ if (pred->boot_entry_id != NULL) {
+ snprintf(boot_entry_path, sizeof(boot_entry_path),
+ "%s/%s", UAPI_BOOT_DIRECTORY, pred->boot_entry_id);
+ assign_string(&rehash_ctx.boot_entry_path, boot_entry_path);
+ if (!(rehash_ctx.boot_entry = sdb_identify_boot_entry(pred->boot_entry_id)))
+ fatal("unable to identify next kernel \"%s\"\n", pred->boot_entry_id);
+ }
for (ev = pred->event_log; ev; ev = ev->next) {
tpm_evdigest_t *pcr;
diff --git a/src/sd-boot.c b/src/sd-boot.c
index ede2569..a16f814 100644
--- a/src/sd-boot.c
+++ b/src/sd-boot.c
@@ -130,10 +130,9 @@ get_valid_kernel_entry_tokens(void)
/*
* This should probably use UAPI boot entry logic as well
*/
-bool
-sdb_is_kernel(const char *application)
+static bool
+is_valid_entry_token(const char *application, const char *prefix)
{
- static const char prefix[] = "linux-";
const uapi_kernel_entry_tokens_t *match;
char *path_copy;
int found = 0;
@@ -151,7 +150,7 @@ sdb_is_kernel(const char *application)
if (!strcmp(ptr, token))
found |= 1;
- else if (!strncmp(ptr, prefix, sizeof(prefix) - 1))
+ else if (!strncmp(ptr, prefix, strlen(prefix)))
found |= 2;
}
}
@@ -160,6 +159,27 @@ sdb_is_kernel(const char *application)
return (found == 3);
}
+bool
+sdb_is_kernel(const char *application)
+{
+ return is_valid_entry_token(application, "linux-");
+}
+
+bool
+sdb_is_initrd(const char *application)
+{
+ return is_valid_entry_token(application, "initrd-");
+}
+
+bool
+sdb_is_boot_entry(const char *application)
+{
+ if (!application)
+ return false;
+
+ return !strncmp(application, UAPI_BOOT_DIRECTORY_EFI, sizeof(UAPI_BOOT_DIRECTORY_EFI) - 1);
+}
+
/*
* Identify the next kernel and initrd given an ID
*/
diff --git a/src/sd-boot.h b/src/sd-boot.h
index 0472320..ceab13d 100644
--- a/src/sd-boot.h
+++ b/src/sd-boot.h
@@ -43,7 +43,9 @@ typedef struct sdb_entry_list {
} sdb_entry_list_t;
extern uapi_boot_entry_t * sdb_identify_boot_entry(const char *id);
+extern bool sdb_is_boot_entry(const char *application);
extern bool sdb_is_kernel(const char *application);
+extern bool sdb_is_initrd(const char *application);
/* This will have to update the systemd json file, and add a new entry. */
extern bool sdb_policy_file_add_entry(const char *filename,
diff --git a/src/uapi.h b/src/uapi.h
index 96ca7ed..8bcb94f 100644
--- a/src/uapi.h
+++ b/src/uapi.h
@@ -41,7 +41,8 @@ typedef struct uapi_kernel_entry_tokens {
char * entry_token[UAPI_MAX_ENTRY_TOKENS];
} uapi_kernel_entry_tokens_t;
-#define UAPI_BOOT_DIRECTORY "/boot/efi/loader/entries"
+#define UAPI_BOOT_DIRECTORY_EFI "/loader/entries"
+#define UAPI_BOOT_DIRECTORY "/boot/efi" UAPI_BOOT_DIRECTORY_EFI
extern uapi_boot_entry_t * uapi_get_boot_entry(const char *id);
extern uapi_boot_entry_t * uapi_find_boot_entry(const uapi_kernel_entry_tokens_t *match, const char *machine_id);

79
fix_loader_conf.patch Normal file
View File

@ -0,0 +1,79 @@
From c2453df75ecdbc547e4637268dccde5cdc012881 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Tue, 20 Feb 2024 19:12:08 +0100
Subject: [PATCH] Measure systemd-boot loader.conf
Since systemd-boot v255 the /loader/loader.conf file can be measured
under a EV_EVENT_TAG event in PCR#5.
This commit measure the file in the ESP.
Fix #49
Signed-off-by: Alberto Planas <aplanas@suse.com>
---
src/eventlog.c | 18 ++++++++++++++++++
src/eventlog.h | 7 +++++--
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/src/eventlog.c b/src/eventlog.c
index 4277d42..2e29b0e 100644
--- a/src/eventlog.c
+++ b/src/eventlog.c
@@ -842,6 +842,19 @@ __tpm_event_tag_destroy(tpm_parsed_event_t *parsed)
{
}
+static const char *
+__tpm_event_tag_loader_conf_describe(const tpm_parsed_event_t *parsed)
+{
+ return "/loader/loader.conf (measured by systemd-boot)";
+}
+
+static const tpm_evdigest_t *
+__tpm_event_tag_loader_conf_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *parsed, tpm_event_log_rehash_ctx_t *ctx)
+{
+ debug(" re-hashing /loader/loader.conf");
+ return runtime_digest_efi_file(ctx->algo, "/loader/loader.conf");
+}
+
static const char *
__tpm_event_tag_options_describe(const tpm_parsed_event_t *parsed)
{
@@ -880,6 +893,7 @@ __tpm_event_tag_initrd_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *p
}
/*
+ * Generated by systemd-boot (PCR#5), to measure loader.conf
* Generated by the kernel (PCR#9), to measure the cmdline and initrd
*/
static bool
@@ -900,6 +914,10 @@ __tpm_event_parse_tag(tpm_event_t *ev, tpm_parsed_event_t *parsed, buffer_t *bp)
return false;
parsed->destroy = __tpm_event_tag_destroy;
+ if (evspec->event_id == LOADER_CONF_EVENT_TAG_ID) {
+ parsed->rehash = __tpm_event_tag_loader_conf_rehash;
+ parsed->describe = __tpm_event_tag_loader_conf_describe;
+ } else
if (evspec->event_id == LOAD_OPTIONS_EVENT_TAG_ID) {
parsed->rehash = __tpm_event_tag_options_rehash;
parsed->describe = __tpm_event_tag_options_describe;
diff --git a/src/eventlog.h b/src/eventlog.h
index 3741b58..d78e3da 100644
--- a/src/eventlog.h
+++ b/src/eventlog.h
@@ -96,8 +96,11 @@ enum {
};
enum {
- LOAD_OPTIONS_EVENT_TAG_ID = 0x8F3B22EDU,
- INITRD_EVENT_TAG_ID = 0x8F3B22ECU,
+ /* systemd-boot */
+ LOADER_CONF_EVENT_TAG_ID = 0xF5BC582A,
+ /* kernel */
+ LOAD_OPTIONS_EVENT_TAG_ID = 0x8F3B22ED,
+ INITRD_EVENT_TAG_ID = 0x8F3B22EC,
};
#define EFI_DEVICE_PATH_MAX 16

3
pcr-oracle-0.5.4.tar.xz Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:130085dbd77b8e4001356cbe9411829228eb29cdd6f14931aea5ecb57c75a2e6
size 81828

179
pcr-oracle.changes Normal file
View File

@ -0,0 +1,179 @@
-------------------------------------------------------------------
Mon Aug 5 06:11:52 UTC 2024 - Gary Ching-Pang Lin <glin@suse.com>
- Add support-ecc-srk.patch to support ECC SRK
- Add fix-testcase-empty-efi-variables.patch to fix the testcase
playback on empty EFI variables
-------------------------------------------------------------------
Mon Mar 25 20:16:53 UTC 2024 - Alberto Planas Dominguez <aplanas@suse.com>
- Add fix_grub_bls_cmdline.patch to include the measurements of the
cmdline and the linux and initrd grub commands
-------------------------------------------------------------------
Thu Mar 14 10:33:23 UTC 2024 - Alberto Planas Dominguez <aplanas@suse.com>
- Add fix_grub_bls_entry.patch to measure boot entries in GRUB BLS
-------------------------------------------------------------------
Mon Feb 26 15:14:37 UTC 2024 - Alberto Planas Dominguez <aplanas@suse.com>
- Remove fix_efi_measure.patch
- Add fix_efi_measure_and_shim.patch (bsc#1219807)
-------------------------------------------------------------------
Tue Feb 20 18:16:53 UTC 2024 - Alberto Planas Dominguez <aplanas@suse.com>
- Add fix_loader_conf.patch to measure the systemd-boot loader.conf file
-------------------------------------------------------------------
Fri Jan 12 07:28:55 UTC 2024 - Alberto Planas Dominguez <aplanas@suse.com>
- Add fix_efi_measure.patch to fix the measurement of EFI binaries
-------------------------------------------------------------------
Fri Dec 8 07:17:35 UTC 2023 - Gary Ching-Pang Lin <glin@suse.com>
- Update to 0.5.4
- Improve systemd-boot support
- Add --boot-entry for systemd-boot
- Manpage fixes
- Fix PCR index in JSON file
- Fix GrubPcrSnapshot parsing
- Drop upstreamed patches: boot_entry.patch and fix_pcr_index.patch
-------------------------------------------------------------------
Wed Nov 29 15:56:39 UTC 2023 - Alberto Planas Dominguez <aplanas@suse.com>
- Update to 0.5.3
- Improve documentation
- Detect key format store via extension
- Replace --key-format and --policy-format options with a single
--target-platform option
- The json file can contain multiple predictions
- Remove fix_rsa.patch as is already upstream
- Add boot_entry.patch to add new parameter to point to a new systemd
boot entry
- Add fix_pcr_index.patch to fix the PCR index number in the JSON file
-------------------------------------------------------------------
Mon Nov 20 10:24:32 UTC 2023 - Alberto Planas Dominguez <aplanas@suse.com>
- Add fix_rsa.patch to support the export in PEM format of the public
key
-------------------------------------------------------------------
Mon Nov 20 10:16:20 UTC 2023 - Alberto Planas Dominguez <aplanas@suse.com>
- FAPI is not present until tpm2-tss >= 2.4.0. Express that in the
BuildRequirement
-------------------------------------------------------------------
Wed Nov 15 20:54:57 UTC 2023 - Alberto Planas Dominguez <aplanas@suse.com>
- Update to 0.5.2
- Support EV_EVENT_TAG events from the kernel (PCR9 for the cmdline
and the kernel)
- Fix cmdline measurements
- Update to 0.5.1
- Measure the kernel as an EFI binary (PCR4)
-------------------------------------------------------------------
Mon Nov 13 10:53:20 UTC 2023 - Alberto Planas Dominguez <aplanas@suse.com>
- Update to 0.5.0
- Support systemd-cryptenroll JSON files
- Generate RSA keys in more scenarios
- Select RSA key size
- Drop systemd-boot.patch (already present in upstream)
-------------------------------------------------------------------
Thu Oct 19 11:01:10 UTC 2023 - Alberto Planas Dominguez <aplanas@suse.com>
- Add systemd-boot.patch to support systemd-cryptenroll JSON files
-------------------------------------------------------------------
Wed Jul 26 14:06:43 UTC 2023 - Gary Ching-Pang Lin <glin@suse.com>
- Add libtss2-tcti-device0 as the default TCTI interface to avoid
the following error:
Esys_Initialize() Initialize default tcti. ErrorCode (0x000a000a)
-------------------------------------------------------------------
Tue Jul 4 07:44:10 UTC 2023 - Olaf Kirch <okir@suse.com>
- Added a _service file
- BuildRequire libopenssl-devel rather than openssl
- Updated to version 0.4.6:
- recognize SOURCE_DATE_EPOCH for reproducible builds
- Remove authorized policy file from the unseal action
- Unseal the data without calling __pcr_policy_make()
- Skip the variable event with 0 length (#26)
- Add the new parameter: policy-name (#27)
- Skip the leading operators when matching grub2 commands (#28)
- microconf change: force rebuilding the sed script
-------------------------------------------------------------------
Mon Jun 5 07:45:13 UTC 2023 - Gary Ching-Pang Lin <glin@suse.com>
- Update to version 0.4.5
- update manpage to reflect added support of unseal w/ tpm2.0 key
format
- Implement unseal for TPM 2.0 Key File
- Update manpage to describe the new key-format switch
- Add TPM 2.0 Key File support to 'seal-secret' and 'sign'
- Add comment to SRK template regarding NODA flag.
- pcr-oracle.8: add a section on pcr policy sealing
- Add self-test subcommand to pcr-oracle
- Rename __tss_check_error -> tss_check_error
- Moved two tss related functions to a file of their own
- Add test-pcr.sh script
- Use the same SRK template as the one in grub2
- Implement seal/unseal using a regular PCR policy
- When displaying the DevicePath, print ACPI PNP ids
- Handle failure to read EFI variables more gracefully
- Gracefully handle AUTHORITY events for eg driver BSAs that
reside in ROM
- efi-variable rehash: break out the code to detect how the
firmware hashed the event
-------------------------------------------------------------------
Thu Jun 1 07:07:04 UTC 2023 - Marcus Meissner <meissner@suse.com>
- build with optflags, remove unneeded clean section, macro bindir
-------------------------------------------------------------------
Mon Jan 16 08:52:50 UTC 2023 - Olaf Kirch <okir@suse.com>
- Updated to version 0.4.2
-------------------------------------------------------------------
Thu Jan 5 13:54:40 UTC 2023 - Michal Suchanek <msuchanek@suse.com>
- Fix project URL
-------------------------------------------------------------------
Wed Jan 4 11:50:54 UTC 2023 - Olaf Kirch <okir@suse.com>
- add --rsa-generate-key option
-------------------------------------------------------------------
Tue Jan 3 15:00:08 UTC 2023 - Olaf Kirch <okir@suse.com>
- Updated to version 0.4.1:
- disable debug messages from authenticode PECOFF parser
- add --tpm-eventlog option
- add manpage
-------------------------------------------------------------------
Mon Jan 2 16:36:29 UTC 2023 - Olaf Kirch <okir@suse.com>
- Updated to version 0.4:
- drop the dependency on tss2 fapi
- introduce authorized policies
-------------------------------------------------------------------
Tue Nov 8 11:18:07 UTC 2022 - Olaf Kirch <okir@suse.com>
- Establish pcr-oracle as standalone package, apart from fde-tools

72
pcr-oracle.spec Normal file
View File

@ -0,0 +1,72 @@
#
# spec file for package pcr-oracle
#
# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
# needssslcertforbuild
Name: pcr-oracle
Version: 0.5.4
Release: 0
Summary: Predict TPM PCR values
License: GPL-2.0-only
Group: System/Boot
URL: https://github.com/okirch/pcr-oracle
Source: %{name}-%{version}.tar.xz
# PATCH-FIX-UPSTREAM fix_efi_measure_and_shim.patch gh#okirch/pcr-oracle!47
# PATCH-FIX-UPSTREAM fix_efi_measure_and_shim.patch gh#okirch/pcr-oracle!51
Patch0: fix_efi_measure_and_shim.patch
# PATCH-FIX-UPSTREAM fix_loader_conf.patch gh#okirch/pcr-oracle!50
Patch1: fix_loader_conf.patch
# PATCH-FIX-UPSTREAM fix_grub_bls_entry.patch gh#okirch/pcr-oracle!52
Patch2: fix_grub_bls_entry.patch
# PATCH-FIX-UPSTREAM fix_grub_bls_cmdline.patch gh#okirch/pcr-oracle!52 (cont)
Patch3: fix_grub_bls_cmdline.patch
# PATCH-FIX-UPSTREAM support-ecc-srk.patch gh#okirch/pcr-oracle!56
Patch4: support-ecc-srk.patch
# PATCH-FIX-UPSTREAM fix-testcase-empty-efi-variables.patch gh#okirch/pcr-oracle!58
Patch5: fix-testcase-empty-efi-variables.patch
BuildRequires: libopenssl-devel >= 0.9.8
BuildRequires: tpm2-0-tss-devel >= 2.4.0
Requires: libtss2-tcti-device0
ExclusiveArch: x86_64 aarch64 ppc64le riscv64
%description
This utility tries to predict the values of the TPM's Platform
Configuration Registers following an update of system components
like shim, grub, etc.
%prep
%autosetup -p1
%build
# beware, this is not autoconf
./configure --prefix /usr
make CCOPT="%optflags"
%install
make install DESTDIR=%{buildroot}
install -d %{buildroot}/%{_bindir}
mv %{buildroot}/bin/pcr-oracle %{buildroot}/%{_bindir}
rmdir %{buildroot}/bin
%files
%defattr(-,root,root)
%doc README.md
%doc test-authorized.sh
%{_bindir}/pcr-oracle
%{_mandir}/man8/pcr-oracle.8*
%changelog

413
support-ecc-srk.patch Normal file
View File

@ -0,0 +1,413 @@
From 60ce42dbf61ce89012d9bc71c92c5cc92759b02c Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 3 Apr 2024 14:41:49 +0800
Subject: [PATCH 1/3] Update the comment for SRK template
USERWITHAUTH and NODA are set according to "TCG TPM v2.0 Provisioning
Guidance". This commit updates the comment to add the reference.
Signed-off-by: Gary Lin <glin@suse.com>
---
src/pcr-policy.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/pcr-policy.c b/src/pcr-policy.c
index 8f2c42c..f03b6e0 100644
--- a/src/pcr-policy.c
+++ b/src/pcr-policy.c
@@ -67,8 +67,9 @@ static TPM2B_PUBLIC SRK_template = {
.publicArea = {
.type = TPM2_ALG_RSA,
.nameAlg = TPM2_ALG_SHA256,
- /* For reasons not clear to me, grub2 derives the SRK using the NODA attribute,
- * which means it is not subject to dictionary attack protections. */
+ /* Per "Storage Primary Key (SRK) Templates" in section 7.5.1 of
+ * TCG TPM v2.0 Provisioning Guidance 1.0 Revision 1.0, the
+ * template for shared SRKs sets USERWITHAUTH and NODA. */
.objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT \
|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT \
|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH \
--
2.35.3
From 0085c5a6a47f433dc69739c54b9db11796aff62e Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 10 Apr 2024 16:20:44 +0800
Subject: [PATCH 2/3] Support SRK template with ECC_NIST_P256
When sealing data with SRK, the data is actually encrypted with the
symmetric key, and the selection of the asymmetric algorithm is only
a parameter for KDF to derive the symmetric key. Compared with RSA,
ECC NIST-P256 provides the faster key generation, so it's a better
choice for the SRK template in general.
This commit adds a new option, '--ecc-srk', to switch the default SRK
template from the RSA one to the ECC one, so that the user can specify
the SRK template when sealing/unsealing data.
Signed-off-by: Gary Lin <glin@suse.com>
---
src/oracle.c | 7 +++++++
src/pcr-policy.c | 44 +++++++++++++++++++++++++++++++++++++++++---
src/pcr.h | 1 +
3 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/src/oracle.c b/src/oracle.c
index 1cafafc..f391430 100644
--- a/src/oracle.c
+++ b/src/oracle.c
@@ -92,6 +92,7 @@ enum {
OPT_RSA_PUBLIC_KEY,
OPT_RSA_GENERATE_KEY,
OPT_RSA_BITS,
+ OPT_ECC_SRK,
OPT_INPUT,
OPT_OUTPUT,
OPT_AUTHORIZED_POLICY,
@@ -125,6 +126,7 @@ static struct option options[] = {
{ "public-key", required_argument, 0, OPT_RSA_PUBLIC_KEY },
{ "rsa-generate-key", no_argument, 0, OPT_RSA_GENERATE_KEY },
{ "rsa-bits", required_argument, 0, OPT_RSA_BITS },
+ { "ecc-srk", no_argument, 0, OPT_ECC_SRK },
{ "input", required_argument, 0, OPT_INPUT },
{ "output", required_argument, 0, OPT_OUTPUT },
{ "authorized-policy", required_argument, 0, OPT_AUTHORIZED_POLICY },
@@ -1042,6 +1044,8 @@ main(int argc, char **argv)
unsigned int rsa_bits = 2048;
int c, exit_code = 0;
+ set_srk_alg("RSA");
+
while ((c = getopt_long(argc, argv, "dhA:CF:LSZ", options, NULL)) != EOF) {
switch (c) {
case 'A':
@@ -1109,6 +1113,9 @@ main(int argc, char **argv)
case OPT_RSA_BITS:
opt_rsa_bits = optarg;
break;
+ case OPT_ECC_SRK:
+ set_srk_alg("ECC");
+ break;
case OPT_INPUT:
opt_input = optarg;
break;
diff --git a/src/pcr-policy.c b/src/pcr-policy.c
index f03b6e0..f65becf 100644
--- a/src/pcr-policy.c
+++ b/src/pcr-policy.c
@@ -62,7 +62,7 @@ struct target_platform {
const stored_key_t *public_key_file);
};
-static TPM2B_PUBLIC SRK_template = {
+static TPM2B_PUBLIC RSA_SRK_template = {
.size = sizeof(TPMT_PUBLIC),
.publicArea = {
.type = TPM2_ALG_RSA,
@@ -88,6 +88,35 @@ static TPM2B_PUBLIC SRK_template = {
}
};
+static TPM2B_PUBLIC ECC_SRK_template = {
+ .size = sizeof(TPMT_PUBLIC),
+ .publicArea = {
+ .type = TPM2_ALG_ECC,
+ .nameAlg = TPM2_ALG_SHA256,
+ /* Per "Storage Primary Key (SRK) Templates" in section 7.5.1 of
+ * TCG TPM v2.0 Provisioning Guidance 1.0 Revision 1.0, the
+ * template for shared SRKs sets USERWITHAUTH and NODA. */
+ .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT \
+ |TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT \
+ |TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH \
+ |TPMA_OBJECT_NODA,
+ .parameters = {
+ .eccDetail = {
+ .symmetric = {
+ .algorithm = TPM2_ALG_AES,
+ .keyBits = { .sym = 128 },
+ .mode = { .sym = TPM2_ALG_CFB },
+ },
+ .scheme = { TPM2_ALG_NULL },
+ .curveID = TPM2_ECC_NIST_P256,
+ .kdf.scheme = TPM2_ALG_NULL
+ }
+ }
+ }
+};
+
+static const TPM2B_PUBLIC *SRK_template;
+
static const TPM2B_PUBLIC seal_public_template = {
.size = sizeof(TPMT_PUBLIC),
.publicArea = {
@@ -107,10 +136,19 @@ static const TPM2B_PUBLIC seal_public_template = {
}
};
+void
+set_srk_alg (const char *alg)
+{
+ if (strcmp(alg, "RSA") == 0)
+ SRK_template = &RSA_SRK_template;
+ else
+ SRK_template = &ECC_SRK_template;
+}
+
void
set_srk_rsa_bits (const unsigned int rsa_bits)
{
- SRK_template.publicArea.parameters.rsaDetail.keyBits = rsa_bits;
+ RSA_SRK_template.publicArea.parameters.rsaDetail.keyBits = rsa_bits;
}
static inline const tpm_evdigest_t *
@@ -609,7 +647,7 @@ esys_create_primary(ESYS_CONTEXT *esys_context, ESYS_TR *handle_ret)
t0 = timing_begin();
rc = Esys_CreatePrimary(esys_context, ESYS_TR_RH_OWNER,
ESYS_TR_PASSWORD,
- ESYS_TR_NONE, ESYS_TR_NONE, &in_sensitive, &SRK_template,
+ ESYS_TR_NONE, ESYS_TR_NONE, &in_sensitive, SRK_template,
NULL, &creation_pcr, handle_ret,
NULL, NULL,
NULL, NULL);
diff --git a/src/pcr.h b/src/pcr.h
index 4d8f816..f1dc9af 100644
--- a/src/pcr.h
+++ b/src/pcr.h
@@ -39,6 +39,7 @@ typedef struct tpm_pcr_selection {
const tpm_algo_info_t * algo_info;
} tpm_pcr_selection_t;
+extern void set_srk_alg (const char *alg);
extern void set_srk_rsa_bits (const unsigned int rsa_bits);
extern void pcr_bank_initialize(tpm_pcr_bank_t *bank, unsigned int pcr_mask, const tpm_algo_info_t *algo);
extern bool pcr_bank_wants_pcr(tpm_pcr_bank_t *bank, unsigned int index);
--
2.35.3
From 207bd496868d65455e63aa9586bfc6e02900a4a1 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 24 Apr 2024 14:53:25 +0800
Subject: [PATCH 3/3] Update to conform the latest TPM 2.0 Key File
For TPM 2.0 Key File, the default asymmetric algorithm of SRK is ECC
NIST-P256, not RSA 2048. A new field 'rsaParent' is introduced to note
the key is sealed with RSA SRK.
This commit implements two new fields: description and rsaParent in
tpm2key.c/tpm2key-asn.h and sets rsaParent when RSA SRK is used to seal
the key. When unsealing a tpm2key, the SRK template is set to the RSA
template if rsaParent is TRUE. Otherwise, the SRK template is switched
to the ECC SRK template.
A new testing script, test-tpm2key-ecc.sh, is also added to test the
tpm2key file sealed with ECC SRK.
Signed-off-by: Gary Lin <glin@suse.com>
---
src/pcr-policy.c | 8 +++
src/tpm2key-asn.h | 4 ++
src/tpm2key.c | 2 +
test-tpm2key-ecc.sh | 127 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 141 insertions(+)
create mode 100755 test-tpm2key-ecc.sh
diff --git a/src/pcr-policy.c b/src/pcr-policy.c
index f65becf..90f60ff 100644
--- a/src/pcr-policy.c
+++ b/src/pcr-policy.c
@@ -1505,6 +1505,11 @@ tpm2key_unseal_secret(const char *input_path, const char *output_path,
if (!tpm2key_read_file(input_path, &tpm2key))
return false;
+ if (tpm2key->rsaParent == 1)
+ SRK_template = &RSA_SRK_template;
+ else
+ SRK_template = &ECC_SRK_template;
+
buffer_init_read(&buf, tpm2key->pubkey->data, tpm2key->pubkey->length);
rc = Tss2_MU_TPM2B_PUBLIC_Unmarshal(buf.data, buf.size, &buf.rpos, &pub);
if (rc != TSS2_RC_SUCCESS)
@@ -1634,6 +1639,9 @@ tpm2key_write_sealed_secret(const char *pathname,
if (!tpm2key_basekey(&tpm2key, TPM2_RH_OWNER, sealed_public, sealed_private))
goto cleanup;
+ if (SRK_template->publicArea.type == TPM2_ALG_RSA)
+ tpm2key->rsaParent = 1;
+
if (pcr_sel && !tpm2key_add_policy_policypcr(tpm2key, pcr_sel))
goto cleanup;
diff --git a/src/tpm2key-asn.h b/src/tpm2key-asn.h
index 3f1c0d7..d0cdfaa 100644
--- a/src/tpm2key-asn.h
+++ b/src/tpm2key-asn.h
@@ -77,6 +77,8 @@ DEFINE_STACK_OF(TSSAUTHPOLICY);
* policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
* secret [2] EXPLICIT OCTET STRING OPTIONAL
* authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL
+ * description [4] EXPLICIT UTF8String OPTIONAL
+ * rsaParent [5] EXPLICIT BOOLEAN OPTIONAL
* parent INTEGER
* pubkey OCTET STRING
* privkey OCTET STRING
@@ -89,6 +91,8 @@ typedef struct {
STACK_OF(TSSOPTPOLICY) *policy;
ASN1_OCTET_STRING *secret;
STACK_OF(TSSAUTHPOLICY) *authPolicy;
+ ASN1_UTF8STRING description;
+ ASN1_BOOLEAN rsaParent;
ASN1_INTEGER *parent;
ASN1_OCTET_STRING *pubkey;
ASN1_OCTET_STRING *privkey;
diff --git a/src/tpm2key.c b/src/tpm2key.c
index cabd791..af4c984 100644
--- a/src/tpm2key.c
+++ b/src/tpm2key.c
@@ -278,6 +278,8 @@ ASN1_SEQUENCE(TSSPRIVKEY) = {
ASN1_EXP_SEQUENCE_OF_OPT(TSSPRIVKEY, policy, TSSOPTPOLICY, 1),
ASN1_EXP_OPT(TSSPRIVKEY, secret, ASN1_OCTET_STRING, 2),
ASN1_EXP_SEQUENCE_OF_OPT(TSSPRIVKEY, authPolicy, TSSAUTHPOLICY, 3),
+ ASN1_EXP_OPT(TSSPRIVKEY, description, ASN1_UTF8STRING, 4),
+ ASN1_EXP_OPT(TSSPRIVKEY, rsaParent, ASN1_BOOLEAN, 5),
ASN1_SIMPLE(TSSPRIVKEY, parent, ASN1_INTEGER),
ASN1_SIMPLE(TSSPRIVKEY, pubkey, ASN1_OCTET_STRING),
ASN1_SIMPLE(TSSPRIVKEY, privkey, ASN1_OCTET_STRING)
diff --git a/test-tpm2key-ecc.sh b/test-tpm2key-ecc.sh
new file mode 100755
index 0000000..d87acff
--- /dev/null
+++ b/test-tpm2key-ecc.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+#
+# This script needs to be run with root privilege
+#
+
+# TESTDIR=policy.test
+PCR_MASK=0,2,4,12
+
+pcr_oracle=pcr-oracle
+if [ -x pcr-oracle ]; then
+ pcr_oracle=$PWD/pcr-oracle
+fi
+
+function call_oracle {
+
+ echo "****************"
+ echo "pcr-oracle $*"
+ $pcr_oracle --target-platform tpm2.0 -d "$@"
+}
+
+if [ -z "$TESTDIR" ]; then
+ tmpdir=$(mktemp -d /tmp/pcrtestXXXXXX)
+ trap "cd / && rm -rf $tmpdir" 0 1 2 10 11 15
+
+ TESTDIR=$tmpdir
+fi
+
+trap "echo 'FAIL: command exited with error'; exit 1" ERR
+
+echo "This is super secret" >$TESTDIR/secret
+
+set -e
+cd $TESTDIR
+
+echo "Seal the secret with PCR policy"
+call_oracle \
+ --from current \
+ --input secret \
+ --output sealed \
+ --ecc-srk \
+ seal-secret $PCR_MASK
+
+echo "Unseal the sealed with PCR policy"
+call_oracle \
+ --input sealed \
+ --output recovered \
+ unseal-secret
+
+if ! cmp secret recovered; then
+ echo "BAD: Unable to recover original secret"
+ echo "Secret:"
+ od -tx1c secret
+ echo "Recovered:"
+ od -tx1c recovered
+ exit 1
+else
+ echo "NICE: we were able to recover the original secret"
+fi
+
+rm -f sealed recovered
+
+call_oracle \
+ --rsa-generate-key \
+ --private-key policy-key.pem \
+ --auth authorized.policy \
+ create-authorized-policy $PCR_MASK
+
+call_oracle \
+ --private-key policy-key.pem \
+ --public-key policy-pubkey \
+ store-public-key
+
+call_oracle \
+ --auth authorized.policy \
+ --input secret \
+ --output sealed \
+ --ecc-srk \
+ seal-secret
+
+for attempt in first second; do
+ echo "Sign the set of PCRs we want to authorize"
+ call_oracle \
+ --policy-name "authorized-policy-test" \
+ --private-key policy-key.pem \
+ --from current \
+ --input sealed \
+ --output sealed-signed \
+ sign $PCR_MASK
+
+ echo "$attempt attempt to unseal the secret"
+ call_oracle \
+ --input sealed-signed \
+ --output recovered \
+ unseal-secret
+
+ if ! cmp secret recovered; then
+ echo "BAD: Unable to recover original secret"
+ echo "Secret:"
+ od -tx1c secret
+ echo "Recovered:"
+ od -tx1c recovered
+ exit 1
+ else
+ echo "NICE: we were able to recover the original secret"
+ fi
+
+ if [ "$attempt" = "second" ]; then
+ break
+ fi
+
+ echo "Extend PCR 12. Unsealing should fail afterwards"
+ tpm2_pcrextend 12:sha256=21d2013e3081f1e455fdd5ba6230a8620c3cfc9a9c31981d857fe3891f79449e
+ rm -f recovered
+ call_oracle \
+ --input sealed-signed \
+ --output recovered \
+ unseal-secret || true
+
+ if [ -s recovered ] && ! cmp secret recovered; then
+ echo "BAD: We were still able to recover the original secret. Something stinks"
+ exit 1
+ else
+ echo "GOOD: After changing a PCR, the secret can no longer be unsealed"
+ fi
+
+ echo "Now recreate the signed PCR policy"
+done
--
2.35.3