]> git.proxmox.com Git - grub2.git/blame - grub-core/commands/verify.c
verifiers: File type for fine-grained signature-verification controlling
[grub2.git] / grub-core / commands / verify.c
CommitLineData
5e3b8dcb
VS
1/*
2 * GRUB -- GRand Unified Bootloader
1a78d573 3 * Copyright (C) 2013 Free Software Foundation, Inc.
5e3b8dcb
VS
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <grub/types.h>
20#include <grub/misc.h>
21#include <grub/mm.h>
22#include <grub/err.h>
23#include <grub/dl.h>
24#include <grub/file.h>
25#include <grub/command.h>
26#include <grub/crypto.h>
27#include <grub/i18n.h>
28#include <grub/gcrypt/gcrypt.h>
29#include <grub/pubkey.h>
30#include <grub/env.h>
31#include <grub/kernel.h>
0d711431 32#include <grub/extcmd.h>
5e3b8dcb
VS
33
34GRUB_MOD_LICENSE ("GPLv3+");
35
ebb3d958
AB
36struct grub_verified
37{
38 grub_file_t file;
39 void *buf;
40};
41typedef struct grub_verified *grub_verified_t;
42
0d711431
VS
43enum
44 {
45 OPTION_SKIP_SIG = 0
46 };
47
48static const struct grub_arg_option options[] =
49 {
50 {"skip-sig", 's', 0,
bfdfeb25 51 N_("Skip signature-checking of the public key file."), 0, ARG_TYPE_NONE},
0d711431
VS
52 {0, 0, 0, 0, 0, 0}
53 };
54
5e3b8dcb
VS
55static grub_err_t
56read_packet_header (grub_file_t sig, grub_uint8_t *out_type, grub_size_t *len)
57{
58 grub_uint8_t type;
59 grub_uint8_t l;
60 grub_uint16_t l16;
61 grub_uint32_t l32;
62
63 /* New format. */
64 switch (grub_file_read (sig, &type, sizeof (type)))
65 {
66 case 1:
67 break;
68 case 0:
69 {
70 *out_type = 0xff;
71 return 0;
72 }
73 default:
74 if (grub_errno)
75 return grub_errno;
f8e98fee
VS
76 /* TRANSLATORS: it's about GNUPG signatures. */
77 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
78 }
79
80 if (type == 0)
81 {
82 *out_type = 0xfe;
83 return 0;
84 }
85
86 if (!(type & 0x80))
f8e98fee 87 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
88 if (type & 0x40)
89 {
90 *out_type = (type & 0x3f);
91 if (grub_file_read (sig, &l, sizeof (l)) != 1)
f8e98fee 92 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
93 if (l < 192)
94 {
95 *len = l;
96 return 0;
97 }
98 if (l < 224)
99 {
52eab656 100 *len = (l - 192) << GRUB_CHAR_BIT;
5e3b8dcb 101 if (grub_file_read (sig, &l, sizeof (l)) != 1)
f8e98fee 102 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
103 *len |= l;
104 return 0;
105 }
106 if (l == 255)
107 {
108 if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
f8e98fee 109 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
110 *len = grub_be_to_cpu32 (l32);
111 return 0;
112 }
f8e98fee 113 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
114 }
115 *out_type = ((type >> 2) & 0xf);
116 switch (type & 0x3)
117 {
118 case 0:
119 if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
f8e98fee 120 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
121 *len = l;
122 return 0;
123 case 1:
124 if (grub_file_read (sig, &l16, sizeof (l16)) != sizeof (l16))
f8e98fee 125 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
126 *len = grub_be_to_cpu16 (l16);
127 return 0;
128 case 2:
129 if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
f8e98fee 130 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
131 *len = grub_be_to_cpu32 (l32);
132 return 0;
133 }
f8e98fee 134 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
135}
136
137struct signature_v4_header
138{
139 grub_uint8_t type;
140 grub_uint8_t pkeyalgo;
141 grub_uint8_t hash;
142 grub_uint16_t hashed_sub;
7e47e27b 143} GRUB_PACKED;
5e3b8dcb
VS
144
145const char *hashes[] = {
40f1c000
AB
146 [0x01] = "md5",
147 [0x02] = "sha1",
148 [0x03] = "ripemd160",
d7a6506e
VS
149 [0x08] = "sha256",
150 [0x09] = "sha384",
151 [0x0a] = "sha512",
152 [0x0b] = "sha224"
5e3b8dcb
VS
153};
154
1106c3f0
VS
155struct gcry_pk_spec *grub_crypto_pk_dsa;
156struct gcry_pk_spec *grub_crypto_pk_ecdsa;
157struct gcry_pk_spec *grub_crypto_pk_rsa;
158
159static int
160dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
161 const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
162static int
163rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
164 const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
165
5e3b8dcb
VS
166struct
167{
168 const char *name;
169 grub_size_t nmpisig;
170 grub_size_t nmpipub;
1106c3f0
VS
171 struct gcry_pk_spec **algo;
172 int (*pad) (gcry_mpi_t *hmpi, grub_uint8_t *hval,
173 const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
174 const char *module;
5e3b8dcb
VS
175} pkalgos[] =
176 {
1106c3f0
VS
177 [1] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
178 [3] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
179 [17] = { "dsa", 2, 4, &grub_crypto_pk_dsa, dsa_pad, "gcry_dsa" },
5e3b8dcb
VS
180 };
181
182struct grub_public_key
183{
184 struct grub_public_key *next;
185 struct grub_public_subkey *subkeys;
186};
187
188struct grub_public_subkey
189{
190 struct grub_public_subkey *next;
191 grub_uint8_t type;
192 grub_uint32_t fingerprint[5];
193 gcry_mpi_t mpis[10];
194};
195
196static void
197free_pk (struct grub_public_key *pk)
198{
199 struct grub_public_subkey *nsk, *sk;
200 for (sk = pk->subkeys; sk; sk = nsk)
201 {
7bbb60cf
VS
202 grub_size_t i;
203 for (i = 0; i < ARRAY_SIZE (sk->mpis); i++)
204 if (sk->mpis[i])
205 gcry_mpi_release (sk->mpis[i]);
5e3b8dcb
VS
206 nsk = sk->next;
207 grub_free (sk);
208 }
209 grub_free (pk);
210}
211
4f84ae0e
VS
212#define READBUF_SIZE 4096
213
5e3b8dcb
VS
214struct grub_public_key *
215grub_load_public_key (grub_file_t f)
216{
217 grub_err_t err;
218 struct grub_public_key *ret;
219 struct grub_public_subkey **last = 0;
4f84ae0e
VS
220 void *fingerprint_context = NULL;
221 grub_uint8_t *buffer = NULL;
5e3b8dcb
VS
222
223 ret = grub_zalloc (sizeof (*ret));
224 if (!ret)
1dcb2715
VS
225 {
226 grub_free (fingerprint_context);
227 return NULL;
228 }
5e3b8dcb 229
4f84ae0e
VS
230 buffer = grub_zalloc (READBUF_SIZE);
231 fingerprint_context = grub_zalloc (GRUB_MD_SHA1->contextsize);
232
233 if (!buffer || !fingerprint_context)
234 goto fail;
235
5e3b8dcb
VS
236 last = &ret->subkeys;
237
238 while (1)
239 {
240 grub_uint8_t type;
241 grub_size_t len;
242 grub_uint8_t v, pk;
243 grub_uint32_t creation_time;
244 grub_off_t pend;
245 struct grub_public_subkey *sk;
246 grub_size_t i;
247 grub_uint16_t len_be;
5e3b8dcb
VS
248
249 err = read_packet_header (f, &type, &len);
250
251 if (err)
252 goto fail;
253 if (type == 0xfe)
254 continue;
255 if (type == 0xff)
1dcb2715
VS
256 {
257 grub_free (fingerprint_context);
7bbb60cf 258 grub_free (buffer);
1dcb2715
VS
259 return ret;
260 }
5e3b8dcb
VS
261
262 grub_dprintf ("crypt", "len = %x\n", (int) len);
263
264 pend = grub_file_tell (f) + len;
265 if (type != 6 && type != 14
266 && type != 5 && type != 7)
267 {
268 grub_file_seek (f, pend);
269 continue;
270 }
271
272 if (grub_file_read (f, &v, sizeof (v)) != sizeof (v))
273 {
f8e98fee 274 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
275 goto fail;
276 }
277
278 grub_dprintf ("crypt", "v = %x\n", v);
279
280 if (v != 4)
281 {
f8e98fee 282 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
283 goto fail;
284 }
285 if (grub_file_read (f, &creation_time, sizeof (creation_time)) != sizeof (creation_time))
286 {
f8e98fee 287 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
288 goto fail;
289 }
290
291 grub_dprintf ("crypt", "time = %x\n", creation_time);
292
293 if (grub_file_read (f, &pk, sizeof (pk)) != sizeof (pk))
294 {
f8e98fee 295 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
296 goto fail;
297 }
298
299 grub_dprintf ("crypt", "pk = %x\n", pk);
300
301 if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
302 {
303 grub_file_seek (f, pend);
304 continue;
305 }
306
307 sk = grub_zalloc (sizeof (struct grub_public_subkey));
308 if (!sk)
309 goto fail;
310
37ba761b 311 grub_memset (fingerprint_context, 0, GRUB_MD_SHA1->contextsize);
5e3b8dcb
VS
312 GRUB_MD_SHA1->init (fingerprint_context);
313 GRUB_MD_SHA1->write (fingerprint_context, "\x99", 1);
314 len_be = grub_cpu_to_be16 (len);
315 GRUB_MD_SHA1->write (fingerprint_context, &len_be, sizeof (len_be));
316 GRUB_MD_SHA1->write (fingerprint_context, &v, sizeof (v));
317 GRUB_MD_SHA1->write (fingerprint_context, &creation_time, sizeof (creation_time));
318 GRUB_MD_SHA1->write (fingerprint_context, &pk, sizeof (pk));
319
320 for (i = 0; i < pkalgos[pk].nmpipub; i++)
321 {
322 grub_uint16_t l;
323 grub_size_t lb;
5e3b8dcb
VS
324 if (grub_file_read (f, &l, sizeof (l)) != sizeof (l))
325 {
f8e98fee 326 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
6c35ce72 327 break;
5e3b8dcb
VS
328 }
329
52eab656 330 lb = (grub_be_to_cpu16 (l) + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT;
4f84ae0e 331 if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
5e3b8dcb 332 {
f8e98fee 333 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
6c35ce72 334 break;
5e3b8dcb
VS
335 }
336 if (grub_file_read (f, buffer + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
337 {
f8e98fee 338 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
6c35ce72 339 break;
5e3b8dcb
VS
340 }
341 grub_memcpy (buffer, &l, sizeof (l));
342
343 GRUB_MD_SHA1->write (fingerprint_context, buffer, lb + sizeof (grub_uint16_t));
344
345 if (gcry_mpi_scan (&sk->mpis[i], GCRYMPI_FMT_PGP,
346 buffer, lb + sizeof (grub_uint16_t), 0))
347 {
f8e98fee 348 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
6c35ce72 349 break;
5e3b8dcb
VS
350 }
351 }
352
6c35ce72
AB
353 if (i < pkalgos[pk].nmpipub)
354 {
355 grub_free (sk);
356 goto fail;
357 }
358
5e3b8dcb
VS
359 GRUB_MD_SHA1->final (fingerprint_context);
360
361 grub_memcpy (sk->fingerprint, GRUB_MD_SHA1->read (fingerprint_context), 20);
362
363 *last = sk;
364 last = &sk->next;
365
5e3b8dcb
VS
366 grub_dprintf ("crypt", "actual pos: %x, expected: %x\n", (int)grub_file_tell (f), (int)pend);
367
368 grub_file_seek (f, pend);
369 }
370 fail:
371 free_pk (ret);
1dcb2715 372 grub_free (fingerprint_context);
4f84ae0e 373 grub_free (buffer);
5e3b8dcb
VS
374 return NULL;
375}
376
377struct grub_public_key *grub_pk_trusted;
378
379struct grub_public_subkey *
380grub_crypto_pk_locate_subkey (grub_uint64_t keyid, struct grub_public_key *pkey)
381{
382 struct grub_public_subkey *sk;
383 for (sk = pkey->subkeys; sk; sk = sk->next)
384 if (grub_memcmp (sk->fingerprint + 3, &keyid, 8) == 0)
385 return sk;
386 return 0;
387}
388
389struct grub_public_subkey *
390grub_crypto_pk_locate_subkey_in_trustdb (grub_uint64_t keyid)
391{
392 struct grub_public_key *pkey;
393 struct grub_public_subkey *sk;
394 for (pkey = grub_pk_trusted; pkey; pkey = pkey->next)
395 {
396 sk = grub_crypto_pk_locate_subkey (keyid, pkey);
397 if (sk)
398 return sk;
399 }
400 return 0;
401}
402
1106c3f0
VS
403
404static int
405dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
406 const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
407{
408 unsigned nbits = gcry_mpi_get_nbits (sk->mpis[1]);
409 grub_dprintf ("crypt", "must be %u bits got %d bits\n", nbits,
410 (int)(8 * hash->mdlen));
411 return gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, hval,
412 nbits / 8 < (unsigned) hash->mdlen ? nbits / 8
413 : (unsigned) hash->mdlen, 0);
414}
415
416static int
417rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
418 const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
419{
420 grub_size_t tlen, emlen, fflen;
421 grub_uint8_t *em, *emptr;
422 unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
423 int ret;
424 tlen = hash->mdlen + hash->asnlen;
425 emlen = (nbits + 7) / 8;
426 if (emlen < tlen + 11)
427 return 1;
428
429 em = grub_malloc (emlen);
430 if (!em)
431 return 1;
432
433 em[0] = 0x00;
434 em[1] = 0x01;
435 fflen = emlen - tlen - 3;
436 for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
437 *emptr = 0xff;
438 *emptr++ = 0x00;
439 grub_memcpy (emptr, hash->asnoid, hash->asnlen);
440 emptr += hash->asnlen;
441 grub_memcpy (emptr, hval, hash->mdlen);
442
443 ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
444 grub_free (em);
445 return ret;
446}
447
1a78d573
VS
448static grub_err_t
449grub_verify_signature_real (char *buf, grub_size_t size,
450 grub_file_t f, grub_file_t sig,
451 struct grub_public_key *pkey)
5e3b8dcb
VS
452{
453 grub_size_t len;
454 grub_uint8_t v;
455 grub_uint8_t h;
456 grub_uint8_t t;
457 grub_uint8_t pk;
458 const gcry_md_spec_t *hash;
459 struct signature_v4_header v4;
460 grub_err_t err;
461 grub_size_t i;
462 gcry_mpi_t mpis[10];
ed07b7e1 463 grub_uint8_t type = 0;
5e3b8dcb
VS
464
465 err = read_packet_header (sig, &type, &len);
466 if (err)
467 return err;
468
469 if (type != 0x2)
f8e98fee 470 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
471
472 if (grub_file_read (sig, &v, sizeof (v)) != sizeof (v))
f8e98fee 473 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
474
475 if (v != 4)
f8e98fee 476 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
477
478 if (grub_file_read (sig, &v4, sizeof (v4)) != sizeof (v4))
f8e98fee 479 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
480
481 h = v4.hash;
482 t = v4.type;
483 pk = v4.pkeyalgo;
484
485 if (t != 0)
f8e98fee 486 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
487
488 if (h >= ARRAY_SIZE (hashes) || hashes[h] == NULL)
489 return grub_error (GRUB_ERR_BAD_SIGNATURE, "unknown hash");
490
491 if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
f8e98fee 492 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
5e3b8dcb
VS
493
494 hash = grub_crypto_lookup_md_by_name (hashes[h]);
495 if (!hash)
496 return grub_error (GRUB_ERR_BAD_SIGNATURE, "hash `%s' not loaded", hashes[h]);
497
498 grub_dprintf ("crypt", "alive\n");
499
500 {
1dcb2715 501 void *context = NULL;
5e3b8dcb
VS
502 unsigned char *hval;
503 grub_ssize_t rem = grub_be_to_cpu16 (v4.hashed_sub);
504 grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6);
505 grub_uint8_t s;
506 grub_uint16_t unhashed_sub;
507 grub_ssize_t r;
508 grub_uint8_t hash_start[2];
509 gcry_mpi_t hmpi;
510 grub_uint64_t keyid = 0;
511 struct grub_public_subkey *sk;
4f84ae0e 512 grub_uint8_t *readbuf = NULL;
5e3b8dcb 513
1dcb2715 514 context = grub_zalloc (hash->contextsize);
4f84ae0e
VS
515 readbuf = grub_zalloc (READBUF_SIZE);
516 if (!context || !readbuf)
517 goto fail;
1dcb2715 518
5e3b8dcb 519 hash->init (context);
1a78d573
VS
520 if (buf)
521 hash->write (context, buf, size);
522 else
523 while (1)
524 {
4f84ae0e 525 r = grub_file_read (f, readbuf, READBUF_SIZE);
1a78d573 526 if (r < 0)
1dcb2715 527 goto fail;
1a78d573
VS
528 if (r == 0)
529 break;
530 hash->write (context, readbuf, r);
531 }
5e3b8dcb
VS
532
533 hash->write (context, &v, sizeof (v));
534 hash->write (context, &v4, sizeof (v4));
535 while (rem)
536 {
4f84ae0e
VS
537 r = grub_file_read (sig, readbuf,
538 rem < READBUF_SIZE ? rem : READBUF_SIZE);
5e3b8dcb 539 if (r < 0)
1dcb2715 540 goto fail;
5e3b8dcb
VS
541 if (r == 0)
542 break;
543 hash->write (context, readbuf, r);
544 rem -= r;
545 }
546 hash->write (context, &v, sizeof (v));
547 s = 0xff;
548 hash->write (context, &s, sizeof (s));
549 hash->write (context, &headlen, sizeof (headlen));
550 r = grub_file_read (sig, &unhashed_sub, sizeof (unhashed_sub));
551 if (r != sizeof (unhashed_sub))
1dcb2715 552 goto fail;
5e3b8dcb 553 {
5e3b8dcb
VS
554 grub_uint8_t *ptr;
555 grub_uint32_t l;
556 rem = grub_be_to_cpu16 (unhashed_sub);
4f84ae0e 557 if (rem > READBUF_SIZE)
1dcb2715 558 goto fail;
5e3b8dcb
VS
559 r = grub_file_read (sig, readbuf, rem);
560 if (r != rem)
1dcb2715 561 goto fail;
5e3b8dcb
VS
562 for (ptr = readbuf; ptr < readbuf + rem; ptr += l)
563 {
564 if (*ptr < 192)
565 l = *ptr++;
566 else if (*ptr < 255)
567 {
568 if (ptr + 1 >= readbuf + rem)
569 break;
52eab656 570 l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192;
5e3b8dcb
VS
571 ptr += 2;
572 }
573 else
574 {
575 if (ptr + 5 >= readbuf + rem)
576 break;
577 l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1));
578 ptr += 5;
579 }
580 if (*ptr == 0x10 && l >= 8)
581 keyid = grub_get_unaligned64 (ptr + 1);
582 }
583 }
584
585 hash->final (context);
586
587 grub_dprintf ("crypt", "alive\n");
588
589 hval = hash->read (context);
590
591 if (grub_file_read (sig, hash_start, sizeof (hash_start)) != sizeof (hash_start))
1dcb2715 592 goto fail;
5e3b8dcb 593 if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
1dcb2715 594 goto fail;
5e3b8dcb
VS
595
596 grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (sig));
597
598 for (i = 0; i < pkalgos[pk].nmpisig; i++)
599 {
600 grub_uint16_t l;
601 grub_size_t lb;
5e3b8dcb
VS
602 grub_dprintf ("crypt", "alive\n");
603 if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
1dcb2715 604 goto fail;
5e3b8dcb
VS
605 grub_dprintf ("crypt", "alive\n");
606 lb = (grub_be_to_cpu16 (l) + 7) / 8;
607 grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l));
4f84ae0e 608 if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
1dcb2715 609 goto fail;
5e3b8dcb 610 grub_dprintf ("crypt", "alive\n");
4f84ae0e 611 if (grub_file_read (sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
1dcb2715 612 goto fail;
5e3b8dcb 613 grub_dprintf ("crypt", "alive\n");
4f84ae0e 614 grub_memcpy (readbuf, &l, sizeof (l));
5e3b8dcb
VS
615 grub_dprintf ("crypt", "alive\n");
616
617 if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
4f84ae0e 618 readbuf, lb + sizeof (grub_uint16_t), 0))
1dcb2715 619 goto fail;
5e3b8dcb
VS
620 grub_dprintf ("crypt", "alive\n");
621 }
622
623 if (pkey)
624 sk = grub_crypto_pk_locate_subkey (keyid, pkey);
625 else
626 sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid);
627 if (!sk)
1dcb2715
VS
628 {
629 /* TRANSLATORS: %08x is 32-bit key id. */
630 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"),
631 keyid);
632 goto fail;
633 }
5e3b8dcb 634
1106c3f0 635 if (pkalgos[pk].pad (&hmpi, hval, hash, sk))
1dcb2715
VS
636 goto fail;
637 if (!*pkalgos[pk].algo)
638 {
639 grub_dl_load (pkalgos[pk].module);
640 grub_errno = GRUB_ERR_NONE;
641 }
642
1106c3f0 643 if (!*pkalgos[pk].algo)
1dcb2715
VS
644 {
645 grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"),
646 pkalgos[pk].module);
647 goto fail;
648 }
1106c3f0 649 if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0))
1dcb2715
VS
650 goto fail;
651
7bbb60cf
VS
652 grub_free (context);
653 grub_free (readbuf);
654
1dcb2715
VS
655 return GRUB_ERR_NONE;
656
657 fail:
658 grub_free (context);
4f84ae0e 659 grub_free (readbuf);
1dcb2715 660 if (!grub_errno)
f8e98fee 661 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
1dcb2715 662 return grub_errno;
5e3b8dcb 663 }
5e3b8dcb
VS
664}
665
1a78d573
VS
666grub_err_t
667grub_verify_signature (grub_file_t f, grub_file_t sig,
668 struct grub_public_key *pkey)
669{
670 return grub_verify_signature_real (0, 0, f, sig, pkey);
671}
672
5e3b8dcb 673static grub_err_t
0d711431
VS
674grub_cmd_trust (grub_extcmd_context_t ctxt,
675 int argc, char **args)
5e3b8dcb
VS
676{
677 grub_file_t pkf;
678 struct grub_public_key *pk = NULL;
679
680 if (argc < 1)
f8e98fee 681 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
5e3b8dcb 682
ca0a4f68
VS
683 pkf = grub_file_open (args[0],
684 GRUB_FILE_TYPE_PUBLIC_KEY_TRUST
685 | GRUB_FILE_TYPE_NO_DECOMPRESS
686 | (ctxt->state[OPTION_SKIP_SIG].set
687 ? GRUB_FILE_TYPE_SKIP_SIGNATURE
688 : GRUB_FILE_TYPE_NONE));
5e3b8dcb
VS
689 if (!pkf)
690 return grub_errno;
691 pk = grub_load_public_key (pkf);
692 if (!pk)
693 {
694 grub_file_close (pkf);
695 return grub_errno;
696 }
697 grub_file_close (pkf);
698
699 pk->next = grub_pk_trusted;
700 grub_pk_trusted = pk;
701
702 return GRUB_ERR_NONE;
703}
704
adcc6020
VS
705static grub_err_t
706grub_cmd_list (grub_command_t cmd __attribute__ ((unused)),
707 int argc __attribute__ ((unused)),
708 char **args __attribute__ ((unused)))
709{
710 struct grub_public_key *pk = NULL;
711 struct grub_public_subkey *sk = NULL;
712
713 for (pk = grub_pk_trusted; pk; pk = pk->next)
714 for (sk = pk->subkeys; sk; sk = sk->next)
715 {
716 unsigned i;
717 for (i = 0; i < 20; i += 2)
718 grub_printf ("%02x%02x ", ((grub_uint8_t *) sk->fingerprint)[i],
719 ((grub_uint8_t *) sk->fingerprint)[i + 1]);
720 grub_printf ("\n");
721 }
722
723 return GRUB_ERR_NONE;
724}
725
5e3b8dcb
VS
726static grub_err_t
727grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)),
728 int argc, char **args)
729{
730 grub_uint32_t keyid, keyid_be;
731 struct grub_public_key **pkey;
732 struct grub_public_subkey *sk;
733
734 if (argc < 1)
f8e98fee 735 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
5e3b8dcb
VS
736 keyid = grub_strtoull (args[0], 0, 16);
737 if (grub_errno)
738 return grub_errno;
739 keyid_be = grub_cpu_to_be32 (keyid);
740
741 for (pkey = &grub_pk_trusted; *pkey; pkey = &((*pkey)->next))
742 {
743 struct grub_public_key *next;
744 for (sk = (*pkey)->subkeys; sk; sk = sk->next)
745 if (grub_memcmp (sk->fingerprint + 4, &keyid_be, 4) == 0)
746 break;
747 if (!sk)
748 continue;
749 next = (*pkey)->next;
750 free_pk (*pkey);
751 *pkey = next;
752 return GRUB_ERR_NONE;
753 }
f8e98fee
VS
754 /* TRANSLATORS: %08x is 32-bit key id. */
755 return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), keyid);
5e3b8dcb
VS
756}
757
758static grub_err_t
0d711431 759grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
5e3b8dcb
VS
760 int argc, char **args)
761{
7bbb60cf
VS
762 grub_file_t f = NULL, sig = NULL;
763 grub_err_t err = GRUB_ERR_NONE;
5e3b8dcb
VS
764 struct grub_public_key *pk = NULL;
765
766 grub_dprintf ("crypt", "alive\n");
767
768 if (argc < 2)
f8e98fee 769 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
5e3b8dcb
VS
770
771 grub_dprintf ("crypt", "alive\n");
772
773 if (argc > 2)
774 {
775 grub_file_t pkf;
ca0a4f68
VS
776 pkf = grub_file_open (args[2],
777 GRUB_FILE_TYPE_PUBLIC_KEY
778 | GRUB_FILE_TYPE_NO_DECOMPRESS
779 | (ctxt->state[OPTION_SKIP_SIG].set
780 ? GRUB_FILE_TYPE_SKIP_SIGNATURE
781 : GRUB_FILE_TYPE_NONE));
5e3b8dcb
VS
782 if (!pkf)
783 return grub_errno;
784 pk = grub_load_public_key (pkf);
785 if (!pk)
786 {
787 grub_file_close (pkf);
788 return grub_errno;
789 }
790 grub_file_close (pkf);
791 }
792
ca0a4f68 793 f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
5e3b8dcb 794 if (!f)
7bbb60cf
VS
795 {
796 err = grub_errno;
797 goto fail;
798 }
5e3b8dcb 799
ca0a4f68
VS
800 sig = grub_file_open (args[1],
801 GRUB_FILE_TYPE_SIGNATURE
802 | GRUB_FILE_TYPE_NO_DECOMPRESS);
5e3b8dcb
VS
803 if (!sig)
804 {
7bbb60cf
VS
805 err = grub_errno;
806 goto fail;
5e3b8dcb
VS
807 }
808
809 err = grub_verify_signature (f, sig, pk);
7bbb60cf
VS
810 fail:
811 if (sig)
812 grub_file_close (sig);
813 if (f)
814 grub_file_close (f);
815 if (pk)
816 free_pk (pk);
5e3b8dcb
VS
817 return err;
818}
819
820static int sec = 0;
821
ebb3d958
AB
822static void
823verified_free (grub_verified_t verified)
824{
825 if (verified)
826 {
827 grub_free (verified->buf);
828 grub_free (verified);
829 }
830}
831
1a78d573
VS
832static grub_ssize_t
833verified_read (struct grub_file *file, char *buf, grub_size_t len)
834{
ebb3d958
AB
835 grub_verified_t verified = file->data;
836
837 grub_memcpy (buf, (char *) verified->buf + file->offset, len);
1a78d573
VS
838 return len;
839}
840
841static grub_err_t
842verified_close (struct grub_file *file)
843{
ebb3d958
AB
844 grub_verified_t verified = file->data;
845
846 grub_file_close (verified->file);
847 verified_free (verified);
1a78d573 848 file->data = 0;
ebb3d958
AB
849
850 /* device and name are freed by parent */
851 file->device = 0;
852 file->name = 0;
853
854 return grub_errno;
1a78d573
VS
855}
856
857struct grub_fs verified_fs =
858{
859 .name = "verified_read",
860 .read = verified_read,
861 .close = verified_close
862};
863
5e3b8dcb 864static grub_file_t
ca0a4f68 865grub_pubkey_open (grub_file_t io, enum grub_file_type type)
5e3b8dcb
VS
866{
867 grub_file_t sig;
868 char *fsuf, *ptr;
869 grub_err_t err;
1a78d573 870 grub_file_t ret;
ebb3d958 871 grub_verified_t verified;
5e3b8dcb 872
ca0a4f68
VS
873 if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE
874 || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE
875 || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE))
876 return io;
877
5e3b8dcb
VS
878 if (!sec)
879 return io;
2c2c5c72
VS
880 if (io->device->disk &&
881 (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID
882 || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID))
1a78d573 883 return io;
ca0a4f68 884 fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
5e3b8dcb
VS
885 if (!fsuf)
886 return NULL;
ca0a4f68 887 ptr = grub_stpcpy (fsuf, io->name);
5e3b8dcb
VS
888 grub_memcpy (ptr, ".sig", sizeof (".sig"));
889
ca0a4f68 890 sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE);
5e3b8dcb
VS
891 grub_free (fsuf);
892 if (!sig)
893 return NULL;
894
1a78d573
VS
895 ret = grub_malloc (sizeof (*ret));
896 if (!ret)
ebb3d958
AB
897 {
898 grub_file_close (sig);
899 return NULL;
900 }
1a78d573
VS
901 *ret = *io;
902
903 ret->fs = &verified_fs;
904 ret->not_easily_seekable = 0;
905 if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1))
906 {
907 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
908 "big file signature isn't implemented yet");
ebb3d958
AB
909 grub_file_close (sig);
910 grub_free (ret);
911 return NULL;
912 }
913 verified = grub_malloc (sizeof (*verified));
914 if (!verified)
915 {
916 grub_file_close (sig);
917 grub_free (ret);
1a78d573
VS
918 return NULL;
919 }
ebb3d958
AB
920 verified->buf = grub_malloc (ret->size);
921 if (!verified->buf)
1a78d573 922 {
ebb3d958 923 grub_file_close (sig);
ca0a4f68 924 verified_free (verified);
1a78d573
VS
925 grub_free (ret);
926 return NULL;
927 }
ebb3d958 928 if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size)
1a78d573
VS
929 {
930 if (!grub_errno)
931 grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
ca0a4f68 932 io->name);
ebb3d958
AB
933 grub_file_close (sig);
934 verified_free (verified);
935 grub_free (ret);
1a78d573
VS
936 return NULL;
937 }
938
ebb3d958 939 err = grub_verify_signature_real (verified->buf, ret->size, 0, sig, NULL);
5e3b8dcb
VS
940 grub_file_close (sig);
941 if (err)
ebb3d958
AB
942 {
943 verified_free (verified);
944 grub_free (ret);
945 return NULL;
946 }
947 verified->file = io;
948 ret->data = verified;
1a78d573 949 return ret;
5e3b8dcb
VS
950}
951
952static char *
953grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)),
954 const char *val)
955{
956 sec = (*val == '1') || (*val == 'e');
957 return grub_strdup (sec ? "enforce" : "no");
958}
959
960static grub_ssize_t
961pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
962{
963 grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
964 return len;
965}
966
967
968/* Filesystem descriptor. */
969struct grub_fs pseudo_fs =
970 {
971 .name = "pseudo",
972 .read = pseudo_read
973};
974
5e3b8dcb 975
0d711431
VS
976static grub_extcmd_t cmd, cmd_trust;
977static grub_command_t cmd_distrust, cmd_list;
5e3b8dcb
VS
978
979GRUB_MOD_INIT(verify)
980{
981 const char *val;
982 struct grub_module_header *header;
983
984 val = grub_env_get ("check_signatures");
985 if (val && (val[0] == '1' || val[0] == 'e'))
986 sec = 1;
987 else
988 sec = 0;
989
990 grub_file_filter_register (GRUB_FILE_FILTER_PUBKEY, grub_pubkey_open);
991
992 grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec);
993 grub_env_export ("check_signatures");
994
995 grub_pk_trusted = 0;
996 FOR_MODULES (header)
997 {
998 struct grub_file pseudo_file;
999 struct grub_public_key *pk = NULL;
1000
1001 grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
1002
1003 /* Not an ELF module, skip. */
1004 if (header->type != OBJ_TYPE_PUBKEY)
1005 continue;
1006
1007 pseudo_file.fs = &pseudo_fs;
1008 pseudo_file.size = (header->size - sizeof (struct grub_module_header));
1009 pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
1010
1011 pk = grub_load_public_key (&pseudo_file);
1012 if (!pk)
1013 grub_fatal ("error loading initial key: %s\n", grub_errmsg);
1014
1015 pk->next = grub_pk_trusted;
1016 grub_pk_trusted = pk;
1017 }
1018
1019 if (!val)
1020 grub_env_set ("check_signatures", grub_pk_trusted ? "enforce" : "no");
1021
0d711431
VS
1022 cmd = grub_register_extcmd ("verify_detached", grub_cmd_verify_signature, 0,
1023 N_("[-s|--skip-sig] FILE SIGNATURE_FILE [PUBKEY_FILE]"),
1024 N_("Verify detached signature."),
1025 options);
1026 cmd_trust = grub_register_extcmd ("trust", grub_cmd_trust, 0,
1027 N_("[-s|--skip-sig] PUBKEY_FILE"),
496a6b30 1028 N_("Add PUBKEY_FILE to trusted keys."),
0d711431 1029 options);
adcc6020
VS
1030 cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
1031 0,
bfdfeb25 1032 N_("Show the list of trusted keys."));
5e3b8dcb 1033 cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust,
f8e98fee 1034 N_("PUBKEY_ID"),
496a6b30 1035 N_("Remove PUBKEY_ID from trusted keys."));
5e3b8dcb
VS
1036}
1037
1038GRUB_MOD_FINI(verify)
1039{
1040 grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY);
0d711431
VS
1041 grub_unregister_extcmd (cmd);
1042 grub_unregister_extcmd (cmd_trust);
adcc6020 1043 grub_unregister_command (cmd_list);
5e3b8dcb
VS
1044 grub_unregister_command (cmd_distrust);
1045}