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