Fix: Isolate installer GPG inspection

This commit is contained in:
Gabriel Brown
2026-08-27 06:05:42 -04:00
parent 94a4314730
commit 18ecc2244f
2 changed files with 36 additions and 13 deletions
+18 -10
View File
@@ -6,10 +6,16 @@
declare -gA INSTALLER_PROVENANCE=() declare -gA INSTALLER_PROVENANCE=()
_primary_key_fingerprints() { _primary_key_fingerprints() (
gpg --batch --with-colons --import-options show-only --import "$1" 2>/dev/null \ local home
home="$(mktemp -d)" || exit 1
chmod 700 "$home"
trap 'rm -rf -- "$home"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
GNUPGHOME="$home" gpg --batch --with-colons --import-options show-only --import "$1" 2>/dev/null \
| awk -F: '$1 == "pub" { primary = 1; next } primary && $1 == "fpr" { print $10; primary = 0 }' | awk -F: '$1 == "pub" { primary = 1; next } primary && $1 == "fpr" { print $10; primary = 0 }'
} )
key_fingerprint_matches() { key_fingerprint_matches() {
local file="$1" expected="$2" local file="$1" expected="$2"
@@ -27,13 +33,15 @@ _key_has_one_primary() {
verify_detached_signature() { verify_detached_signature() {
local key="$1" signature="$2" content="$3" home local key="$1" signature="$2" content="$3" home
_key_has_one_primary "$key" || return 1 _key_has_one_primary "$key" || return 1
home="$(mktemp -d)" || return 1 (
chmod 700 "$home" home="$(mktemp -d)" || exit 1
GNUPGHOME="$home" gpg --batch --quiet --import "$key" >/dev/null 2>&1 \ chmod 700 "$home"
&& GNUPGHOME="$home" gpg --batch --verify "$signature" "$content" >/dev/null 2>&1 trap 'rm -rf -- "$home"' EXIT
local status=$? trap 'exit 130' INT
rm -rf -- "$home" trap 'exit 143' TERM
return "$status" GNUPGHOME="$home" gpg --batch --quiet --import "$key" >/dev/null 2>&1 \
&& GNUPGHOME="$home" gpg --batch --verify "$signature" "$content" >/dev/null 2>&1
)
} }
download_sha256() { download_sha256() {
+18 -3
View File
@@ -10,6 +10,7 @@ config="$repo_dir/setup/provenance/installers.conf"
test_tmp="$(mktemp -d)" test_tmp="$(mktemp -d)"
host_gnupg="${GNUPGHOME:-$HOME/.gnupg}" host_gnupg="${GNUPGHOME:-$HOME/.gnupg}"
host_rpmdb="/usr/lib/sysimage/rpm/rpmdb.sqlite" host_rpmdb="/usr/lib/sysimage/rpm/rpmdb.sqlite"
ambient_gnupg="$test_tmp/fresh-ambient-gnupg"
cleanup() { cleanup() {
rm -rf -- "$test_tmp" rm -rf -- "$test_tmp"
@@ -55,6 +56,14 @@ snapshot_gpg_state() {
done < <(find "$path" -maxdepth 1 -type f \( -name pubring.kbx -o -name trustdb.gpg \) | sort) done < <(find "$path" -maxdepth 1 -type f \( -name pubring.kbx -o -name trustdb.gpg \) | sort)
} }
export GNUPGHOME="$ambient_gnupg"
mkdir -m 700 "$ambient_gnupg"
ambient_before="$(snapshot "$ambient_gnupg")"
ambient_gpg_files_before="$(snapshot_gpg_state "$ambient_gnupg")"
before_gnupg="$(snapshot "$host_gnupg")"
before_gpg_files="$(snapshot_gpg_state "$host_gnupg")"
before_rpmdb="$(snapshot "$host_rpmdb")"
# This must be the only production file sourced by the contract. # This must be the only production file sourced by the contract.
# shellcheck source=../../setup/lib/artifact-provenance # shellcheck source=../../setup/lib/artifact-provenance
source "$repo_dir/setup/lib/artifact-provenance" source "$repo_dir/setup/lib/artifact-provenance"
@@ -70,6 +79,10 @@ base64 --decode "$fixtures/wrong-signer-fixture.rpm.base64" > "$test_tmp/wrong-s
|| fail 'tampered artifact does not differ by exactly one byte' || fail 'tampered artifact does not differ by exactly one byte'
expect_success key_fingerprint_matches "$fixtures/fixture-key.asc" "$fixture_fingerprint" expect_success key_fingerprint_matches "$fixtures/fixture-key.asc" "$fixture_fingerprint"
[[ "$ambient_before" == "$(snapshot "$ambient_gnupg")" ]] \
|| fail 'fingerprint inspection created ambient GPG state'
[[ "$ambient_gpg_files_before" == "$(snapshot_gpg_state "$ambient_gnupg")" ]] \
|| fail 'fingerprint inspection created an ambient GPG keybox or trust database'
expect_failure key_fingerprint_matches "$fixtures/fixture-key.asc" '0000000000000000000000000000000000000000' expect_failure key_fingerprint_matches "$fixtures/fixture-key.asc" '0000000000000000000000000000000000000000'
cat "$fixtures/fixture-key.asc" "$fixtures/wrong-signer-key.asc" > "$test_tmp/combined-key.asc" cat "$fixtures/fixture-key.asc" "$fixtures/wrong-signer-key.asc" > "$test_tmp/combined-key.asc"
expect_failure key_fingerprint_matches "$test_tmp/combined-key.asc" "$fixture_fingerprint" expect_failure key_fingerprint_matches "$test_tmp/combined-key.asc" "$fixture_fingerprint"
@@ -78,6 +91,8 @@ expect_success verify_detached_signature \
"$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/SHASUMS256.txt" "$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/SHASUMS256.txt"
expect_failure verify_detached_signature \ expect_failure verify_detached_signature \
"$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/tiny-artifact" "$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/tiny-artifact"
expect_failure verify_detached_signature \
"$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/tiny-artifact-tampered"
cp "$fixtures/SHASUMS256.txt.asc" "$test_tmp/bad-signature.asc" cp "$fixtures/SHASUMS256.txt.asc" "$test_tmp/bad-signature.asc"
sed -i 's/^=MJqv$/=MJqa/' "$test_tmp/bad-signature.asc" sed -i 's/^=MJqv$/=MJqa/' "$test_tmp/bad-signature.asc"
expect_failure verify_detached_signature \ expect_failure verify_detached_signature \
@@ -159,9 +174,6 @@ expect_failure download_sha256 'https://fixture.invalid/interrupted' "$tiny_sha2
assert_file_bytes "$destination" 'known-good' assert_file_bytes "$destination" 'known-good'
[[ ! -e "$destination.part" ]] || fail 'interrupted download left a part file' [[ ! -e "$destination.part" ]] || fail 'interrupted download left a part file'
before_gnupg="$(snapshot "$host_gnupg")"
before_gpg_files="$(snapshot_gpg_state "$host_gnupg")"
before_rpmdb="$(snapshot "$host_rpmdb")"
expect_success rpm_signature_matches \ expect_success rpm_signature_matches \
"$test_tmp/signed-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint" "$test_tmp/signed-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint"
expect_failure rpm_signature_matches \ expect_failure rpm_signature_matches \
@@ -175,6 +187,9 @@ expect_failure rpm_signature_matches \
[[ "$before_gnupg" == "$(snapshot "$host_gnupg")" ]] || fail 'host GPG state changed' [[ "$before_gnupg" == "$(snapshot "$host_gnupg")" ]] || fail 'host GPG state changed'
[[ "$before_gpg_files" == "$(snapshot_gpg_state "$host_gnupg")" ]] || fail 'host GPG keybox or trust database changed' [[ "$before_gpg_files" == "$(snapshot_gpg_state "$host_gnupg")" ]] || fail 'host GPG keybox or trust database changed'
[[ "$before_rpmdb" == "$(snapshot "$host_rpmdb")" ]] || fail 'host RPM database changed' [[ "$before_rpmdb" == "$(snapshot "$host_rpmdb")" ]] || fail 'host RPM database changed'
[[ "$ambient_before" == "$(snapshot "$ambient_gnupg")" ]] || fail 'production helper created ambient GPG state'
[[ "$ambient_gpg_files_before" == "$(snapshot_gpg_state "$ambient_gnupg")" ]] \
|| fail 'production helper created an ambient GPG keybox or trust database'
expect_success load_installer_provenance "$config" expect_success load_installer_provenance "$config"
[[ "${INSTALLER_PROVENANCE[BUN_VERSION]:-}" == '1.4.0' ]] || fail 'valid provenance was not loaded' [[ "${INSTALLER_PROVENANCE[BUN_VERSION]:-}" == '1.4.0' ]] || fail 'valid provenance was not loaded'