grub-devel
[Top][All Lists]
Advanced

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

Re: [PATCH v1 17/21] appendedsig: While verifying the kernel, use truste


From: Stefan Berger
Subject: Re: [PATCH v1 17/21] appendedsig: While verifying the kernel, use trusted and distrusted lists
Date: Tue, 31 Dec 2024 12:37:59 -0500
User-agent: Mozilla Thunderbird



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
To verify the kernel's: verify the kernel binary against list of binary hashes

To verify the kernel's signature?

against lists of binary hashes

that are distrusted and trusted. If it is not listed in both trusted and 
distrusted,

that are either distrusted or trusted.

If it is not list in either trusted or distrusted hashes list then the trusted keys from the trusted key list are used to verify the signature.

the trusted keys from trusted key list used to verify the signature.

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

diff --git a/grub-core/commands/appendedsig/appendedsig.c 
b/grub-core/commands/appendedsig/appendedsig.c
index 31649e800..8b084087e 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -497,6 +497,81 @@ extract_appended_signature (const grub_uint8_t *buf, 
grub_size_t bufsize,
    return parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
  }
+static grub_err_t
+grub_get_binary_hash (const grub_size_t binary_hash_size, const grub_uint8_t 
*data,
+                      const grub_size_t data_size, grub_uint8_t *hash, 
grub_size_t *hash_size)
+{
+  grub_uuid_t guid = { 0 };
+
+  /* support SHA256, SHA384 and SHA512 for binary hash */
+  if (binary_hash_size == 32)
+    grub_memcpy (&guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE);
+  else if (binary_hash_size == 48)
+    grub_memcpy (&guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE);
+  else if (binary_hash_size == 64)
+    grub_memcpy (&guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE);
+  else
+    {
+      grub_dprintf ("appendedsig", "unsupported hash type (%" PRIuGRUB_SIZE ") and 
skipping binary hash\n",
+                    binary_hash_size);
+      return GRUB_ERR_UNKNOWN_COMMAND;
+    }
+
+  return grub_get_hash (&guid, data, data_size, hash, hash_size);
+}
+
+/*
+ * verify binary hash against the list of binary hashes that are distrusted
Verify a binary hash
+ * and trusted.

The following errors can occur:
- GRUB_ERR_BAD_SIGNATURE: indicates that the hash is distrusted.
- GRUB_ERR_NONE: the hash is trusted, since it was found in the trusted hashes list
- GRUB_ERR_EOF: the hash could not be found in the hashes list

+ */
+static grub_err_t
+grub_verify_binary_hash (const grub_uint8_t *data, const grub_size_t data_size)
+{
+  grub_err_t rc = GRUB_ERR_NONE;
+  grub_size_t i = 0, hash_size = 0;
+  grub_uint8_t hash[GRUB_MAX_HASH_SIZE] = { 0 };
+
+  for (i = 0; i < grub_dbx.signature_entries; i++)
+    {
+      rc = grub_get_binary_hash (grub_dbx.signature_size[i], data, data_size,
+                                 hash, &hash_size);
+      if (rc != GRUB_ERR_NONE)
+        continue;
+
+      if (hash_size == grub_dbx.signature_size[i] &&
+          grub_memcmp (grub_dbx.signatures[i], hash, hash_size) == 0)
+        {
+          grub_dprintf ("appendedsig", "the binary hash (%02x%02x%02x%02x) was 
listed "
+                        "as distrusted\n", hash[0], hash[1], hash[2], hash[3]);

merge the error string into one

+          return GRUB_ERR_BAD_SIGNATURE;
+        }
+    }
+
+  for (i = 0; i < grub_db.signature_entries; i++)
+    {
+      rc = grub_get_binary_hash (grub_db.signature_size[i], data, data_size,
+                                 hash, &hash_size);
+      if (rc != GRUB_ERR_NONE)
+        continue;
+
+      if (hash_size == grub_db.signature_size[i] &&
+          grub_memcmp (grub_db.signatures[i], hash, hash_size) == 0)
+        {
+          grub_dprintf ("appendedsig", "verified with a trusted binary hash "
+                        "(%02x%02x%02x%02x)\n", hash[0], hash[1], hash[2], 
hash[3]);
+          return GRUB_ERR_NONE;
+        }
+    }
+
+  return GRUB_ERR_EOF;
+}
+
+
+/*
+ * verify the kernel's integrity, the trusted key will be used from
+ * the trusted key list. If it fails, verify it against the list of binary 
hashes
+ * that are distrusted and trusted.
+ */
  static grub_err_t
  grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
  {
@@ -506,12 +581,12 @@ grub_verify_appended_signature (const grub_uint8_t *buf, 
grub_size_t bufsize)
    unsigned char *hash;
    gcry_mpi_t hashmpi;
    gcry_err_code_t rc;
-  struct x509_certificate *pk;
+  struct x509_certificate *cert;
    struct grub_appended_signature sig;
    struct pkcs7_signerInfo *si;
    int i;
- if (!grub_db.key_entries)
+  if (!grub_db.key_entries && !grub_db.signature_entries)
      return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify 
against"));
err = extract_appended_signature (buf, bufsize, &sig);
@@ -520,68 +595,71 @@ grub_verify_appended_signature (const grub_uint8_t *buf, 
grub_size_t bufsize)
datasize = bufsize - sig.signature_len; - for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
+  err = grub_verify_binary_hash (buf, datasize);
+  if (err == GRUB_ERR_EOF)
      {
-      /*
-       * This could be optimised in a couple of ways:
-       * - we could only compute hashes once per hash type
-       * - we could track signer information and only verify where IDs match
-       * For now we do the naive O(trusted keys * pkcs7 signers) approach.
-       */
-      si = &sig.pkcs7.signerInfos[i];
-      context = grub_zalloc (si->hash->contextsize);
-      if (!context)
-        return grub_errno;
-
-      si->hash->init (context);
-      si->hash->write (context, buf, datasize);
-      si->hash->final (context);
-      hash = si->hash->read (context);
-
-      grub_dprintf ("appendedsig", "data size %" PRIxGRUB_SIZE ", signer %d hash 
%02x%02x%02x%02x...\n",
-                    datasize, i, hash[0], hash[1], hash[2], hash[3]);
-
-      err = GRUB_ERR_BAD_SIGNATURE;
-      for (pk = grub_db.keys; pk; pk = pk->next)

/* Hash was not found in trusted and distrusted list: check signature now */

+      for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
          {
-          rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
-          if (rc)
+          /*
+           * This could be optimised in a couple of ways:
+           * - we could only compute hashes once per hash type
+           * - we could track signer information and only verify where IDs 
match
+           * For now we do the naive O(grub_db.keys * pkcs7 signers) approach.
+           */
+          si = &sig.pkcs7.signerInfos[i];
+          context = grub_zalloc (si->hash->contextsize);
+          if (context == NULL)
+            return grub_errno;
+
+          si->hash->init (context);
+          si->hash->write (context, buf, datasize);
+          si->hash->final (context);
+          hash = si->hash->read (context);
+
+          grub_dprintf ("appendedsig",
+                        "data size %" PRIxGRUB_SIZE ", signer %d hash 
%02x%02x%02x%02x...\n",
+                        datasize, i, hash[0], hash[1], hash[2], hash[3]);
+
+          err = GRUB_ERR_BAD_SIGNATURE;
+          for (cert = grub_db.keys; cert; cert = cert->next)
              {
-              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
-                                N_("Error padding hash for RSA verification: 
%d"), rc);
-              grub_free (context);
-              goto cleanup;
+              rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, 
cert->mpis[0]);
+              if (rc != 0)
+                {
+                  err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                                    N_("Error padding hash for RSA verification: 
%d"), rc);
+                  grub_free (context);
+                  pkcs7_signedData_release (&sig.pkcs7);
+                  return err;
+                }
+
+              rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, 
cert->mpis, NULL, NULL);
+              gcry_mpi_release (hashmpi);
+              if (rc == 0)
+                {
+                  grub_dprintf ("appendedsig", "verify signer %d with key '%s' 
succeeded\n",
+                                i, cert->subject);
+                  err = GRUB_ERR_NONE;
+                  break;
+                }
+
+              grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed 
with %d\n",
+                            i, cert->subject, rc);
              }
- rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL);
-          gcry_mpi_release (hashmpi);
-
-          if (rc == 0)
-            {
-              grub_dprintf ("appendedsig", "verify signer %d with key '%s' 
succeeded\n",
-                            i, pk->subject);
-              err = GRUB_ERR_NONE;
-              break;
-            }
-
-          grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with 
%d\n",
-                        i, pk->subject, rc);
-        }
-
-      grub_free (context);
-
-      if (err == GRUB_ERR_NONE)
-        break;
+          grub_free (context);
+          if (err == GRUB_ERR_NONE)
+            break;
+      }
      }
- /* If we didn't verify, provide a neat message */
-  if (err != GRUB_ERR_NONE)
-    err = grub_error (GRUB_ERR_BAD_SIGNATURE,
-                      N_("Failed to verify signature against a trusted key"));
-
-cleanup:
    pkcs7_signedData_release (&sig.pkcs7);
+ if (err != GRUB_ERR_NONE)
+    err = grub_error (err, N_("failed to verify signature with any trusted 
key\n"));

You may need a special case to jump to from after the hash list test to indicate that the hash was found in the distrusted hashes list.

+  else
+    grub_printf ("appendedsig: successfully verified the signature with a trusted 
key\n");
+
    return err;
  }




reply via email to

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