diff --git a/_service b/_service index 15c5ab7..99a13d5 100644 --- a/_service +++ b/_service @@ -7,7 +7,7 @@ https://github.com/okirch/pcr-oracle.git pcr-oracle @PARENT_TAG@ - refs/tags/0.4.6 + refs/tags/0.5.2 pcr-oracle*.tar diff --git a/fix_rsa.patch b/fix_rsa.patch new file mode 100644 index 0000000..2757095 --- /dev/null +++ b/fix_rsa.patch @@ -0,0 +1,224 @@ +From bba8e4aa53d7c75ad3a153418c6c8ece19d8049b Mon Sep 17 00:00:00 2001 +From: Alberto Planas +Date: Fri, 17 Nov 2023 08:40:39 +0100 +Subject: [PATCH 1/2] Add rsa-public-pem paramenter + +This parameter will instruct store-public-key to store the public part +in PEM format. + +Signed-off-by: Alberto Planas +--- + man/pcr-oracle.8.in | 23 +++++++++++++++++++ + src/oracle.c | 16 ++++++++++++-- + src/rsa.c | 54 +++++++++++++++++++++++++++++++++------------ + src/rsa.h | 2 ++ + 4 files changed, 79 insertions(+), 16 deletions(-) + +diff --git a/man/pcr-oracle.8.in b/man/pcr-oracle.8.in +index 8fed99e..bc210c5 100644 +--- a/man/pcr-oracle.8.in ++++ b/man/pcr-oracle.8.in +@@ -199,6 +199,29 @@ supports this via its \fBstore-public-key\fP subcommand: + This command will read the RSA private key from the PEM file, + and write the public key as a \fBTPM2B_PUBLIC\fP object to + the indicated output file \fBpolicy-pubkey\fP. ++.P ++In other cases it is convenient to generate a private key and store ++the public and the private components without using \fBopenssl\fP, but ++using more conventional formats like PEM. ++.P ++.nf ++.in +2 ++# pcr-oracle \\ ++.br ++ --rsa-generate-key \\ ++.br ++ --rsa-public-pem \\ ++.br ++ --private-key policy-key.pem \\ ++.br ++ --public-key policy-pubkey \\ ++.br ++ store-public-key ++.fi ++.P ++This command will read the RSA private key from the PEM file, ++and write the public key as a \fBTPM2B_PUBLIC\fP object to ++the indicated output file \fBpolicy-pubkey\fP. + .\" ################################################################## + .\" # New key format + .\" ################################################################## +diff --git a/src/oracle.c b/src/oracle.c +index 0238110..726c11d 100644 +--- a/src/oracle.c ++++ b/src/oracle.c +@@ -89,6 +89,7 @@ enum { + OPT_RSA_PUBLIC_KEY, + OPT_RSA_GENERATE_KEY, + OPT_RSA_BITS, ++ OPT_RSA_PUBLIC_PEM, + OPT_INPUT, + OPT_OUTPUT, + OPT_AUTHORIZED_POLICY, +@@ -119,6 +120,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 }, ++ { "rsa-public-pem", no_argument, 0, OPT_RSA_PUBLIC_PEM }, + { "input", required_argument, 0, OPT_INPUT }, + { "output", required_argument, 0, OPT_OUTPUT }, + { "authorized-policy", required_argument, 0, OPT_AUTHORIZED_POLICY }, +@@ -1016,6 +1018,7 @@ main(int argc, char **argv) + char *opt_rsa_public_key = NULL; + bool opt_rsa_generate = false; + char *opt_rsa_bits = NULL; ++ bool opt_rsa_public_pem = false; + char *opt_key_format = NULL; + char *opt_policy_name = NULL; + char *opt_policy_format = NULL; +@@ -1086,6 +1089,9 @@ main(int argc, char **argv) + case OPT_RSA_BITS: + opt_rsa_bits = optarg; + break; ++ case OPT_RSA_PUBLIC_PEM: ++ opt_rsa_public_pem = true; ++ break; + case OPT_INPUT: + opt_input = optarg; + break; +@@ -1267,8 +1273,14 @@ main(int argc, char **argv) + } + + if (action == ACTION_STORE_PUBLIC_KEY) { +- if (!pcr_store_public_key(opt_rsa_private_key, opt_rsa_public_key)) +- return 1; ++ if (opt_rsa_public_pem) { ++ tpm_rsa_key_t *key = tpm_rsa_key_read_private(opt_rsa_private_key); ++ if (!key || !tpm_rsa_key_write_public(opt_rsa_public_key, key)) ++ return 1; ++ } ++ else ++ if (!pcr_store_public_key(opt_rsa_private_key, opt_rsa_public_key)) ++ return 1; + return 0; + } + +diff --git a/src/rsa.c b/src/rsa.c +index f3672b1..5385441 100644 +--- a/src/rsa.c ++++ b/src/rsa.c +@@ -95,36 +95,27 @@ tpm_rsa_key_read_public(const char *pathname) + } + + /* +- * Write a private key to a PEM file. +- * Pass phrases currently not supported. ++ * Write a public key to a PEM file. + */ + bool +-tpm_rsa_key_write_private(const char *pathname, const tpm_rsa_key_t *key) ++tpm_rsa_key_write_public(const char *pathname, const tpm_rsa_key_t *key) + { + bool ok = false; +- mode_t omask; + FILE *fp; + +- /* Turn off group and other rw bits to make the private key mode 600 +- * right from the start. */ +- omask = umask(077); +- + if (!(fp = fopen(pathname, "w"))) { +- error("Cannot open RSA private key file %s: %m\n", pathname); ++ error("Cannot open RSA public key file %s: %m\n", pathname); + goto fail; + } + +- if (!PEM_write_PrivateKey(fp, key->pkey, NULL, NULL, 0, 0, NULL)) { +- error("Unable to write private key to %s\n", pathname); ++ if (!PEM_write_PUBKEY(fp, key->pkey)) { ++ error("Unable to write public key to %s\n", pathname); + goto fail; + } + + ok = true; + + fail: +- /* Reset the umask */ +- umask(omask); +- + fclose(fp); + return ok; + } +@@ -164,6 +155,41 @@ tpm_rsa_key_read_private(const char *pathname) + return NULL; + } + ++/* ++ * Write a private key to a PEM file. ++ * Pass phrases currently not supported. ++ */ ++bool ++tpm_rsa_key_write_private(const char *pathname, const tpm_rsa_key_t *key) ++{ ++ bool ok = false; ++ mode_t omask; ++ FILE *fp; ++ ++ /* Turn off group and other rw bits to make the private key mode 600 ++ * right from the start. */ ++ omask = umask(077); ++ ++ if (!(fp = fopen(pathname, "w"))) { ++ error("Cannot open RSA private key file %s: %m\n", pathname); ++ goto fail; ++ } ++ ++ if (!PEM_write_PrivateKey(fp, key->pkey, NULL, NULL, 0, 0, NULL)) { ++ error("Unable to write private key to %s\n", pathname); ++ goto fail; ++ } ++ ++ ok = true; ++ ++fail: ++ /* Reset the umask */ ++ umask(omask); ++ ++ fclose(fp); ++ return ok; ++} ++ + tpm_rsa_key_t * + tpm_rsa_generate(unsigned int bits) + { +diff --git a/src/rsa.h b/src/rsa.h +index 49c0bb4..7b8362f 100644 +--- a/src/rsa.h ++++ b/src/rsa.h +@@ -26,6 +26,8 @@ + typedef struct tpm_rsa_key tpm_rsa_key_t; + + extern tpm_rsa_key_t * tpm_rsa_key_read_public(const char *pathname); ++extern bool tpm_rsa_key_write_public(const char *pathname, ++ const tpm_rsa_key_t *key); + extern tpm_rsa_key_t * tpm_rsa_key_read_private(const char *pathname); + extern bool tpm_rsa_key_write_private(const char *pathname, + const tpm_rsa_key_t *key); + +From ddd92b8f58d0f3bb89aada4adeb71d6ba9d1573a Mon Sep 17 00:00:00 2001 +From: Alberto Planas +Date: Fri, 17 Nov 2023 08:43:47 +0100 +Subject: [PATCH 2/2] Update version 0.5.3 + +Signed-off-by: Alberto Planas +--- + microconf/version | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/microconf/version b/microconf/version +index a486208..c4f2939 100644 +--- a/microconf/version ++++ b/microconf/version +@@ -1 +1 @@ +-uc_version=0.5.2 ++uc_version=0.5.3 diff --git a/pcr-oracle-0.4.6.tar.xz b/pcr-oracle-0.4.6.tar.xz deleted file mode 100644 index acb1aa0..0000000 --- a/pcr-oracle-0.4.6.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e01306c442eeec8a31acc1abb26445190380db210c01330e2d40156e51cfd294 -size 71696 diff --git a/pcr-oracle-0.5.2.tar.xz b/pcr-oracle-0.5.2.tar.xz new file mode 100644 index 0000000..ecb4482 --- /dev/null +++ b/pcr-oracle-0.5.2.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fcf10282e1dd989dd638231682ef5fe1fc141ca82a55fb27224bf4d77fd85d64 +size 76060 diff --git a/pcr-oracle.changes b/pcr-oracle.changes index 2362951..deea280 100644 --- a/pcr-oracle.changes +++ b/pcr-oracle.changes @@ -1,3 +1,34 @@ +------------------------------------------------------------------- +Mon Nov 20 10:24:32 UTC 2023 - Alberto Planas Dominguez + +- 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 + +- 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 + +- 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 + +- 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 diff --git a/pcr-oracle.spec b/pcr-oracle.spec index a207013..1a7ac77 100644 --- a/pcr-oracle.spec +++ b/pcr-oracle.spec @@ -18,17 +18,17 @@ Name: pcr-oracle -Version: 0.4.6 +Version: 0.5.2 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-FEATURE-UPSTREAM systemd-boot.patch gh#okirch/pcr-oracle#31 -Patch01: systemd-boot.patch +# PATCH-FEATURE-UPSTREAM fix_rsa.patch gh#okirch/pcr-oracle#37 +Patch: fix_rsa.patch BuildRequires: libopenssl-devel >= 0.9.8 -BuildRequires: tpm2-0-tss-devel +BuildRequires: tpm2-0-tss-devel >= 2.4.0 Requires: libtss2-tcti-device0 ExclusiveArch: x86_64 aarch64 ppc64le riscv64 diff --git a/systemd-boot.patch b/systemd-boot.patch deleted file mode 100644 index a333cab..0000000 --- a/systemd-boot.patch +++ /dev/null @@ -1,1091 +0,0 @@ -From 0baab1fc20a34e298466e4f87ad23701b46e6096 Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Wed, 20 Sep 2023 10:12:21 +0200 -Subject: [PATCH 01/10] testcase: iterate over s instead - -Signed-off-by: Alberto Planas ---- - src/testcase.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/testcase.c b/src/testcase.c -index bae3a69..f74238b 100644 ---- a/src/testcase.c -+++ b/src/testcase.c -@@ -453,7 +453,7 @@ canon_path(const char *path) - ++path; - - save_path = strdup(path); -- for (s = save_path; *comp; ) { -+ for (s = save_path; *s; ) { - comp = s; - while (*s) { - if (*s == '/') { - -From 2aec1cc9b0fb095f4be28f0895fb3fc2f73935d4 Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Thu, 21 Sep 2023 18:38:12 +0200 -Subject: [PATCH 02/10] util: add print_base64_value function - -Signed-off-by: Alberto Planas ---- - src/util.c | 37 +++++++++++++++++++++++++++++++++++++ - src/util.h | 2 ++ - 2 files changed, 39 insertions(+) - -diff --git a/src/util.c b/src/util.c -index 04d53f4..2c90315 100644 ---- a/src/util.c -+++ b/src/util.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - #include "util.h" - #include "digest.h" -@@ -188,6 +189,42 @@ print_octet_string(const unsigned char *data, unsigned int len) - - } - -+const char * -+print_base64_value(const unsigned char *data, unsigned int len) -+{ -+ static char buffer[2048]; -+ static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -+ unsigned int b64_len, i; -+ char *b; -+ -+ b64_len = 4 * ((len + 2) / 3) + 1; -+ assert(b64_len < 2048); -+ -+ b = buffer; -+ for (i = 0; (i + 2) < len; i += 3) { -+ *b++ = table[(data[i] >> 2) & 63]; -+ *b++ = table[((data[i] & 3) << 4 | data[i + 1] >> 4) & 63]; -+ *b++ = table[((data[i + 1] & 15) << 2 | data[i + 2] >> 6) & 63]; -+ *b++ = table[data[i + 2] & 63]; -+ } -+ -+ if ((i + 2) == len) { -+ *b++ = table[(data[i] >> 2) & 63]; -+ *b++ = table[((data[i] & 3) << 4 | data[i + 1] >> 4) & 63]; -+ *b++ = table[((data[i + 1] & 15) << 2) & 63]; -+ *b++ = '='; -+ } else if ((i + 1) == len) { -+ *b++ = table[(data[i] >> 2) & 63]; -+ *b++ = table[((data[i] & 3) << 4) & 63]; -+ *b++ = '='; -+ *b++ = '='; -+ } -+ -+ *b = 0; -+ -+ return buffer; -+} -+ - const tpm_evdigest_t * - parse_digest(const char *string, const char *algo) - { -diff --git a/src/util.h b/src/util.h -index 6f89f4b..79f54cb 100644 ---- a/src/util.h -+++ b/src/util.h -@@ -129,6 +129,8 @@ extern const tpm_evdigest_t *parse_digest(const char *string, const char *algo); - extern void hexdump(const void *data, size_t size, void (*)(const char *, ...), unsigned int indent); - extern const char * print_octet_string(const unsigned char *data, unsigned int len); - -+extern const char * print_base64_value(const unsigned char *data, unsigned int len); -+ - extern bool __convert_from_utf16le(char *in_string, size_t in_bytes, char *out_string, size_t out_bytes); - extern bool __convert_to_utf16le(char *in_string, size_t in_bytes, char *out_string, size_t out_bytes); - - -From 5841fd76d1483af24a71ce022495f6961947eec8 Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Mon, 25 Sep 2023 12:52:44 +0200 -Subject: [PATCH 03/10] util: add print_hex_string function - -Signed-off-by: Alberto Planas ---- - src/util.c | 22 ++++++++++++++++++++++ - src/util.h | 4 +++- - 2 files changed, 25 insertions(+), 1 deletion(-) - -diff --git a/src/util.c b/src/util.c -index 2c90315..4d95b30 100644 ---- a/src/util.c -+++ b/src/util.c -@@ -189,6 +189,28 @@ print_octet_string(const unsigned char *data, unsigned int len) - - } - -+const char * -+print_hex_string(const unsigned char *data, unsigned int len) -+{ -+ static char buffer[2 * 64 + 1]; -+ -+ if (len <= 64) { -+ unsigned int i; -+ char *s; -+ -+ s = buffer; -+ for (i = 0; i < len; ++i) { -+ sprintf(s, "%02x", data[i]); -+ s += 2; -+ } -+ *s = '\0'; -+ } else { -+ snprintf(buffer, sizeof(buffer), "<%u bytes of data>", len); -+ } -+ -+ return buffer; -+} -+ - const char * - print_base64_value(const unsigned char *data, unsigned int len) - { -diff --git a/src/util.h b/src/util.h -index 79f54cb..5168f19 100644 ---- a/src/util.h -+++ b/src/util.h -@@ -129,7 +129,9 @@ extern const tpm_evdigest_t *parse_digest(const char *string, const char *algo); - extern void hexdump(const void *data, size_t size, void (*)(const char *, ...), unsigned int indent); - extern const char * print_octet_string(const unsigned char *data, unsigned int len); - --extern const char * print_base64_value(const unsigned char *data, unsigned int len); -+extern const char * print_hex_string(const unsigned char *data, unsigned int len); -+ -+extern const char * print_base64_value(const unsigned char *data, unsigned int len); - - extern bool __convert_from_utf16le(char *in_string, size_t in_bytes, char *out_string, size_t out_bytes); - extern bool __convert_to_utf16le(char *in_string, size_t in_bytes, char *out_string, size_t out_bytes); - -From 683473448c70ce8fcc87caff5d13647ab264ecbe Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Mon, 25 Sep 2023 13:06:04 +0200 -Subject: [PATCH 04/10] rsa: add tpm_rsa_key_public_digest function - -This function convert the public key into DER format and calculate the -SHA256 hash of it. - -Signed-off-by: Alberto Planas ---- - src/rsa.c | 32 ++++++++++++++++++++++++++++++++ - src/rsa.h | 1 + - 2 files changed, 33 insertions(+) - -diff --git a/src/rsa.c b/src/rsa.c -index 4d3883e..f3f694f 100644 ---- a/src/rsa.c -+++ b/src/rsa.c -@@ -32,6 +32,7 @@ - - #include "util.h" - #include "rsa.h" -+#include "digest.h" - - struct tpm_rsa_key { - bool is_private; -@@ -324,3 +325,34 @@ tpm_rsa_key_to_tss2(const tpm_rsa_key_t *key) - return rsa_pubkey_alloc(n, e, key->path); - } - -+const tpm_evdigest_t * -+tpm_rsa_key_public_digest(tpm_rsa_key_t *pubkey) { -+ unsigned int der_size; -+ unsigned char *der, *bder = NULL; -+ const tpm_algo_info_t *algo; -+ const tpm_evdigest_t *digest = NULL; -+ -+ /* Convert the public key into DER format */ -+ der_size = i2d_PublicKey(pubkey->pkey, NULL); -+ if (der_size < 0) { -+ error("%s: cannot convert public key into DER format", pubkey->path); -+ return NULL; -+ } -+ -+ der = bder = malloc(der_size); -+ der_size = i2d_PublicKey(pubkey->pkey, &der); -+ if (der_size < 0) { -+ error("%s: cannot convert public key into DER format", pubkey->path); -+ goto out; -+ } -+ -+ /* Hash the public key */ -+ algo = digest_by_name("sha256"); -+ digest = digest_compute(algo, bder, der_size); -+ -+ out: -+ if (bder) -+ free(bder); -+ -+ return digest; -+} -diff --git a/src/rsa.h b/src/rsa.h -index 0d73ee8..49c0bb4 100644 ---- a/src/rsa.h -+++ b/src/rsa.h -@@ -37,4 +37,5 @@ extern int tpm_rsa_sign(const tpm_rsa_key_t *, - - extern TPM2B_PUBLIC * tpm_rsa_key_to_tss2(const tpm_rsa_key_t *key); - -+extern const tpm_evdigest_t * tpm_rsa_key_public_digest(tpm_rsa_key_t *pubkey); - #endif /* RSA_H */ - -From 0b0c0d310cdbf779bbfae72329fe0ffbc9c5b2b7 Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Wed, 27 Sep 2023 15:09:31 +0200 -Subject: [PATCH 05/10] util: remove duplicate code - -Signed-off-by: Alberto Planas ---- - src/util.c | 35 +++++++++++++---------------------- - 1 file changed, 13 insertions(+), 22 deletions(-) - -diff --git a/src/util.c b/src/util.c -index 4d95b30..aab9f9d 100644 ---- a/src/util.c -+++ b/src/util.c -@@ -310,15 +310,13 @@ hexdump(const void *data, size_t size, void (*print_fn)(const char *, ...), unsi - } - } - --/* -- * Conversion between UTF-8 and UTF-16LE for EFI event log -- */ -+ - bool --__convert_from_utf16le(char *in_string, size_t in_bytes, char *out_string, size_t out_bytes) -+__convert(const char *tocode, const char *fromcode, char *in_string, size_t in_bytes, char *out_string, size_t out_bytes) - { - iconv_t *ctx; - -- ctx = iconv_open("utf8", "utf16le"); -+ ctx = iconv_open(tocode, fromcode); - - while (in_bytes) { - size_t converted; -@@ -336,26 +334,19 @@ __convert_from_utf16le(char *in_string, size_t in_bytes, char *out_string, size_ - return true; - } - -+/* -+ * Conversion between UTF-8 and UTF-16LE for EFI event log -+ */ - bool --__convert_to_utf16le(char *in_string, size_t in_bytes, char *out_string, size_t out_bytes) -+__convert_from_utf16le(char *in_string, size_t in_bytes, char *out_string, size_t out_bytes) - { -- iconv_t *ctx; -- -- ctx = iconv_open("utf16le", "utf8"); -- -- while (in_bytes) { -- size_t converted; -- -- converted = iconv(ctx, -- &in_string, &in_bytes, -- &out_string, &out_bytes); -- if (converted == (size_t) -1) { -- perror("iconv"); -- return false; -- } -- } -+ return __convert("utf8", "utf16le", in_string, in_bytes, out_string, out_bytes); -+} - -- return true; -+bool -+__convert_to_utf16le(char *in_string, size_t in_bytes, char *out_string, size_t out_bytes) -+{ -+ return __convert("utf16le", "utf8", in_string, in_bytes, out_string, out_bytes); - } - - /* - -From 37edd2b4fdac5b037b68215dfd1546478c359cd5 Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Thu, 28 Sep 2023 16:19:51 +0200 -Subject: [PATCH 06/10] eventlog: parse sd-boot events for PCR12 - -Systemd boot can extend PCR12 with the initrd line. This is stored in -UTF16, that also includes a double 0x00 at the end. - -Signed-off-by: Alberto Planas ---- - src/eventlog.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++- - src/eventlog.h | 6 +++++ - 2 files changed, 64 insertions(+), 1 deletion(-) - -diff --git a/src/eventlog.c b/src/eventlog.c -index 4f4ed44..4f2d3f4 100644 ---- a/src/eventlog.c -+++ b/src/eventlog.c -@@ -551,7 +551,7 @@ tpm_event_decode_uuid(const unsigned char *data) - } - - /* -- * Handle IPL events, which grub2 uses to hide its stuff in -+ * 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) -@@ -764,6 +764,60 @@ __tpm_event_shim_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed, const - return true; - } - -+static void -+__tpm_event_systemd_destroy(tpm_parsed_event_t *parsed) -+{ -+ drop_string(&parsed->systemd_event.string); -+} -+ -+static const char * -+__tpm_event_systemd_describe(const tpm_parsed_event_t *parsed) -+{ -+ static char buffer[1024]; -+ char data[768]; -+ unsigned int len; -+ -+ /* It is in UTF16, and also include two '\0' at the end */ -+ len = parsed->systemd_event.len >> 1; -+ if (len > sizeof(data)) -+ len = sizeof(data); -+ __convert_from_utf16le(parsed->systemd_event.string, parsed->systemd_event.len, data, len); -+ data[len] = '\0'; -+ -+ snprintf(buffer, sizeof(buffer), "systemd boot event %s", data); -+ return buffer; -+} -+ -+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) -+{ -+ if (parsed->systemd_event.string == NULL) -+ return NULL; -+ -+ /* TODO: The hashed string (UTF16) should be the new initrd command */ -+ return digest_compute(ctx->algo, parsed->systemd_event.string, parsed->systemd_event.len); -+} -+ -+/* -+ * This event holds stuff like -+ * initrd = .... -+ */ -+static bool -+__tpm_event_systemd_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed, const char *value, unsigned int len) -+{ -+ struct systemd_event *evspec = &parsed->systemd_event; -+ -+ evspec->len = len; -+ evspec->string = malloc(len); -+ memcpy(evspec->string, value, len); -+ -+ parsed->event_subtype = SYSTEMD_EVENT_VARIABLE; -+ parsed->destroy = __tpm_event_systemd_destroy; -+ parsed->rehash = __tpm_event_systemd_rehash; -+ parsed->describe = __tpm_event_systemd_describe; -+ -+ return true; -+} - - static bool - __tpm_event_parse_ipl(tpm_event_t *ev, tpm_parsed_event_t *parsed, buffer_t *bp) -@@ -788,6 +842,9 @@ __tpm_event_parse_ipl(tpm_event_t *ev, tpm_parsed_event_t *parsed, buffer_t *bp) - if (ev->pcr_index == 9) - return __tpm_event_grub_file_event_parse(ev, parsed, value); - -+ if (ev->pcr_index == 12) -+ return __tpm_event_systemd_event_parse(ev, parsed, value, len); -+ - if (ev->pcr_index == 14) - return __tpm_event_shim_event_parse(ev, parsed, value); - -diff --git a/src/eventlog.h b/src/eventlog.h -index 9acbac4..514fee2 100644 ---- a/src/eventlog.h -+++ b/src/eventlog.h -@@ -92,6 +92,7 @@ enum { - GRUB_EVENT_FILE = 0x0002, - GRUB_EVENT_KERNEL_CMDLINE = 0x0003, - SHIM_EVENT_VARIABLE = 0x0004, -+ SYSTEMD_EVENT_VARIABLE = 0x0005, - }; - - #define EFI_DEVICE_PATH_MAX 16 -@@ -254,6 +255,11 @@ typedef struct tpm_parsed_event { - char * efi_partition; - char * disk_device; - } efi_gpt_event; -+ -+ struct systemd_event { -+ unsigned int len; -+ char * string; -+ } systemd_event; - }; - } tpm_parsed_event_t; - - -From c032131e7d7e45f31aef85ce1fee76c336963101 Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Thu, 28 Sep 2023 16:21:47 +0200 -Subject: [PATCH 07/10] Support measurement of empty EFI vars - -If secure boot is disabled, the PCR7 is still extended with serialized -event structs, but without associated data. - -This patch support the rehash of emtpy EFI vars if they are associated -with PCR7. - -Signed-off-by: Alberto Planas ---- - src/bufparser.h | 19 ++++++++++++++----- - src/efi-variable.c | 5 ++++- - src/runtime.c | 2 +- - 3 files changed, 19 insertions(+), 7 deletions(-) - -diff --git a/src/bufparser.h b/src/bufparser.h -index 0eba6da..3f7c5a6 100644 ---- a/src/bufparser.h -+++ b/src/bufparser.h -@@ -55,13 +55,19 @@ buffer_skip(buffer_t *bp, unsigned int count) - static inline const void * - buffer_read_pointer(const buffer_t *bp) - { -- return bp->data + bp->rpos; -+ if (bp) -+ return bp->data + bp->rpos; -+ else -+ return NULL; - } - - static inline unsigned int - buffer_available(const buffer_t *bp) - { -- return bp->wpos - bp->rpos; -+ if (bp) -+ return bp->wpos - bp->rpos; -+ else -+ return 0; - } - - static inline bool -@@ -206,14 +212,17 @@ buffer_alloc_write(unsigned long size) - static inline void - buffer_free(buffer_t *bp) - { -- free(bp); -+ if (bp) -+ free(bp); - } - - static inline void - buffer_free_secret(buffer_t *bp) - { -- memset(bp->data, 0, bp->size); -- free(bp); -+ if (bp) { -+ memset(bp->data, 0, bp->size); -+ free(bp); -+ } - } - - static inline void * -diff --git a/src/efi-variable.c b/src/efi-variable.c -index 0188273..7e9e38b 100644 ---- a/src/efi-variable.c -+++ b/src/efi-variable.c -@@ -206,7 +206,10 @@ __tpm_event_efi_variable_rehash(const tpm_event_t *ev, const tpm_parsed_event_t - file_data = runtime_read_efi_variable(var_name); - } - -- if (file_data == NULL) { -+ /* The PCR 7 is always expanded, even if the data is empty */ -+ if (file_data == NULL -+ && ev->event_type != TPM2_EFI_VARIABLE_DRIVER_CONFIG -+ && ev->pcr_index != 7) { - if (parsed->efi_variable_event.len == 0) { - /* The content of the variable doesn't exist during the measurement - * and is also not available at runtime. Let's skip this event. -diff --git a/src/runtime.c b/src/runtime.c -index f2ae90f..39acb25 100644 ---- a/src/runtime.c -+++ b/src/runtime.c -@@ -157,7 +157,7 @@ __system_read_efi_variable(const char *var_name) - } - - if (result == NULL) -- error("Unable to read EFI variable \"%s\"\n", var_name); -+ debug("Unable to read EFI variable \"%s\"\n", var_name); - else if (testcase_recording) - testcase_record_efi_variable(testcase_recording, var_name, result); - - -From 45a8f1f8becabfe8aa24d933ad71a6e8e4f481ed Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Fri, 6 Oct 2023 09:53:56 +0200 -Subject: [PATCH 08/10] Add pcr_policy_sign_systemd - -Similar to pcr_policy_sign, the new function will create a pcr policy -and sign it, but the output will be a JSON file expected by -systemd-cryptenroll. - -Signed-off-by: Alberto Planas ---- - src/pcr-policy.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/pcr.h | 2 ++ - 2 files changed, 52 insertions(+) - -diff --git a/src/pcr-policy.c b/src/pcr-policy.c -index bc882da..dd54ad0 100644 ---- a/src/pcr-policy.c -+++ b/src/pcr-policy.c -@@ -1538,3 +1538,53 @@ pcr_policy_unseal_tpm2key(const char *input_path, const char *output_path) - - return okay; - } -+ -+bool -+pcr_policy_sign_systemd(const tpm_pcr_bank_t *bank, const char *rsakey_path, -+ const char *output_path) -+{ -+ bool ok = false; -+ FILE *fp = NULL; -+ tpm_rsa_key_t *rsa_key = NULL; -+ const tpm_evdigest_t *digest; -+ ESYS_CONTEXT *esys_context = tss_esys_context(); -+ TPM2B_DIGEST *pcr_policy = NULL; -+ TPMT_SIGNATURE *signed_policy = NULL; -+ -+ if (!(fp = fopen(output_path, "w"))) { -+ error("Cannot open systemd JSON file %s: %m\n", output_path); -+ goto out; -+ } -+ -+ if (!(rsa_key = tpm_rsa_key_read_private(rsakey_path))) -+ goto out; -+ digest = tpm_rsa_key_public_digest(rsa_key); -+ -+ if (!(pcr_policy = __pcr_policy_make(esys_context, bank))) -+ goto out; -+ -+ if (!__pcr_policy_sign(rsa_key, pcr_policy, &signed_policy)) -+ goto out; -+ -+ fprintf(fp, "{\n"); -+ fprintf(fp, "\t\"%s\": [\n", bank->algo_name); -+ fprintf(fp, "\t\t\{\n"); -+ fprintf(fp, "\t\t\t\"pcrs\": [\n"); -+ fprintf(fp, "\t\t\t\t%s\n", print_pcr_mask(bank->pcr_mask)); -+ fprintf(fp, "\t\t\t],\n"); -+ fprintf(fp, "\t\t\t\"pkfp\": \"%s\",\n", print_hex_string(digest->data, digest->size)); -+ fprintf(fp, "\t\t\t\"pol\": \"%s\",\n", print_hex_string(pcr_policy->buffer, pcr_policy->size)); -+ fprintf(fp, "\t\t\t\"sig\": \"%s\"\n", print_base64_value(signed_policy->signature.rsassa.sig.buffer, signed_policy->signature.rsassa.sig.size)); -+ fprintf(fp, "\t\t\}\n"); -+ fprintf(fp, "\t]\n"); -+ fprintf(fp, "}\n"); -+ -+ ok = true; -+ -+out: -+ if (rsa_key) -+ tpm_rsa_key_free(rsa_key); -+ -+ fclose(fp); -+ return ok; -+} -diff --git a/src/pcr.h b/src/pcr.h -index 5138e54..cc0fb0f 100644 ---- a/src/pcr.h -+++ b/src/pcr.h -@@ -61,6 +61,8 @@ extern bool pcr_store_public_key(const char *rsakey_path, const char *output_pa - extern bool pcr_policy_sign(const bool tpm2key_fmt, const tpm_pcr_bank_t *bank, - const char *rsakey_path, const char *input_path, - const char *output_path, const char *policy_name); -+extern bool pcr_policy_sign_systemd(const tpm_pcr_bank_t *bank, const char *rsakey_path, -+ const char *output_path); - extern bool pcr_authorized_policy_seal_secret(const bool tpm2key_fmt, - const char *authorized_policy, const char *input_path, - const char *output_path); - -From 2d135060fee1eff8da74e756ac19dc128691a1f2 Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Fri, 6 Oct 2023 10:01:08 +0200 -Subject: [PATCH 09/10] Add --policy-format parameter - -Signed-off-by: Alberto Planas ---- - src/oracle.c | 33 +++++++++++++++++++++++++++------ - 1 file changed, 27 insertions(+), 6 deletions(-) - -diff --git a/src/oracle.c b/src/oracle.c -index 0a7668e..1db8285 100644 ---- a/src/oracle.c -+++ b/src/oracle.c -@@ -93,6 +93,7 @@ enum { - OPT_PCR_POLICY, - OPT_KEY_FORMAT, - OPT_POLICY_NAME, -+ OPT_POLICY_FORMAT, - }; - - static struct option options[] = { -@@ -121,6 +122,7 @@ static struct option options[] = { - { "pcr-policy", required_argument, 0, OPT_PCR_POLICY }, - { "key-format", required_argument, 0, OPT_KEY_FORMAT }, - { "policy-name", required_argument, 0, OPT_POLICY_NAME }, -+ { "policy-format", required_argument, 0, OPT_POLICY_FORMAT }, - - { NULL } - }; -@@ -1008,7 +1010,9 @@ main(int argc, char **argv) - bool opt_rsa_generate = false; - char *opt_key_format = NULL; - char *opt_policy_name = NULL; -+ char *opt_policy_format = NULL; - bool tpm2key_fmt = false; -+ int systemd_json = false; - int c, exit_code = 0; - - while ((c = getopt_long(argc, argv, "dhA:CF:LSZ", options, NULL)) != EOF) { -@@ -1088,6 +1092,9 @@ main(int argc, char **argv) - case OPT_POLICY_NAME: - opt_policy_name = optarg; - break; -+ case OPT_POLICY_FORMAT: -+ opt_policy_format = optarg; -+ break; - case 'h': - usage(0, NULL); - default: -@@ -1114,6 +1121,14 @@ main(int argc, char **argv) - else - fatal("Unsupported key format \"%s\"\n", opt_key_format); - -+ if (!opt_policy_format || !strcasecmp(opt_policy_format, "grub2")) -+ systemd_json = false; -+ else -+ if (!strcasecmp(opt_policy_format, "systemd")) -+ systemd_json = true; -+ else -+ fatal("Unsupported policy format \"%s\"\n", opt_policy_format); -+ - /* Validate options */ - switch (action) { - case ACTION_PREDICT: -@@ -1163,10 +1178,11 @@ main(int argc, char **argv) - case ACTION_SIGN: - if (opt_rsa_private_key == NULL) - usage(1, "You need to specify the --private-key option when signing a policy\n"); -- if (tpm2key_fmt) { -- if (opt_input == NULL) -- usage(1, "You need to specify the --input option when signing a policy into a TPM 2.0 Key file\n"); -- } -+ if (systemd_json && opt_output == NULL) -+ usage(1, "You need to specify the --output option when signing a systemd policy\n"); -+ if (tpm2key_fmt && opt_input == NULL) -+ usage(1, "You need to specify the --input option when signing a policy into a TPM 2.0 Key file\n"); -+ - pcr_selection = get_pcr_selection_argument(argc, argv, opt_algo); - end_arguments(argc, argv); - break; -@@ -1268,8 +1284,13 @@ main(int argc, char **argv) - return 1; - } else - if (action == ACTION_SIGN) { -- if (!pcr_policy_sign(tpm2key_fmt, &pred->prediction, opt_rsa_private_key, opt_input, opt_output, opt_policy_name)) -- return 1; -+ if (systemd_json) { -+ if (!pcr_policy_sign_systemd(&pred->prediction, opt_rsa_private_key, opt_output)) -+ return 1; -+ } else { -+ if (!pcr_policy_sign(tpm2key_fmt, &pred->prediction, opt_rsa_private_key, opt_input, opt_output, opt_policy_name)) -+ return 1; -+ } - } - - return exit_code; - -From 822ae935ada56b11a8e0b6a44d393f24311c91af Mon Sep 17 00:00:00 2001 -From: Alberto Planas -Date: Wed, 18 Oct 2023 15:45:47 +0200 -Subject: [PATCH 10/10] Predict PCR12 for systemd-boot - -Generate the list of boot entries, sorted using the BLS algorithm (that -will select the latest kernel). From this, compose the initrd entry -that will be used to exted the PCR12 register. - -Signed-off-by: Alberto Planas ---- - Makefile.in | 3 +- - src/eventlog.c | 21 ++++- - src/sd-boot.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++ - src/sd-boot.h | 44 +++++++++ - 4 files changed, 315 insertions(+), 3 deletions(-) - create mode 100644 src/sd-boot.c - create mode 100644 src/sd-boot.h - -diff --git a/Makefile.in b/Makefile.in -index bfcb3f3..cf7b141 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -30,7 +30,8 @@ ORACLE_SRCS = oracle.c \ - platform.c \ - testcase.c \ - bufparser.c \ -- util.c -+ util.c \ -+ sd-boot.c - ORACLE_OBJS = $(addprefix build/,$(patsubst %.c,%.o,$(ORACLE_SRCS))) - - all: $(TOOLS) $(MANPAGES) -diff --git a/src/eventlog.c b/src/eventlog.c -index 4f2d3f4..7de9cd6 100644 ---- a/src/eventlog.c -+++ b/src/eventlog.c -@@ -31,6 +31,7 @@ - #include "runtime.h" - #include "digest.h" - #include "util.h" -+#include "sd-boot.h" - - #define TPM_EVENT_LOG_MAX_ALGOS 64 - -@@ -791,11 +792,27 @@ __tpm_event_systemd_describe(const tpm_parsed_event_t *parsed) - 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) - { -+ sdb_entry_list_t entry_list; -+ char initrd[1024]; -+ char initrd_utf16[2048]; -+ unsigned int len; -+ - if (parsed->systemd_event.string == NULL) - return NULL; - -- /* TODO: The hashed string (UTF16) should be the new initrd command */ -- return digest_compute(ctx->algo, parsed->systemd_event.string, parsed->systemd_event.len); -+ if (!sdb_get_entry_list(&entry_list)) { -+ error("Error generating the list of boot entries\n"); -+ return NULL; -+ } -+ -+ debug("Next boot entry expected from: %s\n", entry_list.entries[0].path); -+ snprintf(initrd, sizeof(initrd), "initrd=%s %s", -+ entry_list.entries[0].initrd, entry_list.entries[0].options); -+ -+ len = (strlen(initrd) + 1) << 2; -+ __convert_to_utf16le(initrd, strlen(initrd) + 1, initrd_utf16, len); -+ -+ return digest_compute(ctx->algo, initrd_utf16, len); - } - - /* -diff --git a/src/sd-boot.c b/src/sd-boot.c -new file mode 100644 -index 0000000..56a4257 ---- /dev/null -+++ b/src/sd-boot.c -@@ -0,0 +1,250 @@ -+/* -+ * 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. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sd-boot.h" -+#include "util.h" -+ -+static char * -+machine_id() -+{ -+ static char id[33]; -+ FILE *fp; -+ -+ if (!(fp = fopen("/etc/machine-id", "r"))) { -+ error("Cannot read /etc/machine_id: %m\n"); -+ goto fail; -+ } -+ if (fread(id, 32, 1, fp) != 1) { -+ error("Cannot read /etc/machine_id: %m\n"); -+ goto fail; -+ } -+ -+ id[32] = '\0'; -+ return id; -+ -+fail: -+ fclose(fp); -+ return NULL; -+} -+ -+static bool -+read_entry(sdb_entry_data_t *result) -+{ -+ FILE *fp; -+ char line[SDB_LINE_MAX]; -+ -+ if (!(fp = fopen(result->path, "r"))) { -+ error("Cannot read %s: %m\n", result->path); -+ goto fail; -+ } -+ -+ while (fgets(line, SDB_LINE_MAX, fp)) { -+ char *dest = NULL; -+ -+ if (!strncmp("sort-key", line, strlen("sort-key"))) -+ dest = result->sort_key; -+ else -+ if (!strncmp("machine-id", line, strlen("machine-id"))) -+ dest = result->machine_id; -+ else -+ if (!strncmp("version", line, strlen("version"))) -+ dest = result->version; -+ else -+ if (!strncmp("options", line, strlen("options"))) -+ dest = result->options; -+ else -+ if (!strncmp("initrd", line, strlen("initrd"))) -+ dest = result->initrd; -+ else -+ continue; -+ -+ /* Position the index on the value section of the line */ -+ unsigned int index = 0; -+ while (line[++index] != ' '); -+ while (line[++index] == ' '); -+ strncpy(dest, &line[index], strlen(&line[index]) - 1); -+ } -+ -+ return true; -+ -+fail: -+ fclose(fp); -+ return false; -+} -+ -+static int -+cmp(int a, int b) -+{ -+ return a - b; -+} -+ -+static bool -+isvalid(char a) -+{ -+ return isalnum(a) || a == '~' || a == '-' || a == '^' || a == '.'; -+} -+ -+static int -+natoi(const char *a, unsigned int n) -+{ -+ char line[SDB_LINE_MAX]; -+ -+ strncpy(line, a, MIN(SDB_LINE_MAX, n)); -+ return atoi(line); -+} -+ -+static int -+vercmp(const void *va, const void *vb) -+{ -+ /* https://uapi-group.org/specifications/specs/version_format_specification/ */ -+ /* This code is based on strverscmp_improved from systemd */ -+ -+ const char *a = va; -+ const char *b = vb; -+ const char *sep = "~-^."; -+ -+ assert(a != NULL); -+ assert(b != NULL); -+ -+ for(;;) { -+ const char *aa, *bb; -+ int r; -+ -+ while (*a != '\0' && !isvalid(*a)) -+ a++; -+ while (*b != '\0' && !isvalid(*b)) -+ b++; -+ -+ /* The longer string is considered new */ -+ if (*a == '\0' || *b == '\0') -+ return cmp(*a, *b); -+ -+ for (int i = 0; i < strlen(sep); i++) { -+ char s = sep[i]; -+ -+ if (*a == s || *b == s) { -+ r = cmp(*a != s, *b != s); -+ if (r != 0) -+ return r; -+ -+ a++; -+ b++; -+ } -+ } -+ -+ if (isdigit(*a) || isdigit(*b)) { -+ for (aa = a; isdigit(*aa); aa++); -+ for (bb = b; isdigit(*bb); bb++); -+ -+ r = cmp(a != aa, b != bb); -+ if (r != 0) -+ return r; -+ -+ r = cmp(natoi(a, aa - a), natoi(b, bb - b)); -+ if (r != 0) -+ return r; -+ } else { -+ for (aa = a; isalpha(*aa); aa++); -+ for (bb = b; isalpha(*bb); bb++); -+ -+ r = cmp(strncmp(a, b, MIN(aa - a, bb - b)), 0); -+ if (r != 0) -+ return r; -+ -+ r = cmp(aa - a, bb - b); -+ if (r != 0) -+ return r; -+ } -+ -+ a = aa; -+ b = bb; -+ } -+} -+ -+static int -+entrycmp(const void *va, const void *vb) -+{ -+ /* https://uapi-group.org/specifications/specs/boot_loader_specification/#sorting */ -+ int result; -+ const sdb_entry_data_t *a = va; -+ const sdb_entry_data_t *b = vb; -+ -+ result = strcmp(a->sort_key, b->sort_key); -+ -+ if (result == 0) -+ result = strcmp(a->machine_id, b->machine_id); -+ -+ if (result == 0) -+ result = vercmp(a->version, b->version); -+ -+ /* Reverse the order, so new kernels appears first */ -+ return -result; -+} -+ -+bool -+sdb_get_entry_list(sdb_entry_list_t *result) -+{ -+ char *id = NULL; -+ DIR *d = NULL; -+ struct dirent *dir; -+ char *path = "/boot/efi/loader/entries"; -+ -+ memset(result, 0, sizeof(*result)); -+ -+ if (!(id = machine_id())) -+ goto fail; -+ -+ if (!(d = opendir(path))) { -+ error("Cannot read directory contents from /boot/efi/loader/entries: %m\n"); -+ goto fail; -+ } -+ -+ while ((dir = readdir(d)) != NULL) { -+ if (strncmp(id, dir->d_name, strlen(id))) -+ continue; -+ -+ debug("Bootloader entry %s\n", dir->d_name); -+ -+ snprintf(result->entries[result->num_entries].path, PATH_MAX, "%s/%s", path, dir->d_name); -+ if (!read_entry(&result->entries[result->num_entries])) { -+ error("Cannot read bootloader entry %s\n", dir->d_name); -+ continue; -+ } -+ -+ result->num_entries++; -+ } -+ -+ qsort(result->entries, result->num_entries, sizeof(result->entries[0]), entrycmp); -+ -+ return true; -+ -+fail: -+ closedir(d); -+ return false; -+} -+ -diff --git a/src/sd-boot.h b/src/sd-boot.h -new file mode 100644 -index 0000000..80f21d6 ---- /dev/null -+++ b/src/sd-boot.h -@@ -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. -+ * -+ */ -+ -+#ifndef SD_BOOT_H -+#define SD_BOOT_H -+ -+#include -+ -+#define SDB_MAX_ENTRIES 16 -+#define SDB_LINE_MAX 512 -+ -+typedef struct sdb_entry_data { -+ char path[PATH_MAX]; -+ char sort_key[SDB_LINE_MAX]; -+ char machine_id[SDB_LINE_MAX]; -+ char version[SDB_LINE_MAX]; -+ char options[SDB_LINE_MAX]; -+ char initrd[SDB_LINE_MAX]; -+} sdb_entry_data_t; -+ -+typedef struct sdb_entry_list { -+ unsigned int num_entries; -+ sdb_entry_data_t entries[SDB_MAX_ENTRIES]; -+} sdb_entry_list_t; -+ -+extern bool sdb_get_entry_list(sdb_entry_list_t *result); -+ -+#endif /* SD_BOOT_H */