slackhq/nebula · error

invalid curve: %s

Error message

invalid curve: %s

What it means

VerifyPrivateKey validates that a private key matches a CA certificate. The switch over curve only handles Curve_CURVE25519 and Curve_P256; any other curve value reaches this default branch. It means the caller passed a curve the library cannot verify, not that the key bytes are wrong.

Source

Thrown at cert/cert_v2.go:199

			// the call to PublicKey below will panic slice bounds out of range otherwise
			if len(key) != ed25519.PrivateKeySize {
				return ErrInvalidPrivateKey
			}

			if !ed25519.PublicKey(c.publicKey).Equal(ed25519.PrivateKey(key).Public()) {
				return ErrPublicPrivateKeyMismatch
			}
		case Curve_P256:
			privkey, err := ecdh.P256().NewPrivateKey(key)
			if err != nil {
				return ErrInvalidPrivateKey
			}
			pub := privkey.PublicKey().Bytes()
			if !bytes.Equal(pub, c.publicKey) {
				return ErrPublicPrivateKeyMismatch
			}
		default:
			return fmt.Errorf("invalid curve: %s", curve)
		}
		return nil
	}

	var pub []byte
	switch curve {
	case Curve_CURVE25519:
		var err error
		pub, err = curve25519.X25519(key, curve25519.Basepoint)
		if err != nil {
			return ErrInvalidPrivateKey
		}
	case Curve_P256:
		privkey, err := ecdh.P256().NewPrivateKey(key)
		if err != nil {
			return ErrInvalidPrivateKey
		}
		pub = privkey.PublicKey().Bytes()

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Only call VerifyPrivateKey with Curve_CURVE25519 or Curve_P256; check the curve value before calling.
  2. Ensure the certificate was produced by a compatible version of this library; re-generate certificates with supported curves.
  3. Re-serialize/re-parse the certificate with a current proto schema if the curve value came from decoding an unknown enum number.

Example fix

// before
err := caCert.VerifyPrivateKey(cert.Curve(3), keyBytes)
// after
if curve != cert.Curve_CURVE25519 && curve != cert.Curve_P256 {
    return fmt.Errorf("unsupported curve %v", curve)
}
err := caCert.VerifyPrivateKey(curve, keyBytes)
Defensive patterns

Strategy: validation

Validate before calling

if curve != cert.Curve_CURVE25519 && curve != cert.Curve_P256 {
    return fmt.Errorf("curve %v unsupported by VerifyPrivateKey", curve)
}
err := caCert.VerifyPrivateKey(curve, keyBytes)

Type guard

func supportedCurve(c cert.Curve) bool {
    return c == cert.Curve_CURVE25519 || c == cert.Curve_P256
}

Try / catch

if err := caCert.VerifyPrivateKey(curve, key); err != nil {
    if strings.HasPrefix(err.Error(), "invalid curve:") {
        return fmt.Errorf("unsupported curve %v; use CURVE25519 or P256", curve)
    }
    return err
}

Prevention

When it happens

Trigger: Calling certificateV2.VerifyPrivateKey(curve, key) on a CA certificate with any Curve value other than Curve_CURVE25519 or Curve_P256 (e.g. an unmarshalled proto enum with an out-of-range or reserved value).

Common situations: Certificates deserialized from a newer/older protobuf with an unknown curve number, hand-constructed certificates in tests, or code that forwards a raw integer cast to Curve without checking.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/e14680f26b126104. Report an issue: GitHub.