grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted


From: Stefan Berger
Subject: Re: [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists
Date: Tue, 31 Dec 2024 12:21:34 -0500
User-agent: Mozilla Thunderbird



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
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

integrity

would be stored in the buffer db and dbx.

needs to be stored?


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,

integrity

the extracted data would be stored in the buffer db.

needs to be stored?


Note:-

if the trusted certificate nor binary hash exists in the distrusted list (DBX),

If neither the ... nor ...

rejected it while extracting it from the platform keystore buffer.

what is 'it' in this context


Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
  grub-core/commands/appendedsig/appendedsig.c | 636 +++++++++++++++++--
  1 file changed, 592 insertions(+), 44 deletions(-)

diff --git a/grub-core/commands/appendedsig/appendedsig.c 
b/grub-core/commands/appendedsig/appendedsig.c
index 5c82b96a4..31649e800 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -34,7 +34,7 @@
  #include <libtasn1.h>
  #include <grub/env.h>
  #include <grub/lockdown.h>
-
+#include <grub/platform_keystore.h>
  #include "appendedsig.h"
GRUB_MOD_LICENSE ("GPLv3+");
@@ -64,9 +64,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.
   *
@@ -87,6 +101,13 @@ struct x509_certificate *grub_trusted_key;
   * also resolves our concerns about loading from the filesystem.
   */
  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 */

Typically these functions start with 'free'. Free trusted list memory.

+static void grub_release_trusted_list (void);
+/* releasing distrusted list memory */
+static void grub_release_distrusted_list (void);

I am not sure whether local functions and variables should be prefixed with grub_ since typically those prefixed wit grub_ are global functions. This comment applies to all functions in this patch and series.

static enum
  {
@@ -95,6 +116,248 @@ static enum
    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, "GUID 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;

return grub_error (GRUB_ERR_OUT_OF_RANGE, "Unsupported GUID for hash")

+
+  grub_memset (hash, 0x00, GRUB_MAX_HASH_SIZE);
+  grub_crypto_hash (hash_func, hash, data, data_size);
+  *hash_size =  hash_func->mdlen;

grub_memset(hash, 0, *hash_size);

+
+  return GRUB_ERR_NONE;
+}
+
+/* adding the certificate/binary hash into the trusted/distrusted list */

Add the ...

+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));
+    }

Also in this case grub_realloc can be used for first parameter being NULL but may need a 2nd variable to handle allocation failures.

+
+  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)

Return int like many other *_is_xyz functions do ?

+{
+  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)

Return int ?

+{
+
+  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

Verify -- capitalize everywhere.

+ * distrusted list, if it is present, return a bad signature.

You won't construct a bad signture but you return GRUB_ERR_BAD_SIGNATURE.

+ * else, no errors.

Otherwise no error is returned. -- or omit entirely. Also in other cases.

It looks like it can return GRUB_ERR_OUT_OF_MEMORY as well.


+ */
+static grub_err_t
+grub_is_distrusted_cert (const struct x509_certificate *db_cert)

So this one here can have allocation failures and should return grub_err_t but calls the other two without propagating their errors.

+{
+  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 &&


should be a '||' or simply remove data_size == 0 check?

+          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_pks_sd_t));

s/0x00/0

+              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 */

Add the ..

+static grub_err_t
+grub_add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
+                      struct grub_database *database, const grub_size_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);

distrusted

+
+  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)

This function sounds so generic that it could be used in other places as well. It would we goood to move it to the same file as grub_file_read.

+{
+  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."));

could not determine the 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)))
@@ -248,7 +511,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, 
grub_size_t bufsize)
    struct pkcs7_signerInfo *si;
    int i;
- if (!grub_trusted_key)
+  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);
@@ -279,7 +542,7 @@ 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)
+      for (pk = grub_db.keys; pk; pk = pk->next)
          {
            rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
            if (rc)
@@ -376,16 +639,16 @@ grub_cmd_distrust (grub_command_t cmd __attribute__ 
((unused)), int argc, char *
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)
@@ -432,8 +695,8 @@ grub_cmd_trust (grub_command_t cmd __attribute__ 
((unused)), int argc, char **ar
      }
    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;
  }
@@ -446,7 +709,7 @@ grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), 
int argc __attribute
    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);
@@ -539,6 +802,280 @@ static struct grub_fs pseudo_fs = { .name = "pseudo", .fs_read = pseudo_read }; static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; +/*
+ * verify the trusted certificate against the certificate hashes from platform 
keystore buffer's

Verify

+ * distrusted list, if it is present, return a bad signature.

Same comments as above.

+ * 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_pks_sd_t));

s/0x00/0

sizeof(grub_platform_keystore.dbx[i]) -- so we don't need to know the type of this array

+          return GRUB_ERR_BAD_SIGNATURE;
+        }
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * verify the trusted binary hash against the platform keystore buffer's

Verify.

+ * distrusted list, if it is present, return a bad signature.

Same comments as above.

+ * 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_pks_sd_t));

same comments as above

+          return GRUB_ERR_BAD_SIGNATURE;
+        }
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * extracts the binary hashes from the platform keystore buffer,

Extract the ...

+ * and adds it to the trusted list if not exists in distrusted list.

and add it .. if it does not exist in the 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)

Here you have the '||'...

+    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)

Same comments as with other functions as above.

+{
+  /* 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,

Extract the x509...

+ * parses it, and adds it to the trusted list.

parse it, and add 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;

'continue' not needed

+        }
+      else if (grub_is_x509 (&grub_platform_keystore.db[i].guid) == 
GRUB_ERR_NONE)
+        {
+

stray empty line

+          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) == 
GRUB_ERR_NONE)
+            {
+              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)
+{
+  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));

ah, '0'

+  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;
+
+  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
+  if (cert_data != NULL)
+    grub_free (cert_data);

no need to check for cert_data != NULL
+
+  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));

s/0x00/0

+}
+
+/* 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));

s/0x00.0

+}
+
  GRUB_MOD_INIT (appendedsig)
  {
    int rc;
@@ -548,7 +1085,6 @@ 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_env_export ("check_appended_signatures");
@@ -556,39 +1092,51 @@ GRUB_MOD_INIT (appendedsig)
    if (rc)
      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 X.509 certificate, 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);
+  if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
+    {
+      FOR_MODULES (header)
+        {
+          /* Not an ELF module, skip.  */
+          if (header->type != OBJ_TYPE_X509_PUBKEY)
+            continue;
- grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject);
+          rc = grub_build_static_trusted_list (header);
+          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)
+    {
+      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);
+        }
- pk->next = grub_trusted_key;
-    grub_trusted_key = pk;
-  }
+      grub_release_platform_keystore ();
+    }
cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"),
                                       N_("Add X509_CERTIFICATE to trusted 
certificates."));




reply via email to

[Prev in Thread] Current Thread [Next in Thread]