slackhq/nebula · error

ErrFingerprintMismatch

ErrFingerprintMismatch

Error message

certificate fingerprint did not match

What it means

ErrFingerprintMismatch is returned by verify when the caller supplied an expected signer fingerprint and the fingerprint of the CA that actually signed the certificate does not equal it. This guards against trusting a different (possibly malicious) CA within the pool.

Source

Thrown at cert/errors.go:15

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")

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Compare the pinned fingerprint with the actual CA's Fingerprint value and update the config or the ca.crt so they agree.
  2. Re-sign the certificate with the CA whose fingerprint is pinned.
  3. Clear the fingerprint hint if pinning is not intended (only pass the expected fingerprint when you mean to pin).
  4. Print both fingerprints (expected vs signer.Fingerprint) when debugging to spot rotation drift.

Example fix

// before
valid, err := pool.VerifyCertificate(c, oldCaFp, "") // CA was rotated

// after
newCaFp := hex.EncodeToString(currentCA.Fingerprint)
valid, err := pool.VerifyCertificate(c, newCaFp, "")
Defensive patterns

Strategy: validation

Validate before calling

expectedFp := config.PinnedCAFingerprint
if expectedFp != "" && expectedFp != hex.EncodeToString(ca.Fingerprint) {
    return fmt.Errorf("pinned CA fingerprint mismatch: update config after rotation")
}

Type guard

func fingerprintMatches(signer *cert.CachedCertificate, expectedFp string) bool {
    return expectedFp == "" || expectedFp == signer.Fingerprint
}

Try / catch

if _, err := pool.VerifyCertificate(c, pinnedFp, ""); errors.Is(err, cert.ErrFingerprintMismatch) {
    return fmt.Errorf("CA rotated? pinned fp %s != signer fp %s", pinnedFp, signer.Fingerprint)
}

Prevention

When it happens

Trigger: CAPool.verify (cert/ca_pool.go:236) when len(signerFp) > 0 and the resolved signer's Fingerprint differs from the provided signerFp — i.e., VerifyCertificate was given a fingerprint hint that matches a different CA in the pool.

Common situations: The pinned CA fingerprint in config doesn't match the ca.crt actually distributed (stale ca.crt after rotation); multiple CAs in the pool and the wrong one signed the cert; copy/paste error in fingerprint configuration.

Understand the failure class

Related errors


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