caddyserver/caddy · error

parsing certificate: %v

Error message

parsing certificate: %v

What it means

While configuring TLS client verification, Caddy decodes each base64 DER cert in ClientAuthentication.TrustedLeafCerts (the deprecated trusted_leaf_certs option); if decodeBase64DERCert fails (bad base64 or non-X.509 DER bytes) this error wraps it. The field is deprecated — the log also emits a warning pointing you to leaf verifier modules.

Source

Thrown at modules/caddytls/connpolicy.go:880

		} else {
			cfg.ClientAuth = tls.RequireAnyClientCert
		}
	}

	// enforce CA verification by adding CA certs to the ClientCAs pool
	if clientauth.ca != nil {
		cfg.ClientCAs = clientauth.ca.CertPool()
	}

	// TODO: DEPRECATED: Only here for backwards compatibility.
	// If leaf cert is specified, enforce by adding a client auth module
	if len(clientauth.TrustedLeafCerts) > 0 {
		caddy.Log().Named("tls.connection_policy").Warn("trusted_leaf_certs is deprecated; use leaf verifier module instead")
		var trustedLeafCerts []*x509.Certificate
		for _, clientCertString := range clientauth.TrustedLeafCerts {
			clientCert, err := decodeBase64DERCert(clientCertString)
			if err != nil {
				return fmt.Errorf("parsing certificate: %v", err)
			}
			trustedLeafCerts = append(trustedLeafCerts, clientCert)
		}
		clientauth.verifiers = append(clientauth.verifiers, LeafCertClientAuth{trustedLeafCerts: trustedLeafCerts})
	}

	// if a custom verification function already exists, wrap it
	clientauth.existingVerifyPeerCert = cfg.VerifyPeerCertificate
	cfg.VerifyConnection = clientauth.verifyConnection
	return nil
}

// verifyConnection is for use as a tls.Config.VerifyConnection callback
// to do custom client certificate verification. It is intended for
// installation only by clientauth.ConfigureTLSConfig().
//
// Unlike VerifyPeerCertificate, VerifyConnection is called on every
// connection including resumed sessions, preventing session-resumption bypass.

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Prefer the modern equivalent: tls.client_auth.verifier.leaf with a leaf_cert_loader (inline cert or file) instead of trusted_leaf_certs
  2. If you must keep the deprecated field, supply base64(STD) of the DER bytes: openssl x509 -in cert.pem -outform der | base64 -w0
  3. Verify round-trip: echo <value> | base64 -d | openssl x509 -inform der -noout
  4. Check for line breaks or whitespace corruption inside the base64 string in the JSON

Example fix

# before (deprecated + error-prone JSON)
"client_authentication": {
  "trusted_leaf_certs": ["MIIB...pem-text..."],
  "mode": "require_and_verify"
}

# after (caddyfile)
client_auth {
  mode require_and_verify
  verifier leaf {
    leaf_cert_file /etc/caddy/client-leaf.pem
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a value is base64(DER) of an X.509 cert before putting it in trusted_leaf_certs
func isBase64DERCert(s string) error {
	der, err := base64.StdEncoding.DecodeString(strings.TrimSpace(s))
	if err != nil {
		return err
	}
	if _, err := x509.ParseCertificate(der); err != nil {
		return fmt.Errorf("not an X.509 DER cert: %w", err)
	}
	return nil
}

Prevention

When it happens

Trigger: Putting a PEM string, a file path, or malformed base64 into the trusted_leaf_certs JSON array instead of base64-encoded DER; values that decode but are not parseable as X.509 certificates.

Common situations: Hand-building JSON configs with trust_leaf_certs copied from a PEM file; scripts that base64-encode the wrong input; migrating configs written for older Caddy versions.

Understand the failure class

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/ba7c057c979f848f. Report an issue: GitHub.