siyuan-note/siyuan · error

failed to parse CA private key: %w

Error message

failed to parse CA private key: %w

What it means

Returned by ImportCABundle when x509.ParseECPrivateKey fails on the decoded key block bytes. ImportCABundle only accepts an EC private key (SEC1, PEM type `EC PRIVATE KEY`). RSA keys, PKCS#8-wrapped keys, or malformed EC keys all fail here.

Source

Thrown at kernel/util/cert.go:337

	}

	caCert, err := x509.ParseCertificate(certBlock.Bytes)
	if err != nil {
		return fmt.Errorf("failed to parse CA certificate: %w", err)
	}

	if !caCert.IsCA {
		return fmt.Errorf("the provided certificate is not a CA certificate")
	}

	keyBlock, _ := pem.Decode([]byte(caKeyPEM))
	if keyBlock == nil {
		return fmt.Errorf("failed to decode CA private key PEM")
	}

	_, err = x509.ParseECPrivateKey(keyBlock.Bytes)
	if err != nil {
		return fmt.Errorf("failed to parse CA private key: %w", err)
	}

	caCertPath := filepath.Join(ConfDir, TLSCACertFilename)
	caKeyPath := filepath.Join(ConfDir, TLSCAKeyFilename)

	if err := os.WriteFile(caCertPath, []byte(caCertPEM), 0644); err != nil {
		return fmt.Errorf("failed to write CA certificate: %w", err)
	}

	if err := os.WriteFile(caKeyPath, []byte(caKeyPEM), 0600); err != nil {
		return fmt.Errorf("failed to write CA private key: %w", err)
	}

	certPath := filepath.Join(ConfDir, TLSCertFilename)
	keyPath := filepath.Join(ConfDir, TLSKeyFilename)

	if gulu.File.IsExist(certPath) {
		os.Remove(certPath)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Generate/provide an EC (P-256) private key in SEC1 PEM form.
  2. Convert RSA or PKCS#8 keys: `openssl ecparam -name prime256v1 -genkey -noout -out ca.key` for a fresh EC key, or `openssl pkcs8 -topk8 -nocrypt -in pkcs8.pem -out sec1.pem` then ensure SEC1 EC encoding.
  3. Match the key to the cert: the public key in caCertPEM must correspond to caKeyPEM.

Example fix

// before: RSA key rejected by ParseECPrivateKey
ImportCABundle(certPEM, rsaKeyPEM) // -> failed to parse CA private key

// after: generate an EC P-256 key pair and use that
// openssl ecparam -name prime256v1 -genkey -noout -out ca.key
ImportCABundle(certPEM, ecSec1KeyPEM)
Defensive patterns

Strategy: try-catch

Try / catch

if err := util.ImportCABundle(certPEM, keyPEM); err != nil {
    if strings.Contains(err.Error(), "failed to parse CA private key") {
        // Only SEC1 EC keys are accepted; RSA / PKCS#8 / malformed all fail here
        return fmt.Errorf("%v; supply a P-256 EC key in SEC1 PEM form", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling ImportCABundle with a private key that is not a SEC1 EC private key — e.g. an RSA key (`-----BEGIN RSA PRIVATE KEY-----`), a PKCS#8 `PRIVATE KEY`, or a corrupted EC key.

Common situations: Trying to reuse an existing RSA CA key with SiYuan's local TLS (which is ECDSA/P-256 based); supplying a PKCS#8-encoded EC key without converting to SEC1.

Understand the failure class

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/db8b58468d19cd74. Report an issue: GitHub.