From a32e7af37afa24dce75f1771ca2c728113848fbc Mon Sep 17 00:00:00 2001 From: GrapeS Date: Tue, 10 Nov 2026 15:12:56 +0800 Subject: [PATCH] fix: accept start.sh downloads signed by an expired release key gpg judges key expiry at verification time and reports a signature made by a key that has expired since as EXPKEYSIG, so rejecting EXPKEYSIG made the jars of all earlier releases fail verification once the release key expires. checkSign accepts EXPKEYSIG as well as GOODSIG and rejects only a revoked release key. gpg reports a key that has been revoked and has also expired as EXPKEYSIG, so revocation is also read from the key listing. --- shell.md | 2 +- start.sh | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/shell.md b/shell.md index ec274d1ce4e..96990bd8bc7 100644 --- a/shell.md +++ b/shell.md @@ -10,7 +10,7 @@ The script is available in the java-tron project at [github](https://github.com/ The script runs on x86_64 with JDK 8 and on ARM64 with JDK 17. It picks the JVM options for the Java version it finds, and downloads the release jars built for that architecture (`FullNode-aarch64.jar` on ARM64). -Downloaded release jars are verified against the GPG signature published with each release, made by the key listed under "Integrity Check" in the [README](./README.md), so `gpg` must be installed; a jar that fails verification is not used. A signature made by a revoked or expired release key fails verification. The mainnet config is downloaded from java-tron and the Nile testnet config from [nile-testnet](https://github.com/tron-nile-testnet/nile-testnet). +Downloaded release jars are verified against the GPG signature published with each release, made by the key listed under "Integrity Check" in the [README](./README.md), so `gpg` must be installed; a jar that fails verification is not used. A signature made by a revoked release key fails verification. The mainnet config is downloaded from java-tron and the Nile testnet config from [nile-testnet](https://github.com/tron-nile-testnet/nile-testnet). For each download the release key is fetched by its fingerprint from keys.openpgp.org, or from keyserver.ubuntu.com if the first server does not answer, so installing a release jar needs outbound HTTPS access (port 443) to one of these key servers. If neither can be reached, the signature cannot be checked and the downloaded jar is removed. diff --git a/start.sh b/start.sh index 4ed1a34589f..400cd3a54d4 100644 --- a/start.sh +++ b/start.sh @@ -788,7 +788,7 @@ specifyConfig(){ # Verifies file $3 against the signature of asset $2 in release $1, which must be made # by the release key. Removes $3 if the signature is missing or invalid, or if the release -# key is revoked or expired. +# key has been revoked. checkSign() { info 'verify signature' local version=$1 @@ -797,8 +797,10 @@ checkSign() { local gnupg_home local server local status + local revoked_keys # gpg names the key of a signature by its long key id, the last 16 digits of the fingerprint. - local key="(${RELEASE_KEY_FINGERPRINT: -16}|$RELEASE_KEY_FINGERPRINT)" + local id=${RELEASE_KEY_FINGERPRINT: -16} + local key="($id|$RELEASE_KEY_FINGERPRINT)" local verified=false if type gpg >/dev/null 2>&1; then # Use a temporary keyring, so that the user's keyring is neither read nor changed. @@ -810,17 +812,16 @@ checkSign() { gpg --homedir "$gnupg_home" --batch --quiet --keyserver "$server" \ --keyserver-options timeout=10 --recv-keys "$RELEASE_KEY_FINGERPRINT" >/dev/null 2>&1 && break done - # Download the detached signature. It counts as verified only when gpg reports the release - # key's signature good and a VALIDSIG status line carries the release key fingerprint. gpg - # also prints VALIDSIG, and exits with 0, for a signature made by a revoked or expired key, - # which it reports as REVKEYSIG or EXPKEYSIG instead of GOODSIG. + # Download the detached signature and verify it. A revoked release key is rejected; gpg does + # not always report it as REVKEYSIG, so the key listing is checked as well. if download "$RELEASE_URL/download/$version/$asset.sig" "$file.sig"; then status=$(gpg --homedir "$gnupg_home" --batch --status-fd 1 --verify "$file.sig" "$file" 2>/dev/null) - if grep -q -E "^\[GNUPG:\] REVKEYSIG $key " <<< "$status"; then + revoked_keys=$(gpg --homedir "$gnupg_home" --batch --with-colons \ + --list-keys "$RELEASE_KEY_FINGERPRINT" 2>/dev/null \ + | awk -F: -v id="$id" '$2 == "r" && ($1 == "pub" || ($1 == "sub" && $5 == id))') + if [[ -n $revoked_keys ]] || grep -q -E "^\[GNUPG:\] REVKEYSIG $key " <<< "$status"; then warn 'the release key has been revoked' - elif grep -q -E "^\[GNUPG:\] EXPKEYSIG $key " <<< "$status"; then - warn 'the release key has expired' - elif grep -q -E "^\[GNUPG:\] GOODSIG $key " <<< "$status" \ + elif grep -q -E "^\[GNUPG:\] (GOODSIG|EXPKEYSIG) $key " <<< "$status" \ && grep '^\[GNUPG:\] VALIDSIG ' <<< "$status" | grep -q -w "$RELEASE_KEY_FINGERPRINT"; then verified=true fi