AlexxIT/go2rtc · error
hap: ValidateSignature
Error message
hap: ValidateSignature
What it means
In Pair's STEP M6, the client verifies the accessory's signature over its signed data using the ed25519 public key carried inside the M6 message itself. This error means the accessory's self-attested identity did not verify — the exchange is untrustworthy, so Pair aborts before comparing DeviceID.
Solutions
- Retry Pair on a fresh session — transient corruption resolves on a clean exchange.
- Ensure only the intended accessory responds: match the mDNS entry id to DeviceID and remove duplicates on the network.
- Power-cycle the accessory and repeat pairing; if it still fails, update or replace the firmware.
- Treat repeated failures as a security signal: the peer cannot prove its identity, so do not persist pairing data from the attempt.
Example fix
// before: Pair failure leaves partial state persisted
err := client.Pair(pin)
savePairing(client) // persisted even on ValidateSignature failure
// after: persist only after a fully verified pairing
if err := client.Pair(pin); err != nil {
if strings.Contains(err.Error(), "ValidateSignature") {
return errors.New("device identity could not be verified; pairing aborted")
}
return err
}
savePairing(client) Defensive patterns
Strategy: try-catch
Validate before calling
entries := mdns.Query(mdns.ServiceHAP)
ids := map[string]int{}
for _, e := range entries { if e.Complete() { ids[e.Info["id"]]++ } }
for id, n := range ids {
if n > 1 { return fmt.Errorf("duplicate HAP device id %s on network", id) }
} Try / catch
if err := client.Pair(pin); err != nil {
if strings.Contains(err.Error(), "ValidateSignature") {
// identity not verifiable: abort, do not persist pairing data
return errors.New("device identity verification failed; check for duplicate devices or bad firmware, then retry on a fresh session")
}
return err
} Prevention
- Retry pairing on a fresh session once — transient corruption is the most common cause.
- Eliminate duplicate mDNS names/ids on the network so the client cannot talk to the wrong accessory.
- Never persist pairing state from a failed M6 verification.
- Update clone/experimental firmware that may produce malformed signatures.
When it happens
Trigger: A corrupted or truncated M6 response over a flaky transport; a device (or MITM) answering the pairing exchange without valid long-term key material; firmware bug producing a malformed M6 payload; mixing pairing responses from two devices (e.g. duplicate mDNS entries).
Common situations: Two accessories on the network exposing the same mDNS name so the client talks to the wrong one; experimental/clone firmware with broken signing; radio-level packet corruption during pairing; replayed M6 from a previous aborted pairing.
Related errors
- hap: ValidateSignature
- hap: can't dial witout client_id or client_private
- hap: VerifyServerAuthenticator
- echo: bin not in allow_paths:
- exec: bin not in allow_paths:
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/94bdd52878bf2a6f.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/hap/client_pairing.go:266
Identifier string `tlv8:"1"`
PublicKey string `tlv8:"3"`
Signature string `tlv8:"10"`
}{}
if err = tlv8.Unmarshal(b, &plainM6); err != nil {
return
}
// STEP M6. Verify payload
remoteSign, err := hkdf.Sha512(
sessionShared, "Pair-Setup-Accessory-Sign-Salt", "Pair-Setup-Accessory-Sign-Info",
)
if err != nil {
return
}
b = Append(remoteSign, plainM6.Identifier, plainM6.PublicKey)
if !ed25519.ValidateSignature([]byte(plainM6.PublicKey), b, []byte(plainM6.Signature)) {
return errors.New("hap: ValidateSignature")
}
if c.DeviceID != plainM6.Identifier {
return errors.New("hap: wrong DeviceID: " + plainM6.Identifier)
}
c.DevicePublic = []byte(plainM6.PublicKey)
return nil
}
func (c *Client) ListPairings() error {
plainM1 := struct {
Method byte `tlv8:"0"`
State byte `tlv8:"6"`
}{
Method: MethodListPairings,
State: StateM1,View on GitHub (pinned to c245815e75)