{"record":{"id":"65ef5c57a6609a76","repo":"slackhq/nebula","slug":"invalid-curve-v","errorCode":null,"errorMessage":"invalid curve: %v","messagePattern":"invalid curve: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/crypto.go","lineNumber":189,"sourceCode":"\t\t\t\tMemory:      kdfParams.Memory,\n\t\t\t\tParallelism: uint32(kdfParams.Parallelism),\n\t\t\t\tIterations:  kdfParams.Iterations,\n\t\t\t\tSalt:        kdfParams.salt,\n\t\t\t},\n\t\t},\n\t\tCiphertext: ciphertext,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch curve {\n\tcase Curve_CURVE25519:\n\t\treturn pem.EncodeToMemory(&pem.Block{Type: EncryptedEd25519PrivateKeyBanner, Bytes: b}), nil\n\tcase Curve_P256:\n\t\treturn pem.EncodeToMemory(&pem.Block{Type: EncryptedECDSAP256PrivateKeyBanner, Bytes: b}), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid curve: %v\", curve)\n\t}\n}\n\n// UnmarshalNebulaEncryptedData will unmarshal a protobuf byte representation of a nebula cert into its\n// protobuf-generated struct.\nfunc UnmarshalNebulaEncryptedData(b []byte) (*NebulaEncryptedData, error) {\n\tif len(b) == 0 {\n\t\treturn nil, fmt.Errorf(\"nil byte array\")\n\t}\n\tvar rned RawNebulaEncryptedData\n\terr := proto.Unmarshal(b, &rned)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rned.EncryptionMetadata == nil {\n\t\treturn nil, fmt.Errorf(\"encoded EncryptionMetadata was nil\")\n\t}","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/crypto.go#L171-L207","documentation":"EncryptAndMarshalSigningPrivateKey only supports Curve_CURVE25519 (Ed25519) and Curve_P256 (ECDSA P-256). Passing any other Curve enum value (e.g. Curve_CURVE448 or an unset/unknown value) has no PEM banner mapping, so the function fails before encoding.","triggerScenarios":"Calling EncryptAndMarshalSigningPrivateKey with a signing key and a curve argument other than Curve_CURVE25519 or Curve_P256 - typically Curve(0) from an unset field or a value deserialized from an untrusted/unknown source.","commonSituations":"Protobuf-decoding a cert whose curve field is 0/unknown and passing it straight into encryption; copying code from a P-256 example while holding a Curve25519 key (or vice versa); adding a new curve to the enum without updating this switch.","solutions":["Pass only Curve_CURVE25519 for Ed25519 keys or Curve_P256 for ECDSA P-256 keys; verify which key type you actually hold before calling","Check that the curve value was not lost/zeroed during protobuf unmarshalling - an unset proto3 enum field reads as 0 and will fail","If you need another curve, it is unsupported by this API; re-generate the key as Ed25519 or P-256"],"exampleFix":"// before\npem, err := cert.EncryptAndMarshalSigningPrivateKey(key, pass, cert.Curve_CURVE448)\n// after\npem, err := cert.EncryptAndMarshalSigningPrivateKey(key, pass, cert.Curve_CURVE25519)","handlingStrategy":"validation","validationCode":"if curve != cert.Curve_CURVE25519 && curve != cert.Curve_P256 { return fmt.Errorf(\"unsupported curve: %v\", curve) }","typeGuard":"func isSupportedCurve(c cert.Curve) bool { return c == cert.Curve_CURVE25519 || c == cert.Curve_P256 }","tryCatchPattern":"pemBytes, err := cert.EncryptAndMarshalSigningPrivateKey(key, pass, curve)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid curve\") { /* check curve value source */ }\n    return err\n}","preventionTips":["Only pass Curve_CURVE25519 or Curve_P256; remember proto3 enums default to 0 when unset","Verify the curve enum survived protobuf round-trips","Match the curve to the actual key type (Ed25519 vs ECDSA P-256)"],"tags":["crypto","curve","enum","unsupported"],"backgroundTag":"unsupported-curve","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"}