Skip to content

Commit

Permalink
Merge pull request #207 from puppetlabs/iterate-on-download-verify
Browse files Browse the repository at this point in the history
Improve download task gpg verification
  • Loading branch information
reidmv authored Sep 10, 2021
2 parents 7bd528d + f31b6ae commit ea5d1d8
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 36 deletions.
12 changes: 11 additions & 1 deletion tasks/download.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@
"type": "String",
"description": "Where to save the downloaded file"
},
"check_download": {
"verify_download": {
"type": "Boolean",
"description": "Whether to check the integrity of the downloaded file",
"default": true
},
"key_id": {
"type": "String",
"description": "The GPG key ID to use when verifying the download",
"default": "4528B6CD9E61EF26"
},
"key_server": {
"type": "String",
"description": "The GPG keyserver to retrieve the GPG key from",
"default": "hkp://keyserver.ubuntu.com:11371"
}
},
"input_method": "environment",
Expand Down
115 changes: 80 additions & 35 deletions tasks/download.sh
Original file line number Diff line number Diff line change
@@ -1,45 +1,90 @@
#!/bin/bash

urisize=$(curl -s -L --head "$PT_source" | sed -n 's/Content-Length: \([0-9]\+\)/\1/p' | tr -d '\012\015')
filesize=$(stat -c%s "$PT_path" 2>/dev/null)
# Exit code indicating "a service is unavailable", from
# /usr/include/sysexits.h. The verify-file function will return this code if
# prerequisites for verification are unavailable.
EX_UNAVAILABLE=69

# Assume that if the file exists and is the same size, we don't have to
# re-download.
if [[ ! -z "$urisize" && ! -z "$filesize" && "$filesize" -eq "$urisize" ]]; then
exit 0
else
printf '%s\n' "Downloading: ${PT_source}" >&2
curl -f -L -o "$PT_path" "$PT_source"
fi
verify-file() {
local sig="$1"
local doc="$2"

if [[ "$PT_check_download" == "false" ]]; then
exit 0
fi
# The GPG binary is required to be present in order to perform file download
# verification. If it is not present, return EX_UNAVAILABLE.
if ! command -v gpg >/dev/null; then
echo "gpg binary not found; required in path for checking download"
return "$EX_UNAVAILABLE"
fi

if ! which -s gpg ; then
echo "gpg binary required in path for checking download. Skipping check."
exit 0
fi
# The verification key must be present, or it must be possible to download it
# from the keyserver to perform file verification. If it is not present,
# return EX_UNAVAILABLE.
if ! { gpg --list-keys "$PT_key_id" || gpg --keyserver "$PT_key_server" --recv-key "$PT_key_id"; } then
echo "Unable to download verification key ${PT_key_id}"
return "$EX_UNAVAILABLE"
fi

echo "Importing Puppet gpg public key"
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --recv-key 4528B6CD9E61EF26
if gpg --list-key --fingerprint 4528B6CD9E61EF26 | grep -q -E "D681 +1ED3 +ADEE +B844 +1AF5 +AA8F +4528 +B6CD +9E61 +EF26" ; then
echo "gpg public key imported successfully."
else
echo "Could not import gpg public key - wrong fingerprint."
exit 1
fi
# Perform the verification and return success or failure.
if gpg --verify "$sig" "$doc"; then
echo "Signature verification succeeded"
return 0
else
echo "Signature verification failed"
return 1
fi
}

download() {
printf '%s\n' "Downloading: ${1}"
curl -s -f -L -o "$2" "$1"
}

download-size-verify() {
local source="$1"
local path="$2"

urisize=$(curl -s -L --head "$source" | sed -rn 's/Content-Length: ([0-9]+)/\1/p' | tr -d '\012\015')
filesize=$(stat -c%s "$path" 2>/dev/null || stat -f%z "$path" 2>/dev/null)

echo "Filesize: ${filesize}"
echo "Content-Length header: ${urisize}"

# Assume that if the file exists and is the same size, we don't have to
# re-download.
if [[ ! -z "$urisize" && ! -z "$filesize" && "$filesize" -eq "$urisize" ]]; then
echo "File size matches HTTP Content-Length header. Using file as-is."
exit 0
else
download "$source" "$path"
fi
}

download-signature-verify() {
local source="$1"
local path="$2"

if ! download "${source}.asc" "${path}.asc" ; then
echo "Unable to download ${source}.asc. Skipping verification."
download-size-verify "$source" "$path"
return "$?"
fi

sigpath=${PT_path}.asc
sigsource=${PT_source}.asc
echo "Verifying ${path}..."
verify_output=$(verify-file "${path}.asc" "$path");
verify_exit="$?"
if [[ "$verify_exit" -eq "$EX_UNAVAILABLE" ]]; then
echo "Verification unavailable. ${verify_output}. Skipping verification."
download-size-verify "$source" "$path"
elif [[ "$verify_exit" -eq "1" ]]; then
echo "$verify_output"
download "$source" "$path"
echo "Verifying ${path}..."
verify-file "${path}.asc" "$path"
fi
}

echo "Downloading tarball signature from ${sigsource}..."
curl -f -L -o "${sigpath}" "${sigsource}"
echo "Downloaded tarball signature to ${sigpath}."
echo "Checking tarball signature at ${sigpath}..."
if gpg --verify "${sigpath}" "${PT_path}" ; then
echo "Signature verification succeeded."
if [[ "$PT_verify_download" == "true" ]]; then
download-signature-verify "$PT_source" "$PT_path"
else
echo "Signature verification failed, please re-run the installation."
exit 1
download-size-verify "$PT_source" "$PT_path"
fi

0 comments on commit ea5d1d8

Please sign in to comment.