verify.c 25.4 KB
Newer Older
1 2
/*
 *  GRUB  --  GRand Unified Bootloader
3
 *  Copyright (C) 2013  Free Software Foundation, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 *  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>
32
#include <grub/extcmd.h>
33 34 35

GRUB_MOD_LICENSE ("GPLv3+");

36 37 38 39 40 41 42
struct grub_verified
{
  grub_file_t file;
  void *buf;
};
typedef struct grub_verified *grub_verified_t;

43 44 45 46 47 48 49 50
enum
  {
    OPTION_SKIP_SIG = 0
  };

static const struct grub_arg_option options[] =
  {
    {"skip-sig", 's', 0,
51
     N_("Skip signature-checking of the public key file."), 0, ARG_TYPE_NONE},
52 53 54
    {0, 0, 0, 0, 0, 0}
  };

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
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;
76 77
      /* TRANSLATORS: it's about GNUPG signatures.  */
      return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
78 79 80 81 82 83 84 85 86
    }

  if (type == 0)
    {
      *out_type = 0xfe;
      return 0;      
    }

  if (!(type & 0x80))
87
    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
88 89 90 91
  if (type & 0x40)
    {
      *out_type = (type & 0x3f);
      if (grub_file_read (sig, &l, sizeof (l)) != 1)
92
	return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
93 94 95 96 97 98 99
      if (l < 192)
	{
	  *len = l;
	  return 0;
	}
      if (l < 224)
	{
100
	  *len = (l - 192) << GRUB_CHAR_BIT;
101
	  if (grub_file_read (sig, &l, sizeof (l)) != 1)
102
	    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
103 104 105 106 107 108
	  *len |= l;
	  return 0;
	}
      if (l == 255)
	{
	  if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
109
	    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
110 111 112
	  *len = grub_be_to_cpu32 (l32);
	  return 0;
	}
113
      return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
114 115 116 117 118 119
    }
  *out_type = ((type >> 2) & 0xf);
  switch (type & 0x3)
    {
    case 0:
      if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
120
	return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
121 122 123 124
      *len = l;
      return 0;
    case 1:
      if (grub_file_read (sig, &l16, sizeof (l16)) != sizeof (l16))
125
	return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
126 127 128 129
      *len = grub_be_to_cpu16 (l16);
      return 0;
    case 2:
      if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
130
	return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
131 132 133
      *len = grub_be_to_cpu32 (l32);
      return 0;
    }
134
  return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
135 136 137 138 139 140 141 142
}

struct signature_v4_header
{
  grub_uint8_t type;
  grub_uint8_t pkeyalgo;
  grub_uint8_t hash;
  grub_uint16_t hashed_sub;
143
} GRUB_PACKED;
144 145

const char *hashes[] = {
146 147 148
  [0x01] = "md5",
  [0x02] = "sha1",
  [0x03] = "ripemd160",
149 150 151 152
  [0x08] = "sha256",
  [0x09] = "sha384",
  [0x0a] = "sha512",
  [0x0b] = "sha224"
153 154
};

155 156 157 158 159 160 161 162 163 164 165
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);

166 167 168 169 170
struct
{
  const char *name;
  grub_size_t nmpisig;
  grub_size_t nmpipub;
171 172 173 174
  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;
175 176
} pkalgos[] = 
  {
177 178 179
    [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" },
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
  };

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)
    {
202 203 204 205
      grub_size_t i;
      for (i = 0; i < ARRAY_SIZE (sk->mpis); i++)
	if (sk->mpis[i])
	  gcry_mpi_release (sk->mpis[i]);
206 207 208 209 210 211
      nsk = sk->next;
      grub_free (sk);
    }
  grub_free (pk);
}

212 213
#define READBUF_SIZE 4096

214 215 216 217 218 219
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;
220 221
  void *fingerprint_context = NULL;
  grub_uint8_t *buffer = NULL;
222 223 224

  ret = grub_zalloc (sizeof (*ret));
  if (!ret)
225 226 227 228
    {
      grub_free (fingerprint_context);
      return NULL;
    }
229

230 231 232 233 234 235
  buffer = grub_zalloc (READBUF_SIZE);
  fingerprint_context = grub_zalloc (GRUB_MD_SHA1->contextsize);

  if (!buffer || !fingerprint_context)
    goto fail;

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
  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)
256 257
	{
	  grub_free (fingerprint_context);
258
	  grub_free (buffer);
259 260
	  return ret;
	}
261 262 263 264 265 266 267 268 269 270 271 272 273

      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))
	{
274
	  grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
275 276 277 278 279 280 281
	  goto fail;
	}

      grub_dprintf ("crypt", "v = %x\n", v);

      if (v != 4)
	{
282
	  grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
283 284 285 286
	  goto fail;
	}
      if (grub_file_read (f, &creation_time, sizeof (creation_time)) != sizeof (creation_time))
	{
287
	  grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
288 289 290 291 292 293 294
	  goto fail;
	}

      grub_dprintf ("crypt", "time = %x\n", creation_time);

      if (grub_file_read (f, &pk, sizeof (pk)) != sizeof (pk))
	{
295
	  grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	  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;

311
      grub_memset (fingerprint_context, 0, GRUB_MD_SHA1->contextsize);
312 313 314 315 316 317 318 319 320 321 322 323 324 325
      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))
	    {
326
	      grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
327
	      break;
328 329
	    }
	  
330
	  lb = (grub_be_to_cpu16 (l) + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT;
331
	  if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
332
	    {
333
	      grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
334
	      break;
335 336 337
	    }
	  if (grub_file_read (f, buffer + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
	    {
338
	      grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
339
	      break;
340 341 342 343 344 345 346 347
	    }
	  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))
	    {
348
	      grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
349
	      break;
350 351 352
	    }
	}

353 354 355 356 357 358
      if (i < pkalgos[pk].nmpipub)
	{
	  grub_free (sk);
	  goto fail;
	}

359 360 361 362 363 364 365 366 367 368 369 370 371
      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);
372
  grub_free (fingerprint_context);
373
  grub_free (buffer);
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
  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;
}

403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

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;
}

448 449 450 451
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)
452 453 454 455 456 457 458 459 460 461 462
{
  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];
463
  grub_uint8_t type = 0;
464 465 466 467 468 469

  err = read_packet_header (sig, &type, &len);
  if (err)
    return err;

  if (type != 0x2)
470
    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
471 472

  if (grub_file_read (sig, &v, sizeof (v)) != sizeof (v))
473
    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
474 475

  if (v != 4)
476
    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
477 478

  if (grub_file_read (sig, &v4, sizeof (v4)) != sizeof (v4))
479
    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
480 481 482 483 484 485

  h = v4.hash;
  t = v4.type;
  pk = v4.pkeyalgo;
  
  if (t != 0)
486
    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
487 488 489 490 491

  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)
492
    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
493 494 495 496 497 498 499 500

  hash = grub_crypto_lookup_md_by_name (hashes[h]);
  if (!hash)
    return grub_error (GRUB_ERR_BAD_SIGNATURE, "hash `%s' not loaded", hashes[h]);

  grub_dprintf ("crypt", "alive\n");

  {
501
    void *context = NULL;
502 503 504 505 506 507 508 509 510 511
    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;
512
    grub_uint8_t *readbuf = NULL;
513

514
    context = grub_zalloc (hash->contextsize);
515 516 517
    readbuf = grub_zalloc (READBUF_SIZE);
    if (!context || !readbuf)
      goto fail;
518

519
    hash->init (context);
520 521 522 523 524
    if (buf)
      hash->write (context, buf, size);
    else 
      while (1)
	{
525
	  r = grub_file_read (f, readbuf, READBUF_SIZE);
526
	  if (r < 0)
527
	    goto fail;
528 529 530 531
	  if (r == 0)
	    break;
	  hash->write (context, readbuf, r);
	}
532 533 534 535 536

    hash->write (context, &v, sizeof (v));
    hash->write (context, &v4, sizeof (v4));
    while (rem)
      {
537 538
	r = grub_file_read (sig, readbuf,
			    rem < READBUF_SIZE ? rem : READBUF_SIZE);
539
	if (r < 0)
540
	  goto fail;
541 542 543 544 545 546 547 548 549 550 551
	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))
552
      goto fail;
553 554 555 556
    {
      grub_uint8_t *ptr;
      grub_uint32_t l;
      rem = grub_be_to_cpu16 (unhashed_sub);
557
      if (rem > READBUF_SIZE)
558
	goto fail;
559 560
      r = grub_file_read (sig, readbuf, rem);
      if (r != rem)
561
	goto fail;
562 563 564 565 566 567 568 569
      for (ptr = readbuf; ptr < readbuf + rem; ptr += l)
	{
	  if (*ptr < 192)
	    l = *ptr++;
	  else if (*ptr < 255)
	    {
	      if (ptr + 1 >= readbuf + rem)
		break;
570
	      l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192;
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
	      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);
	}
    }

    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))
592
      goto fail;
593
    if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
594
      goto fail;
595 596 597 598 599 600 601 602 603

    grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (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 (sig, &l, sizeof (l)) != sizeof (l))
604
	  goto fail;
605 606 607
	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));
608
	if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
609
	  goto fail;
610
	grub_dprintf ("crypt", "alive\n");
611
	if (grub_file_read (sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
612
	  goto fail;
613
	grub_dprintf ("crypt", "alive\n");
614
	grub_memcpy (readbuf, &l, sizeof (l));
615 616 617
	grub_dprintf ("crypt", "alive\n");

	if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
618
			   readbuf, lb + sizeof (grub_uint16_t), 0))
619
	  goto fail;
620 621 622 623 624 625 626 627
	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)
628 629 630 631 632 633
      {
	/* TRANSLATORS: %08x is 32-bit key id.  */
	grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"),
		    keyid);
	goto fail;
      }
634

635
    if (pkalgos[pk].pad (&hmpi, hval, hash, sk))
636 637 638 639 640 641 642
      goto fail;
    if (!*pkalgos[pk].algo)
      {
	grub_dl_load (pkalgos[pk].module);
	grub_errno = GRUB_ERR_NONE;
      }

643
    if (!*pkalgos[pk].algo)
644 645 646 647 648
      {
	grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"),
		    pkalgos[pk].module);
	goto fail;
      }
649
    if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0))
650 651
      goto fail;

652 653 654
    grub_free (context);
    grub_free (readbuf);

655 656 657 658
    return GRUB_ERR_NONE;

  fail:
    grub_free (context);
659
    grub_free (readbuf);
660
    if (!grub_errno)
661
      return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
662
    return grub_errno;
663 664 665
  }
}

666 667 668 669 670 671 672
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);
}

673
static grub_err_t
674 675
grub_cmd_trust (grub_extcmd_context_t ctxt,
		int argc, char **args)
676 677 678 679 680
{
  grub_file_t pkf;
  struct grub_public_key *pk = NULL;

  if (argc < 1)
681
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
682

683 684 685
  grub_file_filter_disable_compression ();
  if (ctxt->state[OPTION_SKIP_SIG].set)
    grub_file_filter_disable_pubkey ();
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
  pkf = grub_file_open (args[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;
}

703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
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;
}

724 725 726 727 728 729 730 731 732
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)
733
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
  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;
    }
752 753
  /* TRANSLATORS: %08x is 32-bit key id.  */
  return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), keyid);
754 755 756
}

static grub_err_t
757
grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
758 759
			   int argc, char **args)
{
760 761
  grub_file_t f = NULL, sig = NULL;
  grub_err_t err = GRUB_ERR_NONE;
762 763 764 765 766
  struct grub_public_key *pk = NULL;

  grub_dprintf ("crypt", "alive\n");

  if (argc < 2)
767
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
768 769 770 771 772 773

  grub_dprintf ("crypt", "alive\n");

  if (argc > 2)
    {
      grub_file_t pkf;
774 775 776
      grub_file_filter_disable_compression ();
      if (ctxt->state[OPTION_SKIP_SIG].set)
	grub_file_filter_disable_pubkey ();
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
      pkf = grub_file_open (args[2]);
      if (!pkf)
	return grub_errno;
      pk = grub_load_public_key (pkf);
      if (!pk)
	{
	  grub_file_close (pkf);
	  return grub_errno;
	}
      grub_file_close (pkf);
    }

  grub_file_filter_disable_all ();
  f = grub_file_open (args[0]);
  if (!f)
792 793 794 795
    {
      err = grub_errno;
      goto fail;
    }
796 797 798 799 800

  grub_file_filter_disable_all ();
  sig = grub_file_open (args[1]);
  if (!sig)
    {
801 802
      err = grub_errno;
      goto fail;
803 804 805
    }

  err = grub_verify_signature (f, sig, pk);
806 807 808 809 810 811 812
 fail:
  if (sig)
    grub_file_close (sig);
  if (f)
    grub_file_close (f);
  if (pk)
    free_pk (pk);
813 814 815 816 817
  return err;
}

static int sec = 0;

818 819 820 821 822 823 824 825 826 827
static void
verified_free (grub_verified_t verified)
{
  if (verified)
    {
      grub_free (verified->buf);
      grub_free (verified);
    }
}

828 829 830
static grub_ssize_t
verified_read (struct grub_file *file, char *buf, grub_size_t len)
{
831 832 833
  grub_verified_t verified = file->data;

  grub_memcpy (buf, (char *) verified->buf + file->offset, len);
834 835 836 837 838 839
  return len;
}

static grub_err_t
verified_close (struct grub_file *file)
{
840 841 842 843
  grub_verified_t verified = file->data;

  grub_file_close (verified->file);
  verified_free (verified);
844
  file->data = 0;
845 846 847 848 849 850

  /* device and name are freed by parent */
  file->device = 0;
  file->name = 0;

  return grub_errno;
851 852 853 854 855 856 857 858 859
}

struct grub_fs verified_fs =
{
  .name = "verified_read",
  .read = verified_read,
  .close = verified_close
};

860 861 862 863 864 865 866
static grub_file_t
grub_pubkey_open (grub_file_t io, const char *filename)
{
  grub_file_t sig;
  char *fsuf, *ptr;
  grub_err_t err;
  grub_file_filter_t curfilt[GRUB_FILE_FILTER_MAX];
867
  grub_file_t ret;
868
  grub_verified_t verified;
869 870 871

  if (!sec)
    return io;
872 873 874
  if (io->device->disk && 
      (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID
       || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID))
875
    return io;
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
  fsuf = grub_malloc (grub_strlen (filename) + sizeof (".sig"));
  if (!fsuf)
    return NULL;
  ptr = grub_stpcpy (fsuf, filename);
  grub_memcpy (ptr, ".sig", sizeof (".sig"));

  grub_memcpy (curfilt, grub_file_filters_enabled,
	       sizeof (curfilt));
  grub_file_filter_disable_all ();
  sig = grub_file_open (fsuf);
  grub_memcpy (grub_file_filters_enabled, curfilt,
	       sizeof (curfilt));
  grub_free (fsuf);
  if (!sig)
    return NULL;

892 893
  ret = grub_malloc (sizeof (*ret));
  if (!ret)
894 895 896 897
    {
      grub_file_close (sig);
      return NULL;
    }
898 899 900 901 902 903 904 905
  *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");
906 907 908 909 910 911 912 913 914
      grub_file_close (sig);
      grub_free (ret);
      return NULL;
    }
  verified = grub_malloc (sizeof (*verified));
  if (!verified)
    {
      grub_file_close (sig);
      grub_free (ret);
915 916
      return NULL;
    }
917 918
  verified->buf = grub_malloc (ret->size);
  if (!verified->buf)
919
    {
920 921
      grub_file_close (sig);
      grub_free (verified);
922 923 924
      grub_free (ret);
      return NULL;
    }
925
  if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size)
926 927 928 929
    {
      if (!grub_errno)
	grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
		    filename);
930 931 932
      grub_file_close (sig);
      verified_free (verified);
      grub_free (ret);
933 934 935
      return NULL;
    }

936
  err = grub_verify_signature_real (verified->buf, ret->size, 0, sig, NULL);
937 938
  grub_file_close (sig);
  if (err)
939 940 941 942 943 944 945
    {
      verified_free (verified);
      grub_free (ret);
      return NULL;
    }
  verified->file = io;
  ret->data = verified;
946
  return ret;
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
}

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
};


973 974
static grub_extcmd_t cmd, cmd_trust;
static grub_command_t cmd_distrust, cmd_list;
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018

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_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");

  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");

1019 1020 1021 1022 1023 1024
  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"),
1025
				     N_("Add PUBKEY_FILE to trusted keys."),
1026
				     options);
1027 1028
  cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
				    0,
1029
				    N_("Show the list of trusted keys."));
1030
  cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust,
1031
					N_("PUBKEY_ID"),
1032
					N_("Remove PUBKEY_ID from trusted keys."));
1033 1034 1035 1036 1037
}

GRUB_MOD_FINI(verify)
{
  grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY);
1038 1039
  grub_unregister_extcmd (cmd);
  grub_unregister_extcmd (cmd_trust);
1040
  grub_unregister_command (cmd_list);
1041 1042
  grub_unregister_command (cmd_distrust);
}