slackhq/nebula · error

pki: use of ChaChaPoly is not allowed in FIPS 140-only mode

Error message

pki: use of ChaChaPoly is not allowed in FIPS 140-only mode

What it means

newCipherSuite rejects the ChaCha20-Poly1305 Noise cipher when FIPS 140-only mode is enforced, since ChaChaPoly is not a FIPS-approved AEAD. The check runs after the DH curve is resolved: any cipher == "chachapoly" with fips140Enforced set returns this error instead of building the cipher suite.

Source

Thrown at pki.go:265

	switch curve {
	case cert.Curve_CURVE25519:
		if fips140Enforced {
			return nil, errors.New("pki: use of Curve25519 is not allowed in FIPS 140-only mode")
		}
		dhFunc = noise.DH25519
	case cert.Curve_P256:
		if pkcs11backed {
			dhFunc = noiseutil.DHP256PKCS11
		} else {
			dhFunc = noiseutil.DHP256
		}
	default:
		return nil, fmt.Errorf("unsupported curve: %s", curve)
	}

	if cipher == "chachapoly" {
		if fips140Enforced {
			return nil, errors.New("pki: use of ChaChaPoly is not allowed in FIPS 140-only mode")
		}
		return noise.NewCipherSuite(dhFunc, noise.CipherChaChaPoly, noise.HashSHA256), nil
	}
	return noise.NewCipherSuite(dhFunc, noiseutil.CipherAESGCM, noise.HashSHA256), nil
}

func (cs *CertState) String() string {
	b, err := cs.MarshalJSON()
	if err != nil {
		return fmt.Sprintf("error marshaling certificate state: %v", err)
	}
	return string(b)
}

func (cs *CertState) MarshalJSON() ([]byte, error) {
	msg := []json.RawMessage{}
	if cs.v1Cert != nil {
		b, err := cs.v1Cert.MarshalJSON()

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Change the cipher configuration from "chachapoly" to AES-GCM (default path via noiseutil.CipherAESGCM), which is FIPS-approved.
  2. If policy allows, disable FIPS 140-only mode so ChaChaPoly remains available.
  3. Roll the config change fleet-wide with startup validation that rejects chachapoly under FIPS enforcement.
  4. Confirm AES-NI/hardware AES support on the hosts so AES-GCM performance is acceptable.
  5. Document cipher requirements per environment so FIPS and non-FIPS fleets use distinct config templates.

Example fix

// before: config.toml on a FIPS host
[metrics/pki]
cipher = "chachapoly"
// after
cipher = "aesgcm"
// startup validation:
if fips140Enforced && cipher == "chachapoly" {
    return fmt.Errorf("config error: chachapoly is not FIPS approved; use aesgcm")
}
Defensive patterns

Strategy: fallback

Validate before calling

// Go: reject unsafe cipher config before starting
if fips140Enforced && cipher == "chachapoly" {
    return fmt.Errorf("cipher chachapoly is not allowed in FIPS mode; use aesgcm")
}

Try / catch

cs, err := newCipherSuite(curve, pkcs11backed, cipher, fips140Enforced)
if err != nil && strings.Contains(err.Error(), "ChaChaPoly is not allowed in FIPS") {
    log.Warn("falling back to AES-GCM for FIPS compliance")
    cs, err = newCipherSuite(curve, pkcs11backed, "aesgcm", fips140Enforced)
}
if err != nil {
    return err
}

Prevention

When it happens

Trigger: Node configuration selects cipher "chachapoly" (the Noise ChaChaPoly suite) while FIPS 140-only mode is enforced (GODEBUG=fips140=only or FIPS-enforcing OS), causing newCipherSuite to return this error during newCertState/cipher suite construction.

Common situations: FIPS-host deployments retaining default/non-FIPS configs specifying chachapoly; mixed fleets where a template written for non-FIPS nodes is applied to FIPS nodes; enabling FIPS mode via environment/OS update without revisiting cipher settings.

Related errors


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