slackhq/nebula · error
can not sign a CA certificate with another
Error message
can not sign a CA certificate with another
What it means
SignWith refuses to sign a CA certificate (t.IsCA == true) when an explicit signer certificate is supplied. The library forbids CA-to-CA signing: an existing CA must never be signed by another CA, since CAs are self-signed roots. This is a deliberate security invariant of nebula's PKI.
Source
Thrown at cert/sign.go:84
hashed := sha256.Sum256(certBytes)
return ecdsa.SignASN1(rand.Reader, pk, hashed[:])
}
return t.SignWith(signer, curve, sp)
default:
return nil, fmt.Errorf("invalid curve: %s", t.Curve)
}
}
// SignWith does the same thing as sign, but uses the function in `sp` to calculate the signature.
// You should only use SignWith if you do not have direct access to your private key.
func (t *TBSCertificate) SignWith(signer Certificate, curve Curve, sp SignerLambda) (Certificate, error) {
if curve != t.Curve {
return nil, fmt.Errorf("curve in cert and private key supplied don't match")
}
if signer != nil {
if t.IsCA {
return nil, fmt.Errorf("can not sign a CA certificate with another")
}
err := checkCAConstraints(signer, t.NotBefore, t.NotAfter, t.Groups, t.Networks, t.UnsafeNetworks)
if err != nil {
return nil, err
}
issuer, err := signer.Fingerprint()
if err != nil {
return nil, fmt.Errorf("error computing issuer: %v", err)
}
t.issuer = issuer
} else {
if !t.IsCA {
return nil, fmt.Errorf("self signed certificates must have IsCA set to true")
}
}
View on GitHub (pinned to dd8f660c0a)
Solutions
- Set t.IsCA = false when the certificate is meant to be signed by an existing CA.
- If you truly want a new CA, pass signer = nil so it is self-signed (IsCA must then be true).
- Check the CLI flags: do not pass both -ca and a signing key/cert combination that implies CA signing.
Example fix
// before
cert := cert.NebulaCertificate{Details: cert.NebulaCertificateDetails{IsCA: true}}
signed, err := cert.Sign(caCert, caKey, cert)
// after
cert := cert.NebulaCertificate{Details: cert.NebulaCertificateDetails{IsCA: false}}
signed, err := cert.Sign(caCert, caKey, cert) Defensive patterns
Strategy: validation
Validate before calling
if t.Details.IsCA && signer != nil {
return fmt.Errorf("refusing to sign: IsCA is true and a signer was provided")
} Try / catch
signed, err := cert.Sign(signer, key, t)
if err != nil {
if strings.Contains(err.Error(), "can not sign a CA certificate") {
// fix IsCA or signer selection
}
return err
} Prevention
- Only set IsCA: true in code paths that self-sign (nil signer).
- Centralize certificate construction in one helper that enforces IsCA/signer invariants.
- Review CLI flag combinations that pass both a CA flag and a signer.
When it happens
Trigger: Calling SignWith (directly or via cert.Sign or cmd/nebula-cert signCert/ca) with a t whose IsCA field is true while passing a non-nil signer certificate.
Common situations: Users trying to chain CAs (intermediate CA signed by a root CA), reusing the CA-signing flag (-ca) with an existing signer, or copy-pasting CA-generation code but accidentally still passing a signer.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- error while adding CA certificate to CA trust store: %s
- no certificates found in pki.cert
- no pki.ca path or PEM data provided
- no valid CA certificates present
- %s: %w
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/27af0eabbd6ff063.
Report an issue: GitHub.