]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/tls: return a typed error on invalid record headers
authorCaleb Spare <cespare@gmail.com>
Tue, 20 Oct 2015 07:23:11 +0000 (00:23 -0700)
committerAdam Langley <agl@golang.org>
Mon, 16 Nov 2015 21:54:44 +0000 (21:54 +0000)
The user can inspect the record data to detect that the other side is
not using the TLS protocol.

This will be used by the net/http client (in a follow-on CL) to detect
when an HTTPS client is speaking to an HTTP server.

Updates #11111.

Change-Id: I872f78717aa8e8e98cebd8075436209a52039a73
Reviewed-on: https://go-review.googlesource.com/16078
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/crypto/tls/conn.go

index 7638bbc6a9934d9ddc316a03e6196bb27851c17b..115b6c6578c9deb5397f1795e3a2e0e46767a411 100644 (file)
@@ -506,6 +506,23 @@ func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
        return b, bb
 }
 
+// RecordHeaderError results when a TLS record header is invalid.
+type RecordHeaderError struct {
+       // Msg contains a human readable string that describes the error.
+       Msg string
+       // RecordHeader contains the five bytes of TLS record header that
+       // triggered the error.
+       RecordHeader [5]byte
+}
+
+func (e RecordHeaderError) Error() string { return "tls: " + e.Msg }
+
+func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) {
+       err.Msg = msg
+       copy(err.RecordHeader[:], c.rawInput.data)
+       return err
+}
+
 // readRecord reads the next TLS record from the connection
 // and updates the record layer state.
 // c.in.Mutex <= L; c.input == nil.
@@ -556,18 +573,20 @@ Again:
        // an SSLv2 client.
        if want == recordTypeHandshake && typ == 0x80 {
                c.sendAlert(alertProtocolVersion)
-               return c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
+               return c.in.setErrorLocked(c.newRecordHeaderError("unsupported SSLv2 handshake received"))
        }
 
        vers := uint16(b.data[1])<<8 | uint16(b.data[2])
        n := int(b.data[3])<<8 | int(b.data[4])
        if c.haveVers && vers != c.vers {
                c.sendAlert(alertProtocolVersion)
-               return c.in.setErrorLocked(fmt.Errorf("tls: 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, c.vers)
+               return c.in.setErrorLocked(c.newRecordHeaderError(msg))
        }
        if n > maxCiphertext {
                c.sendAlert(alertRecordOverflow)
-               return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
+               msg := fmt.Sprintf("oversized record received with length %d", n)
+               return c.in.setErrorLocked(c.newRecordHeaderError(msg))
        }
        if !c.haveVers {
                // First message, be extra suspicious: this might not be a TLS
@@ -576,7 +595,7 @@ Again:
                // it's probably not real.
                if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 {
                        c.sendAlert(alertUnexpectedMessage)
-                       return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
+                       return c.in.setErrorLocked(c.newRecordHeaderError("first record does not look like a TLS handshake"))
                }
        }
        if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {