Commit 45d1c8ab authored by Caleb Spare's avatar Caleb Spare Committed by Adam Langley

crypto/tls: return a typed error on invalid record headers

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/16078Reviewed-by: 's avatarAdam Langley <agl@golang.org>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent bf5b4e71
......@@ -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 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment