Compare commits
48 Commits
Author | SHA256 | Date | |
---|---|---|---|
688c2225ab | |||
2d95392753 | |||
de0b83190f | |||
69528f8e7e | |||
ced8963ad8 | |||
825822e9bb | |||
8a0f76e4e3 | |||
34510ba1ec | |||
41ba24edaf | |||
c3a080f6f8 | |||
69dc577df1 | |||
356f288230 | |||
94085ce4bf | |||
a18732fa3e | |||
f604fd8668 | |||
7c7e9fe35b | |||
48bd67e6f2 | |||
1790411994 | |||
4eb2926a47 | |||
7834539dac | |||
35a9565808 | |||
b1b6d47435 | |||
246045e36c | |||
9228f7c5da | |||
ce0c7b4d23 | |||
d02e4f852b | |||
ca20a1e932 | |||
64e374e9eb | |||
a5ac97965f | |||
3d40a4e426 | |||
9002765e42 | |||
07fa94a1ef | |||
e05dc895ab | |||
|
2c84831601 | ||
ad947a615d | |||
9df1c87f90 | |||
e70764a3f9 | |||
3ad693c87e | |||
3fc7a58b04 | |||
|
49e6bbc33c | ||
89cd3b9216 | |||
10f6f31e6f | |||
73961a43fe | |||
ff8df83650 | |||
d76e3a088c | |||
1093b87607 | |||
e5e3f71945 | |||
47716611e2 |
@@ -1,34 +0,0 @@
|
||||
From 55fe5c34cf41813fd91fff85281770da77913b68 Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Fri, 7 Mar 2025 16:40:36 +0800
|
||||
Subject: [PATCH 2/2] Stop the SbatLevelRT prediction if .sbatlevel not
|
||||
available
|
||||
|
||||
The SbatLevelRT prediction relies on the PCR4 events to locate shim.efi,
|
||||
so PCR4 has to be a hard requirement.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
src/efi-variable.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/efi-variable.c b/src/efi-variable.c
|
||||
index b70f63b..f8527cc 100644
|
||||
--- a/src/efi-variable.c
|
||||
+++ b/src/efi-variable.c
|
||||
@@ -291,9 +291,9 @@ efi_variable_authority_get_record(const tpm_parsed_event_t *parsed, const char *
|
||||
db_name = "MokList";
|
||||
} else
|
||||
if (!strcmp(var_short_name, "SbatLevel")) {
|
||||
- if (ctx->sbatlevel != NULL)
|
||||
- return efi_sbatlevel_get_record(ctx->sbatlevel);
|
||||
- return runtime_read_efi_variable(var_name);
|
||||
+ if (ctx->sbatlevel == NULL)
|
||||
+ fatal("No reference .sbatlevel section. Please add PCR4 into the PCR index list\n");
|
||||
+ return efi_sbatlevel_get_record(ctx->sbatlevel);
|
||||
} else {
|
||||
/* Read as-is (this could be SbatLevel, or some other variable that's not
|
||||
* a signature db). */
|
||||
--
|
||||
2.43.0
|
||||
|
@@ -1,103 +0,0 @@
|
||||
From 07e43365379ef5bd9fb53a45306af02025442b92 Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Fri, 7 Mar 2025 14:09:34 +0800
|
||||
Subject: [PATCH 1/2] Fix SbatLevelRT prediction when Secure Boot is disabled
|
||||
|
||||
Since shim 15.8, instead of using SBAT automatic as the default
|
||||
candidate, it always resets SbatLevel to SBAT_ORIGINAL. To make the
|
||||
prediction work for shim >= 15.8, the additinal check is added to adjust
|
||||
the SBAT candidate.
|
||||
|
||||
Also fix POLICY_RESET for not setting sbat_reset to true and a few
|
||||
typos.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
src/efi-variable.c | 30 ++++++++++++++++++++++++++----
|
||||
1 file changed, 26 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/efi-variable.c b/src/efi-variable.c
|
||||
index 9c56eec..b70f63b 100644
|
||||
--- a/src/efi-variable.c
|
||||
+++ b/src/efi-variable.c
|
||||
@@ -100,6 +100,7 @@ __tpm_event_efi_variable_build_event(const tpm_parsed_event_t *parsed, const voi
|
||||
#define POLICY_LATEST 1
|
||||
#define POLICY_AUTOMATIC 2
|
||||
#define POLICY_RESET 3
|
||||
+#define POLICY_NOTREAD 255
|
||||
|
||||
#define SBAT_ORIGINAL "sbat,1,2021030218\n"
|
||||
|
||||
@@ -169,6 +170,7 @@ efi_sbatlevel_get_record(buffer_t *sbatlevel)
|
||||
buffer_t *result = NULL;
|
||||
uint8_t secureboot;
|
||||
uint8_t sbatpolicy;
|
||||
+ uint32_t auto_date;
|
||||
uint32_t current_date;
|
||||
uint32_t candidate_date;
|
||||
bool sbat_reset = false;
|
||||
@@ -178,6 +180,11 @@ efi_sbatlevel_get_record(buffer_t *sbatlevel)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+ if (!fetch_sbat_datestamp(sbat_automatic, strlen(sbat_automatic), &auto_date)) {
|
||||
+ error("Unable to get datestamp of SBAT automatic\n");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
buffer = runtime_read_efi_variable(SECUREBOOT_VARNAME);
|
||||
if (buffer == NULL || !buffer_get_u8(buffer, &secureboot))
|
||||
secureboot = 0;
|
||||
@@ -185,7 +192,7 @@ efi_sbatlevel_get_record(buffer_t *sbatlevel)
|
||||
|
||||
buffer = runtime_read_efi_variable(SBATPOLICY_VARNAME);
|
||||
if (buffer == NULL || !buffer_get_u8(buffer, &sbatpolicy))
|
||||
- sbatpolicy = POLICY_AUTOMATIC;
|
||||
+ sbatpolicy = POLICY_NOTREAD;
|
||||
buffer_free(buffer);
|
||||
|
||||
switch (sbatpolicy) {
|
||||
@@ -200,9 +207,24 @@ efi_sbatlevel_get_record(buffer_t *sbatlevel)
|
||||
infomsg("SBAT cannot be reset when Secure Boot is enabled.\n");
|
||||
sbat_candidate = sbat_automatic;
|
||||
} else {
|
||||
+ sbat_reset = true;
|
||||
sbat_candidate = SBAT_ORIGINAL;
|
||||
}
|
||||
break;
|
||||
+ case POLICY_NOTREAD:
|
||||
+ if (secureboot == 1) {
|
||||
+ sbat_candidate = sbat_automatic;
|
||||
+ } else {
|
||||
+ /* shim 15.8 always resets SbatLevel when Secure Boot is disabled.
|
||||
+ * The automatic datestamp of shim 15.8 is 2023012900. */
|
||||
+ if (auto_date >= 2023012900) {
|
||||
+ sbat_reset = true;
|
||||
+ sbat_candidate = SBAT_ORIGINAL;
|
||||
+ } else {
|
||||
+ sbat_candidate = sbat_automatic;
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
error("Invalid SBAT policy\n");
|
||||
return NULL;
|
||||
@@ -217,12 +239,12 @@ efi_sbatlevel_get_record(buffer_t *sbatlevel)
|
||||
|
||||
if (!fetch_sbat_datestamp(sbat_current, sbatlvlrt->size, ¤t_date)
|
||||
|| !fetch_sbat_datestamp(sbat_candidate, strlen(sbat_candidate), &candidate_date)) {
|
||||
- error("Unable to get SBAT timestamp\n");
|
||||
+ error("Unable to get SBAT datestamp\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- debug("Current SBAT datestampe: %u\n", current_date);
|
||||
- debug("Candidate SBAT datestampe: %u\n", candidate_date);
|
||||
+ debug("Current SBAT datestamp: %u\n", current_date);
|
||||
+ debug("Candidate SBAT datestamp: %u\n", candidate_date);
|
||||
|
||||
if (current_date >= candidate_date && sbat_reset == false) {
|
||||
debug("Use current SbatLevel\n");
|
||||
--
|
||||
2.43.0
|
||||
|
@@ -1,422 +0,0 @@
|
||||
From 5f73c8d655465470498c91f238788d2ffa48de81 Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Tue, 25 Feb 2025 16:13:28 +0800
|
||||
Subject: [PATCH 1/2] Locate .sbatlevel section in shim.efi
|
||||
|
||||
The .sbatlevel section in shim.efi will be used to set SbatLevelRT and
|
||||
we need the section to predict SbatLevelRT.
|
||||
|
||||
Per PE format SPEC(*), the section name is
|
||||
|
||||
"An 8-byte, null-padded UTF-8 encoded string. If the string is exactly 8
|
||||
8 characters long, there is no terminating null. For longer names, this
|
||||
field contains a slash (/) that is followed by an ASCII representation
|
||||
of a decimal number that is an offset into the string table."
|
||||
|
||||
Before looking for the .sbatlevel section, we have to get the string
|
||||
table, To get the offset to the string table:
|
||||
|
||||
string_table_offset = symbol_table_offset +
|
||||
(number_of_symbols * symbol_size)
|
||||
|
||||
With the offset, we can go further to look for the longer section names
|
||||
and get the .sbatlevel section.
|
||||
|
||||
(*) https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
src/authenticode.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
src/authenticode.h | 2 ++
|
||||
2 files changed, 77 insertions(+)
|
||||
|
||||
Index: pcr-oracle-0.5.4/src/authenticode.c
|
||||
===================================================================
|
||||
--- pcr-oracle-0.5.4.orig/src/authenticode.c
|
||||
+++ pcr-oracle-0.5.4/src/authenticode.c
|
||||
@@ -91,10 +91,14 @@ struct pecoff_image_info {
|
||||
uint16_t machine_id;
|
||||
uint16_t num_sections;
|
||||
uint32_t symtab_offset;
|
||||
+ uint32_t num_symbols;
|
||||
uint16_t optional_hdr_size;
|
||||
uint32_t optional_hdr_offset;
|
||||
|
||||
uint32_t section_table_offset;
|
||||
+
|
||||
+ uint32_t strtab_offset;
|
||||
+ uint32_t strtab_size;
|
||||
} pe_hdr;
|
||||
|
||||
struct {
|
||||
@@ -111,6 +115,9 @@ struct pecoff_image_info {
|
||||
pecoff_section_t * section;
|
||||
|
||||
authenticode_image_info_t auth_info;
|
||||
+
|
||||
+ /* The contents of .sbatlevel */
|
||||
+ buffer_t * sbatlevel;
|
||||
};
|
||||
|
||||
#define MSDOS_STUB_PE_OFFSET 0x3c
|
||||
@@ -147,6 +154,7 @@ void
|
||||
pecoff_image_info_free(pecoff_image_info_t *img)
|
||||
{
|
||||
buffer_free(img->data);
|
||||
+ buffer_free(img->sbatlevel);
|
||||
free(img->display_name);
|
||||
free(img->data_dirs);
|
||||
free(img->section);
|
||||
@@ -351,6 +359,8 @@ __pecoff_process_header(buffer_t *in, pe
|
||||
|
||||
if (!__pecoff_get_u32(in, img, PECOFF_HEADER_SYMTAB_POS_OFFSET, &img->pe_hdr.symtab_offset))
|
||||
return false;
|
||||
+ if (!__pecoff_get_u32(in, img, PECOFF_HEADER_SYMTAB_CNT_OFFSET, &img->pe_hdr.num_symbols))
|
||||
+ return false;
|
||||
|
||||
img->pe_hdr.optional_hdr_offset = img->pe_hdr.offset + PECOFF_HEADER_LENGTH;
|
||||
if (!__pecoff_get_u16(in, img, PECOFF_HEADER_OPTIONAL_HDR_SIZE_OFFSET, &img->pe_hdr.optional_hdr_size))
|
||||
@@ -358,6 +368,19 @@ __pecoff_process_header(buffer_t *in, pe
|
||||
|
||||
img->pe_hdr.section_table_offset = img->pe_hdr.optional_hdr_offset + img->pe_hdr.optional_hdr_size;
|
||||
|
||||
+ /* String table follows symbol table immediately.
|
||||
+ * One symbol is 18 bytes, so the offset to string table is
|
||||
+ * symtab_offset + num_symbols * 18
|
||||
+ *
|
||||
+ * ref: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#coff-string-table
|
||||
+ * https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#coff-symbol-table
|
||||
+ */
|
||||
+ if (img->pe_hdr.symtab_offset != 0) {
|
||||
+ img->pe_hdr.strtab_offset = img->pe_hdr.symtab_offset + (img->pe_hdr.num_symbols * 18);
|
||||
+ if (!__pecoff_get_u32(in, img, img->pe_hdr.strtab_offset, &img->pe_hdr.strtab_size))
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -451,6 +474,27 @@ __pecoff_process_optional_header(buffer_
|
||||
}
|
||||
|
||||
static bool
|
||||
+__pecoff_name_to_offset(char *sec_name, uint32_t *offset)
|
||||
+{
|
||||
+ uint32_t result = 0;
|
||||
+ int i;
|
||||
+
|
||||
+ if (sec_name[0] != '/')
|
||||
+ return false;
|
||||
+
|
||||
+ for (i = 1; i < 8 && sec_name[i] != '\0'; i++) {
|
||||
+ if (sec_name[i] < '0' || sec_name[i] > '9')
|
||||
+ return false;
|
||||
+
|
||||
+ result = result * 10 + sec_name[i] - '0';
|
||||
+ }
|
||||
+
|
||||
+ *offset = result;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
__pecoff_process_sections(buffer_t *in, pecoff_image_info_t *info)
|
||||
{
|
||||
unsigned int tbl_offset = info->pe_hdr.section_table_offset;
|
||||
@@ -458,6 +502,9 @@ __pecoff_process_sections(buffer_t *in,
|
||||
buffer_t hdr;
|
||||
unsigned int i;
|
||||
pecoff_section_t *sec;
|
||||
+ uint32_t str_offset;
|
||||
+ char *long_name;
|
||||
+ buffer_t *sec_buf;
|
||||
|
||||
pe_debug(" Processing %u sections (table at offset %u)\n", num_sections, tbl_offset);
|
||||
|
||||
@@ -483,6 +530,27 @@ __pecoff_process_sections(buffer_t *in,
|
||||
|
||||
pe_debug(" Section %-8s raw %7u at 0x%08x-0x%08x\n",
|
||||
sec->name, sec->raw.size, sec->raw.addr, sec->raw.addr + sec->raw.size);
|
||||
+ /* Process the section names longer than 8 bytes */
|
||||
+ long_name = NULL;
|
||||
+ if (__pecoff_name_to_offset(sec->name, &str_offset) &&
|
||||
+ str_offset < info->pe_hdr.strtab_size) {
|
||||
+ long_name = (char *)(in->data + info->pe_hdr.strtab_offset + str_offset);
|
||||
+ pe_debug(" Long Name: %s\n", long_name);
|
||||
+ }
|
||||
+
|
||||
+ /* Get sbatlevel from .sbatlevel section */
|
||||
+ if (long_name != NULL && strcmp(long_name, ".sbatlevel") == 0) {
|
||||
+ if (!(sec_buf = buffer_alloc_write(sec->raw.size)))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!buffer_seek_read(in, sec->raw.addr))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!buffer_copy(in, sec->raw.size, sec_buf))
|
||||
+ return false;
|
||||
+
|
||||
+ info->sbatlevel = sec_buf;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* We are supposed to sort the sections in ascending order, but we're not doing it here, we
|
||||
@@ -506,6 +574,7 @@ __pecoff_show_header(pecoff_image_info_t
|
||||
pe_debug(" Architecture: %s\n", __pecoff_get_machine(img));
|
||||
pe_debug(" Number of sections: %d\n", img->pe_hdr.num_sections);
|
||||
pe_debug(" Symbol table position: 0x%08x\n", img->pe_hdr.symtab_offset);
|
||||
+ pe_debug(" String table position: 0x%08x\n", img->pe_hdr.strtab_offset);
|
||||
pe_debug(" Optional header size: %d\n", img->pe_hdr.optional_hdr_size);
|
||||
}
|
||||
|
||||
@@ -751,3 +820,9 @@ authenticode_get_signer(const pecoff_ima
|
||||
cert_table_free(cert_tbl);
|
||||
return signer;
|
||||
}
|
||||
+
|
||||
+buffer_t *
|
||||
+pecoff_image_get_sbatlevel(pecoff_image_info_t *img)
|
||||
+{
|
||||
+ return img->sbatlevel;
|
||||
+}
|
||||
Index: pcr-oracle-0.5.4/src/authenticode.h
|
||||
===================================================================
|
||||
--- pcr-oracle-0.5.4.orig/src/authenticode.h
|
||||
+++ pcr-oracle-0.5.4/src/authenticode.h
|
||||
@@ -29,5 +29,7 @@ extern tpm_evdigest_t * authenticode_get
|
||||
extern cert_table_t * authenticode_get_certificate_table(const pecoff_image_info_t *img);
|
||||
extern parsed_cert_t * authenticode_get_signer(const pecoff_image_info_t *);
|
||||
|
||||
+extern buffer_t * pecoff_image_get_sbatlevel(pecoff_image_info_t *);
|
||||
+
|
||||
#endif /* AUTHENTICODE_H */
|
||||
|
||||
Index: pcr-oracle-0.5.4/src/efi-application.c
|
||||
===================================================================
|
||||
--- pcr-oracle-0.5.4.orig/src/efi-application.c
|
||||
+++ pcr-oracle-0.5.4/src/efi-application.c
|
||||
@@ -315,6 +315,7 @@ __tpm_event_efi_bsa_rehash(const tpm_eve
|
||||
const struct efi_bsa_event *evspec = &parsed->efi_bsa_event;
|
||||
const char *new_application;
|
||||
struct efi_bsa_event evspec_clone;
|
||||
+ buffer_t *sbatlevel;
|
||||
|
||||
/* Some BSA events do not refer to files, but to some data blobs residing somewhere on a device.
|
||||
* We're not yet prepared to handle these, so we hope the user doesn't mess with them, and
|
||||
@@ -348,6 +349,14 @@ __tpm_event_efi_bsa_rehash(const tpm_eve
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Set the sbatlevel section from shim.efi */
|
||||
+ if (ctx->sbatlevel == NULL
|
||||
+ && (sbatlevel = pecoff_image_get_sbatlevel(evspec->img_info)) != NULL) {
|
||||
+ if ((ctx->sbatlevel = buffer_alloc_write(sbatlevel->size)) == NULL
|
||||
+ || !buffer_copy(sbatlevel, sbatlevel->size, ctx->sbatlevel))
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
if (ctx->use_pesign)
|
||||
return __efi_application_rehash_pesign(ctx, evspec->efi_partition, evspec->efi_application);
|
||||
|
||||
Index: pcr-oracle-0.5.4/src/efi-variable.c
|
||||
===================================================================
|
||||
--- pcr-oracle-0.5.4.orig/src/efi-variable.c
|
||||
+++ pcr-oracle-0.5.4/src/efi-variable.c
|
||||
@@ -93,6 +93,159 @@ __tpm_event_efi_variable_build_event(con
|
||||
return bp;
|
||||
}
|
||||
|
||||
+#define SBATLEVELRT_VARNAME "SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23"
|
||||
+#define SBATPOLICY_VARNAME "SbatPolicy-605dab50-e046-4300-abb6-3dd810dd8b23"
|
||||
+#define SECUREBOOT_VARNAME "SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c"
|
||||
+
|
||||
+#define POLICY_LATEST 1
|
||||
+#define POLICY_AUTOMATIC 2
|
||||
+#define POLICY_RESET 3
|
||||
+
|
||||
+#define SBAT_ORIGINAL "sbat,1,2021030218\n"
|
||||
+
|
||||
+static bool
|
||||
+parse_sbatlevel_section(buffer_t *sec, char **sbat_automatic, char **sbat_latest)
|
||||
+{
|
||||
+ uint32_t fmt_ver;
|
||||
+ uint32_t offset_auto;
|
||||
+ uint32_t offset_latest;
|
||||
+
|
||||
+ if (!buffer_get_u32le(sec, &fmt_ver)
|
||||
+ || !buffer_get_u32le(sec, &offset_auto)
|
||||
+ || !buffer_get_u32le(sec, &offset_latest))
|
||||
+ return false;
|
||||
+
|
||||
+ if (offset_auto >= offset_latest)
|
||||
+ return false;
|
||||
+
|
||||
+ if (!buffer_seek_read(sec, offset_auto + 4))
|
||||
+ return false;
|
||||
+ *sbat_automatic = (char *)buffer_read_pointer(sec);
|
||||
+
|
||||
+ if (!buffer_seek_read(sec, offset_latest + 4))
|
||||
+ return false;
|
||||
+ *sbat_latest = (char *)(buffer_read_pointer(sec));
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+fetch_sbat_datestamp(const char *sbat, size_t size, uint32_t *datestamp)
|
||||
+{
|
||||
+ uint32_t date = 0;
|
||||
+ size_t i;
|
||||
+
|
||||
+ /* Expected string: "sbat,X,YYYYYYYYYY\n" */
|
||||
+ if (size < 17)
|
||||
+ return false;
|
||||
+
|
||||
+ if (strncmp(sbat, "sbat,", 5) != 0)
|
||||
+ return false;
|
||||
+
|
||||
+ for (i = 5; i < size && sbat[i] != ','; i++);
|
||||
+ i++;
|
||||
+ if (i >= size)
|
||||
+ return false;
|
||||
+
|
||||
+ for (; i < size && sbat[i] != '\n'; i++) {
|
||||
+ if (sbat[i] < '0' || sbat[i] > '9')
|
||||
+ return false;
|
||||
+ date = date * 10 + sbat[i] - '0';
|
||||
+ }
|
||||
+
|
||||
+ *datestamp = date;
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static buffer_t *
|
||||
+efi_sbatlevel_get_record(buffer_t *sbatlevel)
|
||||
+{
|
||||
+ char *sbat_automatic;
|
||||
+ char *sbat_latest;
|
||||
+ const char *sbat_candidate;
|
||||
+ const char *sbat_current;
|
||||
+ buffer_t *buffer = NULL;
|
||||
+ buffer_t *sbatlvlrt = NULL;
|
||||
+ buffer_t *result = NULL;
|
||||
+ uint8_t secureboot;
|
||||
+ uint8_t sbatpolicy;
|
||||
+ uint32_t current_date;
|
||||
+ uint32_t candidate_date;
|
||||
+ bool sbat_reset = false;
|
||||
+
|
||||
+ if (!parse_sbatlevel_section(sbatlevel, &sbat_automatic, &sbat_latest)) {
|
||||
+ error("Unable to process SbatLevel\n");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ buffer = runtime_read_efi_variable(SECUREBOOT_VARNAME);
|
||||
+ if (buffer == NULL || !buffer_get_u8(buffer, &secureboot))
|
||||
+ secureboot = 0;
|
||||
+ buffer_free(buffer);
|
||||
+
|
||||
+ buffer = runtime_read_efi_variable(SBATPOLICY_VARNAME);
|
||||
+ if (buffer == NULL || !buffer_get_u8(buffer, &sbatpolicy))
|
||||
+ sbatpolicy = POLICY_AUTOMATIC;
|
||||
+ buffer_free(buffer);
|
||||
+
|
||||
+ switch (sbatpolicy) {
|
||||
+ case POLICY_LATEST:
|
||||
+ sbat_candidate = sbat_latest;
|
||||
+ break;
|
||||
+ case POLICY_AUTOMATIC:
|
||||
+ sbat_candidate = sbat_automatic;
|
||||
+ break;
|
||||
+ case POLICY_RESET:
|
||||
+ if (secureboot == 1) {
|
||||
+ infomsg("SBAT cannot be reset when Secure Boot is enabled.\n");
|
||||
+ sbat_candidate = sbat_automatic;
|
||||
+ } else {
|
||||
+ sbat_candidate = SBAT_ORIGINAL;
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ error("Invalid SBAT policy\n");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ if ((sbatlvlrt = runtime_read_efi_variable(SBATLEVELRT_VARNAME)) == NULL) {
|
||||
+ error("Unable to read SbatLevelRT\n");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ sbat_current = (const char *)buffer_read_pointer(sbatlvlrt);
|
||||
+
|
||||
+ if (!fetch_sbat_datestamp(sbat_current, sbatlvlrt->size, ¤t_date)
|
||||
+ || !fetch_sbat_datestamp(sbat_candidate, strlen(sbat_candidate), &candidate_date)) {
|
||||
+ error("Unable to get SBAT timestamp\n");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ debug("Current SBAT datestampe: %u\n", current_date);
|
||||
+ debug("Candidate SBAT datestampe: %u\n", candidate_date);
|
||||
+
|
||||
+ if (current_date >= candidate_date && sbat_reset == false) {
|
||||
+ debug("Use current SbatLevel\n");
|
||||
+ result = sbatlvlrt;
|
||||
+ } else {
|
||||
+ debug("Use candidate SbatLevel\n");
|
||||
+ buffer_free(sbatlvlrt);
|
||||
+
|
||||
+ /* Copy the candidate SbatLevel string without the terminating null */
|
||||
+ if ((result = buffer_alloc_write(strlen(sbat_candidate))) == NULL
|
||||
+ || !buffer_put(result, sbat_candidate, strlen(sbat_candidate)))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ return result;
|
||||
+
|
||||
+fail:
|
||||
+ buffer_free(sbatlvlrt);
|
||||
+ buffer_free(result);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
enum {
|
||||
HASH_STRATEGY_EVENT,
|
||||
HASH_STRATEGY_DATA,
|
||||
@@ -114,6 +267,11 @@ efi_variable_authority_get_record(const
|
||||
} else
|
||||
if (!strcmp(var_short_name, "MokListRT")) {
|
||||
db_name = "MokList";
|
||||
+ } else
|
||||
+ if (!strcmp(var_short_name, "SbatLevel")) {
|
||||
+ if (ctx->sbatlevel != NULL)
|
||||
+ return efi_sbatlevel_get_record(ctx->sbatlevel);
|
||||
+ return runtime_read_efi_variable(var_name);
|
||||
} else {
|
||||
/* Read as-is (this could be SbatLevel, or some other variable that's not
|
||||
* a signature db). */
|
||||
Index: pcr-oracle-0.5.4/src/eventlog.c
|
||||
===================================================================
|
||||
--- pcr-oracle-0.5.4.orig/src/eventlog.c
|
||||
+++ pcr-oracle-0.5.4/src/eventlog.c
|
||||
@@ -1148,6 +1148,7 @@ tpm_event_log_rehash_ctx_init(tpm_event_
|
||||
void
|
||||
tpm_event_log_rehash_ctx_destroy(tpm_event_log_rehash_ctx_t *ctx)
|
||||
{
|
||||
+ buffer_free(ctx->sbatlevel);
|
||||
}
|
||||
|
||||
void
|
||||
Index: pcr-oracle-0.5.4/src/eventlog.h
|
||||
===================================================================
|
||||
--- pcr-oracle-0.5.4.orig/src/eventlog.h
|
||||
+++ pcr-oracle-0.5.4/src/eventlog.h
|
||||
@@ -209,6 +209,8 @@ typedef struct tpm_event_log_rehash_ctx
|
||||
/* This get set when the user specifies --next-kernel */
|
||||
char * boot_entry_path;
|
||||
uapi_boot_entry_t * boot_entry;
|
||||
+
|
||||
+ buffer_t * sbatlevel;
|
||||
} tpm_event_log_rehash_ctx_t;
|
||||
|
||||
#define GRUB_COMMAND_ARGV_MAX 32
|
@@ -1,35 +0,0 @@
|
||||
From bfd8520b4af3743a51046c83a1382fe1e66cc95a Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Thu, 26 Dec 2024 13:46:45 +0800
|
||||
Subject: [PATCH] Fix event rehash for grub files on system partition
|
||||
|
||||
The crypto device logged by grub may not be 'crypto0'. It could begin
|
||||
with the 'cryptouuid' prefix like this:
|
||||
|
||||
cryptouuid/4203418d2b034db5b9476f013ee3dc80
|
||||
|
||||
This commit adds the additional prefix matching for 'cryptouuid' to make
|
||||
pcr-oracle to search the file on system partition.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
src/eventlog.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/eventlog.c b/src/eventlog.c
|
||||
index 4277d42..c49599d 100644
|
||||
--- a/src/eventlog.c
|
||||
+++ b/src/eventlog.c
|
||||
@@ -578,7 +578,8 @@ __tpm_event_grub_file_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *pa
|
||||
const tpm_evdigest_t *md = NULL;
|
||||
|
||||
debug(" re-hashing %s\n", __tpm_event_grub_file_describe(parsed));
|
||||
- if (evspec->device == NULL || !strcmp(evspec->device, "crypto0")) {
|
||||
+ if (evspec->device == NULL || !strcmp(evspec->device, "crypto0") ||
|
||||
+ !strncmp(evspec->device, "cryptouuid", strlen("cryptouuid"))) {
|
||||
debug(" assuming the file resides on system partition\n");
|
||||
md = runtime_digest_rootfs_file(ctx->algo, evspec->path);
|
||||
} else {
|
||||
--
|
||||
2.43.0
|
||||
|
@@ -1,58 +0,0 @@
|
||||
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
|
||||
|
@@ -1,412 +0,0 @@
|
||||
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);
|
||||
|
@@ -1,335 +0,0 @@
|
||||
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;
|
@@ -1,188 +0,0 @@
|
||||
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);
|
@@ -1,79 +0,0 @@
|
||||
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
|
BIN
pcr-oracle-0.5.4.tar.xz
(Stored with Git LFS)
BIN
pcr-oracle-0.5.4.tar.xz
(Stored with Git LFS)
Binary file not shown.
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f4a1392f94e18ebf3f1c7214414e92392276cb6c124bf4d976857a46a378e7eb
|
||||
size 85876
|
BIN
pcr-oracle-0.5.6.tar.xz
(Stored with Git LFS)
BIN
pcr-oracle-0.5.6.tar.xz
(Stored with Git LFS)
Binary file not shown.
@@ -1,413 +0,0 @@
|
||||
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
|
||||
|
Reference in New Issue
Block a user