Signing policy + optional Signature, From and Seqno#359
Conversation
vyzo
left a comment
There was a problem hiding this comment.
Thank you! This looks great at first glance, I'll take a closer look tomorrow morning.
vyzo
left a comment
There was a problem hiding this comment.
We need to handle the unexpected signature in the score tracer.
Also, it might make sense to enforce empty from/seqno when we operate in anoymous mode to defend against and adversary stuffing garbage in those fields.
|
Some concerns:
|
|
Hrm, the test passes on travis and wfm; maybe there is some non-determinism. |
|
cc @raulk |
|
The test that fails locally:
connect(t, h[0], h[1])
connect(t, h[0], h[2])
// verify that the direct peers connected
time.Sleep(2 * time.Second)
if len(h[1].Network().ConnsToPeer(h[2].ID())) == 0 {
t.Fatal("expected a connection between direct peers")
}Looks like it's a timing thing that misses, and unrelated to this PR. Edit: increasing the two sleep statements before expectations to 10s worked. Flaky test. |
|
I think this is where things go wrong with the flaky test: Line 1529 in aabbdb1 New go routines are started to make connections, and the connections are not awaited (no waitgroup). At the same time, maybe that is desirable, to not halt the heartbeat loop. Waiting for it in a test is not ideal though. And I wonder what happens next heartbeat, does it just repeatedly try to connect? Is that what the ticking is for?\ Edit: if 1 tick is 1 heartbeat is 1 second, then 2 ticks to try 2nd connect attempt will be just enough or not, depending on go routine order. And the first attempt |
|
Yeah, we can't block the event loop. It retries every few ticks, with an initial spawn. |
vyzo
left a comment
There was a problem hiding this comment.
Ok, this looks good to me.
|
So, regardless of the very interesting issues you raise, codewise this is ready to be merged. |
|
I am going to merge it but not yet tag a release. |
With respect to the seqno...not only can it be used to fingerprint nodes, but the fact that it is incremented with each new gossip message authored allows attackers to approximate how many validators a node is running (in the case of eth2). |
| } | ||
| if t.p.signID != "" { | ||
| m.From = []byte(t.p.signID) | ||
| m.Seqno = t.p.nextSeqno() |
There was a problem hiding this comment.
Note: I don't think whether we set or not the Seqno is correlated with whether we send or not the source peer ID, rather with whether we have a custom MessageIdFn or not.
There was a problem hiding this comment.
Yes, we can introduce another option for it, but the thought here is that seq-no makes little sense without a message author (since everyone can claim the seq-no for any message data), so it's just left out.
There's some polishing that can be done. I appreciate the quick PR merge, but would have welcomed more feedback/discussion. Reviewing the update path for eth2 clients would also help. Implementations all behave a little different, and this is the chance to plan signing functionality (non-eth2, but relevant) for those that don't have it yet, make verification strict yes/no, and align everything. I am tracking behavioral differences in a table in the eth2-specs issue here: ethereum/consensus-specs#1981 (comment)
There was a problem hiding this comment.
Sure, that's why I haven't cut a release yet -- we can iterate on it.
This PR proposes new non-breaking PubSub options, to force stricter validation (avoid hypothethical network split), and avoid privacy problems in Eth2.
Why
Privacy
The current gossip message ID is purely based on a hash of the contents, but it is still wrapped in a protobuf that carries
From,SeqnoandSignature.The
FromandSeqnoaffect privacy: we don't need, or want, the original source of the message to be known. Currently, I believe that if messages are not re-published,but propagated, that at least in the Go implementation these details remain in the gossip message.
While
Fromis problematic (and previously known to be, just not fixed by anyone),Seqnoalone is also problematic, since (in Go at least) it is initialized as nanosecond time of the node, and then only increments by 1. Because of the slow non-random increase on top of a big number, it's effectively a unique identifier of the origin, embedded in every message.This could be used to quickly correlate messages, and narrow down which validators (based on message contents) run on which nodes.
Network split
The "Signature" is not really used, and empty. However, the Go implementation seems to validate it anyway, if it is non-empty.
Now other gossip implementations don't use it at all, or have a stalled PR open that implements similar behavior.
In our case, the signature is dangerous, because it can make different nodes mislike eachother:
Changes
Loosely based on discussion with @raulk:
MessageSignaturePolicyenum:WithStrictSignatureVerificationandWithMessageSigningto use the enum. This refactors out the logic away from the function, and into the constructor (but minimal). This avoids an unnecessary peerstore private-key lookup (getting the host private key when not using it as signing key)WithMessageSignaturePolicyto set the singing policy. I have doubts here, alternatively we could not deprecateWithMessageSigning, and eventually just say that the verification bool is always on.not signing && verificationmeans that signatures must be nil to be valid.pushMsgnow checks if the signature is nil, given the right circumstances (and added a trace for it)WithNoAuthoroption, to not sign any messages, and omit any origin data (seq no and signer identity)pb.MessageKeyattribute, but might need to be omitted or handled as well?signIDis nil, the signing option is disabled: you can't be not signing while also requiring signatures. (matches previous "non sensical option" check in constructor). Instead of returning an error I am disabling the signing now. But maybe it should just error instead?Message.Fromshould be set to the signer, not the current host (since they may be different, and potentially it is used for signature checking via key extraction, unlessKeyis set?).Any feedback welcome, I can make changes, or change the approach.