grub-devel
[Top][All Lists]
Advanced

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

[PATCH REBASED] verify: search keyid in hashed signature subpackets


From: Daniel Axtens
Subject: [PATCH REBASED] verify: search keyid in hashed signature subpackets
Date: Fri, 29 May 2020 13:05:58 +1000

Currently GRUB2 verify logic searches PGP keyid only in unhashed subpackets of
PGP signature packet. As a result, signatures generated with GoLang openpgp
package (https://godoc.org/golang.org/x/crypto/openpgp) could not be verified,
because this package puts keyid in hashed subpackets and GRUB code never
initializes the keyid variable, therefore is not able to find "verification
key" with id 0x0.

(Add further description per thread at 
https://lists.gnu.org/archive/html/grub-devel/2016-11/msg00073.html)

Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
[ modified by Charles Duffy <charles@dyfis.net>, needs his Signed-off-by before 
merging ]
[ modified by dja: rebase, split out 'readbuf' to both readbuf and 
subpacket_buf for clarity
  signature_test still passes but I have not run any other tests ]
[ Under DCO rules I cannot provied a signed-off-by until Charles certifies his 
work can be redistributed ]
---
 grub-core/commands/pgp.c | 117 ++++++++++++++++++++++++++-------------
 1 file changed, 77 insertions(+), 40 deletions(-)

diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
index bbf6871fe71f..ad91f462bb91 100644
--- a/grub-core/commands/pgp.c
+++ b/grub-core/commands/pgp.c
@@ -448,6 +448,38 @@ struct grub_pubkey_context
   void *hash_context;
 };
 
+static grub_uint64_t
+grub_subpacket_keyid_search (const grub_uint8_t * sub, grub_ssize_t sub_len)
+{
+  const grub_uint8_t *ptr;
+  grub_uint32_t l;
+  grub_uint64_t keyid = 0;
+
+  for (ptr = sub; ptr < sub + sub_len; ptr += l)
+    {
+      if (*ptr < 192)
+       l = *ptr++;
+      else if (*ptr < 255)
+       {
+         if (ptr + 1 >= sub + sub_len)
+           break;
+         l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192;
+         ptr += 2;
+       }
+      else
+       {
+         if (ptr + 5 >= sub + sub_len)
+           break;
+         l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1));
+         ptr += 5;
+       }
+      if (*ptr == 0x10 && l >= 8)
+       keyid = grub_get_unaligned64 (ptr + 1);
+    }
+
+  return keyid;
+}
+
 static grub_err_t
 grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
 {
@@ -520,7 +552,7 @@ grub_verify_signature_real (struct grub_pubkey_context 
*ctxt,
   gcry_mpi_t mpis[10];
   grub_uint8_t pk = ctxt->v4.pkeyalgo;
   grub_size_t i;
-  grub_uint8_t *readbuf = NULL;
+  grub_uint8_t *readbuf = NULL, *subpacket_buf = NULL;
   unsigned char *hval;
   grub_ssize_t rem = grub_be_to_cpu16 (ctxt->v4.hashed_sub);
   grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6);
@@ -538,17 +570,29 @@ grub_verify_signature_real (struct grub_pubkey_context 
*ctxt,
 
   ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
   ctxt->hash->write (ctxt->hash_context, &ctxt->v4, sizeof (ctxt->v4));
-  while (rem)
+
+  subpacket_buf = grub_malloc (rem);
+  if (!subpacket_buf)
+    goto fail;
+
+  r = 0;
+  while (r < rem)
     {
-      r = grub_file_read (ctxt->sig, readbuf,
-                         rem < READBUF_SIZE ? rem : READBUF_SIZE);
-      if (r < 0)
-       goto fail;
-      if (r == 0)
+      grub_ssize_t rr = grub_file_read (ctxt->sig, subpacket_buf + r, rem - r);
+      if (rr < 0)
+        goto fail;
+      if (rr == 0)
        break;
-      ctxt->hash->write (ctxt->hash_context, readbuf, r);
-      rem -= r;
+      r += rr;
     }
+  if (r != rem)
+    goto fail;
+  ctxt->hash->write (ctxt->hash_context, subpacket_buf, rem);
+
+  keyid = grub_subpacket_keyid_search (subpacket_buf, rem);
+  grub_free (subpacket_buf);
+  subpacket_buf = NULL;
+
   ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
   s = 0xff;
   ctxt->hash->write (ctxt->hash_context, &s, sizeof (s));
@@ -556,37 +600,27 @@ grub_verify_signature_real (struct grub_pubkey_context 
*ctxt,
   r = grub_file_read (ctxt->sig, &unhashed_sub, sizeof (unhashed_sub));
   if (r != sizeof (unhashed_sub))
     goto fail;
-  {
-    grub_uint8_t *ptr;
-    grub_uint32_t l;
-    rem = grub_be_to_cpu16 (unhashed_sub);
-    if (rem > READBUF_SIZE)
-      goto fail;
-    r = grub_file_read (ctxt->sig, readbuf, rem);
-    if (r != rem)
-      goto fail;
-    for (ptr = readbuf; ptr < readbuf + rem; ptr += l)
-      {
-       if (*ptr < 192)
-         l = *ptr++;
-       else if (*ptr < 255)
-         {
-           if (ptr + 1 >= readbuf + rem)
-             break;
-           l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192;
-           ptr += 2;
-         }
-       else
-         {
-           if (ptr + 5 >= readbuf + rem)
-             break;
-           l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1));
-           ptr += 5;
-         }
-       if (*ptr == 0x10 && l >= 8)
-         keyid = grub_get_unaligned64 (ptr + 1);
-      }
-  }
+
+  rem = grub_be_to_cpu16 (unhashed_sub);
+  subpacket_buf = grub_malloc (rem);
+  if (!subpacket_buf)
+    goto fail;
+
+  r = 0;
+  while (r < rem)
+    {
+     grub_ssize_t rr = grub_file_read (ctxt->sig, subpacket_buf + r, rem - r);
+     if (rr < 0)
+       goto fail;
+     if (rr == 0)
+       break;
+     r += rr;
+    }
+  if (r != rem)
+    goto fail;
+
+  if (keyid == 0)
+    keyid = grub_subpacket_keyid_search (subpacket_buf, rem);
 
   ctxt->hash->final (ctxt->hash_context);
 
@@ -656,10 +690,13 @@ grub_verify_signature_real (struct grub_pubkey_context 
*ctxt,
     goto fail;
 
   grub_free (readbuf);
+  grub_free (subpacket_buf);
 
   return GRUB_ERR_NONE;
 
  fail:
+  if (subpacket_buf)
+    grub_free (subpacket_buf);
   grub_free (readbuf);
   if (!grub_errno)
     return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-- 
2.20.1




reply via email to

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