[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v3 5/8] verifiers: Rename verify module to pgp module
From: |
Daniel Kiper |
Subject: |
[PATCH v3 5/8] verifiers: Rename verify module to pgp module |
Date: |
Wed, 3 Oct 2018 11:36:52 +0200 |
Just for clarity. No functional change.
Signed-off-by: Daniel Kiper <address@hidden>
---
grub-core/Makefile.core.def | 4 +-
grub-core/commands/pgp.c | 1018 +++++++++++++++++++++++++++++++++++++++++++
grub-core/commands/verify.c | 1018 -------------------------------------------
3 files changed, 1020 insertions(+), 1020 deletions(-)
create mode 100644 grub-core/commands/pgp.c
delete mode 100644 grub-core/commands/verify.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index dfcc95d..3008b58 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -888,8 +888,8 @@ module = {
};
module = {
- name = verify;
- common = commands/verify.c;
+ name = pgp;
+ common = commands/pgp.c;
cflags = '$(CFLAGS_POSIX)';
cppflags = '-I$(srcdir)/lib/posix_wrap';
};
diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
new file mode 100644
index 0000000..d5d7c0f
--- /dev/null
+++ b/grub-core/commands/pgp.c
@@ -0,0 +1,1018 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/command.h>
+#include <grub/crypto.h>
+#include <grub/i18n.h>
+#include <grub/gcrypt/gcrypt.h>
+#include <grub/pubkey.h>
+#include <grub/env.h>
+#include <grub/kernel.h>
+#include <grub/extcmd.h>
+#include <grub/verify.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+enum
+ {
+ OPTION_SKIP_SIG = 0
+ };
+
+static const struct grub_arg_option options[] =
+ {
+ {"skip-sig", 's', 0,
+ N_("Skip signature-checking of the public key file."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+read_packet_header (grub_file_t sig, grub_uint8_t *out_type, grub_size_t *len)
+{
+ grub_uint8_t type;
+ grub_uint8_t l;
+ grub_uint16_t l16;
+ grub_uint32_t l32;
+
+ /* New format. */
+ switch (grub_file_read (sig, &type, sizeof (type)))
+ {
+ case 1:
+ break;
+ case 0:
+ {
+ *out_type = 0xff;
+ return 0;
+ }
+ default:
+ if (grub_errno)
+ return grub_errno;
+ /* TRANSLATORS: it's about GNUPG signatures. */
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ }
+
+ if (type == 0)
+ {
+ *out_type = 0xfe;
+ return 0;
+ }
+
+ if (!(type & 0x80))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ if (type & 0x40)
+ {
+ *out_type = (type & 0x3f);
+ if (grub_file_read (sig, &l, sizeof (l)) != 1)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ if (l < 192)
+ {
+ *len = l;
+ return 0;
+ }
+ if (l < 224)
+ {
+ *len = (l - 192) << GRUB_CHAR_BIT;
+ if (grub_file_read (sig, &l, sizeof (l)) != 1)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len |= l;
+ return 0;
+ }
+ if (l == 255)
+ {
+ if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu32 (l32);
+ return 0;
+ }
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ }
+ *out_type = ((type >> 2) & 0xf);
+ switch (type & 0x3)
+ {
+ case 0:
+ if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = l;
+ return 0;
+ case 1:
+ if (grub_file_read (sig, &l16, sizeof (l16)) != sizeof (l16))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu16 (l16);
+ return 0;
+ case 2:
+ if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu32 (l32);
+ return 0;
+ }
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+}
+
+struct signature_v4_header
+{
+ grub_uint8_t type;
+ grub_uint8_t pkeyalgo;
+ grub_uint8_t hash;
+ grub_uint16_t hashed_sub;
+} GRUB_PACKED;
+
+const char *hashes[] = {
+ [0x01] = "md5",
+ [0x02] = "sha1",
+ [0x03] = "ripemd160",
+ [0x08] = "sha256",
+ [0x09] = "sha384",
+ [0x0a] = "sha512",
+ [0x0b] = "sha224"
+};
+
+struct gcry_pk_spec *grub_crypto_pk_dsa;
+struct gcry_pk_spec *grub_crypto_pk_ecdsa;
+struct gcry_pk_spec *grub_crypto_pk_rsa;
+
+static int
+dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+static int
+rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+
+struct
+{
+ const char *name;
+ grub_size_t nmpisig;
+ grub_size_t nmpipub;
+ struct gcry_pk_spec **algo;
+ int (*pad) (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+ const char *module;
+} pkalgos[] =
+ {
+ [1] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
+ [3] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
+ [17] = { "dsa", 2, 4, &grub_crypto_pk_dsa, dsa_pad, "gcry_dsa" },
+ };
+
+struct grub_public_key
+{
+ struct grub_public_key *next;
+ struct grub_public_subkey *subkeys;
+};
+
+struct grub_public_subkey
+{
+ struct grub_public_subkey *next;
+ grub_uint8_t type;
+ grub_uint32_t fingerprint[5];
+ gcry_mpi_t mpis[10];
+};
+
+static void
+free_pk (struct grub_public_key *pk)
+{
+ struct grub_public_subkey *nsk, *sk;
+ for (sk = pk->subkeys; sk; sk = nsk)
+ {
+ grub_size_t i;
+ for (i = 0; i < ARRAY_SIZE (sk->mpis); i++)
+ if (sk->mpis[i])
+ gcry_mpi_release (sk->mpis[i]);
+ nsk = sk->next;
+ grub_free (sk);
+ }
+ grub_free (pk);
+}
+
+#define READBUF_SIZE 4096
+
+struct grub_public_key *
+grub_load_public_key (grub_file_t f)
+{
+ grub_err_t err;
+ struct grub_public_key *ret;
+ struct grub_public_subkey **last = 0;
+ void *fingerprint_context = NULL;
+ grub_uint8_t *buffer = NULL;
+
+ ret = grub_zalloc (sizeof (*ret));
+ if (!ret)
+ {
+ grub_free (fingerprint_context);
+ return NULL;
+ }
+
+ buffer = grub_zalloc (READBUF_SIZE);
+ fingerprint_context = grub_zalloc (GRUB_MD_SHA1->contextsize);
+
+ if (!buffer || !fingerprint_context)
+ goto fail;
+
+ last = &ret->subkeys;
+
+ while (1)
+ {
+ grub_uint8_t type;
+ grub_size_t len;
+ grub_uint8_t v, pk;
+ grub_uint32_t creation_time;
+ grub_off_t pend;
+ struct grub_public_subkey *sk;
+ grub_size_t i;
+ grub_uint16_t len_be;
+
+ err = read_packet_header (f, &type, &len);
+
+ if (err)
+ goto fail;
+ if (type == 0xfe)
+ continue;
+ if (type == 0xff)
+ {
+ grub_free (fingerprint_context);
+ grub_free (buffer);
+ return ret;
+ }
+
+ grub_dprintf ("crypt", "len = %x\n", (int) len);
+
+ pend = grub_file_tell (f) + len;
+ if (type != 6 && type != 14
+ && type != 5 && type != 7)
+ {
+ grub_file_seek (f, pend);
+ continue;
+ }
+
+ if (grub_file_read (f, &v, sizeof (v)) != sizeof (v))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "v = %x\n", v);
+
+ if (v != 4)
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+ if (grub_file_read (f, &creation_time, sizeof (creation_time)) != sizeof
(creation_time))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "time = %x\n", creation_time);
+
+ if (grub_file_read (f, &pk, sizeof (pk)) != sizeof (pk))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "pk = %x\n", pk);
+
+ if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
+ {
+ grub_file_seek (f, pend);
+ continue;
+ }
+
+ sk = grub_zalloc (sizeof (struct grub_public_subkey));
+ if (!sk)
+ goto fail;
+
+ grub_memset (fingerprint_context, 0, GRUB_MD_SHA1->contextsize);
+ GRUB_MD_SHA1->init (fingerprint_context);
+ GRUB_MD_SHA1->write (fingerprint_context, "\x99", 1);
+ len_be = grub_cpu_to_be16 (len);
+ GRUB_MD_SHA1->write (fingerprint_context, &len_be, sizeof (len_be));
+ GRUB_MD_SHA1->write (fingerprint_context, &v, sizeof (v));
+ GRUB_MD_SHA1->write (fingerprint_context, &creation_time, sizeof
(creation_time));
+ GRUB_MD_SHA1->write (fingerprint_context, &pk, sizeof (pk));
+
+ for (i = 0; i < pkalgos[pk].nmpipub; i++)
+ {
+ grub_uint16_t l;
+ grub_size_t lb;
+ if (grub_file_read (f, &l, sizeof (l)) != sizeof (l))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+
+ lb = (grub_be_to_cpu16 (l) + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT;
+ if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ if (grub_file_read (f, buffer + sizeof (grub_uint16_t), lb) !=
(grub_ssize_t) lb)
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ grub_memcpy (buffer, &l, sizeof (l));
+
+ GRUB_MD_SHA1->write (fingerprint_context, buffer, lb + sizeof
(grub_uint16_t));
+
+ if (gcry_mpi_scan (&sk->mpis[i], GCRYMPI_FMT_PGP,
+ buffer, lb + sizeof (grub_uint16_t), 0))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ }
+
+ if (i < pkalgos[pk].nmpipub)
+ {
+ grub_free (sk);
+ goto fail;
+ }
+
+ GRUB_MD_SHA1->final (fingerprint_context);
+
+ grub_memcpy (sk->fingerprint, GRUB_MD_SHA1->read (fingerprint_context),
20);
+
+ *last = sk;
+ last = &sk->next;
+
+ grub_dprintf ("crypt", "actual pos: %x, expected: %x\n",
(int)grub_file_tell (f), (int)pend);
+
+ grub_file_seek (f, pend);
+ }
+ fail:
+ free_pk (ret);
+ grub_free (fingerprint_context);
+ grub_free (buffer);
+ return NULL;
+}
+
+struct grub_public_key *grub_pk_trusted;
+
+struct grub_public_subkey *
+grub_crypto_pk_locate_subkey (grub_uint64_t keyid, struct grub_public_key
*pkey)
+{
+ struct grub_public_subkey *sk;
+ for (sk = pkey->subkeys; sk; sk = sk->next)
+ if (grub_memcmp (sk->fingerprint + 3, &keyid, 8) == 0)
+ return sk;
+ return 0;
+}
+
+struct grub_public_subkey *
+grub_crypto_pk_locate_subkey_in_trustdb (grub_uint64_t keyid)
+{
+ struct grub_public_key *pkey;
+ struct grub_public_subkey *sk;
+ for (pkey = grub_pk_trusted; pkey; pkey = pkey->next)
+ {
+ sk = grub_crypto_pk_locate_subkey (keyid, pkey);
+ if (sk)
+ return sk;
+ }
+ return 0;
+}
+
+
+static int
+dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
+{
+ unsigned nbits = gcry_mpi_get_nbits (sk->mpis[1]);
+ grub_dprintf ("crypt", "must be %u bits got %d bits\n", nbits,
+ (int)(8 * hash->mdlen));
+ return gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, hval,
+ nbits / 8 < (unsigned) hash->mdlen ? nbits / 8
+ : (unsigned) hash->mdlen, 0);
+}
+
+static int
+rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
+{
+ grub_size_t tlen, emlen, fflen;
+ grub_uint8_t *em, *emptr;
+ unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
+ int ret;
+ tlen = hash->mdlen + hash->asnlen;
+ emlen = (nbits + 7) / 8;
+ if (emlen < tlen + 11)
+ return 1;
+
+ em = grub_malloc (emlen);
+ if (!em)
+ return 1;
+
+ em[0] = 0x00;
+ em[1] = 0x01;
+ fflen = emlen - tlen - 3;
+ for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
+ *emptr = 0xff;
+ *emptr++ = 0x00;
+ grub_memcpy (emptr, hash->asnoid, hash->asnlen);
+ emptr += hash->asnlen;
+ grub_memcpy (emptr, hval, hash->mdlen);
+
+ ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
+ grub_free (em);
+ return ret;
+}
+
+struct grub_pubkey_context
+{
+ grub_file_t sig;
+ struct signature_v4_header v4;
+ grub_uint8_t v;
+ const gcry_md_spec_t *hash;
+ void *hash_context;
+};
+
+static grub_err_t
+grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
+{
+ grub_size_t len;
+ grub_uint8_t h;
+ grub_uint8_t t;
+ grub_err_t err;
+ grub_uint8_t type = 0;
+ grub_uint8_t pk;
+
+ grub_memset (ctxt, 0, sizeof (*ctxt));
+
+ err = read_packet_header (sig, &type, &len);
+ if (err)
+ return err;
+
+ if (type != 0x2)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (ctxt->v != 4)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ h = ctxt->v4.hash;
+ t = ctxt->v4.type;
+ pk = ctxt->v4.pkeyalgo;
+
+ if (t != 0)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (h >= ARRAY_SIZE (hashes) || hashes[h] == NULL)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, "unknown hash");
+
+ if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ ctxt->hash = grub_crypto_lookup_md_by_name (hashes[h]);
+ if (!ctxt->hash)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, "hash `%s' not loaded",
hashes[h]);
+
+ grub_dprintf ("crypt", "alive\n");
+
+ ctxt->sig = sig;
+
+ ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
+ if (!ctxt->hash_context)
+ return grub_errno;
+
+ ctxt->hash->init (ctxt->hash_context);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_pubkey_write (void *ctxt_, void *buf, grub_size_t size)
+{
+ struct grub_pubkey_context *ctxt = ctxt_;
+ ctxt->hash->write (ctxt->hash_context, buf, size);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_verify_signature_real (struct grub_pubkey_context *ctxt,
+ struct grub_public_key *pkey)
+{
+ gcry_mpi_t mpis[10];
+ grub_uint8_t pk = ctxt->v4.pkeyalgo;
+ grub_size_t i;
+ grub_uint8_t *readbuf = 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);
+ grub_uint8_t s;
+ grub_uint16_t unhashed_sub;
+ grub_ssize_t r;
+ grub_uint8_t hash_start[2];
+ gcry_mpi_t hmpi;
+ grub_uint64_t keyid = 0;
+ struct grub_public_subkey *sk;
+
+ readbuf = grub_malloc (READBUF_SIZE);
+ if (!readbuf)
+ goto fail;
+
+ ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
+ ctxt->hash->write (ctxt->hash_context, &ctxt->v4, sizeof (ctxt->v4));
+ while (rem)
+ {
+ r = grub_file_read (ctxt->sig, readbuf,
+ rem < READBUF_SIZE ? rem : READBUF_SIZE);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ break;
+ ctxt->hash->write (ctxt->hash_context, readbuf, r);
+ rem -= r;
+ }
+ ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
+ s = 0xff;
+ ctxt->hash->write (ctxt->hash_context, &s, sizeof (s));
+ ctxt->hash->write (ctxt->hash_context, &headlen, sizeof (headlen));
+ 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);
+ }
+ }
+
+ ctxt->hash->final (ctxt->hash_context);
+
+ grub_dprintf ("crypt", "alive\n");
+
+ hval = ctxt->hash->read (ctxt->hash_context);
+
+ if (grub_file_read (ctxt->sig, hash_start, sizeof (hash_start)) != sizeof
(hash_start))
+ goto fail;
+ if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
+ goto fail;
+
+ grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (ctxt->sig));
+
+ for (i = 0; i < pkalgos[pk].nmpisig; i++)
+ {
+ grub_uint16_t l;
+ grub_size_t lb;
+ grub_dprintf ("crypt", "alive\n");
+ if (grub_file_read (ctxt->sig, &l, sizeof (l)) != sizeof (l))
+ goto fail;
+ grub_dprintf ("crypt", "alive\n");
+ lb = (grub_be_to_cpu16 (l) + 7) / 8;
+ grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l));
+ if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
+ goto fail;
+ grub_dprintf ("crypt", "alive\n");
+ if (grub_file_read (ctxt->sig, readbuf + sizeof (grub_uint16_t), lb) !=
(grub_ssize_t) lb)
+ goto fail;
+ grub_dprintf ("crypt", "alive\n");
+ grub_memcpy (readbuf, &l, sizeof (l));
+ grub_dprintf ("crypt", "alive\n");
+
+ if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
+ readbuf, lb + sizeof (grub_uint16_t), 0))
+ goto fail;
+ grub_dprintf ("crypt", "alive\n");
+ }
+
+ if (pkey)
+ sk = grub_crypto_pk_locate_subkey (keyid, pkey);
+ else
+ sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid);
+ if (!sk)
+ {
+ /* TRANSLATORS: %08x is 32-bit key id. */
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"),
+ keyid);
+ goto fail;
+ }
+
+ if (pkalgos[pk].pad (&hmpi, hval, ctxt->hash, sk))
+ goto fail;
+ if (!*pkalgos[pk].algo)
+ {
+ grub_dl_load (pkalgos[pk].module);
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ if (!*pkalgos[pk].algo)
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"),
+ pkalgos[pk].module);
+ goto fail;
+ }
+ if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0))
+ goto fail;
+
+ grub_free (readbuf);
+
+ return GRUB_ERR_NONE;
+
+ fail:
+ grub_free (readbuf);
+ if (!grub_errno)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ return grub_errno;
+}
+
+static void
+grub_pubkey_close_real (struct grub_pubkey_context *ctxt)
+{
+ if (ctxt->sig)
+ grub_file_close (ctxt->sig);
+ if (ctxt->hash_context)
+ grub_free (ctxt->hash_context);
+}
+
+static void
+grub_pubkey_close (void *ctxt)
+{
+ grub_pubkey_close_real (ctxt);
+ grub_free (ctxt);
+}
+
+grub_err_t
+grub_verify_signature (grub_file_t f, grub_file_t sig,
+ struct grub_public_key *pkey)
+{
+ grub_err_t err;
+ struct grub_pubkey_context ctxt;
+ grub_uint8_t *readbuf = NULL;
+ err = grub_verify_signature_init (&ctxt, sig);
+ if (err)
+ return err;
+
+ readbuf = grub_zalloc (READBUF_SIZE);
+ if (!readbuf)
+ goto fail;
+
+ while (1)
+ {
+ grub_ssize_t r;
+ r = grub_file_read (f, readbuf, READBUF_SIZE);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ break;
+ err = grub_pubkey_write (&ctxt, readbuf, r);
+ if (err)
+ return err;
+ }
+
+ grub_verify_signature_real (&ctxt, pkey);
+ fail:
+ grub_pubkey_close_real (&ctxt);
+ return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_trust (grub_extcmd_context_t ctxt,
+ int argc, char **args)
+{
+ grub_file_t pkf;
+ struct grub_public_key *pk = NULL;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ pkf = grub_file_open (args[0],
+ GRUB_FILE_TYPE_PUBLIC_KEY_TRUST
+ | GRUB_FILE_TYPE_NO_DECOMPRESS
+ | (ctxt->state[OPTION_SKIP_SIG].set
+ ? GRUB_FILE_TYPE_SKIP_SIGNATURE
+ : 0));
+ if (!pkf)
+ return grub_errno;
+ pk = grub_load_public_key (pkf);
+ if (!pk)
+ {
+ grub_file_close (pkf);
+ return grub_errno;
+ }
+ grub_file_close (pkf);
+
+ pk->next = grub_pk_trusted;
+ grub_pk_trusted = pk;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_list (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_public_key *pk = NULL;
+ struct grub_public_subkey *sk = NULL;
+
+ for (pk = grub_pk_trusted; pk; pk = pk->next)
+ for (sk = pk->subkeys; sk; sk = sk->next)
+ {
+ unsigned i;
+ for (i = 0; i < 20; i += 2)
+ grub_printf ("%02x%02x ", ((grub_uint8_t *) sk->fingerprint)[i],
+ ((grub_uint8_t *) sk->fingerprint)[i + 1]);
+ grub_printf ("\n");
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_uint32_t keyid, keyid_be;
+ struct grub_public_key **pkey;
+ struct grub_public_subkey *sk;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ keyid = grub_strtoull (args[0], 0, 16);
+ if (grub_errno)
+ return grub_errno;
+ keyid_be = grub_cpu_to_be32 (keyid);
+
+ for (pkey = &grub_pk_trusted; *pkey; pkey = &((*pkey)->next))
+ {
+ struct grub_public_key *next;
+ for (sk = (*pkey)->subkeys; sk; sk = sk->next)
+ if (grub_memcmp (sk->fingerprint + 4, &keyid_be, 4) == 0)
+ break;
+ if (!sk)
+ continue;
+ next = (*pkey)->next;
+ free_pk (*pkey);
+ *pkey = next;
+ return GRUB_ERR_NONE;
+ }
+ /* TRANSLATORS: %08x is 32-bit key id. */
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"),
keyid);
+}
+
+static grub_err_t
+grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
+ int argc, char **args)
+{
+ grub_file_t f = NULL, sig = NULL;
+ grub_err_t err = GRUB_ERR_NONE;
+ struct grub_public_key *pk = NULL;
+
+ grub_dprintf ("crypt", "alive\n");
+
+ if (argc < 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ grub_dprintf ("crypt", "alive\n");
+
+ if (argc > 2)
+ {
+ grub_file_t pkf;
+ pkf = grub_file_open (args[2],
+ GRUB_FILE_TYPE_PUBLIC_KEY
+ | GRUB_FILE_TYPE_NO_DECOMPRESS
+ | (ctxt->state[OPTION_SKIP_SIG].set
+ ? GRUB_FILE_TYPE_SKIP_SIGNATURE
+ : 0));
+ if (!pkf)
+ return grub_errno;
+ pk = grub_load_public_key (pkf);
+ if (!pk)
+ {
+ grub_file_close (pkf);
+ return grub_errno;
+ }
+ grub_file_close (pkf);
+ }
+
+ f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+ if (!f)
+ {
+ err = grub_errno;
+ goto fail;
+ }
+
+ sig = grub_file_open (args[1],
+ GRUB_FILE_TYPE_SIGNATURE
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (!sig)
+ {
+ err = grub_errno;
+ goto fail;
+ }
+
+ err = grub_verify_signature (f, sig, pk);
+ fail:
+ if (sig)
+ grub_file_close (sig);
+ if (f)
+ grub_file_close (f);
+ if (pk)
+ free_pk (pk);
+ return err;
+}
+
+static int sec = 0;
+
+static grub_err_t
+grub_pubkey_init (grub_file_t io, enum grub_file_type type __attribute__
((unused)),
+ void **context, enum grub_verify_flags *flags)
+{
+ grub_file_t sig;
+ char *fsuf, *ptr;
+ grub_err_t err;
+
+ if (!sec)
+ {
+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
+ return GRUB_ERR_NONE;
+ }
+
+ fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
+ if (!fsuf)
+ return grub_errno;
+ ptr = grub_stpcpy (fsuf, io->name);
+ grub_memcpy (ptr, ".sig", sizeof (".sig"));
+
+ sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE);
+ grub_free (fsuf);
+ if (!sig)
+ return grub_errno;
+
+
+ struct grub_pubkey_context *ctxt = grub_malloc (sizeof (*ctxt));
+ if (!ctxt)
+ {
+ grub_file_close (sig);
+ return grub_errno;
+ }
+ err = grub_verify_signature_init (ctxt, sig);
+ if (err)
+ {
+ grub_pubkey_close (ctxt);
+ return err;
+ }
+ *context = ctxt;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_pubkey_fini (void *ctxt)
+{
+ return grub_verify_signature_real (ctxt, NULL);
+}
+
+static char *
+grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ sec = (*val == '1') || (*val == 'e');
+ return grub_strdup (sec ? "enforce" : "no");
+}
+
+static grub_ssize_t
+pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
+{
+ grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
+ return len;
+}
+
+
+/* Filesystem descriptor. */
+struct grub_fs pseudo_fs =
+ {
+ .name = "pseudo",
+ .read = pseudo_read
+ };
+
+struct grub_file_verifier grub_pubkey_verifier =
+ {
+ .name = "pgp",
+ .init = grub_pubkey_init,
+ .fini = grub_pubkey_fini,
+ .write = grub_pubkey_write,
+ .close = grub_pubkey_close,
+ };
+
+static grub_extcmd_t cmd, cmd_trust;
+static grub_command_t cmd_distrust, cmd_list;
+
+GRUB_MOD_INIT(verify)
+{
+ const char *val;
+ struct grub_module_header *header;
+
+ val = grub_env_get ("check_signatures");
+ if (val && (val[0] == '1' || val[0] == 'e'))
+ sec = 1;
+ else
+ sec = 0;
+
+ grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec);
+ grub_env_export ("check_signatures");
+
+ grub_pk_trusted = 0;
+ FOR_MODULES (header)
+ {
+ struct grub_file pseudo_file;
+ struct grub_public_key *pk = NULL;
+
+ grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
+
+ /* Not an ELF module, skip. */
+ if (header->type != OBJ_TYPE_PUBKEY)
+ continue;
+
+ 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);
+
+ pk = grub_load_public_key (&pseudo_file);
+ if (!pk)
+ grub_fatal ("error loading initial key: %s\n", grub_errmsg);
+
+ pk->next = grub_pk_trusted;
+ grub_pk_trusted = pk;
+ }
+
+ if (!val)
+ grub_env_set ("check_signatures", grub_pk_trusted ? "enforce" : "no");
+
+ cmd = grub_register_extcmd ("verify_detached", grub_cmd_verify_signature, 0,
+ N_("[-s|--skip-sig] FILE SIGNATURE_FILE
[PUBKEY_FILE]"),
+ N_("Verify detached signature."),
+ options);
+ cmd_trust = grub_register_extcmd ("trust", grub_cmd_trust, 0,
+ N_("[-s|--skip-sig] PUBKEY_FILE"),
+ N_("Add PUBKEY_FILE to trusted keys."),
+ options);
+ cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
+ 0,
+ N_("Show the list of trusted keys."));
+ cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust,
+ N_("PUBKEY_ID"),
+ N_("Remove PUBKEY_ID from trusted
keys."));
+
+ grub_verifier_register (&grub_pubkey_verifier);
+}
+
+GRUB_MOD_FINI(verify)
+{
+ grub_verifier_unregister (&grub_pubkey_verifier);
+ grub_unregister_extcmd (cmd);
+ grub_unregister_extcmd (cmd_trust);
+ grub_unregister_command (cmd_list);
+ grub_unregister_command (cmd_distrust);
+}
diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
deleted file mode 100644
index d5d7c0f..0000000
--- a/grub-core/commands/verify.c
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2013 Free Software Foundation, Inc.
- *
- * GRUB 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 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/types.h>
-#include <grub/misc.h>
-#include <grub/mm.h>
-#include <grub/err.h>
-#include <grub/dl.h>
-#include <grub/file.h>
-#include <grub/command.h>
-#include <grub/crypto.h>
-#include <grub/i18n.h>
-#include <grub/gcrypt/gcrypt.h>
-#include <grub/pubkey.h>
-#include <grub/env.h>
-#include <grub/kernel.h>
-#include <grub/extcmd.h>
-#include <grub/verify.h>
-
-GRUB_MOD_LICENSE ("GPLv3+");
-
-enum
- {
- OPTION_SKIP_SIG = 0
- };
-
-static const struct grub_arg_option options[] =
- {
- {"skip-sig", 's', 0,
- N_("Skip signature-checking of the public key file."), 0, ARG_TYPE_NONE},
- {0, 0, 0, 0, 0, 0}
- };
-
-static grub_err_t
-read_packet_header (grub_file_t sig, grub_uint8_t *out_type, grub_size_t *len)
-{
- grub_uint8_t type;
- grub_uint8_t l;
- grub_uint16_t l16;
- grub_uint32_t l32;
-
- /* New format. */
- switch (grub_file_read (sig, &type, sizeof (type)))
- {
- case 1:
- break;
- case 0:
- {
- *out_type = 0xff;
- return 0;
- }
- default:
- if (grub_errno)
- return grub_errno;
- /* TRANSLATORS: it's about GNUPG signatures. */
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- }
-
- if (type == 0)
- {
- *out_type = 0xfe;
- return 0;
- }
-
- if (!(type & 0x80))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- if (type & 0x40)
- {
- *out_type = (type & 0x3f);
- if (grub_file_read (sig, &l, sizeof (l)) != 1)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- if (l < 192)
- {
- *len = l;
- return 0;
- }
- if (l < 224)
- {
- *len = (l - 192) << GRUB_CHAR_BIT;
- if (grub_file_read (sig, &l, sizeof (l)) != 1)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len |= l;
- return 0;
- }
- if (l == 255)
- {
- if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len = grub_be_to_cpu32 (l32);
- return 0;
- }
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- }
- *out_type = ((type >> 2) & 0xf);
- switch (type & 0x3)
- {
- case 0:
- if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len = l;
- return 0;
- case 1:
- if (grub_file_read (sig, &l16, sizeof (l16)) != sizeof (l16))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len = grub_be_to_cpu16 (l16);
- return 0;
- case 2:
- if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- *len = grub_be_to_cpu32 (l32);
- return 0;
- }
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-}
-
-struct signature_v4_header
-{
- grub_uint8_t type;
- grub_uint8_t pkeyalgo;
- grub_uint8_t hash;
- grub_uint16_t hashed_sub;
-} GRUB_PACKED;
-
-const char *hashes[] = {
- [0x01] = "md5",
- [0x02] = "sha1",
- [0x03] = "ripemd160",
- [0x08] = "sha256",
- [0x09] = "sha384",
- [0x0a] = "sha512",
- [0x0b] = "sha224"
-};
-
-struct gcry_pk_spec *grub_crypto_pk_dsa;
-struct gcry_pk_spec *grub_crypto_pk_ecdsa;
-struct gcry_pk_spec *grub_crypto_pk_rsa;
-
-static int
-dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
-static int
-rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
-
-struct
-{
- const char *name;
- grub_size_t nmpisig;
- grub_size_t nmpipub;
- struct gcry_pk_spec **algo;
- int (*pad) (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
- const char *module;
-} pkalgos[] =
- {
- [1] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
- [3] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
- [17] = { "dsa", 2, 4, &grub_crypto_pk_dsa, dsa_pad, "gcry_dsa" },
- };
-
-struct grub_public_key
-{
- struct grub_public_key *next;
- struct grub_public_subkey *subkeys;
-};
-
-struct grub_public_subkey
-{
- struct grub_public_subkey *next;
- grub_uint8_t type;
- grub_uint32_t fingerprint[5];
- gcry_mpi_t mpis[10];
-};
-
-static void
-free_pk (struct grub_public_key *pk)
-{
- struct grub_public_subkey *nsk, *sk;
- for (sk = pk->subkeys; sk; sk = nsk)
- {
- grub_size_t i;
- for (i = 0; i < ARRAY_SIZE (sk->mpis); i++)
- if (sk->mpis[i])
- gcry_mpi_release (sk->mpis[i]);
- nsk = sk->next;
- grub_free (sk);
- }
- grub_free (pk);
-}
-
-#define READBUF_SIZE 4096
-
-struct grub_public_key *
-grub_load_public_key (grub_file_t f)
-{
- grub_err_t err;
- struct grub_public_key *ret;
- struct grub_public_subkey **last = 0;
- void *fingerprint_context = NULL;
- grub_uint8_t *buffer = NULL;
-
- ret = grub_zalloc (sizeof (*ret));
- if (!ret)
- {
- grub_free (fingerprint_context);
- return NULL;
- }
-
- buffer = grub_zalloc (READBUF_SIZE);
- fingerprint_context = grub_zalloc (GRUB_MD_SHA1->contextsize);
-
- if (!buffer || !fingerprint_context)
- goto fail;
-
- last = &ret->subkeys;
-
- while (1)
- {
- grub_uint8_t type;
- grub_size_t len;
- grub_uint8_t v, pk;
- grub_uint32_t creation_time;
- grub_off_t pend;
- struct grub_public_subkey *sk;
- grub_size_t i;
- grub_uint16_t len_be;
-
- err = read_packet_header (f, &type, &len);
-
- if (err)
- goto fail;
- if (type == 0xfe)
- continue;
- if (type == 0xff)
- {
- grub_free (fingerprint_context);
- grub_free (buffer);
- return ret;
- }
-
- grub_dprintf ("crypt", "len = %x\n", (int) len);
-
- pend = grub_file_tell (f) + len;
- if (type != 6 && type != 14
- && type != 5 && type != 7)
- {
- grub_file_seek (f, pend);
- continue;
- }
-
- if (grub_file_read (f, &v, sizeof (v)) != sizeof (v))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- goto fail;
- }
-
- grub_dprintf ("crypt", "v = %x\n", v);
-
- if (v != 4)
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- goto fail;
- }
- if (grub_file_read (f, &creation_time, sizeof (creation_time)) != sizeof
(creation_time))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- goto fail;
- }
-
- grub_dprintf ("crypt", "time = %x\n", creation_time);
-
- if (grub_file_read (f, &pk, sizeof (pk)) != sizeof (pk))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- goto fail;
- }
-
- grub_dprintf ("crypt", "pk = %x\n", pk);
-
- if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
- {
- grub_file_seek (f, pend);
- continue;
- }
-
- sk = grub_zalloc (sizeof (struct grub_public_subkey));
- if (!sk)
- goto fail;
-
- grub_memset (fingerprint_context, 0, GRUB_MD_SHA1->contextsize);
- GRUB_MD_SHA1->init (fingerprint_context);
- GRUB_MD_SHA1->write (fingerprint_context, "\x99", 1);
- len_be = grub_cpu_to_be16 (len);
- GRUB_MD_SHA1->write (fingerprint_context, &len_be, sizeof (len_be));
- GRUB_MD_SHA1->write (fingerprint_context, &v, sizeof (v));
- GRUB_MD_SHA1->write (fingerprint_context, &creation_time, sizeof
(creation_time));
- GRUB_MD_SHA1->write (fingerprint_context, &pk, sizeof (pk));
-
- for (i = 0; i < pkalgos[pk].nmpipub; i++)
- {
- grub_uint16_t l;
- grub_size_t lb;
- if (grub_file_read (f, &l, sizeof (l)) != sizeof (l))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- break;
- }
-
- lb = (grub_be_to_cpu16 (l) + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT;
- if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- break;
- }
- if (grub_file_read (f, buffer + sizeof (grub_uint16_t), lb) !=
(grub_ssize_t) lb)
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- break;
- }
- grub_memcpy (buffer, &l, sizeof (l));
-
- GRUB_MD_SHA1->write (fingerprint_context, buffer, lb + sizeof
(grub_uint16_t));
-
- if (gcry_mpi_scan (&sk->mpis[i], GCRYMPI_FMT_PGP,
- buffer, lb + sizeof (grub_uint16_t), 0))
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- break;
- }
- }
-
- if (i < pkalgos[pk].nmpipub)
- {
- grub_free (sk);
- goto fail;
- }
-
- GRUB_MD_SHA1->final (fingerprint_context);
-
- grub_memcpy (sk->fingerprint, GRUB_MD_SHA1->read (fingerprint_context),
20);
-
- *last = sk;
- last = &sk->next;
-
- grub_dprintf ("crypt", "actual pos: %x, expected: %x\n",
(int)grub_file_tell (f), (int)pend);
-
- grub_file_seek (f, pend);
- }
- fail:
- free_pk (ret);
- grub_free (fingerprint_context);
- grub_free (buffer);
- return NULL;
-}
-
-struct grub_public_key *grub_pk_trusted;
-
-struct grub_public_subkey *
-grub_crypto_pk_locate_subkey (grub_uint64_t keyid, struct grub_public_key
*pkey)
-{
- struct grub_public_subkey *sk;
- for (sk = pkey->subkeys; sk; sk = sk->next)
- if (grub_memcmp (sk->fingerprint + 3, &keyid, 8) == 0)
- return sk;
- return 0;
-}
-
-struct grub_public_subkey *
-grub_crypto_pk_locate_subkey_in_trustdb (grub_uint64_t keyid)
-{
- struct grub_public_key *pkey;
- struct grub_public_subkey *sk;
- for (pkey = grub_pk_trusted; pkey; pkey = pkey->next)
- {
- sk = grub_crypto_pk_locate_subkey (keyid, pkey);
- if (sk)
- return sk;
- }
- return 0;
-}
-
-
-static int
-dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
-{
- unsigned nbits = gcry_mpi_get_nbits (sk->mpis[1]);
- grub_dprintf ("crypt", "must be %u bits got %d bits\n", nbits,
- (int)(8 * hash->mdlen));
- return gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, hval,
- nbits / 8 < (unsigned) hash->mdlen ? nbits / 8
- : (unsigned) hash->mdlen, 0);
-}
-
-static int
-rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
-{
- grub_size_t tlen, emlen, fflen;
- grub_uint8_t *em, *emptr;
- unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
- int ret;
- tlen = hash->mdlen + hash->asnlen;
- emlen = (nbits + 7) / 8;
- if (emlen < tlen + 11)
- return 1;
-
- em = grub_malloc (emlen);
- if (!em)
- return 1;
-
- em[0] = 0x00;
- em[1] = 0x01;
- fflen = emlen - tlen - 3;
- for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
- *emptr = 0xff;
- *emptr++ = 0x00;
- grub_memcpy (emptr, hash->asnoid, hash->asnlen);
- emptr += hash->asnlen;
- grub_memcpy (emptr, hval, hash->mdlen);
-
- ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
- grub_free (em);
- return ret;
-}
-
-struct grub_pubkey_context
-{
- grub_file_t sig;
- struct signature_v4_header v4;
- grub_uint8_t v;
- const gcry_md_spec_t *hash;
- void *hash_context;
-};
-
-static grub_err_t
-grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
-{
- grub_size_t len;
- grub_uint8_t h;
- grub_uint8_t t;
- grub_err_t err;
- grub_uint8_t type = 0;
- grub_uint8_t pk;
-
- grub_memset (ctxt, 0, sizeof (*ctxt));
-
- err = read_packet_header (sig, &type, &len);
- if (err)
- return err;
-
- if (type != 0x2)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- if (ctxt->v != 4)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4))
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- h = ctxt->v4.hash;
- t = ctxt->v4.type;
- pk = ctxt->v4.pkeyalgo;
-
- if (t != 0)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- if (h >= ARRAY_SIZE (hashes) || hashes[h] == NULL)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, "unknown hash");
-
- if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
-
- ctxt->hash = grub_crypto_lookup_md_by_name (hashes[h]);
- if (!ctxt->hash)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, "hash `%s' not loaded",
hashes[h]);
-
- grub_dprintf ("crypt", "alive\n");
-
- ctxt->sig = sig;
-
- ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
- if (!ctxt->hash_context)
- return grub_errno;
-
- ctxt->hash->init (ctxt->hash_context);
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_pubkey_write (void *ctxt_, void *buf, grub_size_t size)
-{
- struct grub_pubkey_context *ctxt = ctxt_;
- ctxt->hash->write (ctxt->hash_context, buf, size);
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_verify_signature_real (struct grub_pubkey_context *ctxt,
- struct grub_public_key *pkey)
-{
- gcry_mpi_t mpis[10];
- grub_uint8_t pk = ctxt->v4.pkeyalgo;
- grub_size_t i;
- grub_uint8_t *readbuf = 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);
- grub_uint8_t s;
- grub_uint16_t unhashed_sub;
- grub_ssize_t r;
- grub_uint8_t hash_start[2];
- gcry_mpi_t hmpi;
- grub_uint64_t keyid = 0;
- struct grub_public_subkey *sk;
-
- readbuf = grub_malloc (READBUF_SIZE);
- if (!readbuf)
- goto fail;
-
- ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
- ctxt->hash->write (ctxt->hash_context, &ctxt->v4, sizeof (ctxt->v4));
- while (rem)
- {
- r = grub_file_read (ctxt->sig, readbuf,
- rem < READBUF_SIZE ? rem : READBUF_SIZE);
- if (r < 0)
- goto fail;
- if (r == 0)
- break;
- ctxt->hash->write (ctxt->hash_context, readbuf, r);
- rem -= r;
- }
- ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
- s = 0xff;
- ctxt->hash->write (ctxt->hash_context, &s, sizeof (s));
- ctxt->hash->write (ctxt->hash_context, &headlen, sizeof (headlen));
- 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);
- }
- }
-
- ctxt->hash->final (ctxt->hash_context);
-
- grub_dprintf ("crypt", "alive\n");
-
- hval = ctxt->hash->read (ctxt->hash_context);
-
- if (grub_file_read (ctxt->sig, hash_start, sizeof (hash_start)) != sizeof
(hash_start))
- goto fail;
- if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
- goto fail;
-
- grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (ctxt->sig));
-
- for (i = 0; i < pkalgos[pk].nmpisig; i++)
- {
- grub_uint16_t l;
- grub_size_t lb;
- grub_dprintf ("crypt", "alive\n");
- if (grub_file_read (ctxt->sig, &l, sizeof (l)) != sizeof (l))
- goto fail;
- grub_dprintf ("crypt", "alive\n");
- lb = (grub_be_to_cpu16 (l) + 7) / 8;
- grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l));
- if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
- goto fail;
- grub_dprintf ("crypt", "alive\n");
- if (grub_file_read (ctxt->sig, readbuf + sizeof (grub_uint16_t), lb) !=
(grub_ssize_t) lb)
- goto fail;
- grub_dprintf ("crypt", "alive\n");
- grub_memcpy (readbuf, &l, sizeof (l));
- grub_dprintf ("crypt", "alive\n");
-
- if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
- readbuf, lb + sizeof (grub_uint16_t), 0))
- goto fail;
- grub_dprintf ("crypt", "alive\n");
- }
-
- if (pkey)
- sk = grub_crypto_pk_locate_subkey (keyid, pkey);
- else
- sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid);
- if (!sk)
- {
- /* TRANSLATORS: %08x is 32-bit key id. */
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"),
- keyid);
- goto fail;
- }
-
- if (pkalgos[pk].pad (&hmpi, hval, ctxt->hash, sk))
- goto fail;
- if (!*pkalgos[pk].algo)
- {
- grub_dl_load (pkalgos[pk].module);
- grub_errno = GRUB_ERR_NONE;
- }
-
- if (!*pkalgos[pk].algo)
- {
- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"),
- pkalgos[pk].module);
- goto fail;
- }
- if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0))
- goto fail;
-
- grub_free (readbuf);
-
- return GRUB_ERR_NONE;
-
- fail:
- grub_free (readbuf);
- if (!grub_errno)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- return grub_errno;
-}
-
-static void
-grub_pubkey_close_real (struct grub_pubkey_context *ctxt)
-{
- if (ctxt->sig)
- grub_file_close (ctxt->sig);
- if (ctxt->hash_context)
- grub_free (ctxt->hash_context);
-}
-
-static void
-grub_pubkey_close (void *ctxt)
-{
- grub_pubkey_close_real (ctxt);
- grub_free (ctxt);
-}
-
-grub_err_t
-grub_verify_signature (grub_file_t f, grub_file_t sig,
- struct grub_public_key *pkey)
-{
- grub_err_t err;
- struct grub_pubkey_context ctxt;
- grub_uint8_t *readbuf = NULL;
- err = grub_verify_signature_init (&ctxt, sig);
- if (err)
- return err;
-
- readbuf = grub_zalloc (READBUF_SIZE);
- if (!readbuf)
- goto fail;
-
- while (1)
- {
- grub_ssize_t r;
- r = grub_file_read (f, readbuf, READBUF_SIZE);
- if (r < 0)
- goto fail;
- if (r == 0)
- break;
- err = grub_pubkey_write (&ctxt, readbuf, r);
- if (err)
- return err;
- }
-
- grub_verify_signature_real (&ctxt, pkey);
- fail:
- grub_pubkey_close_real (&ctxt);
- return grub_errno;
-}
-
-static grub_err_t
-grub_cmd_trust (grub_extcmd_context_t ctxt,
- int argc, char **args)
-{
- grub_file_t pkf;
- struct grub_public_key *pk = NULL;
-
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
-
- pkf = grub_file_open (args[0],
- GRUB_FILE_TYPE_PUBLIC_KEY_TRUST
- | GRUB_FILE_TYPE_NO_DECOMPRESS
- | (ctxt->state[OPTION_SKIP_SIG].set
- ? GRUB_FILE_TYPE_SKIP_SIGNATURE
- : 0));
- if (!pkf)
- return grub_errno;
- pk = grub_load_public_key (pkf);
- if (!pk)
- {
- grub_file_close (pkf);
- return grub_errno;
- }
- grub_file_close (pkf);
-
- pk->next = grub_pk_trusted;
- grub_pk_trusted = pk;
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_cmd_list (grub_command_t cmd __attribute__ ((unused)),
- int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
-{
- struct grub_public_key *pk = NULL;
- struct grub_public_subkey *sk = NULL;
-
- for (pk = grub_pk_trusted; pk; pk = pk->next)
- for (sk = pk->subkeys; sk; sk = sk->next)
- {
- unsigned i;
- for (i = 0; i < 20; i += 2)
- grub_printf ("%02x%02x ", ((grub_uint8_t *) sk->fingerprint)[i],
- ((grub_uint8_t *) sk->fingerprint)[i + 1]);
- grub_printf ("\n");
- }
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)),
- int argc, char **args)
-{
- grub_uint32_t keyid, keyid_be;
- struct grub_public_key **pkey;
- struct grub_public_subkey *sk;
-
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
- keyid = grub_strtoull (args[0], 0, 16);
- if (grub_errno)
- return grub_errno;
- keyid_be = grub_cpu_to_be32 (keyid);
-
- for (pkey = &grub_pk_trusted; *pkey; pkey = &((*pkey)->next))
- {
- struct grub_public_key *next;
- for (sk = (*pkey)->subkeys; sk; sk = sk->next)
- if (grub_memcmp (sk->fingerprint + 4, &keyid_be, 4) == 0)
- break;
- if (!sk)
- continue;
- next = (*pkey)->next;
- free_pk (*pkey);
- *pkey = next;
- return GRUB_ERR_NONE;
- }
- /* TRANSLATORS: %08x is 32-bit key id. */
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"),
keyid);
-}
-
-static grub_err_t
-grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
- int argc, char **args)
-{
- grub_file_t f = NULL, sig = NULL;
- grub_err_t err = GRUB_ERR_NONE;
- struct grub_public_key *pk = NULL;
-
- grub_dprintf ("crypt", "alive\n");
-
- if (argc < 2)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
-
- grub_dprintf ("crypt", "alive\n");
-
- if (argc > 2)
- {
- grub_file_t pkf;
- pkf = grub_file_open (args[2],
- GRUB_FILE_TYPE_PUBLIC_KEY
- | GRUB_FILE_TYPE_NO_DECOMPRESS
- | (ctxt->state[OPTION_SKIP_SIG].set
- ? GRUB_FILE_TYPE_SKIP_SIGNATURE
- : 0));
- if (!pkf)
- return grub_errno;
- pk = grub_load_public_key (pkf);
- if (!pk)
- {
- grub_file_close (pkf);
- return grub_errno;
- }
- grub_file_close (pkf);
- }
-
- f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
- if (!f)
- {
- err = grub_errno;
- goto fail;
- }
-
- sig = grub_file_open (args[1],
- GRUB_FILE_TYPE_SIGNATURE
- | GRUB_FILE_TYPE_NO_DECOMPRESS);
- if (!sig)
- {
- err = grub_errno;
- goto fail;
- }
-
- err = grub_verify_signature (f, sig, pk);
- fail:
- if (sig)
- grub_file_close (sig);
- if (f)
- grub_file_close (f);
- if (pk)
- free_pk (pk);
- return err;
-}
-
-static int sec = 0;
-
-static grub_err_t
-grub_pubkey_init (grub_file_t io, enum grub_file_type type __attribute__
((unused)),
- void **context, enum grub_verify_flags *flags)
-{
- grub_file_t sig;
- char *fsuf, *ptr;
- grub_err_t err;
-
- if (!sec)
- {
- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
- return GRUB_ERR_NONE;
- }
-
- fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
- if (!fsuf)
- return grub_errno;
- ptr = grub_stpcpy (fsuf, io->name);
- grub_memcpy (ptr, ".sig", sizeof (".sig"));
-
- sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE);
- grub_free (fsuf);
- if (!sig)
- return grub_errno;
-
-
- struct grub_pubkey_context *ctxt = grub_malloc (sizeof (*ctxt));
- if (!ctxt)
- {
- grub_file_close (sig);
- return grub_errno;
- }
- err = grub_verify_signature_init (ctxt, sig);
- if (err)
- {
- grub_pubkey_close (ctxt);
- return err;
- }
- *context = ctxt;
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_pubkey_fini (void *ctxt)
-{
- return grub_verify_signature_real (ctxt, NULL);
-}
-
-static char *
-grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)),
- const char *val)
-{
- sec = (*val == '1') || (*val == 'e');
- return grub_strdup (sec ? "enforce" : "no");
-}
-
-static grub_ssize_t
-pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
-{
- grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
- return len;
-}
-
-
-/* Filesystem descriptor. */
-struct grub_fs pseudo_fs =
- {
- .name = "pseudo",
- .read = pseudo_read
- };
-
-struct grub_file_verifier grub_pubkey_verifier =
- {
- .name = "pgp",
- .init = grub_pubkey_init,
- .fini = grub_pubkey_fini,
- .write = grub_pubkey_write,
- .close = grub_pubkey_close,
- };
-
-static grub_extcmd_t cmd, cmd_trust;
-static grub_command_t cmd_distrust, cmd_list;
-
-GRUB_MOD_INIT(verify)
-{
- const char *val;
- struct grub_module_header *header;
-
- val = grub_env_get ("check_signatures");
- if (val && (val[0] == '1' || val[0] == 'e'))
- sec = 1;
- else
- sec = 0;
-
- grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec);
- grub_env_export ("check_signatures");
-
- grub_pk_trusted = 0;
- FOR_MODULES (header)
- {
- struct grub_file pseudo_file;
- struct grub_public_key *pk = NULL;
-
- grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
-
- /* Not an ELF module, skip. */
- if (header->type != OBJ_TYPE_PUBKEY)
- continue;
-
- 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);
-
- pk = grub_load_public_key (&pseudo_file);
- if (!pk)
- grub_fatal ("error loading initial key: %s\n", grub_errmsg);
-
- pk->next = grub_pk_trusted;
- grub_pk_trusted = pk;
- }
-
- if (!val)
- grub_env_set ("check_signatures", grub_pk_trusted ? "enforce" : "no");
-
- cmd = grub_register_extcmd ("verify_detached", grub_cmd_verify_signature, 0,
- N_("[-s|--skip-sig] FILE SIGNATURE_FILE
[PUBKEY_FILE]"),
- N_("Verify detached signature."),
- options);
- cmd_trust = grub_register_extcmd ("trust", grub_cmd_trust, 0,
- N_("[-s|--skip-sig] PUBKEY_FILE"),
- N_("Add PUBKEY_FILE to trusted keys."),
- options);
- cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
- 0,
- N_("Show the list of trusted keys."));
- cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust,
- N_("PUBKEY_ID"),
- N_("Remove PUBKEY_ID from trusted
keys."));
-
- grub_verifier_register (&grub_pubkey_verifier);
-}
-
-GRUB_MOD_FINI(verify)
-{
- grub_verifier_unregister (&grub_pubkey_verifier);
- grub_unregister_extcmd (cmd);
- grub_unregister_extcmd (cmd_trust);
- grub_unregister_command (cmd_list);
- grub_unregister_command (cmd_distrust);
-}
--
1.7.10.4
[PATCH v3 4/8] verifiers: Add possibility to defer verification to other verifiers, Daniel Kiper, 2018/10/03
[PATCH v3 1/8] verifiers: File type for fine-grained signature-verification controlling, Daniel Kiper, 2018/10/03
[PATCH v3 5/8] verifiers: Rename verify module to pgp module,
Daniel Kiper <=
Re: [PATCH v3 5/8] verifiers: Rename verify module to pgp module, Konrad Rzeszutek Wilk, 2018/10/09
[PATCH v3 8/8] efi: Add EFI shim lock verifier, Daniel Kiper, 2018/10/03