diff --git a/conn.go b/conn.go index a5e19dc..847d3f8 100644 --- a/conn.go +++ b/conn.go @@ -639,10 +639,16 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error { } vers := uint16(hdr[1])<<8 | uint16(hdr[2]) + expectedVers := c.vers + if expectedVers == VersionTLS13 { + // All TLS 1.3 records are expected to have 0x0303 (1.2) after + // the initial hello (RFC 8446 Section 5.1). + expectedVers = VersionTLS12 + } n := int(hdr[3])<<8 | int(hdr[4]) - if c.haveVers && c.vers != VersionTLS13 && vers != c.vers { + if c.haveVers && vers != expectedVers { c.sendAlert(alertProtocolVersion) - msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers) + msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, expectedVers) return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg)) } if !c.haveVers { diff --git a/conn_test.go b/conn_test.go index 78935b1..5e090a0 100644 --- a/conn_test.go +++ b/conn_test.go @@ -285,3 +285,35 @@ func TestHairpinInClose(t *testing.T) { // This call should not deadlock. tlsConn.Close() } + +func TestRecordBadVersionTLS13(t *testing.T) { + client, server := localPipe(t) + defer server.Close() + defer client.Close() + + config := testConfig.Clone() + config.MinVersion, config.MaxVersion = VersionTLS13, VersionTLS13 + + go func() { + tlsConn := Client(client, config) + if err := tlsConn.Handshake(); err != nil { + t.Errorf("Error from client handshake: %v", err) + return + } + tlsConn.vers = 0x1111 + tlsConn.Write([]byte{1}) + }() + + tlsConn := Server(server, config) + if err := tlsConn.Handshake(); err != nil { + t.Errorf("Error from client handshake: %v", err) + return + } + + expectedErr := "tls: received record with version 1111 when expecting version 303" + + _, err := tlsConn.Read(make([]byte, 10)) + if err.Error() != expectedErr { + t.Fatalf("unexpected error: got %q, want %q", err, expectedErr) + } +}