#include <grub/env.h>
#include <grub/kernel.h>
#include <grub/extcmd.h>
+#include <grub/verify.h>
GRUB_MOD_LICENSE ("GPLv3+");
-struct grub_verified
-{
- grub_file_t file;
- void *buf;
-};
-typedef struct grub_verified *grub_verified_t;
-
enum
{
OPTION_SKIP_SIG = 0
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_real (char *buf, grub_size_t size,
- grub_file_t f, grub_file_t sig,
- struct grub_public_key *pkey)
+grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
{
grub_size_t len;
- grub_uint8_t v;
grub_uint8_t h;
grub_uint8_t t;
- grub_uint8_t pk;
- const gcry_md_spec_t *hash;
- struct signature_v4_header v4;
grub_err_t err;
- grub_size_t i;
- gcry_mpi_t mpis[10];
grub_uint8_t type = 0;
+ grub_uint8_t pk;
+
+ grub_memset (ctxt, 0, sizeof (*ctxt));
err = read_packet_header (sig, &type, &len);
if (err)
if (type != 0x2)
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- if (grub_file_read (sig, &v, sizeof (v)) != sizeof (v))
+ if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v))
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- if (v != 4)
+ if (ctxt->v != 4)
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- if (grub_file_read (sig, &v4, sizeof (v4)) != sizeof (v4))
+ if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4))
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- h = v4.hash;
- t = v4.type;
- pk = v4.pkeyalgo;
+ 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 (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- hash = grub_crypto_lookup_md_by_name (hashes[h]);
- if (!hash)
+ 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");
- {
- void *context = NULL;
- unsigned char *hval;
- grub_ssize_t rem = grub_be_to_cpu16 (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;
- grub_uint8_t *readbuf = NULL;
-
- context = grub_zalloc (hash->contextsize);
- readbuf = grub_zalloc (READBUF_SIZE);
- if (!context || !readbuf)
- goto fail;
+ ctxt->sig = sig;
- hash->init (context);
- if (buf)
- hash->write (context, buf, size);
- else
- while (1)
- {
- r = grub_file_read (f, readbuf, READBUF_SIZE);
- if (r < 0)
- goto fail;
- if (r == 0)
- break;
- hash->write (context, readbuf, r);
- }
+ ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
+ if (!ctxt->hash_context)
+ return grub_errno;
- hash->write (context, &v, sizeof (v));
- hash->write (context, &v4, sizeof (v4));
- while (rem)
- {
- r = grub_file_read (sig, readbuf,
- rem < READBUF_SIZE ? rem : READBUF_SIZE);
- if (r < 0)
- goto fail;
- if (r == 0)
- break;
- hash->write (context, readbuf, r);
- rem -= r;
- }
- hash->write (context, &v, sizeof (v));
- s = 0xff;
- hash->write (context, &s, sizeof (s));
- hash->write (context, &headlen, sizeof (headlen));
- r = grub_file_read (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 (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->init (ctxt->hash_context);
- hash->final (context);
+ return GRUB_ERR_NONE;
+}
- grub_dprintf ("crypt", "alive\n");
+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;
+}
- hval = hash->read (context);
+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;
- if (grub_file_read (sig, hash_start, sizeof (hash_start)) != sizeof (hash_start))
+ 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;
- if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
+ 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);
+ }
+ }
- grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (sig));
+ ctxt->hash->final (ctxt->hash_context);
- 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 (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 (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");
+ 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");
- }
+ hval = ctxt->hash->read (ctxt->hash_context);
- 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);
+ 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 (pkalgos[pk].pad (&hmpi, hval, hash, sk))
+ 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].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))
+ 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 (context);
- grub_free (readbuf);
+ grub_free (readbuf);
- return GRUB_ERR_NONE;
+ return GRUB_ERR_NONE;
- fail:
- grub_free (context);
- grub_free (readbuf);
- if (!grub_errno)
- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
- return grub_errno;
- }
+ 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)
{
- return grub_verify_signature_real (0, 0, f, sig, 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
static int sec = 0;
-static void
-verified_free (grub_verified_t verified)
-{
- if (verified)
- {
- grub_free (verified->buf);
- grub_free (verified);
- }
-}
-
-static grub_ssize_t
-verified_read (struct grub_file *file, char *buf, grub_size_t len)
-{
- grub_verified_t verified = file->data;
-
- grub_memcpy (buf, (char *) verified->buf + file->offset, len);
- return len;
-}
-
static grub_err_t
-verified_close (struct grub_file *file)
-{
- grub_verified_t verified = file->data;
-
- grub_file_close (verified->file);
- verified_free (verified);
- file->data = 0;
-
- /* device and name are freed by parent */
- file->device = 0;
- file->name = 0;
-
- return grub_errno;
-}
-
-struct grub_fs verified_fs =
-{
- .name = "verified_read",
- .read = verified_read,
- .close = verified_close
-};
-
-static grub_file_t
-grub_pubkey_open (grub_file_t io, enum grub_file_type type)
+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;
- grub_file_t ret;
- grub_verified_t verified;
-
- if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE
- || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE
- || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE))
- return io;
if (!sec)
- return io;
- if (io->device->disk &&
- (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID
- || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID))
- return io;
+ {
+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
+ return GRUB_ERR_NONE;
+ }
+
fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
if (!fsuf)
- return NULL;
+ 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 NULL;
+ return grub_errno;
- ret = grub_malloc (sizeof (*ret));
- if (!ret)
- {
- grub_free (fsuf);
- return NULL;
- }
- *ret = *io;
- ret->fs = &verified_fs;
- ret->not_easily_seekable = 0;
- if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1))
- {
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "big file signature isn't implemented yet");
- grub_file_close (sig);
- grub_free (ret);
- return NULL;
- }
- verified = grub_malloc (sizeof (*verified));
- if (!verified)
+ struct grub_pubkey_context *ctxt = grub_malloc (sizeof (*ctxt));
+ if (!ctxt)
{
grub_file_close (sig);
- grub_free (ret);
- return NULL;
- }
- verified->buf = grub_malloc (ret->size);
- if (!verified->buf)
- {
- grub_file_close (sig);
- verified_free (verified);
- grub_free (ret);
- return NULL;
- }
- if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size)
- {
- if (!grub_errno)
- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
- io->name);
- grub_file_close (sig);
- verified_free (verified);
- grub_free (ret);
- return NULL;
+ return grub_errno;
}
-
- err = grub_verify_signature_real (verified->buf, ret->size, 0, sig, NULL);
- grub_file_close (sig);
+ err = grub_verify_signature_init (ctxt, sig);
if (err)
{
- verified_free (verified);
- grub_free (ret);
- return NULL;
+ grub_pubkey_close (ctxt);
+ return err;
}
- verified->file = io;
- ret->data = verified;
- return ret;
+ *context = ctxt;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_pubkey_fini (void *ctxt)
+{
+ return grub_verify_signature_real (ctxt, NULL);
}
static char *
{
.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;
sec = 1;
else
sec = 0;
-
- grub_file_filter_register (GRUB_FILE_FILTER_PUBKEY, grub_pubkey_open);
grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec);
grub_env_export ("check_signatures");
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_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY);
+ grub_verifier_unregister (&grub_pubkey_verifier);
grub_unregister_extcmd (cmd);
grub_unregister_extcmd (cmd_trust);
grub_unregister_command (cmd_list);