Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 31 additions & 20 deletions tools/verify-signatures.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ REPORT=""
NOTES="$(dirname "${BASH_SOURCE[0]}")/source-notes.tsv"
for a in "$@"; do
case "$a" in
--refresh) rm -rf "$GNUPGHOME" "$GNU_KEYRING" ;;
--refresh) rm -rf "$GNUPGHOME" "$GNU_KEYRING" "${GNU_KEYRING}.imported" ;;
--fetch-unknown-keys) FETCH_UNKNOWN=1 ;;
--strict) STRICT=1 ;;
--report=*) REPORT="${a#--report=}" ;;
Expand Down Expand Up @@ -150,40 +150,51 @@ import_keys() {

# Fetched over the network, so it gives "signed by whoever the keyring
# says" unless its keys are checked out of band (docs/supply-chain.md).
# The keyring counts as imported only when the GNU keyring and every
# pinned key are in it; what a run could not fetch, the next fetches again.
local count
log "fetching GNU keyring"
if [[ ! -s "$GNU_KEYRING" ]]; then
quiet_fetch "${CANONICAL_GNU}/gnu-keyring.gpg" "$GNU_KEYRING" \
|| { rm -f "$GNU_KEYRING"; warn "could not fetch GNU keyring"; }
quiet_fetch "${CANONICAL_GNU}/gnu-keyring.gpg" "$GNU_KEYRING" || rm -f "$GNU_KEYRING"
fi

if [[ -s "$GNU_KEYRING" ]]; then
if [[ -s "$GNU_KEYRING" && ! -f "${GNU_KEYRING}.imported" ]]; then
log "importing GNU keyring (a few thousand keys, this takes a moment)"
gpg --batch --quiet --import "$GNU_KEYRING" 2>/dev/null || true
count="$(gpg --batch --list-keys 2>/dev/null | grep -c '^pub' || true)"
[[ "$count" =~ ^[0-9]+$ && "$count" -ge 100 ]] && : > "${GNU_KEYRING}.imported"
fi
# Without it nothing a GNU maintainer signed can be checked: a run that
# could not fetch it is not a pass.
if [[ ! -f "${GNU_KEYRING}.imported" ]]; then
rm -f "$IMPORTED_MARK"
if [[ "$STRICT" -eq 1 ]]; then
err "the GNU keyring could not be fetched from ${CANONICAL_GNU}"
die "Without it nothing a GNU maintainer signed can be authenticated, and
--strict will not report a run that could not check anything as a pass.
Run again: what was fetched is kept."
fi
warn "the GNU keyring could not be fetched: what GNU maintainers signed is unverifiable this run"
fi

# Safe from a keyserver: it cannot serve another key under a full fingerprint.
# Safe from a keyserver: it cannot serve another key under a full
# fingerprint. One it does not serve is fetched again next run, and the
# sources that key signs are unverifiable until then.
log "fetching pinned maintainer keys (${#PINNED_FPRS[@]})"
local fpr
local fpr missing=0
for fpr in "${PINNED_FPRS[@]}"; do
recv_key "$fpr" || warn "could not fetch pinned key ${fpr}"
gpg --batch --list-keys "$fpr" >/dev/null 2>&1 && continue
recv_key "$fpr" || { warn "could not fetch pinned key ${fpr}"; missing=$((missing + 1)); }
done

local count
count="$(gpg --batch --list-keys 2>/dev/null | grep -c '^pub' || true)"
[[ "$count" =~ ^[0-9]+$ ]] || count=0
printf '%s' "$count" > "$IMPORTED_MARK"

if [[ "$count" -lt 2 ]]; then
if [[ "$STRICT" -eq 1 ]]; then
err "only ${count} key(s) imported"
die "Without the maintainer keys nothing can be authenticated, and
--strict will not report a run that could not check anything as a pass.
Restore network access, or re-run without --strict for an informational pass."
fi
warn "only ${count} key(s) imported - verification will be mostly unverifiable"
if [[ -f "${GNU_KEYRING}.imported" && "$missing" -eq 0 ]]; then
printf '%s' "$count" > "$IMPORTED_MARK"
else
ok "keyring ready (${count} public keys)"
rm -f "$IMPORTED_MARK"
fi
ok "keyring ready (${count} public keys)"
[[ "$missing" -eq 0 ]] || warn "${missing} pinned key(s) not fetched; fetched again next run"
}

# --- verification ----------------------------------------------------------
Expand Down
Loading