slackhq/nebula · error
certificate expires after signing certificate
Error message
certificate expires after signing certificate
What it means
checkCAConstraints enforces that a signed certificate's validity window fits inside the signer's. This error means the certificate's notAfter is later than the signing CA's notAfter, i.e. the cert would outlive its issuer. It is returned both when checking existing certs (CheckCAConstraints) and when signing new ones (SignWith).
Source
Thrown at cert/ca_pool.go:290
i := 0
for k := range ncp.CAs {
fp[i] = k
i++
}
return fp
}
// CheckCAConstraints returns an error if the sub certificate violates constraints present in the signer certificate.
func CheckCAConstraints(signer Certificate, sub Certificate) error {
return checkCAConstraints(signer, sub.NotBefore(), sub.NotAfter(), sub.Groups(), sub.Networks(), sub.UnsafeNetworks())
}
// checkCAConstraints is a very generic function allowing both Certificates and TBSCertificates to be tested.
func checkCAConstraints(signer Certificate, notBefore, notAfter time.Time, groups []string, networks, unsafeNetworks []netip.Prefix) error {
// Make sure this cert isn't valid after the root
if notAfter.After(signer.NotAfter()) {
return fmt.Errorf("certificate expires after signing certificate")
}
// Make sure this cert wasn't valid before the root
if notBefore.Before(signer.NotBefore()) {
return fmt.Errorf("certificate is valid before the signing certificate")
}
// If the signer has a limited set of groups make sure the cert only contains a subset
signerGroups := signer.Groups()
if len(signerGroups) > 0 {
for _, g := range groups {
if !slices.Contains(signerGroups, g) {
return fmt.Errorf("certificate contained a group not present on the signing ca: %s", g)
}
}
}
// If the signer has a limited set of ip ranges to issue from make sure the cert only contains a subsetView on GitHub (pinned to dd8f660c0a)
Solutions
- Shorten the certificate's notAfter to be <= the signing CA's notAfter
- Renew/extend the CA certificate's validity, then re-sign
- Use SignWith with an expiry computed as min(desired, signer.NotAfter())
Example fix
// before
nc, err := ca.SignWith(pubKey, curve, opts) // opts.NotAfter after CA expiry
// after
expiry := desiredExpiry
if ca.NotAfter().Before(expiry) {
expiry = ca.NotAfter()
}
opts.NotAfter = expiry
nc, err := ca.SignWith(pubKey, curve, opts) Defensive patterns
Strategy: validation
Validate before calling
if sub.NotAfter().After(signer.NotAfter()) {
return fmt.Errorf("cert would outlive its CA; renew CA or shorten cert validity")
}
err := pool.CheckCAConstraints(signer, sub) Prevention
- Set leaf cert validity well inside CA validity (e.g. CA life / 2)
- Compute SignWith expiry as min(desired, ca.NotAfter())
- Alert on CAs approaching expiry before issuing new certs
- Review cert lifetimes in CI when generation configs change
When it happens
Trigger: Calling CAPool.CheckCAConstraints(signer, sub) where sub.NotAfter() is after signer.NotAfter(); or SignWith with an expiry parameter beyond the signing CA's expiration.
Common situations: Issuing a 10-year host certificate signed by a 1-year CA; config generators defaulting cert lifetime independently of CA lifetime; renewing the CA with a shorter validity than long-lived leaf certs.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- certificate is valid before the signing certificate
- certificate contained a group not present on the signing ca:
- certificate contained a network assignment outside the limit
- certificate contained an unsafe network assignment outside t
- ErrBadFormat
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/8ab83d51cba1b9a3.
Report an issue: GitHub.