slackhq/nebula · error
cannot parse private key as P256: %w
Error message
cannot parse private key as P256: %w
What it means
VerifyPrivateKey's P256 branch parses the raw private key bytes with crypto/ecdh's P256 NewPrivateKey before deriving the public key. If the bytes are not a valid scalar in the P256 field (wrong length, leading issues, not a real key), the parse fails and this error wraps the underlying reason.
Source
Thrown at cert/cert_v1.go:153
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()
if !bytes.Equal(pub, c.details.publicKey) {
return fmt.Errorf("public key in cert and private key supplied don't match")
}
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 errView on GitHub (pinned to dd8f660c0a)
Solutions
- Confirm the certificate's curve matches the key's curve and pass the correct curve constant
- Strip PEM armor and decode base64 so only the raw key bytes are passed
- Re-issue the keypair/certificate for the intended curve if the key was generated for a different curve
- Inspect the wrapped error (%w) to see the exact ecdh parse failure
Example fix
// before cert.VerifyPrivateKey(key, cert.Curve_P256, ed25519KeyBytes) // cannot parse as P256 // after p256Key := generateP256KeyRaw() // raw 32-byte P256 scalar cert.VerifyPrivateKey(key, cert.Curve_P256, p256Key)
Defensive patterns
Strategy: validation
Validate before calling
func isRawP256Key(b []byte) bool {
_, err := ecdh.P256().NewPrivateKey(b)
return err == nil
}
if !isRawP256Key(keyBytes) {
return fmt.Errorf("key bytes are not a valid P256 private key")
}
err := c.VerifyPrivateKey(key, cert.Curve_P256, keyBytes) Type guard
func isP256Sized(b []byte) bool { return len(b) == 32 } Try / catch
if err := c.VerifyPrivateKey(key, cert.Curve_P256, keyBytes); err != nil {
if strings.Contains(err.Error(), "cannot parse private key as P256") {
return fmt.Errorf("supplied key is not a valid P256 scalar: %w", err)
}
return err
} Prevention
- Match the curve when generating keys and certificates
- Strip PEM/base64 to raw bytes before passing the key
- Store keys in a fixed raw binary format to avoid format drift
- Log the wrapped cause of ecdh parse failures to diagnose quickly
When it happens
Trigger: Calling (*certificateV1).VerifyPrivateKey with curve=Curve_P256 and key bytes that ecdh.P256().NewPrivateKey rejects (wrong size, all-zero, out of range, or actually an Ed25519 key).
Common situations: Passing an Ed25519 64-byte private key to a P256 certificate; key file contains PEM text not stripped to raw bytes; truncated or corrupted key file; NIST-curve vs Ed25519 confusion in config.
Related errors
- could not calculate alternate fingerprint to verify: %w
- error while converting ecdsa key: %s
- ErrBadFormat
- ErrRootExpired
- ErrExpired
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/68788e993c14964f.
Report an issue: GitHub.