introduce a marshaling format for data saved in the session ticket

This commit is contained in:
Marten Seemann
2020-02-02 10:52:52 +07:00
parent a8fc893ec4
commit 3e32a693ad
5 changed files with 104 additions and 11 deletions

View File

@@ -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 {

View 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
}

View 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"))
})
})

View File

@@ -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):])

View File

@@ -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.