Skip to content

Commit 48fe23d

Browse files
committed
Include RenegotiationInfo in ServerHello
Before if clients sent a ClientHello with RenegotiationInfo we would just ignore. Now we properly respond that we don't support. Relates to #314
1 parent eee772b commit 48fe23d

4 files changed

Lines changed: 135 additions & 5 deletions

File tree

conn_test.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,3 +1902,125 @@ func TestMultipleHelloVerifyRequest(t *testing.T) {
19021902
}
19031903
cancel()
19041904
}
1905+
1906+
// Assert that a DTLS Server only responds with RenegotiationInfo if
1907+
// a ClientHello contained that extension
1908+
func TestRenegotationInfo(t *testing.T) {
1909+
// Limit runtime in case of deadlocks
1910+
lim := test.TimeOut(10 * time.Second)
1911+
defer lim.Stop()
1912+
1913+
// Check for leaking routines
1914+
report := test.CheckRoutines(t)
1915+
defer report()
1916+
1917+
resp := make([]byte, 1024)
1918+
1919+
for _, testCase := range []struct {
1920+
Name string
1921+
ExpectRenegotiationInfo bool
1922+
}{
1923+
{
1924+
"Include RenegotiationInfo",
1925+
true,
1926+
},
1927+
{
1928+
"No RenegotiationInfo",
1929+
false,
1930+
},
1931+
} {
1932+
test := testCase
1933+
t.Run(test.Name, func(t *testing.T) {
1934+
sendClientHello := func(cookie []byte, ca net.Conn, sequenceNumber uint64) {
1935+
extensions := []extension.Extension{}
1936+
if test.ExpectRenegotiationInfo {
1937+
extensions = append(extensions, &extension.RenegotiationInfo{
1938+
RenegotiatedConnection: 0,
1939+
})
1940+
}
1941+
1942+
packet, err := (&recordlayer.RecordLayer{
1943+
Header: recordlayer.Header{
1944+
Version: protocol.Version1_2,
1945+
SequenceNumber: sequenceNumber,
1946+
},
1947+
Content: &handshake.Handshake{
1948+
Header: handshake.Header{
1949+
MessageSequence: uint16(sequenceNumber),
1950+
},
1951+
Message: &handshake.MessageClientHello{
1952+
Version: protocol.Version1_2,
1953+
Cookie: cookie,
1954+
CipherSuiteIDs: cipherSuiteIDs(defaultCipherSuites()),
1955+
CompressionMethods: defaultCompressionMethods(),
1956+
Extensions: extensions,
1957+
},
1958+
},
1959+
}).Marshal()
1960+
if err != nil {
1961+
t.Fatal(err)
1962+
}
1963+
1964+
if _, err = ca.Write(packet); err != nil {
1965+
t.Fatal(err)
1966+
}
1967+
}
1968+
1969+
ca, cb := dpipe.Pipe()
1970+
defer func() {
1971+
if err := ca.Close(); err != nil {
1972+
t.Error(err)
1973+
}
1974+
}()
1975+
1976+
ctx, cancel := context.WithCancel(context.Background())
1977+
defer cancel()
1978+
1979+
go func() {
1980+
if _, err := testServer(ctx, cb, &Config{}, true); !errors.Is(err, context.Canceled) {
1981+
t.Error(err)
1982+
}
1983+
}()
1984+
1985+
time.Sleep(50 * time.Millisecond)
1986+
1987+
sendClientHello([]byte{}, ca, 0)
1988+
n, err := ca.Read(resp)
1989+
if err != nil {
1990+
t.Fatal(err)
1991+
}
1992+
r := &recordlayer.RecordLayer{}
1993+
if err = r.Unmarshal(resp[:n]); err != nil {
1994+
t.Fatal(err)
1995+
}
1996+
1997+
helloVerifyRequest := r.Content.(*handshake.Handshake).Message.(*handshake.MessageHelloVerifyRequest)
1998+
1999+
sendClientHello(helloVerifyRequest.Cookie, ca, 1)
2000+
if n, err = ca.Read(resp); err != nil {
2001+
t.Fatal(err)
2002+
}
2003+
2004+
messages, err := recordlayer.UnpackDatagram(resp[:n])
2005+
if err != nil {
2006+
t.Fatal(err)
2007+
}
2008+
2009+
if err := r.Unmarshal(messages[0]); err != nil {
2010+
t.Fatal(err)
2011+
}
2012+
2013+
serverHello := r.Content.(*handshake.Handshake).Message.(*handshake.MessageServerHello)
2014+
actualNegotationInfo := false
2015+
for _, v := range serverHello.Extensions {
2016+
if _, ok := v.(*extension.RenegotiationInfo); ok {
2017+
actualNegotationInfo = true
2018+
}
2019+
}
2020+
2021+
if test.ExpectRenegotiationInfo != actualNegotationInfo {
2022+
t.Fatalf("NegotationInfo state in ServerHello is incorrect: expected(%t) actual(%t)", test.ExpectRenegotiationInfo, actualNegotationInfo)
2023+
}
2024+
})
2025+
}
2026+
}

flight0handler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ func flight0Parse(ctx context.Context, c flightConn, state *State, cache *handsh
6464
}
6565
case *extension.ServerName:
6666
state.serverName = e.ServerName // remote server name
67+
case *extension.RenegotiationInfo:
68+
state.remoteSupportsRenegotiation = true
6769
}
6870
}
6971

flight4handler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ func flight4Generate(c flightConn, state *State, cache *handshakeCache, cfg *han
185185
ProtectionProfiles: []SRTPProtectionProfile{state.srtpProtectionProfile},
186186
})
187187
}
188+
if state.remoteSupportsRenegotiation {
189+
extensions = append(extensions, &extension.RenegotiationInfo{
190+
RenegotiatedConnection: 0,
191+
})
192+
}
188193
if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {
189194
extensions = append(extensions, []extension.Extension{
190195
&extension.SupportedEllipticCurves{

state.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ import (
1313

1414
// State holds the dtls connection state and implements both encoding.BinaryMarshaler and encoding.BinaryUnmarshaler
1515
type State struct {
16-
localEpoch, remoteEpoch atomic.Value
17-
localSequenceNumber []uint64 // uint48
18-
localRandom, remoteRandom handshake.Random
19-
masterSecret []byte
20-
cipherSuite CipherSuite // nil if a cipherSuite hasn't been chosen
16+
localEpoch, remoteEpoch atomic.Value
17+
localSequenceNumber []uint64 // uint48
18+
localRandom, remoteRandom handshake.Random
19+
masterSecret []byte
20+
cipherSuite CipherSuite // nil if a cipherSuite hasn't been chosen
21+
remoteSupportsRenegotiation bool // did ClientHello contain a RenegotiationInfo
2122

2223
srtpProtectionProfile SRTPProtectionProfile // Negotiated SRTPProtectionProfile
2324
PeerCertificates [][]byte

0 commit comments

Comments
 (0)