buildgcc: Implement simple tarball hash verification
This patch implements a relatively simple hash-based verification scheme for downloaded files (tarballs): After buildgcc downloads a file or notices that it has already been downloaded, it hashes the file, and compares the hash against the known hash stored in util/crossgcc/sum/$filename.cksum. Two errors can occur: 1. The hash file is missing. In this case, crossgcc asks the user to verify the authenticity of the downloaded file. It also calculates its hash and stores it in util/crossgcc/sum/$filename.cksum.calc. If the file is authentic, the user may rename the calculated hash file to $filename.cksum, so that it can be found the next time buildgcc is started. 2. The known hash and the calculated hash differ. This is the case that this patch seeks to protect against, because it may imply that the downloaded file was unexpectedly changed, either in transit (Man-in-the-Middle attack) or on the file server that it was downloaded from. If buildgcc detects such a hash mismatch, it asks the user to delete the downloaded file and retry, because it can also be caused by a benign network error. If, however, the error persists, buildgcc can't continue without risking that the user runs malicious code, and it stops. Note: The hash algorithm may be changed in the future, but for now I left it at SHA-1, to avoid bloating this patch. Change-Id: I0d5d67b34684d02011a845d00f6f5b6769f43b4f Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net> Reviewed-on: https://review.coreboot.org/21592 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
parent
b632c29aeb
commit
92d483a892
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
|
|
||||||
CROSSGCC_DATE="August 16th, 2017"
|
CROSSGCC_DATE="September 19th, 2017"
|
||||||
CROSSGCC_VERSION="1.47"
|
CROSSGCC_VERSION="1.48"
|
||||||
CROSSGCC_COMMIT=$( git describe )
|
CROSSGCC_COMMIT=$( git describe )
|
||||||
|
|
||||||
# default settings
|
# default settings
|
||||||
|
@ -304,18 +304,6 @@ ada_requested() {
|
||||||
echo "${LANGUAGES}" | grep -q '\<ada\>'
|
echo "${LANGUAGES}" | grep -q '\<ada\>'
|
||||||
}
|
}
|
||||||
|
|
||||||
check_sum() {
|
|
||||||
test -z "$CHECKSUM" || \
|
|
||||||
test "$(cat sum/$1.cksum 2>/dev/null | sed -e 's@.*\([0-9a-f]\{40,\}\).*@\1@')" = \
|
|
||||||
"$($CHECKSUM tarballs/$1 2>/dev/null | sed -e 's@.*\([0-9a-f]\{40,\}\).*@\1@')"
|
|
||||||
}
|
|
||||||
|
|
||||||
compute_sum() {
|
|
||||||
test ! -f sum/$1.cksum && test -f tarballs/$1 && \
|
|
||||||
(test -z "$CHECKSUM" || $CHECKSUM tarballs/$1 > sum/$1.cksum ) && \
|
|
||||||
printf "(checksum created. ${RED}Note. Please upload sum/$1.cksum if the corresponding archive is upgraded.)${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
download() {
|
download() {
|
||||||
package=$1
|
package=$1
|
||||||
archive="$(eval echo \$$package"_ARCHIVE")"
|
archive="$(eval echo \$$package"_ARCHIVE")"
|
||||||
|
@ -323,15 +311,14 @@ download() {
|
||||||
FILE=$(basename $archive)
|
FILE=$(basename $archive)
|
||||||
printf " * $FILE "
|
printf " * $FILE "
|
||||||
|
|
||||||
if test -f tarballs/$FILE && check_sum $FILE ; then
|
if test -f tarballs/$FILE; then
|
||||||
echo "(cached)"
|
printf "(cached)... "
|
||||||
else
|
else
|
||||||
printf "(downloading from $archive)"
|
printf "(downloading from $archive)"
|
||||||
rm -f tarballs/$FILE
|
rm -f tarballs/$FILE
|
||||||
cd tarballs
|
cd tarballs
|
||||||
download_showing_percentage $archive
|
download_showing_percentage $archive
|
||||||
cd ..
|
cd ..
|
||||||
compute_sum $FILE
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f tarballs/$FILE ]; then
|
if [ ! -f tarballs/$FILE ]; then
|
||||||
|
@ -340,6 +327,91 @@ download() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Compute the hash of the package given in $1, and print it raw (just the
|
||||||
|
# hexadecimal hash).
|
||||||
|
compute_hash() {
|
||||||
|
package=$1
|
||||||
|
archive="$(eval echo \$$package"_ARCHIVE")"
|
||||||
|
file="$(basename "$archive")"
|
||||||
|
|
||||||
|
if test -z "$CHECKSUM"; then
|
||||||
|
echo "${RED}\$CHECKSUM program missing. This is bad.${NC}" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$CHECKSUM "tarballs/$file" 2>/dev/null | sed -e 's@.*\([0-9a-f]\{40,\}\).*@\1@'
|
||||||
|
}
|
||||||
|
|
||||||
|
error_hash_missing() {
|
||||||
|
package="$1"
|
||||||
|
archive="$(eval echo \$$package"_ARCHIVE")"
|
||||||
|
file="$(basename "$archive")"
|
||||||
|
|
||||||
|
fullhashfile="util/crossgcc/sum/$file.cksum"
|
||||||
|
printf "${RED}hash file missing:${NC}\n\n" 1>&2
|
||||||
|
printf "Please verify util/crossgcc/tarball/$file carefully\n" 1>&2
|
||||||
|
printf "(using PGP if possible), and then rename\n" 1>&2
|
||||||
|
printf " ${CYAN}${fullhashfile}.calc${NC}\n" 1>&2
|
||||||
|
printf " to ${CYAN}${fullhashfile}${NC}\n\n" 1>&2
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the known hash file of the package given in $1, and print it raw.
|
||||||
|
get_known_hash() {
|
||||||
|
package=$1
|
||||||
|
archive="$(eval echo \$$package"_ARCHIVE")"
|
||||||
|
file="$(basename "$archive")"
|
||||||
|
hashfile="sum/$file.cksum"
|
||||||
|
|
||||||
|
if [ ! -f "$hashfile" ]; then
|
||||||
|
calc_hash="$(compute_hash "$package")" || exit 1
|
||||||
|
echo "$calc_hash tarballs/$file" > "${hashfile}.calc"
|
||||||
|
|
||||||
|
error_hash_missing "$package"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat "$hashfile" | sed -e 's@.*\([0-9a-f]\{40,\}\).*@\1@'
|
||||||
|
}
|
||||||
|
|
||||||
|
error_hash_mismatch() {
|
||||||
|
package=$1
|
||||||
|
known_hash="$2"
|
||||||
|
computed_hash="$3"
|
||||||
|
archive="$(eval echo \$$package"_ARCHIVE")"
|
||||||
|
file="$(basename "$archive")"
|
||||||
|
|
||||||
|
printf "${RED}hash mismatch:${NC}\n\n"
|
||||||
|
printf " expected (known) hash: $known_hash\n"
|
||||||
|
printf "calculated hash of downloaded file: $computed_hash\n\n"
|
||||||
|
|
||||||
|
printf "If you think this is due to a network error, please delete\n"
|
||||||
|
printf " ${CYAN}util/crossgcc/tarballs/$file${NC}\n"
|
||||||
|
printf "and try again. If the problem persists, it may be due to an\n"
|
||||||
|
printf "administration error on the file server, or you might be\n"
|
||||||
|
printf "subject to a Man-in-the-Middle attack\n\n"
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# verify_hash - Check that the hash of the file given in $1 matches the known
|
||||||
|
# hash; Bail out on mismatch or missing hash file.
|
||||||
|
verify_hash() {
|
||||||
|
package=$1
|
||||||
|
archive="$(eval echo \$$package"_ARCHIVE")"
|
||||||
|
|
||||||
|
known_hash="$(get_known_hash "$package")" || exit "$?"
|
||||||
|
computed_hash="$(compute_hash "$package")" || exit "$?"
|
||||||
|
|
||||||
|
if [ "$known_hash" != "$computed_hash" ]; then
|
||||||
|
error_hash_mismatch "$package" "$known_hash" "$computed_hash"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "${GREEN}hash verified ("$known_hash")${NC}\n"
|
||||||
|
}
|
||||||
|
|
||||||
unpack_and_patch() {
|
unpack_and_patch() {
|
||||||
package=$1
|
package=$1
|
||||||
archive="$(eval echo \$$package"_ARCHIVE")"
|
archive="$(eval echo \$$package"_ARCHIVE")"
|
||||||
|
@ -965,7 +1037,7 @@ if searchtool wget "GNU" nofail > /dev/null; then
|
||||||
wget $url 2>&1 | while read line; do
|
wget $url 2>&1 | while read line; do
|
||||||
echo $line | grep -o "[0-9]\+%" | awk '{printf("\b\b\b\b%4s", $1)}'
|
echo $line | grep -o "[0-9]\+%" | awk '{printf("\b\b\b\b%4s", $1)}'
|
||||||
done
|
done
|
||||||
printf "${NC}\n"
|
printf "${NC}... "
|
||||||
}
|
}
|
||||||
elif searchtool curl "^curl " > /dev/null; then
|
elif searchtool curl "^curl " > /dev/null; then
|
||||||
download_showing_percentage() {
|
download_showing_percentage() {
|
||||||
|
@ -1129,10 +1201,11 @@ export PATH=$DESTDIR$TARGETDIR/bin:$PATH
|
||||||
|
|
||||||
# Download, unpack, patch and build all packages
|
# Download, unpack, patch and build all packages
|
||||||
|
|
||||||
printf "Downloading tarballs ... \n"
|
printf "Downloading and verifing tarballs ... \n"
|
||||||
mkdir -p tarballs
|
mkdir -p tarballs
|
||||||
for P in $PACKAGES; do
|
for P in $PACKAGES; do
|
||||||
download $P
|
download "$P" || exit "$?"
|
||||||
|
verify_hash "$P" || exit "$?"
|
||||||
done
|
done
|
||||||
printf "Downloaded tarballs ... ${green}ok${NC}\n"
|
printf "Downloaded tarballs ... ${green}ok${NC}\n"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue