forked from quic-go/quic-go
introduce a marshaling format for data saved in the session ticket
This commit is contained in:
@@ -444,7 +444,9 @@ func (h *cryptoSetup) handleTransportParameters(data []byte) {
|
||||
|
||||
// must be called after receiving the transport parameters
|
||||
func (h *cryptoSetup) marshalPeerParamsForSessionState() []byte {
|
||||
return h.peerParams.MarshalForSessionTicket()
|
||||
b := &bytes.Buffer{}
|
||||
h.peerParams.MarshalForSessionTicket(b)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handlePeerParamsFromSessionState(data []byte) {
|
||||
@@ -477,7 +479,7 @@ func (h *cryptoSetup) maybeSendSessionTicket() {
|
||||
var appData []byte
|
||||
// Save transport parameters to the session ticket if we're allowing 0-RTT.
|
||||
if h.tlsConf.MaxEarlyData > 0 {
|
||||
appData = h.ourParams.MarshalForSessionTicket()
|
||||
appData = (&sessionTicket{Parameters: h.ourParams}).Marshal()
|
||||
}
|
||||
ticket, err := h.conn.GetSessionTicket(appData)
|
||||
if err != nil {
|
||||
@@ -492,12 +494,12 @@ func (h *cryptoSetup) maybeSendSessionTicket() {
|
||||
// accept0RTT is called for the server when receiving the client's session ticket.
|
||||
// It decides whether to accept 0-RTT.
|
||||
func (h *cryptoSetup) accept0RTT(sessionTicketData []byte) bool {
|
||||
var tp TransportParameters
|
||||
if err := tp.UnmarshalFromSessionTicket(sessionTicketData); err != nil {
|
||||
var t sessionTicket
|
||||
if err := t.Unmarshal(sessionTicketData); err != nil {
|
||||
h.logger.Debugf("Unmarshaling transport parameters from session ticket failed: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
valid := h.ourParams.ValidFor0RTT(&tp)
|
||||
valid := h.ourParams.ValidFor0RTT(t.Parameters)
|
||||
if valid {
|
||||
h.logger.Debugf("Accepting 0-RTT.")
|
||||
} else {
|
||||
|
||||
39
internal/handshake/session_ticket.go
Normal file
39
internal/handshake/session_ticket.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
const sessionTicketRevision = 0
|
||||
|
||||
type sessionTicket struct {
|
||||
Parameters *TransportParameters
|
||||
}
|
||||
|
||||
func (t *sessionTicket) Marshal() []byte {
|
||||
b := &bytes.Buffer{}
|
||||
utils.WriteVarInt(b, sessionTicketRevision)
|
||||
t.Parameters.MarshalForSessionTicket(b)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (t *sessionTicket) Unmarshal(b []byte) error {
|
||||
r := bytes.NewReader(b)
|
||||
rev, err := utils.ReadVarInt(r)
|
||||
if err != nil {
|
||||
return errors.New("failed to read session ticket revision")
|
||||
}
|
||||
if rev != sessionTicketRevision {
|
||||
return fmt.Errorf("unknown session ticket revision: %d", rev)
|
||||
}
|
||||
var tp TransportParameters
|
||||
if err := tp.UnmarshalFromSessionTicket(b[len(b)-r.Len():]); err != nil {
|
||||
return fmt.Errorf("unmarshaling transport parameters from session ticket failed: %s", err.Error())
|
||||
}
|
||||
t.Parameters = &tp
|
||||
return nil
|
||||
}
|
||||
42
internal/handshake/session_ticket_test.go
Normal file
42
internal/handshake/session_ticket_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Session Ticket", func() {
|
||||
It("marshals and unmarshals a session ticket", func() {
|
||||
params := &TransportParameters{
|
||||
InitialMaxStreamDataBidiLocal: 1,
|
||||
InitialMaxStreamDataBidiRemote: 2,
|
||||
}
|
||||
var t sessionTicket
|
||||
Expect(t.Unmarshal((&sessionTicket{Parameters: params}).Marshal())).To(Succeed())
|
||||
Expect(t.Parameters.InitialMaxStreamDataBidiLocal).To(BeEquivalentTo(1))
|
||||
Expect(t.Parameters.InitialMaxStreamDataBidiRemote).To(BeEquivalentTo(2))
|
||||
})
|
||||
|
||||
It("refuses to unmarshal if the ticket is too short for the revision", func() {
|
||||
Expect((&sessionTicket{}).Unmarshal([]byte{})).To(MatchError("failed to read session ticket revision"))
|
||||
})
|
||||
|
||||
It("refuses to unmarshal if the revision doesn't match", func() {
|
||||
b := &bytes.Buffer{}
|
||||
utils.WriteVarInt(b, 1337)
|
||||
Expect((&sessionTicket{}).Unmarshal(b.Bytes())).To(MatchError("unknown session ticket revision: 1337"))
|
||||
})
|
||||
|
||||
It("refuses to unmarshal if unmarshaling the transport parameters fails", func() {
|
||||
b := &bytes.Buffer{}
|
||||
utils.WriteVarInt(b, sessionTicketRevision)
|
||||
b.Write([]byte("foobar"))
|
||||
err := (&sessionTicket{}).Unmarshal(b.Bytes())
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("unmarshaling transport parameters from session ticket failed"))
|
||||
})
|
||||
})
|
||||
@@ -343,6 +343,16 @@ var _ = Describe("Transport Parameters", func() {
|
||||
MaxUniStreamNum: protocol.StreamNum(getRandomValue()),
|
||||
}
|
||||
Expect(params.ValidFor0RTT(params)).To(BeTrue())
|
||||
b := &bytes.Buffer{}
|
||||
params.MarshalForSessionTicket(b)
|
||||
var tp TransportParameters
|
||||
Expect(tp.UnmarshalFromSessionTicket(b.Bytes())).To(Succeed())
|
||||
Expect(tp.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal))
|
||||
Expect(tp.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote))
|
||||
Expect(tp.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni))
|
||||
Expect(tp.InitialMaxData).To(Equal(params.InitialMaxData))
|
||||
Expect(tp.MaxBidiStreamNum).To(Equal(params.MaxBidiStreamNum))
|
||||
Expect(tp.MaxUniStreamNum).To(Equal(params.MaxUniStreamNum))
|
||||
})
|
||||
|
||||
It("rejects the parameters if it can't parse them", func() {
|
||||
@@ -352,7 +362,9 @@ var _ = Describe("Transport Parameters", func() {
|
||||
|
||||
It("rejects the parameters if the version changed", func() {
|
||||
var p TransportParameters
|
||||
data := p.MarshalForSessionTicket()
|
||||
buf := &bytes.Buffer{}
|
||||
p.MarshalForSessionTicket(buf)
|
||||
data := buf.Bytes()
|
||||
b := &bytes.Buffer{}
|
||||
utils.WriteVarInt(b, transportParameterMarshalingVersion+1)
|
||||
b.Write(data[utils.VarIntLen(transportParameterMarshalingVersion):])
|
||||
|
||||
@@ -379,8 +379,7 @@ func (p *TransportParameters) marshalVarintParam(b *bytes.Buffer, id transportPa
|
||||
// if the transport parameters changed.
|
||||
// Since the session ticket is encrypted, the serialization format is defined by the server.
|
||||
// For convenience, we use the same format that we also use for sending the transport parameters.
|
||||
func (p *TransportParameters) MarshalForSessionTicket() []byte {
|
||||
b := &bytes.Buffer{}
|
||||
func (p *TransportParameters) MarshalForSessionTicket(b *bytes.Buffer) {
|
||||
utils.WriteVarInt(b, transportParameterMarshalingVersion)
|
||||
startLen := b.Len()
|
||||
b.Write([]byte{0, 0}) // length. Will be replaced later
|
||||
@@ -398,9 +397,8 @@ func (p *TransportParameters) MarshalForSessionTicket() []byte {
|
||||
// initial_max_uni_streams
|
||||
p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
|
||||
|
||||
data := b.Bytes()
|
||||
binary.BigEndian.PutUint16(data[startLen:startLen+2], uint16(b.Len()-2-startLen))
|
||||
return data
|
||||
// replace the length
|
||||
binary.BigEndian.PutUint16(b.Bytes()[startLen:startLen+2], uint16(b.Len()-2-startLen))
|
||||
}
|
||||
|
||||
// UnmarshalFromSessionTicket unmarshals transport parameters from a session ticket.
|
||||
|
||||
Reference in New Issue
Block a user