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

proposal: crypto/tls: QUIC 0-RTT APIs #60107

Open
FiloSottile opened this issue May 10, 2023 · 11 comments
Open

proposal: crypto/tls: QUIC 0-RTT APIs #60107

FiloSottile opened this issue May 10, 2023 · 11 comments
Labels
Proposal Proposal-Crypto Proposal related to crypto packages or other security issues Proposal-FinalCommentPeriod
Milestone

Comments

@FiloSottile
Copy link
Contributor

This proposal adds a couple features on top of #60105 and #44886 to let QUIC stacks implement 0-RTT. It does NOT add 0-RTT support for TLS connections. The hard part of supporting 0-RTT in TLS is figuring out a safe application API which doesn't break the net.Conn contract. A QUIC stack has a easier to adapt interface with its applications.

const QUICEncryptionLevelEarly QUICEncryptionLevel

const QUICRejectedEarlyData QUICEventKind

type SessionState struct {
    EarlyData bool
}

func (*QUICConn) SendSessionTicket(earlyData bool) ([]QUICEvent, error)

The flow on the server side is:

  1. After the handshake has completed, the server calls SendSessionTicket with earlyData set to true, and gets back a QUICWriteData event to send a fresh session ticket with the early_data extension. During this call, the Config.WrapSession callback is called and allows the QUIC stack to store parameters in SessionState.Extra.
  2. In a following handshake, the server receives a ticket which gets passed to Config.UnwrapSession. The state has SessionState.EarlyData set to true, if the server wants to reject early data it sets it to false before returning it.
  3. If crypto/tls likes the session for resumption and for early data, HandleData returns a QUICSetReadSecret with level QUICEncryptionLevelEarly before QUICEncryptionLevelHandshake. If the former is not returned before the latter, early data was rejected.

The flow on the client side is:

  1. The client receives a session ticket and ClientSessionCache.Put gets called. ClientSessionState.ResumptionSession returns a SessionState with EarlyData set to true if the server enabled early data support.
  2. ClientSessionCache.Get returns that session for a later connection during Start. If the client doesn't want to request early data, it can set SessionState.EarlyData to false.
  3. Start returns a QUICSetWriteSecret with QUICEncryptionLevelEarly if the session is good and early data was be offered. The client can start sending early data.
  4. If the server rejects early data in its Encrypted Extensions, HandleData returns a QUICRejectedEarlyData event before QUICEncryptionLevelApplication keys are returned. If the former is not returned before the latter, the early data was accepted.

This was designed with @marten-seemann and if I'm not mistaken along with #60105 and #44886 it should allow quic-go to drop its crypto/tls fork

/cc @golang/security @golang/proposal-review

@FiloSottile FiloSottile added Proposal Proposal-Crypto Proposal related to crypto packages or other security issues labels May 10, 2023
@FiloSottile FiloSottile added this to the Proposal milestone May 10, 2023
@marten-seemann
Copy link
Contributor

Thank you @FiloSottile! You're right, this would allow quic-go to drop the crypto/tls fork.
Needless to say, I'm planning to do exactly that the minute this proposal is implemented.

@ianlancetaylor
Copy link
Contributor

CC @neild

@neild
Copy link
Contributor

neild commented May 10, 2023

After the handshake has completed, the server calls SendSessionTicket with earlyData set to true, and gets back a QUICWriteData event to send a fresh session ticket with the early_data extension.

Currently, the server will include a session ticket (without the early_data extension set) in the flight of data which concludes the handshake. We presumably don't want to send both a session ticket without early_data and one with. How will that work? Do QUIC connections only send session tickets when SendSessionTicket is called? What happens if QUICConn.SendSessionTicket is called when Config.SessionTicketsDisabled is true?

The state has SessionState.EarlyData set to true, if the server wants to reject early data it sets it to false before returning it.

I think it'd be safer if the server needs to explicitly accept early data, but it doesn't matter all that much.

@FiloSottile
Copy link
Contributor Author

Currently, the server will include a session ticket (without the early_data extension set) in the flight of data which concludes the handshake. We presumably don't want to send both a session ticket without early_data and one with. How will that work? Do QUIC connections only send session tickets when SendSessionTicket is called?

Yep, that's the idea. The current behavior would be equivalent to calling HandleData and then SendSessionTicket immediately after. This also allows sending multiple tickets if desired.

What happens if QUICConn.SendSessionTicket is called when Config.SessionTicketsDisabled is true?

I'd say SendSessionTicket returns an error.

I think it'd be safer if the server needs to explicitly accept early data, but it doesn't matter all that much.

For what it's worth, the server needs to have called SendSessionTicket with earlyData true for this to happen, the client can't force it unilaterally.

@rsc
Copy link
Contributor

rsc commented May 10, 2023

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

@rsc
Copy link
Contributor

rsc commented May 17, 2023

This is a lot of new API, but my understanding is that @FiloSottile, @neild, and @marten-seemann are all in favor of it.

Have all remaining concerns been addressed?

@neild
Copy link
Contributor

neild commented May 17, 2023

LGTM. Minor change: Under the latest version of #44886, the SendSessionTicket signature will be:

func (*QUICConn) SendSessionTicket(earlyData bool) error

@gopherbot
Copy link

Change https://go.dev/cl/496995 mentions this issue: crypto/tls: add QUIC 0-RTT APIs

@marten-seemann
Copy link
Contributor

I updated my branch in quic-go to make use of the new API exposed in https://go.dev/cl/496995.
My 0-RTT test suite passes. It works!

@rsc
Copy link
Contributor

rsc commented May 24, 2023

Based on the discussion above, this proposal seems like a likely accept.
— rsc for the proposal review group

@dmitshur
Copy link
Contributor

This got closed but the proposal is still in progress. Reopening so it can get to a resolution (and if it doesn't make it to accepted state, to revert the CL).

@dmitshur dmitshur reopened this May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Proposal Proposal-Crypto Proposal related to crypto packages or other security issues Proposal-FinalCommentPeriod
Projects
Status: Likely Accept
Development

No branches or pull requests

7 participants