|
| 1 | +#! /usr/bin/env bash |
| 2 | +# Shared helper: download, normalize, and update one distro signing key. |
| 3 | +# Called by per-distro wrapper scripts in bin/update_distro_signing_key/. |
| 4 | +# |
| 5 | +# Usage: update_distro_signing_key_helper.sh <label> <url> <uid> <key_relpath> |
| 6 | +# |
| 7 | +# <label> Human-readable distro name, used in log output (e.g. "Tails") |
| 8 | +# <url> URL to download the raw key bundle from |
| 9 | +# <uid> GPG UID to select for export (email or full name string) |
| 10 | +# <key_relpath> Repo-relative path to the key file to update |
| 11 | +# (e.g. initrd/etc/distro/keys/tails.key) |
| 12 | +# |
| 13 | +# Normalization applied: |
| 14 | +# --export-options export-minimal,export-clean |
| 15 | +# --export-filter drop-subkey=expired -gt 0 || usage !~ s |
| 16 | +# |
| 17 | +# Only the primary key and non-expired signing subkeys are kept — no |
| 18 | +# encryption, authentication, or expired subkeys. |
| 19 | + |
| 20 | +set -eo pipefail |
| 21 | + |
| 22 | +die() { echo "ERROR: $*" >&2; exit 1; } |
| 23 | + |
| 24 | +[ $# -eq 4 ] || die "Usage: $(basename "$0") <label> <url> <uid> <key_relpath>" |
| 25 | + |
| 26 | +LABEL="$1" |
| 27 | +KEY_URL="$2" |
| 28 | +KEY_UID="$3" |
| 29 | +KEY_RELPATH="$4" |
| 30 | + |
| 31 | +REPO_ROOT="$(git -C "$(cd "$(dirname "$0")" && pwd)" rev-parse --show-toplevel)" |
| 32 | +KEY_FILE="$REPO_ROOT/$KEY_RELPATH" |
| 33 | + |
| 34 | +[ -f "$KEY_FILE" ] || die "Key file not found in repo: $KEY_RELPATH" |
| 35 | + |
| 36 | +# Temporary GPG home — cleaned up on exit |
| 37 | +GPGHOME="$(mktemp -d --tmpdir "update-distro-key-XXXXXX")" |
| 38 | +trap 'rm -rf -- "$GPGHOME"' EXIT |
| 39 | + |
| 40 | +echo "[$LABEL] Downloading $KEY_URL ..." |
| 41 | +wget -q "$KEY_URL" -O "$GPGHOME/raw.key" \ |
| 42 | + || die "[$LABEL] Failed to download key from $KEY_URL" |
| 43 | + |
| 44 | +echo "[$LABEL] Importing key into temporary keyring ..." |
| 45 | +gpg --homedir "$GPGHOME" --batch --import "$GPGHOME/raw.key" 2>/dev/null \ |
| 46 | + || die "[$LABEL] gpg --import failed" |
| 47 | + |
| 48 | +echo "[$LABEL] Exporting normalized key for '$KEY_UID' ..." |
| 49 | +gpg --homedir "$GPGHOME" --batch \ |
| 50 | + --export --armor \ |
| 51 | + --export-options export-minimal,export-clean \ |
| 52 | + --export-filter 'drop-subkey=expired -gt 0 || usage !~ s' \ |
| 53 | + "$KEY_UID" > "$GPGHOME/normalized.key" \ |
| 54 | + || die "[$LABEL] gpg --export failed" |
| 55 | + |
| 56 | +[ -s "$GPGHOME/normalized.key" ] \ |
| 57 | + || die "[$LABEL] Exported key is empty — is '$KEY_UID' present in the downloaded keyring?" |
| 58 | + |
| 59 | +cp "$GPGHOME/normalized.key" "$KEY_FILE" |
| 60 | +echo "[$LABEL] Written to $KEY_RELPATH" |
| 61 | + |
| 62 | +# Report primary key expiry; warn (in color) if expiring within 365 days |
| 63 | +WARN_DAYS=365 |
| 64 | +WARN_SECS=$(( WARN_DAYS * 86400 )) |
| 65 | +NOW="$(date +%s)" |
| 66 | +RED='\033[0;31m' |
| 67 | +YELLOW='\033[0;33m' |
| 68 | +NC='\033[0m' |
| 69 | +echo "" |
| 70 | +gpg --homedir "$GPGHOME" --batch --list-keys --with-colons "$KEY_UID" 2>/dev/null \ |
| 71 | + | awk -F: -v label="$LABEL" -v now="$NOW" -v warn_secs="$WARN_SECS" \ |
| 72 | + -v red="$RED" -v yellow="$YELLOW" -v nc="$NC" ' |
| 73 | + /^pub:/ { |
| 74 | + expiry = $7 |
| 75 | + if (expiry != "") { |
| 76 | + cmd = "date -d @" expiry " +%Y-%m-%d" |
| 77 | + cmd | getline expdate |
| 78 | + close(cmd) |
| 79 | + days_left = int((expiry - now) / 86400) |
| 80 | + if (expiry <= now) { |
| 81 | + print red "WARNING: [" label "] Primary key EXPIRED on " expdate " -- update immediately!" nc |
| 82 | + } else if ((expiry - now) <= warn_secs) { |
| 83 | + print yellow "WARNING: [" label "] Primary key expires " expdate " (" days_left " days) -- update soon!" nc |
| 84 | + } else { |
| 85 | + print "[" label "] Primary key expires " expdate " (" days_left " days)" |
| 86 | + } |
| 87 | + } else { |
| 88 | + print "[" label "] Primary key: no expiry" |
| 89 | + } |
| 90 | + } |
| 91 | + ' |
| 92 | + |
| 93 | +# Report change status via git |
| 94 | +if git -C "$REPO_ROOT" diff --quiet -- "$KEY_RELPATH"; then |
| 95 | + echo "[$LABEL] No change — key is identical to the committed version." |
| 96 | +else |
| 97 | + echo "" |
| 98 | + echo "[$LABEL] Key has CHANGED since the last committed version:" |
| 99 | + echo "" |
| 100 | + git -C "$REPO_ROOT" diff --stat -- "$KEY_RELPATH" |
| 101 | + echo "" |
| 102 | + echo "Review the diff with:" |
| 103 | + echo " git diff -- $KEY_RELPATH" |
| 104 | + echo "" |
| 105 | + echo "If the change is expected, commit it with:" |
| 106 | + echo " git add $KEY_RELPATH" |
| 107 | + echo " git commit -s -S -m 'distro/keys: update $LABEL signing key'" |
| 108 | +fi |
0 commit comments