{"record":{"id":"f240dadacbadbca9","repo":"siyuan-note/siyuan","slug":"the-provided-certificate-is-not-a-ca-certificate","errorCode":null,"errorMessage":"the provided certificate is not a CA certificate","messagePattern":"the provided certificate is not a CA certificate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/cert.go","lineNumber":327,"sourceCode":"\t}\n\n\treturn nil\n}\n\n// ImportCABundle imports a CA certificate and private key from PEM-encoded strings.\nfunc ImportCABundle(caCertPEM, caKeyPEM string) error {\n\tcertBlock, _ := pem.Decode([]byte(caCertPEM))\n\tif certBlock == nil {\n\t\treturn fmt.Errorf(\"failed to decode CA certificate PEM\")\n\t}\n\n\tcaCert, err := x509.ParseCertificate(certBlock.Bytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CA certificate: %w\", err)\n\t}\n\n\tif !caCert.IsCA {\n\t\treturn fmt.Errorf(\"the provided certificate is not a CA certificate\")\n\t}\n\n\tkeyBlock, _ := pem.Decode([]byte(caKeyPEM))\n\tif keyBlock == nil {\n\t\treturn fmt.Errorf(\"failed to decode CA private key PEM\")\n\t}\n\n\t_, err = x509.ParseECPrivateKey(keyBlock.Bytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CA private key: %w\", err)\n\t}\n\n\tcaCertPath := filepath.Join(ConfDir, TLSCACertFilename)\n\tcaKeyPath := filepath.Join(ConfDir, TLSCAKeyFilename)\n\n\tif err := os.WriteFile(caCertPath, []byte(caCertPEM), 0644); err != nil {\n\t\treturn fmt.Errorf(\"failed to write CA certificate: %w\", err)\n\t}","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/cert.go#L309-L345","documentation":"ImportCABundle requires that the supplied certificate actually be a Certificate Authority (CA). After parsing succeeds, it checks caCert.IsCA; if the BasicConstraints CA flag is false the import is rejected because the cert cannot sign the server/leaf certificates the TLS layer will issue or verify.","triggerScenarios":"Importing a leaf/server or client certificate PEM instead of the CA certificate; the PEM parses as valid X.509 but its BasicConstraints extension does not assert CA:TRUE.","commonSituations":"Copying the server cert (cert.pem) rather than the CA cert when setting up HTTPS for the workspace; using a self-signed end-entity certificate as the trust anchor.","solutions":["Import the CA certificate (the one that signed your server cert), not the server certificate itself","If you only have a leaf cert, generate a proper CA first (openssl req -x509 -new ...) and issue a server cert from it","Confirm CA status with 'openssl x509 -text -noout -in ca.crt' — look for 'CA:TRUE' under X509v3 Basic Constraints"],"exampleFix":"// before\nImportCABundle(serverCertPEM, caKeyPEM) // leaf cert rejected\n// after\nImportCABundle(caCertPEM, caKeyPEM) // cert with CA:TRUE BasicConstraints","handlingStrategy":"validation","validationCode":"func isCACert(pemStr string) bool {\n    block, _ := pem.Decode([]byte(pemStr))\n    if block == nil { return false }\n    cert, err := x509.ParseCertificate(block.Bytes)\n    return err == nil && cert.IsCA\n}","typeGuard":"if cert, err := x509.ParseCertificate(block.Bytes); err != nil || !cert.IsCA { return errors.New(\"not a CA certificate\") }","tryCatchPattern":"if err := util.ImportCABundle(caCertPEM, caKeyPEM); err != nil {\n    if strings.Contains(err.Error(), \"not a CA certificate\") {\n        // prompt user to select the CA cert, not the server cert\n    }\n}","preventionTips":["Keep CA and server certificates in clearly named separate files (ca.crt vs server.crt)","Check 'CA:TRUE' in Basic Constraints before importing","Generate the CA with a tool that sets BasicConstraints CA:TRUE by default"],"tags":["tls","certificate","ca","x509"],"backgroundTag":"invalid-argument-value","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}