axelarnetwork / tofnd

A gRPC server wrapper for the https://github.com/axelarnetwork/tofn library.
Apache License 2.0
25 stars 11 forks source link

Ensure correct sender in tofn traffic #60

Closed ggutoski closed 3 years ago

ggutoski commented 3 years ago

Currently, the sender of a tofnd message is not authenticated. Thus, malicious parties could spoof messages from other parties.

Tofnd currently processes incoming traffic as follows: we ignore all fields of TrafficIn messages except the binary payload, which is passed directly to tofn for deserialization: https://github.com/axelarnetwork/tofnd/blob/56068f8f6090362a33d948e837f5f3442355ecae/src/gg20/protocol.rs#L106-L117 This binary payload contains a from field indicating to tofn the tofn-index of the message sender---see tofn code:

struct MsgMeta {
    msg_type: MsgType,
    from: usize,
    payload: MsgBytes,
}

It is easy for a malicious actor to dig into the binary payload and spoof this from field and therefore send messages on behalf of other parties.

Instead of ignoring TrafficIn metadata, tofnd must somehow verify that the from_party_uid field in TrafficIn is consistent with the from field wrapped in the tofn binary payload.

Tofn currently does not expose the format of the binary payload. Thus, in order to enable tofnd to perform the above mentioned authentication, tofn must expose the necessary data in its API. This requirement is posted in a separate issue in the tofn repo: axelarnetwork/tofn#42

sergeynog commented 3 years ago

Alternatively, can you pass from metadata value from the tofnd to tofn, and when tofn unpacks the payload it checks that from-party_uid == from? return error if not. (Otherwise we have to send payload to tofn, get a reply and then check on tofnd and continue in tofn. seems more back and forth calls).

sdaveas commented 3 years ago

To my understanding, the following can happen: When we receive a message in tofnd, we can discover sender's party_uid, which leads us to tofnd_index. There is no way to correlate tofnd_index with a specific tofn_index (aka a specific share), because we only know the name of the sender at that point (who may have more that one shares). But we can determine whether the sender sent a message from some other's behalf.

Example:

A attempts to spoof a message and creates:

// tofn level
msg = MsgMeta {
    msg_type: <some type>,
    from: 0, // A has shares 0, 1
    payload: <some payload>,
}

// tofnd level
t = TrafficIn { 
  from_party_uid: B, // spoof: send on behalf of B 
  data:{ msg } 
}

When we receive the message in tofnd, we search for TrafficIn::from_party_uid's tofnd index (B has index 1). From tofnd's index, we find the tofn's indices of this party (B0, B1 have indices 2, 3). If MsgMeta::from is not either 2 or 3, we know that the message is spoofed.

Question

Can we be sure that A spoofed; If it is possible to change from_party_uid from A to B, then it should be also possible to change from from 0 to 2.

ggutoski commented 3 years ago

It's the job of axelar-core to ensure that from_party_uid is correct. I believe axelar-core sets from_party_uid based on the pubkey that signed the message---it's not something that the sender chooses.

Thus, in your example it is impossible for Alice to spoof a message from Bob by tampering with from_party_uid because Alice does not have this ability.

Given that from_party_uid is correct, tofnd should be able to verify that the tofn-index from is a subshare that belongs to from_party_uid.

Consider a tweak of your example. Alice could try to spoof a message form Bob by setting MsgMeta::from = 2 but she cannot tamper with the setting TrafficIn::from_party_uid: A. Then tofnd would see that 2 is not a tofn-index that belongs to A and so tofnd can identify A as criminal.

Of course, we cannot stop Alice from lying about which of her subshares sent the message. But such behaviour would only hurt Alice.

sdaveas commented 3 years ago

So users have freedom only over MsgMeta. Thanks!

sergeynog commented 3 years ago

I would still to try to identify most faults inside tofn and hence just pass from_party_uid and do the check from_party_uid == MsgMeta inside the tofn only. You can return the same error as for the other ZK faults, for instance. (In an event an adversary takes someone else's ZK proofs/payload, but changes all from, MsgMega fields to its own, the authentication will pass but ZK proofs will fail. Do we call it an authentication failure or a ZK failure in this case? The events are very similar).

ggutoski commented 3 years ago

Stelios and I had a long call to spec out the details. Detection of authentication fault will indeed happen inside tofn as you suggest but the details are slightly different.

In an event an adversary takes someone else's ZK proofs/payload, but changes all from, MsgMega fields to its own, the authentication will pass but ZK proofs will fail.

This attack would be detected as an authentication failure if the adversary takes proofs/payload from another party, but would result in a zk proof failure if instead the adversary merely takes proofs/payload from another subshare controlled by the adversary. eg. If Alice:3 spoofs Bob:5 then it's an authentication failure, but if Alice:3 spoofs Alice:5 then it's a zk proof failure.