slackhq/nebula · error
curve in cert and private key supplied don't match
Error message
curve in cert and private key supplied don't match
What it means
certificateV1.VerifyPrivateKey first checks that the curve argument matches the curve recorded in the certificate details. This error means the caller supplied a curve that differs from the certificate's own curve, so the private key cannot be meaningfully validated against the cert.
Source
Thrown at cert/cert_v1.go:137
case Curve_P256:
pubKey, err := ecdsa.ParseUncompressedPublicKey(elliptic.P256(), key)
if err != nil {
return false
}
hashed := sha256.Sum256(b)
return ecdsa.VerifyASN1(pubKey, hashed[:], c.signature)
default:
return false
}
}
func (c *certificateV1) Expired(t time.Time) bool {
return c.details.notBefore.After(t) || c.details.notAfter.Before(t)
}
func (c *certificateV1) VerifyPrivateKey(curve Curve, key []byte) error {
if curve != c.details.curve {
return fmt.Errorf("curve in cert and private key supplied don't match")
}
if c.details.isCA {
switch curve {
case Curve_CURVE25519:
// the call to PublicKey below will panic slice bounds out of range otherwise
if len(key) != ed25519.PrivateKeySize {
return fmt.Errorf("key was not 64 bytes, is invalid ed25519 private key")
}
if !ed25519.PublicKey(c.details.publicKey).Equal(ed25519.PrivateKey(key).Public()) {
return fmt.Errorf("public key in cert and private key supplied don't match")
}
case Curve_P256:
privkey, err := ecdh.P256().NewPrivateKey(key)
if err != nil {
return fmt.Errorf("cannot parse private key as P256: %w", err)
}
pub := privkey.PublicKey().Bytes()View on GitHub (pinned to dd8f660c0a)
Solutions
- Pass the same curve the certificate was issued with
- Regenerate the keypair and certificate on the intended curve so they match
- Log/compare curve values to confirm which side is wrong before calling VerifyPrivateKey
Example fix
// before err := cert.VerifyPrivateKey(cert.Curve_CURVE25519, myKey) // cert is P256 // after err := cert.VerifyPrivateKey(cert.Curve(), myKey) // derive from the cert itself
Defensive patterns
Strategy: validation
Validate before calling
if curve != cert.Curve() {
return fmt.Errorf("supplied curve %s does not match cert curve %s", curve, cert.Curve())
}
err := cert.VerifyPrivateKey(curve, key) Prevention
- Pass cert.Curve() rather than a hardcoded constant
- Regenerate keys and certs together whenever the curve choice changes
- Add a startup check that key/cert curves agree
- Avoid copy-pasted curve constants from examples
When it happens
Trigger: Calling cert.VerifyPrivateKey(curve, key) on a certificateV1 where curve != c.details.curve — e.g. passing Curve_CURVE25519 for a P256 cert or vice versa.
Common situations: Hardcoded curve constant that doesn't match the CA/cert generation settings; migration from Curve25519 to P256 (or the reverse) where certs and keys were regenerated inconsistently; copying example code with the wrong Curve enum.
Related errors
- certificate curve %s does not match expected %s
- key was not 64 bytes, is invalid ed25519 private key
- invalid curve: %s
- invalid curve: %s
- invalid curve: %s
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/4c28837caacd5475.
Report an issue: GitHub.