slackhq/nebula · error

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

Error message

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

What it means

newCipherSuite refuses to use Curve25519 as the Noise DH function when FIPS 140-only mode is enforced, because Curve25519 is not an approved primitive under FIPS 140-3. The caller (newCertState) passes fips140Enforced (derived from crypto/fips140.Enforced()) and this check runs before any key exchange is set up.

Source

Thrown at pki.go:250

	case cert.Version1:
		return cs.v1Cert
	case cert.Version2:
		return cs.v2Cert
	}

	return nil
}

// newCipherSuite builds the noise.CipherSuite for the given curve and cipher.
// When fips140Enforced is true (FIPS 140-only mode), non-approved algorithms
// (Curve25519 and ChaChaPoly) are rejected with an error. Callers pass
// fips140.Enforced() for fips140Enforced.
func newCipherSuite(curve cert.Curve, pkcs11backed bool, cipher string, fips140Enforced bool) (noise.CipherSuite, error) {
	var dhFunc noise.DHFunc
	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
	}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Switch the pki curve configuration from CURVE25519 to cert.Curve_P256, which is FIPS-approved.
  2. Disable FIPS 140-only mode (remove GODEBUG=fips140=only / disable OS FIPS mode) only if policy permits.
  3. Regenerate/reissue node certificates signed for P256 so handshakes negotiate the compliant curve.
  4. Validate config at startup: fail fast with a clear message when FIPS mode and Curve25519 are combined.
  5. Update fleet provisioning templates so FIPS environments always emit P256 curve settings.

Example fix

// before: config.toml on a FIPS host
pki = { curve = "CURVE25519" }
// after
pki = { curve = "P256" }
// or startup validation:
if fips140Enforced && curve == cert.Curve_CURVE25519 {
    return fmt.Errorf("config error: curve25519 is not FIPS approved; set pki.curve = P256")
}
Defensive patterns

Strategy: fallback

Validate before calling

// Go: reject unsafe config before starting
if fips140Enforced && curve == cert.Curve_CURVE25519 {
    return fmt.Errorf("pki.curve CURVE25519 is not allowed in FIPS mode; use P256")
}

Try / catch

cs, err := newCipherSuite(curve, pkcs11backed, cipher, fips140.Enforced())
if err != nil && strings.Contains(err.Error(), "Curve25519 is not allowed in FIPS") {
    log.Warn("falling back to P256 for FIPS compliance")
    cs, err = newCipherSuite(cert.Curve_P256, pkcs11backed, cipher, fips140Enforced)
}
if err != nil {
    return err
}

Prevention

When it happens

Trigger: Starting a node whose certificate/curve configuration selects cert.Curve_CURVE25519 while the process runs with FIPS 140-only mode enabled (e.g. GODEBUG=fips140=only, or FIPS-enforcing environment), so newCipherSuite returns this error at cipher-suite construction time.

Common situations: Deploying on FIPS-mandated hosts (RHEL/Fedora FIPS mode, gov clouds) with a default pki config that still uses Curve25519; upgrading a binary with FIPS enforcement newly enabled; copying a non-FIPS config into a FIPS cluster.

Related errors


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