apache/pulsar · error · IOException

Failed to decode public key

Error message

Failed to decode public key

What it means

AuthTokenUtils.decodePublicKey wraps any failure while parsing an X.509-encoded public key (for RSA or EC signature algorithms) into an IOException. KeyFactory.generatePublic rejects the bytes if they are not a valid DER/X.509 SubjectPublicKeyInfo structure or do not match the expected key algorithm.

Source

Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/utils/AuthTokenUtils.java:75

    public static PrivateKey decodePrivateKey(byte[] key, SignatureAlgorithm algType) throws IOException {
        try {
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key);
            KeyFactory kf = KeyFactory.getInstance(keyTypeForSignatureAlgorithm(algType));
            return kf.generatePrivate(spec);
        } catch (Exception e) {
            throw new IOException("Failed to decode private key", e);
        }
    }


    public static PublicKey decodePublicKey(byte[] key, SignatureAlgorithm algType) throws IOException {
        try {
            X509EncodedKeySpec spec = new X509EncodedKeySpec(key);
            KeyFactory kf = KeyFactory.getInstance(keyTypeForSignatureAlgorithm(algType));
            return kf.generatePublic(spec);
        } catch (Exception e) {
            throw new IOException("Failed to decode public key", e);
        }
    }

    private static String keyTypeForSignatureAlgorithm(SignatureAlgorithm alg) {
        if (alg.getFamilyName().equals("RSA")) {
            return "RSA";
        } else if (alg.getFamilyName().equals("ECDSA")) {
            return "EC";
        } else {
            String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
            throw new IllegalArgumentException(msg);
        }
    }

    public static String encodeKeyBase64(Key key) {
        return Encoders.BASE64.encode(key.getEncoded());
    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Verify the input is a public key in X.509/SubjectPublicKeyInfo (SPKI) DER format; regenerate with `openssl rsa -pubout` or `openssl ec -pubout` and base64-encode the DER bytes.
  2. Strip PEM armor and whitespace before calling decodePublicKey — it expects raw DER bytes, not the '-----BEGIN PUBLIC KEY-----' text.
  3. Ensure the SignatureAlgorithm matches the key family (RSA key with RSA alg, EC key with ECDSA alg).
  4. Confirm the base64 string decodes cleanly (Decoders.BASE64.decode in a test) and was not truncated by copy/paste or line wrapping.

Example fix

// before
byte[] key = Files.readAllBytes(Path.of("public.key")); // file contains PEM text
PublicKey pk = AuthTokenUtils.decodePublicKey(key, SignatureAlgorithm.RS256);
// after
String pem = Files.readString(Path.of("public.key"));
String b64 = pem.replaceAll("-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\\s", "");
byte[] key = Base64.getDecoder().decode(b64);
PublicKey pk = AuthTokenUtils.decodePublicKey(key, SignatureAlgorithm.RS256);
Defensive patterns

Strategy: validation

Validate before calling

byte[] der = Base64.getDecoder().decode(cleanB64);
if (der.length == 0 || der[0] != 0x30) throw new IllegalArgumentException("not DER/SPKI public key");
new X509EncodedKeySpec(der); // parses or throws before calling the API

Type guard

boolean isSpkiPublicKey(byte[] b) { return b != null && b.length > 0 && b[0] == 0x30; }

Try / catch

try { PublicKey pk = AuthTokenUtils.decodePublicKey(bytes, alg); } catch (IOException e) { log.error("bad public key material", e); throw new ConfigurationException("check tokenPublicKey: must be base64 X.509 SPKI"); }

Prevention

When it happens

Trigger: Calling decodePublicKey(byte[], SignatureAlgorithm) with bytes that are not a valid X509EncodedKeySpec: corrupted key file contents, a PEM body with surrounding junk, a private key passed where a public key is expected, or truncated base64 input.

Common situations: Passing the contents of a PKCS#8 private key file instead of the public key; pasting a raw hex key instead of base64 DER; hand-editing a key file and corrupting the encoding; using a key generated for a different algorithm than the configured algType.

Understand the failure class

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/6072ddedc881c699. Report an issue: GitHub.