{"record":{"id":"fca9c5d35c54e3e8","repo":"slackhq/nebula","slug":"certificate-curve-s-does-not-match-expected-s","errorCode":null,"errorMessage":"certificate curve %s does not match expected %s","messagePattern":"certificate curve (.+?) does not match expected (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/cert.go","lineNumber":155,"sourceCode":"\tvar c Certificate\n\tvar err error\n\n\tswitch v {\n\t// Implementations must ensure the result is a valid cert!\n\tcase VersionPre1, Version1:\n\t\tc, err = unmarshalCertificateV1(rawCertBytes, publicKey)\n\tcase Version2:\n\t\tc, err = unmarshalCertificateV2(rawCertBytes, publicKey, curve)\n\tdefault:\n\t\treturn nil, ErrUnknownVersion\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif c.Curve() != curve {\n\t\treturn nil, fmt.Errorf(\"certificate curve %s does not match expected %s\", c.Curve().String(), curve.String())\n\t}\n\n\treturn c, nil\n}\n\n// CalculateAlternateFingerprint calculates a 2nd fingerprint representation for P256 certificates\n// CAPool blocklist testing through `VerifyCertificate` and `VerifyCachedCertificate` automatically performs this step.\nfunc CalculateAlternateFingerprint(c Certificate) (string, error) {\n\tif c.Curve() != Curve_P256 {\n\t\treturn \"\", nil\n\t}\n\n\tnc := c.Copy()\n\tb, err := p256.Swap(nc.Signature())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/cert.go#L137-L173","documentation":"Recombine unmarshals a raw certificate against an expected curve and then checks that the parsed certificate's curve matches the caller-supplied curve. This error means the certificate was issued on a different elliptic curve than the one the caller declared (e.g. passing Curve_CURVE25519 while the cert is P256).","triggerScenarios":"Calling Recombine(publicKey, rawCertBytes, vpe, curve) where c.Curve() != curve — typically a Version2 cert (or an expected curve passed to v1 unmarshal path) whose embedded curve differs from the expected parameter.","commonSituations":"Mixing P256 and Curve25519 artifacts during migration between cert versions/curves; hardcoding the wrong curve constant; loading a cert bundle where v2 certs use a different curve than the handshake's key curve.","solutions":["Pass the curve the certificate was actually issued with (check the cert's curve before calling Recombine)","Re-issue the certificate on the expected curve","Ensure keypair generation and cert signing use the same curve"],"exampleFix":"// before\nc, err := cert.Recombine(pubKey, raw, vpe, cert.Curve_CURVE25519) // cert is P256\n// after\nexpected := detectCurve(raw) // e.g. from cert metadata\nc, err := cert.Recombine(pubKey, raw, vpe, expected)","handlingStrategy":"validation","validationCode":"if c.Curve() != expectedCurve {\n    return fmt.Errorf(\"refusing Recombine: cert curve %s != expected %s\", c.Curve(), expectedCurve)\n}\ncert, err := cert.Recombine(pubKey, raw, vpe, expectedCurve)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Derive the curve from the cert/key material instead of hardcoding","Keep curve consistent across CA signing, key generation, and handshake","Test mixed-curve artifacts in CI to catch migration mistakes","Check for a curve-mismatch guard (ErrCurveMismatch) elsewhere in the pipeline"],"tags":["certificate","curve","mismatch","ecdsa"],"backgroundTag":"certificate-curve-mismatch","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"}