hashsum.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2009 Free Software Foundation, Inc.
  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. #include <grub/dl.h>
  19. #include <grub/extcmd.h>
  20. #include <grub/file.h>
  21. #include <grub/disk.h>
  22. #include <grub/mm.h>
  23. #include <grub/misc.h>
  24. #include <grub/crypto.h>
  25. #include <grub/i18n.h>
  26. #include <grub/lib.h>
  27. static const struct grub_arg_option options[] = {
  28. {"hash", 'h', 0, N_("Specify hash to use."), N_("HASH"), ARG_TYPE_STRING},
  29. {"check", 'c', 0, N_("Check hash list file."), N_("FILE"), ARG_TYPE_STRING},
  30. {"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIRECTORY"),
  31. ARG_TYPE_STRING},
  32. {"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0},
  33. {0, 0, 0, 0, 0, 0}
  34. };
  35. struct { const char *name; const char *hashname; } aliases[] =
  36. {
  37. {"sha256sum", "sha256"},
  38. {"sha512sum", "sha512"},
  39. {"md5sum", "md5"},
  40. };
  41. static inline int
  42. hextoval (char c)
  43. {
  44. if (c >= '0' && c <= '9')
  45. return c - '0';
  46. if (c >= 'a' && c <= 'f')
  47. return c - 'a' + 10;
  48. if (c >= 'A' && c <= 'F')
  49. return c - 'A' + 10;
  50. return -1;
  51. }
  52. static grub_err_t
  53. hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result)
  54. {
  55. grub_uint8_t context[hash->contextsize];
  56. grub_uint8_t readbuf[4096];
  57. grub_memset (context, 0, sizeof (context));
  58. hash->init (context);
  59. while (1)
  60. {
  61. grub_ssize_t r;
  62. r = grub_file_read (file, readbuf, sizeof (readbuf));
  63. if (r < 0)
  64. return grub_errno;
  65. if (r == 0)
  66. break;
  67. hash->write (context, readbuf, r);
  68. }
  69. hash->final (context);
  70. grub_memcpy (result, hash->read (context), hash->mdlen);
  71. return GRUB_ERR_NONE;
  72. }
  73. static grub_err_t
  74. check_list (const gcry_md_spec_t *hash, const char *hashfilename,
  75. const char *prefix, int keep)
  76. {
  77. grub_file_t hashlist, file;
  78. char *buf = NULL;
  79. grub_uint8_t expected[hash->mdlen];
  80. grub_uint8_t actual[hash->mdlen];
  81. grub_err_t err;
  82. unsigned i;
  83. unsigned unread = 0, mismatch = 0;
  84. hashlist = grub_file_open (hashfilename);
  85. if (!hashlist)
  86. return grub_errno;
  87. while (grub_free (buf), (buf = grub_getline (hashlist)))
  88. {
  89. const char *p = buf;
  90. for (i = 0; i < hash->mdlen; i++)
  91. {
  92. int high, low;
  93. high = hextoval (*p++);
  94. low = hextoval (*p++);
  95. if (high < 0 || low < 0)
  96. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
  97. expected[i] = (high << 4) | low;
  98. }
  99. if (*p++ != ' ' || *p++ != ' ')
  100. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
  101. if (prefix)
  102. {
  103. char *filename;
  104. filename = grub_xasprintf ("%s/%s", prefix, p);
  105. if (!filename)
  106. return grub_errno;
  107. file = grub_file_open (filename);
  108. grub_free (filename);
  109. }
  110. else
  111. file = grub_file_open (p);
  112. if (!file)
  113. {
  114. grub_file_close (hashlist);
  115. grub_free (buf);
  116. return grub_errno;
  117. }
  118. err = hash_file (file, hash, actual);
  119. grub_file_close (file);
  120. if (err)
  121. {
  122. grub_printf ("%s: READ ERROR\n", p);
  123. if (!keep)
  124. {
  125. grub_file_close (hashlist);
  126. grub_free (buf);
  127. return err;
  128. }
  129. grub_print_error ();
  130. grub_errno = GRUB_ERR_NONE;
  131. unread++;
  132. continue;
  133. }
  134. if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0)
  135. {
  136. grub_printf ("%s: HASH MISMATCH\n", p);
  137. if (!keep)
  138. {
  139. grub_file_close (hashlist);
  140. grub_free (buf);
  141. return grub_error (GRUB_ERR_TEST_FAILURE,
  142. "hash of '%s' mismatches", p);
  143. }
  144. mismatch++;
  145. continue;
  146. }
  147. grub_printf ("%s: OK\n", p);
  148. }
  149. if (mismatch || unread)
  150. return grub_error (GRUB_ERR_TEST_FAILURE,
  151. "%d files couldn't be read and hash "
  152. "of %d files mismatches", unread, mismatch);
  153. return GRUB_ERR_NONE;
  154. }
  155. static grub_err_t
  156. grub_cmd_hashsum (struct grub_extcmd *cmd,
  157. int argc, char **args)
  158. {
  159. struct grub_arg_list *state = cmd->state;
  160. const char *hashname = NULL;
  161. const char *prefix = NULL;
  162. const gcry_md_spec_t *hash;
  163. unsigned i;
  164. int keep = state[3].set;
  165. unsigned unread = 0;
  166. for (i = 0; i < ARRAY_SIZE (aliases); i++)
  167. if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0)
  168. hashname = aliases[i].hashname;
  169. if (state[0].set)
  170. hashname = state[0].arg;
  171. if (!hashname)
  172. return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified");
  173. hash = grub_crypto_lookup_md_by_name (hashname);
  174. if (!hash)
  175. return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash");
  176. if (state[2].set)
  177. prefix = state[2].arg;
  178. if (state[1].set)
  179. {
  180. if (argc != 0)
  181. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  182. "--check is incompatible with file list");
  183. return check_list (hash, state[1].arg, prefix, keep);
  184. }
  185. for (i = 0; i < (unsigned) argc; i++)
  186. {
  187. grub_uint8_t result[hash->mdlen];
  188. grub_file_t file;
  189. grub_err_t err;
  190. unsigned j;
  191. file = grub_file_open (args[i]);
  192. if (!file)
  193. {
  194. if (!keep)
  195. return grub_errno;
  196. grub_print_error ();
  197. grub_errno = GRUB_ERR_NONE;
  198. unread++;
  199. continue;
  200. }
  201. err = hash_file (file, hash, result);
  202. grub_file_close (file);
  203. if (err)
  204. {
  205. if (!keep)
  206. return err;
  207. grub_print_error ();
  208. grub_errno = GRUB_ERR_NONE;
  209. unread++;
  210. continue;
  211. }
  212. for (j = 0; j < hash->mdlen; j++)
  213. grub_printf ("%02x", result[j]);
  214. grub_printf (" %s\n", args[i]);
  215. }
  216. if (unread)
  217. return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read.",
  218. unread);
  219. return GRUB_ERR_NONE;
  220. }
  221. static grub_extcmd_t cmd, cmd_md5, cmd_sha256, cmd_sha512;
  222. GRUB_MOD_INIT(hashsum)
  223. {
  224. cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum,
  225. GRUB_COMMAND_FLAG_BOTH,
  226. "hashsum -h HASH [-c FILE [-p PREFIX]] "
  227. "[FILE1 [FILE2 ...]]",
  228. "Compute or check hash checksum.",
  229. options);
  230. cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum,
  231. GRUB_COMMAND_FLAG_BOTH,
  232. N_("[-c FILE [-p PREFIX]] "
  233. "[FILE1 [FILE2 ...]]"),
  234. N_("Compute or check hash checksum."),
  235. options);
  236. cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum,
  237. GRUB_COMMAND_FLAG_BOTH,
  238. N_("[-c FILE [-p PREFIX]] "
  239. "[FILE1 [FILE2 ...]]"),
  240. "Compute or check hash checksum.",
  241. options);
  242. cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum,
  243. GRUB_COMMAND_FLAG_BOTH,
  244. N_("[-c FILE [-p PREFIX]] "
  245. "[FILE1 [FILE2 ...]]"),
  246. N_("Compute or check hash checksum."),
  247. options);
  248. }
  249. GRUB_MOD_FINI(hashsum)
  250. {
  251. grub_unregister_extcmd (cmd);
  252. grub_unregister_extcmd (cmd_md5);
  253. grub_unregister_extcmd (cmd_sha256);
  254. grub_unregister_extcmd (cmd_sha512);
  255. }