mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-22 07:12:39 +00:00
verify framework.
This commit is contained in:
1 parent
aa93127ed8
commit
09bd17faaa
6 files changed
+477
-284
No files matched your search
@@ -899,6 +899,11 @@ module = {
|
||||
cppflags = '-I$(srcdir)/lib/posix_wrap';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = verify_helper;
|
||||
common = commands/verify_helper.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = hdparm;
|
||||
common = commands/hdparm.c;
|
||||
|
||||
+256
-283
@@ -30,16 +30,10 @@
|
||||
#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
|
||||
@@ -445,22 +439,26 @@ rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
|
||||
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)
|
||||
@@ -469,18 +467,18 @@ grub_verify_signature_real (char *buf, grub_size_t size,
|
||||
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"));
|
||||
@@ -491,183 +489,232 @@ grub_verify_signature_real (char *buf, grub_size_t size,
|
||||
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;
|
||||
ctxt->sig = sig;
|
||||
|
||||
context = grub_zalloc (hash->contextsize);
|
||||
readbuf = grub_zalloc (READBUF_SIZE);
|
||||
if (!context || !readbuf)
|
||||
goto fail;
|
||||
ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
|
||||
if (!ctxt->hash_context)
|
||||
return grub_errno;
|
||||
|
||||
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->init (ctxt->hash_context);
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
grub_uint8_t *ptr;
|
||||
grub_uint32_t l;
|
||||
rem = grub_be_to_cpu16 (unhashed_sub);
|
||||
if (rem > READBUF_SIZE)
|
||||
r = grub_file_read (ctxt->sig, readbuf,
|
||||
rem < READBUF_SIZE ? rem : READBUF_SIZE);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = grub_file_read (sig, readbuf, rem);
|
||||
if (r != rem)
|
||||
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;
|
||||
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", "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");
|
||||
}
|
||||
|
||||
hash->final (context);
|
||||
|
||||
grub_dprintf ("crypt", "alive\n");
|
||||
|
||||
hval = hash->read (context);
|
||||
|
||||
if (grub_file_read (sig, hash_start, sizeof (hash_start)) != sizeof (hash_start))
|
||||
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 (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 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_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (sig));
|
||||
grub_free (readbuf);
|
||||
|
||||
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");
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
|
||||
readbuf, lb + sizeof (grub_uint16_t), 0))
|
||||
goto fail;
|
||||
grub_dprintf ("crypt", "alive\n");
|
||||
}
|
||||
fail:
|
||||
grub_free (readbuf);
|
||||
if (!grub_errno)
|
||||
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
if (pkalgos[pk].pad (&hmpi, hval, 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);
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
@@ -819,134 +866,52 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
|
||||
|
||||
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;
|
||||
return grub_errno;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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 *
|
||||
@@ -970,8 +935,16 @@ 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;
|
||||
@@ -987,8 +960,6 @@ GRUB_MOD_INIT(verify)
|
||||
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");
|
||||
|
||||
@@ -1033,11 +1004,13 @@ GRUB_MOD_INIT(verify)
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
#include <grub/file.h>
|
||||
#include <grub/verify.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
struct grub_file_verifier *grub_file_verifiers;
|
||||
|
||||
struct grub_verified
|
||||
{
|
||||
grub_file_t file;
|
||||
void *buf;
|
||||
};
|
||||
typedef struct grub_verified *grub_verified_t;
|
||||
|
||||
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_verify_helper_open (grub_file_t io, enum grub_file_type type)
|
||||
{
|
||||
grub_verified_t verified = 0;
|
||||
struct grub_file_verifier *ver;
|
||||
void *context;
|
||||
grub_file_t ret = 0;
|
||||
grub_err_t err;
|
||||
|
||||
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 (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;
|
||||
|
||||
FOR_LIST_ELEMENTS(ver, grub_file_verifiers)
|
||||
{
|
||||
enum grub_verify_flags flags = 0;
|
||||
err = ver->init (io, type, &context, &flags);
|
||||
if (err)
|
||||
goto fail_noclose;
|
||||
if (!(flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION))
|
||||
break;
|
||||
}
|
||||
if (!ver)
|
||||
/* No verifiers wanted to verify. Just return underlying file. */
|
||||
return io;
|
||||
|
||||
ret = grub_malloc (sizeof (*ret));
|
||||
if (!ret)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
*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");
|
||||
goto fail;
|
||||
}
|
||||
verified = grub_malloc (sizeof (*verified));
|
||||
if (!verified)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
verified->buf = grub_malloc (ret->size);
|
||||
if (!verified->buf)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
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);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = ver->write (context, verified->buf, ret->size);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = ver->fini (context);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
ver->close (context);
|
||||
|
||||
FOR_LIST_ELEMENTS_NEXT(ver, grub_file_verifiers)
|
||||
{
|
||||
enum grub_verify_flags flags = 0;
|
||||
err = ver->init (io, type, &context, &flags);
|
||||
if (err)
|
||||
goto fail_noclose;
|
||||
if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION)
|
||||
continue;
|
||||
err = ver->write (context, verified->buf, ret->size);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = ver->fini (context);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
ver->close (context);
|
||||
}
|
||||
|
||||
verified->file = io;
|
||||
ret->data = verified;
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
ver->close (context);
|
||||
fail_noclose:
|
||||
verified_free (verified);
|
||||
grub_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GRUB_MOD_INIT(verify_helper)
|
||||
{
|
||||
grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verify_helper_open);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(verify_helper)
|
||||
{
|
||||
grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY);
|
||||
}
|
||||
+1
-1
@@ -170,7 +170,7 @@ extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook);
|
||||
/* Filters with lower ID are executed first. */
|
||||
typedef enum grub_file_filter_id
|
||||
{
|
||||
GRUB_FILE_FILTER_PUBKEY,
|
||||
GRUB_FILE_FILTER_VERIFY,
|
||||
GRUB_FILE_FILTER_GZIO,
|
||||
GRUB_FILE_FILTER_XZIO,
|
||||
GRUB_FILE_FILTER_LZOPIO,
|
||||
|
||||
@@ -35,6 +35,7 @@ void EXPORT_FUNC(grub_list_push) (grub_list_t *head, grub_list_t item);
|
||||
void EXPORT_FUNC(grub_list_remove) (grub_list_t item);
|
||||
|
||||
#define FOR_LIST_ELEMENTS(var, list) for ((var) = (list); (var); (var) = (var)->next)
|
||||
#define FOR_LIST_ELEMENTS_NEXT(var, list) for ((var) = (var)->next; (var); (var) = (var)->next)
|
||||
#define FOR_LIST_ELEMENTS_SAFE(var, nxt, list) for ((var) = (list), (nxt) = ((var) ? (var)->next : 0); (var); (var) = (nxt), ((nxt) = (var) ? (var)->next : 0))
|
||||
|
||||
static inline void *
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <grub/file.h>
|
||||
#include <grub/list.h>
|
||||
|
||||
enum grub_verify_flags
|
||||
{
|
||||
GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1,
|
||||
GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2,
|
||||
};
|
||||
|
||||
struct grub_file_verifier
|
||||
{
|
||||
struct grub_file_verifier *next;
|
||||
struct grub_file_verifier **prev;
|
||||
|
||||
const char *name;
|
||||
|
||||
/* Check if file needs to be verified and set up context. */
|
||||
/* init/read/fini is structured in the same way as hash interface. */
|
||||
grub_err_t (*init) (grub_file_t io, enum grub_file_type type,
|
||||
void **context, enum grub_verify_flags *verify_flags);
|
||||
/* Right now we pass the whole file in one call but it
|
||||
will change in the future. If you insist on single buffer we can
|
||||
you need to set GRUB_VERIFY_FLAGS_SINGLE_CHUNK in verify_flags.
|
||||
*/
|
||||
grub_err_t (*write) (void *context, void *buf, grub_size_t sz);
|
||||
grub_err_t (*fini) (void *context);
|
||||
void (*close) (void *context);
|
||||
};
|
||||
|
||||
extern struct grub_file_verifier *grub_file_verifiers;
|
||||
|
||||
static inline void
|
||||
grub_verifier_register (struct grub_file_verifier *ver)
|
||||
{
|
||||
grub_list_push (GRUB_AS_LIST_P (&grub_file_verifiers), GRUB_AS_LIST (ver));
|
||||
}
|
||||
|
||||
static inline void
|
||||
grub_verifier_unregister (struct grub_file_verifier *ver)
|
||||
{
|
||||
grub_list_remove (GRUB_AS_LIST (ver));
|
||||
}
|
||||
Reference in new issue
Block a user