BOLT 7 states in multiple places that gossip message signatures are to be verified over the actual message bytes. For example, for channel_update:
The receiving node:
- if
signature is not a valid signature, using node_id of the double-SHA256 of the entire message following the signature field (including unknown fields following fee_proportional_millionths):
- SHOULD send a
warning and close the connection.
- MUST NOT process the message further.
But Eclair actually re-encodes messages through its own codec before verifying signatures, and for certain fields the round trip can change the underlying bytes:
- characters after the first null byte are stripped from
alias
features bitvectors are changed to minimal form
message_flags and channel_flags have the upper bits stripped
When this occurs, Eclair verifies signatures incorrectly and may reject gossip that other implementations accept, or vice versa.
Implications
While a spec-conforming node should never create gossip that triggers these bugs, a buggy or malicious node could do it and cause Eclair's view of the LN network to diverge from other nodes' views.
A more concerning network isolation vector could arise if any implementation ever decides to ban peers that repeatedly send gossip with incorrect signatures. While no implementation does this currently, Eclair does have a TODO indicating the intention to do it in the future:
|
case GossipDecision.InvalidSignature(r) => |
|
val bin: String = LightningMessageCodecs.meteredLightningMessageCodec.encode(r) match { |
|
case Attempt.Successful(b) => b.toHex |
|
case _ => "unknown" |
|
} |
|
log.error(s"peer sent us a routing message with invalid sig: r=$r bin=$bin") |
|
// for now we just send a warning, maybe ban the peer in the future? |
|
// TODO: this doesn't actually disconnect the peer, once we introduce peer banning we should actively disconnect |
|
d.transport ! Warning(s"invalid announcement sig (bin=$bin)") |
|
d.behavior |
Reproducing
0001-Demonstrate-signature-verification-bugs.patch
Discovery
This issue was surfaced while fuzzing node_announcements using Smite. Eclair failed to verify the signature when alias had trailing non-null bytes after the initial null byte, while other implementations succeeded in verifying the signature.
BOLT 7 states in multiple places that gossip message signatures are to be verified over the actual message bytes. For example, for
channel_update:But Eclair actually re-encodes messages through its own codec before verifying signatures, and for certain fields the round trip can change the underlying bytes:
aliasfeaturesbitvectors are changed to minimal formmessage_flagsandchannel_flagshave the upper bits strippedWhen this occurs, Eclair verifies signatures incorrectly and may reject gossip that other implementations accept, or vice versa.
Implications
While a spec-conforming node should never create gossip that triggers these bugs, a buggy or malicious node could do it and cause Eclair's view of the LN network to diverge from other nodes' views.
A more concerning network isolation vector could arise if any implementation ever decides to ban peers that repeatedly send gossip with incorrect signatures. While no implementation does this currently, Eclair does have a TODO indicating the intention to do it in the future:
eclair/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala
Lines 459 to 468 in 2dda794
Reproducing
0001-Demonstrate-signature-verification-bugs.patch
Discovery
This issue was surfaced while fuzzing
node_announcements using Smite. Eclair failed to verify the signature whenaliashad trailing non-null bytes after the initial null byte, while other implementations succeeded in verifying the signature.