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

noise-libp2p: introduce "handshake seal"; more. #234

Closed
wants to merge 4 commits into from

Conversation

raulk
Copy link
Member

@raulk raulk commented Dec 4, 2019

This PR supersedes #210, and implements the outcome of that discussion.

The current construction is vulnerable to replay attacks by a MITM agent that records previous handshakes, and transplants old user data from those handshakes into new ones, as long as the static key hasn't changed.

We fix this vulnerability by leveraging Noise channel binding, in order to "seal" the handshake and assert that the exchanged data was witnessed equally by both parties.

This commit also simplifies protobuf field naming.

Finally, we formalise in which Noise messages of IK and XX the message payload is to be shared, to guarantee secrecy, integrity and authentication.

ping: @shahankhatch @Mikerah @djrtwo @dryajov @mpetrunic @morrigan @araskachoi -- please review too (can't assign you as a reviewer as you're not part of the libp2p org yet).

The current construction is vulnerable to replay attacks by a MITM agent
that records previous handshakes, and transplants old user data from
those handshakes into new ones, as long as the static key hasn't changed.

We fix this vulnerability by leveraging Noise channel binding, in order
to "seal" the handshake and assert that the exchanged data was witnessed
equally by both parties.

This commit also simplifies protobuf field naming.

Finally, we formalise in which Noise messages of IK and XX the message
payload is to be shared, to guarantee secrecy, integrity and
authentication.
Copy link
Contributor

@yusefnapora yusefnapora left a comment

Choose a reason for hiding this comment

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

This looks great to me; thanks @raulk.

@raulk
Copy link
Member Author

raulk commented Dec 4, 2019

@yusefnapora awesome! Let's wait for a few more approvals. @burges -- would appreciate thoughts, if any.

Copy link

@shahankhatch shahankhatch left a comment

Choose a reason for hiding this comment

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

Thanks @raulk. LGTM.
I've some minor changes suggested in #235.

noise/README.md Outdated Show resolved Hide resolved
noise/README.md Outdated Show resolved Hide resolved
noise/README.md Show resolved Hide resolved
Copy link
Contributor

@jacobheun jacobheun left a comment

Choose a reason for hiding this comment

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

added some language and spacing corrections/suggestions

noise/README.md Show resolved Hide resolved
noise/README.md Outdated Show resolved Hide resolved
noise/README.md Outdated Show resolved Hide resolved
noise/README.md Outdated Show resolved Hide resolved
@raulk raulk requested a review from jacobheun December 6, 2019 12:35
Copy link
Contributor

@jacobheun jacobheun left a comment

Choose a reason for hiding this comment

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

This looks good from my end. 👍

efficiency and enhanced security purposes, we choose to adopt the [channel
binding][npf-channel-binding] technique defined in the Noise Protocol Framework.

The Noise Protocol state machine tracks the handshake hash throughout the entire
Copy link

@morrigan morrigan Dec 10, 2019

Choose a reason for hiding this comment

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

Can you be more precise which data should be hashed? Also, do you want to specify this to be SHA256?

Copy link
Member Author

Choose a reason for hiding this comment

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

The handshake hash is defined in the Noise spec: https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine. The noise library you use should be computing the hash -- you shouldn't need to do it in the noise-libp2p implementation.

@raulk
Copy link
Member Author

raulk commented Dec 11, 2019

🚃🚃🚃🚃🚃 Merge train leaving tomorrow morning. Please get your remarks in today!

@romanb
Copy link
Contributor

romanb commented Dec 11, 2019

Could someone elaborate (e.g. with concrete examples) on

The current construction is vulnerable to replay attacks by a MITM agent that records previous handshakes, and transplants old user data from those handshakes into new ones, as long as the static key hasn't changed.

as well as

[..] In the above scheme, the data field is not guarded against tampering. Consequently, a MITM agent could alter the data in transit, or even record the handshake to replay it at a later time with mutated or transplanted data.

Given that all "early data" is sent as part of encrypted handshake payloads using an AEAD scheme and the current handshake hash h as associated data, how is such transplantation or mutation performed exactly?

I'm probably missing the obvious, but I currently don't see what the signing of the handshake hash is supposed to accomplish on top of signing the static DH public key as far as authentication is concerned. I mean, I can understand why one would rather want to sign the handshake hash instead of the static DH public key (e.g. to prevent signature replays when a static DH private key is compromised, allowing impersonating the owner of the private identity key) but I fail to see why you would want to do both. If someone could enlighten me with more details on the attack vectors addressed here and why both, signing the static DH key as well as the handshake hash is necessary, I would be very grateful.

@raulk
Copy link
Member Author

raulk commented Dec 17, 2019

@romanb I think you're right.

I missed the fact that EncryptAndHash and DecryptAndHash also call MixHash with the ciphertexts, and that WriteMessage(payload) and ReadMessage(into_payload_buffer) call EncryptAndHash and DecryptAndHash respectively.

For some reason, I thought only the keys were mixed in, but I was wrong.

Consequently, the AD (authentication data) already includes the payload ciphertexts we've witnessed, and by introducing this handshake seal we are not proposing any extra guarantee that is not already awarded by the AEAD scheme that encompasses the payloads.

If an intermediary constructs a transplant or tamper attack, I'm confident it'll be caught by an authentication tag mismatch.

I'm going to retract this RFC, and open a new PR with the other changes.

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.

6 participants