Skip to content

Commit af125a5

Browse files
committed
crypto/tls: allow renegotiation to be handled by a client.
This change adds Config.Renegotiation which controls whether a TLS client will accept renegotiation requests from a server. This is used, for example, by some web servers that wish to “add” a client certificate to an HTTPS connection. This is disabled by default because it significantly complicates the state machine. Originally, handshakeMutex was taken before locking either Conn.in or Conn.out. However, if renegotiation is permitted then a handshake may be triggered during a Read() call. If Conn.in were unlocked before taking handshakeMutex then a concurrent Read() call could see an intermediate state and trigger an error. Thus handshakeMutex is now locked after Conn.in and the handshake functions assume that Conn.in is locked for the duration of the handshake. Additionally, handshakeMutex used to protect Conn.out also. With the possibility of renegotiation that's no longer viable and so writeRecordLocked has been split off. Fixes #5742. Change-Id: I935914db1f185d507ff39bba8274c148d756a1c8 Reviewed-on: https://go-review.googlesource.com/22475 Run-TryBot: Adam Langley <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Russ Cox <[email protected]>
1 parent d610d30 commit af125a5

12 files changed

+1633
-162
lines changed

src/crypto/tls/common.go

+32
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const (
4848

4949
// TLS handshake message types.
5050
const (
51+
typeHelloRequest uint8 = 0
5152
typeClientHello uint8 = 1
5253
typeServerHello uint8 = 2
5354
typeNewSessionTicket uint8 = 4
@@ -238,6 +239,33 @@ type ClientHelloInfo struct {
238239
SupportedPoints []uint8
239240
}
240241

242+
// RenegotiationSupport enumerates the different levels of support for TLS
243+
// renegotiation. TLS renegotiation is the act of performing subsequent
244+
// handshakes on a connection after the first. This significantly complicates
245+
// the state machine and has been the source of numerous, subtle security
246+
// issues. Initiating a renegotiation is not supported, but support for
247+
// accepting renegotiation requests may be enabled.
248+
//
249+
// Even when enabled, the server may not change its identity between handshakes
250+
// (i.e. the leaf certificate must be the same). Additionally, concurrent
251+
// handshake and application data flow is not permitted so renegotiation can
252+
// only be used with protocols that synchronise with the renegotiation, such as
253+
// HTTPS.
254+
type RenegotiationSupport int
255+
256+
const (
257+
// RenegotiateNever disables renegotiation.
258+
RenegotiateNever RenegotiationSupport = iota
259+
260+
// RenegotiateOnceAsClient allows a remote server to request
261+
// renegotiation once per connection.
262+
RenegotiateOnceAsClient
263+
264+
// RenegotiateFreelyAsClient allows a remote server to repeatedly
265+
// request renegotiation.
266+
RenegotiateFreelyAsClient
267+
)
268+
241269
// A Config structure is used to configure a TLS client or server.
242270
// After one has been passed to a TLS function it must not be
243271
// modified. A Config may be reused; the tls package will also not
@@ -355,6 +383,10 @@ type Config struct {
355383
// improve latency.
356384
DynamicRecordSizingDisabled bool
357385

386+
// Renegotiation controls what types of renegotiation are supported.
387+
// The default, none, is correct for the vast majority of applications.
388+
Renegotiation RenegotiationSupport
389+
358390
serverInitOnce sync.Once // guards calling (*Config).serverInit
359391

360392
// mutex protects sessionTicketKeys

src/crypto/tls/conn.go

+138-36
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,44 @@ type Conn struct {
2828
isClient bool
2929

3030
// constant after handshake; protected by handshakeMutex
31-
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
32-
handshakeErr error // error resulting from handshake
33-
vers uint16 // TLS version
34-
haveVers bool // version has been negotiated
35-
config *Config // configuration passed to constructor
31+
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
32+
handshakeErr error // error resulting from handshake
33+
vers uint16 // TLS version
34+
haveVers bool // version has been negotiated
35+
config *Config // configuration passed to constructor
36+
// handshakeComplete is true if the connection is currently transfering
37+
// application data (i.e. is not currently processing a handshake).
3638
handshakeComplete bool
37-
didResume bool // whether this connection was a session resumption
38-
cipherSuite uint16
39-
ocspResponse []byte // stapled OCSP response
40-
scts [][]byte // signed certificate timestamps from server
41-
peerCertificates []*x509.Certificate
39+
// handshakes counts the number of handshakes performed on the
40+
// connection so far. If renegotiation is disabled then this is either
41+
// zero or one.
42+
handshakes int
43+
didResume bool // whether this connection was a session resumption
44+
cipherSuite uint16
45+
ocspResponse []byte // stapled OCSP response
46+
scts [][]byte // signed certificate timestamps from server
47+
peerCertificates []*x509.Certificate
4248
// verifiedChains contains the certificate chains that we built, as
4349
// opposed to the ones presented by the server.
4450
verifiedChains [][]*x509.Certificate
4551
// serverName contains the server name indicated by the client, if any.
4652
serverName string
47-
// firstFinished contains the first Finished hash sent during the
48-
// handshake. This is the "tls-unique" channel binding value.
49-
firstFinished [12]byte
53+
// secureRenegotiation is true if the server echoed the secure
54+
// renegotiation extension. (This is meaningless as a server because
55+
// renegotiation is not supported in that case.)
56+
secureRenegotiation bool
57+
58+
// clientFinishedIsFirst is true if the client sent the first Finished
59+
// message during the most recent handshake. This is recorded because
60+
// the first transmitted Finished message is the tls-unique
61+
// channel-binding value.
62+
clientFinishedIsFirst bool
63+
// clientFinished and serverFinished contain the Finished message sent
64+
// by the client or server in the most recent handshake. This is
65+
// retained to support the renegotiation extension and tls-unique
66+
// channel-binding.
67+
clientFinished [12]byte
68+
serverFinished [12]byte
5069

5170
clientProtocol string
5271
clientProtocolFallback bool
@@ -128,13 +147,6 @@ func (hc *halfConn) setErrorLocked(err error) error {
128147
return err
129148
}
130149

131-
func (hc *halfConn) error() error {
132-
hc.Lock()
133-
err := hc.err
134-
hc.Unlock()
135-
return err
136-
}
137-
138150
// prepareCipherSpec sets the encryption and MAC states
139151
// that a subsequent changeCipherSpec will use.
140152
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
@@ -532,20 +544,20 @@ func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) {
532544
func (c *Conn) readRecord(want recordType) error {
533545
// Caller must be in sync with connection:
534546
// handshake data if handshake not yet completed,
535-
// else application data. (We don't support renegotiation.)
547+
// else application data.
536548
switch want {
537549
default:
538550
c.sendAlert(alertInternalError)
539551
return c.in.setErrorLocked(errors.New("tls: unknown record type requested"))
540552
case recordTypeHandshake, recordTypeChangeCipherSpec:
541553
if c.handshakeComplete {
542554
c.sendAlert(alertInternalError)
543-
return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
555+
return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested while not in handshake"))
544556
}
545557
case recordTypeApplicationData:
546558
if !c.handshakeComplete {
547559
c.sendAlert(alertInternalError)
548-
return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
560+
return c.in.setErrorLocked(errors.New("tls: application data record requested while in handshake"))
549561
}
550562
}
551563

@@ -669,7 +681,7 @@ Again:
669681

670682
case recordTypeHandshake:
671683
// TODO(rsc): Should at least pick off connection close.
672-
if typ != want {
684+
if typ != want && !(c.isClient && c.config.Renegotiation != RenegotiateNever) {
673685
return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
674686
}
675687
c.hand.Write(data)
@@ -692,7 +704,7 @@ func (c *Conn) sendAlertLocked(err alert) error {
692704
}
693705
c.tmp[1] = byte(err)
694706

695-
_, writeErr := c.writeRecord(recordTypeAlert, c.tmp[0:2])
707+
_, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2])
696708
if err == alertCloseNotify {
697709
// closeNotify is a special case in that it isn't an error.
698710
return writeErr
@@ -779,10 +791,10 @@ func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int {
779791
return payloadBytes
780792
}
781793

782-
// writeRecord writes a TLS record with the given type and payload
783-
// to the connection and updates the record layer state.
794+
// writeRecordLocked writes a TLS record with the given type and payload to the
795+
// connection and updates the record layer state.
784796
// c.out.Mutex <= L.
785-
func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
797+
func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
786798
b := c.out.newBlock()
787799
defer c.out.freeBlock(b)
788800

@@ -855,6 +867,16 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
855867
return n, nil
856868
}
857869

870+
// writeRecord writes a TLS record with the given type and payload to the
871+
// connection and updates the record layer state.
872+
// L < c.out.Mutex.
873+
func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
874+
c.out.Lock()
875+
defer c.out.Unlock()
876+
877+
return c.writeRecordLocked(typ, data)
878+
}
879+
858880
// readHandshake reads the next handshake message from
859881
// the record layer.
860882
// c.in.Mutex < L; c.out.Mutex < L.
@@ -885,6 +907,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
885907
data = c.hand.Next(4 + n)
886908
var m handshakeMessage
887909
switch data[0] {
910+
case typeHelloRequest:
911+
m = new(helloRequestMsg)
888912
case typeClientHello:
889913
m = new(clientHelloMsg)
890914
case typeServerHello:
@@ -971,18 +995,60 @@ func (c *Conn) Write(b []byte) (int, error) {
971995
var m int
972996
if len(b) > 1 && c.vers <= VersionTLS10 {
973997
if _, ok := c.out.cipher.(cipher.BlockMode); ok {
974-
n, err := c.writeRecord(recordTypeApplicationData, b[:1])
998+
n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
975999
if err != nil {
9761000
return n, c.out.setErrorLocked(err)
9771001
}
9781002
m, b = 1, b[1:]
9791003
}
9801004
}
9811005

982-
n, err := c.writeRecord(recordTypeApplicationData, b)
1006+
n, err := c.writeRecordLocked(recordTypeApplicationData, b)
9831007
return n + m, c.out.setErrorLocked(err)
9841008
}
9851009

1010+
// handleRenegotiation processes a HelloRequest handshake message.
1011+
// c.in.Mutex <= L
1012+
func (c *Conn) handleRenegotiation() error {
1013+
msg, err := c.readHandshake()
1014+
if err != nil {
1015+
return err
1016+
}
1017+
1018+
_, ok := msg.(*helloRequestMsg)
1019+
if !ok {
1020+
c.sendAlert(alertUnexpectedMessage)
1021+
return alertUnexpectedMessage
1022+
}
1023+
1024+
if !c.isClient {
1025+
return c.sendAlert(alertNoRenegotiation)
1026+
}
1027+
1028+
switch c.config.Renegotiation {
1029+
case RenegotiateNever:
1030+
return c.sendAlert(alertNoRenegotiation)
1031+
case RenegotiateOnceAsClient:
1032+
if c.handshakes > 1 {
1033+
return c.sendAlert(alertNoRenegotiation)
1034+
}
1035+
case RenegotiateFreelyAsClient:
1036+
// Ok.
1037+
default:
1038+
c.sendAlert(alertInternalError)
1039+
return errors.New("tls: unknown Renegotiation value")
1040+
}
1041+
1042+
c.handshakeMutex.Lock()
1043+
defer c.handshakeMutex.Unlock()
1044+
1045+
c.handshakeComplete = false
1046+
if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil {
1047+
c.handshakes++
1048+
}
1049+
return c.handshakeErr
1050+
}
1051+
9861052
// Read can be made to time out and return a net.Error with Timeout() == true
9871053
// after a fixed time limit; see SetDeadline and SetReadDeadline.
9881054
func (c *Conn) Read(b []byte) (n int, err error) {
@@ -1007,6 +1073,13 @@ func (c *Conn) Read(b []byte) (n int, err error) {
10071073
// Soft error, like EAGAIN
10081074
return 0, err
10091075
}
1076+
if c.hand.Len() > 0 {
1077+
// We received handshake bytes, indicating the
1078+
// start of a renegotiation.
1079+
if err := c.handleRenegotiation(); err != nil {
1080+
return 0, err
1081+
}
1082+
}
10101083
}
10111084
if err := c.in.err; err != nil {
10121085
return 0, err
@@ -1087,20 +1160,45 @@ func (c *Conn) Close() error {
10871160
// Most uses of this package need not call Handshake
10881161
// explicitly: the first Read or Write will call it automatically.
10891162
func (c *Conn) Handshake() error {
1163+
// c.handshakeErr and c.handshakeComplete are protected by
1164+
// c.handshakeMutex. In order to perform a handshake, we need to lock
1165+
// c.in also and c.handshakeMutex must be locked after c.in.
1166+
//
1167+
// However, if a Read() operation is hanging then it'll be holding the
1168+
// lock on c.in and so taking it here would cause all operations that
1169+
// need to check whether a handshake is pending (such as Write) to
1170+
// block.
1171+
//
1172+
// Thus we take c.handshakeMutex first and, if we find that a handshake
1173+
// is needed, then we unlock, acquire c.in and c.handshakeMutex in the
1174+
// correct order, and check again.
10901175
c.handshakeMutex.Lock()
10911176
defer c.handshakeMutex.Unlock()
1092-
if err := c.handshakeErr; err != nil {
1093-
return err
1094-
}
1095-
if c.handshakeComplete {
1096-
return nil
1177+
1178+
for i := 0; i < 2; i++ {
1179+
if i == 1 {
1180+
c.handshakeMutex.Unlock()
1181+
c.in.Lock()
1182+
defer c.in.Unlock()
1183+
c.handshakeMutex.Lock()
1184+
}
1185+
1186+
if err := c.handshakeErr; err != nil {
1187+
return err
1188+
}
1189+
if c.handshakeComplete {
1190+
return nil
1191+
}
10971192
}
10981193

10991194
if c.isClient {
11001195
c.handshakeErr = c.clientHandshake()
11011196
} else {
11021197
c.handshakeErr = c.serverHandshake()
11031198
}
1199+
if c.handshakeErr == nil {
1200+
c.handshakes++
1201+
}
11041202
return c.handshakeErr
11051203
}
11061204

@@ -1123,7 +1221,11 @@ func (c *Conn) ConnectionState() ConnectionState {
11231221
state.SignedCertificateTimestamps = c.scts
11241222
state.OCSPResponse = c.ocspResponse
11251223
if !c.didResume {
1126-
state.TLSUnique = c.firstFinished[:]
1224+
if c.clientFinishedIsFirst {
1225+
state.TLSUnique = c.clientFinished[:]
1226+
} else {
1227+
state.TLSUnique = c.serverFinished[:]
1228+
}
11271229
}
11281230
}
11291231

0 commit comments

Comments
 (0)