Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check block integrity when necessary #1764

Merged
merged 8 commits into from
Mar 21, 2019
Merged

Conversation

Gilthoniel
Copy link
Contributor

The proof verification was not checking that the last forward link was pointing on the actual latest block provided by the proof which that a malicious peer can in some extend modify the block. This check has been added in the Java and the Go code.

Another issue was that only the forward links of a request skipblock were checked so any other fields could be modified as we were not checking the received skipblock hash. This has been fixed in the Java library.

Fixes #1703

@Gilthoniel Gilthoniel self-assigned this Mar 14, 2019
@Gilthoniel
Copy link
Contributor Author

I think this covers the different request of blocks we do in the Java library. @kc1212 Please let me know if I forgot something.

I'm investigating the skipchain service on the Go side..

@kc1212
Copy link
Contributor

kc1212 commented Mar 15, 2019

The java side looks good

Gaylor Bosson added 6 commits March 20, 2019 10:18
This fixes the Java and Go verification of a proof to add a check
for the last forward link to point on the actual hash of the
latest block to be sure the latest block has not been tempered.

Fixes #1703
This adds a check to the skipchain rpc when asking for a skipblock
so that the hash must match the block identifier

Fixes #1703
This adds block integrity checks among the skipchain service
when blocks are requested from a peer which means it could
be malicious data.

Fixes #1703
This adds further checkings in byzcoin and skipchain services
so that a request to a distant node is verified before usage.
The value returned must be assumed untrusted because the service
is lacking the context to verify it belongs to the chain.
Verifications must be done upstream.
@Gilthoniel Gilthoniel force-pushed the java_skipblock_hash_1703 branch from 8c8057a to dd4195b Compare March 20, 2019 09:19
This adds a verification step to make sure the returned genesis
block has been created with the same proposed parameters
@Gilthoniel
Copy link
Contributor Author

So the conclusion of this PR is that mainly the byzcoin and skipchain API were assuming data coming from the service is safe and then I added integrity checks where it was possible to verify. Sometimes you lack the context and then the verification must be done upstream, like when you ask for a single block (maybe we should always return a proof alongside?).

Aside of that the main goal of this PR was to fix the proof verification to insure the last forward link points to the correct returned latest block.

byzcoin/api.go Outdated
func (c *Client) StreamTransactions(handler func(StreamingResponse, error)) error {
req := StreamingRequest{
ID: c.ID,
}
// TODO: what if the leader is down ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the error handler handler(StreamingResponse{}, err) should be called and the function returns

// for testing purpose
if testCorruptNewLedgerResponse != nil {
reply = testCorruptNewLedgerResponse
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's easier to just test verifyGenesisBlock by itself. then you don't need to insert test code into production code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another possibility: can we register a corrupted byzcoin service that always just returns a wrong genesis block (e.g., embed byzcoin.Service inside byzcoin.BadService and overwrite the create genesis block function), it doesn't even have to do consensus or anything like that, just returns the bad block? just a few ideas to think about

Copy link
Contributor Author

@Gilthoniel Gilthoniel Mar 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes for the verifyGenesisBlock but I really want to make sure the request is checking this, and that no one removed this check accidentally.

another posibility...
I tried that first, but the service name is a constant (which is fine) so you can't change which service is going to be used, or am I missing something ? I would love to do it that way..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, I found a way to go around without too many complex mocking

byzcoin/api.go Outdated
// send the block only if the integrity is correct
handler(resp, nil)
} else {
log.Warnf("got a corrupted block from %v", c.Roster.List[0])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably you should call the handler here too, to say there is an error, like handler(StreamingResponse{}, err)

byzcoin/api.go Outdated
@@ -417,3 +450,54 @@ func DefaultGenesisMsg(v Version, r *onet.Roster, rules []string, ids ...darc.Id
}
return &m, nil
}

func verifyGenesisBlock(sb *skipchain.SkipBlock, req *CreateGenesisBlock) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would name those parameters like: actual *skipchain.SkipBlock, expected *CreateGenesisBlock, so it's obvious which input is trusted.

byzcoin/api.go Outdated
}

if len(data.TxResults) != 1 || len(data.TxResults[0].ClientTransaction.Instructions) != 1 {
return nil, errors.New("didn't get only one instruction")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return nil, errors.New("didn't get only one instruction")
return nil, errors.New("genesis darc tx should only have one instruction")

// we don't want a malicious peer to send a block with tempered
// data like a different roster with different public keys
throw new CothorityCommunicationException("invalid block integrity");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the function comment says the block is not verified, is that still the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change the comment. The integrity is verified but the caller must verify if it belongs to the chain.

skipchain/api.go Outdated

if testCorruptSSBResponse != nil {
sb = testCorruptSSBResponse
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment above regarding the possibility of creating a bad service

return sb.Latest, nil
}

// CompareGenesisBlocks compares the content of two blocks and returns an error
// if there is any difference
func compareGenesisBlocks(prop *SkipBlock, ret *SkipBlock) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can't you re-calculate the hash? if the hash is different then the block content should also be different right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish I could but the service is adding information to the genesis like a random backlink

@jeffallen jeffallen merged commit c5b18f2 into master Mar 21, 2019
@jeffallen jeffallen deleted the java_skipblock_hash_1703 branch March 21, 2019 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Java library doesn't check the hash of received blocks
3 participants