slackhq/nebula · error

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

Error message

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

What it means

In cmd/nebula-cert/ca.go (ca), when generating a CA with a Curve25519 curve ('25519', 'X25519', 'Curve25519', 'CURVE25519') and FIPS 140-only mode is enforced (fips140.Enforced()), the tool refuses to proceed. FIPS-only mode disallows non-approved algorithms, and Curve25519/X25519 is not FIPS-approved, so CA key generation is blocked deliberately.

Source

Thrown at cmd/nebula-cert/ca.go:272

			return fmt.Errorf("invalid curve for PKCS#11: %s", *cf.curve)
		}

		p11Client, err = pkclient.FromUrl(*cf.p11url)
		if err != nil {
			return fmt.Errorf("error while creating PKCS#11 client: %w", err)
		}
		defer func(client *pkclient.PKClient) {
			_ = client.Close()
		}(p11Client)
		pub, err = p11Client.GetPubKey()
		if err != nil {
			return fmt.Errorf("error while getting public key with PKCS#11: %w", err)
		}
	} else {
		switch *cf.curve {
		case "25519", "X25519", "Curve25519", "CURVE25519":
			if fips140.Enforced() {
				return errors.New("use of Curve25519 is not allowed in FIPS 140-only mode")
			}
			curve = cert.Curve_CURVE25519
			pub, rawPriv, err = ed25519.GenerateKey(rand.Reader)
			if err != nil {
				return fmt.Errorf("error while generating ed25519 keys: %s", err)
			}
		case "P256":
			var key *ecdsa.PrivateKey
			curve = cert.Curve_P256
			key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
			if err != nil {
				return fmt.Errorf("error while generating ecdsa keys: %s", err)
			}

			// ecdh.PrivateKey lets us get at the encoded bytes, even though
			// we aren't using ECDH here.
			eKey, err := key.ECDH()
			if err != nil {

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Generate the CA with a FIPS-approved curve instead: pass -curve P256.
  2. If 25519 is required, run without FIPS 140-only enforcement (remove fips140=only GODEBUG / use a non-FIPS build).
  3. Reuse an existing FIPS-compliant CA and only sign new certs with P256.
  4. Update organizational policy/config to declare the approved curve explicitly.

Example fix

// before
$ nebula-cert ca -curve 25519

// after
$ nebula-cert ca -curve P256
Defensive patterns

Strategy: validation

Validate before calling

if fips140.Enforced() {
    if curve == "25519" || curve == "X25519" || curve == "Curve25519" || curve == "CURVE25519" {
        return fmt.Errorf("curve %s unavailable under FIPS 140-only mode; use P256", curve)
    }
}
return nebulaCertCA(curve)

Type guard

func fipsAllowedCurve(c string) bool {
    switch c {
    case "25519", "X25519", "Curve25519", "CURVE25519":
        return !fips140.Enforced()
    case "P256":
        return true
    }
    return false
}

Try / catch

err := runCA(args)
if errors.Is(err, errFipsCurve) /* or check message */ {
    log.Println("FIPS mode: falling back to P256")
    err = runCA(replaceCurve(args, "P256"))
}

Prevention

When it happens

Trigger: Running 'nebula-cert ca -curve 25519' (or any alias) while the binary/environment has FIPS 140 enforcement enabled (GODEBUG fips140=only / fips140.Enforced() true).

Common situations: Deploying nebula-cert on FIPS-mandated hosts (government/regulated environments) while reusing an existing 25519-based config; CI containers built with FIPS-only Go toolchains.

Related errors


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