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: make it possible for the server to send early data #1750

Merged
merged 6 commits into from
Sep 19, 2022

Conversation

marten-seemann
Copy link
Contributor

So far, only the client could send early data in its first handshake message, which the server would then receive.

This PR extends the logic, such that the server can now also send early data in its first handshake message.

Needed for libp2p/specs#404 (comment). Also needed for libp2p/specs#446, if I understand correctly.

Copy link
Contributor

@julian88110 julian88110 left a comment

Choose a reason for hiding this comment

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

Hi Marten, Thanks for making this API available!

return err
}
if s.earlyDataHandler != nil {
if err := s.earlyDataHandler.Received(ctx, s.insecureConn, rcvdEd); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

The early data handler may need to know the handshake state to drive its internal state machine, for example if this is the server or client side, at which stage is the early data received. Do you think we should pass the handshake state info to the earlyDataHandler too? or maybe that is available in other ways already and I missed it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For both client and server, the data is sent with their respective first flights.

I think the nicest way to resolve this is to pass separate client and server EarlyDataHandlers to the EarlyData option. I applied that change in 0b36832. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

That looks great, thanks for the changes which make the Noise based muxer selection and other early data utilization smoother.

@@ -82,7 +77,7 @@ func (s *secureSession) runHandshake(ctx context.Context) (err error) {
// will be the size of the maximum handshake message for the Noise XX pattern.
// Also, since we prefix every noise handshake message with its length, we need to account for
// it when we fetch the buffer from the pool
maxMsgSize := 2*noise.DH25519.DHLen() + len(payload) + 2*chacha20poly1305.Overhead
maxMsgSize := 2*noise.DH25519.DHLen() + 2*chacha20poly1305.Overhead + 1024 /* payload */
Copy link
Contributor

Choose a reason for hiding this comment

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

Just wondering if there is a more efficient way of setting length rather than a hard limit here, I don't have a better way readily available, just want to throw some thoughts here to explore the options.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to a fixed value of 2048 in 24459c5.

It's not even a hard limit, it's just the size we use to get a buffer from the buffer pool. If we get a buffer that's too small, the worst thing that happens is that append would allocate a larger buffer.

We can just use a large enough buffer here. What exactly "large enough" means depends on the amount of early data we send, but 2048 should be enough for practically all use cases. And if not, we can live with that one allocation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the clarification, that makes sense. Sorry I was not aware that we can do extra allocation if the limit is exceeded.

Copy link
Contributor

@julian88110 julian88110 left a comment

Choose a reason for hiding this comment

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

LGTM

p2p/security/noise/handshake.go Outdated Show resolved Hide resolved
p2p/security/noise/session.go Show resolved Hide resolved
p2p/security/noise/session_transport.go Outdated Show resolved Hide resolved
p2p/security/noise/transport_test.go Show resolved Hide resolved
@marten-seemann
Copy link
Contributor Author

@MarcoPolo Good catch, this will make the code easier to understand. I updated the variable names to match the spec.

Copy link
Collaborator

@MarcoPolo MarcoPolo left a comment

Choose a reason for hiding this comment

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

One small thing

p2p/security/noise/session_transport.go Show resolved Hide resolved
Copy link
Collaborator

@MarcoPolo MarcoPolo left a comment

Choose a reason for hiding this comment

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

Approved with the comments I added to EarlyDataHandler. Feel free to tweak, but the gist should be the same (a user should understand the caveats around this and what "early data" means in go-libp2p since this isn't a standard).

@marten-seemann
Copy link
Contributor Author

I updated the PR, such that early data is sent with the 2nd and 3rd handshake message. This means that early data is always sent encrypted.

The slight annoyance here is that if the Received function returns an error, we can't fail the handshake any more more, as the client already completed its handshake. Instead, it will just encounter a closed connection. Note that this is similar to what happens in TLS 1.3 when the server rejects the client certificate, so I'm not too worried about this.

Copy link
Collaborator

@MarcoPolo MarcoPolo left a comment

Choose a reason for hiding this comment

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

One fix for the comment, but otherwise looks good. Feel free to ping when the change is in and I’ll approve

// EarlyDataHandler allows attaching an (unencrypted) application payload to the first handshake message.
// While unencrypted, the integrity of this early data is retroactively authenticated on completion of the handshake.
// EarlyDataHandler defines what the application payload is for either the second
// (if initiator) or third (if responder) handshake message, and defines the
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// (if initiator) or third (if responder) handshake message, and defines the
// (if responder) or third (if initiator) handshake message, and defines the

Right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I’m going to commit this and approve.

@marten-seemann marten-seemann merged commit c1bdab4 into master Sep 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants