{"record":{"id":"98d3e41a5584e281","repo":"slackhq/nebula","slug":"use-of-curve25519-is-not-allowed-in-fips-140-only-98d3e4","errorCode":null,"errorMessage":"use of Curve25519 is not allowed in FIPS 140-only mode","messagePattern":"use of Curve25519 is not allowed in FIPS 140-only mode","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/nebula-cert/sign.go","lineNumber":273,"sourceCode":"\t\t}\n\t}\n\n\tvar pub, rawPriv []byte\n\tvar p11Client *pkclient.PKClient\n\n\tif isP11 {\n\t\tcurve = cert.Curve_P256\n\t\tp11Client, err = pkclient.FromUrl(*sf.p11url)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error while creating PKCS#11 client: %w\", err)\n\t\t}\n\t\tdefer func(client *pkclient.PKClient) {\n\t\t\t_ = client.Close()\n\t\t}(p11Client)\n\t}\n\n\tif fips140.Enforced() && curve == cert.Curve_CURVE25519 {\n\t\treturn errors.New(\"use of Curve25519 is not allowed in FIPS 140-only mode\")\n\t}\n\n\tif *sf.inPubPath != \"\" {\n\t\tvar pubCurve cert.Curve\n\t\trawPub, err := readInput(\"in-pub\", *sf.inPubPath, &claims)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error while reading in-pub: %s\", err)\n\t\t}\n\n\t\tpub, _, pubCurve, err = cert.UnmarshalPublicKeyFromPEM(rawPub)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error while parsing in-pub: %s\", err)\n\t\t}\n\t\tif pubCurve != curve {\n\t\t\treturn fmt.Errorf(\"curve of in-pub does not match ca\")\n\t\t}\n\t} else if isP11 {\n\t\tpub, err = p11Client.GetPubKey()","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cmd/nebula-cert/sign.go#L255-L291","documentation":"In cmd/nebula-cert/sign.go (signCert), after curve selection (including PKCS#11 paths) the code rejects cert.Curve_CURVE25519 whenever fips140.Enforced() is true. Signing a node certificate with a non-FIPS-approved curve is refused to keep the whole PKI FIPS-compliant.","triggerScenarios":"Running 'nebula-cert sign -curve 25519...' (or signing with a 25519 CA/public key) while FIPS 140-only enforcement is active; sign.go:273 checks fips140.Enforced() && curve == cert.Curve_CURVE25519.","commonSituations":"Signing existing 25519 node keys on newly FIPS-hardened hosts; mixed fleets where legacy certs are 25519 and new signing hosts enforce FIPS.","solutions":["Sign with -curve P256 (and rekey nodes with P256 keys).","Rebuild or reconfigure the environment without fips140=only if 25519 must be used.","Migrate the PKI: generate a P256 CA and re-issue all node certificates.","Use a PKCS#11 client bound to a FIPS-validated module with P256 keys."],"exampleFix":"// before\n$ nebula-cert sign -curve 25519 -in-pub node.pub ...\n\n// after\n$ nebula-cert sign -curve P256 -in-pub node.pub ...","handlingStrategy":"validation","validationCode":"if fips140.Enforced() && curve == cert.Curve_CURVE25519 {\n    return errors.New(\"sign: P256 required under FIPS 140-only mode\")\n}\n// proceed with nebula-cert sign","typeGuard":"func signableUnderFIPS(c cert.Curve) bool {\n    return c != cert.Curve_CURVE25519\n}","tryCatchPattern":"out, err := exec.Command(\"nebula-cert\", \"sign\", args...).CombinedOutput()\nif err != nil && strings.Contains(string(out), \"FIPS 140-only\") {\n    return rekeyAndSignWithP256()\n}","preventionTips":["Plan the PKI around P256 where FIPS compliance is required.","Inventory existing node keys and rekey any 25519 nodes before FIPS rollout.","Run signing pipelines against a FIPS-enforced canary first.","Keep CA and node curves consistent; mixed-curve PKIs will fail at sign time."],"tags":["fips","crypto","curve25519","signing"],"backgroundTag":"fips-only-algorithm-rejected","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}