enforce a minimum value of the remote idle timeout

This prevents a DoS where a peer could send us a really small remote
idle timeout, and we would continuously send it PING frames.
This commit is contained in:
Marten Seemann
2017-10-03 11:06:31 -07:00
parent 0ffb64b5d7
commit 4eec7433d9
7 changed files with 32 additions and 5 deletions

View File

@@ -437,10 +437,10 @@ var _ = Describe("Client Crypto Setup", func() {
})
It("reads the connection paramaters", func() {
shloMap[TagICSL] = []byte{3, 0, 0, 0} // 3 seconds
shloMap[TagICSL] = []byte{13, 0, 0, 0} // 13 seconds
err := cs.handleSHLOMessage(shloMap)
Expect(err).ToNot(HaveOccurred())
Expect(cs.params.GetRemoteIdleTimeout()).To(Equal(3 * time.Second))
Expect(cs.params.GetRemoteIdleTimeout()).To(Equal(13 * time.Second))
})
It("errors if it can't read a connection parameter", func() {

View File

@@ -62,7 +62,7 @@ func (h *paramsNegotiator) SetFromTransportParameters(params []transportParamete
if len(p.Value) != 2 {
return fmt.Errorf("wrong length for idle_timeout: %d (expected 2)", len(p.Value))
}
h.remoteIdleTimeout = time.Duration(binary.BigEndian.Uint16(p.Value)) * time.Second
h.setRemoteIdleTimeout(time.Duration(binary.BigEndian.Uint16(p.Value)) * time.Second)
case omitConnectionIDParameterID:
if len(p.Value) != 0 {
return fmt.Errorf("wrong length for omit_connection_id: %d (expected empty)", len(p.Value))

View File

@@ -132,6 +132,10 @@ func (h *paramsNegotiatorBase) GetMaxIncomingStreams() uint32 {
return utils.MaxUint32(uint32(maxStreams)+protocol.MaxStreamsMinimumIncrement, uint32(float64(maxStreams)*protocol.MaxStreamsMultiplier))
}
func (h *paramsNegotiatorBase) setRemoteIdleTimeout(t time.Duration) {
h.remoteIdleTimeout = utils.MaxDuration(protocol.MinRemoteIdleTimeout, t)
}
func (h *paramsNegotiatorBase) GetRemoteIdleTimeout() time.Duration {
h.mutex.RLock()
defer h.mutex.RUnlock()

View File

@@ -61,7 +61,7 @@ func (h *paramsNegotiatorGQUIC) SetFromMap(params map[Tag][]byte) error {
if err != nil {
return errMalformedTag
}
h.remoteIdleTimeout = time.Duration(clientValue) * time.Second
h.setRemoteIdleTimeout(time.Duration(clientValue) * time.Second)
}
if value, ok := params[TagSFCW]; ok {
if h.flowControlNegotiated {

View File

@@ -212,7 +212,7 @@ var _ = Describe("Params Negotiator (for gQUIC)", func() {
})
Context("idle timeout", func() {
It("sets the negotiated lifetime", func() {
It("sets the remote idle timeout", func() {
values := map[Tag][]byte{
TagICSL: {10, 0, 0, 0},
}
@@ -221,6 +221,17 @@ var _ = Describe("Params Negotiator (for gQUIC)", func() {
Expect(pn.GetRemoteIdleTimeout()).To(Equal(10 * time.Second))
})
It("doesn't allow values below the minimum remote idle timeout", func() {
t := 2 * time.Second
Expect(t).To(BeNumerically("<", protocol.MinRemoteIdleTimeout))
values := map[Tag][]byte{
TagICSL: {uint8(t.Seconds()), 0, 0, 0},
}
err := pn.SetFromMap(values)
Expect(err).ToNot(HaveOccurred())
Expect(pn.GetRemoteIdleTimeout()).To(Equal(protocol.MinRemoteIdleTimeout))
})
It("errors when given an invalid value", func() {
values := map[Tag][]byte{TagICSL: {2, 0, 0}} // 1 byte too short
err := pn.SetFromMap(values)

View File

@@ -106,6 +106,15 @@ var _ = Describe("Params Negotiator (for TLS)", func() {
Expect(err).To(MatchError("missing parameter"))
})
It("doesn't allow values below the minimum remote idle timeout", func() {
t := 2 * time.Second
Expect(t).To(BeNumerically("<", protocol.MinRemoteIdleTimeout))
params[idleTimeoutParameterID] = []byte{0, uint8(t.Seconds())}
err := pn.SetFromTransportParameters(paramsMapToList(params))
Expect(err).ToNot(HaveOccurred())
Expect(pn.GetRemoteIdleTimeout()).To(Equal(protocol.MinRemoteIdleTimeout))
})
It("rejects the parameters if the initial_max_stream_data has the wrong length", func() {
params[initialMaxStreamDataParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes
err := pn.SetFromTransportParameters(paramsMapToList(params))

View File

@@ -113,6 +113,9 @@ const CryptoParameterMaxLength = 4000
// EphermalKeyLifetime is the lifetime of the ephermal key during the handshake, see handshake.getEphermalKEX.
const EphermalKeyLifetime = time.Minute
// MinRemoteIdleTimeout is the minimum value that we accept for the remote idle timeout
const MinRemoteIdleTimeout = 5 * time.Second
// DefaultIdleTimeout is the default idle timeout
const DefaultIdleTimeout = 30 * time.Second