router-for-me/CLIProxyAPI · error

home ca certificate pem is invalid

Error message

home ca certificate pem is invalid

What it means

Returned by certificateFingerprintPEM in internal/home/certificate.go when pem.Decode fails or the decoded block is not of type CERTIFICATE. The file passed as the home CA must be a PEM-encoded X.509 certificate; anything else (a key, a CSR, DER binary, text) is rejected before fingerprinting.

Source

Thrown at internal/home/certificate.go:202

func verifyCACertificatePEM(raw []byte, expectedFingerprint string) error {
	actual, errFingerprint := certificateFingerprintPEM(raw)
	if errFingerprint != nil {
		return errFingerprint
	}
	expected := normalizeFingerprint(expectedFingerprint)
	if expected == "" {
		return fmt.Errorf("home ca fingerprint is required")
	}
	if actual != expected {
		return fmt.Errorf("home ca fingerprint mismatch")
	}
	return nil
}

func certificateFingerprintPEM(raw []byte) (string, error) {
	block, _ := pem.Decode(raw)
	if block == nil || block.Type != "CERTIFICATE" {
		return "", fmt.Errorf("home ca certificate pem is invalid")
	}
	cert, errParse := x509.ParseCertificate(block.Bytes)
	if errParse != nil {
		return "", errParse
	}
	sum := sha256.Sum256(cert.Raw)
	return hex.EncodeToString(sum[:]), nil
}

func normalizeFingerprint(fingerprint string) string {
	fingerprint = strings.TrimSpace(strings.ToLower(fingerprint))
	fingerprint = strings.ReplaceAll(fingerprint, ":", "")
	fingerprint = strings.ReplaceAll(fingerprint, " ", "")
	return fingerprint
}

func loadOrCreateClientKey(path string) (*rsa.PrivateKey, error) {
	if fileExists(path) {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Inspect the file: head -1 ca.pem must show -----BEGIN CERTIFICATE-----
  2. If DER, convert: openssl x509 -in ca.der -inform DER -out ca.pem
  3. Re-copy the CA from the home server enrollment output and verify with openssl x509 -in ca.pem -noout

Example fix

# before (DER file used directly)
home:
  ca-cert: /etc/cliproxy/ca.der

# after
openssl x509 -in /etc/cliproxy/ca.der -inform DER -out /etc/cliproxy/ca.pem
home:
  ca-cert: /etc/cliproxy/ca.pem
Defensive patterns

Strategy: validation

Validate before calling

func isPEMCertificate(pemBytes []byte) bool {
    block, _ := pem.Decode(pemBytes)
    return block != nil && block.Type == "CERTIFICATE"
}

if raw, err := os.ReadFile(cfg.CACert); err != nil || !isPEMCertificate(raw) {
    return fmt.Errorf("ca-cert %s is not a PEM certificate", cfg.CACert)
}

Prevention

When it happens

Trigger: Passing a DER-encoded .cer, a private key PEM, a CSR PEM, an empty or truncated file, or a non-PEM file as the home CA certificate path.

Common situations: Operator saved the wrong artifact during enrollment (client cert or key where CA belongs); file truncated by a partial copy or sync tool; Windows line-ending or BOM issues are usually fine but a double-extension file (ca.pem.txt) read raw fails; Docker volume mounted the directory instead of the file.

Understand the failure class

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/206149097519932b. Report an issue: GitHub.