832 lines
28 KiB
Diff
832 lines
28 KiB
Diff
|
From 350e8d823db1febc2c81635115ef3c4c0f41f3e7 Mon Sep 17 00:00:00 2001
|
||
|
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
|
||
|
Date: Tue, 17 Jan 2023 22:38:05 +0530
|
||
|
Subject: [PATCH 3/8] appendedsig: The creation of trusted and distrusted lists
|
||
|
|
||
|
The trusted certificates and binary hashes, distrusted certificates and
|
||
|
binary/certificate hashes will be extracted from the platform keystore buffer
|
||
|
if Secure Boot is enabled with PKS.
|
||
|
In order to verify the integerity of the kernel, the extracted data
|
||
|
would be stored in the buffer db and dbx.
|
||
|
|
||
|
The trusted certificates will be extracted from the grub ELFNOTE if Secure Boot is
|
||
|
enabled with static key. In order to verify the integerity of the kernel,
|
||
|
the extracted data would be stored in the buffer db.
|
||
|
|
||
|
Note:-
|
||
|
|
||
|
if the trusted certificate nor binary hash exists in the distrusted list (DBX),
|
||
|
rejected it while extracting it from the platform keystore buffer.
|
||
|
|
||
|
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
|
||
|
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
|
||
|
Tested-by: Nageswara Sastry <rnsastry@linux.ibm.com>
|
||
|
---
|
||
|
grub-core/commands/appendedsig/appendedsig.c | 701 +++++++++++++++++--
|
||
|
1 file changed, 635 insertions(+), 66 deletions(-)
|
||
|
|
||
|
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
|
||
|
index e63ad1ac6..5bb09e349 100644
|
||
|
--- a/grub-core/commands/appendedsig/appendedsig.c
|
||
|
+++ b/grub-core/commands/appendedsig/appendedsig.c
|
||
|
@@ -33,7 +33,7 @@
|
||
|
#include <grub/libtasn1.h>
|
||
|
#include <grub/env.h>
|
||
|
#include <grub/lockdown.h>
|
||
|
-
|
||
|
+#include <grub/platform_keystore.h>
|
||
|
#include "appendedsig.h"
|
||
|
|
||
|
GRUB_MOD_LICENSE ("GPLv3+");
|
||
|
@@ -66,8 +66,23 @@ struct grub_appended_signature
|
||
|
struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */
|
||
|
};
|
||
|
|
||
|
-/* Trusted certificates for verifying appended signatures */
|
||
|
-struct x509_certificate *grub_trusted_key;
|
||
|
+/* This represents a trusted/distrusted list*/
|
||
|
+struct grub_database
|
||
|
+{
|
||
|
+ struct x509_certificate *keys; /* Certificates */
|
||
|
+ grub_size_t key_entries; /* Number of certificates */
|
||
|
+ grub_uint8_t **signatures; /* Certificate/binary hashes */
|
||
|
+ grub_size_t *signature_size; /* Size of certificate/binary hashes */
|
||
|
+ grub_size_t signature_entries; /* Number of certificate/binary hashes */
|
||
|
+};
|
||
|
+
|
||
|
+/* Trusted list */
|
||
|
+struct grub_database grub_db = {.keys = NULL, .key_entries = 0, .signatures = NULL,
|
||
|
+ .signature_size = NULL, .signature_entries = 0};
|
||
|
+
|
||
|
+/* Distrusted list */
|
||
|
+struct grub_database grub_dbx = {.signatures = NULL, .signature_size = NULL,
|
||
|
+ .signature_entries = 0};
|
||
|
|
||
|
/*
|
||
|
* Force gcry_rsa to be a module dependency.
|
||
|
@@ -90,12 +105,263 @@ struct x509_certificate *grub_trusted_key;
|
||
|
*/
|
||
|
extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
|
||
|
|
||
|
+extern gcry_md_spec_t _gcry_digest_spec_sha224;
|
||
|
+extern gcry_md_spec_t _gcry_digest_spec_sha384;
|
||
|
+
|
||
|
+/* releasing trusted list memory */
|
||
|
+static void grub_release_trusted_list (void);
|
||
|
+/* releasing distrusted list memory */
|
||
|
+static void grub_release_distrusted_list (void);
|
||
|
+
|
||
|
static enum
|
||
|
{ check_sigs_no = 0,
|
||
|
check_sigs_enforce = 1,
|
||
|
check_sigs_forced = 2
|
||
|
} check_sigs = check_sigs_no;
|
||
|
|
||
|
+/*
|
||
|
+ * GUID can be used to determine the hashing function and
|
||
|
+ * generate the hash using determined hashing function.
|
||
|
+ */
|
||
|
+static grub_err_t
|
||
|
+grub_get_hash (const grub_uuid_t *guid, const grub_uint8_t *data, const grub_size_t data_size,
|
||
|
+ grub_uint8_t *hash, grub_size_t *hash_size)
|
||
|
+{
|
||
|
+ gcry_md_spec_t *hash_func = NULL;
|
||
|
+
|
||
|
+ if (guid == NULL)
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "signature data type is null");
|
||
|
+
|
||
|
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
|
||
|
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_UUID_SIZE) == 0)
|
||
|
+ hash_func = &_gcry_digest_spec_sha256;
|
||
|
+ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
|
||
|
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_UUID_SIZE) == 0)
|
||
|
+ hash_func = &_gcry_digest_spec_sha384;
|
||
|
+ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE) == 0 ||
|
||
|
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_UUID_SIZE) == 0)
|
||
|
+ hash_func = &_gcry_digest_spec_sha512;
|
||
|
+ else
|
||
|
+ return GRUB_ERR_UNKNOWN_COMMAND;
|
||
|
+
|
||
|
+ grub_memset (hash, 0x00, GRUB_MAX_HASH_SIZE);
|
||
|
+ grub_crypto_hash (hash_func, hash, data, data_size);
|
||
|
+ *hash_size = hash_func->mdlen;
|
||
|
+
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
+
|
||
|
+/* adding the certificate/binary hash into the trusted/distrusted list */
|
||
|
+static grub_err_t
|
||
|
+grub_add_hash (const grub_uint8_t **data, const grub_size_t data_size,
|
||
|
+ grub_uint8_t ***signature_list, grub_size_t **signature_size_list,
|
||
|
+ grub_size_t *signature_list_entries)
|
||
|
+{
|
||
|
+ grub_uint8_t **signatures = *signature_list;
|
||
|
+ grub_size_t *signature_size = *signature_size_list;
|
||
|
+ grub_size_t signature_entries = *signature_list_entries;
|
||
|
+
|
||
|
+ if (*data == NULL || data_size == 0)
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate/binary hash data/size is null");
|
||
|
+
|
||
|
+ if (signatures == NULL && signature_size == NULL)
|
||
|
+ {
|
||
|
+ signatures = grub_zalloc (sizeof (grub_uint8_t *));
|
||
|
+ signature_size = grub_zalloc (sizeof (grub_size_t));
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ signatures = grub_realloc (signatures, sizeof (grub_uint8_t *) * (signature_entries + 1));
|
||
|
+ signature_size = grub_realloc (signature_size,
|
||
|
+ sizeof (grub_size_t) * (signature_entries + 1));
|
||
|
+ }
|
||
|
+
|
||
|
+ if (signatures == NULL || signature_size == NULL)
|
||
|
+ {
|
||
|
+ /*
|
||
|
+ * allocated memory will be freed by
|
||
|
+ * grub_release_trusted_list/grub_release_distrusted_list
|
||
|
+ */
|
||
|
+ if (signatures != NULL)
|
||
|
+ {
|
||
|
+ *signature_list = signatures;
|
||
|
+ *signature_list_entries = signature_entries + 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (signature_size != NULL)
|
||
|
+ *signature_size_list = signature_size;
|
||
|
+
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||
|
+ }
|
||
|
+
|
||
|
+ signatures[signature_entries] = (grub_uint8_t *) *data;
|
||
|
+ signature_size[signature_entries] = data_size;
|
||
|
+ signature_entries++;
|
||
|
+ *data = NULL;
|
||
|
+
|
||
|
+ *signature_list = signatures;
|
||
|
+ *signature_size_list = signature_size;
|
||
|
+ *signature_list_entries = signature_entries;
|
||
|
+
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
+
|
||
|
+static grub_err_t
|
||
|
+grub_is_x509 (const grub_uuid_t *guid)
|
||
|
+{
|
||
|
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_GUID, GRUB_UUID_SIZE) == 0)
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+
|
||
|
+ return GRUB_ERR_UNKNOWN_COMMAND;
|
||
|
+}
|
||
|
+
|
||
|
+static grub_err_t
|
||
|
+grub_is_cert_match (const struct x509_certificate *distrusted_cert,
|
||
|
+ const struct x509_certificate *db_cert)
|
||
|
+{
|
||
|
+
|
||
|
+ if (grub_memcmp (distrusted_cert->subject, db_cert->subject, db_cert->subject_len) == 0
|
||
|
+ && grub_memcmp (distrusted_cert->serial, db_cert->serial, db_cert->serial_len) == 0
|
||
|
+ && grub_memcmp (distrusted_cert->mpis[0], db_cert->mpis[0], sizeof (db_cert->mpis[0])) == 0
|
||
|
+ && grub_memcmp (distrusted_cert->mpis[1], db_cert->mpis[1], sizeof (db_cert->mpis[1])) == 0)
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+
|
||
|
+ return GRUB_ERR_UNKNOWN_COMMAND;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * verify the certificate against the certificate from platform keystore buffer's
|
||
|
+ * distrusted list, if it is present, return a bad signature.
|
||
|
+ * else, no errors.
|
||
|
+ */
|
||
|
+static grub_err_t
|
||
|
+grub_is_distrusted_cert (const struct x509_certificate *db_cert)
|
||
|
+{
|
||
|
+ grub_err_t rc = GRUB_ERR_NONE;
|
||
|
+ grub_size_t i = 0;
|
||
|
+ struct x509_certificate *distrusted_cert = NULL;
|
||
|
+
|
||
|
+ for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
|
||
|
+ {
|
||
|
+ if (grub_platform_keystore.dbx[i].data == NULL &&
|
||
|
+ grub_platform_keystore.dbx[i].data_size == 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (grub_is_x509 (&grub_platform_keystore.dbx[i].guid) == GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ distrusted_cert = grub_zalloc (sizeof (struct x509_certificate));
|
||
|
+ if (distrusted_cert == NULL)
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||
|
+
|
||
|
+ rc = parse_x509_certificate (grub_platform_keystore.dbx[i].data,
|
||
|
+ grub_platform_keystore.dbx[i].data_size, distrusted_cert);
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ grub_free (distrusted_cert);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (grub_is_cert_match (distrusted_cert, db_cert) == GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ grub_printf ("Warning: a trusted certificate CN='%s' is ignored "
|
||
|
+ "because it is on the distrusted list (dbx).\n", db_cert->subject);
|
||
|
+ grub_free (grub_platform_keystore.dbx[i].data);
|
||
|
+ grub_memset (&grub_platform_keystore.dbx[i], 0x00,
|
||
|
+ sizeof (grub_platform_keystore.dbx[i]));
|
||
|
+ certificate_release (distrusted_cert);
|
||
|
+ grub_free (distrusted_cert);
|
||
|
+ return GRUB_ERR_BAD_SIGNATURE;
|
||
|
+ }
|
||
|
+
|
||
|
+ certificate_release (distrusted_cert);
|
||
|
+ grub_free (distrusted_cert);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
+
|
||
|
+/* adding the certificate into the trusted/distrusted list */
|
||
|
+static grub_err_t
|
||
|
+grub_add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
|
||
|
+ struct grub_database *database, const grub_uint8_t is_db)
|
||
|
+{
|
||
|
+ grub_err_t rc = GRUB_ERR_NONE;
|
||
|
+ grub_size_t key_entries = database->key_entries;
|
||
|
+ struct x509_certificate *cert = NULL;
|
||
|
+
|
||
|
+ if (data == NULL || data_size == 0)
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate data/size is null");
|
||
|
+
|
||
|
+ cert = grub_zalloc (sizeof (struct x509_certificate));
|
||
|
+ if (cert == NULL)
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||
|
+
|
||
|
+ rc = parse_x509_certificate (data, data_size, cert);
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ grub_printf ("Warning: skipping %s certificate (%d)\n",
|
||
|
+ (is_db ? "trusted":"distrused"), rc);
|
||
|
+ grub_free (cert);
|
||
|
+ return rc;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (is_db)
|
||
|
+ {
|
||
|
+ rc = grub_is_distrusted_cert (cert);
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ certificate_release (cert);
|
||
|
+ grub_free (cert);
|
||
|
+ return rc;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ grub_dprintf ("appendedsig", "add a %s certificate CN='%s'\n",
|
||
|
+ (is_db ? "trusted":"distrused"), cert->subject);
|
||
|
+
|
||
|
+ key_entries++;
|
||
|
+ cert->next = database->keys;
|
||
|
+ database->keys = cert;
|
||
|
+ database->key_entries = key_entries;
|
||
|
+
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+static grub_err_t
|
||
|
+grub_read_file (const grub_file_t file, grub_uint8_t **data, grub_ssize_t *data_size)
|
||
|
+{
|
||
|
+ grub_uint8_t *buffer = NULL;
|
||
|
+ grub_ssize_t read_size = 0;
|
||
|
+ grub_off_t total_read_size = 0;
|
||
|
+ grub_off_t file_size = grub_file_size (file);
|
||
|
+
|
||
|
+ if (file_size == GRUB_FILE_SIZE_UNKNOWN)
|
||
|
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||
|
+ N_("could not parse the unknown size of the file."));
|
||
|
+
|
||
|
+ buffer = grub_zalloc (file_size);
|
||
|
+ if (buffer == NULL)
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
|
||
|
+
|
||
|
+ while (total_read_size < file_size)
|
||
|
+ {
|
||
|
+ read_size = grub_file_read (file, &buffer[total_read_size], file_size - total_read_size);
|
||
|
+ if (read_size < 0)
|
||
|
+ {
|
||
|
+ grub_free (buffer);
|
||
|
+ return grub_error (GRUB_ERR_READ_ERROR, N_("unable to read the file"));
|
||
|
+ }
|
||
|
+
|
||
|
+ total_read_size += read_size;
|
||
|
+ }
|
||
|
+
|
||
|
+ *data = buffer;
|
||
|
+ *data_size = total_read_size;
|
||
|
+
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
+
|
||
|
static const char *
|
||
|
grub_env_read_sec (struct grub_env_var *var __attribute__((unused)),
|
||
|
const char *val __attribute__((unused)))
|
||
|
@@ -153,10 +419,7 @@ file_read_all (grub_file_t file, grub_uint8_t **buf, grub_size_t *len)
|
||
|
|
||
|
while (total_read_size < file_size)
|
||
|
{
|
||
|
- read_size =
|
||
|
- grub_file_read (file, *buf + total_read_size,
|
||
|
- file_size - total_read_size);
|
||
|
-
|
||
|
+ read_size = grub_file_read (file, *buf + total_read_size, file_size - total_read_size);
|
||
|
if (read_size < 0)
|
||
|
{
|
||
|
grub_free (*buf);
|
||
|
@@ -267,9 +530,8 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
|
||
|
struct pkcs7_signerInfo *si;
|
||
|
int i;
|
||
|
|
||
|
- if (!grub_trusted_key)
|
||
|
- return grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||
|
- N_("No trusted keys to verify against"));
|
||
|
+ if (!grub_db.key_entries)
|
||
|
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
|
||
|
|
||
|
err = extract_appended_signature (buf, bufsize, &sig);
|
||
|
if (err != GRUB_ERR_NONE)
|
||
|
@@ -299,17 +561,16 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
|
||
|
datasize, i, hash[0], hash[1], hash[2], hash[3]);
|
||
|
|
||
|
err = GRUB_ERR_BAD_SIGNATURE;
|
||
|
- for (pk = grub_trusted_key; pk; pk = pk->next)
|
||
|
- {
|
||
|
- rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
|
||
|
- if (rc)
|
||
|
- {
|
||
|
- err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||
|
- N_("Error padding hash for RSA verification: %d"),
|
||
|
- rc);
|
||
|
- grub_free (context);
|
||
|
- goto cleanup;
|
||
|
- }
|
||
|
+ for (pk = grub_db.keys; pk; pk = pk->next)
|
||
|
+ {
|
||
|
+ rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
|
||
|
+ if (rc)
|
||
|
+ {
|
||
|
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||
|
+ N_("Error padding hash for RSA verification: %d"), rc);
|
||
|
+ grub_free (context);
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
|
||
|
rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi,
|
||
|
pk->mpis, NULL, NULL);
|
||
|
@@ -402,16 +663,16 @@ grub_cmd_distrust (grub_command_t cmd __attribute__((unused)),
|
||
|
|
||
|
if (cert_num == 1)
|
||
|
{
|
||
|
- cert = grub_trusted_key;
|
||
|
- grub_trusted_key = cert->next;
|
||
|
+ cert = grub_db.keys;
|
||
|
+ grub_db.keys = cert->next;
|
||
|
|
||
|
certificate_release (cert);
|
||
|
grub_free (cert);
|
||
|
return GRUB_ERR_NONE;
|
||
|
}
|
||
|
i = 2;
|
||
|
- prev = grub_trusted_key;
|
||
|
- cert = grub_trusted_key->next;
|
||
|
+ prev = grub_db.keys;
|
||
|
+ cert = grub_db.keys->next;
|
||
|
while (cert)
|
||
|
{
|
||
|
if (i == cert_num)
|
||
|
@@ -464,8 +725,8 @@ grub_cmd_trust (grub_command_t cmd __attribute__((unused)),
|
||
|
grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n",
|
||
|
cert->subject);
|
||
|
|
||
|
- cert->next = grub_trusted_key;
|
||
|
- grub_trusted_key = cert;
|
||
|
+ cert->next = grub_db.keys;
|
||
|
+ grub_db.keys = cert;
|
||
|
|
||
|
return GRUB_ERR_NONE;
|
||
|
}
|
||
|
@@ -479,7 +740,7 @@ grub_cmd_list (grub_command_t cmd __attribute__((unused)),
|
||
|
int cert_num = 1;
|
||
|
grub_size_t i;
|
||
|
|
||
|
- for (cert = grub_trusted_key; cert; cert = cert->next)
|
||
|
+ for (cert = grub_db.keys; cert; cert = cert->next)
|
||
|
{
|
||
|
grub_printf (N_("Certificate %d:\n"), cert_num);
|
||
|
|
||
|
@@ -577,6 +838,305 @@ static struct grub_fs pseudo_fs = {
|
||
|
.fs_read = pseudo_read
|
||
|
};
|
||
|
|
||
|
+/*
|
||
|
+ * verify the trusted certificate against the certificate hashes from platform keystore buffer's
|
||
|
+ * distrusted list, if it is present, return a bad signature.
|
||
|
+ * else, no errors.
|
||
|
+ */
|
||
|
+static grub_err_t
|
||
|
+grub_is_distrusted_cert_hash (const grub_uint8_t *data, const grub_size_t data_size)
|
||
|
+{
|
||
|
+ grub_err_t rc = GRUB_ERR_NONE;
|
||
|
+ grub_size_t i = 0, cert_hash_size = 0;
|
||
|
+ grub_uint8_t cert_hash[GRUB_MAX_HASH_SIZE] = { 0 };
|
||
|
+
|
||
|
+ if (data == NULL || data_size == 0)
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted certificate data/size is null");
|
||
|
+
|
||
|
+ for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
|
||
|
+ {
|
||
|
+ if (grub_platform_keystore.dbx[i].data == NULL &&
|
||
|
+ grub_platform_keystore.dbx[i].data_size == 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ rc = grub_get_hash (&grub_platform_keystore.dbx[i].guid, data, data_size,
|
||
|
+ cert_hash, &cert_hash_size);
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (cert_hash_size == grub_platform_keystore.dbx[i].data_size &&
|
||
|
+ grub_memcmp (grub_platform_keystore.dbx[i].data, cert_hash, cert_hash_size) == 0)
|
||
|
+ {
|
||
|
+ grub_printf ("Warning: a trusted certificate (%02x%02x%02x%02x) is ignored "
|
||
|
+ "because this certificate hash is on the distrusted list (dbx).\n",
|
||
|
+ cert_hash[0], cert_hash[1], cert_hash[2], cert_hash[3]);
|
||
|
+ grub_free (grub_platform_keystore.dbx[i].data);
|
||
|
+ grub_memset (&grub_platform_keystore.dbx[i], 0x00,
|
||
|
+ sizeof (grub_platform_keystore.dbx[i]));
|
||
|
+ return GRUB_ERR_BAD_SIGNATURE;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * verify the trusted binary hash against the platform keystore buffer's
|
||
|
+ * distrusted list, if it is present, return a bad signature.
|
||
|
+ * else, no errors.
|
||
|
+ */
|
||
|
+static grub_err_t
|
||
|
+grub_is_distrusted_binary_hash (const grub_uint8_t *binary_hash,
|
||
|
+ const grub_size_t binary_hash_size)
|
||
|
+{
|
||
|
+ grub_size_t i = 0;
|
||
|
+
|
||
|
+ for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
|
||
|
+ {
|
||
|
+ if (grub_platform_keystore.dbx[i].data == NULL &&
|
||
|
+ grub_platform_keystore.dbx[i].data_size == 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (binary_hash_size == grub_platform_keystore.dbx[i].data_size &&
|
||
|
+ grub_memcmp (grub_platform_keystore.dbx[i].data, binary_hash, binary_hash_size) == 0)
|
||
|
+ {
|
||
|
+ grub_printf ("Warning: a trusted binary hash (%02x%02x%02x%02x) is ignored"
|
||
|
+ " because it is on the distrusted list (dbx).\n",
|
||
|
+ binary_hash[0], binary_hash[1], binary_hash[2], binary_hash[3]);
|
||
|
+ grub_free (grub_platform_keystore.dbx[i].data);
|
||
|
+ grub_memset (&grub_platform_keystore.dbx[i], 0x00,
|
||
|
+ sizeof (grub_platform_keystore.dbx[i]));
|
||
|
+ return GRUB_ERR_BAD_SIGNATURE;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * extracts the binary hashes from the platform keystore buffer,
|
||
|
+ * and adds it to the trusted list if not exists in distrusted list.
|
||
|
+ */
|
||
|
+static grub_err_t
|
||
|
+grub_add_trusted_binary_hash (const grub_uint8_t **data, const grub_size_t data_size)
|
||
|
+{
|
||
|
+ grub_err_t rc = GRUB_ERR_NONE;
|
||
|
+
|
||
|
+ if (*data == NULL || data_size == 0)
|
||
|
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted binary hash data/size is null");
|
||
|
+
|
||
|
+ rc = grub_is_distrusted_binary_hash (*data, data_size);
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ return rc;
|
||
|
+
|
||
|
+ rc = grub_add_hash (data, data_size, &grub_db.signatures, &grub_db.signature_size,
|
||
|
+ &grub_db.signature_entries);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+static grub_err_t
|
||
|
+grub_is_hash (const grub_uuid_t *guid)
|
||
|
+{
|
||
|
+ /* GUID type of the binary hash */
|
||
|
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
|
||
|
+ grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
|
||
|
+ grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE) == 0)
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+
|
||
|
+ /* GUID type of the certificate hash */
|
||
|
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
|
||
|
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
|
||
|
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_UUID_SIZE) == 0)
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+
|
||
|
+ return GRUB_ERR_UNKNOWN_COMMAND;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * extracts the x509 certificates/binary hashes from the platform keystore buffer,
|
||
|
+ * parses it, and adds it to the trusted list.
|
||
|
+ */
|
||
|
+static grub_err_t
|
||
|
+grub_create_trusted_list (void)
|
||
|
+{
|
||
|
+ grub_err_t rc = GRUB_ERR_NONE;
|
||
|
+ grub_size_t i = 0;
|
||
|
+
|
||
|
+ for (i = 0; i < grub_platform_keystore.db_entries; i++)
|
||
|
+ {
|
||
|
+ if (grub_is_hash (&grub_platform_keystore.db[i].guid) == GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ rc = grub_add_trusted_binary_hash ((const grub_uint8_t **)
|
||
|
+ &grub_platform_keystore.db[i].data,
|
||
|
+ grub_platform_keystore.db[i].data_size);
|
||
|
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
|
||
|
+ return rc;
|
||
|
+
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ else if (grub_is_x509 (&grub_platform_keystore.db[i].guid) == GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+
|
||
|
+ rc = grub_is_distrusted_cert_hash (grub_platform_keystore.db[i].data,
|
||
|
+ grub_platform_keystore.db[i].data_size);
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ rc = grub_add_certificate (grub_platform_keystore.db[i].data,
|
||
|
+ grub_platform_keystore.db[i].data_size, &grub_db, 1);
|
||
|
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
|
||
|
+ return rc;
|
||
|
+ else if (rc != GRUB_ERR_NONE)
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ grub_printf ("Warning: unsupported signature data type and "
|
||
|
+ "skipping trusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
|
||
|
+ }
|
||
|
+
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * extracts the certificates, certificate/binary hashes out of the platform keystore buffer,
|
||
|
+ * and adds it to the distrusted list.
|
||
|
+ */
|
||
|
+static grub_err_t
|
||
|
+grub_create_distrusted_list (void)
|
||
|
+{
|
||
|
+ grub_err_t rc = GRUB_ERR_NONE;
|
||
|
+ grub_size_t i = 0;
|
||
|
+
|
||
|
+ for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
|
||
|
+ {
|
||
|
+ if (grub_platform_keystore.dbx[i].data != NULL &&
|
||
|
+ grub_platform_keystore.dbx[i].data_size > 0)
|
||
|
+ {
|
||
|
+ if (grub_is_x509 (&grub_platform_keystore.dbx[i].guid))
|
||
|
+ {
|
||
|
+ rc = grub_add_certificate (grub_platform_keystore.dbx[i].data,
|
||
|
+ grub_platform_keystore.dbx[i].data_size, &grub_dbx, 0);
|
||
|
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
|
||
|
+ return rc;
|
||
|
+ }
|
||
|
+ else if (grub_is_hash (&grub_platform_keystore.dbx[i].guid) == GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ rc = grub_add_hash ((const grub_uint8_t **) &grub_platform_keystore.dbx[i].data,
|
||
|
+ grub_platform_keystore.dbx[i].data_size,
|
||
|
+ &grub_dbx.signatures, &grub_dbx.signature_size,
|
||
|
+ &grub_dbx.signature_entries);
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ return rc;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ grub_printf ("Warning: unsupported signature data type and "
|
||
|
+ "skipping distrusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * extracts the x509 certificates from the ELF note header,
|
||
|
+ * parses it, and adds it to the trusted list.
|
||
|
+ */
|
||
|
+static grub_err_t
|
||
|
+grub_build_static_trusted_list (const struct grub_module_header *header, bool mode)
|
||
|
+{
|
||
|
+ grub_err_t err = GRUB_ERR_NONE;
|
||
|
+ struct grub_file pseudo_file;
|
||
|
+ grub_uint8_t *cert_data = NULL;
|
||
|
+ grub_ssize_t cert_data_size = 0;
|
||
|
+
|
||
|
+ grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
|
||
|
+ pseudo_file.fs = &pseudo_fs;
|
||
|
+ pseudo_file.size = header->size - sizeof (struct grub_module_header);
|
||
|
+ pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
|
||
|
+
|
||
|
+ grub_dprintf ("appendedsig", "found an x509 key, size=%" PRIuGRUB_UINT64_T "\n",
|
||
|
+ pseudo_file.size);
|
||
|
+
|
||
|
+ err = grub_read_file (&pseudo_file, &cert_data, &cert_data_size);
|
||
|
+ if (err != GRUB_ERR_NONE)
|
||
|
+ return err;
|
||
|
+
|
||
|
+ if (mode)
|
||
|
+ {
|
||
|
+ err = grub_is_distrusted_cert_hash (cert_data, cert_data_size);
|
||
|
+ if (err != GRUB_ERR_NONE)
|
||
|
+ return err;
|
||
|
+ }
|
||
|
+
|
||
|
+ err = grub_add_certificate (cert_data, cert_data_size, &grub_db, mode);
|
||
|
+ if (cert_data != NULL)
|
||
|
+ grub_free (cert_data);
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+
|
||
|
+/* releasing memory */
|
||
|
+static void
|
||
|
+grub_release_trusted_list (void)
|
||
|
+{
|
||
|
+ struct x509_certificate *cert;
|
||
|
+ grub_size_t i = 0;
|
||
|
+
|
||
|
+ while (grub_db.keys != NULL)
|
||
|
+ {
|
||
|
+ cert = grub_db.keys;
|
||
|
+ grub_db.keys = grub_db.keys->next;
|
||
|
+ certificate_release (cert);
|
||
|
+ grub_free (cert);
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < grub_db.signature_entries; i++)
|
||
|
+ grub_free (grub_db.signatures[i]);
|
||
|
+
|
||
|
+ grub_free (grub_db.signatures);
|
||
|
+ grub_free (grub_db.signature_size);
|
||
|
+ grub_memset (&grub_db, 0x00, sizeof (grub_db));
|
||
|
+}
|
||
|
+
|
||
|
+/* releasing memory */
|
||
|
+static void
|
||
|
+grub_release_distrusted_list (void)
|
||
|
+{
|
||
|
+ struct x509_certificate *cert;
|
||
|
+ grub_size_t i = 0;
|
||
|
+
|
||
|
+ while (grub_dbx.keys != NULL)
|
||
|
+ {
|
||
|
+ cert = grub_dbx.keys;
|
||
|
+ grub_dbx.keys = grub_dbx.keys->next;
|
||
|
+ certificate_release (cert);
|
||
|
+ grub_free (cert);
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < grub_dbx.signature_entries; i++)
|
||
|
+ grub_free (grub_dbx.signatures[i]);
|
||
|
+
|
||
|
+ grub_free (grub_dbx.signatures);
|
||
|
+ grub_free (grub_dbx.signature_size);
|
||
|
+ grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));
|
||
|
+}
|
||
|
+
|
||
|
+static grub_err_t
|
||
|
+grub_load_static_keys (struct grub_module_header *header, bool mode)
|
||
|
+{
|
||
|
+ int rc = GRUB_ERR_NONE;
|
||
|
+
|
||
|
+ FOR_MODULES (header)
|
||
|
+ {
|
||
|
+ /* Not an ELF module, skip. */
|
||
|
+ if (header->type != OBJ_TYPE_X509_PUBKEY)
|
||
|
+ continue;
|
||
|
+ rc = grub_build_static_trusted_list (header, mode);
|
||
|
+ }
|
||
|
+
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust;
|
||
|
|
||
|
GRUB_MOD_INIT (appendedsig)
|
||
|
@@ -588,10 +1148,7 @@ GRUB_MOD_INIT (appendedsig)
|
||
|
if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
|
||
|
check_sigs = check_sigs_forced;
|
||
|
|
||
|
- grub_trusted_key = NULL;
|
||
|
-
|
||
|
- grub_register_variable_hook ("check_appended_signatures",
|
||
|
- grub_env_read_sec, grub_env_write_sec);
|
||
|
+ grub_register_variable_hook ("check_appended_signatures", grub_env_read_sec, grub_env_write_sec);
|
||
|
grub_env_export ("check_appended_signatures");
|
||
|
|
||
|
rc = asn1_init ();
|
||
|
@@ -599,40 +1156,52 @@ GRUB_MOD_INIT (appendedsig)
|
||
|
grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc,
|
||
|
asn1_strerror (rc));
|
||
|
|
||
|
- FOR_MODULES (header)
|
||
|
- {
|
||
|
- struct grub_file pseudo_file;
|
||
|
- struct x509_certificate *pk = NULL;
|
||
|
- grub_err_t err;
|
||
|
-
|
||
|
- /* Not an ELF module, skip. */
|
||
|
- if (header->type != OBJ_TYPE_X509_PUBKEY)
|
||
|
- continue;
|
||
|
-
|
||
|
- grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
|
||
|
- pseudo_file.fs = &pseudo_fs;
|
||
|
- pseudo_file.size = header->size - sizeof (struct grub_module_header);
|
||
|
- pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
|
||
|
-
|
||
|
- grub_dprintf ("appendedsig",
|
||
|
- "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n",
|
||
|
- pseudo_file.size);
|
||
|
-
|
||
|
- pk = grub_zalloc (sizeof (struct x509_certificate));
|
||
|
- if (!pk)
|
||
|
- {
|
||
|
- grub_fatal ("Out of memory loading initial certificates");
|
||
|
- }
|
||
|
-
|
||
|
- err = read_cert_from_file (&pseudo_file, pk);
|
||
|
- if (err != GRUB_ERR_NONE)
|
||
|
- grub_fatal ("Error loading initial key: %s", grub_errmsg);
|
||
|
-
|
||
|
- grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject);
|
||
|
-
|
||
|
- pk->next = grub_trusted_key;
|
||
|
- grub_trusted_key = pk;
|
||
|
- }
|
||
|
+ if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
|
||
|
+ {
|
||
|
+ rc = grub_load_static_keys (header, 0);
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ grub_release_trusted_list ();
|
||
|
+ grub_error (rc, "static trusted list creation failed");
|
||
|
+ }
|
||
|
+ else
|
||
|
+ grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
|
||
|
+ grub_db.key_entries);
|
||
|
+ }
|
||
|
+ else if (grub_use_platform_keystore && check_sigs == check_sigs_forced)
|
||
|
+ {
|
||
|
+ if (grub_platform_keystore.use_static_keys == 1)
|
||
|
+ {
|
||
|
+ grub_printf ("Warning: db variable not available and using a static key"
|
||
|
+ "as a default key in trusted list");
|
||
|
+ rc = grub_load_static_keys (header, 1);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ rc = grub_create_trusted_list ();
|
||
|
+
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ grub_release_trusted_list ();
|
||
|
+ grub_error (rc, "trusted list creation failed");
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ rc = grub_create_distrusted_list ();
|
||
|
+ if (rc != GRUB_ERR_NONE)
|
||
|
+ {
|
||
|
+ grub_release_trusted_list ();
|
||
|
+ grub_release_distrusted_list ();
|
||
|
+ grub_error (rc, "distrusted list creation failed");
|
||
|
+ }
|
||
|
+ else
|
||
|
+ grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " keys.\n"
|
||
|
+ "appendedsig: the distrusted list now has %" PRIuGRUB_SIZE " keys.\n",
|
||
|
+ grub_db.signature_entries + grub_db.key_entries,
|
||
|
+ grub_dbx.signature_entries);
|
||
|
+ }
|
||
|
+
|
||
|
+ grub_release_platform_keystore ();
|
||
|
+ }
|
||
|
|
||
|
cmd_trust =
|
||
|
grub_register_command ("trust_certificate", grub_cmd_trust,
|
||
|
--
|
||
|
2.47.0
|
||
|
|