slackhq/nebula · error

no certificate

Error message

no certificate

What it means

CAPool.VerifyCertificate returns the plain error 'no certificate' when the passed Certificate is nil. Verification cannot proceed without a certificate, and the nil check short-circuits before any fingerprinting or chain validation.

Source

Thrown at cert/ca_pool.go:159

	ncp.certBlocklist = make(map[string]struct{})
}

// IsBlocklisted tests the provided fingerprint against the pools blocklist.
// Returns true if the fingerprint is blocked.
func (ncp *CAPool) IsBlocklisted(fingerprint string) bool {
	if _, ok := ncp.certBlocklist[fingerprint]; ok {
		return true
	}

	return false
}

// VerifyCertificate verifies the certificate is valid and is signed by a trusted CA in the pool.
// If the certificate is valid then the returned CachedCertificate can be used in subsequent verification attempts
// to increase performance.
func (ncp *CAPool) VerifyCertificate(now time.Time, c Certificate) (*CachedCertificate, error) {
	if c == nil {
		return nil, fmt.Errorf("no certificate")
	}
	fp, err := c.Fingerprint()
	if err != nil {
		return nil, fmt.Errorf("could not calculate fingerprint to verify: %w", err)
	}

	signer, err := ncp.verify(c, now, fp, "")
	if err != nil {
		return nil, err
	}

	// Pre nebula v1.10.3 could generate signatures in either high or low s form and validation
	// of signatures allowed for either. Nebula v1.10.3 and beyond clamps signature generation to low-s form
	// but validation still allows for either. Since a change in the signature bytes affects the fingerprint, we
	// need to test both forms until such a time comes that we enforce low-s form on signature validation.
	fp2, err := CalculateAlternateFingerprint(c)
	if err != nil {
		return nil, fmt.Errorf("could not calculate alternate fingerprint to verify: %w", err)

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Check the certificate for nil before calling VerifyCertificate
  2. Handle errors from the certificate parsing/decoding step so a nil cert is never passed
  3. Log and reject the connection early when no peer certificate is available

Example fix

// before
cc, err := pool.VerifyCertificate(now, parsedCert) // parsedCert may be nil
// after
if parsedCert == nil {
    return fmt.Errorf("peer did not present a certificate")
}
cc, err := pool.VerifyCertificate(now, parsedCert)
Defensive patterns

Strategy: type-guard

Validate before calling

if c == nil {
    return fmt.Errorf("no peer certificate available for verification")
}
_, err := pool.VerifyCertificate(now, c)

Type guard

func hasCertificate(c cert.Certificate) bool {
    return c != nil
}

Try / catch

cc, err := pool.VerifyCertificate(now, c)
if err != nil {
    if err.Error() == "no certificate" {
        log.Warn("peer presented no certificate; rejecting handshake")
        return err
    }
    return err
}

Prevention

When it happens

Trigger: Calling VerifyCertificate(now, c) with c == nil — typically when a decoded certificate variable was never populated because PEM decoding or certificate parsing failed upstream.

Common situations: Ignoring errors from earlier ParseCertificate/PEM decode steps and passing the nil result on, or optional certificate lookups (e.g. from a handshake cache) returning nil.

Understand the failure class

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/5ea9bbede593fe05. Report an issue: GitHub.