Просмотр исходного кода

Integrate EMS support for TLS 1.3

Rod Hynes 7 лет назад
Родитель
Сommit
a6081a379b

+ 4 - 3
psiphon/server/meek.go

@@ -937,9 +937,10 @@ func makeMeekTLSConfig(
 	}
 
 	config := &tris.Config{
-		Certificates: []tris.Certificate{tlsCertificate},
-		NextProtos:   []string{"http/1.1"},
-		MinVersion:   tris.VersionTLS10,
+		Certificates:            []tris.Certificate{tlsCertificate},
+		NextProtos:              []string{"http/1.1"},
+		MinVersion:              tris.VersionTLS10,
+		UseExtendedMasterSecret: true,
 	}
 
 	if isFronted {

+ 5 - 4
psiphon/tlsDialer.go

@@ -386,10 +386,11 @@ func CustomTLSDial(
 		}
 
 		tlsConfig := &tris.Config{
-			RootCAs:            tlsRootCAs,
-			InsecureSkipVerify: tlsConfigInsecureSkipVerify,
-			ServerName:         tlsConfigServerName,
-			ClientSessionCache: clientSessionCache,
+			RootCAs:                 tlsRootCAs,
+			InsecureSkipVerify:      tlsConfigInsecureSkipVerify,
+			ServerName:              tlsConfigServerName,
+			ClientSessionCache:      clientSessionCache,
+			UseExtendedMasterSecret: true,
 		}
 
 		conn = &trisConn{

+ 0 - 6
vendor/github.com/Psiphon-Labs/tls-tris/13.go

@@ -152,12 +152,6 @@ CurvePreferenceLoop:
 		return errors.New("tls: HelloRetryRequest not implemented") // TODO(filippo)
 	}
 
-	if committer, ok := c.conn.(Committer); ok {
-		if err := committer.Commit(); err != nil {
-			return err
-		}
-	}
-
 	privateKey, serverKS, err := config.generateKeyShare(ks.group)
 	if err != nil {
 		c.sendAlert(alertInternalError)

+ 1 - 0
vendor/github.com/Psiphon-Labs/tls-tris/alert.go

@@ -38,6 +38,7 @@ const (
 	alertInappropriateFallback  alert = 86
 	alertUserCanceled           alert = 90
 	alertNoRenegotiation        alert = 100
+	alertUnsupportedExtension   alert = 110
 	alertCertificateRequired    alert = 116
 	alertNoApplicationProtocol  alert = 120
 	alertSuccess                alert = 255 // dummy value returned by unmarshal functions

+ 13 - 17
vendor/github.com/Psiphon-Labs/tls-tris/common.go

@@ -23,12 +23,11 @@ import (
 )
 
 const (
-	VersionSSL30        = 0x0300
-	VersionTLS10        = 0x0301
-	VersionTLS11        = 0x0302
-	VersionTLS12        = 0x0303
-	VersionTLS13        = 0x0304
-	VersionTLS13Draft28 = 0x7f00 | 28
+	VersionSSL30 = 0x0300
+	VersionTLS10 = 0x0301
+	VersionTLS11 = 0x0302
+	VersionTLS12 = 0x0303
+	VersionTLS13 = 0x0304
 )
 
 const (
@@ -39,7 +38,7 @@ const (
 	maxWarnAlertCount = 5            // maximum number of consecutive warning alerts
 
 	minVersion = VersionTLS12
-	maxVersion = VersionTLS13Draft28
+	maxVersion = VersionTLS13
 )
 
 // TLS record types.
@@ -85,6 +84,7 @@ const (
 	extensionSignatureAlgorithms     uint16 = 13
 	extensionALPN                    uint16 = 16
 	extensionSCT                     uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
+	extensionEMS                     uint16 = 23
 	extensionSessionTicket           uint16 = 35
 	extensionPreSharedKey            uint16 = 41
 	extensionEarlyData               uint16 = 42
@@ -260,6 +260,7 @@ type ClientSessionState struct {
 	masterSecret       []byte                // MasterSecret generated by client on a full handshake
 	serverCertificates []*x509.Certificate   // Certificate chain presented by the server
 	verifiedChains     [][]*x509.Certificate // Certificate chains we built for verification
+	useEMS             bool                  // State of extended master secret
 }
 
 // ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -642,6 +643,10 @@ type Config struct {
 	// for new tickets and any subsequent keys can be used to decrypt old
 	// tickets.
 	sessionTicketKeys []ticketKey
+
+	// UseExtendedMasterSecret indicates whether or not the connection
+	// should use the extended master secret computation if available
+	UseExtendedMasterSecret bool
 }
 
 // ticketKeyNameLen is the number of bytes of identifier that is prepended to
@@ -712,6 +717,7 @@ func (c *Config) Clone() *Config {
 		AcceptDelegatedCredential:   c.AcceptDelegatedCredential,
 		GetDelegatedCredential:      c.GetDelegatedCredential,
 		sessionTicketKeys:           sessionTicketKeys,
+		UseExtendedMasterSecret:     c.UseExtendedMasterSecret,
 	}
 }
 
@@ -882,12 +888,6 @@ func (c *Config) pickVersion(peerSupportedVersions []uint16) (uint16, bool) {
 // configSuppVersArray is the backing array of Config.getSupportedVersions
 var configSuppVersArray = [...]uint16{VersionTLS13, VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
 
-// tls13DraftSuppVersArray is the backing array of Config.getSupportedVersions
-// with TLS 1.3 draft versions included.
-//
-// TODO: remove once TLS 1.3 is finalised.
-var tls13DraftSuppVersArray = [...]uint16{VersionTLS13Draft28, VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
-
 // getSupportedVersions returns the protocol versions that are supported by the
 // current configuration.
 func (c *Config) getSupportedVersions() []uint16 {
@@ -903,10 +903,6 @@ func (c *Config) getSupportedVersions() []uint16 {
 	if maxVersion < minVersion {
 		return nil
 	}
-	// TODO: remove once TLS 1.3 is finalised.
-	if maxVersion == VersionTLS13 {
-		return tls13DraftSuppVersArray[:len(tls13DraftSuppVersArray)-int(minVersion-VersionSSL30)]
-	}
 	return configSuppVersArray[VersionTLS13-maxVersion : VersionTLS13-minVersion+1]
 }
 

+ 13 - 7
vendor/github.com/Psiphon-Labs/tls-tris/conn.go

@@ -66,6 +66,8 @@ type Conn struct {
 	// renegotiation extension. (This is meaningless as a server because
 	// renegotiation is not supported in that case.)
 	secureRenegotiation bool
+	// indicates wether extended MasterSecret extension is used (see RFC7627)
+	useEMS bool
 
 	// clientFinishedIsFirst is true if the client sent the first Finished
 	// message during the most recent handshake. This is recorded because
@@ -472,23 +474,30 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
 		case aead:
 			// explicitIVLen is always 0 for TLS1.3
 			payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
+			payloadOffset := recordHeaderLen + explicitIVLen
 			nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
 			if len(nonce) == 0 {
 				nonce = hc.seq[:]
 			}
-			payload = b.data[recordHeaderLen+explicitIVLen:]
-			payload = payload[:payloadLen]
 
 			var additionalData []byte
 			if hc.version < VersionTLS13 {
+				// make room in a buffer for payload + MAC
+				b.resize(len(b.data) + c.Overhead())
+
+				payload = b.data[payloadOffset : payloadOffset+payloadLen]
 				copy(hc.additionalData[:], hc.seq[:])
 				copy(hc.additionalData[8:], b.data[:3])
 				binary.BigEndian.PutUint16(hc.additionalData[11:], uint16(payloadLen))
 				additionalData = hc.additionalData[:]
-				b.resize(len(b.data) + c.Overhead())
 			} else {
+				// make room in a buffer for TLSCiphertext.encrypted_record:
+				// payload + MAC + extra data if needed
+				b.resize(len(b.data) + c.Overhead() + 1)
+
+				payload = b.data[payloadOffset : payloadOffset+payloadLen+1]
 				// 1 byte of content type is appended to payload and encrypted
-				payload = append(payload, b.data[0])
+				payload[len(payload)-1] = b.data[0]
 
 				// opaque_type
 				b.data[0] = byte(recordTypeApplicationData)
@@ -498,9 +507,6 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
 				additionalData[0] = b.data[0]
 				binary.BigEndian.PutUint16(additionalData[1:], VersionTLS12)
 				binary.BigEndian.PutUint16(additionalData[3:], uint16(len(payload)+c.Overhead()))
-
-				// make room for TLSCiphertext.encrypted_record
-				b.resize(len(payload) + recordHeaderLen + c.Overhead())
 			}
 			c.Seal(payload[:0], nonce, payload, additionalData)
 		case cbcMode:

+ 23 - 6
vendor/github.com/Psiphon-Labs/tls-tris/handshake_client.go

@@ -67,6 +67,7 @@ func makeClientHello(config *Config) (*clientHelloMsg, error) {
 		secureRenegotiationSupported: true,
 		delegatedCredential:          config.AcceptDelegatedCredential,
 		alpnProtocols:                config.NextProtos,
+		extendedMSSupported:          config.UseExtendedMasterSecret,
 	}
 	possibleCipherSuites := config.cipherSuites()
 	hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
@@ -589,6 +590,13 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 			return err
 		}
 	}
+	c.useEMS = hs.serverHello.extendedMSSupported
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random, hs.finishedHash, c.useEMS)
+
+	if err := c.config.writeKeyLog("CLIENT_RANDOM", 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{
@@ -631,12 +639,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("CLIENT_RANDOM", 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
@@ -697,6 +699,16 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 		}
 	}
 
+	if hs.serverHello.extendedMSSupported {
+		if hs.hello.extendedMSSupported {
+			c.useEMS = true
+		} else {
+			// server wants to calculate master secret in a different way than client
+			c.sendAlert(alertUnsupportedExtension)
+			return false, errors.New("tls: unexpected extension (EMS) received in SH")
+		}
+	}
+
 	clientDidNPN := hs.hello.nextProtoNeg
 	clientDidALPN := len(hs.hello.alpnProtocols) > 0
 	serverHasNPN := hs.serverHello.nextProtoNeg
@@ -727,6 +739,10 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 		return false, nil
 	}
 
+	if hs.session.useEMS != c.useEMS {
+		return false, errors.New("differing EMS state")
+	}
+
 	if hs.session.vers != c.vers {
 		c.sendAlert(alertHandshakeFailure)
 		return false, errors.New("tls: server resumed a session with a different version")
@@ -797,6 +813,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
 		masterSecret:       hs.masterSecret,
 		serverCertificates: c.peerCertificates,
 		verifiedChains:     c.verifiedChains,
+		useEMS:             c.useEMS,
 	}
 
 	return nil

+ 40 - 3
vendor/github.com/Psiphon-Labs/tls-tris/handshake_messages.go

@@ -60,6 +60,7 @@ type clientHelloMsg struct {
 	pskKeyExchangeModes              []uint8
 	earlyData                        bool
 	delegatedCredential              bool
+	extendedMSSupported              bool // RFC7627
 }
 
 // Function used for signature_algorithms and signature_algorithrms_cert
@@ -139,7 +140,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
 		eqKeyShares(m.keyShares, m1.keyShares) &&
 		eqUint16s(m.supportedVersions, m1.supportedVersions) &&
 		m.earlyData == m1.earlyData &&
-		m.delegatedCredential == m1.delegatedCredential
+		m.delegatedCredential == m1.delegatedCredential &&
+		m.extendedMSSupported == m1.extendedMSSupported
 }
 
 func (m *clientHelloMsg) marshal() []byte {
@@ -158,7 +160,6 @@ func (m *clientHelloMsg) marshal() []byte {
 	numExtensions := 0
 	extensionsLength := 0
 
-	// Indicates wether to send signature_algorithms_cert extension
 	if m.nextProtoNeg {
 		numExtensions++
 	}
@@ -225,6 +226,9 @@ func (m *clientHelloMsg) marshal() []byte {
 	if m.delegatedCredential {
 		numExtensions++
 	}
+	if m.extendedMSSupported {
+		numExtensions++
+	}
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -446,6 +450,10 @@ func (m *clientHelloMsg) marshal() []byte {
 		binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
 		z = z[4:]
 	}
+	if m.extendedMSSupported {
+		binary.BigEndian.PutUint16(z, extensionEMS)
+		z = z[4:]
+	}
 
 	m.raw = x
 
@@ -842,6 +850,14 @@ func (m *clientHelloMsg) randomizedMarshal() []byte {
 				z = z[4:]
 			})
 	}
+	if m.extendedMSSupported && common.FlipCoin() { // May be omitted
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				binary.BigEndian.PutUint16(z, extensionEMS)
+				z = z[4:]
+			})
+	}
 
 	// Optional, additional extensions
 
@@ -1001,6 +1017,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert {
 	m.pskKeyExchangeModes = nil
 	m.earlyData = false
 	m.delegatedCredential = false
+	m.extendedMSSupported = false
 
 	if len(data) == 0 {
 		// ClientHello is optionally followed by extension data
@@ -1268,6 +1285,12 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert {
 		case extensionDelegatedCredential:
 			// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02
 			m.delegatedCredential = true
+		case extensionEMS:
+			// RFC 7627
+			m.extendedMSSupported = true
+			if length != 0 {
+				return alertDecodeError
+			}
 		}
 		data = data[length:]
 		bindersOffset += length
@@ -1300,6 +1323,9 @@ type serverHelloMsg struct {
 	keyShare    keyShare
 	psk         bool
 	pskIdentity uint16
+
+	// RFC7627
+	extendedMSSupported bool
 }
 
 func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -1333,7 +1359,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
 		m.keyShare.group == m1.keyShare.group &&
 		bytes.Equal(m.keyShare.data, m1.keyShare.data) &&
 		m.psk == m1.psk &&
-		m.pskIdentity == m1.pskIdentity
+		m.pskIdentity == m1.pskIdentity &&
+		m.extendedMSSupported == m1.extendedMSSupported
 }
 
 func (m *serverHelloMsg) marshal() []byte {
@@ -1364,6 +1391,9 @@ func (m *serverHelloMsg) marshal() []byte {
 		extensionsLength += 1 + len(m.secureRenegotiation)
 		numExtensions++
 	}
+	if m.extendedMSSupported {
+		numExtensions++
+	}
 	if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
 		if alpnLen >= 256 {
 			panic("invalid ALPN protocol")
@@ -1524,6 +1554,10 @@ func (m *serverHelloMsg) marshal() []byte {
 		z[5] = byte(m.pskIdentity)
 		z = z[6:]
 	}
+	if m.extendedMSSupported {
+		binary.BigEndian.PutUint16(z, extensionEMS)
+		z = z[4:]
+	}
 
 	m.raw = x
 
@@ -1560,6 +1594,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) alert {
 	m.keyShare.data = nil
 	m.psk = false
 	m.pskIdentity = 0
+	m.extendedMSSupported = false
 
 	if len(data) == 0 {
 		// ServerHello is optionally followed by extension data
@@ -1701,6 +1736,8 @@ func (m *serverHelloMsg) unmarshal(data []byte) alert {
 			}
 			m.psk = true
 			m.pskIdentity = uint16(data[0])<<8 | uint16(data[1])
+		case extensionEMS:
+			m.extendedMSSupported = true
 		}
 		data = data[length:]
 	}

+ 14 - 8
vendor/github.com/Psiphon-Labs/tls-tris/handshake_server.go

@@ -16,10 +16,6 @@ import (
 	"sync/atomic"
 )
 
-type Committer interface {
-	Commit() error
-}
-
 // serverHandshakeState contains details of a server handshake in progress.
 // It's discarded once the handshake has completed.
 type serverHandshakeState struct {
@@ -281,10 +277,10 @@ Curves:
 
 	if len(hs.clientHello.alpnProtocols) > 0 {
 		if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
-			if hs.hello != nil {
-				hs.hello.alpnProtocol = selectedProto
-			} else {
+			if hs.hello13Enc != nil {
 				hs.hello13Enc.alpnProtocol = selectedProto
+			} else {
+				hs.hello.alpnProtocol = selectedProto
 			}
 			c.clientProtocol = selectedProto
 		}
@@ -413,6 +409,11 @@ func (hs *serverHandshakeState) checkForResumption() bool {
 		return false
 	}
 
+	// Do not resume connections where client support for EMS has changed
+	if (hs.clientHello.extendedMSSupported && c.config.UseExtendedMasterSecret) != hs.sessionState.usedEMS {
+		return false
+	}
+
 	cipherSuiteOk := false
 	// Check that the client is still offering the ciphersuite in the session.
 	for _, id := range hs.clientHello.cipherSuites {
@@ -450,6 +451,7 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
 	// that we're doing a resumption.
 	hs.hello.sessionId = hs.clientHello.sessionId
 	hs.hello.ticketSupported = hs.sessionState.usedOldKey
+	hs.hello.extendedMSSupported = hs.clientHello.extendedMSSupported && c.config.UseExtendedMasterSecret
 	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
 	hs.finishedHash.discardHandshakeBuffer()
 	hs.finishedHash.Write(hs.clientHello.marshal())
@@ -465,6 +467,7 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
 	}
 
 	hs.masterSecret = hs.sessionState.masterSecret
+	c.useEMS = hs.sessionState.usedEMS
 
 	return nil
 }
@@ -478,6 +481,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 
 	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
 	hs.hello.cipherSuite = hs.suite.id
+	hs.hello.extendedMSSupported = hs.clientHello.extendedMSSupported && c.config.UseExtendedMasterSecret
 
 	hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
 	if c.config.ClientAuth == NoClientCert {
@@ -611,7 +615,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 		}
 		return err
 	}
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+	c.useEMS = hs.hello.extendedMSSupported
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random, hs.finishedHash, c.useEMS)
 	if err := c.config.writeKeyLog("CLIENT_RANDOM", hs.clientHello.random, hs.masterSecret); err != nil {
 		c.sendAlert(alertInternalError)
 		return err
@@ -741,6 +746,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
 		cipherSuite:  hs.suite.id,
 		masterSecret: hs.masterSecret,
 		certificates: hs.certsFromClient,
+		usedEMS:      c.useEMS,
 	}
 	m.ticket, err = c.encryptTicket(state.marshal())
 	if err != nil {

+ 16 - 8
vendor/github.com/Psiphon-Labs/tls-tris/prf.go

@@ -117,6 +117,7 @@ var masterSecretLabel = []byte("master secret")
 var keyExpansionLabel = []byte("key expansion")
 var clientFinishedLabel = []byte("client finished")
 var serverFinishedLabel = []byte("server finished")
+var extendedMasterSecretLabel = []byte("extended master secret")
 
 func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
 	switch version {
@@ -141,14 +142,21 @@ func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, labe
 
 // masterFromPreMasterSecret generates the master secret from the pre-master
 // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
-func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
-	seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
-	seed = append(seed, clientRandom...)
-	seed = append(seed, serverRandom...)
-
-	masterSecret := make([]byte, masterSecretLength)
-	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
-	return masterSecret
+func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte, fin finishedHash, ems bool) []byte {
+	if ems {
+		session_hash := fin.Sum()
+		masterSecret := make([]byte, masterSecretLength)
+		prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, session_hash)
+		return masterSecret
+	} else {
+		seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
+		seed = append(seed, clientRandom...)
+		seed = append(seed, serverRandom...)
+
+		masterSecret := make([]byte, masterSecretLength)
+		prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
+		return masterSecret
+	}
 }
 
 // keysFromMasterSecret generates the connection keys from the master

+ 10 - 2
vendor/github.com/Psiphon-Labs/tls-tris/ticket.go

@@ -45,6 +45,7 @@ type SessionTicketSealer interface {
 type sessionState struct {
 	vers         uint16
 	cipherSuite  uint16
+	usedEMS      bool
 	masterSecret []byte
 	certificates [][]byte
 	// usedOldKey is true if the ticket from which this session came from
@@ -59,6 +60,7 @@ func (s *sessionState) equal(i interface{}) bool {
 	}
 
 	if s.vers != s1.vers ||
+		s.usedEMS != s1.usedEMS ||
 		s.cipherSuite != s1.cipherSuite ||
 		!bytes.Equal(s.masterSecret, s1.masterSecret) {
 		return false
@@ -101,7 +103,12 @@ func (s *sessionState) marshal() []byte {
 
 	ret := make([]byte, length)
 	x := ret
-	x[0] = byte(s.vers >> 8)
+	was_used := byte(0)
+	if s.usedEMS {
+		was_used = byte(0x80)
+	}
+
+	x[0] = byte(s.vers>>8) | byte(was_used)
 	x[1] = byte(s.vers)
 	x[2] = byte(s.cipherSuite >> 8)
 	x[3] = byte(s.cipherSuite)
@@ -132,8 +139,9 @@ func (s *sessionState) unmarshal(data []byte) alert {
 		return alertDecodeError
 	}
 
-	s.vers = uint16(data[0])<<8 | uint16(data[1])
+	s.vers = (uint16(data[0])<<8 | uint16(data[1])) & 0x7fff
 	s.cipherSuite = uint16(data[2])<<8 | uint16(data[3])
+	s.usedEMS = (data[0] & 0x80) == 0x80
 	masterSecretLen := int(data[4])<<8 | int(data[5])
 	data = data[6:]
 	if len(data) < masterSecretLen {

+ 3 - 3
vendor/vendor.json

@@ -63,10 +63,10 @@
 			"revisionTime": "2018-09-12T16:47:43Z"
 		},
 		{
-			"checksumSHA1": "yibR+itWrPd8QJO4soBScqrbxzg=",
+			"checksumSHA1": "tPhzygqO+Lk+oY/Gp4jMq7YGbhU=",
 			"path": "github.com/Psiphon-Labs/tls-tris",
-			"revision": "5165552b556552cfd96b918a8121934a7d8d0a66",
-			"revisionTime": "2018-09-15T13:40:56Z"
+			"revision": "a7c2751b906303d32dff10bb728a1d0f124e56f4",
+			"revisionTime": "2018-09-29T21:11:36Z"
 		},
 		{
 			"checksumSHA1": "OBN3dfn0yx9L3I2RPo58o27my2k=",