siyuan-note/siyuan · error

failed to decode CA key PEM

Error message

failed to decode CA key PEM

What it means

loadCA decodes the CA private key with pem.Decode and returns this error when the key bytes are not valid PEM. A decodable block is then parsed as an EC private key, so anything other than a PEM 'EC PRIVATE KEY' (or encrypted/foreign format) fails either here or in the subsequent ParseECPrivateKey.

Source

Thrown at kernel/util/cert.go:274

	block, _ := pem.Decode(certPEM)
	if block == nil {
		return nil, nil, fmt.Errorf("failed to decode CA certificate PEM")
	}

	caCert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, nil, err
	}

	keyPEM, err := os.ReadFile(keyPath)
	if err != nil {
		return nil, nil, err
	}

	block, _ = pem.Decode(keyPEM)
	if block == nil {
		return nil, nil, fmt.Errorf("failed to decode CA key PEM")
	}

	caKey, err := x509.ParseECPrivateKey(block.Bytes)
	if err != nil {
		return nil, nil, err
	}

	return caCert, caKey, nil
}

func writeCertAndKey(certPath, keyPath string, certDER []byte, privateKey *ecdsa.PrivateKey) error {
	certFile, err := os.Create(certPath)
	if err != nil {
		return err
	}
	defer certFile.Close()

	if err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certDER}); err != nil {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Ensure the CA key file contains an unencrypted PEM EC private key (-----BEGIN EC PRIVATE KEY-----)
  2. Regenerate the CA and server certificate pair so formats match what the kernel generates
  3. Convert if needed: openssl ec -in key.pem -out ec-key.pem; verify with openssl ec -in ec-key.pem -check -noout

Example fix

// before: RSA PKCS#1 key saved as the CA key
caKeyPEM, _ := os.ReadFile("ca-rsa-key.pem") // -----BEGIN RSA PRIVATE KEY-----
// after: matching EC key as produced by the kernel
caKeyPEM, _ := os.ReadFile("ca.key") // -----BEGIN EC PRIVATE KEY-----
Defensive patterns

Strategy: validation

Validate before calling

const fs = require("fs");
const pem = fs.readFileSync(caKeyPath, "utf8");
if (!pem.includes("-----BEGIN EC PRIVATE KEY-----")) {
  throw new Error(`${caKeyPath} is not an unencrypted PEM EC private key`);
}

Try / catch

caCert, caKey, err := loadCA(caCertPath, caKeyPath)
if err != nil {
  log.Errorf("load CA key failed: %v", err)
  return nil, err
}

Prevention

When it happens

Trigger: GetOrCreateTLSCert or refreshCertificate loading a CA key file that is empty, holds the certificate instead of the key, contains a PKCS#1 RSA key or an encrypted PEM where an unencrypted EC key is expected, or has lost its -----BEGIN ... PRIVATE KEY----- armor.

Common situations: Manually generated CA where the key was saved in another format (RSA instead of EC, PKCS#8); key file truncated or overwritten during rotation; wrong-path config mixing up cert and key files.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/a4f66a66d2dcd4f1. Report an issue: GitHub.