slackhq/nebula · error
certificate curve %s does not match expected %s
Error message
certificate curve %s does not match expected %s
What it means
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).
Source
Thrown at cert/cert.go:155
var c Certificate
var err error
switch v {
// Implementations must ensure the result is a valid cert!
case VersionPre1, Version1:
c, err = unmarshalCertificateV1(rawCertBytes, publicKey)
case Version2:
c, err = unmarshalCertificateV2(rawCertBytes, publicKey, curve)
default:
return nil, ErrUnknownVersion
}
if err != nil {
return nil, err
}
if c.Curve() != curve {
return nil, fmt.Errorf("certificate curve %s does not match expected %s", c.Curve().String(), curve.String())
}
return c, nil
}
// CalculateAlternateFingerprint calculates a 2nd fingerprint representation for P256 certificates
// CAPool blocklist testing through `VerifyCertificate` and `VerifyCachedCertificate` automatically performs this step.
func CalculateAlternateFingerprint(c Certificate) (string, error) {
if c.Curve() != Curve_P256 {
return "", nil
}
nc := c.Copy()
b, err := p256.Swap(nc.Signature())
if err != nil {
return "", err
}
View on GitHub (pinned to dd8f660c0a)
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
Example fix
// before c, err := cert.Recombine(pubKey, raw, vpe, cert.Curve_CURVE25519) // cert is P256 // after expected := detectCurve(raw) // e.g. from cert metadata c, err := cert.Recombine(pubKey, raw, vpe, expected)
Defensive patterns
Strategy: validation
Validate before calling
if c.Curve() != expectedCurve {
return fmt.Errorf("refusing Recombine: cert curve %s != expected %s", c.Curve(), expectedCurve)
}
cert, err := cert.Recombine(pubKey, raw, vpe, expectedCurve) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- curve in cert and private key supplied don't match
- invalid curve: %s
- invalid curve: %s
- invalid curve: %s
- pki: use of %s is not allowed in FIPS 140-only mode
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/fca9c5d35c54e3e8.
Report an issue: GitHub.