{"record":{"id":"7cf957acc74fa729","repo":"slackhq/nebula","slug":"curve-in-cert-and-private-key-supplied-don-t-match-7cf957","errorCode":null,"errorMessage":"curve in cert and private key supplied don't match","messagePattern":"curve in cert and private key supplied don't match","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/sign.go","lineNumber":79,"sourceCode":"\t\t\treturn nil, err\n\t\t}\n\t\tsp := func(certBytes []byte) ([]byte, error) {\n\t\t\t// We need to hash first for ECDSA\n\t\t\t// - https://pkg.go.dev/crypto/ecdsa#SignASN1\n\t\t\thashed := sha256.Sum256(certBytes)\n\t\t\treturn ecdsa.SignASN1(rand.Reader, pk, hashed[:])\n\t\t}\n\t\treturn t.SignWith(signer, curve, sp)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid curve: %s\", t.Curve)\n\t}\n}\n\n// SignWith does the same thing as sign, but uses the function in `sp` to calculate the signature.\n// You should only use SignWith if you do not have direct access to your private key.\nfunc (t *TBSCertificate) SignWith(signer Certificate, curve Curve, sp SignerLambda) (Certificate, error) {\n\tif curve != t.Curve {\n\t\treturn nil, fmt.Errorf(\"curve in cert and private key supplied don't match\")\n\t}\n\n\tif signer != nil {\n\t\tif t.IsCA {\n\t\t\treturn nil, fmt.Errorf(\"can not sign a CA certificate with another\")\n\t\t}\n\n\t\terr := checkCAConstraints(signer, t.NotBefore, t.NotAfter, t.Groups, t.Networks, t.UnsafeNetworks)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tissuer, err := signer.Fingerprint()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error computing issuer: %v\", err)\n\t\t}\n\t\tt.issuer = issuer\n\t} else {","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/sign.go#L61-L97","documentation":"TBSCertificate.SignWith checks that the curve argument passed in matches the certificate's own t.Curve before delegating to the signer lambda. A mismatch means the private key/signer supplied corresponds to a different curve than the certificate declares (e.g. an Ed25519 key for a P256 cert), producing a signature that would not verify. The library fails fast instead.","triggerScenarios":"Call SignWith(signer, curve, sp) — directly or via Sign — where curve != t.Curve: e.g. a TBSCertificate built with Curve_P256 but signed with a Curve_CURVE25519 key, or a hardcoded curve argument that disagrees with the TBS struct.","commonSituations":"Mixing key types in test helpers (NewTestCert with mismatched key), migrating certificates from Curve25519 to P256 while reusing old signing keys, or copy/pasted signing code passing the wrong Curve constant.","solutions":["Pass the same curve the TBSCertificate was created with (check t.Curve and supply it as the curve argument)","Use a signing key whose type matches the certificate curve (Ed25519 key for CURVE25519 certs, P256 key for P256 certs)","If migrating curves, regenerate both the cert details and the signing key together"],"exampleFix":"// before\ncert, err := tbs.SignWith(signer, nebula.Curve_P256, sp) // tbs.Curve == Curve_CURVE25519\n// after\ncert, err := tbs.SignWith(signer, tbs.Curve, sp)","handlingStrategy":"validation","validationCode":"if curve != tbs.Curve {\n    return fmt.Errorf(\"signing key curve %v does not match certificate curve %v\", curve, tbs.Curve)\n}","typeGuard":"func curvesMatch(tbs *nebula.TBSCertificate, c nebula.Curve) bool { return tbs.Curve == c }","tryCatchPattern":"cert, err := tbs.SignWith(signer, curve, sp)\nif err != nil {\n    return nil, fmt.Errorf(\"certificate curve and signing key curve disagree: %w\", err)\n}","preventionTips":["Derive the curve argument from the signing key type, not a hardcoded constant","When rotating from Curve25519 to P256, regenerate cert details and keys together","Keep a single source of truth for the curve in your cert-generation code"],"tags":["certificate","curve-mismatch","signing","key-type"],"backgroundTag":"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"}