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