elastic/elasticsearch · error · IOException

PGP exception during signature verification for [{}]

Error message

PGP exception during signature verification for [{}]

What it means

IOException (checked) wrapping a `PGPException` that escaped the try block of verifySignature — i.e. a lower-level BouncyCastle/PGP failure during parsing or verification that is neither a key-id mismatch nor a simple verify=false. It is caught by `catch (PGPException e)` and rethrown with context including the URL. Common causes: malformed `.asc` file, ArmoredInputStream parse error, missing public key in the keyring, or `signature.init` failure.

Source

Thrown at distribution/tools/plugin-cli/bc/src/main/java/org/elasticsearch/plugins/cli/bc/PgpSignatureVerifier.java:72

        ) {
            final JcaPGPObjectFactory factory = new JcaPGPObjectFactory(PGPUtil.getDecoderStream(sin));
            final PGPSignature signature = ((PGPSignatureList) factory.nextObject()).get(0);

            // validate the signature has key ID matching our public key ID
            final String keyId = Long.toHexString(signature.getKeyID()).toUpperCase(Locale.ROOT);
            if (publicKeyId.equals(keyId) == false) {
                throw new IllegalStateException("key id [" + keyId + "] does not match expected key id [" + publicKeyId + "]");
            }

            // compute the signature of the downloaded plugin zip
            computeSignatureForDownloadedPlugin(fin, ain, signature);

            // finally we verify the signature of the downloaded plugin zip matches the expected signature
            if (signature.verify() == false) {
                throw new IllegalStateException("signature verification for [" + urlString + "] failed");
            }
        } catch (PGPException e) {
            throw new IOException("PGP exception during signature verification for [" + urlString + "]", e);
        }
    }

    private static void computeSignatureForDownloadedPlugin(InputStream fin, InputStream ain, PGPSignature signature) throws PGPException,
        IOException {
        final PGPPublicKeyRingCollection collection = new PGPPublicKeyRingCollection(ain, new JcaKeyFingerprintCalculator());
        final PGPPublicKey key = collection.getPublicKey(signature.getKeyID());
        signature.init(new JcaPGPContentVerifierBuilderProvider(), key);
        final byte[] buffer = new byte[1024];
        int read;
        while ((read = fin.read(buffer)) != -1) {
            signature.update(buffer, 0, read);
        }
    }

}

View on GitHub (pinned to db6a809a66)

Solutions

  1. Inspect the wrapped PGPException's message/cause to find the precise PGP failure (e.g. 'invalid header', 'unknown object').
  2. Re-download the `.asc` signature and confirm it is valid armored PGP (`-----BEGIN PGP SIGNATURE-----`).
  3. Ensure the public key input is the correct, current Elastic signing key.
  4. Retry with a fresh download; if behind a proxy, bypass and re-test.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    PgpSignatureVerifier.verifySignature(publicKeyId, url, zip, asc, pubKey);
} catch (IOException e) {
    Throwable cause = e.getCause(); // PGPException
    // inspect cause message; re-download .asc / public key and retry
}

Prevention

When it happens

Trigger: A `.asc` file that is not valid ASCII-armored PGP (corrupt or wrong format); the public key ring does not contain the key referenced by the signature; PGP library version incompatibility; truncated signature file.

Common situations: Downloading a `.asc` that is actually an HTML error page from a proxy; outdated bundled public key; partial file transfer.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/0ac558506b35e63b. Report an issue: GitHub.