2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/extcmd.h>
21 #include <grub/file.h>
22 #include <grub/disk.h>
24 #include <grub/misc.h>
25 #include <grub/crypto.h>
26 #include <grub/normal.h>
27 #include <grub/i18n.h>
29 GRUB_MOD_LICENSE ("GPLv3+");
31 static const struct grub_arg_option options
[] = {
32 {"hash", 'h', 0, N_("Specify hash to use."), N_("HASH"), ARG_TYPE_STRING
},
33 {"check", 'c', 0, N_("Check hashes of files with hash list FILE."),
34 N_("FILE"), ARG_TYPE_STRING
},
35 {"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIR"),
37 {"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0},
38 {"uncompress", 'u', 0, N_("Uncompress file before checksumming."), 0, 0},
42 static struct { const char *name
; const char *hashname
; } aliases
[] =
44 {"sha256sum", "sha256"},
45 {"sha512sum", "sha512"},
54 if (c
>= '0' && c
<= '9')
56 if (c
>= 'a' && c
<= 'f')
58 if (c
>= 'A' && c
<= 'F')
64 hash_file (grub_file_t file
, const gcry_md_spec_t
*hash
, void *result
)
67 grub_uint8_t
*readbuf
;
69 readbuf
= grub_malloc (BUF_SIZE
);
72 context
= grub_zalloc (hash
->contextsize
);
73 if (!readbuf
|| !context
)
80 r
= grub_file_read (file
, readbuf
, BUF_SIZE
);
85 hash
->write (context
, readbuf
, r
);
87 hash
->final (context
);
88 grub_memcpy (result
, hash
->read (context
), hash
->mdlen
);
102 check_list (const gcry_md_spec_t
*hash
, const char *hashfilename
,
103 const char *prefix
, int keep
, int uncompress
)
105 grub_file_t hashlist
, file
;
107 grub_uint8_t expected
[GRUB_CRYPTO_MAX_MDLEN
];
108 grub_uint8_t actual
[GRUB_CRYPTO_MAX_MDLEN
];
111 unsigned unread
= 0, mismatch
= 0;
113 if (hash
->mdlen
> GRUB_CRYPTO_MAX_MDLEN
)
114 return grub_error (GRUB_ERR_BUG
, "mdlen is too long");
116 hashlist
= grub_file_open (hashfilename
);
120 while (grub_free (buf
), (buf
= grub_file_getline (hashlist
)))
123 while (grub_isspace (p
[0]))
125 for (i
= 0; i
< hash
->mdlen
; i
++)
128 high
= hextoval (*p
++);
129 low
= hextoval (*p
++);
130 if (high
< 0 || low
< 0)
131 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "invalid hash list");
132 expected
[i
] = (high
<< 4) | low
;
134 if ((p
[0] != ' ' && p
[0] != '\t') || (p
[1] != ' ' && p
[1] != '\t'))
135 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "invalid hash list");
141 filename
= grub_xasprintf ("%s/%s", prefix
, p
);
145 grub_file_filter_disable_compression ();
146 file
= grub_file_open (filename
);
147 grub_free (filename
);
152 grub_file_filter_disable_compression ();
153 file
= grub_file_open (p
);
157 grub_file_close (hashlist
);
161 err
= hash_file (file
, hash
, actual
);
162 grub_file_close (file
);
165 grub_printf_ (N_("%s: READ ERROR\n"), p
);
168 grub_file_close (hashlist
);
173 grub_errno
= GRUB_ERR_NONE
;
177 if (grub_crypto_memcmp (expected
, actual
, hash
->mdlen
) != 0)
179 grub_printf_ (N_("%s: HASH MISMATCH\n"), p
);
182 grub_file_close (hashlist
);
184 return grub_error (GRUB_ERR_TEST_FAILURE
,
185 "hash of '%s' mismatches", p
);
190 grub_printf_ (N_("%s: OK\n"), p
);
192 if (mismatch
|| unread
)
193 return grub_error (GRUB_ERR_TEST_FAILURE
,
194 "%d files couldn't be read and hash "
195 "of %d files mismatches", unread
, mismatch
);
196 return GRUB_ERR_NONE
;
200 grub_cmd_hashsum (struct grub_extcmd_context
*ctxt
,
201 int argc
, char **args
)
203 struct grub_arg_list
*state
= ctxt
->state
;
204 const char *hashname
= NULL
;
205 const char *prefix
= NULL
;
206 const gcry_md_spec_t
*hash
;
208 int keep
= state
[3].set
;
209 int uncompress
= state
[4].set
;
212 for (i
= 0; i
< ARRAY_SIZE (aliases
); i
++)
213 if (grub_strcmp (ctxt
->extcmd
->cmd
->name
, aliases
[i
].name
) == 0)
214 hashname
= aliases
[i
].hashname
;
216 hashname
= state
[0].arg
;
219 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "no hash specified");
221 hash
= grub_crypto_lookup_md_by_name (hashname
);
223 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "unknown hash");
225 if (hash
->mdlen
> GRUB_CRYPTO_MAX_MDLEN
)
226 return grub_error (GRUB_ERR_BUG
, "mdlen is too long");
229 prefix
= state
[2].arg
;
234 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
235 "--check is incompatible with file list");
236 return check_list (hash
, state
[1].arg
, prefix
, keep
, uncompress
);
239 for (i
= 0; i
< (unsigned) argc
; i
++)
241 GRUB_PROPERLY_ALIGNED_ARRAY (result
, GRUB_CRYPTO_MAX_MDLEN
);
246 grub_file_filter_disable_compression ();
247 file
= grub_file_open (args
[i
]);
253 grub_errno
= GRUB_ERR_NONE
;
257 err
= hash_file (file
, hash
, result
);
258 grub_file_close (file
);
264 grub_errno
= GRUB_ERR_NONE
;
268 for (j
= 0; j
< hash
->mdlen
; j
++)
269 grub_printf ("%02x", ((grub_uint8_t
*) result
)[j
]);
270 grub_printf (" %s\n", args
[i
]);
274 return grub_error (GRUB_ERR_TEST_FAILURE
, "%d files couldn't be read",
276 return GRUB_ERR_NONE
;
279 static grub_extcmd_t cmd
, cmd_md5
, cmd_sha1
, cmd_sha256
, cmd_sha512
, cmd_crc
;
281 GRUB_MOD_INIT(hashsum
)
283 cmd
= grub_register_extcmd ("hashsum", grub_cmd_hashsum
, 0,
284 N_("-h HASH [-c FILE [-p PREFIX]] "
285 "[FILE1 [FILE2 ...]]"),
286 /* TRANSLATORS: "hash checksum" is just to
287 be a bit more precise, you can treat it as
289 N_("Compute or check hash checksum."),
291 cmd_md5
= grub_register_extcmd ("md5sum", grub_cmd_hashsum
, 0,
292 N_("[-c FILE [-p PREFIX]] "
293 "[FILE1 [FILE2 ...]]"),
294 N_("Compute or check hash checksum."),
296 cmd_sha1
= grub_register_extcmd ("sha1sum", grub_cmd_hashsum
, 0,
297 N_("[-c FILE [-p PREFIX]] "
298 "[FILE1 [FILE2 ...]]"),
299 N_("Compute or check hash checksum."),
301 cmd_sha256
= grub_register_extcmd ("sha256sum", grub_cmd_hashsum
, 0,
302 N_("[-c FILE [-p PREFIX]] "
303 "[FILE1 [FILE2 ...]]"),
304 N_("Compute or check hash checksum."),
306 cmd_sha512
= grub_register_extcmd ("sha512sum", grub_cmd_hashsum
, 0,
307 N_("[-c FILE [-p PREFIX]] "
308 "[FILE1 [FILE2 ...]]"),
309 N_("Compute or check hash checksum."),
312 cmd_crc
= grub_register_extcmd ("crc", grub_cmd_hashsum
, 0,
313 N_("[-c FILE [-p PREFIX]] "
314 "[FILE1 [FILE2 ...]]"),
315 N_("Compute or check hash checksum."),
319 GRUB_MOD_FINI(hashsum
)
321 grub_unregister_extcmd (cmd
);
322 grub_unregister_extcmd (cmd_md5
);
323 grub_unregister_extcmd (cmd_sha1
);
324 grub_unregister_extcmd (cmd_sha256
);
325 grub_unregister_extcmd (cmd_sha512
);
326 grub_unregister_extcmd (cmd_crc
);