Merge pull request from GHSA-f3w5-v9xx-rp8p

* add time warping lunatic attack test

* create too high and connecton refused errors and add to the light client provider

* add height check to provider

* introduce block lag

* add detection logic for processing forward lunatic attack

* add node-side verification logic

* clean up tests and formatting

* update adr's

* update testing

* fix fetching the latest block

* format

* update changelog

* implement suggestions

* modify ADR's

* format

* clean up node evidence verification
This commit is contained in:
Callum Waters
2021-04-08 08:10:03 -07:00
committed by GitHub
parent 0f41f7465c
commit b272746444
16 changed files with 631 additions and 133 deletions
@@ -8,6 +8,7 @@
* 14-08-2020: Introduce light traces (listed now as an alternative approach)
* 20-08-2020: Light client produces evidence when detected instead of passing to full node
* 16-09-2020: Post-implementation revision
* 15-03-2020: Ammends for the case of a forward lunatic attack
### Glossary of Terms
@@ -106,8 +107,10 @@ This is done with:
```golang
func (c *Client) examineConflictingHeaderAgainstTrace(
trace []*types.LightBlock,
divergentHeader *types.SignedHeader,
source provider.Provider, now time.Time) ([]*types.LightBlock, *types.LightBlock, error)
targetBlock *types.LightBlock,
source provider.Provider,
now time.Time,
) ([]*types.LightBlock, *types.LightBlock, error)
```
which performs the following
@@ -117,16 +120,21 @@ because witnesses cannot be added and removed after the client is initialized. B
as a sanity check. If this fails we have to drop the witness.
2. Querying and verifying the witness's headers using bisection at the same heights of all the
intermediary headers of the primary (In the above example this is A, B, C, D, F, H). If bisection fails or the witness stops responding then
we can call the witness faulty and drop it.
intermediary headers of the primary (In the above example this is A, B, C, D, F, H). If bisection fails
or the witness stops responding then we can call the witness faulty and drop it.
3. We eventually reach a verified header by the witness which is not the same as the intermediary header (In the above example this is E).
This is the point of bifurcation (This could also be the last header).
3. We eventually reach a verified header by the witness which is not the same as the intermediary header
(In the above example this is E). This is the point of bifurcation (This could also be the last header).
4. There is a unique case where the trace that is being examined against has blocks that have a greater
height than the targetBlock. This can occur as part of a forward lunatic attack where the primary has
provided a light block that has a height greater than the head of the chain (see Appendix B). In this
case, the light client will verify the sources blocks up to the targetBlock and return the block in the
trace that is directly after the targetBlock in height as the `ConflictingBlock`
This function then returns the trace of blocks from the witness node between the common header and the
divergent header of the primary as it
is likely as seen in the example to the right below that multiple headers where required in order to
verify the divergent one. This trace will
divergent header of the primary as it is likely, as seen in the example to the right, that multiple
headers where required in order to verify the divergent one. This trace will
be used later (as is also described later in this document).
![](../imgs/bifurcation-point.png)
@@ -225,3 +233,22 @@ would be validators that currently still have something staked.
Not only this but there was a large degree of extra computation required in storing all
the currently staked validators that could possibly fall into the group of being
a phantom validator. Given this, it was removed.
## Appendix B
A unique flavor of lunatic attack is a forward lunatic attack. This is where a malicious
node provides a header with a height greater than the height of the blockchain. Thus there
are no witnesses capable of rebutting the malicious header. Such an attack will also
require an accomplice, i.e. at least one other witness to also return the same forged header.
Although such attacks can be any arbitrary height ahead, they must still remain within the
clock drift of the light clients real time. Therefore, to detect such an attack, a light
client will wait for a time
```
2 * MAX_CLOCK_DRIFT + LAG
```
for a witness to provide the latest block it has. Given the time constraints, if the witness
is operating at the head of the blockchain, it will have a header with an earlier height but
a later timestamp. This can be used to prove that the primary has submitted a lunatic header
which violates monotonically increasing time.
@@ -4,6 +4,7 @@
- 04/09/2020: Initial Draft (Unabridged)
- 07/09/2020: First Version
- 13.03.21: Ammendment to accomodate forward lunatic attack
## Scope
@@ -159,7 +160,7 @@ For `LightClientAttack`
- Fetch the common signed header and val set from the common height and use skipping verification to verify the conflicting header
- Fetch the trusted signed header at the same height as the conflicting header and compare with the conflicting header to work out which type of attack it is and in doing so return the malicious validators.
- Fetch the trusted signed header at the same height as the conflicting header and compare with the conflicting header to work out which type of attack it is and in doing so return the malicious validators. NOTE: If the node doesn't have the signed header at the height of the conflicting header, it instead fetches the latest header it has and checks to see if it can prove the evidence based on a violation of header time. This is known as forward lunatic attack.
- If equivocation, return the validators that signed for the commits of both the trusted and signed header
@@ -167,7 +168,11 @@ For `LightClientAttack`
- If amnesia, return no validators (since we can't know which validators are malicious). This also means that we don't currently send amnesia evidence to the application, although we will introduce more robust amnesia evidence handling in future Tendermint Core releases
- For each validator, check the look up table to make sure there already isn't evidence against this validator
- Check that the hashes of the conflicting header and the trusted header are different
- In the case of a forward lunatic attack, where the trusted header height is less than the conflicting header height, the node checks that the time of the trusted header is later than the time of conflicting header. This proves that the conflicting header breaks monotonically increasing time. If the node doesn't have a trusted header with a later time then it is unable to validate the evidence for now.
- Lastly, for each validator, check the look up table to make sure there already isn't evidence against this validator
After verification we persist the evidence with the key `height/hash` to the pending evidence database in the evidence pool with the following format: