check-hash 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #!/usr/bin/env bash
  2. set -e
  3. # Helper to check a file matches its known hash
  4. # Call it with:
  5. # $1: the path of the file containing all the expected hashes
  6. # $2: the full path to the temporary file that was downloaded, and
  7. # that is to be checked
  8. # $3: the final basename of the file, to which it will be ultimately
  9. # saved as, to be able to match it to the corresponding hashes
  10. # in the .hash file
  11. #
  12. # Exit codes:
  13. # 0: the hash file exists and the file to check matches all its hashes,
  14. # or the hash file does not exist
  15. # 1: unknown command-line option
  16. # 2: the hash file exists and the file to check does not match at least
  17. # one of its hashes
  18. # 3: the hash file exists and there was no hash to check the file against
  19. # 4: the hash file exists and at least one hash type is unknown
  20. while getopts :q OPT; do
  21. case "${OPT}" in
  22. q) exec >/dev/null;;
  23. \?) exit 1;;
  24. esac
  25. done
  26. shift $((OPTIND-1))
  27. h_file="${1}"
  28. file="${2}"
  29. base="${3}"
  30. # Bail early if no hash to check
  31. if [ -z "${h_file}" ]; then
  32. exit 0
  33. fi
  34. # Does the hash-file exist?
  35. if [ ! -f "${h_file}" ]; then
  36. printf "WARNING: no hash file for %s\n" "${base}" >&2
  37. exit 0
  38. fi
  39. # Check one hash for a file
  40. # $1: algo hash
  41. # $2: known hash
  42. # $3: file (full path)
  43. check_one_hash() {
  44. _h="${1}"
  45. _known="${2}"
  46. _file="${3}"
  47. # Note: md5 is supported, but undocumented on purpose.
  48. # Note: sha3 is not supported, since there is currently no implementation
  49. # (the NIST has yet to publish the parameters).
  50. # Note: 'none' means there is explicitly no hash for that file.
  51. case "${_h}" in
  52. none)
  53. return 0
  54. ;;
  55. md5|sha1) ;;
  56. sha224|sha256|sha384|sha512) ;;
  57. *) # Unknown hash, exit with error
  58. printf "ERROR: unknown hash '%s' for '%s'\n" \
  59. "${_h}" "${base}" >&2
  60. exit 4
  61. ;;
  62. esac
  63. # Do the hashes match?
  64. _hash=$( ${_h}sum "${_file}" |cut -d ' ' -f 1 )
  65. if [ "${_hash}" = "${_known}" ]; then
  66. printf "%s: OK (%s: %s)\n" "${base}" "${_h}" "${_hash}"
  67. return 0
  68. fi
  69. printf "ERROR: %s has wrong %s hash:\n" "${base}" "${_h}" >&2
  70. printf "ERROR: expected: %s\n" "${_known}" >&2
  71. printf "ERROR: got : %s\n" "${_hash}" >&2
  72. printf "ERROR: Incomplete download, or man-in-the-middle (MITM) attack\n" >&2
  73. exit 2
  74. }
  75. # Do we know one or more hashes for that file?
  76. nb_checks=0
  77. while read t h f; do
  78. case "${t}" in
  79. ''|'#'*)
  80. # Skip comments and empty lines
  81. continue
  82. ;;
  83. *)
  84. if [ "${f}" = "${base}" ]; then
  85. check_one_hash "${t}" "${h}" "${file}"
  86. : $((nb_checks++))
  87. fi
  88. ;;
  89. esac
  90. done <"${h_file}"
  91. if [ ${nb_checks} -eq 0 ]; then
  92. case " ${BR_NO_CHECK_HASH_FOR} " in
  93. *" ${base} "*)
  94. # File explicitly has no hash
  95. exit 0
  96. ;;
  97. esac
  98. printf "ERROR: No hash found for %s\n" "${base}" >&2
  99. exit 3
  100. fi