0
0
mirror of https://github.com/XTLS/REALITY.git synced 2025-08-22 14:38:35 +00:00

crypto/tls: implement Extended Master Secret

All OpenSSL tests now test operation with EMS. To test a handshake
*without* EMS we need to pass -Options=-ExtendedMasterSecret which is
only available in OpenSSL 3.1, which breaks a number of other tests.

Updates #43922

Change-Id: Ib9ac79a1d03fab6bfba5fe9cd66689cff661cda7
Reviewed-on: https://go-review.googlesource.com/c/go/+/497376
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
yuhan6665 2023-10-14 09:15:54 -04:00
parent aa68126eeb
commit 14202975e0
8 changed files with 94 additions and 15 deletions

View File

@ -90,6 +90,7 @@ const (
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
extensionSCT uint16 = 18
extensionExtendedMasterSecret uint16 = 23
extensionSessionTicket uint16 = 35
extensionPreSharedKey uint16 = 41
extensionEarlyData uint16 = 42
@ -271,12 +272,8 @@ type ConnectionState struct {
OCSPResponse []byte
// TLSUnique contains the "tls-unique" channel binding value (see RFC 5929,
// Section 3). This value will be nil for TLS 1.3 connections and for all
// resumed connections.
//
// Deprecated: there are conditions in which this value might not be unique
// to a connection. See the Security Considerations sections of RFC 5705 and
// RFC 7627, and https://mitls.org/pages/attacks/3SHAKE#channelbindings.
// Section 3). This value will be nil for TLS 1.3 connections and for
// resumed connections that don't support Extended Master Secret (RFC 7627).
TLSUnique []byte
// ekm is a closure exposed via ExportKeyingMaterial.
@ -287,6 +284,10 @@ type ConnectionState struct {
// slice as defined in RFC 5705. If context is nil, it is not used as part of
// the seed. If the connection was set to allow renegotiation via
// Config.Renegotiation, this function will return an error.
//
// There are conditions in which the returned values might not be unique to a
// connection. See the Security Considerations sections of RFC 5705 and RFC 7627,
// and https://mitls.org/pages/attacks/3SHAKE#channelbindings.
func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
return cs.ekm(label, context, length)
}

View File

@ -50,6 +50,7 @@ type Conn struct {
// connection so far. If renegotiation is disabled then this is either
// zero or one.
handshakes int
extMasterSecret bool
didResume bool // whether this connection was a session resumption
cipherSuite uint16
ocspResponse []byte // stapled OCSP response
@ -1670,7 +1671,7 @@ func (c *Conn) connectionStateLocked() ConnectionState {
state.VerifiedChains = c.verifiedChains
state.SignedCertificateTimestamps = c.scts
state.OCSPResponse = c.ocspResponse
if !c.didResume && c.vers != VersionTLS13 {
if (!c.didResume || c.extMasterSecret) && c.vers != VersionTLS13 {
if c.clientFinishedIsFirst {
state.TLSUnique = c.clientFinished[:]
} else {

View File

@ -72,6 +72,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) {
vers: clientHelloVersion,
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
extendedMasterSecret: true,
ocspStapling: true,
scts: true,
serverName: hostnameInSNI(config.ServerName),
@ -645,6 +646,19 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
}
if hs.serverHello.extendedMasterSecret {
c.extMasterSecret = true
hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
hs.finishedHash.Sum())
} else {
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
hs.hello.random, hs.serverHello.random)
}
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
c.sendAlert(alertInternalError)
return errors.New("tls: failed to write to key log: " + err.Error())
}
if chainToSend != nil && len(chainToSend.Certificate) > 0 {
certVerify := &certificateVerifyMsg{}
@ -692,12 +706,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
c.sendAlert(alertInternalError)
return errors.New("tls: failed to write to key log: " + err.Error())
}
hs.finishedHash.discardHandshakeBuffer()
return nil
@ -784,8 +792,15 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
return false, errors.New("tls: server resumed a session with a different cipher suite")
}
// RFC 7627, Section 5.3
if hs.session.extMasterSecret != hs.serverHello.extendedMasterSecret {
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: server resumed a session with a different EMS extension")
}
// Restore master secret and certificates from previous state
hs.masterSecret = hs.session.secret
c.extMasterSecret = hs.session.extMasterSecret
c.peerCertificates = hs.session.peerCertificates
c.activeCertHandles = hs.c.activeCertHandles
c.verifiedChains = hs.session.verifiedChains

View File

@ -136,6 +136,7 @@ func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error {
if hs.serverHello.ocspStapling ||
hs.serverHello.ticketSupported ||
hs.serverHello.extendedMasterSecret ||
hs.serverHello.secureRenegotiationSupported ||
len(hs.serverHello.secureRenegotiation) != 0 ||
len(hs.serverHello.alpnProtocol) != 0 ||

View File

@ -84,6 +84,7 @@ type clientHelloMsg struct {
supportedSignatureAlgorithmsCert []SignatureScheme
secureRenegotiationSupported bool
secureRenegotiation []byte
extendedMasterSecret bool
alpnProtocols []string
scts bool
supportedVersions []uint16
@ -181,6 +182,11 @@ func (m *clientHelloMsg) marshal() ([]byte, error) {
})
})
}
if m.extendedMasterSecret {
// RFC 7627
exts.AddUint16(extensionExtendedMasterSecret)
exts.AddUint16(0) // empty extension_data
}
if len(m.alpnProtocols) > 0 {
// RFC 7301, Section 3.1
exts.AddUint16(extensionALPN)
@ -510,6 +516,9 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
m.secureRenegotiationSupported = true
case extensionExtendedMasterSecret:
// RFC 7627
m.extendedMasterSecret = true
case extensionALPN:
// RFC 7301, Section 3.1
var protoList cryptobyte.String
@ -627,6 +636,7 @@ type serverHelloMsg struct {
ticketSupported bool
secureRenegotiationSupported bool
secureRenegotiation []byte
extendedMasterSecret bool
alpnProtocol string
scts [][]byte
supportedVersion uint16
@ -662,6 +672,10 @@ func (m *serverHelloMsg) marshal() ([]byte, error) {
})
})
}
if m.extendedMasterSecret {
exts.AddUint16(extensionExtendedMasterSecret)
exts.AddUint16(0) // empty extension_data
}
if len(m.alpnProtocol) > 0 {
exts.AddUint16(extensionALPN)
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
@ -802,6 +816,8 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
m.secureRenegotiationSupported = true
case extensionExtendedMasterSecret:
m.extendedMasterSecret = true
case extensionALPN:
var protoList cryptobyte.String
if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {

View File

@ -214,6 +214,7 @@ func (hs *serverHandshakeState) processClientHello() error {
return errors.New("tls: initial handshake had non-empty renegotiation extension")
}
hs.hello.extendedMasterSecret = hs.clientHello.extendedMasterSecret
hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
hs.hello.compressionMethod = compressionNone
if len(hs.clientHello.serverName) > 0 {
@ -471,6 +472,17 @@ func (hs *serverHandshakeState) checkForResumption() error {
return nil
}
// RFC 7627, Section 5.3
if !sessionState.extMasterSecret && hs.clientHello.extendedMasterSecret {
return nil
}
if sessionState.extMasterSecret && !hs.clientHello.extendedMasterSecret {
// Aborting is somewhat harsh, but it's a MUST and it would indicate a
// weird downgrade in client capabilities.
return errors.New("tls: session supported extended_master_secret but client does not")
}
c.extMasterSecret = sessionState.extMasterSecret
hs.sessionState = sessionState
hs.suite = suite
c.didResume = true
@ -647,7 +659,14 @@ func (hs *serverHandshakeState) doFullHandshake() error {
c.sendAlert(alertHandshakeFailure)
return err
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
if hs.hello.extendedMasterSecret {
c.extMasterSecret = true
hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
hs.finishedHash.Sum())
} else {
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
hs.clientHello.random, hs.hello.random)
}
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil {
c.sendAlert(alertInternalError)
return err

9
prf.go
View File

@ -80,6 +80,7 @@ const (
)
var masterSecretLabel = []byte("master secret")
var extendedMasterSecretLabel = []byte("extended master secret")
var keyExpansionLabel = []byte("key expansion")
var clientFinishedLabel = []byte("client finished")
var serverFinishedLabel = []byte("server finished")
@ -115,6 +116,14 @@ func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecr
return masterSecret
}
// extMasterFromPreMasterSecret generates the extended master secret from the
// pre-master secret. See RFC 7627.
func extMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, transcript []byte) []byte {
masterSecret := make([]byte, masterSecretLength)
prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, transcript)
return masterSecret
}
// keysFromMasterSecret generates the connection keys from the master
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
// RFC 2246, Section 6.3.

View File

@ -34,6 +34,7 @@ type SessionState struct {
// uint64 created_at;
// opaque secret<1..2^8-1>;
// opaque extra<0..2^24-1>;
// uint8 ext_master_secret = { 0, 1 };
// uint8 early_data = { 0, 1 };
// CertificateEntry certificate_list<0..2^24-1>;
// select (SessionState.early_data) {
@ -81,6 +82,7 @@ type SessionState struct {
// which the ticket was received on the client.
createdAt uint64 // seconds since UNIX epoch
secret []byte // master secret for TLS 1.2, or the PSK for TLS 1.3
extMasterSecret bool
peerCertificates []*x509.Certificate
activeCertHandles []*activeCert
ocspResponse []byte
@ -117,6 +119,11 @@ func (s *SessionState) Bytes() ([]byte, error) {
b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes(s.Extra)
})
if s.extMasterSecret {
b.AddUint8(1)
} else {
b.AddUint8(0)
}
if s.EarlyData {
b.AddUint8(1)
} else {
@ -173,7 +180,7 @@ func certificatesToBytesSlice(certs []*x509.Certificate) [][]byte {
func ParseSessionState(data []byte) (*SessionState, error) {
ss := &SessionState{}
s := cryptobyte.String(data)
var typ, earlyData uint8
var typ, extMasterSecret, earlyData uint8
var cert Certificate
if !s.ReadUint16(&ss.version) ||
!s.ReadUint8(&typ) ||
@ -182,11 +189,20 @@ func ParseSessionState(data []byte) (*SessionState, error) {
!readUint64(&s, &ss.createdAt) ||
!readUint8LengthPrefixed(&s, &ss.secret) ||
!readUint24LengthPrefixed(&s, &ss.Extra) ||
!s.ReadUint8(&extMasterSecret) ||
!s.ReadUint8(&earlyData) ||
len(ss.secret) == 0 ||
!unmarshalCertificate(&s, &cert) {
return nil, errors.New("tls: invalid session encoding")
}
switch extMasterSecret {
case 0:
ss.extMasterSecret = false
case 1:
ss.extMasterSecret = true
default:
return nil, errors.New("tls: invalid session encoding")
}
switch earlyData {
case 0:
ss.EarlyData = false
@ -279,6 +295,7 @@ func (c *Conn) sessionState() (*SessionState, error) {
ocspResponse: c.ocspResponse,
scts: c.scts,
isClient: c.isClient,
extMasterSecret: c.extMasterSecret,
verifiedChains: verifiedChains,
}, nil
}