Skip to content

Commit 62a3f2e

Browse files
committed
crypto/tls: add Config.VerifyConnection callback
Since the ConnectionState will now be available during verification, some code was moved around in order to initialize and make available as much of the fields on Conn as possible before the ConnectionState is verified. Fixes #36736 Change-Id: I0e3efa97565ead7de5c48bb8a87e3ea54fbde140 Reviewed-on: https://go-review.googlesource.com/c/go/+/229122 Run-TryBot: Katie Hockman <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 43f2f50 commit 62a3f2e

8 files changed

+266
-71
lines changed

src/crypto/tls/common.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ type ConnectionState struct {
219219
CipherSuite uint16 // cipher suite in use (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ...)
220220
NegotiatedProtocol string // negotiated next protocol (not guaranteed to be from Config.NextProtos)
221221
NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server (client side only)
222-
ServerName string // server name requested by client, if any (server side only)
222+
ServerName string // server name requested by client, if any
223223
PeerCertificates []*x509.Certificate // certificate chain presented by remote peer
224224
VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
225225
SignedCertificateTimestamps [][]byte // SCTs from the peer, if any
@@ -520,6 +520,16 @@ type Config struct {
520520
// be considered but the verifiedChains argument will always be nil.
521521
VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
522522

523+
// VerifyConnection, if not nil, is called after normal certificate
524+
// verification and after VerifyPeerCertificate by either a TLS client
525+
// or server. If it returns a non-nil error, the handshake is aborted
526+
// and that error results.
527+
//
528+
// If normal verification fails then the handshake will abort before
529+
// considering this callback. This callback will run for all connections
530+
// regardless of InsecureSkipVerify or ClientAuth settings.
531+
VerifyConnection func(ConnectionState) error
532+
523533
// RootCAs defines the set of root certificate authorities
524534
// that clients use when verifying server certificates.
525535
// If RootCAs is nil, TLS uses the host's root CA set.
@@ -685,6 +695,7 @@ func (c *Config) Clone() *Config {
685695
GetClientCertificate: c.GetClientCertificate,
686696
GetConfigForClient: c.GetConfigForClient,
687697
VerifyPeerCertificate: c.VerifyPeerCertificate,
698+
VerifyConnection: c.VerifyConnection,
688699
RootCAs: c.RootCAs,
689700
NextProtos: c.NextProtos,
690701
ServerName: c.ServerName,

src/crypto/tls/conn.go

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,35 +1379,34 @@ func (c *Conn) Handshake() error {
13791379
func (c *Conn) ConnectionState() ConnectionState {
13801380
c.handshakeMutex.Lock()
13811381
defer c.handshakeMutex.Unlock()
1382+
return c.connectionStateLocked()
1383+
}
13821384

1385+
func (c *Conn) connectionStateLocked() ConnectionState {
13831386
var state ConnectionState
13841387
state.HandshakeComplete = c.handshakeComplete()
1388+
state.Version = c.vers
1389+
state.NegotiatedProtocol = c.clientProtocol
1390+
state.DidResume = c.didResume
1391+
state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
13851392
state.ServerName = c.serverName
1386-
1387-
if state.HandshakeComplete {
1388-
state.Version = c.vers
1389-
state.NegotiatedProtocol = c.clientProtocol
1390-
state.DidResume = c.didResume
1391-
state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
1392-
state.CipherSuite = c.cipherSuite
1393-
state.PeerCertificates = c.peerCertificates
1394-
state.VerifiedChains = c.verifiedChains
1395-
state.SignedCertificateTimestamps = c.scts
1396-
state.OCSPResponse = c.ocspResponse
1397-
if !c.didResume && c.vers != VersionTLS13 {
1398-
if c.clientFinishedIsFirst {
1399-
state.TLSUnique = c.clientFinished[:]
1400-
} else {
1401-
state.TLSUnique = c.serverFinished[:]
1402-
}
1403-
}
1404-
if c.config.Renegotiation != RenegotiateNever {
1405-
state.ekm = noExportedKeyingMaterial
1393+
state.CipherSuite = c.cipherSuite
1394+
state.PeerCertificates = c.peerCertificates
1395+
state.VerifiedChains = c.verifiedChains
1396+
state.SignedCertificateTimestamps = c.scts
1397+
state.OCSPResponse = c.ocspResponse
1398+
if !c.didResume && c.vers != VersionTLS13 {
1399+
if c.clientFinishedIsFirst {
1400+
state.TLSUnique = c.clientFinished[:]
14061401
} else {
1407-
state.ekm = c.ekm
1402+
state.TLSUnique = c.serverFinished[:]
14081403
}
14091404
}
1410-
1405+
if c.config.Renegotiation != RenegotiateNever {
1406+
state.ekm = noExportedKeyingMaterial
1407+
} else {
1408+
state.ekm = c.ekm
1409+
}
14111410
return state
14121411
}
14131412

src/crypto/tls/handshake_client.go

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ func (c *Conn) clientHandshake() (err error) {
146146
if err != nil {
147147
return err
148148
}
149+
c.serverName = hello.serverName
149150

150151
cacheKey, session, earlySecret, binderKey := c.loadSession(hello)
151152
if cacheKey != "" && session != nil {
@@ -388,6 +389,7 @@ func (hs *clientHandshakeState) handshake() error {
388389
hs.finishedHash.Write(hs.serverHello.marshal())
389390

390391
c.buffering = true
392+
c.didResume = isResume
391393
if isResume {
392394
if err := hs.establishKeys(); err != nil {
393395
return err
@@ -399,6 +401,15 @@ func (hs *clientHandshakeState) handshake() error {
399401
return err
400402
}
401403
c.clientFinishedIsFirst = false
404+
// Make sure the connection is still being verified whether or not this
405+
// is a resumption. Resumptions currently don't reverify certificates so
406+
// they don't call verifyServerCertificate. See Issue 31641.
407+
if c.config.VerifyConnection != nil {
408+
if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
409+
c.sendAlert(alertBadCertificate)
410+
return err
411+
}
412+
}
402413
if err := hs.sendFinished(c.clientFinished[:]); err != nil {
403414
return err
404415
}
@@ -428,7 +439,6 @@ func (hs *clientHandshakeState) handshake() error {
428439
}
429440

430441
c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
431-
c.didResume = isResume
432442
atomic.StoreUint32(&c.handshakeStatus, 1)
433443

434444
return nil
@@ -458,25 +468,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
458468
}
459469
hs.finishedHash.Write(certMsg.marshal())
460470

461-
if c.handshakes == 0 {
462-
// If this is the first handshake on a connection, process and
463-
// (optionally) verify the server's certificates.
464-
if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
465-
return err
466-
}
467-
} else {
468-
// This is a renegotiation handshake. We require that the
469-
// server's identity (i.e. leaf certificate) is unchanged and
470-
// thus any previous trust decision is still valid.
471-
//
472-
// See https://mitls.org/pages/attacks/3SHAKE for the
473-
// motivation behind this requirement.
474-
if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
475-
c.sendAlert(alertBadCertificate)
476-
return errors.New("tls: server's identity changed during renegotiation")
477-
}
478-
}
479-
480471
msg, err = c.readHandshake()
481472
if err != nil {
482473
return err
@@ -505,6 +496,25 @@ func (hs *clientHandshakeState) doFullHandshake() error {
505496
}
506497
}
507498

499+
if c.handshakes == 0 {
500+
// If this is the first handshake on a connection, process and
501+
// (optionally) verify the server's certificates.
502+
if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
503+
return err
504+
}
505+
} else {
506+
// This is a renegotiation handshake. We require that the
507+
// server's identity (i.e. leaf certificate) is unchanged and
508+
// thus any previous trust decision is still valid.
509+
//
510+
// See https://mitls.org/pages/attacks/3SHAKE for the
511+
// motivation behind this requirement.
512+
if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
513+
c.sendAlert(alertBadCertificate)
514+
return errors.New("tls: server's identity changed during renegotiation")
515+
}
516+
}
517+
508518
keyAgreement := hs.suite.ka(c.vers)
509519

510520
skx, ok := msg.(*serverKeyExchangeMsg)
@@ -831,13 +841,6 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
831841
}
832842
}
833843

834-
if c.config.VerifyPeerCertificate != nil {
835-
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
836-
c.sendAlert(alertBadCertificate)
837-
return err
838-
}
839-
}
840-
841844
switch certs[0].PublicKey.(type) {
842845
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
843846
break
@@ -848,6 +851,20 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
848851

849852
c.peerCertificates = certs
850853

854+
if c.config.VerifyPeerCertificate != nil {
855+
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
856+
c.sendAlert(alertBadCertificate)
857+
return err
858+
}
859+
}
860+
861+
if c.config.VerifyConnection != nil {
862+
if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
863+
c.sendAlert(alertBadCertificate)
864+
return err
865+
}
866+
}
867+
851868
return nil
852869
}
853870

0 commit comments

Comments
 (0)