cloudflare/pingora · error

invalid ca pem

Error message

invalid ca pem

What it means

When the s2n TLS listener settings include a CA (mutual-TLS client verification), TlsSettings::build() calls builder.trust_pem(&ca.raw_pem) and .expect()s success (pingora-core/src/listeners/tls/s2n/mod.rs:85). If s2n-tls cannot parse the supplied PEM (DER bytes, truncated text, wrong block type, empty file), the expect panics with 'invalid ca pem' while the acceptor is being built, i.e. at listener startup.

Source

Thrown at pingora-core/src/listeners/tls/s2n/mod.rs:85

        if let Some(alpn) = self.alpn {
            builder
                .set_application_protocol_preference(alpn.to_wire_protocols())
                .unwrap();
        }

        if let (Some(cert_path), Some(key_path)) = (self.cert_path, self.key_path) {
            let Ok((cert, key)) = load_certs_and_key_files(&cert_path, &key_path) else {
                panic!(
                    "Failed to load provided certificates \"{}\" or key \"{}\".",
                    cert_path, key_path
                )
            };

            builder.load_pem(&cert, &key).unwrap();
        }

        if let Some(ca) = self.ca {
            builder.trust_pem(&ca.raw_pem).expect("invalid ca pem");
        }

        if !self.verify_client_hostname {
            builder
                .set_verify_host_callback(IgnoreVerifyHostnameCallback::new())
                .unwrap();
        }

        let config = builder.build().unwrap();
        let connection_builder = S2NConnectionBuilder {
            config,
            psk_config: self.psk_config.clone(),
            security_policy: Some(policy.clone()),
        };

        Acceptor {
            acceptor: TlsAcceptor::new(connection_builder),
            offload: self.offload_threadpool.map(|(shards, threads_per_shard)| {

View on GitHub (pinned to 0046038bd4)

Solutions

  1. Re-export the CA in PEM format: openssl x509 -inform der -in ca.der -out ca.pem
  2. Sanity-check the file parses before deploying: openssl x509 -in ca.pem -noout -text
  3. Ensure the PEM contains CERTIFICATE blocks only (keys/cross-signed extras can confuse parsers)

Example fix

# before: DER file or corrupted PEM passed as the s2n CA
ca.pem: "MII..." # base64 DER without -----BEGIN CERTIFICATE-----

# after: convert and verify
openssl x509 -inform der -in ca.der -out ca.pem
openssl x509 -in ca.pem -noout -text
Defensive patterns

Strategy: try-catch

Try / catch

// Turn the startup panic into a clean config error before serving traffic
use std::panic::{catch_unwind, AssertUnwindSafe};
let acceptor = catch_unwind(AssertUnwindSafe(|| tls_settings.build()))
    .map_err(|_| anyhow::anyhow!("invalid CA PEM for s2n listener: cannot parse ca.raw_pem"))?;

Prevention

When it happens

Trigger: Building with the s2n feature and constructing TlsSettings with a CA (client cert verification / add_ca style API) whose raw PEM bytes are not a parseable PEM certificate chain.

Common situations: Certificates exported as DER instead of PEM; copy-paste that dropped the BEGIN/END lines or inserted whitespace; pointing at a bundle with non-certificate blocks; a CI cert-generation script changing format between environments.

Related errors


AI-assisted analysis of cloudflare/pingora@0046038bd4 (2026-08-16). Data as JSON: /api/errors/752ca8e7f09b4692. Report an issue: GitHub.