fatedier/frp · error

failed to parse OIDC CA certificate from file %q

Error message

failed to parse OIDC CA certificate from file %q

What it means

The OIDC trusted CA file was read successfully but x509.NewCertPool().AppendCertsFromPEM rejected its contents: no PEM-encoded certificate blocks could be parsed from the bytes. This validates content, not access; the file exists but is not a usable CA bundle.

Source

Thrown at pkg/auth/oidc.go:56

func createOIDCHTTPClient(trustedCAFile string, insecureSkipVerify bool, proxyURL string) (*http.Client, error) {
	// Clone the default transport to get all reasonable defaults
	transport := http.DefaultTransport.(*http.Transport).Clone()

	// Configure TLS settings
	if trustedCAFile != "" || insecureSkipVerify {
		tlsConfig := &tls.Config{
			InsecureSkipVerify: insecureSkipVerify,
		}

		if trustedCAFile != "" && !insecureSkipVerify {
			caCert, err := os.ReadFile(trustedCAFile)
			if err != nil {
				return nil, fmt.Errorf("failed to read OIDC CA certificate file %q: %w", trustedCAFile, err)
			}

			caCertPool := x509.NewCertPool()
			if !caCertPool.AppendCertsFromPEM(caCert) {
				return nil, fmt.Errorf("failed to parse OIDC CA certificate from file %q", trustedCAFile)
			}

			tlsConfig.RootCAs = caCertPool
		}
		transport.TLSClientConfig = tlsConfig
	}

	// Configure proxy settings
	if proxyURL != "" {
		parsedURL, err := url.Parse(proxyURL)
		if err != nil {
			return nil, fmt.Errorf("failed to parse OIDC proxy URL %q: %w", proxyURL, err)
		}
		transport.Proxy = http.ProxyURL(parsedURL)
	} else {
		// Explicitly disable proxy to override DefaultTransport's ProxyFromEnvironment
		transport.Proxy = nil
	}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Inspect the file: it must contain '-----BEGIN CERTIFICATE-----' blocks; re-export the CA in PEM.
  2. If you have DER, convert it: openssl x509 -inform der -in ca.der -out ca.pem.
  3. Validate before starting frps: openssl x509 -in ca.pem -noout must succeed for each block.
  4. Ensure the file holds the CA or full chain, not just the server key.

Example fix

# verify/convert before starting frps
openssl x509 -in /etc/frp/oidc-ca.pem -noout || \
  openssl x509 -inform der -in /etc/frp/oidc-ca.der -out /etc/frp/oidc-ca.pem
Defensive patterns

Strategy: validation

Validate before calling

pemBytes, err := os.ReadFile(cfg.Auth.OIDC.TrustedCAFile)
if err == nil && !x509.NewCertPool().AppendCertsFromPEM(pemBytes) {
    return fmt.Errorf("OIDC CA file is not valid PEM: %s", cfg.Auth.OIDC.TrustedCAFile)
}

Type guard

func isPEMCertificateFile(path string) bool {
    b, err := os.ReadFile(path)
    if err != nil {
        return false
    }
    return x509.NewCertPool().AppendCertsFromPEM(b)
}

Prevention

When it happens

Trigger: oidc.trustedCAFile contains only a private key or leaf cert, a DER (binary) certificate, stray text around the PEM blocks, or was truncated or copied with formatting damage.

Common situations: Pointing trustedCAFile at a TLS key file instead of the CA cert; DER certificate not converted to PEM; copy/paste artifacts (missing BEGIN/END lines, CRLF, escaped newlines); empty file.

Understand the failure class

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/8d0abc3152eb37f1. Report an issue: GitHub.