]>
Commit | Line | Data |
---|---|---|
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 | |
34 | GRUB_MOD_LICENSE ("GPLv3+"); | |
35 | ||
ebb3d958 AB |
36 | struct grub_verified |
37 | { | |
38 | grub_file_t file; | |
39 | void *buf; | |
40 | }; | |
41 | typedef struct grub_verified *grub_verified_t; | |
42 | ||
0d711431 VS |
43 | enum |
44 | { | |
45 | OPTION_SKIP_SIG = 0 | |
46 | }; | |
47 | ||
48 | static 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 |
55 | static grub_err_t |
56 | read_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 | ||
137 | struct 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 | |
145 | const 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 |
155 | struct gcry_pk_spec *grub_crypto_pk_dsa; |
156 | struct gcry_pk_spec *grub_crypto_pk_ecdsa; | |
157 | struct gcry_pk_spec *grub_crypto_pk_rsa; | |
158 | ||
159 | static int | |
160 | dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, | |
161 | const gcry_md_spec_t *hash, struct grub_public_subkey *sk); | |
162 | static int | |
163 | rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, | |
164 | const gcry_md_spec_t *hash, struct grub_public_subkey *sk); | |
165 | ||
5e3b8dcb VS |
166 | struct |
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 | ||
182 | struct grub_public_key | |
183 | { | |
184 | struct grub_public_key *next; | |
185 | struct grub_public_subkey *subkeys; | |
186 | }; | |
187 | ||
188 | struct 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 | ||
196 | static void | |
197 | free_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 |
214 | struct grub_public_key * |
215 | grub_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 | ||
377 | struct grub_public_key *grub_pk_trusted; | |
378 | ||
379 | struct grub_public_subkey * | |
380 | grub_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 | ||
389 | struct grub_public_subkey * | |
390 | grub_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 | |
404 | static int | |
405 | dsa_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 | ||
416 | static int | |
417 | rsa_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 |
448 | static grub_err_t |
449 | grub_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 |
666 | grub_err_t |
667 | grub_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 | 673 | static grub_err_t |
0d711431 VS |
674 | grub_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 |
705 | static grub_err_t |
706 | grub_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 |
726 | static grub_err_t |
727 | grub_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 | ||
758 | static grub_err_t | |
0d711431 | 759 | grub_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 | ||
820 | static int sec = 0; | |
821 | ||
ebb3d958 AB |
822 | static void |
823 | verified_free (grub_verified_t verified) | |
824 | { | |
825 | if (verified) | |
826 | { | |
827 | grub_free (verified->buf); | |
828 | grub_free (verified); | |
829 | } | |
830 | } | |
831 | ||
1a78d573 VS |
832 | static grub_ssize_t |
833 | verified_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 | ||
841 | static grub_err_t | |
842 | verified_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 | ||
857 | struct grub_fs verified_fs = | |
858 | { | |
859 | .name = "verified_read", | |
860 | .read = verified_read, | |
861 | .close = verified_close | |
862 | }; | |
863 | ||
5e3b8dcb | 864 | static grub_file_t |
ca0a4f68 | 865 | grub_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 | ||
952 | static char * | |
953 | grub_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 | ||
960 | static grub_ssize_t | |
961 | pseudo_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. */ | |
969 | struct grub_fs pseudo_fs = | |
970 | { | |
971 | .name = "pseudo", | |
972 | .read = pseudo_read | |
973 | }; | |
974 | ||
5e3b8dcb | 975 | |
0d711431 VS |
976 | static grub_extcmd_t cmd, cmd_trust; |
977 | static grub_command_t cmd_distrust, cmd_list; | |
5e3b8dcb VS |
978 | |
979 | GRUB_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 | ||
1038 | GRUB_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 | } |