slackhq/nebula · error

ErrInvalidPrivateKey

ErrInvalidPrivateKey

Error message

invalid private key

What it means

ErrInvalidPrivateKey is returned by VerifyPrivateKey when the supplied private key cannot correspond to the certificate's public key: for ed25519 the key length must equal ed25519.PrivateKeySize (checked explicitly to avoid a slice-bounds panic), and for P256/ECDH ecdh.P256().NewPrivateKey(key) fails to parse it.

Source

Thrown at cert/errors.go:18

package cert

import (
	"errors"
	"fmt"
)

var (
	ErrBadFormat                  = errors.New("bad wire format")
	ErrRootExpired                = errors.New("root certificate is expired")
	ErrExpired                    = errors.New("certificate is expired")
	ErrNotCA                      = errors.New("certificate is not a CA")
	ErrNotSelfSigned              = errors.New("certificate is not self-signed")
	ErrBlockListed                = errors.New("certificate is in the block list")
	ErrFingerprintMismatch        = errors.New("certificate fingerprint did not match")
	ErrSignatureMismatch          = errors.New("certificate signature did not match")
	ErrInvalidPublicKey           = errors.New("invalid public key")
	ErrInvalidPrivateKey          = errors.New("invalid private key")
	ErrPublicPrivateCurveMismatch = errors.New("public key does not match private key curve")
	ErrPublicPrivateKeyMismatch   = errors.New("public key and private key are not a pair")
	ErrPrivateKeyEncrypted        = errors.New("private key must be decrypted")
	ErrCaNotFound                 = errors.New("could not find ca for the certificate")
	ErrUnknownVersion             = errors.New("certificate version unrecognized")
	ErrCertPubkeyPresent          = errors.New("certificate has unexpected pubkey present")
	ErrCurveMismatch              = errors.New("certificate curve does not match CA")

	ErrInvalidPEMBlock                   = errors.New("input did not contain a valid PEM encoded block")
	ErrInvalidPEMCertificateBanner       = errors.New("bytes did not contain a proper certificate banner")
	ErrInvalidPEMX25519PublicKeyBanner   = errors.New("bytes did not contain a proper X25519 public key banner")
	ErrInvalidPEMX25519PrivateKeyBanner  = errors.New("bytes did not contain a proper X25519 private key banner")
	ErrInvalidPEMEd25519PublicKeyBanner  = errors.New("bytes did not contain a proper Ed25519 public key banner")
	ErrInvalidPEMEd25519PrivateKeyBanner = errors.New("bytes did not contain a proper Ed25519 private key banner")

	ErrNoPeerStaticKey = errors.New("no peer static key was present")
	ErrNoPayload       = errors.New("provided payload was empty")

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Ensure the key file is the full private key in the expected format and decode armor (pem.Decode) before passing the raw bytes.
  2. Check the key type matches the certificate's curve (ed25519 vs P256) — regenerate the key pair with nebula-cert keygen if mismatched.
  3. Verify key length: 64 bytes for ed25519 private keys; fix cut/paste truncation.
  4. Pair the certificate with the key generated together with it rather than a random existing key.

Example fix

// before
key, _ := os.ReadFile("host.pub") // wrong file
cert.VerifyPrivateKey(hostName, key) // ErrInvalidPrivateKey

// after
block, _ := pem.Decode(hostKeyPEM)
cert.VerifyPrivateKey(hostName, block.Bytes) // matching .key file
Defensive patterns

Strategy: validation

Validate before calling

const ed25519PrivateKeySize = 64
if len(key) != ed25519PrivateKeySize {
    return fmt.Errorf("private key must be %d bytes, got %d", ed25519PrivateKeySize, len(key))
}

Type guard

func isEd25519PrivateKey(key []byte) bool {
    return len(key) == ed25519.PrivateKeySize
}

Try / catch

if err := c.VerifyPrivateKey(hostName, key); errors.Is(err, cert.ErrInvalidPrivateKey) {
    return fmt.Errorf("key file wrong size/curve for cert; regenerate keypair with nebula-cert keygen")
}

Prevention

When it happens

Trigger: cert.VerifyPrivateKey on a v2 cert (cert/cert_v2.go:183,192) when the ed25519 key bytes are the wrong length, or the NIST-Curve key bytes are not a valid P256 scalar — wrong-size PEM, hex/base64 decoding issues, or a key from a different curve.

Common situations: Passing a public key file where a private key is expected; truncated or armored private key files (PEM header not stripped); key generated on a different curve than the certificate's curve; ed25519 vs P256 mismatch after regeneration.

Related errors


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