Browse Source

Vendor github.com/Psiphon-Labs/tls-tris

Rod Hynes 7 years ago
parent
commit
ec8adb21e9
32 changed files with 12291 additions and 0 deletions
  1. 1163 0
      vendor/github.com/Psiphon-Labs/tls-tris/13.go
  2. 107 0
      vendor/github.com/Psiphon-Labs/tls-tris/README.md
  3. 83 0
      vendor/github.com/Psiphon-Labs/tls-tris/alert.go
  4. 107 0
      vendor/github.com/Psiphon-Labs/tls-tris/auth.go
  5. 428 0
      vendor/github.com/Psiphon-Labs/tls-tris/cipher_suites.go
  6. 1229 0
      vendor/github.com/Psiphon-Labs/tls-tris/common.go
  7. 1725 0
      vendor/github.com/Psiphon-Labs/tls-tris/conn.go
  8. 1002 0
      vendor/github.com/Psiphon-Labs/tls-tris/handshake_client.go
  9. 3210 0
      vendor/github.com/Psiphon-Labs/tls-tris/handshake_messages.go
  10. 927 0
      vendor/github.com/Psiphon-Labs/tls-tris/handshake_server.go
  11. 58 0
      vendor/github.com/Psiphon-Labs/tls-tris/hkdf.go
  12. 402 0
      vendor/github.com/Psiphon-Labs/tls-tris/key_agreement.go
  13. 132 0
      vendor/github.com/Psiphon-Labs/tls-tris/obfuscated.go
  14. 347 0
      vendor/github.com/Psiphon-Labs/tls-tris/prf.go
  15. 392 0
      vendor/github.com/Psiphon-Labs/tls-tris/subcerts.go
  16. 344 0
      vendor/github.com/Psiphon-Labs/tls-tris/ticket.go
  17. 297 0
      vendor/github.com/Psiphon-Labs/tls-tris/tls.go
  18. 32 0
      vendor/golang.org/x/crypto/internal/subtle/aliasing.go
  19. 35 0
      vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go
  20. 38 0
      vendor/golang.org/x/sys/cpu/cpu.go
  21. 7 0
      vendor/golang.org/x/sys/cpu/cpu_arm.go
  22. 7 0
      vendor/golang.org/x/sys/cpu/cpu_arm64.go
  23. 16 0
      vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
  24. 43 0
      vendor/golang.org/x/sys/cpu/cpu_gccgo.c
  25. 26 0
      vendor/golang.org/x/sys/cpu/cpu_gccgo.go
  26. 9 0
      vendor/golang.org/x/sys/cpu/cpu_mips64x.go
  27. 9 0
      vendor/golang.org/x/sys/cpu/cpu_mipsx.go
  28. 9 0
      vendor/golang.org/x/sys/cpu/cpu_ppc64x.go
  29. 7 0
      vendor/golang.org/x/sys/cpu/cpu_s390x.go
  30. 55 0
      vendor/golang.org/x/sys/cpu/cpu_x86.go
  31. 27 0
      vendor/golang.org/x/sys/cpu/cpu_x86.s
  32. 18 0
      vendor/vendor.json

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

@@ -0,0 +1,1163 @@
+package tls
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/hmac"
+	"crypto/rsa"
+	"crypto/subtle"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"hash"
+	"io"
+	"log"
+	"os"
+	"runtime"
+	"runtime/debug"
+	"strings"
+	"sync/atomic"
+	"time"
+
+	"golang.org/x/crypto/curve25519"
+)
+
+// numSessionTickets is the number of different session tickets the
+// server sends to a TLS 1.3 client, who will use each only once.
+const numSessionTickets = 2
+
+type secretLabel int
+
+const (
+	secretResumptionPskBinder secretLabel = iota
+	secretEarlyClient
+	secretHandshakeClient
+	secretHandshakeServer
+	secretApplicationClient
+	secretApplicationServer
+	secretResumption
+)
+
+type keySchedule13 struct {
+	suite          *cipherSuite
+	transcriptHash hash.Hash // uses the cipher suite hash algo
+	secret         []byte    // Current secret as used for Derive-Secret
+	handshakeCtx   []byte    // cached handshake context, invalidated on updates.
+	clientRandom   []byte    // Used for keylogging, nil if keylogging is disabled.
+	config         *Config   // Used for KeyLogWriter callback, nil if keylogging is disabled.
+}
+
+func newKeySchedule13(suite *cipherSuite, config *Config, clientRandom []byte) *keySchedule13 {
+	if config.KeyLogWriter == nil {
+		clientRandom = nil
+		config = nil
+	}
+	return &keySchedule13{
+		suite:          suite,
+		transcriptHash: hashForSuite(suite).New(),
+		clientRandom:   clientRandom,
+		config:         config,
+	}
+}
+
+// setSecret sets the early/handshake/master secret based on the given secret
+// (IKM). The salt is based on previous secrets (nil for the early secret).
+func (ks *keySchedule13) setSecret(secret []byte) {
+	hash := hashForSuite(ks.suite)
+	salt := ks.secret
+	if salt != nil {
+		h0 := hash.New().Sum(nil)
+		salt = hkdfExpandLabel(hash, salt, h0, "derived", hash.Size())
+	}
+	ks.secret = hkdfExtract(hash, secret, salt)
+}
+
+// write appends the data to the transcript hash context.
+func (ks *keySchedule13) write(data []byte) {
+	ks.handshakeCtx = nil
+	ks.transcriptHash.Write(data)
+}
+
+func (ks *keySchedule13) getLabel(secretLabel secretLabel) (label, keylogType string) {
+	switch secretLabel {
+	case secretResumptionPskBinder:
+		label = "res binder"
+	case secretEarlyClient:
+		label = "c e traffic"
+		keylogType = "CLIENT_EARLY_TRAFFIC_SECRET"
+	case secretHandshakeClient:
+		label = "c hs traffic"
+		keylogType = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
+	case secretHandshakeServer:
+		label = "s hs traffic"
+		keylogType = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
+	case secretApplicationClient:
+		label = "c ap traffic"
+		keylogType = "CLIENT_TRAFFIC_SECRET_0"
+	case secretApplicationServer:
+		label = "s ap traffic"
+		keylogType = "SERVER_TRAFFIC_SECRET_0"
+	case secretResumption:
+		label = "res master"
+	}
+	return
+}
+
+// deriveSecret returns the secret derived from the handshake context and label.
+func (ks *keySchedule13) deriveSecret(secretLabel secretLabel) []byte {
+	label, keylogType := ks.getLabel(secretLabel)
+	if ks.handshakeCtx == nil {
+		ks.handshakeCtx = ks.transcriptHash.Sum(nil)
+	}
+	hash := hashForSuite(ks.suite)
+	secret := hkdfExpandLabel(hash, ks.secret, ks.handshakeCtx, label, hash.Size())
+	if keylogType != "" && ks.config != nil {
+		ks.config.writeKeyLog(keylogType, ks.clientRandom, secret)
+	}
+	return secret
+}
+
+func (ks *keySchedule13) prepareCipher(secretLabel secretLabel) (interface{}, []byte) {
+	trafficSecret := ks.deriveSecret(secretLabel)
+	hash := hashForSuite(ks.suite)
+	key := hkdfExpandLabel(hash, trafficSecret, nil, "key", ks.suite.keyLen)
+	iv := hkdfExpandLabel(hash, trafficSecret, nil, "iv", ks.suite.ivLen)
+	return ks.suite.aead(key, iv), trafficSecret
+}
+
+func (hs *serverHandshakeState) doTLS13Handshake() error {
+	config := hs.c.config
+	c := hs.c
+
+	hs.c.cipherSuite, hs.hello.cipherSuite = hs.suite.id, hs.suite.id
+	hs.c.clientHello = hs.clientHello.marshal()
+
+	// When picking the group for the handshake, priority is given to groups
+	// that the client provided a keyShare for, so to avoid a round-trip.
+	// After that the order of CurvePreferences is respected.
+	var ks keyShare
+CurvePreferenceLoop:
+	for _, curveID := range config.curvePreferences() {
+		for _, keyShare := range hs.clientHello.keyShares {
+			if curveID == keyShare.group {
+				ks = keyShare
+				break CurvePreferenceLoop
+			}
+		}
+	}
+	if ks.group == 0 {
+		c.sendAlert(alertInternalError)
+		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)
+		return err
+	}
+	hs.hello.keyShare = serverKS
+
+	hash := hashForSuite(hs.suite)
+	hashSize := hash.Size()
+	hs.keySchedule = newKeySchedule13(hs.suite, config, hs.clientHello.random)
+
+	// Check for PSK and update key schedule with new early secret key
+	isResumed, pskAlert := hs.checkPSK()
+	switch {
+	case pskAlert != alertSuccess:
+		c.sendAlert(pskAlert)
+		return errors.New("tls: invalid client PSK")
+	case !isResumed:
+		// apply an empty PSK if not resumed.
+		hs.keySchedule.setSecret(nil)
+	case isResumed:
+		c.didResume = true
+	}
+
+	hs.keySchedule.write(hs.clientHello.marshal())
+
+	earlyClientCipher, _ := hs.keySchedule.prepareCipher(secretEarlyClient)
+
+	ecdheSecret := deriveECDHESecret(ks, privateKey)
+	if ecdheSecret == nil {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: bad ECDHE client share")
+	}
+
+	hs.keySchedule.write(hs.hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
+
+	// middlebox compatibility mode: send CCS after first handshake message
+	if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+		return err
+	}
+
+	hs.keySchedule.setSecret(ecdheSecret)
+	clientCipher, cTrafficSecret := hs.keySchedule.prepareCipher(secretHandshakeClient)
+	hs.hsClientCipher = clientCipher
+	serverCipher, sTrafficSecret := hs.keySchedule.prepareCipher(secretHandshakeServer)
+	c.out.setCipher(c.vers, serverCipher)
+
+	serverFinishedKey := hkdfExpandLabel(hash, sTrafficSecret, nil, "finished", hashSize)
+	hs.clientFinishedKey = hkdfExpandLabel(hash, cTrafficSecret, nil, "finished", hashSize)
+
+	// EncryptedExtensions
+	hs.keySchedule.write(hs.hello13Enc.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello13Enc.marshal()); err != nil {
+		return err
+	}
+
+	// TODO: we should have 2 separated methods - one for full-handshake and the other for PSK-handshake
+	if !c.didResume {
+		// Server MUST NOT send CertificateRequest if authenticating with PSK
+		if c.config.ClientAuth >= RequestClientCert {
+
+			certReq := new(certificateRequestMsg13)
+			// extension 'signature_algorithms' MUST be specified
+			certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
+			certReq.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
+			hs.keySchedule.write(certReq.marshal())
+			if _, err := hs.c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
+				return err
+			}
+		}
+
+		if err := hs.sendCertificate13(); err != nil {
+			return err
+		}
+	}
+
+	verifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, serverFinishedKey)
+	serverFinished := &finishedMsg{
+		verifyData: verifyData,
+	}
+	hs.keySchedule.write(serverFinished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, serverFinished.marshal()); err != nil {
+		return err
+	}
+
+	hs.keySchedule.setSecret(nil) // derive master secret
+	hs.appClientCipher, _ = hs.keySchedule.prepareCipher(secretApplicationClient)
+	serverCipher, _ = hs.keySchedule.prepareCipher(secretApplicationServer)
+	c.out.setCipher(c.vers, serverCipher)
+
+	if c.hand.Len() > 0 {
+		return c.sendAlert(alertUnexpectedMessage)
+	}
+	if hs.hello13Enc.earlyData {
+		c.in.setCipher(c.vers, earlyClientCipher)
+		c.phase = readingEarlyData
+	} else if hs.clientHello.earlyData {
+		c.in.setCipher(c.vers, hs.hsClientCipher)
+		c.phase = discardingEarlyData
+	} else {
+		c.in.setCipher(c.vers, hs.hsClientCipher)
+		c.phase = waitingClientFinished
+	}
+
+	return nil
+}
+
+// readClientFinished13 is called during the server handshake (when no early
+// data it available) or after reading all early data. It discards early data if
+// the server did not accept it and then verifies the Finished message. Once
+// done it sends the session tickets. Under c.in lock.
+func (hs *serverHandshakeState) readClientFinished13(hasConfirmLock bool) error {
+	c := hs.c
+
+	// If the client advertised and sends early data while the server does
+	// not accept it, it must be fully skipped until the Finished message.
+	for c.phase == discardingEarlyData {
+		if err := c.readRecord(recordTypeApplicationData); err != nil {
+			return err
+		}
+		// Assume receipt of Finished message (will be checked below).
+		if c.hand.Len() > 0 {
+			c.phase = waitingClientFinished
+			break
+		}
+	}
+
+	// If the client sends early data followed by a Finished message (but
+	// no end_of_early_data), the server MUST terminate the connection.
+	if c.phase != waitingClientFinished {
+		c.sendAlert(alertUnexpectedMessage)
+		return errors.New("tls: did not expect Client Finished yet")
+	}
+
+	c.phase = readingClientFinished
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	// client authentication
+	if certMsg, ok := msg.(*certificateMsg13); ok {
+
+		// (4.4.2) Client MUST send certificate msg if requested by server
+		if c.config.ClientAuth < RequestClientCert {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certMsg, msg)
+		}
+
+		hs.keySchedule.write(certMsg.marshal())
+		certs := getCertsFromEntries(certMsg.certificates)
+		pubKey, err := hs.processCertsFromClient(certs)
+		if err != nil {
+			return err
+		}
+
+		// 4.4.3: CertificateVerify MUST appear immediately after Certificate msg
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+
+		certVerify, ok := msg.(*certificateVerifyMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certVerify, msg)
+		}
+
+		err, alertCode := verifyPeerHandshakeSignature(
+			certVerify,
+			pubKey,
+			supportedSignatureAlgorithms13,
+			hs.keySchedule.transcriptHash.Sum(nil),
+			"TLS 1.3, client CertificateVerify")
+		if err != nil {
+			c.sendAlert(alertCode)
+			return err
+		}
+		hs.keySchedule.write(certVerify.marshal())
+
+		// Read next chunk
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+
+	} else if (c.config.ClientAuth >= RequestClientCert) && !c.didResume {
+		c.sendAlert(alertCertificateRequired)
+		return unexpectedMessageError(certMsg, msg)
+	}
+
+	clientFinished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(clientFinished, msg)
+	}
+
+	hash := hashForSuite(hs.suite)
+	expectedVerifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, hs.clientFinishedKey)
+	if len(expectedVerifyData) != len(clientFinished.verifyData) ||
+		subtle.ConstantTimeCompare(expectedVerifyData, clientFinished.verifyData) != 1 {
+		c.sendAlert(alertDecryptError)
+		return errors.New("tls: client's Finished message is incorrect")
+	}
+	hs.keySchedule.write(clientFinished.marshal())
+
+	c.hs = nil // Discard the server handshake state
+	if c.hand.Len() > 0 {
+		return c.sendAlert(alertUnexpectedMessage)
+	}
+	c.in.setCipher(c.vers, hs.appClientCipher)
+	c.in.traceErr, c.out.traceErr = nil, nil
+	c.phase = handshakeConfirmed
+	atomic.StoreInt32(&c.handshakeConfirmed, 1)
+
+	// Any read operation after handshakeRunning and before handshakeConfirmed
+	// will be holding this lock, which we release as soon as the confirmation
+	// happens, even if the Read call might do more work.
+	// If a Handshake is pending, c.confirmMutex will never be locked as
+	// ConfirmHandshake will wait for the handshake to complete. If a
+	// handshake was complete, and this was a confirmation, unlock
+	// c.confirmMutex now to allow readers to proceed.
+	if hasConfirmLock {
+		c.confirmMutex.Unlock()
+	}
+
+	return hs.sendSessionTicket13() // TODO: do in a goroutine
+}
+
+func (hs *serverHandshakeState) sendCertificate13() error {
+	c := hs.c
+
+	certEntries := []certificateEntry{}
+	for _, cert := range hs.cert.Certificate {
+		certEntries = append(certEntries, certificateEntry{data: cert})
+	}
+	if len(certEntries) > 0 && hs.clientHello.ocspStapling {
+		certEntries[0].ocspStaple = hs.cert.OCSPStaple
+	}
+	if len(certEntries) > 0 && hs.clientHello.scts {
+		certEntries[0].sctList = hs.cert.SignedCertificateTimestamps
+	}
+
+	// If hs.delegatedCredential is set (see hs.readClientHello()) then the
+	// server is using the delegated credential extension. The DC is added as an
+	// extension to the end-entity certificate, i.e., the last CertificateEntry
+	// of Certificate.certficate_list. (For details, see
+	// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.)
+	if len(certEntries) > 0 && hs.clientHello.delegatedCredential && hs.delegatedCredential != nil {
+		certEntries[0].delegatedCredential = hs.delegatedCredential
+	}
+
+	certMsg := &certificateMsg13{certificates: certEntries}
+
+	hs.keySchedule.write(certMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+		return err
+	}
+
+	sigScheme, err := hs.selectTLS13SignatureScheme()
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+
+	sigHash := hashForSignatureScheme(sigScheme)
+	opts := crypto.SignerOpts(sigHash)
+	if signatureSchemeIsPSS(sigScheme) {
+		opts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+	}
+
+	toSign := prepareDigitallySigned(sigHash, "TLS 1.3, server CertificateVerify", hs.keySchedule.transcriptHash.Sum(nil))
+	signature, err := hs.privateKey.(crypto.Signer).Sign(c.config.rand(), toSign[:], opts)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+
+	verifyMsg := &certificateVerifyMsg{
+		hasSignatureAndHash: true,
+		signatureAlgorithm:  sigScheme,
+		signature:           signature,
+	}
+	hs.keySchedule.write(verifyMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, verifyMsg.marshal()); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *Conn) handleEndOfEarlyData() error {
+	if c.phase != readingEarlyData || c.vers < VersionTLS13 {
+		return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	endOfEarlyData, ok := msg.(*endOfEarlyDataMsg)
+	// No handshake messages are allowed after EOD.
+	if !ok || c.hand.Len() > 0 {
+		return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+	c.hs.keySchedule.write(endOfEarlyData.marshal())
+	c.phase = waitingClientFinished
+	c.in.setCipher(c.vers, c.hs.hsClientCipher)
+	return nil
+}
+
+// selectTLS13SignatureScheme chooses the SignatureScheme for the CertificateVerify
+// based on the certificate type and client supported schemes. If no overlap is found,
+// a fallback is selected.
+//
+// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.4.1.2
+func (hs *serverHandshakeState) selectTLS13SignatureScheme() (sigScheme SignatureScheme, err error) {
+	var supportedSchemes []SignatureScheme
+	signer, ok := hs.privateKey.(crypto.Signer)
+	if !ok {
+		return 0, errors.New("tls: private key does not implement crypto.Signer")
+	}
+	pk := signer.Public()
+	if _, ok := pk.(*rsa.PublicKey); ok {
+		sigScheme = PSSWithSHA256
+		supportedSchemes = []SignatureScheme{PSSWithSHA256, PSSWithSHA384, PSSWithSHA512}
+	} else if pk, ok := pk.(*ecdsa.PublicKey); ok {
+		switch pk.Curve {
+		case elliptic.P256():
+			sigScheme = ECDSAWithP256AndSHA256
+			supportedSchemes = []SignatureScheme{ECDSAWithP256AndSHA256}
+		case elliptic.P384():
+			sigScheme = ECDSAWithP384AndSHA384
+			supportedSchemes = []SignatureScheme{ECDSAWithP384AndSHA384}
+		case elliptic.P521():
+			sigScheme = ECDSAWithP521AndSHA512
+			supportedSchemes = []SignatureScheme{ECDSAWithP521AndSHA512}
+		default:
+			return 0, errors.New("tls: unknown ECDSA certificate curve")
+		}
+	} else {
+		return 0, errors.New("tls: unknown certificate key type")
+	}
+
+	for _, ss := range supportedSchemes {
+		for _, cs := range hs.clientHello.supportedSignatureAlgorithms {
+			if ss == cs {
+				return ss, nil
+			}
+		}
+	}
+
+	return sigScheme, nil
+}
+
+func signatureSchemeIsPSS(s SignatureScheme) bool {
+	return s == PSSWithSHA256 || s == PSSWithSHA384 || s == PSSWithSHA512
+}
+
+// hashForSignatureScheme returns the Hash used by a SignatureScheme which is
+// supported by selectTLS13SignatureScheme.
+func hashForSignatureScheme(ss SignatureScheme) crypto.Hash {
+	switch ss {
+	case PSSWithSHA256, ECDSAWithP256AndSHA256:
+		return crypto.SHA256
+	case PSSWithSHA384, ECDSAWithP384AndSHA384:
+		return crypto.SHA384
+	case PSSWithSHA512, ECDSAWithP521AndSHA512:
+		return crypto.SHA512
+	default:
+		panic("unsupported SignatureScheme passed to hashForSignatureScheme")
+	}
+}
+
+func hashForSuite(suite *cipherSuite) crypto.Hash {
+	if suite.flags&suiteSHA384 != 0 {
+		return crypto.SHA384
+	}
+	return crypto.SHA256
+}
+
+func prepareDigitallySigned(hash crypto.Hash, context string, data []byte) []byte {
+	message := bytes.Repeat([]byte{32}, 64)
+	message = append(message, context...)
+	message = append(message, 0)
+	message = append(message, data...)
+	h := hash.New()
+	h.Write(message)
+	return h.Sum(nil)
+}
+
+func (c *Config) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) {
+	if curveID == X25519 {
+		var scalar, public [32]byte
+		if _, err := io.ReadFull(c.rand(), scalar[:]); err != nil {
+			return nil, keyShare{}, err
+		}
+
+		curve25519.ScalarBaseMult(&public, &scalar)
+		return scalar[:], keyShare{group: curveID, data: public[:]}, nil
+	}
+
+	curve, ok := curveForCurveID(curveID)
+	if !ok {
+		return nil, keyShare{}, errors.New("tls: preferredCurves includes unsupported curve")
+	}
+
+	privateKey, x, y, err := elliptic.GenerateKey(curve, c.rand())
+	if err != nil {
+		return nil, keyShare{}, err
+	}
+	ecdhePublic := elliptic.Marshal(curve, x, y)
+
+	return privateKey, keyShare{group: curveID, data: ecdhePublic}, nil
+}
+
+func deriveECDHESecret(ks keyShare, secretKey []byte) []byte {
+	if ks.group == X25519 {
+		if len(ks.data) != 32 {
+			return nil
+		}
+
+		var theirPublic, sharedKey, scalar [32]byte
+		copy(theirPublic[:], ks.data)
+		copy(scalar[:], secretKey)
+		curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
+		return sharedKey[:]
+	}
+
+	curve, ok := curveForCurveID(ks.group)
+	if !ok {
+		return nil
+	}
+	x, y := elliptic.Unmarshal(curve, ks.data)
+	if x == nil {
+		return nil
+	}
+	x, _ = curve.ScalarMult(x, y, secretKey)
+	xBytes := x.Bytes()
+	curveSize := (curve.Params().BitSize + 8 - 1) >> 3
+	if len(xBytes) == curveSize {
+		return xBytes
+	}
+	buf := make([]byte, curveSize)
+	copy(buf[len(buf)-len(xBytes):], xBytes)
+	return buf
+}
+
+func hkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
+	prefix := "tls13 "
+	hkdfLabel := make([]byte, 4+len(prefix)+len(label)+len(hashValue))
+	hkdfLabel[0] = byte(L >> 8)
+	hkdfLabel[1] = byte(L)
+	hkdfLabel[2] = byte(len(prefix) + len(label))
+	copy(hkdfLabel[3:], prefix)
+	z := hkdfLabel[3+len(prefix):]
+	copy(z, label)
+	z = z[len(label):]
+	z[0] = byte(len(hashValue))
+	copy(z[1:], hashValue)
+
+	return hkdfExpand(hash, secret, hkdfLabel, L)
+}
+
+func hmacOfSum(f crypto.Hash, hash hash.Hash, key []byte) []byte {
+	h := hmac.New(f.New, key)
+	h.Write(hash.Sum(nil))
+	return h.Sum(nil)
+}
+
+// Maximum allowed mismatch between the stated age of a ticket
+// and the server-observed one. See
+// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8.2.
+const ticketAgeSkewAllowance = 10 * time.Second
+
+// checkPSK tries to resume using a PSK, returning true (and updating the
+// early secret in the key schedule) if the PSK was used and false otherwise.
+func (hs *serverHandshakeState) checkPSK() (isResumed bool, alert alert) {
+	if hs.c.config.SessionTicketsDisabled {
+		return false, alertSuccess
+	}
+
+	foundDHE := false
+	for _, mode := range hs.clientHello.pskKeyExchangeModes {
+		if mode == pskDHEKeyExchange {
+			foundDHE = true
+			break
+		}
+	}
+	if !foundDHE {
+		return false, alertSuccess
+	}
+
+	hash := hashForSuite(hs.suite)
+	hashSize := hash.Size()
+	for i := range hs.clientHello.psks {
+		sessionTicket := append([]uint8{}, hs.clientHello.psks[i].identity...)
+		if hs.c.config.SessionTicketSealer != nil {
+			var ok bool
+			sessionTicket, ok = hs.c.config.SessionTicketSealer.Unseal(hs.clientHelloInfo(), sessionTicket)
+			if !ok {
+				continue
+			}
+		} else {
+			sessionTicket, _ = hs.c.decryptTicket(sessionTicket)
+			if sessionTicket == nil {
+				continue
+			}
+		}
+		s := &sessionState13{}
+		if s.unmarshal(sessionTicket) != alertSuccess {
+			continue
+		}
+		if s.vers != hs.c.vers {
+			continue
+		}
+		clientAge := time.Duration(hs.clientHello.psks[i].obfTicketAge-s.ageAdd) * time.Millisecond
+		serverAge := time.Since(time.Unix(int64(s.createdAt), 0))
+		if clientAge-serverAge > ticketAgeSkewAllowance || clientAge-serverAge < -ticketAgeSkewAllowance {
+			// XXX: NSS is off spec and sends obfuscated_ticket_age as seconds
+			clientAge = time.Duration(hs.clientHello.psks[i].obfTicketAge-s.ageAdd) * time.Second
+			if clientAge-serverAge > ticketAgeSkewAllowance || clientAge-serverAge < -ticketAgeSkewAllowance {
+				continue
+			}
+		}
+
+		// This enforces the stricter 0-RTT requirements on all ticket uses.
+		// The benefit of using PSK+ECDHE without 0-RTT are small enough that
+		// we can give them up in the edge case of changed suite or ALPN or SNI.
+		if s.suite != hs.suite.id {
+			continue
+		}
+		if s.alpnProtocol != hs.c.clientProtocol {
+			continue
+		}
+		if s.SNI != hs.c.serverName {
+			continue
+		}
+
+		hs.keySchedule.setSecret(s.pskSecret)
+		binderKey := hs.keySchedule.deriveSecret(secretResumptionPskBinder)
+		binderFinishedKey := hkdfExpandLabel(hash, binderKey, nil, "finished", hashSize)
+		chHash := hash.New()
+		chHash.Write(hs.clientHello.rawTruncated)
+		expectedBinder := hmacOfSum(hash, chHash, binderFinishedKey)
+
+		if subtle.ConstantTimeCompare(expectedBinder, hs.clientHello.psks[i].binder) != 1 {
+			return false, alertDecryptError
+		}
+
+		if i == 0 && hs.clientHello.earlyData {
+			// This is a ticket intended to be used for 0-RTT
+			if s.maxEarlyDataLen == 0 {
+				// But we had not tagged it as such.
+				return false, alertIllegalParameter
+			}
+			if hs.c.config.Accept0RTTData {
+				hs.c.binder = expectedBinder
+				hs.c.ticketMaxEarlyData = int64(s.maxEarlyDataLen)
+				hs.hello13Enc.earlyData = true
+			}
+		}
+		hs.hello.psk = true
+		hs.hello.pskIdentity = uint16(i)
+		return true, alertSuccess
+	}
+
+	return false, alertSuccess
+}
+
+func (hs *serverHandshakeState) sendSessionTicket13() error {
+	c := hs.c
+	if c.config.SessionTicketsDisabled {
+		return nil
+	}
+
+	foundDHE := false
+	for _, mode := range hs.clientHello.pskKeyExchangeModes {
+		if mode == pskDHEKeyExchange {
+			foundDHE = true
+			break
+		}
+	}
+	if !foundDHE {
+		return nil
+	}
+
+	resumptionMasterSecret := hs.keySchedule.deriveSecret(secretResumption)
+
+	ageAddBuf := make([]byte, 4)
+	sessionState := &sessionState13{
+		vers:            c.vers,
+		suite:           hs.suite.id,
+		createdAt:       uint64(time.Now().Unix()),
+		alpnProtocol:    c.clientProtocol,
+		SNI:             c.serverName,
+		maxEarlyDataLen: c.config.Max0RTTDataSize,
+	}
+	hash := hashForSuite(hs.suite)
+
+	for i := 0; i < numSessionTickets; i++ {
+		if _, err := io.ReadFull(c.config.rand(), ageAddBuf); err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		sessionState.ageAdd = uint32(ageAddBuf[0])<<24 | uint32(ageAddBuf[1])<<16 |
+			uint32(ageAddBuf[2])<<8 | uint32(ageAddBuf[3])
+		// ticketNonce must be a unique value for this connection.
+		// Assume there are no more than 255 tickets, otherwise two
+		// tickets might have the same PSK which could be a problem if
+		// one of them is compromised.
+		ticketNonce := []byte{byte(i)}
+		sessionState.pskSecret = hkdfExpandLabel(hash, resumptionMasterSecret, ticketNonce, "resumption", hash.Size())
+		ticket := sessionState.marshal()
+		var err error
+		if c.config.SessionTicketSealer != nil {
+			cs := c.ConnectionState()
+			ticket, err = c.config.SessionTicketSealer.Seal(&cs, ticket)
+		} else {
+			ticket, err = c.encryptTicket(ticket)
+		}
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		if ticket == nil {
+			continue
+		}
+		ticketMsg := &newSessionTicketMsg13{
+			lifetime:           24 * 3600, // TODO(filippo)
+			maxEarlyDataLength: c.config.Max0RTTDataSize,
+			withEarlyDataInfo:  c.config.Max0RTTDataSize > 0,
+			ageAdd:             sessionState.ageAdd,
+			nonce:              ticketNonce,
+			ticket:             ticket,
+		}
+		if _, err := c.writeRecord(recordTypeHandshake, ticketMsg.marshal()); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeState) traceErr(err error) {
+	if err == nil {
+		return
+	}
+	if os.Getenv("TLSDEBUG") == "error" {
+		if hs != nil && hs.clientHello != nil {
+			os.Stderr.WriteString(hex.Dump(hs.clientHello.marshal()))
+		} else if err == io.EOF {
+			return // don't stack trace on EOF before CH
+		}
+		fmt.Fprintf(os.Stderr, "\n%s\n", debug.Stack())
+	}
+	if os.Getenv("TLSDEBUG") == "short" {
+		var pcs [4]uintptr
+		frames := runtime.CallersFrames(pcs[0:runtime.Callers(3, pcs[:])])
+		for {
+			frame, more := frames.Next()
+			if frame.Function != "crypto/tls.(*halfConn).setErrorLocked" &&
+				frame.Function != "crypto/tls.(*Conn).sendAlertLocked" &&
+				frame.Function != "crypto/tls.(*Conn).sendAlert" {
+				file := frame.File[strings.LastIndex(frame.File, "/")+1:]
+				log.Printf("%s:%d (%s): %v", file, frame.Line, frame.Function, err)
+				return
+			}
+			if !more {
+				break
+			}
+		}
+	}
+}
+
+func getCertsFromEntries(certEntries []certificateEntry) [][]byte {
+	certs := make([][]byte, len(certEntries))
+	for i, cert := range certEntries {
+		certs[i] = cert.data
+	}
+	return certs
+}
+
+func (hs *clientHandshakeState) processEncryptedExtensions(ee *encryptedExtensionsMsg) error {
+	c := hs.c
+	if ee.alpnProtocol != "" {
+		c.clientProtocol = ee.alpnProtocol
+		c.clientProtocolFallback = false
+	}
+	return nil
+}
+
+func verifyPeerHandshakeSignature(
+	certVerify *certificateVerifyMsg,
+	pubKey crypto.PublicKey,
+	signAlgosKnown []SignatureScheme,
+	transHash []byte,
+	contextString string) (error, alert) {
+
+	_, sigType, hashFunc, err := pickSignatureAlgorithm(
+		pubKey,
+		[]SignatureScheme{certVerify.signatureAlgorithm},
+		signAlgosKnown,
+		VersionTLS13)
+	if err != nil {
+		return err, alertHandshakeFailure
+	}
+
+	digest := prepareDigitallySigned(hashFunc, contextString, transHash)
+	err = verifyHandshakeSignature(sigType, pubKey, hashFunc, digest, certVerify.signature)
+
+	if err != nil {
+		return err, alertDecryptError
+	}
+
+	return nil, alertSuccess
+}
+
+func (hs *clientHandshakeState) getCertificate13(certReq *certificateRequestMsg13) (*Certificate, error) {
+	certReq12 := &certificateRequestMsg{
+		hasSignatureAndHash:          true,
+		supportedSignatureAlgorithms: certReq.supportedSignatureAlgorithms,
+		certificateAuthorities:       certReq.certificateAuthorities,
+	}
+
+	var rsaAvail, ecdsaAvail bool
+	for _, sigAlg := range certReq.supportedSignatureAlgorithms {
+		switch signatureFromSignatureScheme(sigAlg) {
+		case signaturePKCS1v15, signatureRSAPSS:
+			rsaAvail = true
+		case signatureECDSA:
+			ecdsaAvail = true
+		}
+	}
+	if rsaAvail {
+		certReq12.certificateTypes = append(certReq12.certificateTypes, certTypeRSASign)
+	}
+	if ecdsaAvail {
+		certReq12.certificateTypes = append(certReq12.certificateTypes, certTypeECDSASign)
+	}
+
+	return hs.getCertificate(certReq12)
+}
+
+func (hs *clientHandshakeState) sendCertificate13(chainToSend *Certificate, certReq *certificateRequestMsg13) error {
+	c := hs.c
+
+	certEntries := []certificateEntry{}
+	for _, cert := range chainToSend.Certificate {
+		certEntries = append(certEntries, certificateEntry{data: cert})
+	}
+	certMsg := &certificateMsg13{certificates: certEntries}
+
+	hs.keySchedule.write(certMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+		return err
+	}
+
+	if len(certEntries) == 0 {
+		// No client cert available, nothing to sign.
+		return nil
+	}
+
+	key, ok := chainToSend.PrivateKey.(crypto.Signer)
+	if !ok {
+		c.sendAlert(alertInternalError)
+		return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
+	}
+
+	signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, hs.hello.supportedSignatureAlgorithms, c.vers)
+	if err != nil {
+		hs.c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+
+	digest := prepareDigitallySigned(hashFunc, "TLS 1.3, client CertificateVerify", hs.keySchedule.transcriptHash.Sum(nil))
+	signOpts := crypto.SignerOpts(hashFunc)
+	if sigType == signatureRSAPSS {
+		signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
+	}
+	signature, err := key.Sign(c.config.rand(), digest, signOpts)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+
+	verifyMsg := &certificateVerifyMsg{
+		hasSignatureAndHash: true,
+		signatureAlgorithm:  signatureAlgorithm,
+		signature:           signature,
+	}
+	hs.keySchedule.write(verifyMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, verifyMsg.marshal()); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *clientHandshakeState) doTLS13Handshake() error {
+	c := hs.c
+	hash := hashForSuite(hs.suite)
+	hashSize := hash.Size()
+	serverHello := hs.serverHello
+	c.scts = serverHello.scts
+
+	// middlebox compatibility mode, send CCS before second flight.
+	if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+		return err
+	}
+
+	// TODO check if keyshare is unacceptable, raise HRR.
+
+	clientKS := hs.hello.keyShares[0]
+	if serverHello.keyShare.group != clientKS.group {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("bad or missing key share from server")
+	}
+
+	// 0-RTT is not supported yet, so use an empty PSK.
+	hs.keySchedule.setSecret(nil)
+	ecdheSecret := deriveECDHESecret(serverHello.keyShare, hs.privateKey)
+	if ecdheSecret == nil {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: bad ECDHE server share")
+	}
+
+	// Calculate handshake secrets.
+	hs.keySchedule.setSecret(ecdheSecret)
+	clientCipher, clientHandshakeSecret := hs.keySchedule.prepareCipher(secretHandshakeClient)
+	serverCipher, serverHandshakeSecret := hs.keySchedule.prepareCipher(secretHandshakeServer)
+	if c.hand.Len() > 0 {
+		c.sendAlert(alertUnexpectedMessage)
+		return errors.New("tls: unexpected data after Server Hello")
+	}
+	// Do not change the sender key yet, the server must authenticate first.
+	c.in.setCipher(c.vers, serverCipher)
+
+	// Calculate MAC key for Finished messages.
+	serverFinishedKey := hkdfExpandLabel(hash, serverHandshakeSecret, nil, "finished", hashSize)
+	clientFinishedKey := hkdfExpandLabel(hash, clientHandshakeSecret, nil, "finished", hashSize)
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(encryptedExtensions, msg)
+	}
+	if err := hs.processEncryptedExtensions(encryptedExtensions); err != nil {
+		return err
+	}
+	hs.keySchedule.write(encryptedExtensions.marshal())
+
+	// PSKs are not supported, so receive Certificate message.
+	msg, err = c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	var chainToSend *Certificate
+	certReq, isCertRequested := msg.(*certificateRequestMsg13)
+	if isCertRequested {
+		hs.keySchedule.write(certReq.marshal())
+
+		if chainToSend, err = hs.getCertificate13(certReq); err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	certMsg, ok := msg.(*certificateMsg13)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
+	}
+	hs.keySchedule.write(certMsg.marshal())
+
+	// Validate certificates.
+	certs := getCertsFromEntries(certMsg.certificates)
+	if err := hs.processCertsFromServer(certs); err != nil {
+		return err
+	}
+
+	// Receive CertificateVerify message.
+	msg, err = c.readHandshake()
+	if err != nil {
+		return err
+	}
+	certVerifyMsg, ok := msg.(*certificateVerifyMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certVerifyMsg, msg)
+	}
+
+	// Validate the DC if present. The DC is only processed if the extension was
+	// indicated by the ClientHello; otherwise this call will result in an
+	// "illegal_parameter" alert.
+	if len(certMsg.certificates) > 0 {
+		if err := hs.processDelegatedCredentialFromServer(
+			certMsg.certificates[0].delegatedCredential,
+			certVerifyMsg.signatureAlgorithm); err != nil {
+			return err
+		}
+	}
+
+	// Set the public key used to verify the handshake.
+	pk := hs.c.peerCertificates[0].PublicKey
+
+	// If the delegated credential extension has successfully been negotiated,
+	// then the  CertificateVerify signature will have been produced with the
+	// DelegatedCredential's private key.
+	if hs.c.verifiedDc != nil {
+		pk = hs.c.verifiedDc.cred.publicKey
+	}
+
+	// Verify the handshake signature.
+	err, alertCode := verifyPeerHandshakeSignature(
+		certVerifyMsg,
+		pk,
+		hs.hello.supportedSignatureAlgorithms,
+		hs.keySchedule.transcriptHash.Sum(nil),
+		"TLS 1.3, server CertificateVerify")
+	if err != nil {
+		c.sendAlert(alertCode)
+		return err
+	}
+	hs.keySchedule.write(certVerifyMsg.marshal())
+
+	// Receive Finished message.
+	msg, err = c.readHandshake()
+	if err != nil {
+		return err
+	}
+	serverFinished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverFinished, msg)
+	}
+	// Validate server Finished hash.
+	expectedVerifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, serverFinishedKey)
+	if subtle.ConstantTimeCompare(expectedVerifyData, serverFinished.verifyData) != 1 {
+		c.sendAlert(alertDecryptError)
+		return errors.New("tls: server's Finished message is incorrect")
+	}
+	hs.keySchedule.write(serverFinished.marshal())
+
+	// Server has authenticated itself. Calculate application traffic secrets.
+	hs.keySchedule.setSecret(nil) // derive master secret
+	appServerCipher, _ := hs.keySchedule.prepareCipher(secretApplicationServer)
+	appClientCipher, _ := hs.keySchedule.prepareCipher(secretApplicationClient)
+	// TODO store initial traffic secret key for KeyUpdate GH #85
+
+	// Change outbound handshake cipher for final step
+	c.out.setCipher(c.vers, clientCipher)
+
+	// Client auth requires sending a (possibly empty) Certificate followed
+	// by a CertificateVerify message (if there was an actual certificate).
+	if isCertRequested {
+		if err := hs.sendCertificate13(chainToSend, certReq); err != nil {
+			return err
+		}
+	}
+
+	// Send Finished
+	verifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, clientFinishedKey)
+	clientFinished := &finishedMsg{
+		verifyData: verifyData,
+	}
+	if _, err := c.writeRecord(recordTypeHandshake, clientFinished.marshal()); err != nil {
+		return err
+	}
+
+	// Handshake done, set application traffic secret
+	c.out.setCipher(c.vers, appClientCipher)
+	if c.hand.Len() > 0 {
+		c.sendAlert(alertUnexpectedMessage)
+		return errors.New("tls: unexpected data after handshake")
+	}
+	c.in.setCipher(c.vers, appServerCipher)
+	return nil
+}
+
+// supportedSigAlgorithmsCert iterates over schemes and filters out those algorithms
+// which are not supported for certificate verification.
+func supportedSigAlgorithmsCert(schemes []SignatureScheme) (ret []SignatureScheme) {
+	for _, sig := range schemes {
+		// X509 doesn't support PSS signatures
+		if !signatureSchemeIsPSS(sig) {
+			ret = append(ret, sig)
+		}
+	}
+	return
+}

+ 107 - 0
vendor/github.com/Psiphon-Labs/tls-tris/README.md

@@ -0,0 +1,107 @@
+```
+ _____ _     ____        _        _
+|_   _| |   / ___|      | |_ _ __(_)___
+  | | | |   \___ \ _____| __| '__| / __|
+  | | | |___ ___) |_____| |_| |  | \__ \
+  |_| |_____|____/       \__|_|  |_|___/
+
+```
+
+crypto/tls, now with 100% more 1.3.
+
+THE API IS NOT STABLE AND DOCUMENTATION IS NOT GUARANTEED.
+
+[![Build Status](https://travis-ci.org/cloudflare/tls-tris.svg?branch=master)](https://travis-ci.org/cloudflare/tls-tris)
+
+## Usage
+
+Since `crypto/tls` is very deeply (and not that elegantly) coupled with the Go stdlib,
+tls-tris shouldn't be used as an external package.  It is also impossible to vendor it
+as `crypto/tls` because stdlib packages would import the standard one and mismatch.
+
+So, to build with tls-tris, you need to use a custom GOROOT.
+
+A script is provided that will take care of it for you: `./_dev/go.sh`.
+Just use that instead of the `go` tool.
+
+The script also transparently fetches the custom Cloudflare Go 1.10 compiler with the required backports.
+
+## Development
+
+### Dependencies
+
+Copy paste line bellow to install all required dependencies:
+
+* ArchLinux:
+```
+pacman -S go docker gcc git make patch python2 python-docker rsync
+```
+
+* Debian:
+```
+apt-get install build-essential docker go patch python python-pip rsync
+pip install setuptools
+pip install docker
+```
+
+* Ubuntu (18.04) :
+```
+apt-get update
+apt-get install build-essential docker docker.io golang patch python python-pip rsync sudo
+pip install setuptools
+pip install docker
+sudo usermod -a -G docker $USER
+```
+
+Similar dependencies can be found on any UNIX based system/distribution.
+
+### Building
+
+There are number of things that need to be setup before running tests. Most important step is to copy ``go env GOROOT`` directory to ``_dev`` and swap TLS implementation and recompile GO. Then for testing we use go implementation from ``_dev/GOROOT``.
+
+```
+git clone https://github.com/cloudflare/tls-tris.git
+cd tls-tris; cp _dev/utils/pre-commit .git/hooks/ 
+make -f _dev/Makefile build-all
+```
+
+### Testing
+
+We run 3 kinds of test:.
+
+* Unit testing: <br/>``make -f _dev/Makefile test-unit``
+* Testing against BoringSSL test suite: <br/>``make -f _dev/Makefile test-bogo``
+* Compatibility testing (see below):<br/>``make -f _dev/Makefile test-interop``
+
+To run all the tests in one go use:
+```
+make -f _dev/Makefile test
+```
+
+### Testing interoperability with 3rd party libraries
+
+In order to ensure compatibility we are testing our implementation against BoringSSL, NSS and PicoTLS.
+
+Makefile has a specific target for testing interoperability with external libraries. Following command can be used in order to run such test:
+
+```
+make -f _dev/Makefile test-interop
+```
+
+The makefile target is just a wrapper and it executes ``_dev/interop_test_runner`` script written in python. The script implements interoperability tests using ``python unittest`` framework. 
+
+Script can be started from command line directly. For example:
+
+```
+> ./interop_test_runner -v InteropServer_NSS.test_zero_rtt
+test_zero_rtt (__main__.InteropServer_NSS) ... ok
+
+----------------------------------------------------------------------
+Ran 1 test in 8.765s
+
+OK
+```
+
+### Debugging
+
+When the environment variable `TLSDEBUG` is set to `error`, Tris will print a hexdump of the Client Hello and a stack trace if an handshake error occurs. If the value is `short`, only the error and the first meaningful stack frame are printed.

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

@@ -0,0 +1,83 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import "strconv"
+
+type alert uint8
+
+const (
+	// alert level
+	alertLevelWarning = 1
+	alertLevelError   = 2
+)
+
+const (
+	alertCloseNotify            alert = 0
+	alertUnexpectedMessage      alert = 10
+	alertBadRecordMAC           alert = 20
+	alertDecryptionFailed       alert = 21
+	alertRecordOverflow         alert = 22
+	alertDecompressionFailure   alert = 30
+	alertHandshakeFailure       alert = 40
+	alertBadCertificate         alert = 42
+	alertUnsupportedCertificate alert = 43
+	alertCertificateRevoked     alert = 44
+	alertCertificateExpired     alert = 45
+	alertCertificateUnknown     alert = 46
+	alertIllegalParameter       alert = 47
+	alertUnknownCA              alert = 48
+	alertAccessDenied           alert = 49
+	alertDecodeError            alert = 50
+	alertDecryptError           alert = 51
+	alertProtocolVersion        alert = 70
+	alertInsufficientSecurity   alert = 71
+	alertInternalError          alert = 80
+	alertInappropriateFallback  alert = 86
+	alertUserCanceled           alert = 90
+	alertNoRenegotiation        alert = 100
+	alertCertificateRequired    alert = 116
+	alertNoApplicationProtocol  alert = 120
+	alertSuccess                alert = 255 // dummy value returned by unmarshal functions
+)
+
+var alertText = map[alert]string{
+	alertCloseNotify:            "close notify",
+	alertUnexpectedMessage:      "unexpected message",
+	alertBadRecordMAC:           "bad record MAC",
+	alertDecryptionFailed:       "decryption failed",
+	alertRecordOverflow:         "record overflow",
+	alertDecompressionFailure:   "decompression failure",
+	alertHandshakeFailure:       "handshake failure",
+	alertBadCertificate:         "bad certificate",
+	alertUnsupportedCertificate: "unsupported certificate",
+	alertCertificateRevoked:     "revoked certificate",
+	alertCertificateExpired:     "expired certificate",
+	alertCertificateUnknown:     "unknown certificate",
+	alertIllegalParameter:       "illegal parameter",
+	alertUnknownCA:              "unknown certificate authority",
+	alertAccessDenied:           "access denied",
+	alertDecodeError:            "error decoding message",
+	alertDecryptError:           "error decrypting message",
+	alertProtocolVersion:        "protocol version not supported",
+	alertInsufficientSecurity:   "insufficient security level",
+	alertInternalError:          "internal error",
+	alertInappropriateFallback:  "inappropriate fallback",
+	alertUserCanceled:           "user canceled",
+	alertNoRenegotiation:        "no renegotiation",
+	alertNoApplicationProtocol:  "no application protocol",
+}
+
+func (e alert) String() string {
+	s, ok := alertText[e]
+	if ok {
+		return "tls: " + s
+	}
+	return "tls: alert(" + strconv.Itoa(int(e)) + ")"
+}
+
+func (e alert) Error() string {
+	return e.String()
+}

+ 107 - 0
vendor/github.com/Psiphon-Labs/tls-tris/auth.go

@@ -0,0 +1,107 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"encoding/asn1"
+	"errors"
+	"fmt"
+)
+
+// pickSignatureAlgorithm selects a signature algorithm that is compatible with
+// the given public key and the list of algorithms from the peer and this side.
+//
+// The returned SignatureScheme codepoint is only meaningful for TLS 1.2,
+// previous TLS versions have a fixed hash function.
+func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (SignatureScheme, uint8, crypto.Hash, error) {
+	if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 {
+		// If the client didn't specify any signature_algorithms
+		// extension then we can assume that it supports SHA1. See
+		// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+		switch pubkey.(type) {
+		case *rsa.PublicKey:
+			if tlsVersion < VersionTLS12 {
+				return 0, signaturePKCS1v15, crypto.MD5SHA1, nil
+			} else {
+				return PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1, nil
+			}
+		case *ecdsa.PublicKey:
+			return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil
+		default:
+			return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey)
+		}
+	}
+	for _, sigAlg := range peerSigAlgs {
+		if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) {
+			continue
+		}
+		hashAlg, err := lookupTLSHash(sigAlg)
+		if err != nil {
+			panic("tls: supported signature algorithm has an unknown hash function")
+		}
+		sigType := signatureFromSignatureScheme(sigAlg)
+		if (sigType == signaturePKCS1v15 || hashAlg == crypto.SHA1) && tlsVersion >= VersionTLS13 {
+			// TLS 1.3 forbids RSASSA-PKCS1-v1_5 and SHA-1 for
+			// handshake messages.
+			continue
+		}
+		switch pubkey.(type) {
+		case *rsa.PublicKey:
+			if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS {
+				return sigAlg, sigType, hashAlg, nil
+			}
+		case *ecdsa.PublicKey:
+			if sigType == signatureECDSA {
+				return sigAlg, sigType, hashAlg, nil
+			}
+		}
+	}
+	return 0, 0, 0, errors.New("tls: peer doesn't support any common signature algorithms")
+}
+
+// verifyHandshakeSignature verifies a signature against pre-hashed handshake
+// contents.
+func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, digest, sig []byte) error {
+	switch sigType {
+	case signatureECDSA:
+		pubKey, ok := pubkey.(*ecdsa.PublicKey)
+		if !ok {
+			return errors.New("tls: ECDSA signing requires a ECDSA public key")
+		}
+		ecdsaSig := new(ecdsaSignature)
+		if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
+			return err
+		}
+		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+			return errors.New("tls: ECDSA signature contained zero or negative values")
+		}
+		if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
+			return errors.New("tls: ECDSA verification failure")
+		}
+	case signaturePKCS1v15:
+		pubKey, ok := pubkey.(*rsa.PublicKey)
+		if !ok {
+			return errors.New("tls: RSA signing requires a RSA public key")
+		}
+		if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
+			return err
+		}
+	case signatureRSAPSS:
+		pubKey, ok := pubkey.(*rsa.PublicKey)
+		if !ok {
+			return errors.New("tls: RSA signing requires a RSA public key")
+		}
+		signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
+		if err := rsa.VerifyPSS(pubKey, hashFunc, digest, sig, signOpts); err != nil {
+			return err
+		}
+	default:
+		return errors.New("tls: unknown signature algorithm")
+	}
+	return nil
+}

+ 428 - 0
vendor/github.com/Psiphon-Labs/tls-tris/cipher_suites.go

@@ -0,0 +1,428 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"crypto"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/des"
+	"crypto/hmac"
+	"crypto/rc4"
+	"crypto/sha1"
+	"crypto/sha256"
+	"hash"
+
+	"golang.org/x/crypto/chacha20poly1305"
+)
+
+// a keyAgreement implements the client and server side of a TLS key agreement
+// protocol by generating and processing key exchange messages.
+type keyAgreement interface {
+	// On the server side, the first two methods are called in order.
+
+	// In the case that the key agreement protocol doesn't use a
+	// ServerKeyExchange message, generateServerKeyExchange can return nil,
+	// nil.
+	generateServerKeyExchange(*Config, crypto.PrivateKey, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
+	processClientKeyExchange(*Config, crypto.PrivateKey, *clientKeyExchangeMsg, uint16) ([]byte, error)
+
+	// On the client side, the next two methods are called in order.
+
+	// This method may not be called if the server doesn't send a
+	// ServerKeyExchange message.
+	processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, crypto.PublicKey, *serverKeyExchangeMsg) error
+	generateClientKeyExchange(*Config, *clientHelloMsg, crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error)
+}
+
+const (
+	// suiteECDH indicates that the cipher suite involves elliptic curve
+	// Diffie-Hellman. This means that it should only be selected when the
+	// client indicates that it supports ECC with a curve and point format
+	// that we're happy with.
+	suiteECDHE = 1 << iota
+	// suiteECDSA indicates that the cipher suite involves an ECDSA
+	// signature and therefore may only be selected when the server's
+	// certificate is ECDSA. If this is not set then the cipher suite is
+	// RSA based.
+	suiteECDSA
+	// suiteTLS12 indicates that the cipher suite should only be advertised
+	// and accepted when using TLS 1.2.
+	suiteTLS12
+	// suiteTLS13 indicates that the ones and only cipher suites to be
+	// advertised and accepted when using TLS 1.3.
+	suiteTLS13
+	// suiteSHA384 indicates that the cipher suite uses SHA384 as the
+	// handshake hash.
+	suiteSHA384
+	// suiteDefaultOff indicates that this cipher suite is not included by
+	// default.
+	suiteDefaultOff
+)
+
+// A cipherSuite is a specific combination of key agreement, cipher and MAC
+// function.
+type cipherSuite struct {
+	id uint16
+	// the lengths, in bytes, of the key material needed for each component.
+	keyLen int
+	macLen int
+	ivLen  int
+	ka     func(version uint16) keyAgreement
+	// flags is a bitmask of the suite* values, above.
+	flags  int
+	cipher func(key, iv []byte, isRead bool) interface{}
+	mac    func(version uint16, macKey []byte) macFunction
+	aead   func(key, fixedNonce []byte) cipher.AEAD
+}
+
+var cipherSuites = []*cipherSuite{
+	// TLS 1.3 ciphersuites specify only the AEAD and the HKDF hash.
+	{TLS_CHACHA20_POLY1305_SHA256, 32, 0, 12, nil, suiteTLS13, nil, nil, aeadChaCha20Poly1305},
+	{TLS_AES_128_GCM_SHA256, 16, 0, 12, nil, suiteTLS13, nil, nil, aeadAESGCM13},
+	{TLS_AES_256_GCM_SHA384, 32, 0, 12, nil, suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM13},
+
+	// Ciphersuite order is chosen so that ECDHE comes before plain RSA and
+	// AEADs are the top preference.
+	{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+	{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM12},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM12},
+	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM12},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM12},
+	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
+	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM12},
+	{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM12},
+	{TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
+	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
+	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+
+	// RC4-based cipher suites are disabled by default.
+	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
+}
+
+func cipherRC4(key, iv []byte, isRead bool) interface{} {
+	cipher, _ := rc4.NewCipher(key)
+	return cipher
+}
+
+func cipher3DES(key, iv []byte, isRead bool) interface{} {
+	block, _ := des.NewTripleDESCipher(key)
+	if isRead {
+		return cipher.NewCBCDecrypter(block, iv)
+	}
+	return cipher.NewCBCEncrypter(block, iv)
+}
+
+func cipherAES(key, iv []byte, isRead bool) interface{} {
+	block, _ := aes.NewCipher(key)
+	if isRead {
+		return cipher.NewCBCDecrypter(block, iv)
+	}
+	return cipher.NewCBCEncrypter(block, iv)
+}
+
+// macSHA1 returns a macFunction for the given protocol version.
+func macSHA1(version uint16, key []byte) macFunction {
+	if version == VersionSSL30 {
+		mac := ssl30MAC{
+			h:   sha1.New(),
+			key: make([]byte, len(key)),
+		}
+		copy(mac.key, key)
+		return mac
+	}
+	return tls10MAC{hmac.New(newConstantTimeHash(sha1.New), key)}
+}
+
+// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2
+// so the given version is ignored.
+func macSHA256(version uint16, key []byte) macFunction {
+	return tls10MAC{hmac.New(sha256.New, key)}
+}
+
+type macFunction interface {
+	Size() int
+	MAC(digestBuf, seq, header, data, extra []byte) []byte
+}
+
+type aead interface {
+	cipher.AEAD
+
+	// explicitIVLen returns the number of bytes used by the explicit nonce
+	// that is included in the record. This is eight for older AEADs and
+	// zero for modern ones.
+	explicitNonceLen() int
+}
+
+// fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
+// each call.
+type fixedNonceAEAD struct {
+	// nonce contains the fixed part of the nonce in the first four bytes.
+	nonce [12]byte
+	aead  cipher.AEAD
+}
+
+func (f *fixedNonceAEAD) NonceSize() int { return 8 }
+
+// Overhead returns the maximum difference between the lengths of a
+// plaintext and its ciphertext.
+func (f *fixedNonceAEAD) Overhead() int         { return f.aead.Overhead() }
+func (f *fixedNonceAEAD) explicitNonceLen() int { return 8 }
+
+func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+	copy(f.nonce[4:], nonce)
+	return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
+}
+
+func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
+	copy(f.nonce[4:], nonce)
+	return f.aead.Open(out, f.nonce[:], plaintext, additionalData)
+}
+
+// xoredNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
+// before each call.
+type xorNonceAEAD struct {
+	nonceMask [12]byte
+	aead      cipher.AEAD
+}
+
+func (f *xorNonceAEAD) NonceSize() int        { return 8 }
+func (f *xorNonceAEAD) Overhead() int         { return f.aead.Overhead() }
+func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
+
+func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+	for i, b := range nonce {
+		f.nonceMask[4+i] ^= b
+	}
+	result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
+	for i, b := range nonce {
+		f.nonceMask[4+i] ^= b
+	}
+
+	return result
+}
+
+func (f *xorNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
+	for i, b := range nonce {
+		f.nonceMask[4+i] ^= b
+	}
+	result, err := f.aead.Open(out, f.nonceMask[:], plaintext, additionalData)
+	for i, b := range nonce {
+		f.nonceMask[4+i] ^= b
+	}
+
+	return result, err
+}
+
+func aeadAESGCM12(key, fixedNonce []byte) cipher.AEAD {
+	aes, err := aes.NewCipher(key)
+	if err != nil {
+		panic(err)
+	}
+	aead, err := cipher.NewGCM(aes)
+	if err != nil {
+		panic(err)
+	}
+
+	ret := &fixedNonceAEAD{aead: aead}
+	copy(ret.nonce[:], fixedNonce)
+	return ret
+}
+
+func aeadAESGCM13(key, fixedNonce []byte) cipher.AEAD {
+	aes, err := aes.NewCipher(key)
+	if err != nil {
+		panic(err)
+	}
+	aead, err := cipher.NewGCM(aes)
+	if err != nil {
+		panic(err)
+	}
+
+	ret := &xorNonceAEAD{aead: aead}
+	copy(ret.nonceMask[:], fixedNonce)
+	return ret
+}
+
+func aeadChaCha20Poly1305(key, fixedNonce []byte) cipher.AEAD {
+	aead, err := chacha20poly1305.New(key)
+	if err != nil {
+		panic(err)
+	}
+
+	ret := &xorNonceAEAD{aead: aead}
+	copy(ret.nonceMask[:], fixedNonce)
+	return ret
+}
+
+// ssl30MAC implements the SSLv3 MAC function, as defined in
+// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1
+type ssl30MAC struct {
+	h   hash.Hash
+	key []byte
+}
+
+func (s ssl30MAC) Size() int {
+	return s.h.Size()
+}
+
+var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}
+
+var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
+
+// MAC does not offer constant timing guarantees for SSL v3.0, since it's deemed
+// useless considering the similar, protocol-level POODLE vulnerability.
+func (s ssl30MAC) MAC(digestBuf, seq, header, data, extra []byte) []byte {
+	padLength := 48
+	if s.h.Size() == 20 {
+		padLength = 40
+	}
+
+	s.h.Reset()
+	s.h.Write(s.key)
+	s.h.Write(ssl30Pad1[:padLength])
+	s.h.Write(seq)
+	s.h.Write(header[:1])
+	s.h.Write(header[3:5])
+	s.h.Write(data)
+	digestBuf = s.h.Sum(digestBuf[:0])
+
+	s.h.Reset()
+	s.h.Write(s.key)
+	s.h.Write(ssl30Pad2[:padLength])
+	s.h.Write(digestBuf)
+	return s.h.Sum(digestBuf[:0])
+}
+
+type constantTimeHash interface {
+	hash.Hash
+	ConstantTimeSum(b []byte) []byte
+}
+
+// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces
+// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC.
+type cthWrapper struct {
+	h constantTimeHash
+}
+
+func (c *cthWrapper) Size() int                   { return c.h.Size() }
+func (c *cthWrapper) BlockSize() int              { return c.h.BlockSize() }
+func (c *cthWrapper) Reset()                      { c.h.Reset() }
+func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
+func (c *cthWrapper) Sum(b []byte) []byte         { return c.h.ConstantTimeSum(b) }
+
+func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
+	return func() hash.Hash {
+		return &cthWrapper{h().(constantTimeHash)}
+	}
+}
+
+// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
+type tls10MAC struct {
+	h hash.Hash
+}
+
+func (s tls10MAC) Size() int {
+	return s.h.Size()
+}
+
+// MAC is guaranteed to take constant time, as long as
+// len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into
+// the MAC, but is only provided to make the timing profile constant.
+func (s tls10MAC) MAC(digestBuf, seq, header, data, extra []byte) []byte {
+	s.h.Reset()
+	s.h.Write(seq)
+	s.h.Write(header)
+	s.h.Write(data)
+	res := s.h.Sum(digestBuf[:0])
+	if extra != nil {
+		s.h.Write(extra)
+	}
+	return res
+}
+
+func rsaKA(version uint16) keyAgreement {
+	return rsaKeyAgreement{}
+}
+
+func ecdheECDSAKA(version uint16) keyAgreement {
+	return &ecdheKeyAgreement{
+		isRSA:   false,
+		version: version,
+	}
+}
+
+func ecdheRSAKA(version uint16) keyAgreement {
+	return &ecdheKeyAgreement{
+		isRSA:   true,
+		version: version,
+	}
+}
+
+// mutualCipherSuite returns a cipherSuite given a list of supported
+// ciphersuites and the id requested by the peer.
+func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
+	for _, id := range have {
+		if id == want {
+			for _, suite := range cipherSuites {
+				if suite.id == want {
+					return suite
+				}
+			}
+			return nil
+		}
+	}
+	return nil
+}
+
+// A list of cipher suite IDs that are, or have been, implemented by this
+// package.
+//
+// Taken from http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+const (
+	// TLS 1.0 - 1.2 cipher suites.
+	TLS_RSA_WITH_RC4_128_SHA                uint16 = 0x0005
+	TLS_RSA_WITH_3DES_EDE_CBC_SHA           uint16 = 0x000a
+	TLS_RSA_WITH_AES_128_CBC_SHA            uint16 = 0x002f
+	TLS_RSA_WITH_AES_256_CBC_SHA            uint16 = 0x0035
+	TLS_RSA_WITH_AES_128_CBC_SHA256         uint16 = 0x003c
+	TLS_RSA_WITH_AES_128_GCM_SHA256         uint16 = 0x009c
+	TLS_RSA_WITH_AES_256_GCM_SHA384         uint16 = 0x009d
+	TLS_ECDHE_ECDSA_WITH_RC4_128_SHA        uint16 = 0xc007
+	TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA    uint16 = 0xc009
+	TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA    uint16 = 0xc00a
+	TLS_ECDHE_RSA_WITH_RC4_128_SHA          uint16 = 0xc011
+	TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA     uint16 = 0xc012
+	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA      uint16 = 0xc013
+	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0xc014
+	TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
+	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256   uint16 = 0xc027
+	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   uint16 = 0xc02f
+	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+	TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384   uint16 = 0xc030
+	TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
+	TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305    uint16 = 0xcca8
+	TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305  uint16 = 0xcca9
+
+	// TLS 1.3+ cipher suites.
+	TLS_AES_128_GCM_SHA256       uint16 = 0x1301
+	TLS_AES_256_GCM_SHA384       uint16 = 0x1302
+	TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303
+
+	// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
+	// that the client is doing version fallback. See
+	// https://tools.ietf.org/html/rfc7507.
+	TLS_FALLBACK_SCSV uint16 = 0x5600
+)

+ 1229 - 0
vendor/github.com/Psiphon-Labs/tls-tris/common.go

@@ -0,0 +1,1229 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"container/list"
+	"crypto"
+	"crypto/rand"
+	"crypto/sha512"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"io"
+	"math/big"
+	"net"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/Psiphon-Labs/utls/cipherhw"
+)
+
+const (
+	VersionSSL30        = 0x0300
+	VersionTLS10        = 0x0301
+	VersionTLS11        = 0x0302
+	VersionTLS12        = 0x0303
+	VersionTLS13        = 0x0304
+	VersionTLS13Draft28 = 0x7f00 | 28
+)
+
+const (
+	maxPlaintext      = 16384        // maximum plaintext payload length
+	maxCiphertext     = 16384 + 2048 // maximum ciphertext payload length
+	recordHeaderLen   = 5            // record header length
+	maxHandshake      = 65536        // maximum handshake we support (protocol max is 16 MB)
+	maxWarnAlertCount = 5            // maximum number of consecutive warning alerts
+
+	minVersion = VersionTLS12
+	maxVersion = VersionTLS13Draft28
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+	recordTypeChangeCipherSpec recordType = 20
+	recordTypeAlert            recordType = 21
+	recordTypeHandshake        recordType = 22
+	recordTypeApplicationData  recordType = 23
+)
+
+// TLS handshake message types.
+const (
+	typeHelloRequest        uint8 = 0
+	typeClientHello         uint8 = 1
+	typeServerHello         uint8 = 2
+	typeNewSessionTicket    uint8 = 4
+	typeEndOfEarlyData      uint8 = 5
+	typeEncryptedExtensions uint8 = 8
+	typeCertificate         uint8 = 11
+	typeServerKeyExchange   uint8 = 12
+	typeCertificateRequest  uint8 = 13
+	typeServerHelloDone     uint8 = 14
+	typeCertificateVerify   uint8 = 15
+	typeClientKeyExchange   uint8 = 16
+	typeFinished            uint8 = 20
+	typeCertificateStatus   uint8 = 22
+	typeNextProtocol        uint8 = 67 // Not IANA assigned
+)
+
+// TLS compression types.
+const (
+	compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+const (
+	extensionServerName              uint16 = 0
+	extensionStatusRequest           uint16 = 5
+	extensionSupportedCurves         uint16 = 10 // Supported Groups in 1.3 nomenclature
+	extensionSupportedPoints         uint16 = 11
+	extensionSignatureAlgorithms     uint16 = 13
+	extensionALPN                    uint16 = 16
+	extensionSCT                     uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
+	extensionSessionTicket           uint16 = 35
+	extensionPreSharedKey            uint16 = 41
+	extensionEarlyData               uint16 = 42
+	extensionSupportedVersions       uint16 = 43
+	extensionPSKKeyExchangeModes     uint16 = 45
+	extensionCAs                     uint16 = 47
+	extensionSignatureAlgorithmsCert uint16 = 50
+	extensionKeyShare                uint16 = 51
+	extensionNextProtoNeg            uint16 = 13172 // not IANA assigned
+	extensionRenegotiationInfo       uint16 = 0xff01
+	extensionDelegatedCredential     uint16 = 0xff02 // TODO(any) Get IANA assignment
+)
+
+// TLS signaling cipher suite values
+const (
+	scsvRenegotiation uint16 = 0x00ff
+)
+
+// PSK Key Exchange Modes
+// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.7
+const (
+	pskDHEKeyExchange uint8 = 1
+)
+
+// CurveID is the type of a TLS identifier for an elliptic curve. See
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+//
+// TLS 1.3 refers to these as Groups, but this library implements only
+// curve-based ones anyway. See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4.
+type CurveID uint16
+
+const (
+	CurveP256 CurveID = 23
+	CurveP384 CurveID = 24
+	CurveP521 CurveID = 25
+	X25519    CurveID = 29
+)
+
+// TLS 1.3 Key Share
+// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
+type keyShare struct {
+	group CurveID
+	data  []byte
+}
+
+// TLS 1.3 PSK Identity and Binder, as sent by the client
+// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6
+
+type psk struct {
+	identity     []byte
+	obfTicketAge uint32
+	binder       []byte
+}
+
+// TLS Elliptic Curve Point Formats
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+const (
+	pointFormatUncompressed uint8 = 0
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+	statusTypeOCSP uint8 = 1
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+	certTypeRSASign    = 1 // A certificate containing an RSA key
+	certTypeDSSSign    = 2 // A certificate containing a DSA key
+	certTypeRSAFixedDH = 3 // A certificate containing a static DH key
+	certTypeDSSFixedDH = 4 // A certificate containing a static DH key
+
+	// See RFC 4492 sections 3 and 5.5.
+	certTypeECDSASign      = 64 // A certificate containing an ECDSA-capable public key, signed with ECDSA.
+	certTypeRSAFixedECDH   = 65 // A certificate containing an ECDH-capable public key, signed with RSA.
+	certTypeECDSAFixedECDH = 66 // A certificate containing an ECDH-capable public key, signed with ECDSA.
+
+	// Rest of these are reserved by the TLS spec
+)
+
+// Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1)
+const (
+	signaturePKCS1v15 uint8 = iota + 1
+	signatureECDSA
+	signatureRSAPSS
+)
+
+// supportedSignatureAlgorithms contains the signature and hash algorithms that
+// the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2
+// CertificateRequest. The two fields are merged to match with TLS 1.3.
+// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc.
+var supportedSignatureAlgorithms = []SignatureScheme{
+	PKCS1WithSHA256,
+	ECDSAWithP256AndSHA256,
+	PKCS1WithSHA384,
+	ECDSAWithP384AndSHA384,
+	PKCS1WithSHA512,
+	ECDSAWithP521AndSHA512,
+	PKCS1WithSHA1,
+	ECDSAWithSHA1,
+}
+
+// supportedSignatureAlgorithms13 lists the advertised signature algorithms
+// allowed for digital signatures. It includes TLS 1.2 + PSS.
+var supportedSignatureAlgorithms13 = []SignatureScheme{
+	PSSWithSHA256,
+	PKCS1WithSHA256,
+	ECDSAWithP256AndSHA256,
+	PSSWithSHA384,
+	PKCS1WithSHA384,
+	ECDSAWithP384AndSHA384,
+	PSSWithSHA512,
+	PKCS1WithSHA512,
+	ECDSAWithP521AndSHA512,
+	PKCS1WithSHA1,
+	ECDSAWithSHA1,
+}
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+	ConnectionID                []byte                // Random unique connection id
+	Version                     uint16                // TLS version used by the connection (e.g. VersionTLS12)
+	HandshakeComplete           bool                  // TLS handshake is complete
+	DidResume                   bool                  // connection resumes a previous TLS connection
+	CipherSuite                 uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
+	NegotiatedProtocol          string                // negotiated next protocol (not guaranteed to be from Config.NextProtos)
+	NegotiatedProtocolIsMutual  bool                  // negotiated protocol was advertised by server (client side only)
+	ServerName                  string                // server name requested by client, if any (server side only)
+	PeerCertificates            []*x509.Certificate   // certificate chain presented by remote peer
+	VerifiedChains              [][]*x509.Certificate // verified chains built from PeerCertificates
+	SignedCertificateTimestamps [][]byte              // SCTs from the server, if any
+	OCSPResponse                []byte                // stapled OCSP response from server, if any
+	DelegatedCredential         []byte                // Delegated credential sent by the server, if any
+
+	// TLSUnique contains the "tls-unique" channel binding value (see RFC
+	// 5929, section 3). For resumed sessions this value will be nil
+	// because resumption does not include enough context (see
+	// https://mitls.org/pages/attacks/3SHAKE#channelbindings). This will
+	// change in future versions of Go once the TLS master-secret fix has
+	// been standardized and implemented.
+	TLSUnique []byte
+
+	// HandshakeConfirmed is true once all data returned by Read
+	// (past and future) is guaranteed not to be replayed.
+	HandshakeConfirmed bool
+
+	// Unique0RTTToken is a value that never repeats, and can be used
+	// to detect replay attacks against 0-RTT connections.
+	// Unique0RTTToken is only present if HandshakeConfirmed is false.
+	Unique0RTTToken []byte
+
+	ClientHello []byte // ClientHello packet
+}
+
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+const (
+	NoClientCert ClientAuthType = iota
+	RequestClientCert
+	RequireAnyClientCert
+	VerifyClientCertIfGiven
+	RequireAndVerifyClientCert
+)
+
+// ClientSessionState contains the state needed by clients to resume TLS
+// sessions.
+type ClientSessionState struct {
+	sessionTicket      []uint8               // Encrypted ticket used for session resumption with server
+	vers               uint16                // SSL/TLS version negotiated for the session
+	cipherSuite        uint16                // Ciphersuite negotiated for the session
+	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
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines. Only ticket-based resumption is supported, not SessionID-based
+// resumption.
+type ClientSessionCache interface {
+	// Get searches for a ClientSessionState associated with the given key.
+	// On return, ok is true if one was found.
+	Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+	// Put adds the ClientSessionState to the cache with the given key.
+	Put(sessionKey string, cs *ClientSessionState)
+}
+
+// SignatureScheme identifies a signature algorithm supported by TLS. See
+// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3.
+type SignatureScheme uint16
+
+const (
+	PKCS1WithSHA1   SignatureScheme = 0x0201
+	PKCS1WithSHA256 SignatureScheme = 0x0401
+	PKCS1WithSHA384 SignatureScheme = 0x0501
+	PKCS1WithSHA512 SignatureScheme = 0x0601
+
+	PSSWithSHA256 SignatureScheme = 0x0804
+	PSSWithSHA384 SignatureScheme = 0x0805
+	PSSWithSHA512 SignatureScheme = 0x0806
+
+	ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
+	ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
+	ECDSAWithP521AndSHA512 SignatureScheme = 0x0603
+
+	// Legacy signature and hash algorithms for TLS 1.2.
+	ECDSAWithSHA1 SignatureScheme = 0x0203
+)
+
+// ClientHelloInfo contains information from a ClientHello message in order to
+// guide certificate selection in the GetCertificate callback.
+type ClientHelloInfo struct {
+	// CipherSuites lists the CipherSuites supported by the client (e.g.
+	// TLS_RSA_WITH_RC4_128_SHA).
+	CipherSuites []uint16
+
+	// ServerName indicates the name of the server requested by the client
+	// in order to support virtual hosting. ServerName is only set if the
+	// client is using SNI (see
+	// http://tools.ietf.org/html/rfc4366#section-3.1).
+	ServerName string
+
+	// SupportedCurves lists the elliptic curves supported by the client.
+	// SupportedCurves is set only if the Supported Elliptic Curves
+	// Extension is being used (see
+	// http://tools.ietf.org/html/rfc4492#section-5.1.1).
+	SupportedCurves []CurveID
+
+	// SupportedPoints lists the point formats supported by the client.
+	// SupportedPoints is set only if the Supported Point Formats Extension
+	// is being used (see
+	// http://tools.ietf.org/html/rfc4492#section-5.1.2).
+	SupportedPoints []uint8
+
+	// SignatureSchemes lists the signature and hash schemes that the client
+	// is willing to verify. SignatureSchemes is set only if the Signature
+	// Algorithms Extension is being used (see
+	// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1).
+	SignatureSchemes []SignatureScheme
+
+	// SupportedProtos lists the application protocols supported by the client.
+	// SupportedProtos is set only if the Application-Layer Protocol
+	// Negotiation Extension is being used (see
+	// https://tools.ietf.org/html/rfc7301#section-3.1).
+	//
+	// Servers can select a protocol by setting Config.NextProtos in a
+	// GetConfigForClient return value.
+	SupportedProtos []string
+
+	// SupportedVersions lists the TLS versions supported by the client.
+	// For TLS versions less than 1.3, this is extrapolated from the max
+	// version advertised by the client, so values other than the greatest
+	// might be rejected if used.
+	SupportedVersions []uint16
+
+	// Conn is the underlying net.Conn for the connection. Do not read
+	// from, or write to, this connection; that will cause the TLS
+	// connection to fail.
+	Conn net.Conn
+
+	// Offered0RTTData is true if the client announced that it will send
+	// 0-RTT data. If the server Config.Accept0RTTData is true, and the
+	// client offered a session ticket valid for that purpose, it will
+	// be notified that the 0-RTT data is accepted and it will be made
+	// immediately available for Read.
+	Offered0RTTData bool
+
+	// AcceptsDelegatedCredential is true if the client indicated willingness
+	// to negotiate the delegated credential extension.
+	AcceptsDelegatedCredential bool
+
+	// The Fingerprint is an sequence of bytes unique to this Client Hello.
+	// It can be used to prevent or mitigate 0-RTT data replays as it's
+	// guaranteed that a replayed connection will have the same Fingerprint.
+	Fingerprint []byte
+}
+
+// CertificateRequestInfo contains information from a server's
+// CertificateRequest message, which is used to demand a certificate and proof
+// of control from a client.
+type CertificateRequestInfo struct {
+	// AcceptableCAs contains zero or more, DER-encoded, X.501
+	// Distinguished Names. These are the names of root or intermediate CAs
+	// that the server wishes the returned certificate to be signed by. An
+	// empty slice indicates that the server has no preference.
+	AcceptableCAs [][]byte
+
+	// SignatureSchemes lists the signature schemes that the server is
+	// willing to verify.
+	SignatureSchemes []SignatureScheme
+}
+
+// RenegotiationSupport enumerates the different levels of support for TLS
+// renegotiation. TLS renegotiation is the act of performing subsequent
+// handshakes on a connection after the first. This significantly complicates
+// the state machine and has been the source of numerous, subtle security
+// issues. Initiating a renegotiation is not supported, but support for
+// accepting renegotiation requests may be enabled.
+//
+// Even when enabled, the server may not change its identity between handshakes
+// (i.e. the leaf certificate must be the same). Additionally, concurrent
+// handshake and application data flow is not permitted so renegotiation can
+// only be used with protocols that synchronise with the renegotiation, such as
+// HTTPS.
+type RenegotiationSupport int
+
+const (
+	// RenegotiateNever disables renegotiation.
+	RenegotiateNever RenegotiationSupport = iota
+
+	// RenegotiateOnceAsClient allows a remote server to request
+	// renegotiation once per connection.
+	RenegotiateOnceAsClient
+
+	// RenegotiateFreelyAsClient allows a remote server to repeatedly
+	// request renegotiation.
+	RenegotiateFreelyAsClient
+)
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
+type Config struct {
+	// Rand provides the source of entropy for nonces and RSA blinding.
+	// If Rand is nil, TLS uses the cryptographic random reader in package
+	// crypto/rand.
+	// The Reader must be safe for use by multiple goroutines.
+	Rand io.Reader
+
+	// Time returns the current time as the number of seconds since the epoch.
+	// If Time is nil, TLS uses time.Now.
+	Time func() time.Time
+
+	// Certificates contains one or more certificate chains to present to
+	// the other side of the connection. Server configurations must include
+	// at least one certificate or else set GetCertificate. Clients doing
+	// client-authentication may set either Certificates or
+	// GetClientCertificate.
+	Certificates []Certificate
+
+	// NameToCertificate maps from a certificate name to an element of
+	// Certificates. Note that a certificate name can be of the form
+	// '*.example.com' and so doesn't have to be a domain name as such.
+	// See Config.BuildNameToCertificate
+	// The nil value causes the first element of Certificates to be used
+	// for all connections.
+	NameToCertificate map[string]*Certificate
+
+	// GetCertificate returns a Certificate based on the given
+	// ClientHelloInfo. It will only be called if the client supplies SNI
+	// information or if Certificates is empty.
+	//
+	// If GetCertificate is nil or returns nil, then the certificate is
+	// retrieved from NameToCertificate. If NameToCertificate is nil, the
+	// first element of Certificates will be used.
+	GetCertificate func(*ClientHelloInfo) (*Certificate, error)
+
+	// GetClientCertificate, if not nil, is called when a server requests a
+	// certificate from a client. If set, the contents of Certificates will
+	// be ignored.
+	//
+	// If GetClientCertificate returns an error, the handshake will be
+	// aborted and that error will be returned. Otherwise
+	// GetClientCertificate must return a non-nil Certificate. If
+	// Certificate.Certificate is empty then no certificate will be sent to
+	// the server. If this is unacceptable to the server then it may abort
+	// the handshake.
+	//
+	// GetClientCertificate may be called multiple times for the same
+	// connection if renegotiation occurs or if TLS 1.3 is in use.
+	GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
+
+	// GetConfigForClient, if not nil, is called after a ClientHello is
+	// received from a client. It may return a non-nil Config in order to
+	// change the Config that will be used to handle this connection. If
+	// the returned Config is nil, the original Config will be used. The
+	// Config returned by this callback may not be subsequently modified.
+	//
+	// If GetConfigForClient is nil, the Config passed to Server() will be
+	// used for all connections.
+	//
+	// Uniquely for the fields in the returned Config, session ticket keys
+	// will be duplicated from the original Config if not set.
+	// Specifically, if SetSessionTicketKeys was called on the original
+	// config but not on the returned config then the ticket keys from the
+	// original config will be copied into the new config before use.
+	// Otherwise, if SessionTicketKey was set in the original config but
+	// not in the returned config then it will be copied into the returned
+	// config before use. If neither of those cases applies then the key
+	// material from the returned config will be used for session tickets.
+	GetConfigForClient func(*ClientHelloInfo) (*Config, error)
+
+	// VerifyPeerCertificate, if not nil, is called after normal
+	// certificate verification by either a TLS client or server. It
+	// receives the raw ASN.1 certificates provided by the peer and also
+	// any verified chains that normal processing found. If it returns a
+	// non-nil error, the handshake is aborted and that error results.
+	//
+	// If normal verification fails then the handshake will abort before
+	// considering this callback. If normal verification is disabled by
+	// setting InsecureSkipVerify, or (for a server) when ClientAuth is
+	// RequestClientCert or RequireAnyClientCert, then this callback will
+	// be considered but the verifiedChains argument will always be nil.
+	VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+
+	// RootCAs defines the set of root certificate authorities
+	// that clients use when verifying server certificates.
+	// If RootCAs is nil, TLS uses the host's root CA set.
+	RootCAs *x509.CertPool
+
+	// NextProtos is a list of supported, application level protocols.
+	NextProtos []string
+
+	// ServerName is used to verify the hostname on the returned
+	// certificates unless InsecureSkipVerify is given. It is also included
+	// in the client's handshake to support virtual hosting unless it is
+	// an IP address.
+	ServerName string
+
+	// ClientAuth determines the server's policy for
+	// TLS Client Authentication. The default is NoClientCert.
+	ClientAuth ClientAuthType
+
+	// ClientCAs defines the set of root certificate authorities
+	// that servers use if required to verify a client certificate
+	// by the policy in ClientAuth.
+	ClientCAs *x509.CertPool
+
+	// InsecureSkipVerify controls whether a client verifies the
+	// server's certificate chain and host name.
+	// If InsecureSkipVerify is true, TLS accepts any certificate
+	// presented by the server and any host name in that certificate.
+	// In this mode, TLS is susceptible to man-in-the-middle attacks.
+	// This should be used only for testing.
+	InsecureSkipVerify bool
+
+	// CipherSuites is a list of supported cipher suites to be used in
+	// TLS 1.0-1.2. If CipherSuites is nil, TLS uses a list of suites
+	// supported by the implementation.
+	CipherSuites []uint16
+
+	// PreferServerCipherSuites controls whether the server selects the
+	// client's most preferred ciphersuite, or the server's most preferred
+	// ciphersuite. If true then the server's preference, as expressed in
+	// the order of elements in CipherSuites, is used.
+	PreferServerCipherSuites bool
+
+	// SessionTicketsDisabled may be set to true to disable session ticket
+	// (resumption) support.
+	SessionTicketsDisabled bool
+
+	// SessionTicketKey is used by TLS servers to provide session
+	// resumption. See RFC 5077. If zero, it will be filled with
+	// random data before the first server handshake.
+	//
+	// If multiple servers are terminating connections for the same host
+	// they should all have the same SessionTicketKey. If the
+	// SessionTicketKey leaks, previously recorded and future TLS
+	// connections using that key are compromised.
+	SessionTicketKey [32]byte
+
+	// ClientSessionCache is a cache of ClientSessionState entries for TLS
+	// session resumption.
+	ClientSessionCache ClientSessionCache
+
+	// MinVersion contains the minimum SSL/TLS version that is acceptable.
+	// If zero, then TLS 1.0 is taken as the minimum.
+	MinVersion uint16
+
+	// MaxVersion contains the maximum SSL/TLS version that is acceptable.
+	// If zero, then the maximum version supported by this package is used,
+	// which is currently TLS 1.2.
+	MaxVersion uint16
+
+	// CurvePreferences contains the elliptic curves that will be used in
+	// an ECDHE handshake, in preference order. If empty, the default will
+	// be used.
+	CurvePreferences []CurveID
+
+	// DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
+	// When true, the largest possible TLS record size is always used. When
+	// false, the size of TLS records may be adjusted in an attempt to
+	// improve latency.
+	DynamicRecordSizingDisabled bool
+
+	// Renegotiation controls what types of renegotiation are supported.
+	// The default, none, is correct for the vast majority of applications.
+	Renegotiation RenegotiationSupport
+
+	// KeyLogWriter optionally specifies a destination for TLS master secrets
+	// in NSS key log format that can be used to allow external programs
+	// such as Wireshark to decrypt TLS connections.
+	// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+	// Use of KeyLogWriter compromises security and should only be
+	// used for debugging.
+	KeyLogWriter io.Writer
+
+	// If Max0RTTDataSize is not zero, the client will be allowed to use
+	// session tickets to send at most this number of bytes of 0-RTT data.
+	// 0-RTT data is subject to replay and has memory DoS implications.
+	// The server will later be able to refuse the 0-RTT data with
+	// Accept0RTTData, or wait for the client to prove that it's not
+	// replayed with Conn.ConfirmHandshake.
+	//
+	// It has no meaning on the client.
+	//
+	// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-2.3.
+	Max0RTTDataSize uint32
+
+	// Accept0RTTData makes the 0-RTT data received from the client
+	// immediately available to Read. 0-RTT data is subject to replay.
+	// Use Conn.ConfirmHandshake to wait until the data is known not
+	// to be replayed after reading it.
+	//
+	// It has no meaning on the client.
+	//
+	// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-2.3.
+	Accept0RTTData bool
+
+	// SessionTicketSealer, if not nil, is used to wrap and unwrap
+	// session tickets, instead of SessionTicketKey.
+	SessionTicketSealer SessionTicketSealer
+
+	// AcceptDelegatedCredential is true if the client is willing to negotiate
+	// the delegated credential extension.
+	//
+	// This value has no meaning for the server.
+	//
+	// See https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
+	AcceptDelegatedCredential bool
+
+	// GetDelegatedCredential returns a DC and its private key for use in the
+	// delegated credential extension. The inputs to the callback are some
+	// information parsed from the ClientHello, as well as the protocol version
+	// selected by the server. This is necessary because the DC is bound to the
+	// protocol version in which it's used. The return value is the raw DC
+	// encoded in the wire format specified in
+	// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02. If the return
+	// value is nil, then the server will not offer negotiate the extension.
+	//
+	// This value has no meaning for the client.
+	GetDelegatedCredential func(*ClientHelloInfo, uint16) ([]byte, crypto.PrivateKey, error)
+
+	serverInitOnce sync.Once // guards calling (*Config).serverInit
+
+	// mutex protects sessionTicketKeys.
+	mutex sync.RWMutex
+	// sessionTicketKeys contains zero or more ticket keys. If the length
+	// is zero, SessionTicketsDisabled must be true. The first key is used
+	// for new tickets and any subsequent keys can be used to decrypt old
+	// tickets.
+	sessionTicketKeys []ticketKey
+}
+
+// ticketKeyNameLen is the number of bytes of identifier that is prepended to
+// an encrypted session ticket in order to identify the key used to encrypt it.
+const ticketKeyNameLen = 16
+
+// ticketKey is the internal representation of a session ticket key.
+type ticketKey struct {
+	// keyName is an opaque byte string that serves to identify the session
+	// ticket key. It's exposed as plaintext in every session ticket.
+	keyName [ticketKeyNameLen]byte
+	aesKey  [16]byte
+	hmacKey [16]byte
+}
+
+// ticketKeyFromBytes converts from the external representation of a session
+// ticket key to a ticketKey. Externally, session ticket keys are 32 random
+// bytes and this function expands that into sufficient name and key material.
+func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+	hashed := sha512.Sum512(b[:])
+	copy(key.keyName[:], hashed[:ticketKeyNameLen])
+	copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
+	copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+	return key
+}
+
+// Clone returns a shallow clone of c. It is safe to clone a Config that is
+// being used concurrently by a TLS client or server.
+func (c *Config) Clone() *Config {
+	// Running serverInit ensures that it's safe to read
+	// SessionTicketsDisabled.
+	c.serverInitOnce.Do(func() { c.serverInit(nil) })
+
+	var sessionTicketKeys []ticketKey
+	c.mutex.RLock()
+	sessionTicketKeys = c.sessionTicketKeys
+	c.mutex.RUnlock()
+
+	return &Config{
+		Rand:                        c.Rand,
+		Time:                        c.Time,
+		Certificates:                c.Certificates,
+		NameToCertificate:           c.NameToCertificate,
+		GetCertificate:              c.GetCertificate,
+		GetClientCertificate:        c.GetClientCertificate,
+		GetConfigForClient:          c.GetConfigForClient,
+		VerifyPeerCertificate:       c.VerifyPeerCertificate,
+		RootCAs:                     c.RootCAs,
+		NextProtos:                  c.NextProtos,
+		ServerName:                  c.ServerName,
+		ClientAuth:                  c.ClientAuth,
+		ClientCAs:                   c.ClientCAs,
+		InsecureSkipVerify:          c.InsecureSkipVerify,
+		CipherSuites:                c.CipherSuites,
+		PreferServerCipherSuites:    c.PreferServerCipherSuites,
+		SessionTicketsDisabled:      c.SessionTicketsDisabled,
+		SessionTicketKey:            c.SessionTicketKey,
+		ClientSessionCache:          c.ClientSessionCache,
+		MinVersion:                  c.MinVersion,
+		MaxVersion:                  c.MaxVersion,
+		CurvePreferences:            c.CurvePreferences,
+		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
+		Renegotiation:               c.Renegotiation,
+		KeyLogWriter:                c.KeyLogWriter,
+		Accept0RTTData:              c.Accept0RTTData,
+		Max0RTTDataSize:             c.Max0RTTDataSize,
+		SessionTicketSealer:         c.SessionTicketSealer,
+		AcceptDelegatedCredential:   c.AcceptDelegatedCredential,
+		GetDelegatedCredential:      c.GetDelegatedCredential,
+		sessionTicketKeys:           sessionTicketKeys,
+	}
+}
+
+// serverInit is run under c.serverInitOnce to do initialization of c. If c was
+// returned by a GetConfigForClient callback then the argument should be the
+// Config that was passed to Server, otherwise it should be nil.
+func (c *Config) serverInit(originalConfig *Config) {
+	if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 || c.SessionTicketSealer != nil {
+		return
+	}
+
+	alreadySet := false
+	for _, b := range c.SessionTicketKey {
+		if b != 0 {
+			alreadySet = true
+			break
+		}
+	}
+
+	if !alreadySet {
+		if originalConfig != nil {
+			copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:])
+		} else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+			c.SessionTicketsDisabled = true
+			return
+		}
+	}
+
+	if originalConfig != nil {
+		originalConfig.mutex.RLock()
+		c.sessionTicketKeys = originalConfig.sessionTicketKeys
+		originalConfig.mutex.RUnlock()
+	} else {
+		c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+	}
+}
+
+func (c *Config) ticketKeys() []ticketKey {
+	c.mutex.RLock()
+	// c.sessionTicketKeys is constant once created. SetSessionTicketKeys
+	// will only update it by replacing it with a new value.
+	ret := c.sessionTicketKeys
+	c.mutex.RUnlock()
+	return ret
+}
+
+// SetSessionTicketKeys updates the session ticket keys for a server. The first
+// key will be used when creating new tickets, while all keys can be used for
+// decrypting tickets. It is safe to call this function while the server is
+// running in order to rotate the session ticket keys. The function will panic
+// if keys is empty.
+func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
+	if len(keys) == 0 {
+		panic("tls: keys must have at least one key")
+	}
+
+	newKeys := make([]ticketKey, len(keys))
+	for i, bytes := range keys {
+		newKeys[i] = ticketKeyFromBytes(bytes)
+	}
+
+	c.mutex.Lock()
+	c.sessionTicketKeys = newKeys
+	c.mutex.Unlock()
+}
+
+func (c *Config) rand() io.Reader {
+	r := c.Rand
+	if r == nil {
+		return rand.Reader
+	}
+	return r
+}
+
+func (c *Config) time() time.Time {
+	t := c.Time
+	if t == nil {
+		t = time.Now
+	}
+	return t()
+}
+
+func hasOverlappingCipherSuites(cs1, cs2 []uint16) bool {
+	for _, c1 := range cs1 {
+		for _, c2 := range cs2 {
+			if c1 == c2 {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func (c *Config) cipherSuites() []uint16 {
+	s := c.CipherSuites
+	if s == nil {
+		s = defaultCipherSuites()
+	} else if c.maxVersion() >= VersionTLS13 {
+		// Ensure that TLS 1.3 suites are always present, but respect
+		// the application cipher suite preferences.
+		s13 := defaultTLS13CipherSuites()
+		if !hasOverlappingCipherSuites(s, s13) {
+			allSuites := make([]uint16, len(s13)+len(s))
+			allSuites = append(allSuites, s13...)
+			s = append(allSuites, s...)
+		}
+	}
+	return s
+}
+
+func (c *Config) minVersion() uint16 {
+	if c == nil || c.MinVersion == 0 {
+		return minVersion
+	}
+	return c.MinVersion
+}
+
+func (c *Config) maxVersion() uint16 {
+	if c == nil || c.MaxVersion == 0 {
+		return maxVersion
+	}
+	return c.MaxVersion
+}
+
+var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
+
+func (c *Config) curvePreferences() []CurveID {
+	if c == nil || len(c.CurvePreferences) == 0 {
+		return defaultCurvePreferences
+	}
+	return c.CurvePreferences
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// version of the peer using the legacy non-extension methods.
+func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
+	minVersion := c.minVersion()
+	maxVersion := c.maxVersion()
+
+	// Version 1.3 and higher are not negotiated via this mechanism.
+	if maxVersion > VersionTLS12 {
+		maxVersion = VersionTLS12
+	}
+
+	if vers < minVersion {
+		return 0, false
+	}
+	if vers > maxVersion {
+		vers = maxVersion
+	}
+	return vers, true
+}
+
+// pickVersion returns the protocol version to use given the advertised
+// versions of the peer using the Supported Versions extension.
+func (c *Config) pickVersion(peerSupportedVersions []uint16) (uint16, bool) {
+	supportedVersions := c.getSupportedVersions()
+	for _, supportedVersion := range supportedVersions {
+		for _, version := range peerSupportedVersions {
+			if version == supportedVersion {
+				return version, true
+			}
+		}
+	}
+	return 0, false
+}
+
+// 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 {
+	minVersion := c.minVersion()
+	maxVersion := c.maxVersion()
+	// Sanity check to avoid advertising unsupported versions.
+	if minVersion < VersionSSL30 {
+		minVersion = VersionSSL30
+	}
+	if maxVersion > VersionTLS13 {
+		maxVersion = VersionTLS13
+	}
+	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]
+}
+
+// getCertificate returns the best certificate for the given ClientHelloInfo,
+// defaulting to the first element of c.Certificates.
+func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
+	if c.GetCertificate != nil &&
+		(len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
+		cert, err := c.GetCertificate(clientHello)
+		if cert != nil || err != nil {
+			return cert, err
+		}
+	}
+
+	if len(c.Certificates) == 0 {
+		return nil, errors.New("tls: no certificates configured")
+	}
+
+	if len(c.Certificates) == 1 || c.NameToCertificate == nil {
+		// There's only one choice, so no point doing any work.
+		return &c.Certificates[0], nil
+	}
+
+	name := strings.ToLower(clientHello.ServerName)
+	for len(name) > 0 && name[len(name)-1] == '.' {
+		name = name[:len(name)-1]
+	}
+
+	if cert, ok := c.NameToCertificate[name]; ok {
+		return cert, nil
+	}
+
+	// try replacing labels in the name with wildcards until we get a
+	// match.
+	labels := strings.Split(name, ".")
+	for i := range labels {
+		labels[i] = "*"
+		candidate := strings.Join(labels, ".")
+		if cert, ok := c.NameToCertificate[candidate]; ok {
+			return cert, nil
+		}
+	}
+
+	// If nothing matches, return the first certificate.
+	return &c.Certificates[0], nil
+}
+
+// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
+// from the CommonName and SubjectAlternateName fields of each of the leaf
+// certificates.
+func (c *Config) BuildNameToCertificate() {
+	c.NameToCertificate = make(map[string]*Certificate)
+	for i := range c.Certificates {
+		cert := &c.Certificates[i]
+		x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+		if err != nil {
+			continue
+		}
+		if len(x509Cert.Subject.CommonName) > 0 {
+			c.NameToCertificate[x509Cert.Subject.CommonName] = cert
+		}
+		for _, san := range x509Cert.DNSNames {
+			c.NameToCertificate[san] = cert
+		}
+	}
+}
+
+// writeKeyLog logs client random and master secret if logging was enabled by
+// setting c.KeyLogWriter.
+func (c *Config) writeKeyLog(what string, clientRandom, masterSecret []byte) error {
+	if c.KeyLogWriter == nil {
+		return nil
+	}
+
+	logLine := []byte(fmt.Sprintf("%s %x %x\n", what, clientRandom, masterSecret))
+
+	writerMutex.Lock()
+	_, err := c.KeyLogWriter.Write(logLine)
+	writerMutex.Unlock()
+
+	return err
+}
+
+// writerMutex protects all KeyLogWriters globally. It is rarely enabled,
+// and is only for debugging, so a global mutex saves space.
+var writerMutex sync.Mutex
+
+// A Certificate is a chain of one or more certificates, leaf first.
+type Certificate struct {
+	Certificate [][]byte
+	// PrivateKey contains the private key corresponding to the public key
+	// in Leaf. For a server, this must implement crypto.Signer and/or
+	// crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client
+	// (performing client authentication), this must be a crypto.Signer
+	// with an RSA or ECDSA PublicKey.
+	PrivateKey crypto.PrivateKey
+	// OCSPStaple contains an optional OCSP response which will be served
+	// to clients that request it.
+	OCSPStaple []byte
+	// SignedCertificateTimestamps contains an optional list of Signed
+	// Certificate Timestamps which will be served to clients that request it.
+	SignedCertificateTimestamps [][]byte
+	// Leaf is the parsed form of the leaf certificate, which may be
+	// initialized using x509.ParseCertificate to reduce per-handshake
+	// processing for TLS clients doing client authentication. If nil, the
+	// leaf certificate will be parsed as needed.
+	Leaf *x509.Certificate
+}
+
+type handshakeMessage interface {
+	marshal() []byte
+	unmarshal([]byte) alert
+}
+
+// lruSessionCache is a ClientSessionCache implementation that uses an LRU
+// caching strategy.
+type lruSessionCache struct {
+	sync.Mutex
+
+	m        map[string]*list.Element
+	q        *list.List
+	capacity int
+}
+
+type lruSessionCacheEntry struct {
+	sessionKey string
+	state      *ClientSessionState
+}
+
+// NewLRUClientSessionCache returns a ClientSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+	const defaultSessionCacheCapacity = 64
+
+	if capacity < 1 {
+		capacity = defaultSessionCacheCapacity
+	}
+	return &lruSessionCache{
+		m:        make(map[string]*list.Element),
+		q:        list.New(),
+		capacity: capacity,
+	}
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache.
+func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+	c.Lock()
+	defer c.Unlock()
+
+	if elem, ok := c.m[sessionKey]; ok {
+		entry := elem.Value.(*lruSessionCacheEntry)
+		entry.state = cs
+		c.q.MoveToFront(elem)
+		return
+	}
+
+	if c.q.Len() < c.capacity {
+		entry := &lruSessionCacheEntry{sessionKey, cs}
+		c.m[sessionKey] = c.q.PushFront(entry)
+		return
+	}
+
+	elem := c.q.Back()
+	entry := elem.Value.(*lruSessionCacheEntry)
+	delete(c.m, entry.sessionKey)
+	entry.sessionKey = sessionKey
+	entry.state = cs
+	c.q.MoveToFront(elem)
+	c.m[sessionKey] = elem
+}
+
+// Get returns the ClientSessionState value associated with a given key. It
+// returns (nil, false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+	c.Lock()
+	defer c.Unlock()
+
+	if elem, ok := c.m[sessionKey]; ok {
+		c.q.MoveToFront(elem)
+		return elem.Value.(*lruSessionCacheEntry).state, true
+	}
+	return nil, false
+}
+
+// TODO(jsing): Make these available to both crypto/x509 and crypto/tls.
+type dsaSignature struct {
+	R, S *big.Int
+}
+
+type ecdsaSignature dsaSignature
+
+var emptyConfig Config
+
+func defaultConfig() *Config {
+	return &emptyConfig
+}
+
+var (
+	once                        sync.Once
+	varDefaultCipherSuites      []uint16
+	varDefaultTLS13CipherSuites []uint16
+)
+
+func defaultCipherSuites() []uint16 {
+	once.Do(initDefaultCipherSuites)
+	return varDefaultCipherSuites
+}
+
+func defaultTLS13CipherSuites() []uint16 {
+	once.Do(initDefaultCipherSuites)
+	return varDefaultTLS13CipherSuites
+}
+
+func initDefaultCipherSuites() {
+	var topCipherSuites, topTLS13CipherSuites []uint16
+	if cipherhw.AESGCMSupport() {
+		// If AES-GCM hardware is provided then prioritise AES-GCM
+		// cipher suites.
+		topTLS13CipherSuites = []uint16{
+			TLS_AES_128_GCM_SHA256,
+			TLS_AES_256_GCM_SHA384,
+			TLS_CHACHA20_POLY1305_SHA256,
+		}
+		topCipherSuites = []uint16{
+			TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+			TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+			TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+			TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+			TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+			TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+		}
+	} else {
+		// Without AES-GCM hardware, we put the ChaCha20-Poly1305
+		// cipher suites first.
+		topTLS13CipherSuites = []uint16{
+			TLS_CHACHA20_POLY1305_SHA256,
+			TLS_AES_128_GCM_SHA256,
+			TLS_AES_256_GCM_SHA384,
+		}
+		topCipherSuites = []uint16{
+			TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+			TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+			TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+			TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+			TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+			TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+		}
+	}
+
+	varDefaultTLS13CipherSuites = make([]uint16, 0, len(cipherSuites))
+	varDefaultTLS13CipherSuites = append(varDefaultTLS13CipherSuites, topTLS13CipherSuites...)
+	varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
+	varDefaultCipherSuites = append(varDefaultCipherSuites, topCipherSuites...)
+
+NextCipherSuite:
+	for _, suite := range cipherSuites {
+		if suite.flags&suiteDefaultOff != 0 {
+			continue
+		}
+		if suite.flags&suiteTLS13 != 0 {
+			for _, existing := range varDefaultTLS13CipherSuites {
+				if existing == suite.id {
+					continue NextCipherSuite
+				}
+			}
+			varDefaultTLS13CipherSuites = append(varDefaultTLS13CipherSuites, suite.id)
+		} else {
+			for _, existing := range varDefaultCipherSuites {
+				if existing == suite.id {
+					continue NextCipherSuite
+				}
+			}
+			varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
+		}
+	}
+	varDefaultCipherSuites = append(varDefaultTLS13CipherSuites, varDefaultCipherSuites...)
+}
+
+func unexpectedMessageError(wanted, got interface{}) error {
+	return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
+}
+
+func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool {
+	for _, s := range supportedSignatureAlgorithms {
+		if s == sigAlg {
+			return true
+		}
+	}
+	return false
+}
+
+// signatureFromSignatureScheme maps a signature algorithm to the underlying
+// signature method (without hash function).
+func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 {
+	switch signatureAlgorithm {
+	case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
+		return signaturePKCS1v15
+	case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
+		return signatureRSAPSS
+	case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
+		return signatureECDSA
+	default:
+		return 0
+	}
+}
+
+// TODO(kk): Use variable length encoding?
+func getUint24(b []byte) int {
+	n := int(b[2])
+	n += int(b[1] << 8)
+	n += int(b[0] << 16)
+	return n
+}
+
+func putUint24(b []byte, n int) {
+	b[0] = byte(n >> 16)
+	b[1] = byte(n >> 8)
+	b[2] = byte(n & 0xff)
+}

+ 1725 - 0
vendor/github.com/Psiphon-Labs/tls-tris/conn.go

@@ -0,0 +1,1725 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TLS low level connection and record layer
+
+package tls
+
+import (
+	"bytes"
+	"crypto/cipher"
+	"crypto/subtle"
+	"crypto/x509"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+	// constant
+	conn     net.Conn
+	isClient bool
+
+	phase handshakeStatus // protected by in.Mutex
+	// handshakeConfirmed is an atomic bool for phase == handshakeConfirmed
+	handshakeConfirmed int32
+	// confirmMutex is held by any read operation before handshakeConfirmed
+	confirmMutex sync.Mutex
+
+	// constant after handshake; protected by handshakeMutex
+	handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+	handshakeErr   error      // error resulting from handshake
+	connID         []byte     // Random connection id
+	clientHello    []byte     // ClientHello packet contents
+	vers           uint16     // TLS version
+	haveVers       bool       // version has been negotiated
+	config         *Config    // configuration passed to constructor
+	// handshakeComplete is true if the connection reached application data
+	// and it's equivalent to phase > handshakeRunning
+	handshakeComplete bool
+	// handshakes counts the number of handshakes performed on the
+	// connection so far. If renegotiation is disabled then this is either
+	// zero or one.
+	handshakes       int
+	didResume        bool // whether this connection was a session resumption
+	cipherSuite      uint16
+	ocspResponse     []byte   // stapled OCSP response
+	scts             [][]byte // Signed certificate timestamps from server
+	peerCertificates []*x509.Certificate
+	// verifiedChains contains the certificate chains that we built, as
+	// opposed to the ones presented by the server.
+	verifiedChains [][]*x509.Certificate
+	// verifiedDc is set by a client who negotiates the use of a valid delegated
+	// credential.
+	verifiedDc *delegatedCredential
+	// serverName contains the server name indicated by the client, if any.
+	serverName string
+	// secureRenegotiation is true if the server echoed the secure
+	// renegotiation extension. (This is meaningless as a server because
+	// renegotiation is not supported in that case.)
+	secureRenegotiation bool
+
+	// clientFinishedIsFirst is true if the client sent the first Finished
+	// message during the most recent handshake. This is recorded because
+	// the first transmitted Finished message is the tls-unique
+	// channel-binding value.
+	clientFinishedIsFirst bool
+
+	// closeNotifyErr is any error from sending the alertCloseNotify record.
+	closeNotifyErr error
+	// closeNotifySent is true if the Conn attempted to send an
+	// alertCloseNotify record.
+	closeNotifySent bool
+
+	// clientFinished and serverFinished contain the Finished message sent
+	// by the client or server in the most recent handshake. This is
+	// retained to support the renegotiation extension and tls-unique
+	// channel-binding.
+	clientFinished [12]byte
+	serverFinished [12]byte
+
+	clientProtocol         string
+	clientProtocolFallback bool
+
+	// ticketMaxEarlyData is the maximum bytes of 0-RTT application data
+	// that the client is allowed to send on the ticket it used.
+	ticketMaxEarlyData int64
+
+	// input/output
+	in, out   halfConn     // in.Mutex < out.Mutex
+	rawInput  *block       // raw input, right off the wire
+	input     *block       // application data waiting to be read
+	hand      bytes.Buffer // handshake data waiting to be read
+	buffering bool         // whether records are buffered in sendBuf
+	sendBuf   []byte       // a buffer of records waiting to be sent
+
+	// bytesSent counts the bytes of application data sent.
+	// packetsSent counts packets.
+	bytesSent   int64
+	packetsSent int64
+
+	// warnCount counts the number of consecutive warning alerts received
+	// by Conn.readRecord. Protected by in.Mutex.
+	warnCount int
+
+	// activeCall is an atomic int32; the low bit is whether Close has
+	// been called. the rest of the bits are the number of goroutines
+	// in Conn.Write.
+	activeCall int32
+
+	// TLS 1.3 needs the server state until it reaches the Client Finished
+	hs *serverHandshakeState
+
+	// earlyDataBytes is the number of bytes of early data received so
+	// far. Tracked to enforce max_early_data_size.
+	// We don't keep track of rejected 0-RTT data since there's no need
+	// to ever buffer it. in.Mutex.
+	earlyDataBytes int64
+
+	// binder is the value of the PSK binder that was validated to
+	// accept the 0-RTT data. Exposed as ConnectionState.Unique0RTTToken.
+	binder []byte
+
+	tmp [16]byte
+}
+
+type handshakeStatus int
+
+const (
+	handshakeRunning handshakeStatus = iota
+	discardingEarlyData
+	readingEarlyData
+	waitingClientFinished
+	readingClientFinished
+	handshakeConfirmed
+)
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+	return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+	return c.conn.RemoteAddr()
+}
+
+// SetDeadline sets the read and write deadlines associated with the connection.
+// A zero value for t means Read and Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetDeadline(t time.Time) error {
+	return c.conn.SetDeadline(t)
+}
+
+// SetReadDeadline sets the read deadline on the underlying connection.
+// A zero value for t means Read will not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+	return c.conn.SetReadDeadline(t)
+}
+
+// SetWriteDeadline sets the write deadline on the underlying connection.
+// A zero value for t means Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+	return c.conn.SetWriteDeadline(t)
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+	sync.Mutex
+
+	err            error       // first permanent error
+	version        uint16      // protocol version
+	cipher         interface{} // cipher algorithm
+	mac            macFunction
+	seq            [8]byte  // 64-bit sequence number
+	bfree          *block   // list of free blocks
+	additionalData [13]byte // to avoid allocs; interface method args escape
+
+	nextCipher interface{} // next encryption state
+	nextMac    macFunction // next MAC algorithm
+
+	// used to save allocating a new buffer for each MAC.
+	inDigestBuf, outDigestBuf []byte
+
+	traceErr func(error)
+}
+
+func (hc *halfConn) setErrorLocked(err error) error {
+	hc.err = err
+	if hc.traceErr != nil {
+		hc.traceErr(err)
+	}
+	return err
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
+	hc.version = version
+	hc.nextCipher = cipher
+	hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec() error {
+	if hc.nextCipher == nil {
+		return alertInternalError
+	}
+	hc.cipher = hc.nextCipher
+	hc.mac = hc.nextMac
+	hc.nextCipher = nil
+	hc.nextMac = nil
+	for i := range hc.seq {
+		hc.seq[i] = 0
+	}
+	return nil
+}
+
+func (hc *halfConn) setCipher(version uint16, cipher interface{}) {
+	hc.version = version
+	hc.cipher = cipher
+	for i := range hc.seq {
+		hc.seq[i] = 0
+	}
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq() {
+	for i := 7; i >= 0; i-- {
+		hc.seq[i]++
+		if hc.seq[i] != 0 {
+			return
+		}
+	}
+
+	// Not allowed to let sequence number wrap.
+	// Instead, must renegotiate before it does.
+	// Not likely enough to bother.
+	panic("TLS: sequence number wraparound")
+}
+
+// extractPadding returns, in constant time, the length of the padding to remove
+// from the end of payload. It also returns a byte which is equal to 255 if the
+// padding was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func extractPadding(payload []byte) (toRemove int, good byte) {
+	if len(payload) < 1 {
+		return 0, 0
+	}
+
+	paddingLen := payload[len(payload)-1]
+	t := uint(len(payload)-1) - uint(paddingLen)
+	// if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+	good = byte(int32(^t) >> 31)
+
+	// The maximum possible padding length plus the actual length field
+	toCheck := 256
+	// The length of the padded data is public, so we can use an if here
+	if toCheck > len(payload) {
+		toCheck = len(payload)
+	}
+
+	for i := 0; i < toCheck; i++ {
+		t := uint(paddingLen) - uint(i)
+		// if i <= paddingLen then the MSB of t is zero
+		mask := byte(int32(^t) >> 31)
+		b := payload[len(payload)-1-i]
+		good &^= mask&paddingLen ^ mask&b
+	}
+
+	// We AND together the bits of good and replicate the result across
+	// all the bits.
+	good &= good << 4
+	good &= good << 2
+	good &= good << 1
+	good = uint8(int8(good) >> 7)
+
+	toRemove = int(paddingLen) + 1
+	return
+}
+
+// extractPaddingSSL30 is a replacement for extractPadding in the case that the
+// protocol version is SSLv3. In this version, the contents of the padding
+// are random and cannot be checked.
+func extractPaddingSSL30(payload []byte) (toRemove int, good byte) {
+	if len(payload) < 1 {
+		return 0, 0
+	}
+
+	paddingLen := int(payload[len(payload)-1]) + 1
+	if paddingLen > len(payload) {
+		return 0, 0
+	}
+
+	return paddingLen, 255
+}
+
+func roundUp(a, b int) int {
+	return a + (b-a%b)%b
+}
+
+// cbcMode is an interface for block ciphers using cipher block chaining.
+type cbcMode interface {
+	cipher.BlockMode
+	SetIV([]byte)
+}
+
+// decrypt checks and strips the mac and decrypts the data in b. Returns a
+// success boolean, the number of bytes to skip from the start of the record in
+// order to get the application payload, and an optional alert value.
+func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) {
+	// pull out payload
+	payload := b.data[recordHeaderLen:]
+
+	macSize := 0
+	if hc.mac != nil {
+		macSize = hc.mac.Size()
+	}
+
+	paddingGood := byte(255)
+	paddingLen := 0
+	explicitIVLen := 0
+
+	// decrypt
+	if hc.cipher != nil {
+		switch c := hc.cipher.(type) {
+		case cipher.Stream:
+			c.XORKeyStream(payload, payload)
+		case aead:
+			explicitIVLen = c.explicitNonceLen()
+			if len(payload) < explicitIVLen {
+				return false, 0, alertBadRecordMAC
+			}
+			nonce := payload[:explicitIVLen]
+			payload = payload[explicitIVLen:]
+
+			if len(nonce) == 0 {
+				nonce = hc.seq[:]
+			}
+
+			var additionalData []byte
+			if hc.version < VersionTLS13 {
+				copy(hc.additionalData[:], hc.seq[:])
+				copy(hc.additionalData[8:], b.data[:3])
+				n := len(payload) - c.Overhead()
+				hc.additionalData[11] = byte(n >> 8)
+				hc.additionalData[12] = byte(n)
+				additionalData = hc.additionalData[:]
+			} else {
+				if len(payload) > int((1<<14)+256) {
+					return false, 0, alertRecordOverflow
+				}
+				// Check AD header, see 5.2 of RFC8446
+				additionalData = make([]byte, 5)
+				additionalData[0] = byte(recordTypeApplicationData)
+				binary.BigEndian.PutUint16(additionalData[1:], VersionTLS12)
+				binary.BigEndian.PutUint16(additionalData[3:], uint16(len(payload)))
+			}
+			var err error
+			payload, err = c.Open(payload[:0], nonce, payload, additionalData)
+			if err != nil {
+				return false, 0, alertBadRecordMAC
+			}
+			b.resize(recordHeaderLen + explicitIVLen + len(payload))
+		case cbcMode:
+			blockSize := c.BlockSize()
+			if hc.version >= VersionTLS11 {
+				explicitIVLen = blockSize
+			}
+
+			if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) {
+				return false, 0, alertBadRecordMAC
+			}
+
+			if explicitIVLen > 0 {
+				c.SetIV(payload[:explicitIVLen])
+				payload = payload[explicitIVLen:]
+			}
+			c.CryptBlocks(payload, payload)
+			if hc.version == VersionSSL30 {
+				paddingLen, paddingGood = extractPaddingSSL30(payload)
+			} else {
+				paddingLen, paddingGood = extractPadding(payload)
+
+				// To protect against CBC padding oracles like Lucky13, the data
+				// past paddingLen (which is secret) is passed to the MAC
+				// function as extra data, to be fed into the HMAC after
+				// computing the digest. This makes the MAC constant time as
+				// long as the digest computation is constant time and does not
+				// affect the subsequent write.
+			}
+		default:
+			panic("unknown cipher type")
+		}
+	}
+
+	// check, strip mac
+	if hc.mac != nil {
+		if len(payload) < macSize {
+			return false, 0, alertBadRecordMAC
+		}
+
+		// strip mac off payload, b.data
+		n := len(payload) - macSize - paddingLen
+		n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 }
+		b.data[3] = byte(n >> 8)
+		b.data[4] = byte(n)
+		remoteMAC := payload[n : n+macSize]
+		localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n], payload[n+macSize:])
+
+		if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
+			return false, 0, alertBadRecordMAC
+		}
+		hc.inDigestBuf = localMAC
+
+		b.resize(recordHeaderLen + explicitIVLen + n)
+	}
+	hc.incSeq()
+
+	return true, recordHeaderLen + explicitIVLen, 0
+}
+
+// padToBlockSize calculates the needed padding block, if any, for a payload.
+// On exit, prefix aliases payload and extends to the end of the last full
+// block of payload. finalBlock is a fresh slice which contains the contents of
+// any suffix of payload as well as the needed padding to make finalBlock a
+// full block.
+func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
+	overrun := len(payload) % blockSize
+	paddingLen := blockSize - overrun
+	prefix = payload[:len(payload)-overrun]
+	finalBlock = make([]byte, blockSize)
+	copy(finalBlock, payload[len(payload)-overrun:])
+	for i := overrun; i < blockSize; i++ {
+		finalBlock[i] = byte(paddingLen - 1)
+	}
+	return
+}
+
+// encrypt encrypts and macs the data in b.
+func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
+	// mac
+	if hc.mac != nil {
+		mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:], nil)
+
+		n := len(b.data)
+		b.resize(n + len(mac))
+		copy(b.data[n:], mac)
+		hc.outDigestBuf = mac
+	}
+
+	payload := b.data[recordHeaderLen:]
+
+	// encrypt
+	if hc.cipher != nil {
+		switch c := hc.cipher.(type) {
+		case cipher.Stream:
+			c.XORKeyStream(payload, payload)
+		case aead:
+			// explicitIVLen is always 0 for TLS1.3
+			payloadLen := len(b.data) - 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 {
+				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 {
+				// 1 byte of content type is appended to payload and encrypted
+				payload = append(payload, b.data[0])
+
+				// opaque_type
+				b.data[0] = byte(recordTypeApplicationData)
+
+				// Add AD header, see 5.2 of RFC8446
+				additionalData = make([]byte, 5)
+				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:
+			blockSize := c.BlockSize()
+			if explicitIVLen > 0 {
+				c.SetIV(payload[:explicitIVLen])
+				payload = payload[explicitIVLen:]
+			}
+			prefix, finalBlock := padToBlockSize(payload, blockSize)
+			b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock))
+			c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix)
+			c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock)
+		default:
+			panic("unknown cipher type")
+		}
+	}
+
+	// update length to include MAC and any block padding needed.
+	n := len(b.data) - recordHeaderLen
+	b.data[3] = byte(n >> 8)
+	b.data[4] = byte(n)
+	hc.incSeq()
+
+	return true, 0
+}
+
+// A block is a simple data buffer.
+type block struct {
+	data []byte
+	off  int // index for Read
+	link *block
+}
+
+// resize resizes block to be n bytes, growing if necessary.
+func (b *block) resize(n int) {
+	if n > cap(b.data) {
+		b.reserve(n)
+	}
+	b.data = b.data[0:n]
+}
+
+// reserve makes sure that block contains a capacity of at least n bytes.
+func (b *block) reserve(n int) {
+	if cap(b.data) >= n {
+		return
+	}
+	m := cap(b.data)
+	if m == 0 {
+		m = 1024
+	}
+	for m < n {
+		m *= 2
+	}
+	data := make([]byte, len(b.data), m)
+	copy(data, b.data)
+	b.data = data
+}
+
+// readFromUntil reads from r into b until b contains at least n bytes
+// or else returns an error.
+func (b *block) readFromUntil(r io.Reader, n int) error {
+	// quick case
+	if len(b.data) >= n {
+		return nil
+	}
+
+	// read until have enough.
+	b.reserve(n)
+	for {
+		m, err := r.Read(b.data[len(b.data):cap(b.data)])
+		b.data = b.data[0 : len(b.data)+m]
+		if len(b.data) >= n {
+			// TODO(bradfitz,agl): slightly suspicious
+			// that we're throwing away r.Read's err here.
+			break
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (b *block) Read(p []byte) (n int, err error) {
+	n = copy(p, b.data[b.off:])
+	b.off += n
+	if b.off >= len(b.data) {
+		err = io.EOF
+	}
+	return
+}
+
+// newBlock allocates a new block, from hc's free list if possible.
+func (hc *halfConn) newBlock() *block {
+	b := hc.bfree
+	if b == nil {
+		return new(block)
+	}
+	hc.bfree = b.link
+	b.link = nil
+	b.resize(0)
+	return b
+}
+
+// freeBlock returns a block to hc's free list.
+// The protocol is such that each side only has a block or two on
+// its free list at a time, so there's no need to worry about
+// trimming the list, etc.
+func (hc *halfConn) freeBlock(b *block) {
+	b.link = hc.bfree
+	hc.bfree = b
+}
+
+// splitBlock splits a block after the first n bytes,
+// returning a block with those n bytes and a
+// block with the remainder.  the latter may be nil.
+func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
+	if len(b.data) <= n {
+		return b, nil
+	}
+	bb := hc.newBlock()
+	bb.resize(len(b.data) - n)
+	copy(bb.data, b.data[n:])
+	b.data = b.data[0:n]
+	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.
+// c.input can still be nil after a call, retry if so.
+func (c *Conn) readRecord(want recordType) error {
+	// Caller must be in sync with connection:
+	// handshake data if handshake not yet completed,
+	// else application data.
+	switch want {
+	default:
+		c.sendAlert(alertInternalError)
+		return c.in.setErrorLocked(errors.New("tls: unknown record type requested"))
+	case recordTypeHandshake, recordTypeChangeCipherSpec:
+		if c.phase != handshakeRunning && c.phase != readingClientFinished {
+			c.sendAlert(alertInternalError)
+			return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested while not in handshake"))
+		}
+	case recordTypeApplicationData:
+		if c.phase == handshakeRunning || c.phase == readingClientFinished {
+			c.sendAlert(alertInternalError)
+			return c.in.setErrorLocked(errors.New("tls: application data record requested while in handshake"))
+		}
+	}
+
+Again:
+	if c.rawInput == nil {
+		c.rawInput = c.in.newBlock()
+	}
+	b := c.rawInput
+
+	// Read header, payload.
+	if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil {
+		// RFC suggests that EOF without an alertCloseNotify is
+		// an error, but popular web sites seem to do this,
+		// so we can't make it an error.
+		// if err == io.EOF {
+		// 	err = io.ErrUnexpectedEOF
+		// }
+		if e, ok := err.(net.Error); !ok || !e.Temporary() {
+			c.in.setErrorLocked(err)
+		}
+		return err
+	}
+	typ := recordType(b.data[0])
+
+	// No valid TLS record has a type of 0x80, however SSLv2 handshakes
+	// start with a uint16 length where the MSB is set and the first record
+	// is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+	// an SSLv2 client.
+	if want == recordTypeHandshake && typ == 0x80 {
+		c.sendAlert(alertProtocolVersion)
+		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 n > maxCiphertext {
+		c.sendAlert(alertRecordOverflow)
+		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
+		// client. Bail out before reading a full 'body', if possible.
+		// The current max version is 3.3 so if the version is >= 16.0,
+		// it's probably not real.
+		if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 {
+			c.sendAlert(alertUnexpectedMessage)
+			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 {
+		if err == io.EOF {
+			err = io.ErrUnexpectedEOF
+		}
+		if e, ok := err.(net.Error); !ok || !e.Temporary() {
+			c.in.setErrorLocked(err)
+		}
+		return err
+	}
+
+	// Process message.
+	b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
+
+	// TLS 1.3 middlebox compatibility: skip over unencrypted CCS.
+	if c.vers >= VersionTLS13 && typ == recordTypeChangeCipherSpec && c.phase != handshakeConfirmed {
+		if len(b.data) != 6 || b.data[5] != 1 {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		c.in.freeBlock(b)
+		return c.in.err
+	}
+
+	peekedAlert := peekAlert(b) // peek at a possible alert before decryption
+	ok, off, alertValue := c.in.decrypt(b)
+	switch {
+	case !ok && c.phase == discardingEarlyData:
+		// If the client said that it's sending early data and we did not
+		// accept it, we are expected to fail decryption.
+		c.in.freeBlock(b)
+		return nil
+	case ok && c.phase == discardingEarlyData:
+		c.phase = waitingClientFinished
+	case !ok:
+		c.in.traceErr, c.out.traceErr = nil, nil // not that interesting
+		c.in.freeBlock(b)
+		err := c.sendAlert(alertValue)
+		// If decryption failed because the message is an unencrypted
+		// alert, return a more meaningful error message
+		if alertValue == alertBadRecordMAC && peekedAlert != nil {
+			err = peekedAlert
+		}
+		return c.in.setErrorLocked(err)
+	}
+	b.off = off
+	data := b.data[b.off:]
+	if (c.vers < VersionTLS13 && len(data) > maxPlaintext) || len(data) > maxPlaintext+1 {
+		c.in.freeBlock(b)
+		return c.in.setErrorLocked(c.sendAlert(alertRecordOverflow))
+	}
+
+	// After checking the plaintext length, remove 1.3 padding and
+	// extract the real content type.
+	// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-5.4.
+	if c.vers >= VersionTLS13 {
+		i := len(data) - 1
+		for i >= 0 {
+			if data[i] != 0 {
+				break
+			}
+			i--
+		}
+		if i < 0 {
+			c.in.freeBlock(b)
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		typ = recordType(data[i])
+		data = data[:i]
+		b.resize(b.off + i) // shrinks, guaranteed not to reallocate
+	}
+
+	if typ != recordTypeAlert && len(data) > 0 {
+		// this is a valid non-alert message: reset the count of alerts
+		c.warnCount = 0
+	}
+
+	switch typ {
+	default:
+		c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+
+	case recordTypeAlert:
+		if len(data) != 2 {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			break
+		}
+		if alert(data[1]) == alertCloseNotify {
+			c.in.setErrorLocked(io.EOF)
+			break
+		}
+		switch data[0] {
+		case alertLevelWarning:
+			// drop on the floor
+			c.in.freeBlock(b)
+
+			c.warnCount++
+			if c.warnCount > maxWarnAlertCount {
+				c.sendAlert(alertUnexpectedMessage)
+				return c.in.setErrorLocked(errors.New("tls: too many warn alerts"))
+			}
+
+			goto Again
+		case alertLevelError:
+			c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+		default:
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+
+	case recordTypeChangeCipherSpec:
+		if typ != want || len(data) != 1 || data[0] != 1 || c.vers >= VersionTLS13 {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			break
+		}
+		// Handshake messages are not allowed to fragment across the CCS
+		if c.hand.Len() > 0 {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			break
+		}
+		// Handshake messages are not allowed to fragment across the CCS
+		if c.hand.Len() > 0 {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			break
+		}
+		err := c.in.changeCipherSpec()
+		if err != nil {
+			c.in.setErrorLocked(c.sendAlert(err.(alert)))
+		}
+
+	case recordTypeApplicationData:
+		if typ != want || c.phase == waitingClientFinished {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			break
+		}
+		if c.phase == readingEarlyData {
+			c.earlyDataBytes += int64(len(b.data) - b.off)
+			if c.earlyDataBytes > c.ticketMaxEarlyData {
+				return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			}
+		}
+		c.input = b
+		b = nil
+
+	case recordTypeHandshake:
+		// TODO(rsc): Should at least pick off connection close.
+		// If early data was being read, a Finished message is expected
+		// instead of (early) application data. Other post-handshake
+		// messages include HelloRequest and NewSessionTicket.
+		if typ != want && want != recordTypeApplicationData {
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		c.hand.Write(data)
+	}
+
+	if b != nil {
+		c.in.freeBlock(b)
+	}
+	return c.in.err
+}
+
+// peekAlert looks at a message to spot an unencrypted alert. It must be
+// called before decryption to avoid a side channel, and its result must
+// only be used if decryption fails, to avoid false positives.
+func peekAlert(b *block) error {
+	if len(b.data) < 7 {
+		return nil
+	}
+	if recordType(b.data[0]) != recordTypeAlert {
+		return nil
+	}
+	return &net.OpError{Op: "remote error", Err: alert(b.data[6])}
+}
+
+// sendAlert sends a TLS alert message.
+// c.out.Mutex <= L.
+func (c *Conn) sendAlertLocked(err alert) error {
+	switch err {
+	case alertNoRenegotiation, alertCloseNotify:
+		c.tmp[0] = alertLevelWarning
+	default:
+		c.tmp[0] = alertLevelError
+	}
+	c.tmp[1] = byte(err)
+
+	_, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2])
+	if err == alertCloseNotify {
+		// closeNotify is a special case in that it isn't an error.
+		return writeErr
+	}
+
+	return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+}
+
+// sendAlert sends a TLS alert message.
+// L < c.out.Mutex.
+func (c *Conn) sendAlert(err alert) error {
+	c.out.Lock()
+	defer c.out.Unlock()
+	return c.sendAlertLocked(err)
+}
+
+const (
+	// tcpMSSEstimate is a conservative estimate of the TCP maximum segment
+	// size (MSS). A constant is used, rather than querying the kernel for
+	// the actual MSS, to avoid complexity. The value here is the IPv6
+	// minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
+	// bytes) and a TCP header with timestamps (32 bytes).
+	tcpMSSEstimate = 1208
+
+	// recordSizeBoostThreshold is the number of bytes of application data
+	// sent after which the TLS record size will be increased to the
+	// maximum.
+	recordSizeBoostThreshold = 128 * 1024
+)
+
+// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the
+// next application data record. There is the following trade-off:
+//
+//   - For latency-sensitive applications, such as web browsing, each TLS
+//     record should fit in one TCP segment.
+//   - For throughput-sensitive applications, such as large file transfers,
+//     larger TLS records better amortize framing and encryption overheads.
+//
+// A simple heuristic that works well in practice is to use small records for
+// the first 1MB of data, then use larger records for subsequent data, and
+// reset back to smaller records after the connection becomes idle. See "High
+// Performance Web Networking", Chapter 4, or:
+// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/
+//
+// In the interests of simplicity and determinism, this code does not attempt
+// to reset the record size once the connection is idle, however.
+//
+// c.out.Mutex <= L.
+func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int {
+	if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData {
+		return maxPlaintext
+	}
+
+	if c.bytesSent >= recordSizeBoostThreshold {
+		return maxPlaintext
+	}
+
+	// Subtract TLS overheads to get the maximum payload size.
+	macSize := 0
+	if c.out.mac != nil {
+		macSize = c.out.mac.Size()
+	}
+
+	payloadBytes := tcpMSSEstimate - recordHeaderLen - explicitIVLen
+	if c.out.cipher != nil {
+		switch ciph := c.out.cipher.(type) {
+		case cipher.Stream:
+			payloadBytes -= macSize
+		case cipher.AEAD:
+			payloadBytes -= ciph.Overhead()
+			if c.vers >= VersionTLS13 {
+				payloadBytes -= 1 // ContentType
+			}
+		case cbcMode:
+			blockSize := ciph.BlockSize()
+			// The payload must fit in a multiple of blockSize, with
+			// room for at least one padding byte.
+			payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
+			// The MAC is appended before padding so affects the
+			// payload size directly.
+			payloadBytes -= macSize
+		default:
+			panic("unknown cipher type")
+		}
+	}
+
+	// Allow packet growth in arithmetic progression up to max.
+	pkt := c.packetsSent
+	c.packetsSent++
+	if pkt > 1000 {
+		return maxPlaintext // avoid overflow in multiply below
+	}
+
+	n := payloadBytes * int(pkt+1)
+	if n > maxPlaintext {
+		n = maxPlaintext
+	}
+	return n
+}
+
+// c.out.Mutex <= L.
+func (c *Conn) write(data []byte) (int, error) {
+	if c.buffering {
+		c.sendBuf = append(c.sendBuf, data...)
+		return len(data), nil
+	}
+
+	n, err := c.conn.Write(data)
+	c.bytesSent += int64(n)
+	return n, err
+}
+
+func (c *Conn) flush() (int, error) {
+	if len(c.sendBuf) == 0 {
+		return 0, nil
+	}
+
+	n, err := c.conn.Write(c.sendBuf)
+	c.bytesSent += int64(n)
+	c.sendBuf = nil
+	c.buffering = false
+	return n, err
+}
+
+// writeRecordLocked writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+// c.out.Mutex <= L.
+func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
+	b := c.out.newBlock()
+	defer c.out.freeBlock(b)
+
+	var n int
+	for len(data) > 0 {
+		explicitIVLen := 0
+		explicitIVIsSeq := false
+
+		var cbc cbcMode
+		if c.out.version >= VersionTLS11 {
+			var ok bool
+			if cbc, ok = c.out.cipher.(cbcMode); ok {
+				explicitIVLen = cbc.BlockSize()
+			}
+		}
+		if explicitIVLen == 0 {
+			if c, ok := c.out.cipher.(aead); ok {
+				explicitIVLen = c.explicitNonceLen()
+
+				// The AES-GCM construction in TLS has an
+				// explicit nonce so that the nonce can be
+				// random. However, the nonce is only 8 bytes
+				// which is too small for a secure, random
+				// nonce. Therefore we use the sequence number
+				// as the nonce.
+				explicitIVIsSeq = explicitIVLen > 0
+			}
+		}
+		m := len(data)
+		if maxPayload := c.maxPayloadSizeForWrite(typ, explicitIVLen); m > maxPayload {
+			m = maxPayload
+		}
+		b.resize(recordHeaderLen + explicitIVLen + m)
+		b.data[0] = byte(typ)
+		vers := c.vers
+		if vers == 0 {
+			// Some TLS servers fail if the record version is
+			// greater than TLS 1.0 for the initial ClientHello.
+			vers = VersionTLS10
+		}
+		if c.vers >= VersionTLS13 {
+			// TLS 1.3 froze the record layer version at { 3, 1 }.
+			// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-5.1.
+			// But for draft 22, this was changed to { 3, 3 }.
+			vers = VersionTLS12
+		}
+		b.data[1] = byte(vers >> 8)
+		b.data[2] = byte(vers)
+		b.data[3] = byte(m >> 8)
+		b.data[4] = byte(m)
+		if explicitIVLen > 0 {
+			explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+			if explicitIVIsSeq {
+				copy(explicitIV, c.out.seq[:])
+			} else {
+				if _, err := io.ReadFull(c.config.rand(), explicitIV); err != nil {
+					return n, err
+				}
+			}
+		}
+		copy(b.data[recordHeaderLen+explicitIVLen:], data)
+		c.out.encrypt(b, explicitIVLen)
+		if _, err := c.write(b.data); err != nil {
+			return n, err
+		}
+		n += m
+		data = data[m:]
+	}
+
+	if typ == recordTypeChangeCipherSpec && c.vers < VersionTLS13 {
+		if err := c.out.changeCipherSpec(); err != nil {
+			return n, c.sendAlertLocked(err.(alert))
+		}
+	}
+
+	return n, nil
+}
+
+// writeRecord writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+// L < c.out.Mutex.
+func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	return c.writeRecordLocked(typ, data)
+}
+
+// readHandshake reads the next handshake message from
+// the record layer.
+// c.in.Mutex < L; c.out.Mutex < L.
+func (c *Conn) readHandshake() (interface{}, error) {
+	for c.hand.Len() < 4 {
+		if err := c.in.err; err != nil {
+			return nil, err
+		}
+		if err := c.readRecord(recordTypeHandshake); err != nil {
+			return nil, err
+		}
+	}
+
+	data := c.hand.Bytes()
+	n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+	if n > maxHandshake {
+		c.sendAlertLocked(alertInternalError)
+		return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake))
+	}
+	for c.hand.Len() < 4+n {
+		if err := c.in.err; err != nil {
+			return nil, err
+		}
+		if err := c.readRecord(recordTypeHandshake); err != nil {
+			return nil, err
+		}
+	}
+	data = c.hand.Next(4 + n)
+	var m handshakeMessage
+	switch data[0] {
+	case typeHelloRequest:
+		m = new(helloRequestMsg)
+	case typeClientHello:
+		m = new(clientHelloMsg)
+	case typeServerHello:
+		m = new(serverHelloMsg)
+	case typeEncryptedExtensions:
+		m = new(encryptedExtensionsMsg)
+	case typeNewSessionTicket:
+		if c.vers >= VersionTLS13 {
+			m = new(newSessionTicketMsg13)
+		} else {
+			m = new(newSessionTicketMsg)
+		}
+	case typeEndOfEarlyData:
+		m = new(endOfEarlyDataMsg)
+	case typeCertificate:
+		if c.vers >= VersionTLS13 {
+			m = new(certificateMsg13)
+		} else {
+			m = new(certificateMsg)
+		}
+	case typeCertificateRequest:
+		if c.vers >= VersionTLS13 {
+			m = new(certificateRequestMsg13)
+		} else {
+			m = &certificateRequestMsg{
+				hasSignatureAndHash: c.vers >= VersionTLS12,
+			}
+		}
+	case typeCertificateStatus:
+		m = new(certificateStatusMsg)
+	case typeServerKeyExchange:
+		m = new(serverKeyExchangeMsg)
+	case typeServerHelloDone:
+		m = new(serverHelloDoneMsg)
+	case typeClientKeyExchange:
+		m = new(clientKeyExchangeMsg)
+	case typeCertificateVerify:
+		m = &certificateVerifyMsg{
+			hasSignatureAndHash: c.vers >= VersionTLS12,
+		}
+	case typeNextProtocol:
+		m = new(nextProtoMsg)
+	case typeFinished:
+		m = new(finishedMsg)
+	default:
+		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+
+	// The handshake message unmarshalers
+	// expect to be able to keep references to data,
+	// so pass in a fresh copy that won't be overwritten.
+	data = append([]byte(nil), data...)
+
+	if unmarshalAlert := m.unmarshal(data); unmarshalAlert != alertSuccess {
+		return nil, c.in.setErrorLocked(c.sendAlert(unmarshalAlert))
+	}
+	return m, nil
+}
+
+var (
+	errClosed   = errors.New("tls: use of closed connection")
+	errShutdown = errors.New("tls: protocol is shutdown")
+)
+
+// Write writes data to the connection.
+func (c *Conn) Write(b []byte) (int, error) {
+	// interlock with Close below
+	for {
+		x := atomic.LoadInt32(&c.activeCall)
+		if x&1 != 0 {
+			return 0, errClosed
+		}
+		if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
+			defer atomic.AddInt32(&c.activeCall, -2)
+			break
+		}
+	}
+
+	if err := c.Handshake(); err != nil {
+		return 0, err
+	}
+
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	if err := c.out.err; err != nil {
+		return 0, err
+	}
+
+	if !c.handshakeComplete {
+		return 0, alertInternalError
+	}
+
+	if c.closeNotifySent {
+		return 0, errShutdown
+	}
+
+	// SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
+	// attack when using block mode ciphers due to predictable IVs.
+	// This can be prevented by splitting each Application Data
+	// record into two records, effectively randomizing the IV.
+	//
+	// http://www.openssl.org/~bodo/tls-cbc.txt
+	// https://bugzilla.mozilla.org/show_bug.cgi?id=665814
+	// http://www.imperialviolet.org/2012/01/15/beastfollowup.html
+
+	var m int
+	if len(b) > 1 && c.vers <= VersionTLS10 {
+		if _, ok := c.out.cipher.(cipher.BlockMode); ok {
+			n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
+			if err != nil {
+				return n, c.out.setErrorLocked(err)
+			}
+			m, b = 1, b[1:]
+		}
+	}
+
+	n, err := c.writeRecordLocked(recordTypeApplicationData, b)
+	return n + m, c.out.setErrorLocked(err)
+}
+
+// Process Handshake messages after the handshake has completed.
+// c.in.Mutex <= L
+func (c *Conn) handlePostHandshake() error {
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	switch hm := msg.(type) {
+	case *helloRequestMsg:
+		return c.handleRenegotiation(hm)
+	case *newSessionTicketMsg13:
+		if !c.isClient {
+			c.sendAlert(alertUnexpectedMessage)
+			return alertUnexpectedMessage
+		}
+		return nil // TODO implement session tickets
+	default:
+		c.sendAlert(alertUnexpectedMessage)
+		return alertUnexpectedMessage
+	}
+}
+
+// handleRenegotiation processes a HelloRequest handshake message.
+// c.in.Mutex <= L
+func (c *Conn) handleRenegotiation(*helloRequestMsg) error {
+	if !c.isClient {
+		return c.sendAlert(alertNoRenegotiation)
+	}
+
+	if c.vers >= VersionTLS13 {
+		return c.sendAlert(alertNoRenegotiation)
+	}
+
+	switch c.config.Renegotiation {
+	case RenegotiateNever:
+		return c.sendAlert(alertNoRenegotiation)
+	case RenegotiateOnceAsClient:
+		if c.handshakes > 1 {
+			return c.sendAlert(alertNoRenegotiation)
+		}
+	case RenegotiateFreelyAsClient:
+		// Ok.
+	default:
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: unknown Renegotiation value")
+	}
+
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	c.phase = handshakeRunning
+	c.handshakeComplete = false
+	if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil {
+		c.handshakes++
+	}
+	return c.handshakeErr
+}
+
+// ConfirmHandshake waits for the handshake to reach a point at which
+// the connection is certainly not replayed. That is, after receiving
+// the Client Finished.
+//
+// If ConfirmHandshake returns an error and until ConfirmHandshake
+// returns, the 0-RTT data should not be trusted not to be replayed.
+//
+// This is only meaningful in TLS 1.3 when Accept0RTTData is true and the
+// client sent valid 0-RTT data. In any other case it's equivalent to
+// calling Handshake.
+func (c *Conn) ConfirmHandshake() error {
+	if c.isClient {
+		panic("ConfirmHandshake should only be called for servers")
+	}
+
+	if err := c.Handshake(); err != nil {
+		return err
+	}
+
+	if c.vers < VersionTLS13 {
+		return nil
+	}
+
+	c.confirmMutex.Lock()
+	if atomic.LoadInt32(&c.handshakeConfirmed) == 1 { // c.phase == handshakeConfirmed
+		c.confirmMutex.Unlock()
+		return nil
+	} else {
+		defer func() {
+			// If we transitioned to handshakeConfirmed we already released the lock,
+			// otherwise do it here.
+			if c.phase != handshakeConfirmed {
+				c.confirmMutex.Unlock()
+			}
+		}()
+	}
+
+	c.in.Lock()
+	defer c.in.Unlock()
+
+	var input *block
+	// Try to read all data (if phase==readingEarlyData) or extract the
+	// remaining data from the previous read that could not fit in the read
+	// buffer (if c.input != nil).
+	if c.phase == readingEarlyData || c.input != nil {
+		buf := &bytes.Buffer{}
+		if _, err := buf.ReadFrom(earlyDataReader{c}); err != nil {
+			c.in.setErrorLocked(err)
+			return err
+		}
+		input = &block{data: buf.Bytes()}
+	}
+
+	// At this point, earlyDataReader has read all early data and received
+	// the end_of_early_data signal. Expect a Finished message.
+	// Locks held so far: c.confirmMutex, c.in
+	// not confirmed implies c.phase == discardingEarlyData || c.phase == waitingClientFinished
+	for c.phase != handshakeConfirmed {
+		if err := c.hs.readClientFinished13(true); err != nil {
+			c.in.setErrorLocked(err)
+			return err
+		}
+	}
+
+	if c.phase != handshakeConfirmed {
+		panic("should have reached handshakeConfirmed state")
+	}
+	if c.input != nil {
+		panic("should not have read past the Client Finished")
+	}
+
+	c.input = input
+
+	return nil
+}
+
+// earlyDataReader wraps a Conn and reads only early data, both buffered
+// and still on the wire.
+type earlyDataReader struct {
+	c *Conn
+}
+
+// c.in.Mutex <= L
+func (r earlyDataReader) Read(b []byte) (n int, err error) {
+	c := r.c
+
+	if c.phase == handshakeConfirmed {
+		// c.input might not be early data
+		panic("earlyDataReader called at handshakeConfirmed")
+	}
+
+	for c.input == nil && c.in.err == nil && c.phase == readingEarlyData {
+		if err := c.readRecord(recordTypeApplicationData); err != nil {
+			return 0, err
+		}
+		if c.hand.Len() > 0 {
+			if err := c.handleEndOfEarlyData(); err != nil {
+				return 0, err
+			}
+		}
+	}
+	if err := c.in.err; err != nil {
+		return 0, err
+	}
+
+	if c.input != nil {
+		n, err = c.input.Read(b)
+		if err == io.EOF {
+			err = nil
+			c.in.freeBlock(c.input)
+			c.input = nil
+		}
+	}
+
+	// Following early application data, an end_of_early_data is expected.
+	if err == nil && c.phase != readingEarlyData && c.input == nil {
+		err = io.EOF
+	}
+	return
+}
+
+// Read can be made to time out and return a net.Error with Timeout() == true
+// after a fixed time limit; see SetDeadline and SetReadDeadline.
+func (c *Conn) Read(b []byte) (n int, err error) {
+	if err = c.Handshake(); err != nil {
+		return
+	}
+	if len(b) == 0 {
+		// Put this after Handshake, in case people were calling
+		// Read(nil) for the side effect of the Handshake.
+		return
+	}
+
+	c.confirmMutex.Lock()
+	if atomic.LoadInt32(&c.handshakeConfirmed) == 1 { // c.phase == handshakeConfirmed
+		c.confirmMutex.Unlock()
+	} else {
+		defer func() {
+			// If we transitioned to handshakeConfirmed we already released the lock,
+			// otherwise do it here.
+			if c.phase != handshakeConfirmed {
+				c.confirmMutex.Unlock()
+			}
+		}()
+	}
+
+	c.in.Lock()
+	defer c.in.Unlock()
+
+	// Some OpenSSL servers send empty records in order to randomize the
+	// CBC IV. So this loop ignores a limited number of empty records.
+	const maxConsecutiveEmptyRecords = 100
+	for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ {
+		for c.input == nil && c.in.err == nil {
+			if err := c.readRecord(recordTypeApplicationData); err != nil {
+				// Soft error, like EAGAIN
+				return 0, err
+			}
+			if c.hand.Len() > 0 {
+				if c.phase == readingEarlyData || c.phase == waitingClientFinished {
+					if c.phase == readingEarlyData {
+						if err := c.handleEndOfEarlyData(); err != nil {
+							return 0, err
+						}
+					}
+					// Server has received all early data, confirm
+					// by reading the Client Finished message.
+					if err := c.hs.readClientFinished13(true); err != nil {
+						c.in.setErrorLocked(err)
+						return 0, err
+					}
+					continue
+				}
+				if err := c.handlePostHandshake(); err != nil {
+					return 0, err
+				}
+			}
+		}
+		if err := c.in.err; err != nil {
+			return 0, err
+		}
+
+		n, err = c.input.Read(b)
+		if err == io.EOF {
+			err = nil
+			c.in.freeBlock(c.input)
+			c.input = nil
+		}
+
+		// If a close-notify alert is waiting, read it so that
+		// we can return (n, EOF) instead of (n, nil), to signal
+		// to the HTTP response reading goroutine that the
+		// connection is now closed. This eliminates a race
+		// where the HTTP response reading goroutine would
+		// otherwise not observe the EOF until its next read,
+		// by which time a client goroutine might have already
+		// tried to reuse the HTTP connection for a new
+		// request.
+		// See https://codereview.appspot.com/76400046
+		// and https://golang.org/issue/3514
+		if ri := c.rawInput; ri != nil &&
+			n != 0 && err == nil &&
+			c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert {
+			if recErr := c.readRecord(recordTypeApplicationData); recErr != nil {
+				err = recErr // will be io.EOF on closeNotify
+			}
+		}
+
+		if n != 0 || err != nil {
+			return n, err
+		}
+	}
+
+	return 0, io.ErrNoProgress
+}
+
+// Close closes the connection.
+func (c *Conn) Close() error {
+	// Interlock with Conn.Write above.
+	var x int32
+	for {
+		x = atomic.LoadInt32(&c.activeCall)
+		if x&1 != 0 {
+			return errClosed
+		}
+		if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) {
+			break
+		}
+	}
+	if x != 0 {
+		// io.Writer and io.Closer should not be used concurrently.
+		// If Close is called while a Write is currently in-flight,
+		// interpret that as a sign that this Close is really just
+		// being used to break the Write and/or clean up resources and
+		// avoid sending the alertCloseNotify, which may block
+		// waiting on handshakeMutex or the c.out mutex.
+		return c.conn.Close()
+	}
+
+	var alertErr error
+
+	c.handshakeMutex.Lock()
+	if c.handshakeComplete {
+		alertErr = c.closeNotify()
+	}
+	c.handshakeMutex.Unlock()
+
+	if err := c.conn.Close(); err != nil {
+		return err
+	}
+	return alertErr
+}
+
+var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete")
+
+// CloseWrite shuts down the writing side of the connection. It should only be
+// called once the handshake has completed and does not call CloseWrite on the
+// underlying connection. Most callers should just use Close.
+func (c *Conn) CloseWrite() error {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	if !c.handshakeComplete {
+		return errEarlyCloseWrite
+	}
+
+	return c.closeNotify()
+}
+
+func (c *Conn) closeNotify() error {
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	if !c.closeNotifySent {
+		c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
+		c.closeNotifySent = true
+	}
+	return c.closeNotifyErr
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+// Most uses of this package need not call Handshake
+// explicitly: the first Read or Write will call it automatically.
+//
+// In TLS 1.3 Handshake returns after the client and server first flights,
+// without waiting for the Client Finished.
+func (c *Conn) Handshake() error {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	if err := c.handshakeErr; err != nil {
+		return err
+	}
+	if c.handshakeComplete {
+		return nil
+	}
+
+	c.in.Lock()
+	defer c.in.Unlock()
+
+	// The handshake cannot have completed when handshakeMutex was unlocked
+	// because this goroutine set handshakeCond.
+	if c.handshakeErr != nil || c.handshakeComplete {
+		panic("handshake should not have been able to complete after handshakeCond was set")
+	}
+
+	c.connID = make([]byte, 8)
+	if _, err := io.ReadFull(c.config.rand(), c.connID); err != nil {
+		return err
+	}
+
+	if c.isClient {
+		c.handshakeErr = c.clientHandshake()
+	} else {
+		c.handshakeErr = c.serverHandshake()
+	}
+	if c.handshakeErr == nil {
+		c.handshakes++
+	} else {
+		// If an error occurred during the hadshake try to flush the
+		// alert that might be left in the buffer.
+		c.flush()
+	}
+
+	if c.handshakeErr == nil && !c.handshakeComplete {
+		panic("handshake should have had a result.")
+	}
+
+	return c.handshakeErr
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	var state ConnectionState
+	state.HandshakeComplete = c.handshakeComplete
+	state.ServerName = c.serverName
+
+	if c.handshakeComplete {
+		state.ConnectionID = c.connID
+		state.ClientHello = c.clientHello
+		state.Version = c.vers
+		state.NegotiatedProtocol = c.clientProtocol
+		state.DidResume = c.didResume
+		state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
+		state.CipherSuite = c.cipherSuite
+		state.PeerCertificates = c.peerCertificates
+		state.VerifiedChains = c.verifiedChains
+		state.SignedCertificateTimestamps = c.scts
+		state.OCSPResponse = c.ocspResponse
+		if c.verifiedDc != nil {
+			state.DelegatedCredential = c.verifiedDc.raw
+		}
+		state.HandshakeConfirmed = atomic.LoadInt32(&c.handshakeConfirmed) == 1
+		if !state.HandshakeConfirmed {
+			state.Unique0RTTToken = c.binder
+		}
+		if !c.didResume {
+			if c.clientFinishedIsFirst {
+				state.TLSUnique = c.clientFinished[:]
+			} else {
+				state.TLSUnique = c.serverFinished[:]
+			}
+		}
+	}
+
+	return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	return c.ocspResponse
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host. If so, it returns nil; if not, it returns an error
+// describing the problem.
+func (c *Conn) VerifyHostname(host string) error {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	if !c.isClient {
+		return errors.New("tls: VerifyHostname called on TLS server connection")
+	}
+	if !c.handshakeComplete {
+		return errors.New("tls: handshake has not yet been performed")
+	}
+	if len(c.verifiedChains) == 0 {
+		return errors.New("tls: handshake did not verify certificate chain")
+	}
+	return c.peerCertificates[0].VerifyHostname(host)
+}

+ 1002 - 0
vendor/github.com/Psiphon-Labs/tls-tris/handshake_client.go

@@ -0,0 +1,1002 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/subtle"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"strconv"
+	"strings"
+	"sync/atomic"
+)
+
+type clientHandshakeState struct {
+	c            *Conn
+	serverHello  *serverHelloMsg
+	hello        *clientHelloMsg
+	suite        *cipherSuite
+	masterSecret []byte
+	session      *ClientSessionState
+
+	// TLS 1.0-1.2 fields
+	finishedHash finishedHash
+
+	// TLS 1.3 fields
+	keySchedule *keySchedule13
+	privateKey  []byte
+}
+
+func makeClientHello(config *Config) (*clientHelloMsg, error) {
+	if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
+		return nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
+	}
+
+	nextProtosLength := 0
+	for _, proto := range config.NextProtos {
+		if l := len(proto); l == 0 || l > 255 {
+			return nil, errors.New("tls: invalid NextProtos value")
+		} else {
+			nextProtosLength += 1 + l
+		}
+	}
+
+	if nextProtosLength > 0xffff {
+		return nil, errors.New("tls: NextProtos values too large")
+	}
+
+	hello := &clientHelloMsg{
+		vers:                         config.maxVersion(),
+		compressionMethods:           []uint8{compressionNone},
+		random:                       make([]byte, 32),
+		ocspStapling:                 true,
+		scts:                         true,
+		serverName:                   hostnameInSNI(config.ServerName),
+		supportedCurves:              config.curvePreferences(),
+		supportedPoints:              []uint8{pointFormatUncompressed},
+		nextProtoNeg:                 len(config.NextProtos) > 0,
+		secureRenegotiationSupported: true,
+		delegatedCredential:          config.AcceptDelegatedCredential,
+		alpnProtocols:                config.NextProtos,
+	}
+	possibleCipherSuites := config.cipherSuites()
+	hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
+
+NextCipherSuite:
+	for _, suiteId := range possibleCipherSuites {
+		for _, suite := range cipherSuites {
+			if suite.id != suiteId {
+				continue
+			}
+			// Don't advertise TLS 1.2-only cipher suites unless
+			// we're attempting TLS 1.2.
+			if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
+				continue NextCipherSuite
+			}
+			// Don't advertise TLS 1.3-only cipher suites unless
+			// we're attempting TLS 1.3.
+			if hello.vers < VersionTLS13 && suite.flags&suiteTLS13 != 0 {
+				continue NextCipherSuite
+			}
+			hello.cipherSuites = append(hello.cipherSuites, suiteId)
+			continue NextCipherSuite
+		}
+	}
+
+	_, err := io.ReadFull(config.rand(), hello.random)
+	if err != nil {
+		return nil, errors.New("tls: short read from Rand: " + err.Error())
+	}
+
+	if hello.vers >= VersionTLS12 {
+		hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+	}
+
+	if hello.vers >= VersionTLS13 {
+		// Version preference is indicated via "supported_extensions",
+		// set legacy_version to TLS 1.2 for backwards compatibility.
+		hello.vers = VersionTLS12
+		hello.supportedVersions = config.getSupportedVersions()
+		hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
+		hello.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
+	}
+
+	return hello, nil
+}
+
+// c.out.Mutex <= L; c.handshakeMutex <= L.
+func (c *Conn) clientHandshake() error {
+	if c.config == nil {
+		c.config = defaultConfig()
+	}
+
+	// This may be a renegotiation handshake, in which case some fields
+	// need to be reset.
+	c.didResume = false
+
+	hello, err := makeClientHello(c.config)
+	if err != nil {
+		return err
+	}
+
+	if c.handshakes > 0 {
+		hello.secureRenegotiation = c.clientFinished[:]
+	}
+
+	var session *ClientSessionState
+	var cacheKey string
+	sessionCache := c.config.ClientSessionCache
+	// TLS 1.3 has no session resumption based on session tickets.
+	if c.config.SessionTicketsDisabled || c.config.maxVersion() >= VersionTLS13 {
+		sessionCache = nil
+	}
+
+	if sessionCache != nil {
+		hello.ticketSupported = true
+	}
+
+	// Session resumption is not allowed if renegotiating because
+	// renegotiation is primarily used to allow a client to send a client
+	// certificate, which would be skipped if session resumption occurred.
+	if sessionCache != nil && c.handshakes == 0 {
+		// Try to resume a previously negotiated TLS session, if
+		// available.
+		cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+		candidateSession, ok := sessionCache.Get(cacheKey)
+		if ok {
+			// Check that the ciphersuite/version used for the
+			// previous session are still valid.
+			cipherSuiteOk := false
+			for _, id := range hello.cipherSuites {
+				if id == candidateSession.cipherSuite {
+					cipherSuiteOk = true
+					break
+				}
+			}
+
+			versOk := candidateSession.vers >= c.config.minVersion() &&
+				candidateSession.vers <= c.config.maxVersion()
+			if versOk && cipherSuiteOk {
+				session = candidateSession
+			}
+		}
+	}
+
+	if session != nil {
+		hello.sessionTicket = session.sessionTicket
+		// A random session ID is used to detect when the
+		// server accepted the ticket and is resuming a session
+		// (see RFC 5077).
+		hello.sessionId = make([]byte, 16)
+		if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
+			return errors.New("tls: short read from Rand: " + err.Error())
+		}
+	}
+
+	hs := &clientHandshakeState{
+		c:       c,
+		hello:   hello,
+		session: session,
+	}
+
+	var clientKS keyShare
+	if c.config.maxVersion() >= VersionTLS13 {
+		// Create one keyshare for the first default curve. If it is not
+		// appropriate, the server should raise a HRR.
+		defaultGroup := c.config.curvePreferences()[0]
+		hs.privateKey, clientKS, err = c.config.generateKeyShare(defaultGroup)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		hello.keyShares = []keyShare{clientKS}
+		// middlebox compatibility mode, provide a non-empty session ID
+		hello.sessionId = make([]byte, 16)
+		if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
+			return errors.New("tls: short read from Rand: " + err.Error())
+		}
+	}
+
+	if err = hs.handshake(); err != nil {
+		return err
+	}
+
+	// If we had a successful handshake and hs.session is different from
+	// the one already cached - cache a new one
+	if sessionCache != nil && hs.session != nil && session != hs.session && c.vers < VersionTLS13 {
+		sessionCache.Put(cacheKey, hs.session)
+	}
+
+	return nil
+}
+
+// Does the handshake, either a full one or resumes old session.
+// Requires hs.c, hs.hello, and, optionally, hs.session to be set.
+func (hs *clientHandshakeState) handshake() error {
+	c := hs.c
+
+	// send ClientHello
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	var ok bool
+	if hs.serverHello, ok = msg.(*serverHelloMsg); !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(hs.serverHello, msg)
+	}
+
+	if err = hs.pickTLSVersion(); err != nil {
+		return err
+	}
+
+	if err = hs.pickCipherSuite(); err != nil {
+		return err
+	}
+
+	var isResume bool
+	if c.vers >= VersionTLS13 {
+		hs.keySchedule = newKeySchedule13(hs.suite, c.config, hs.hello.random)
+		hs.keySchedule.write(hs.hello.marshal())
+		hs.keySchedule.write(hs.serverHello.marshal())
+	} else {
+		isResume, err = hs.processServerHello()
+		if err != nil {
+			return err
+		}
+
+		hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+
+		// No signatures of the handshake are needed in a resumption.
+		// Otherwise, in a full handshake, if we don't have any certificates
+		// configured then we will never send a CertificateVerify message and
+		// thus no signatures are needed in that case either.
+		if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) {
+			hs.finishedHash.discardHandshakeBuffer()
+		}
+
+		hs.finishedHash.Write(hs.hello.marshal())
+		hs.finishedHash.Write(hs.serverHello.marshal())
+	}
+
+	c.buffering = true
+	if c.vers >= VersionTLS13 {
+		if err := hs.doTLS13Handshake(); err != nil {
+			return err
+		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+	} else if isResume {
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.readSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(c.serverFinished[:]); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = false
+		if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+			return err
+		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+	} else {
+		if err := hs.doFullHandshake(); err != nil {
+			return err
+		}
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+			return err
+		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = true
+		if err := hs.readSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(c.serverFinished[:]); err != nil {
+			return err
+		}
+	}
+
+	c.didResume = isResume
+	c.phase = handshakeConfirmed
+	atomic.StoreInt32(&c.handshakeConfirmed, 1)
+	c.handshakeComplete = true
+
+	return nil
+}
+
+func (hs *clientHandshakeState) pickTLSVersion() error {
+	vers, ok := hs.c.config.pickVersion([]uint16{hs.serverHello.vers})
+	if !ok || vers < VersionTLS10 {
+		// TLS 1.0 is the minimum version supported as a client.
+		hs.c.sendAlert(alertProtocolVersion)
+		return fmt.Errorf("tls: server selected unsupported protocol version %x", hs.serverHello.vers)
+	}
+
+	hs.c.vers = vers
+	hs.c.haveVers = true
+
+	return nil
+}
+
+func (hs *clientHandshakeState) pickCipherSuite() error {
+	if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil {
+		hs.c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: server chose an unconfigured cipher suite")
+	}
+	// Check that the chosen cipher suite matches the protocol version.
+	if hs.c.vers >= VersionTLS13 && hs.suite.flags&suiteTLS13 == 0 ||
+		hs.c.vers < VersionTLS13 && hs.suite.flags&suiteTLS13 != 0 {
+		hs.c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: server chose an inappropriate cipher suite")
+	}
+
+	hs.c.cipherSuite = hs.suite.id
+	return nil
+}
+
+// processCertsFromServer takes a chain of server certificates from a
+// Certificate message and verifies them.
+func (hs *clientHandshakeState) processCertsFromServer(certificates [][]byte) error {
+	c := hs.c
+	certs := make([]*x509.Certificate, len(certificates))
+	for i, asn1Data := range certificates {
+		cert, err := x509.ParseCertificate(asn1Data)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: failed to parse certificate from server: " + err.Error())
+		}
+		certs[i] = cert
+	}
+
+	if !c.config.InsecureSkipVerify {
+		opts := x509.VerifyOptions{
+			Roots:         c.config.RootCAs,
+			CurrentTime:   c.config.time(),
+			DNSName:       c.config.ServerName,
+			Intermediates: x509.NewCertPool(),
+		}
+
+		for i, cert := range certs {
+			if i == 0 {
+				continue
+			}
+			opts.Intermediates.AddCert(cert)
+		}
+		var err error
+		c.verifiedChains, err = certs[0].Verify(opts)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	if c.config.VerifyPeerCertificate != nil {
+		if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	switch certs[0].PublicKey.(type) {
+	case *rsa.PublicKey, *ecdsa.PublicKey:
+		break
+	default:
+		c.sendAlert(alertUnsupportedCertificate)
+		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
+	}
+
+	c.peerCertificates = certs
+	return nil
+}
+
+// processDelegatedCredentialFromServer unmarshals the delegated credential
+// offered by the server (if present) and validates it using the peer
+// certificate and the signature scheme (`scheme`) indicated by the server in
+// the "signature_scheme" extension.
+func (hs *clientHandshakeState) processDelegatedCredentialFromServer(serialized []byte, scheme SignatureScheme) error {
+	c := hs.c
+
+	var dc *delegatedCredential
+	var err error
+	if serialized != nil {
+		// Assert that the DC extension was indicated by the client.
+		if !hs.hello.delegatedCredential {
+			c.sendAlert(alertUnexpectedMessage)
+			return errors.New("tls: got delegated credential extension without indication")
+		}
+
+		// Parse the delegated credential.
+		dc, err = unmarshalDelegatedCredential(serialized)
+		if err != nil {
+			c.sendAlert(alertDecodeError)
+			return fmt.Errorf("tls: delegated credential: %s", err)
+		}
+	}
+
+	if dc != nil && !c.config.InsecureSkipVerify {
+		if v, err := dc.validate(c.peerCertificates[0], c.config.time()); err != nil {
+			c.sendAlert(alertIllegalParameter)
+			return fmt.Errorf("delegated credential: %s", err)
+		} else if !v {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("delegated credential: signature invalid")
+		} else if dc.cred.expectedVersion != hs.c.vers {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("delegated credential: protocol version mismatch")
+		} else if dc.cred.expectedCertVerifyAlgorithm != scheme {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("delegated credential: signature scheme mismatch")
+		}
+	}
+
+	c.verifiedDc = dc
+	return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+	c := hs.c
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	certMsg, ok := msg.(*certificateMsg)
+	if !ok || len(certMsg.certificates) == 0 {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
+	}
+	hs.finishedHash.Write(certMsg.marshal())
+
+	if c.handshakes == 0 {
+		// If this is the first handshake on a connection, process and
+		// (optionally) verify the server's certificates.
+		if err := hs.processCertsFromServer(certMsg.certificates); err != nil {
+			return err
+		}
+	} else {
+		// This is a renegotiation handshake. We require that the
+		// server's identity (i.e. leaf certificate) is unchanged and
+		// thus any previous trust decision is still valid.
+		//
+		// See https://mitls.org/pages/attacks/3SHAKE for the
+		// motivation behind this requirement.
+		if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: server's identity changed during renegotiation")
+		}
+	}
+
+	msg, err = c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	cs, ok := msg.(*certificateStatusMsg)
+	if ok {
+		// RFC4366 on Certificate Status Request:
+		// The server MAY return a "certificate_status" message.
+
+		if !hs.serverHello.ocspStapling {
+			// If a server returns a "CertificateStatus" message, then the
+			// server MUST have included an extension of type "status_request"
+			// with empty "extension_data" in the extended server hello.
+
+			c.sendAlert(alertUnexpectedMessage)
+			return errors.New("tls: received unexpected CertificateStatus message")
+		}
+		hs.finishedHash.Write(cs.marshal())
+
+		if cs.statusType == statusTypeOCSP {
+			c.ocspResponse = cs.response
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	keyAgreement := hs.suite.ka(c.vers)
+
+	// Set the public key used to verify the handshake.
+	pk := c.peerCertificates[0].PublicKey
+
+	skx, ok := msg.(*serverKeyExchangeMsg)
+	if ok {
+		hs.finishedHash.Write(skx.marshal())
+
+		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, pk, skx)
+		if err != nil {
+			c.sendAlert(alertUnexpectedMessage)
+			return err
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	var chainToSend *Certificate
+	var certRequested bool
+	certReq, ok := msg.(*certificateRequestMsg)
+	if ok {
+		certRequested = true
+		hs.finishedHash.Write(certReq.marshal())
+
+		if chainToSend, err = hs.getCertificate(certReq); err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	shd, ok := msg.(*serverHelloDoneMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(shd, msg)
+	}
+	hs.finishedHash.Write(shd.marshal())
+
+	// If the server requested a certificate then we have to send a
+	// Certificate message, even if it's empty because we don't have a
+	// certificate to send.
+	if certRequested {
+		certMsg = new(certificateMsg)
+		certMsg.certificates = chainToSend.Certificate
+		hs.finishedHash.Write(certMsg.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+			return err
+		}
+	}
+
+	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, pk)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+	if ckx != nil {
+		hs.finishedHash.Write(ckx.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil {
+			return err
+		}
+	}
+
+	if chainToSend != nil && len(chainToSend.Certificate) > 0 {
+		certVerify := &certificateVerifyMsg{
+			hasSignatureAndHash: c.vers >= VersionTLS12,
+		}
+
+		key, ok := chainToSend.PrivateKey.(crypto.Signer)
+		if !ok {
+			c.sendAlert(alertInternalError)
+			return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
+		}
+
+		signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, hs.hello.supportedSignatureAlgorithms, c.vers)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		// SignatureAndHashAlgorithm was introduced in TLS 1.2.
+		if certVerify.hasSignatureAndHash {
+			certVerify.signatureAlgorithm = signatureAlgorithm
+		}
+		digest, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		signOpts := crypto.SignerOpts(hashFunc)
+		if sigType == signatureRSAPSS {
+			signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
+		}
+		certVerify.signature, err = key.Sign(c.config.rand(), digest, signOpts)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+
+		hs.finishedHash.Write(certVerify.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil {
+			return err
+		}
+	}
+
+	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
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+	c := hs.c
+
+	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+	var clientCipher, serverCipher interface{}
+	var clientHash, serverHash macFunction
+	if hs.suite.cipher != nil {
+		clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+		clientHash = hs.suite.mac(c.vers, clientMAC)
+		serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
+		serverHash = hs.suite.mac(c.vers, serverMAC)
+	} else {
+		clientCipher = hs.suite.aead(clientKey, clientIV)
+		serverCipher = hs.suite.aead(serverKey, serverIV)
+	}
+
+	c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+	c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
+	return nil
+}
+
+func (hs *clientHandshakeState) serverResumedSession() bool {
+	// If the server responded with the same sessionId then it means the
+	// sessionTicket is being used to resume a TLS session.
+	return hs.session != nil && hs.hello.sessionId != nil &&
+		bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
+
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+	c := hs.c
+
+	if hs.serverHello.compressionMethod != compressionNone {
+		c.sendAlert(alertUnexpectedMessage)
+		return false, errors.New("tls: server selected unsupported compression format")
+	}
+
+	if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported {
+		c.secureRenegotiation = true
+		if len(hs.serverHello.secureRenegotiation) != 0 {
+			c.sendAlert(alertHandshakeFailure)
+			return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+		}
+	}
+
+	if c.handshakes > 0 && c.secureRenegotiation {
+		var expectedSecureRenegotiation [24]byte
+		copy(expectedSecureRenegotiation[:], c.clientFinished[:])
+		copy(expectedSecureRenegotiation[12:], c.serverFinished[:])
+		if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) {
+			c.sendAlert(alertHandshakeFailure)
+			return false, errors.New("tls: incorrect renegotiation extension contents")
+		}
+	}
+
+	clientDidNPN := hs.hello.nextProtoNeg
+	clientDidALPN := len(hs.hello.alpnProtocols) > 0
+	serverHasNPN := hs.serverHello.nextProtoNeg
+	serverHasALPN := len(hs.serverHello.alpnProtocol) > 0
+
+	if !clientDidNPN && serverHasNPN {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server advertised unrequested NPN extension")
+	}
+
+	if !clientDidALPN && serverHasALPN {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server advertised unrequested ALPN extension")
+	}
+
+	if serverHasNPN && serverHasALPN {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server advertised both NPN and ALPN extensions")
+	}
+
+	if serverHasALPN {
+		c.clientProtocol = hs.serverHello.alpnProtocol
+		c.clientProtocolFallback = false
+	}
+	c.scts = hs.serverHello.scts
+
+	if !hs.serverResumedSession() {
+		return false, nil
+	}
+
+	if hs.session.vers != c.vers {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server resumed a session with a different version")
+	}
+
+	if hs.session.cipherSuite != hs.suite.id {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server resumed a session with a different cipher suite")
+	}
+
+	// Restore masterSecret and peerCerts from previous state
+	hs.masterSecret = hs.session.masterSecret
+	c.peerCertificates = hs.session.serverCertificates
+	c.verifiedChains = hs.session.verifiedChains
+	return true, nil
+}
+
+func (hs *clientHandshakeState) readFinished(out []byte) error {
+	c := hs.c
+
+	c.readRecord(recordTypeChangeCipherSpec)
+	if c.in.err != nil {
+		return c.in.err
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	serverFinished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverFinished, msg)
+	}
+
+	verify := hs.finishedHash.serverSum(hs.masterSecret)
+	if len(verify) != len(serverFinished.verifyData) ||
+		subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+		c.sendAlert(alertDecryptError)
+		return errors.New("tls: server's Finished message was incorrect")
+	}
+	hs.finishedHash.Write(serverFinished.marshal())
+	copy(out, verify)
+	return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+	if !hs.serverHello.ticketSupported {
+		return nil
+	}
+
+	c := hs.c
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(sessionTicketMsg, msg)
+	}
+	hs.finishedHash.Write(sessionTicketMsg.marshal())
+
+	hs.session = &ClientSessionState{
+		sessionTicket:      sessionTicketMsg.ticket,
+		vers:               c.vers,
+		cipherSuite:        hs.suite.id,
+		masterSecret:       hs.masterSecret,
+		serverCertificates: c.peerCertificates,
+		verifiedChains:     c.verifiedChains,
+	}
+
+	return nil
+}
+
+func (hs *clientHandshakeState) sendFinished(out []byte) error {
+	c := hs.c
+
+	if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+		return err
+	}
+	if hs.serverHello.nextProtoNeg {
+		nextProto := new(nextProtoMsg)
+		proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
+		nextProto.proto = proto
+		c.clientProtocol = proto
+		c.clientProtocolFallback = fallback
+
+		hs.finishedHash.Write(nextProto.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, nextProto.marshal()); err != nil {
+			return err
+		}
+	}
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+	hs.finishedHash.Write(finished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+		return err
+	}
+	copy(out, finished.verifyData)
+	return nil
+}
+
+// tls11SignatureSchemes contains the signature schemes that we synthesise for
+// a TLS <= 1.1 connection, based on the supported certificate types.
+var tls11SignatureSchemes = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1}
+
+const (
+	// tls11SignatureSchemesNumECDSA is the number of initial elements of
+	// tls11SignatureSchemes that use ECDSA.
+	tls11SignatureSchemesNumECDSA = 3
+	// tls11SignatureSchemesNumRSA is the number of trailing elements of
+	// tls11SignatureSchemes that use RSA.
+	tls11SignatureSchemesNumRSA = 4
+)
+
+func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) (*Certificate, error) {
+	c := hs.c
+
+	var rsaAvail, ecdsaAvail bool
+	for _, certType := range certReq.certificateTypes {
+		switch certType {
+		case certTypeRSASign:
+			rsaAvail = true
+		case certTypeECDSASign:
+			ecdsaAvail = true
+		}
+	}
+
+	if c.config.GetClientCertificate != nil {
+		var signatureSchemes []SignatureScheme
+
+		if !certReq.hasSignatureAndHash {
+			// Prior to TLS 1.2, the signature schemes were not
+			// included in the certificate request message. In this
+			// case we use a plausible list based on the acceptable
+			// certificate types.
+			signatureSchemes = tls11SignatureSchemes
+			if !ecdsaAvail {
+				signatureSchemes = signatureSchemes[tls11SignatureSchemesNumECDSA:]
+			}
+			if !rsaAvail {
+				signatureSchemes = signatureSchemes[:len(signatureSchemes)-tls11SignatureSchemesNumRSA]
+			}
+		} else {
+			signatureSchemes = certReq.supportedSignatureAlgorithms
+		}
+
+		return c.config.GetClientCertificate(&CertificateRequestInfo{
+			AcceptableCAs:    certReq.certificateAuthorities,
+			SignatureSchemes: signatureSchemes,
+		})
+	}
+
+	// RFC 4346 on the certificateAuthorities field: A list of the
+	// distinguished names of acceptable certificate authorities.
+	// These distinguished names may specify a desired
+	// distinguished name for a root CA or for a subordinate CA;
+	// thus, this message can be used to describe both known roots
+	// and a desired authorization space. If the
+	// certificate_authorities list is empty then the client MAY
+	// send any certificate of the appropriate
+	// ClientCertificateType, unless there is some external
+	// arrangement to the contrary.
+
+	// We need to search our list of client certs for one
+	// where SignatureAlgorithm is acceptable to the server and the
+	// Issuer is in certReq.certificateAuthorities
+findCert:
+	for i, chain := range c.config.Certificates {
+		if !rsaAvail && !ecdsaAvail {
+			continue
+		}
+
+		for j, cert := range chain.Certificate {
+			x509Cert := chain.Leaf
+			// parse the certificate if this isn't the leaf
+			// node, or if chain.Leaf was nil
+			if j != 0 || x509Cert == nil {
+				var err error
+				if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+					c.sendAlert(alertInternalError)
+					return nil, errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
+				}
+			}
+
+			switch {
+			case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
+			case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
+			default:
+				continue findCert
+			}
+
+			if len(certReq.certificateAuthorities) == 0 {
+				// they gave us an empty list, so just take the
+				// first cert from c.config.Certificates
+				return &chain, nil
+			}
+
+			for _, ca := range certReq.certificateAuthorities {
+				if bytes.Equal(x509Cert.RawIssuer, ca) {
+					return &chain, nil
+				}
+			}
+		}
+	}
+
+	// No acceptable certificate found. Don't send a certificate.
+	return new(Certificate), nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+	if len(config.ServerName) > 0 {
+		return config.ServerName
+	}
+
+	// [Psiphon]
+	//
+	// In certain error conditions, serverAddr may be nil. In this case, since
+	// ServerName is blank, there is no valid session cache key. Calling code
+	// assumes clientSessionCacheKey always succeeds. To minimize changes to
+	// this tls fork, we return "" and no error.
+	//
+	// We assume the cache key won't be used for setting the cache, as the
+	// existing error condition in the conn should result in handshake
+	// failure. In the unlikely case of success and caching a session, the
+	// outcome could include future failure to renegotiate, although in the
+	// case of Psiphon, each connection has its own cache.
+	if serverAddr == nil {
+		return ""
+	}
+
+	return serverAddr.String()
+}
+
+// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol
+// given list of possible protocols and a list of the preference order. The
+// first list must not be empty. It returns the resulting protocol and flag
+// indicating if the fallback case was reached.
+func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
+	for _, s := range preferenceProtos {
+		for _, c := range protos {
+			if s == c {
+				return s, false
+			}
+		}
+	}
+
+	return protos[0], true
+}
+
+// hostnameInSNI converts name into an appropriate hostname for SNI.
+// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
+// See https://tools.ietf.org/html/rfc6066#section-3.
+func hostnameInSNI(name string) string {
+	host := name
+	if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+		host = host[1 : len(host)-1]
+	}
+	if i := strings.LastIndex(host, "%"); i > 0 {
+		host = host[:i]
+	}
+	if net.ParseIP(host) != nil {
+		return ""
+	}
+	for len(name) > 0 && name[len(name)-1] == '.' {
+		name = name[:len(name)-1]
+	}
+	return name
+}

+ 3210 - 0
vendor/github.com/Psiphon-Labs/tls-tris/handshake_messages.go

@@ -0,0 +1,3210 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"bytes"
+	"encoding/binary"
+	"strings"
+
+	// [Psiphon]
+	"crypto/rand"
+	"math/big"
+	math_rand "math/rand"
+
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
+)
+
+// [Psiphon]
+var randomizeClientHello = true
+
+// signAlgosCertList helper function returns either list of signature algorithms in case
+// signature_algorithms_cert extension should be marshalled or nil in the other case.
+// signAlgos is a list of algorithms from signature_algorithms extension. signAlgosCert is a list
+// of algorithms from signature_algorithms_cert extension.
+func signAlgosCertList(signAlgos, signAlgosCert []SignatureScheme) []SignatureScheme {
+	if eqSignatureAlgorithms(signAlgos, signAlgosCert) {
+		// ensure that only supported_algorithms extension is send if supported_algorithms_cert
+		// has identical content
+		return nil
+	}
+	return signAlgosCert
+}
+
+type clientHelloMsg struct {
+	raw                              []byte
+	rawTruncated                     []byte // for PSK binding
+	vers                             uint16
+	random                           []byte
+	sessionId                        []byte
+	cipherSuites                     []uint16
+	compressionMethods               []uint8
+	nextProtoNeg                     bool
+	serverName                       string
+	ocspStapling                     bool
+	scts                             bool
+	supportedCurves                  []CurveID
+	supportedPoints                  []uint8
+	ticketSupported                  bool
+	sessionTicket                    []uint8
+	supportedSignatureAlgorithms     []SignatureScheme
+	supportedSignatureAlgorithmsCert []SignatureScheme
+	secureRenegotiation              []byte
+	secureRenegotiationSupported     bool
+	alpnProtocols                    []string
+	keyShares                        []keyShare
+	supportedVersions                []uint16
+	psks                             []psk
+	pskKeyExchangeModes              []uint8
+	earlyData                        bool
+	delegatedCredential              bool
+}
+
+// Function used for signature_algorithms and signature_algorithrms_cert
+// extensions only (for more details, see TLS 1.3 draft 28, 4.2.3).
+//
+// It advances data slice and returns it, so that it can be used for further
+// processing
+func marshalExtensionSignatureAlgorithms(extension uint16, data []byte, schemes []SignatureScheme) []byte {
+	algNum := uint16(len(schemes))
+	if algNum == 0 {
+		return data
+	}
+
+	binary.BigEndian.PutUint16(data, extension)
+	data = data[2:]
+	binary.BigEndian.PutUint16(data, (2*algNum)+2) // +1 for length
+	data = data[2:]
+	binary.BigEndian.PutUint16(data, (2 * algNum))
+	data = data[2:]
+
+	for _, algo := range schemes {
+		binary.BigEndian.PutUint16(data, uint16(algo))
+		data = data[2:]
+	}
+	return data
+}
+
+// Function used for unmarshalling signature_algorithms or signature_algorithms_cert extensions only
+// (for more details, see TLS 1.3 draft 28, 4.2.3)
+// In case of error function returns alertDecoderError otherwise filled SignatureScheme slice and alertSuccess
+func unmarshalExtensionSignatureAlgorithms(data []byte, length int) ([]SignatureScheme, alert) {
+
+	if length < 2 || length&1 != 0 {
+		return nil, alertDecodeError
+	}
+
+	algLen := binary.BigEndian.Uint16(data)
+	idx := 2
+
+	if int(algLen) != length-2 {
+		return nil, alertDecodeError
+	}
+
+	schemes := make([]SignatureScheme, algLen/2)
+	for i := range schemes {
+		schemes[i] = SignatureScheme(binary.BigEndian.Uint16(data[idx:]))
+		idx += 2
+	}
+	return schemes, alertSuccess
+}
+
+func (m *clientHelloMsg) equal(i interface{}) bool {
+	m1, ok := i.(*clientHelloMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.vers == m1.vers &&
+		bytes.Equal(m.random, m1.random) &&
+		bytes.Equal(m.sessionId, m1.sessionId) &&
+		eqUint16s(m.cipherSuites, m1.cipherSuites) &&
+		bytes.Equal(m.compressionMethods, m1.compressionMethods) &&
+		m.nextProtoNeg == m1.nextProtoNeg &&
+		m.serverName == m1.serverName &&
+		m.ocspStapling == m1.ocspStapling &&
+		m.scts == m1.scts &&
+		eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
+		bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
+		m.ticketSupported == m1.ticketSupported &&
+		bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
+		eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
+		eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert) &&
+		m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
+		bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
+		eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
+		eqKeyShares(m.keyShares, m1.keyShares) &&
+		eqUint16s(m.supportedVersions, m1.supportedVersions) &&
+		m.earlyData == m1.earlyData &&
+		m.delegatedCredential == m1.delegatedCredential
+}
+
+func (m *clientHelloMsg) marshal() []byte {
+
+	// [Psiphon]
+	// Note: the original marshal function is retained as-is for ease of merging upstream changes.
+	if randomizeClientHello {
+		return m.randomizedMarshal()
+	}
+
+	if m.raw != nil {
+		return m.raw
+	}
+
+	length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
+	numExtensions := 0
+	extensionsLength := 0
+
+	// Indicates wether to send signature_algorithms_cert extension
+	if m.nextProtoNeg {
+		numExtensions++
+	}
+	if m.ocspStapling {
+		extensionsLength += 1 + 2 + 2
+		numExtensions++
+	}
+	if len(m.serverName) > 0 {
+		extensionsLength += 5 + len(m.serverName)
+		numExtensions++
+	}
+	if len(m.supportedCurves) > 0 {
+		extensionsLength += 2 + 2*len(m.supportedCurves)
+		numExtensions++
+	}
+	if len(m.supportedPoints) > 0 {
+		extensionsLength += 1 + len(m.supportedPoints)
+		numExtensions++
+	}
+	if m.ticketSupported {
+		extensionsLength += len(m.sessionTicket)
+		numExtensions++
+	}
+	if len(m.supportedSignatureAlgorithms) > 0 {
+		extensionsLength += 2 + 2*len(m.supportedSignatureAlgorithms)
+		numExtensions++
+	}
+	if m.getSignatureAlgorithmsCert() != nil {
+		extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
+		numExtensions++
+	}
+	if m.secureRenegotiationSupported {
+		extensionsLength += 1 + len(m.secureRenegotiation)
+		numExtensions++
+	}
+	if len(m.alpnProtocols) > 0 {
+		extensionsLength += 2
+		for _, s := range m.alpnProtocols {
+			if l := len(s); l == 0 || l > 255 {
+				panic("invalid ALPN protocol")
+			}
+			extensionsLength++
+			extensionsLength += len(s)
+		}
+		numExtensions++
+	}
+	if m.scts {
+		numExtensions++
+	}
+	if len(m.keyShares) > 0 {
+		extensionsLength += 2
+		for _, k := range m.keyShares {
+			extensionsLength += 4 + len(k.data)
+		}
+		numExtensions++
+	}
+	if len(m.supportedVersions) > 0 {
+		extensionsLength += 1 + 2*len(m.supportedVersions)
+		numExtensions++
+	}
+	if m.earlyData {
+		numExtensions++
+	}
+	if m.delegatedCredential {
+		numExtensions++
+	}
+	if numExtensions > 0 {
+		extensionsLength += 4 * numExtensions
+		length += 2 + extensionsLength
+	}
+
+	x := make([]byte, 4+length)
+	x[0] = typeClientHello
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	x[4] = uint8(m.vers >> 8)
+	x[5] = uint8(m.vers)
+	copy(x[6:38], m.random)
+	x[38] = uint8(len(m.sessionId))
+	copy(x[39:39+len(m.sessionId)], m.sessionId)
+	y := x[39+len(m.sessionId):]
+	y[0] = uint8(len(m.cipherSuites) >> 7)
+	y[1] = uint8(len(m.cipherSuites) << 1)
+	for i, suite := range m.cipherSuites {
+		y[2+i*2] = uint8(suite >> 8)
+		y[3+i*2] = uint8(suite)
+	}
+	z := y[2+len(m.cipherSuites)*2:]
+	z[0] = uint8(len(m.compressionMethods))
+	copy(z[1:], m.compressionMethods)
+
+	z = z[1+len(m.compressionMethods):]
+	if numExtensions > 0 {
+		z[0] = byte(extensionsLength >> 8)
+		z[1] = byte(extensionsLength)
+		z = z[2:]
+	}
+	if m.nextProtoNeg {
+		z[0] = byte(extensionNextProtoNeg >> 8)
+		z[1] = byte(extensionNextProtoNeg & 0xff)
+		// The length is always 0
+		z = z[4:]
+	}
+	if len(m.serverName) > 0 {
+		z[0] = byte(extensionServerName >> 8)
+		z[1] = byte(extensionServerName & 0xff)
+		l := len(m.serverName) + 5
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z = z[4:]
+
+		// RFC 3546, section 3.1
+		//
+		// struct {
+		//     NameType name_type;
+		//     select (name_type) {
+		//         case host_name: HostName;
+		//     } name;
+		// } ServerName;
+		//
+		// enum {
+		//     host_name(0), (255)
+		// } NameType;
+		//
+		// opaque HostName<1..2^16-1>;
+		//
+		// struct {
+		//     ServerName server_name_list<1..2^16-1>
+		// } ServerNameList;
+
+		z[0] = byte((len(m.serverName) + 3) >> 8)
+		z[1] = byte(len(m.serverName) + 3)
+		z[3] = byte(len(m.serverName) >> 8)
+		z[4] = byte(len(m.serverName))
+		copy(z[5:], []byte(m.serverName))
+		z = z[l:]
+	}
+	if m.ocspStapling {
+		// RFC 4366, section 3.6
+		z[0] = byte(extensionStatusRequest >> 8)
+		z[1] = byte(extensionStatusRequest)
+		z[2] = 0
+		z[3] = 5
+		z[4] = 1 // OCSP type
+		// Two zero valued uint16s for the two lengths.
+		z = z[9:]
+	}
+	if len(m.supportedCurves) > 0 {
+		// http://tools.ietf.org/html/rfc4492#section-5.5.1
+		// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
+		z[0] = byte(extensionSupportedCurves >> 8)
+		z[1] = byte(extensionSupportedCurves)
+		l := 2 + 2*len(m.supportedCurves)
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		l -= 2
+		z[4] = byte(l >> 8)
+		z[5] = byte(l)
+		z = z[6:]
+		for _, curve := range m.supportedCurves {
+			z[0] = byte(curve >> 8)
+			z[1] = byte(curve)
+			z = z[2:]
+		}
+	}
+	if len(m.supportedPoints) > 0 {
+		// http://tools.ietf.org/html/rfc4492#section-5.5.2
+		z[0] = byte(extensionSupportedPoints >> 8)
+		z[1] = byte(extensionSupportedPoints)
+		l := 1 + len(m.supportedPoints)
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		l--
+		z[4] = byte(l)
+		z = z[5:]
+		for _, pointFormat := range m.supportedPoints {
+			z[0] = pointFormat
+			z = z[1:]
+		}
+	}
+	if m.ticketSupported {
+		// http://tools.ietf.org/html/rfc5077#section-3.2
+		z[0] = byte(extensionSessionTicket >> 8)
+		z[1] = byte(extensionSessionTicket)
+		l := len(m.sessionTicket)
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z = z[4:]
+		copy(z, m.sessionTicket)
+		z = z[len(m.sessionTicket):]
+	}
+
+	if len(m.supportedSignatureAlgorithms) > 0 {
+		z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
+	}
+	if m.getSignatureAlgorithmsCert() != nil {
+		// Ensure only one list of algorithms is sent if supported_algorithms and supported_algorithms_cert are the same
+		z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
+	}
+
+	if m.secureRenegotiationSupported {
+		z[0] = byte(extensionRenegotiationInfo >> 8)
+		z[1] = byte(extensionRenegotiationInfo & 0xff)
+		z[2] = 0
+		z[3] = byte(len(m.secureRenegotiation) + 1)
+		z[4] = byte(len(m.secureRenegotiation))
+		z = z[5:]
+		copy(z, m.secureRenegotiation)
+		z = z[len(m.secureRenegotiation):]
+	}
+	if len(m.alpnProtocols) > 0 {
+		z[0] = byte(extensionALPN >> 8)
+		z[1] = byte(extensionALPN & 0xff)
+		lengths := z[2:]
+		z = z[6:]
+
+		stringsLength := 0
+		for _, s := range m.alpnProtocols {
+			l := len(s)
+			z[0] = byte(l)
+			copy(z[1:], s)
+			z = z[1+l:]
+			stringsLength += 1 + l
+		}
+
+		lengths[2] = byte(stringsLength >> 8)
+		lengths[3] = byte(stringsLength)
+		stringsLength += 2
+		lengths[0] = byte(stringsLength >> 8)
+		lengths[1] = byte(stringsLength)
+	}
+	if m.scts {
+		// https://tools.ietf.org/html/rfc6962#section-3.3.1
+		z[0] = byte(extensionSCT >> 8)
+		z[1] = byte(extensionSCT)
+		// zero uint16 for the zero-length extension_data
+		z = z[4:]
+	}
+	if len(m.keyShares) > 0 {
+		// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
+		z[0] = byte(extensionKeyShare >> 8)
+		z[1] = byte(extensionKeyShare)
+		lengths := z[2:]
+		z = z[6:]
+
+		totalLength := 0
+		for _, ks := range m.keyShares {
+			z[0] = byte(ks.group >> 8)
+			z[1] = byte(ks.group)
+			z[2] = byte(len(ks.data) >> 8)
+			z[3] = byte(len(ks.data))
+			copy(z[4:], ks.data)
+			z = z[4+len(ks.data):]
+			totalLength += 4 + len(ks.data)
+		}
+
+		lengths[2] = byte(totalLength >> 8)
+		lengths[3] = byte(totalLength)
+		totalLength += 2
+		lengths[0] = byte(totalLength >> 8)
+		lengths[1] = byte(totalLength)
+	}
+	if len(m.supportedVersions) > 0 {
+		z[0] = byte(extensionSupportedVersions >> 8)
+		z[1] = byte(extensionSupportedVersions)
+		l := 1 + 2*len(m.supportedVersions)
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		l -= 1
+		z[4] = byte(l)
+		z = z[5:]
+		for _, v := range m.supportedVersions {
+			z[0] = byte(v >> 8)
+			z[1] = byte(v)
+			z = z[2:]
+		}
+	}
+	if m.earlyData {
+		z[0] = byte(extensionEarlyData >> 8)
+		z[1] = byte(extensionEarlyData)
+		z = z[4:]
+	}
+	if m.delegatedCredential {
+		binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
+		z = z[4:]
+	}
+
+	m.raw = x
+
+	return x
+}
+
+// [Psiphon]
+//
+// Randomize the ClientHello. The offered algorithms are shuffled and
+// truncated (longer lists are selected with higher probability). Extensions
+// are shuffled, certain extensions may be omitted, and some additional
+// extensions may be added in.
+//
+// Inspired by parrotRandomized in utls:
+// https://github.com/refraction-networking/utls/blob/db1b65d2300d3a59616a43d2df4ea556b4a7d277/u_parrots.go#L300
+func (m *clientHelloMsg) randomizedMarshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	permute := func(n int, swap func(i, j int)) {
+		if n < 2 {
+			return
+		}
+		perm, err := common.MakeSecureRandomPerm(n)
+		if err == nil {
+			for i, j := range perm {
+				swap(i, j)
+			}
+		}
+	}
+
+	truncate := func(n int, cut func(i int)) {
+		i := n
+		for ; i > 1; i-- {
+			if !common.FlipCoin() {
+				break
+			}
+		}
+		if i < n {
+			cut(i)
+		}
+	}
+
+	// Keep TLS 1.3 cipher suites ordered first, as required.
+	numTLS13CipherSuites := 0
+	for ; numTLS13CipherSuites < len(m.cipherSuites); numTLS13CipherSuites++ {
+		// TODO: check suiteTLS13 flag?
+		if m.cipherSuites[numTLS13CipherSuites]>>8 != 0x13 {
+			break
+		}
+	}
+	if numTLS13CipherSuites > 1 {
+		tls13CipherSuites := m.cipherSuites[:numTLS13CipherSuites]
+		permute(
+			len(tls13CipherSuites),
+			func(i, j int) {
+				tls13CipherSuites[i], tls13CipherSuites[j] = tls13CipherSuites[j], tls13CipherSuites[i]
+			})
+	}
+	if numTLS13CipherSuites < len(m.cipherSuites) {
+		olderCipherSuites := m.cipherSuites[numTLS13CipherSuites:]
+		permute(
+			len(olderCipherSuites),
+			func(i, j int) {
+				olderCipherSuites[i], olderCipherSuites[j] = olderCipherSuites[j], olderCipherSuites[i]
+			})
+		truncate(
+			len(olderCipherSuites),
+			func(i int) { m.cipherSuites = m.cipherSuites[:numTLS13CipherSuites+i] })
+	}
+
+	permute(
+		len(m.supportedCurves),
+		func(i, j int) {
+			m.supportedCurves[i], m.supportedCurves[j] = m.supportedCurves[j], m.supportedCurves[i]
+		})
+	truncate(
+		len(m.supportedCurves),
+		func(i int) { m.supportedCurves = m.supportedCurves[:i] })
+
+	permute(
+		len(m.supportedPoints),
+		func(i, j int) {
+			m.supportedPoints[i], m.supportedPoints[j] = m.supportedPoints[j], m.supportedPoints[i]
+		})
+	truncate(
+		len(m.supportedPoints),
+		func(i int) { m.supportedPoints = m.supportedPoints[:i] })
+
+	permute(
+		len(m.supportedSignatureAlgorithms),
+		func(i, j int) {
+			m.supportedSignatureAlgorithms[i], m.supportedSignatureAlgorithms[j] = m.supportedSignatureAlgorithms[j], m.supportedSignatureAlgorithms[i]
+		})
+	truncate(
+		len(m.supportedSignatureAlgorithms),
+		func(i int) { m.supportedSignatureAlgorithms = m.supportedSignatureAlgorithms[:i] })
+
+	permute(
+		len(m.supportedSignatureAlgorithmsCert),
+		func(i, j int) {
+			m.supportedSignatureAlgorithmsCert[i], m.supportedSignatureAlgorithmsCert[j] = m.supportedSignatureAlgorithmsCert[j], m.supportedSignatureAlgorithmsCert[i]
+		})
+	truncate(
+		len(m.supportedSignatureAlgorithmsCert),
+		func(i int) { m.supportedSignatureAlgorithmsCert = m.supportedSignatureAlgorithmsCert[:i] })
+
+	m.alpnProtocols = []string{"h2", "http/1.1"}
+
+	if common.FlipCoin() {
+		m.supportedVersions = []uint16{VersionTLS13, VersionTLS12, VersionTLS11, VersionTLS10}
+	}
+
+	numExtensions := 0
+	extensionsLength := 0
+	extensionMarshalers := make([]func(), 0)
+	var z []byte
+
+	// Indicates whether to send signature_algorithms_cert extension
+	if m.nextProtoNeg {
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				z[0] = byte(extensionNextProtoNeg >> 8)
+				z[1] = byte(extensionNextProtoNeg & 0xff)
+				// The length is always 0
+				z = z[4:]
+			})
+	}
+	if m.ocspStapling && common.FlipCoin() { // May be omitted
+		extensionsLength += 1 + 2 + 2
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				// RFC 4366, section 3.6
+				z[0] = byte(extensionStatusRequest >> 8)
+				z[1] = byte(extensionStatusRequest)
+				z[2] = 0
+				z[3] = 5
+				z[4] = 1 // OCSP type
+				// Two zero valued uint16s for the two lengths.
+				z = z[9:]
+			})
+	}
+	if len(m.serverName) > 0 {
+		extensionsLength += 5 + len(m.serverName)
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				z[0] = byte(extensionServerName >> 8)
+				z[1] = byte(extensionServerName & 0xff)
+				l := len(m.serverName) + 5
+				z[2] = byte(l >> 8)
+				z[3] = byte(l)
+				z = z[4:]
+
+				// RFC 3546, section 3.1
+				//
+				// struct {
+				//     NameType name_type;
+				//     select (name_type) {
+				//         case host_name: HostName;
+				//     } name;
+				// } ServerName;
+				//
+				// enum {
+				//     host_name(0), (255)
+				// } NameType;
+				//
+				// opaque HostName<1..2^16-1>;
+				//
+				// struct {
+				//     ServerName server_name_list<1..2^16-1>
+				// } ServerNameList;
+
+				z[0] = byte((len(m.serverName) + 3) >> 8)
+				z[1] = byte(len(m.serverName) + 3)
+				z[3] = byte(len(m.serverName) >> 8)
+				z[4] = byte(len(m.serverName))
+				copy(z[5:], []byte(m.serverName))
+				z = z[l:]
+			})
+	}
+	if len(m.supportedCurves) > 0 {
+		extensionsLength += 2 + 2*len(m.supportedCurves)
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				// http://tools.ietf.org/html/rfc4492#section-5.5.1
+				// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
+				z[0] = byte(extensionSupportedCurves >> 8)
+				z[1] = byte(extensionSupportedCurves)
+				l := 2 + 2*len(m.supportedCurves)
+				z[2] = byte(l >> 8)
+				z[3] = byte(l)
+				l -= 2
+				z[4] = byte(l >> 8)
+				z[5] = byte(l)
+				z = z[6:]
+				for _, curve := range m.supportedCurves {
+					z[0] = byte(curve >> 8)
+					z[1] = byte(curve)
+					z = z[2:]
+				}
+			})
+	}
+	if len(m.supportedPoints) > 0 {
+		extensionsLength += 1 + len(m.supportedPoints)
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				// http://tools.ietf.org/html/rfc4492#section-5.5.2
+				z[0] = byte(extensionSupportedPoints >> 8)
+				z[1] = byte(extensionSupportedPoints)
+				l := 1 + len(m.supportedPoints)
+				z[2] = byte(l >> 8)
+				z[3] = byte(l)
+				l--
+				z[4] = byte(l)
+				z = z[5:]
+				for _, pointFormat := range m.supportedPoints {
+					z[0] = pointFormat
+					z = z[1:]
+				}
+			})
+	}
+	if m.ticketSupported {
+		extensionsLength += len(m.sessionTicket)
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				// http://tools.ietf.org/html/rfc5077#section-3.2
+				z[0] = byte(extensionSessionTicket >> 8)
+				z[1] = byte(extensionSessionTicket)
+				l := len(m.sessionTicket)
+				z[2] = byte(l >> 8)
+				z[3] = byte(l)
+				z = z[4:]
+				copy(z, m.sessionTicket)
+				z = z[len(m.sessionTicket):]
+			})
+	}
+	if len(m.supportedSignatureAlgorithms) > 0 {
+		extensionsLength += 2 + 2*len(m.supportedSignatureAlgorithms)
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
+			})
+	}
+	if m.getSignatureAlgorithmsCert() != nil {
+		extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				// Ensure only one list of algorithms is sent if supported_algorithms and supported_algorithms_cert are the same
+				z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
+			})
+	}
+	if m.secureRenegotiationSupported && common.FlipCoin() { // May be omitted
+		extensionsLength += 1 + len(m.secureRenegotiation)
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				z[0] = byte(extensionRenegotiationInfo >> 8)
+				z[1] = byte(extensionRenegotiationInfo & 0xff)
+				z[2] = 0
+				z[3] = byte(len(m.secureRenegotiation) + 1)
+				z[4] = byte(len(m.secureRenegotiation))
+				z = z[5:]
+				copy(z, m.secureRenegotiation)
+				z = z[len(m.secureRenegotiation):]
+			})
+	}
+	if len(m.alpnProtocols) > 0 {
+		extensionsLength += 2
+		for _, s := range m.alpnProtocols {
+			if l := len(s); l == 0 || l > 255 {
+				panic("invalid ALPN protocol")
+			}
+			extensionsLength++
+			extensionsLength += len(s)
+		}
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				z[0] = byte(extensionALPN >> 8)
+				z[1] = byte(extensionALPN & 0xff)
+				lengths := z[2:]
+				z = z[6:]
+
+				stringsLength := 0
+				for _, s := range m.alpnProtocols {
+					l := len(s)
+					z[0] = byte(l)
+					copy(z[1:], s)
+					z = z[1+l:]
+					stringsLength += 1 + l
+				}
+
+				lengths[2] = byte(stringsLength >> 8)
+				lengths[3] = byte(stringsLength)
+				stringsLength += 2
+				lengths[0] = byte(stringsLength >> 8)
+				lengths[1] = byte(stringsLength)
+			})
+	}
+	if m.scts && common.FlipCoin() { // May be omitted
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				// https://tools.ietf.org/html/rfc6962#section-3.3.1
+				z[0] = byte(extensionSCT >> 8)
+				z[1] = byte(extensionSCT)
+				// zero uint16 for the zero-length extension_data
+				z = z[4:]
+			})
+	}
+	if len(m.keyShares) > 0 {
+		extensionsLength += 2
+		for _, k := range m.keyShares {
+			extensionsLength += 4 + len(k.data)
+		}
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
+				z[0] = byte(extensionKeyShare >> 8)
+				z[1] = byte(extensionKeyShare)
+				lengths := z[2:]
+				z = z[6:]
+
+				totalLength := 0
+				for _, ks := range m.keyShares {
+					z[0] = byte(ks.group >> 8)
+					z[1] = byte(ks.group)
+					z[2] = byte(len(ks.data) >> 8)
+					z[3] = byte(len(ks.data))
+					copy(z[4:], ks.data)
+					z = z[4+len(ks.data):]
+					totalLength += 4 + len(ks.data)
+				}
+
+				lengths[2] = byte(totalLength >> 8)
+				lengths[3] = byte(totalLength)
+				totalLength += 2
+				lengths[0] = byte(totalLength >> 8)
+				lengths[1] = byte(totalLength)
+			})
+	}
+	if len(m.supportedVersions) > 0 {
+		extensionsLength += 1 + 2*len(m.supportedVersions)
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				z[0] = byte(extensionSupportedVersions >> 8)
+				z[1] = byte(extensionSupportedVersions)
+				l := 1 + 2*len(m.supportedVersions)
+				z[2] = byte(l >> 8)
+				z[3] = byte(l)
+				l -= 1
+				z[4] = byte(l)
+				z = z[5:]
+				for _, v := range m.supportedVersions {
+					z[0] = byte(v >> 8)
+					z[1] = byte(v)
+					z = z[2:]
+				}
+			})
+	}
+	if m.earlyData {
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				z[0] = byte(extensionEarlyData >> 8)
+				z[1] = byte(extensionEarlyData)
+				z = z[4:]
+			})
+	}
+	if m.delegatedCredential {
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
+				z = z[4:]
+			})
+	}
+
+	// Optional, additional extensions
+
+	// TODO: GREASE, Extended Master Secret (https://github.com/cloudflare/tls-tris/pull/30)
+
+	if common.FlipCoin() {
+		numExtensions++
+		extensionMarshalers = append(extensionMarshalers,
+			func() {
+				extensionChannelID := uint16(30032)
+				z[0] = byte(extensionChannelID >> 8)
+				z[1] = byte(extensionChannelID & 0xff)
+				z = z[4:]
+			})
+	}
+
+	preExtensionLength := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
+
+	if common.FlipCoin() {
+
+		// Padding must be last, since it depends on extensionsLength
+
+		// Logic from:
+		// https://github.com/google/boringssl/blob/46db7af2c998cf8514d606408546d9be9699f03c/ssl/t1_lib.c#L2803
+		// https://github.com/google/boringssl/blob/master/LICENSE
+
+		unpaddedLength := preExtensionLength
+		if numExtensions > 0 {
+			unpaddedLength += 2 + 4*numExtensions + extensionsLength
+		}
+		if unpaddedLength > 0xff && unpaddedLength < 0x200 {
+			paddingLength := uint16(0x200) - uint16(unpaddedLength)
+			if paddingLength >= 4+1 {
+				paddingLength -= 4
+			} else {
+				paddingLength = 1
+			}
+			extensionsLength += int(paddingLength)
+			numExtensions++
+			extensionMarshalers = append(extensionMarshalers,
+				func() {
+					extensionPadding := uint16(21)
+					z[0] = byte(extensionPadding >> 8)
+					z[1] = byte(extensionPadding & 0xff)
+					z[2] = byte(paddingLength >> 8)
+					z[3] = byte(paddingLength)
+					z = z[4+paddingLength:]
+				})
+		}
+	}
+
+	permute(
+		len(extensionMarshalers),
+		func(i, j int) {
+			extensionMarshalers[i], extensionMarshalers[j] = extensionMarshalers[j], extensionMarshalers[i]
+		})
+
+	length := preExtensionLength
+
+	if numExtensions > 0 {
+		extensionsLength += 4 * numExtensions
+		length += 2 + extensionsLength
+	}
+
+	x := make([]byte, 4+length)
+	x[0] = typeClientHello
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	x[4] = uint8(m.vers >> 8)
+	x[5] = uint8(m.vers)
+	copy(x[6:38], m.random)
+	x[38] = uint8(len(m.sessionId))
+	copy(x[39:39+len(m.sessionId)], m.sessionId)
+	y := x[39+len(m.sessionId):]
+	y[0] = uint8(len(m.cipherSuites) >> 7)
+	y[1] = uint8(len(m.cipherSuites) << 1)
+	for i, suite := range m.cipherSuites {
+		y[2+i*2] = uint8(suite >> 8)
+		y[3+i*2] = uint8(suite)
+	}
+	z = y[2+len(m.cipherSuites)*2:]
+	z[0] = uint8(len(m.compressionMethods))
+	copy(z[1:], m.compressionMethods)
+	z = z[1+len(m.compressionMethods):]
+
+	if numExtensions > 0 {
+		z[0] = byte(extensionsLength >> 8)
+		z[1] = byte(extensionsLength)
+		z = z[2:]
+		for _, extensionMarshaler := range extensionMarshalers {
+			extensionMarshaler()
+		}
+	}
+
+	m.raw = x
+
+	return x
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) alert {
+	if len(data) < 42 {
+		return alertDecodeError
+	}
+	m.raw = data
+	m.vers = uint16(data[4])<<8 | uint16(data[5])
+	m.random = data[6:38]
+	sessionIdLen := int(data[38])
+	if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+		return alertDecodeError
+	}
+	m.sessionId = data[39 : 39+sessionIdLen]
+	data = data[39+sessionIdLen:]
+	bindersOffset := 39 + sessionIdLen
+	if len(data) < 2 {
+		return alertDecodeError
+	}
+	// cipherSuiteLen is the number of bytes of cipher suite numbers. Since
+	// they are uint16s, the number must be even.
+	cipherSuiteLen := int(data[0])<<8 | int(data[1])
+	if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
+		return alertDecodeError
+	}
+	numCipherSuites := cipherSuiteLen / 2
+	m.cipherSuites = make([]uint16, numCipherSuites)
+	for i := 0; i < numCipherSuites; i++ {
+		m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+		if m.cipherSuites[i] == scsvRenegotiation {
+			m.secureRenegotiationSupported = true
+		}
+	}
+	data = data[2+cipherSuiteLen:]
+	bindersOffset += 2 + cipherSuiteLen
+	if len(data) < 1 {
+		return alertDecodeError
+	}
+	compressionMethodsLen := int(data[0])
+	if len(data) < 1+compressionMethodsLen {
+		return alertDecodeError
+	}
+	m.compressionMethods = data[1 : 1+compressionMethodsLen]
+
+	data = data[1+compressionMethodsLen:]
+	bindersOffset += 1 + compressionMethodsLen
+
+	m.nextProtoNeg = false
+	m.serverName = ""
+	m.ocspStapling = false
+	m.ticketSupported = false
+	m.sessionTicket = nil
+	m.supportedSignatureAlgorithms = nil
+	m.alpnProtocols = nil
+	m.scts = false
+	m.keyShares = nil
+	m.supportedVersions = nil
+	m.psks = nil
+	m.pskKeyExchangeModes = nil
+	m.earlyData = false
+	m.delegatedCredential = false
+
+	if len(data) == 0 {
+		// ClientHello is optionally followed by extension data
+		return alertSuccess
+	}
+	if len(data) < 2 {
+		return alertDecodeError
+	}
+
+	extensionsLength := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+	bindersOffset += 2
+	if extensionsLength != len(data) {
+		return alertDecodeError
+	}
+
+	for len(data) != 0 {
+		if len(data) < 4 {
+			return alertDecodeError
+		}
+		extension := uint16(data[0])<<8 | uint16(data[1])
+		length := int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		bindersOffset += 4
+		if len(data) < length {
+			return alertDecodeError
+		}
+
+		switch extension {
+		case extensionServerName:
+			d := data[:length]
+			if len(d) < 2 {
+				return alertDecodeError
+			}
+			namesLen := int(d[0])<<8 | int(d[1])
+			d = d[2:]
+			if len(d) != namesLen {
+				return alertDecodeError
+			}
+			for len(d) > 0 {
+				if len(d) < 3 {
+					return alertDecodeError
+				}
+				nameType := d[0]
+				nameLen := int(d[1])<<8 | int(d[2])
+				d = d[3:]
+				if len(d) < nameLen {
+					return alertDecodeError
+				}
+				if nameType == 0 {
+					m.serverName = string(d[:nameLen])
+					// An SNI value may not include a
+					// trailing dot. See
+					// https://tools.ietf.org/html/rfc6066#section-3.
+					if strings.HasSuffix(m.serverName, ".") {
+						// TODO use alertDecodeError?
+						return alertUnexpectedMessage
+					}
+					break
+				}
+				d = d[nameLen:]
+			}
+		case extensionNextProtoNeg:
+			if length > 0 {
+				return alertDecodeError
+			}
+			m.nextProtoNeg = true
+		case extensionStatusRequest:
+			m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
+		case extensionSupportedCurves:
+			// http://tools.ietf.org/html/rfc4492#section-5.5.1
+			// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
+			if length < 2 {
+				return alertDecodeError
+			}
+			l := int(data[0])<<8 | int(data[1])
+			if l%2 == 1 || length != l+2 {
+				return alertDecodeError
+			}
+			numCurves := l / 2
+			m.supportedCurves = make([]CurveID, numCurves)
+			d := data[2:]
+			for i := 0; i < numCurves; i++ {
+				m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
+				d = d[2:]
+			}
+		case extensionSupportedPoints:
+			// http://tools.ietf.org/html/rfc4492#section-5.5.2
+			if length < 1 {
+				return alertDecodeError
+			}
+			l := int(data[0])
+			if length != l+1 {
+				return alertDecodeError
+			}
+			m.supportedPoints = make([]uint8, l)
+			copy(m.supportedPoints, data[1:])
+		case extensionSessionTicket:
+			// http://tools.ietf.org/html/rfc5077#section-3.2
+			m.ticketSupported = true
+			m.sessionTicket = data[:length]
+		case extensionSignatureAlgorithms:
+			// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+			// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3
+			if length < 2 || length&1 != 0 {
+				return alertDecodeError
+			}
+			l := int(data[0])<<8 | int(data[1])
+			if l != length-2 {
+				return alertDecodeError
+			}
+			n := l / 2
+			d := data[2:]
+			m.supportedSignatureAlgorithms = make([]SignatureScheme, n)
+			for i := range m.supportedSignatureAlgorithms {
+				m.supportedSignatureAlgorithms[i] = SignatureScheme(d[0])<<8 | SignatureScheme(d[1])
+				d = d[2:]
+			}
+		case extensionRenegotiationInfo:
+			if length == 0 {
+				return alertDecodeError
+			}
+			d := data[:length]
+			l := int(d[0])
+			d = d[1:]
+			if l != len(d) {
+				return alertDecodeError
+			}
+
+			m.secureRenegotiation = d
+			m.secureRenegotiationSupported = true
+		case extensionALPN:
+			if length < 2 {
+				return alertDecodeError
+			}
+			l := int(data[0])<<8 | int(data[1])
+			if l != length-2 {
+				return alertDecodeError
+			}
+			d := data[2:length]
+			for len(d) != 0 {
+				stringLen := int(d[0])
+				d = d[1:]
+				if stringLen == 0 || stringLen > len(d) {
+					return alertDecodeError
+				}
+				m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
+				d = d[stringLen:]
+			}
+		case extensionSCT:
+			m.scts = true
+			if length != 0 {
+				return alertDecodeError
+			}
+		case extensionKeyShare:
+			// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
+			if length < 2 {
+				return alertDecodeError
+			}
+			l := int(data[0])<<8 | int(data[1])
+			if l != length-2 {
+				return alertDecodeError
+			}
+			d := data[2:length]
+			for len(d) != 0 {
+				if len(d) < 4 {
+					return alertDecodeError
+				}
+				dataLen := int(d[2])<<8 | int(d[3])
+				if dataLen == 0 || 4+dataLen > len(d) {
+					return alertDecodeError
+				}
+				m.keyShares = append(m.keyShares, keyShare{
+					group: CurveID(d[0])<<8 | CurveID(d[1]),
+					data:  d[4 : 4+dataLen],
+				})
+				d = d[4+dataLen:]
+			}
+		case extensionSupportedVersions:
+			// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.1
+			if length < 1 {
+				return alertDecodeError
+			}
+			l := int(data[0])
+			if l%2 == 1 || length != l+1 {
+				return alertDecodeError
+			}
+			n := l / 2
+			d := data[1:]
+			for i := 0; i < n; i++ {
+				v := uint16(d[0])<<8 + uint16(d[1])
+				m.supportedVersions = append(m.supportedVersions, v)
+				d = d[2:]
+			}
+		case extensionPreSharedKey:
+			// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6
+			if length < 2 {
+				return alertDecodeError
+			}
+			// Ensure this extension is the last one in the Client Hello
+			if len(data) != length {
+				return alertIllegalParameter
+			}
+			li := int(data[0])<<8 | int(data[1])
+			if 2+li+2 > length {
+				return alertDecodeError
+			}
+			d := data[2 : 2+li]
+			bindersOffset += 2 + li
+			for len(d) > 0 {
+				if len(d) < 6 {
+					return alertDecodeError
+				}
+				l := int(d[0])<<8 | int(d[1])
+				if len(d) < 2+l+4 {
+					return alertDecodeError
+				}
+				m.psks = append(m.psks, psk{
+					identity: d[2 : 2+l],
+					obfTicketAge: uint32(d[l+2])<<24 | uint32(d[l+3])<<16 |
+						uint32(d[l+4])<<8 | uint32(d[l+5]),
+				})
+				d = d[2+l+4:]
+			}
+			lb := int(data[li+2])<<8 | int(data[li+3])
+			d = data[2+li+2:]
+			if lb != len(d) || lb == 0 {
+				return alertDecodeError
+			}
+			i := 0
+			for len(d) > 0 {
+				if i >= len(m.psks) {
+					return alertIllegalParameter
+				}
+				if len(d) < 1 {
+					return alertDecodeError
+				}
+				l := int(d[0])
+				if l > len(d)-1 {
+					return alertDecodeError
+				}
+				if i >= len(m.psks) {
+					return alertIllegalParameter
+				}
+				m.psks[i].binder = d[1 : 1+l]
+				d = d[1+l:]
+				i++
+			}
+			if i != len(m.psks) {
+				return alertIllegalParameter
+			}
+			m.rawTruncated = m.raw[:bindersOffset]
+		case extensionPSKKeyExchangeModes:
+			if length < 2 {
+				return alertDecodeError
+			}
+			l := int(data[0])
+			if length != l+1 {
+				return alertDecodeError
+			}
+			m.pskKeyExchangeModes = data[1:length]
+		case extensionEarlyData:
+			// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8
+			m.earlyData = true
+		case extensionDelegatedCredential:
+			// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02
+			m.delegatedCredential = true
+		}
+		data = data[length:]
+		bindersOffset += length
+	}
+
+	return alertSuccess
+}
+
+func (m *clientHelloMsg) getSignatureAlgorithmsCert() []SignatureScheme {
+	return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
+}
+
+type serverHelloMsg struct {
+	raw                          []byte
+	vers                         uint16
+	random                       []byte
+	sessionId                    []byte
+	cipherSuite                  uint16
+	compressionMethod            uint8
+	nextProtoNeg                 bool
+	nextProtos                   []string
+	ocspStapling                 bool
+	scts                         [][]byte
+	ticketSupported              bool
+	secureRenegotiation          []byte
+	secureRenegotiationSupported bool
+	alpnProtocol                 string
+
+	// TLS 1.3
+	keyShare    keyShare
+	psk         bool
+	pskIdentity uint16
+}
+
+func (m *serverHelloMsg) equal(i interface{}) bool {
+	m1, ok := i.(*serverHelloMsg)
+	if !ok {
+		return false
+	}
+
+	if len(m.scts) != len(m1.scts) {
+		return false
+	}
+	for i, sct := range m.scts {
+		if !bytes.Equal(sct, m1.scts[i]) {
+			return false
+		}
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.vers == m1.vers &&
+		bytes.Equal(m.random, m1.random) &&
+		bytes.Equal(m.sessionId, m1.sessionId) &&
+		m.cipherSuite == m1.cipherSuite &&
+		m.compressionMethod == m1.compressionMethod &&
+		m.nextProtoNeg == m1.nextProtoNeg &&
+		eqStrings(m.nextProtos, m1.nextProtos) &&
+		m.ocspStapling == m1.ocspStapling &&
+		m.ticketSupported == m1.ticketSupported &&
+		m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
+		bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
+		m.alpnProtocol == m1.alpnProtocol &&
+		m.keyShare.group == m1.keyShare.group &&
+		bytes.Equal(m.keyShare.data, m1.keyShare.data) &&
+		m.psk == m1.psk &&
+		m.pskIdentity == m1.pskIdentity
+}
+
+func (m *serverHelloMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	length := 38 + len(m.sessionId)
+	numExtensions := 0
+	extensionsLength := 0
+
+	nextProtoLen := 0
+	if m.nextProtoNeg {
+		numExtensions++
+		for _, v := range m.nextProtos {
+			nextProtoLen += len(v)
+		}
+		nextProtoLen += len(m.nextProtos)
+		extensionsLength += nextProtoLen
+	}
+	if m.ocspStapling {
+		numExtensions++
+	}
+	if m.ticketSupported {
+		numExtensions++
+	}
+	if m.secureRenegotiationSupported {
+		extensionsLength += 1 + len(m.secureRenegotiation)
+		numExtensions++
+	}
+	if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
+		if alpnLen >= 256 {
+			panic("invalid ALPN protocol")
+		}
+		extensionsLength += 2 + 1 + alpnLen
+		numExtensions++
+	}
+	sctLen := 0
+	if len(m.scts) > 0 {
+		for _, sct := range m.scts {
+			sctLen += len(sct) + 2
+		}
+		extensionsLength += 2 + sctLen
+		numExtensions++
+	}
+	if m.keyShare.group != 0 {
+		extensionsLength += 4 + len(m.keyShare.data)
+		numExtensions++
+	}
+	if m.psk {
+		extensionsLength += 2
+		numExtensions++
+	}
+	// supported_versions extension
+	if m.vers >= VersionTLS13 {
+		extensionsLength += 2
+		numExtensions++
+	}
+
+	if numExtensions > 0 {
+		extensionsLength += 4 * numExtensions
+		length += 2 + extensionsLength
+	}
+
+	x := make([]byte, 4+length)
+	x[0] = typeServerHello
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	if m.vers >= VersionTLS13 {
+		x[4] = 3
+		x[5] = 3
+	} else {
+		x[4] = uint8(m.vers >> 8)
+		x[5] = uint8(m.vers)
+	}
+	copy(x[6:38], m.random)
+	z := x[38:]
+	x[38] = uint8(len(m.sessionId))
+	copy(x[39:39+len(m.sessionId)], m.sessionId)
+	z = x[39+len(m.sessionId):]
+	z[0] = uint8(m.cipherSuite >> 8)
+	z[1] = uint8(m.cipherSuite)
+	z[2] = m.compressionMethod
+	z = z[3:]
+
+	if numExtensions > 0 {
+		z[0] = byte(extensionsLength >> 8)
+		z[1] = byte(extensionsLength)
+		z = z[2:]
+	}
+	if m.vers >= VersionTLS13 {
+		z[0] = byte(extensionSupportedVersions >> 8)
+		z[1] = byte(extensionSupportedVersions)
+		z[3] = 2
+		z[4] = uint8(m.vers >> 8)
+		z[5] = uint8(m.vers)
+		z = z[6:]
+	}
+	if m.nextProtoNeg {
+		z[0] = byte(extensionNextProtoNeg >> 8)
+		z[1] = byte(extensionNextProtoNeg & 0xff)
+		z[2] = byte(nextProtoLen >> 8)
+		z[3] = byte(nextProtoLen)
+		z = z[4:]
+
+		for _, v := range m.nextProtos {
+			l := len(v)
+			if l > 255 {
+				l = 255
+			}
+			z[0] = byte(l)
+			copy(z[1:], []byte(v[0:l]))
+			z = z[1+l:]
+		}
+	}
+	if m.ocspStapling {
+		z[0] = byte(extensionStatusRequest >> 8)
+		z[1] = byte(extensionStatusRequest)
+		z = z[4:]
+	}
+	if m.ticketSupported {
+		z[0] = byte(extensionSessionTicket >> 8)
+		z[1] = byte(extensionSessionTicket)
+		z = z[4:]
+	}
+	if m.secureRenegotiationSupported {
+		z[0] = byte(extensionRenegotiationInfo >> 8)
+		z[1] = byte(extensionRenegotiationInfo & 0xff)
+		z[2] = 0
+		z[3] = byte(len(m.secureRenegotiation) + 1)
+		z[4] = byte(len(m.secureRenegotiation))
+		z = z[5:]
+		copy(z, m.secureRenegotiation)
+		z = z[len(m.secureRenegotiation):]
+	}
+	if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
+		z[0] = byte(extensionALPN >> 8)
+		z[1] = byte(extensionALPN & 0xff)
+		l := 2 + 1 + alpnLen
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		l -= 2
+		z[4] = byte(l >> 8)
+		z[5] = byte(l)
+		l -= 1
+		z[6] = byte(l)
+		copy(z[7:], []byte(m.alpnProtocol))
+		z = z[7+alpnLen:]
+	}
+	if sctLen > 0 {
+		z[0] = byte(extensionSCT >> 8)
+		z[1] = byte(extensionSCT)
+		l := sctLen + 2
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z[4] = byte(sctLen >> 8)
+		z[5] = byte(sctLen)
+
+		z = z[6:]
+		for _, sct := range m.scts {
+			z[0] = byte(len(sct) >> 8)
+			z[1] = byte(len(sct))
+			copy(z[2:], sct)
+			z = z[len(sct)+2:]
+		}
+	}
+	if m.keyShare.group != 0 {
+		z[0] = uint8(extensionKeyShare >> 8)
+		z[1] = uint8(extensionKeyShare)
+		l := 4 + len(m.keyShare.data)
+		z[2] = uint8(l >> 8)
+		z[3] = uint8(l)
+		z[4] = uint8(m.keyShare.group >> 8)
+		z[5] = uint8(m.keyShare.group)
+		l -= 4
+		z[6] = uint8(l >> 8)
+		z[7] = uint8(l)
+		copy(z[8:], m.keyShare.data)
+		z = z[8+l:]
+	}
+
+	if m.psk {
+		z[0] = byte(extensionPreSharedKey >> 8)
+		z[1] = byte(extensionPreSharedKey)
+		z[3] = 2
+		z[4] = byte(m.pskIdentity >> 8)
+		z[5] = byte(m.pskIdentity)
+		z = z[6:]
+	}
+
+	m.raw = x
+
+	return x
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) alert {
+	if len(data) < 42 {
+		return alertDecodeError
+	}
+	m.raw = data
+	m.vers = uint16(data[4])<<8 | uint16(data[5])
+	m.random = data[6:38]
+	sessionIdLen := int(data[38])
+	if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+		return alertDecodeError
+	}
+	m.sessionId = data[39 : 39+sessionIdLen]
+	data = data[39+sessionIdLen:]
+	if len(data) < 3 {
+		return alertDecodeError
+	}
+	m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
+	m.compressionMethod = data[2]
+	data = data[3:]
+
+	m.nextProtoNeg = false
+	m.nextProtos = nil
+	m.ocspStapling = false
+	m.scts = nil
+	m.ticketSupported = false
+	m.alpnProtocol = ""
+	m.keyShare.group = 0
+	m.keyShare.data = nil
+	m.psk = false
+	m.pskIdentity = 0
+
+	if len(data) == 0 {
+		// ServerHello is optionally followed by extension data
+		return alertSuccess
+	}
+	if len(data) < 2 {
+		return alertDecodeError
+	}
+
+	extensionsLength := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+	if len(data) != extensionsLength {
+		return alertDecodeError
+	}
+
+	svData := findExtension(data, extensionSupportedVersions)
+	if svData != nil {
+		if len(svData) != 2 {
+			return alertDecodeError
+		}
+		if m.vers != VersionTLS12 {
+			return alertDecodeError
+		}
+		rcvVer := binary.BigEndian.Uint16(svData[0:])
+		if rcvVer < VersionTLS13 {
+			return alertIllegalParameter
+		}
+		m.vers = rcvVer
+	}
+
+	for len(data) != 0 {
+		if len(data) < 4 {
+			return alertDecodeError
+		}
+		extension := uint16(data[0])<<8 | uint16(data[1])
+		length := int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		if len(data) < length {
+			return alertDecodeError
+		}
+
+		switch extension {
+		case extensionNextProtoNeg:
+			m.nextProtoNeg = true
+			d := data[:length]
+			for len(d) > 0 {
+				l := int(d[0])
+				d = d[1:]
+				if l == 0 || l > len(d) {
+					return alertDecodeError
+				}
+				m.nextProtos = append(m.nextProtos, string(d[:l]))
+				d = d[l:]
+			}
+		case extensionStatusRequest:
+			if length > 0 {
+				return alertDecodeError
+			}
+			m.ocspStapling = true
+		case extensionSessionTicket:
+			if length > 0 {
+				return alertDecodeError
+			}
+			m.ticketSupported = true
+		case extensionRenegotiationInfo:
+			if length == 0 {
+				return alertDecodeError
+			}
+			d := data[:length]
+			l := int(d[0])
+			d = d[1:]
+			if l != len(d) {
+				return alertDecodeError
+			}
+
+			m.secureRenegotiation = d
+			m.secureRenegotiationSupported = true
+		case extensionALPN:
+			d := data[:length]
+			if len(d) < 3 {
+				return alertDecodeError
+			}
+			l := int(d[0])<<8 | int(d[1])
+			if l != len(d)-2 {
+				return alertDecodeError
+			}
+			d = d[2:]
+			l = int(d[0])
+			if l != len(d)-1 {
+				return alertDecodeError
+			}
+			d = d[1:]
+			if len(d) == 0 {
+				// ALPN protocols must not be empty.
+				return alertDecodeError
+			}
+			m.alpnProtocol = string(d)
+		case extensionSCT:
+			d := data[:length]
+
+			if len(d) < 2 {
+				return alertDecodeError
+			}
+			l := int(d[0])<<8 | int(d[1])
+			d = d[2:]
+			if len(d) != l || l == 0 {
+				return alertDecodeError
+			}
+
+			m.scts = make([][]byte, 0, 3)
+			for len(d) != 0 {
+				if len(d) < 2 {
+					return alertDecodeError
+				}
+				sctLen := int(d[0])<<8 | int(d[1])
+				d = d[2:]
+				if sctLen == 0 || len(d) < sctLen {
+					return alertDecodeError
+				}
+				m.scts = append(m.scts, d[:sctLen])
+				d = d[sctLen:]
+			}
+		case extensionKeyShare:
+			d := data[:length]
+
+			if len(d) < 4 {
+				return alertDecodeError
+			}
+			m.keyShare.group = CurveID(d[0])<<8 | CurveID(d[1])
+			l := int(d[2])<<8 | int(d[3])
+			d = d[4:]
+			if len(d) != l {
+				return alertDecodeError
+			}
+			m.keyShare.data = d[:l]
+		case extensionPreSharedKey:
+			if length != 2 {
+				return alertDecodeError
+			}
+			m.psk = true
+			m.pskIdentity = uint16(data[0])<<8 | uint16(data[1])
+		}
+		data = data[length:]
+	}
+
+	return alertSuccess
+}
+
+type encryptedExtensionsMsg struct {
+	raw          []byte
+	alpnProtocol string
+	earlyData    bool
+}
+
+func (m *encryptedExtensionsMsg) equal(i interface{}) bool {
+	m1, ok := i.(*encryptedExtensionsMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.alpnProtocol == m1.alpnProtocol &&
+		m.earlyData == m1.earlyData
+}
+
+func (m *encryptedExtensionsMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	length := 2
+
+	if m.earlyData {
+		length += 4
+	}
+	alpnLen := len(m.alpnProtocol)
+	if alpnLen > 0 {
+		if alpnLen >= 256 {
+			panic("invalid ALPN protocol")
+		}
+		length += 2 + 2 + 2 + 1 + alpnLen
+	}
+
+	x := make([]byte, 4+length)
+	x[0] = typeEncryptedExtensions
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	length -= 2
+	x[4] = uint8(length >> 8)
+	x[5] = uint8(length)
+
+	z := x[6:]
+	if alpnLen > 0 {
+		z[0] = byte(extensionALPN >> 8)
+		z[1] = byte(extensionALPN)
+		l := 2 + 1 + alpnLen
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		l -= 2
+		z[4] = byte(l >> 8)
+		z[5] = byte(l)
+		l -= 1
+		z[6] = byte(l)
+		copy(z[7:], []byte(m.alpnProtocol))
+		z = z[7+alpnLen:]
+	}
+
+	if m.earlyData {
+		z[0] = byte(extensionEarlyData >> 8)
+		z[1] = byte(extensionEarlyData)
+		z = z[4:]
+	}
+
+	m.raw = x
+	return x
+}
+
+func (m *encryptedExtensionsMsg) unmarshal(data []byte) alert {
+	if len(data) < 6 {
+		return alertDecodeError
+	}
+	m.raw = data
+
+	m.alpnProtocol = ""
+	m.earlyData = false
+
+	extensionsLength := int(data[4])<<8 | int(data[5])
+	data = data[6:]
+	if len(data) != extensionsLength {
+		return alertDecodeError
+	}
+
+	for len(data) != 0 {
+		if len(data) < 4 {
+			return alertDecodeError
+		}
+		extension := uint16(data[0])<<8 | uint16(data[1])
+		length := int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		if len(data) < length {
+			return alertDecodeError
+		}
+
+		switch extension {
+		case extensionALPN:
+			d := data[:length]
+			if len(d) < 3 {
+				return alertDecodeError
+			}
+			l := int(d[0])<<8 | int(d[1])
+			if l != len(d)-2 {
+				return alertDecodeError
+			}
+			d = d[2:]
+			l = int(d[0])
+			if l != len(d)-1 {
+				return alertDecodeError
+			}
+			d = d[1:]
+			if len(d) == 0 {
+				// ALPN protocols must not be empty.
+				return alertDecodeError
+			}
+			m.alpnProtocol = string(d)
+		case extensionEarlyData:
+			// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8
+			m.earlyData = true
+		}
+
+		data = data[length:]
+	}
+
+	return alertSuccess
+}
+
+type certificateMsg struct {
+	raw          []byte
+	certificates [][]byte
+}
+
+func (m *certificateMsg) equal(i interface{}) bool {
+	m1, ok := i.(*certificateMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		eqByteSlices(m.certificates, m1.certificates)
+}
+
+func (m *certificateMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var i int
+	for _, slice := range m.certificates {
+		i += len(slice)
+	}
+
+	length := 3 + 3*len(m.certificates) + i
+	x = make([]byte, 4+length)
+	x[0] = typeCertificate
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	certificateOctets := length - 3
+	x[4] = uint8(certificateOctets >> 16)
+	x[5] = uint8(certificateOctets >> 8)
+	x[6] = uint8(certificateOctets)
+
+	y := x[7:]
+	for _, slice := range m.certificates {
+		y[0] = uint8(len(slice) >> 16)
+		y[1] = uint8(len(slice) >> 8)
+		y[2] = uint8(len(slice))
+		copy(y[3:], slice)
+		y = y[3+len(slice):]
+	}
+
+	m.raw = x
+	return
+}
+
+func (m *certificateMsg) unmarshal(data []byte) alert {
+	if len(data) < 7 {
+		return alertDecodeError
+	}
+
+	m.raw = data
+	certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
+	if uint32(len(data)) != certsLen+7 {
+		return alertDecodeError
+	}
+
+	numCerts := 0
+	d := data[7:]
+	for certsLen > 0 {
+		if len(d) < 4 {
+			return alertDecodeError
+		}
+		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+		if uint32(len(d)) < 3+certLen {
+			return alertDecodeError
+		}
+		d = d[3+certLen:]
+		certsLen -= 3 + certLen
+		numCerts++
+	}
+
+	m.certificates = make([][]byte, numCerts)
+	d = data[7:]
+	for i := 0; i < numCerts; i++ {
+		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+		m.certificates[i] = d[3 : 3+certLen]
+		d = d[3+certLen:]
+	}
+
+	return alertSuccess
+}
+
+type certificateEntry struct {
+	data                []byte
+	ocspStaple          []byte
+	sctList             [][]byte
+	delegatedCredential []byte
+}
+
+type certificateMsg13 struct {
+	raw            []byte
+	requestContext []byte
+	certificates   []certificateEntry
+}
+
+func (m *certificateMsg13) equal(i interface{}) bool {
+	m1, ok := i.(*certificateMsg13)
+	if !ok {
+		return false
+	}
+
+	if len(m.certificates) != len(m1.certificates) {
+		return false
+	}
+	for i, _ := range m.certificates {
+		ok := bytes.Equal(m.certificates[i].data, m1.certificates[i].data)
+		ok = ok && bytes.Equal(m.certificates[i].ocspStaple, m1.certificates[i].ocspStaple)
+		ok = ok && eqByteSlices(m.certificates[i].sctList, m1.certificates[i].sctList)
+		ok = ok && bytes.Equal(m.certificates[i].delegatedCredential, m1.certificates[i].delegatedCredential)
+		if !ok {
+			return false
+		}
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.requestContext, m1.requestContext)
+}
+
+func (m *certificateMsg13) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var i int
+	for _, cert := range m.certificates {
+		i += len(cert.data)
+		if len(cert.ocspStaple) != 0 {
+			i += 8 + len(cert.ocspStaple)
+		}
+		if len(cert.sctList) != 0 {
+			i += 6
+			for _, sct := range cert.sctList {
+				i += 2 + len(sct)
+			}
+		}
+		if len(cert.delegatedCredential) != 0 {
+			i += 4 + len(cert.delegatedCredential)
+		}
+	}
+
+	length := 3 + 3*len(m.certificates) + i
+	length += 2 * len(m.certificates) // extensions
+	length += 1 + len(m.requestContext)
+	x = make([]byte, 4+length)
+	x[0] = typeCertificate
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	z := x[4:]
+
+	z[0] = byte(len(m.requestContext))
+	copy(z[1:], m.requestContext)
+	z = z[1+len(m.requestContext):]
+
+	certificateOctets := len(z) - 3
+	z[0] = uint8(certificateOctets >> 16)
+	z[1] = uint8(certificateOctets >> 8)
+	z[2] = uint8(certificateOctets)
+
+	z = z[3:]
+	for _, cert := range m.certificates {
+		z[0] = uint8(len(cert.data) >> 16)
+		z[1] = uint8(len(cert.data) >> 8)
+		z[2] = uint8(len(cert.data))
+		copy(z[3:], cert.data)
+		z = z[3+len(cert.data):]
+
+		extLenPos := z[:2]
+		z = z[2:]
+
+		extensionLen := 0
+		if len(cert.ocspStaple) != 0 {
+			stapleLen := 4 + len(cert.ocspStaple)
+			z[0] = uint8(extensionStatusRequest >> 8)
+			z[1] = uint8(extensionStatusRequest)
+			z[2] = uint8(stapleLen >> 8)
+			z[3] = uint8(stapleLen)
+
+			stapleLen -= 4
+			z[4] = statusTypeOCSP
+			z[5] = uint8(stapleLen >> 16)
+			z[6] = uint8(stapleLen >> 8)
+			z[7] = uint8(stapleLen)
+			copy(z[8:], cert.ocspStaple)
+			z = z[8+stapleLen:]
+
+			extensionLen += 8 + stapleLen
+		}
+		if len(cert.sctList) != 0 {
+			z[0] = uint8(extensionSCT >> 8)
+			z[1] = uint8(extensionSCT)
+			sctLenPos := z[2:6]
+			z = z[6:]
+			extensionLen += 6
+
+			sctLen := 2
+			for _, sct := range cert.sctList {
+				z[0] = uint8(len(sct) >> 8)
+				z[1] = uint8(len(sct))
+				copy(z[2:], sct)
+				z = z[2+len(sct):]
+
+				extensionLen += 2 + len(sct)
+				sctLen += 2 + len(sct)
+			}
+			sctLenPos[0] = uint8(sctLen >> 8)
+			sctLenPos[1] = uint8(sctLen)
+			sctLen -= 2
+			sctLenPos[2] = uint8(sctLen >> 8)
+			sctLenPos[3] = uint8(sctLen)
+		}
+		if len(cert.delegatedCredential) != 0 {
+			binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
+			binary.BigEndian.PutUint16(z[2:], uint16(len(cert.delegatedCredential)))
+			z = z[4:]
+			copy(z, cert.delegatedCredential)
+			z = z[len(cert.delegatedCredential):]
+			extensionLen += 4 + len(cert.delegatedCredential)
+		}
+
+		extLenPos[0] = uint8(extensionLen >> 8)
+		extLenPos[1] = uint8(extensionLen)
+	}
+
+	m.raw = x
+	return
+}
+
+func (m *certificateMsg13) unmarshal(data []byte) alert {
+	if len(data) < 5 {
+		return alertDecodeError
+	}
+
+	m.raw = data
+
+	ctxLen := data[4]
+	if len(data) < int(ctxLen)+5+3 {
+		return alertDecodeError
+	}
+	m.requestContext = data[5 : 5+ctxLen]
+
+	d := data[5+ctxLen:]
+	certsLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+	if uint32(len(d)) != certsLen+3 {
+		return alertDecodeError
+	}
+
+	numCerts := 0
+	d = d[3:]
+	for certsLen > 0 {
+		if len(d) < 4 {
+			return alertDecodeError
+		}
+		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+		if uint32(len(d)) < 3+certLen {
+			return alertDecodeError
+		}
+		d = d[3+certLen:]
+
+		if len(d) < 2 {
+			return alertDecodeError
+		}
+		extLen := uint16(d[0])<<8 | uint16(d[1])
+		if uint16(len(d)) < 2+extLen {
+			return alertDecodeError
+		}
+		d = d[2+extLen:]
+
+		certsLen -= 3 + certLen + 2 + uint32(extLen)
+		numCerts++
+	}
+
+	m.certificates = make([]certificateEntry, numCerts)
+	d = data[8+ctxLen:]
+	for i := 0; i < numCerts; i++ {
+		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+		m.certificates[i].data = d[3 : 3+certLen]
+		d = d[3+certLen:]
+
+		extLen := uint16(d[0])<<8 | uint16(d[1])
+		d = d[2:]
+		for extLen > 0 {
+			if extLen < 4 {
+				return alertDecodeError
+			}
+			typ := uint16(d[0])<<8 | uint16(d[1])
+			bodyLen := uint16(d[2])<<8 | uint16(d[3])
+			if extLen < 4+bodyLen {
+				return alertDecodeError
+			}
+			body := d[4 : 4+bodyLen]
+			d = d[4+bodyLen:]
+			extLen -= 4 + bodyLen
+
+			switch typ {
+			case extensionStatusRequest:
+				if len(body) < 4 || body[0] != 0x01 {
+					return alertDecodeError
+				}
+				ocspLen := int(body[1])<<16 | int(body[2])<<8 | int(body[3])
+				if len(body) != 4+ocspLen {
+					return alertDecodeError
+				}
+				m.certificates[i].ocspStaple = body[4:]
+
+			case extensionSCT:
+				if len(body) < 2 {
+					return alertDecodeError
+				}
+				listLen := int(body[0])<<8 | int(body[1])
+				body = body[2:]
+				if len(body) != listLen {
+					return alertDecodeError
+				}
+				for len(body) > 0 {
+					if len(body) < 2 {
+						return alertDecodeError
+					}
+					sctLen := int(body[0])<<8 | int(body[1])
+					if len(body) < 2+sctLen {
+						return alertDecodeError
+					}
+					m.certificates[i].sctList = append(m.certificates[i].sctList, body[2:2+sctLen])
+					body = body[2+sctLen:]
+				}
+			case extensionDelegatedCredential:
+				m.certificates[i].delegatedCredential = body
+			}
+		}
+	}
+
+	return alertSuccess
+}
+
+type serverKeyExchangeMsg struct {
+	raw []byte
+	key []byte
+}
+
+func (m *serverKeyExchangeMsg) equal(i interface{}) bool {
+	m1, ok := i.(*serverKeyExchangeMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.key, m1.key)
+}
+
+func (m *serverKeyExchangeMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+	length := len(m.key)
+	x := make([]byte, length+4)
+	x[0] = typeServerKeyExchange
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	copy(x[4:], m.key)
+
+	m.raw = x
+	return x
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) alert {
+	m.raw = data
+	if len(data) < 4 {
+		return alertDecodeError
+	}
+	m.key = data[4:]
+	return alertSuccess
+}
+
+type certificateStatusMsg struct {
+	raw        []byte
+	statusType uint8
+	response   []byte
+}
+
+func (m *certificateStatusMsg) equal(i interface{}) bool {
+	m1, ok := i.(*certificateStatusMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.statusType == m1.statusType &&
+		bytes.Equal(m.response, m1.response)
+}
+
+func (m *certificateStatusMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var x []byte
+	if m.statusType == statusTypeOCSP {
+		x = make([]byte, 4+4+len(m.response))
+		x[0] = typeCertificateStatus
+		l := len(m.response) + 4
+		x[1] = byte(l >> 16)
+		x[2] = byte(l >> 8)
+		x[3] = byte(l)
+		x[4] = statusTypeOCSP
+
+		l -= 4
+		x[5] = byte(l >> 16)
+		x[6] = byte(l >> 8)
+		x[7] = byte(l)
+		copy(x[8:], m.response)
+	} else {
+		x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType}
+	}
+
+	m.raw = x
+	return x
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) alert {
+	m.raw = data
+	if len(data) < 5 {
+		return alertDecodeError
+	}
+	m.statusType = data[4]
+
+	m.response = nil
+	if m.statusType == statusTypeOCSP {
+		if len(data) < 8 {
+			return alertDecodeError
+		}
+		respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+		if uint32(len(data)) != 4+4+respLen {
+			return alertDecodeError
+		}
+		m.response = data[8:]
+	}
+	return alertSuccess
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) equal(i interface{}) bool {
+	_, ok := i.(*serverHelloDoneMsg)
+	return ok
+}
+
+func (m *serverHelloDoneMsg) marshal() []byte {
+	x := make([]byte, 4)
+	x[0] = typeServerHelloDone
+	return x
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) alert {
+	if len(data) != 4 {
+		return alertDecodeError
+	}
+	return alertSuccess
+}
+
+type clientKeyExchangeMsg struct {
+	raw        []byte
+	ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) equal(i interface{}) bool {
+	m1, ok := i.(*clientKeyExchangeMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.ciphertext, m1.ciphertext)
+}
+
+func (m *clientKeyExchangeMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+	length := len(m.ciphertext)
+	x := make([]byte, length+4)
+	x[0] = typeClientKeyExchange
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	copy(x[4:], m.ciphertext)
+
+	m.raw = x
+	return x
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) alert {
+	m.raw = data
+	if len(data) < 4 {
+		return alertDecodeError
+	}
+	l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+	if l != len(data)-4 {
+		return alertDecodeError
+	}
+	m.ciphertext = data[4:]
+	return alertSuccess
+}
+
+type finishedMsg struct {
+	raw        []byte
+	verifyData []byte
+}
+
+func (m *finishedMsg) equal(i interface{}) bool {
+	m1, ok := i.(*finishedMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.verifyData, m1.verifyData)
+}
+
+func (m *finishedMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	x = make([]byte, 4+len(m.verifyData))
+	x[0] = typeFinished
+	x[3] = byte(len(m.verifyData))
+	copy(x[4:], m.verifyData)
+	m.raw = x
+	return
+}
+
+func (m *finishedMsg) unmarshal(data []byte) alert {
+	m.raw = data
+	if len(data) < 4 {
+		return alertDecodeError
+	}
+	m.verifyData = data[4:]
+	return alertSuccess
+}
+
+type nextProtoMsg struct {
+	raw   []byte
+	proto string
+}
+
+func (m *nextProtoMsg) equal(i interface{}) bool {
+	m1, ok := i.(*nextProtoMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.proto == m1.proto
+}
+
+func (m *nextProtoMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+	l := len(m.proto)
+	if l > 255 {
+		l = 255
+	}
+
+	padding := 32 - (l+2)%32
+	length := l + padding + 2
+	x := make([]byte, length+4)
+	x[0] = typeNextProtocol
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	y := x[4:]
+	y[0] = byte(l)
+	copy(y[1:], []byte(m.proto[0:l]))
+	y = y[1+l:]
+	y[0] = byte(padding)
+
+	m.raw = x
+
+	return x
+}
+
+func (m *nextProtoMsg) unmarshal(data []byte) alert {
+	m.raw = data
+
+	if len(data) < 5 {
+		return alertDecodeError
+	}
+	data = data[4:]
+	protoLen := int(data[0])
+	data = data[1:]
+	if len(data) < protoLen {
+		return alertDecodeError
+	}
+	m.proto = string(data[0:protoLen])
+	data = data[protoLen:]
+
+	if len(data) < 1 {
+		return alertDecodeError
+	}
+	paddingLen := int(data[0])
+	data = data[1:]
+	if len(data) != paddingLen {
+		return alertDecodeError
+	}
+
+	return alertSuccess
+}
+
+type certificateRequestMsg struct {
+	raw []byte
+	// hasSignatureAndHash indicates whether this message includes a list
+	// of signature and hash functions. This change was introduced with TLS
+	// 1.2.
+	hasSignatureAndHash bool
+
+	certificateTypes             []byte
+	supportedSignatureAlgorithms []SignatureScheme
+	certificateAuthorities       [][]byte
+}
+
+func (m *certificateRequestMsg) equal(i interface{}) bool {
+	m1, ok := i.(*certificateRequestMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.certificateTypes, m1.certificateTypes) &&
+		eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
+		eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms)
+}
+
+func (m *certificateRequestMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See http://tools.ietf.org/html/rfc4346#section-7.4.4
+	length := 1 + len(m.certificateTypes) + 2
+	casLength := 0
+	for _, ca := range m.certificateAuthorities {
+		casLength += 2 + len(ca)
+	}
+	length += casLength
+
+	if m.hasSignatureAndHash {
+		length += 2 + 2*len(m.supportedSignatureAlgorithms)
+	}
+
+	x = make([]byte, 4+length)
+	x[0] = typeCertificateRequest
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	x[4] = uint8(len(m.certificateTypes))
+
+	copy(x[5:], m.certificateTypes)
+	y := x[5+len(m.certificateTypes):]
+
+	if m.hasSignatureAndHash {
+		n := len(m.supportedSignatureAlgorithms) * 2
+		y[0] = uint8(n >> 8)
+		y[1] = uint8(n)
+		y = y[2:]
+		for _, sigAlgo := range m.supportedSignatureAlgorithms {
+			y[0] = uint8(sigAlgo >> 8)
+			y[1] = uint8(sigAlgo)
+			y = y[2:]
+		}
+	}
+
+	y[0] = uint8(casLength >> 8)
+	y[1] = uint8(casLength)
+	y = y[2:]
+	for _, ca := range m.certificateAuthorities {
+		y[0] = uint8(len(ca) >> 8)
+		y[1] = uint8(len(ca))
+		y = y[2:]
+		copy(y, ca)
+		y = y[len(ca):]
+	}
+
+	m.raw = x
+	return
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) alert {
+	m.raw = data
+
+	if len(data) < 5 {
+		return alertDecodeError
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return alertDecodeError
+	}
+
+	numCertTypes := int(data[4])
+	data = data[5:]
+	if numCertTypes == 0 || len(data) <= numCertTypes {
+		return alertDecodeError
+	}
+
+	m.certificateTypes = make([]byte, numCertTypes)
+	if copy(m.certificateTypes, data) != numCertTypes {
+		return alertDecodeError
+	}
+
+	data = data[numCertTypes:]
+
+	if m.hasSignatureAndHash {
+		if len(data) < 2 {
+			return alertDecodeError
+		}
+		sigAndHashLen := uint16(data[0])<<8 | uint16(data[1])
+		data = data[2:]
+		if sigAndHashLen&1 != 0 {
+			return alertDecodeError
+		}
+		if len(data) < int(sigAndHashLen) {
+			return alertDecodeError
+		}
+		numSigAlgos := sigAndHashLen / 2
+		m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos)
+		for i := range m.supportedSignatureAlgorithms {
+			m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1])
+			data = data[2:]
+		}
+	}
+
+	if len(data) < 2 {
+		return alertDecodeError
+	}
+	casLength := uint16(data[0])<<8 | uint16(data[1])
+	data = data[2:]
+	if len(data) < int(casLength) {
+		return alertDecodeError
+	}
+	cas := make([]byte, casLength)
+	copy(cas, data)
+	data = data[casLength:]
+
+	m.certificateAuthorities = nil
+	for len(cas) > 0 {
+		if len(cas) < 2 {
+			return alertDecodeError
+		}
+		caLen := uint16(cas[0])<<8 | uint16(cas[1])
+		cas = cas[2:]
+
+		if len(cas) < int(caLen) {
+			return alertDecodeError
+		}
+
+		m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
+		cas = cas[caLen:]
+	}
+
+	if len(data) != 0 {
+		return alertDecodeError
+	}
+
+	return alertSuccess
+}
+
+type certificateRequestMsg13 struct {
+	raw []byte
+
+	requestContext                   []byte
+	supportedSignatureAlgorithms     []SignatureScheme
+	supportedSignatureAlgorithmsCert []SignatureScheme
+	certificateAuthorities           [][]byte
+}
+
+func (m *certificateRequestMsg13) equal(i interface{}) bool {
+	m1, ok := i.(*certificateRequestMsg13)
+	return ok &&
+		bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.requestContext, m1.requestContext) &&
+		eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
+		eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
+		eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert)
+}
+
+func (m *certificateRequestMsg13) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.3.2
+	length := 1 + len(m.requestContext)
+	numExtensions := 1
+	extensionsLength := 2 + 2*len(m.supportedSignatureAlgorithms)
+
+	if m.getSignatureAlgorithmsCert() != nil {
+		numExtensions += 1
+		extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
+	}
+
+	casLength := 0
+	if len(m.certificateAuthorities) > 0 {
+		for _, ca := range m.certificateAuthorities {
+			casLength += 2 + len(ca)
+		}
+		extensionsLength += 2 + casLength
+		numExtensions++
+	}
+
+	extensionsLength += 4 * numExtensions
+	length += 2 + extensionsLength
+
+	x = make([]byte, 4+length)
+	x[0] = typeCertificateRequest
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	x[4] = uint8(len(m.requestContext))
+	copy(x[5:], m.requestContext)
+	z := x[5+len(m.requestContext):]
+
+	z[0] = byte(extensionsLength >> 8)
+	z[1] = byte(extensionsLength)
+	z = z[2:]
+
+	// TODO: this function should be reused by CH
+	z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
+
+	if m.getSignatureAlgorithmsCert() != nil {
+		z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
+	}
+	// certificate_authorities
+	if casLength > 0 {
+		z[0] = byte(extensionCAs >> 8)
+		z[1] = byte(extensionCAs)
+		l := 2 + casLength
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z = z[4:]
+
+		z[0] = uint8(casLength >> 8)
+		z[1] = uint8(casLength)
+		z = z[2:]
+		for _, ca := range m.certificateAuthorities {
+			z[0] = uint8(len(ca) >> 8)
+			z[1] = uint8(len(ca))
+			z = z[2:]
+			copy(z, ca)
+			z = z[len(ca):]
+		}
+	}
+
+	m.raw = x
+	return
+}
+
+func (m *certificateRequestMsg13) unmarshal(data []byte) alert {
+	m.raw = data
+	m.supportedSignatureAlgorithms = nil
+	m.certificateAuthorities = nil
+
+	if len(data) < 5 {
+		return alertDecodeError
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return alertDecodeError
+	}
+
+	ctxLen := data[4]
+	if len(data) < 5+int(ctxLen)+2 {
+		return alertDecodeError
+	}
+	m.requestContext = data[5 : 5+ctxLen]
+	data = data[5+ctxLen:]
+
+	extensionsLength := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+	if len(data) != extensionsLength {
+		return alertDecodeError
+	}
+
+	for len(data) != 0 {
+		if len(data) < 4 {
+			return alertDecodeError
+		}
+		extension := uint16(data[0])<<8 | uint16(data[1])
+		length := int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		if len(data) < length {
+			return alertDecodeError
+		}
+
+		switch extension {
+		case extensionSignatureAlgorithms:
+			// TODO: unmarshalExtensionSignatureAlgorithms should be shared with CH and pre-1.3 CV
+			// https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.2.3
+			var err alert
+			m.supportedSignatureAlgorithms, err = unmarshalExtensionSignatureAlgorithms(data, length)
+			if err != alertSuccess {
+				return err
+			}
+		case extensionSignatureAlgorithmsCert:
+			var err alert
+			m.supportedSignatureAlgorithmsCert, err = unmarshalExtensionSignatureAlgorithms(data, length)
+			if err != alertSuccess {
+				return err
+			}
+		case extensionCAs:
+			// TODO DRY: share code with CH
+			if length < 2 {
+				return alertDecodeError
+			}
+			l := int(data[0])<<8 | int(data[1])
+			if l != length-2 || l < 3 {
+				return alertDecodeError
+			}
+			cas := make([]byte, l)
+			copy(cas, data[2:])
+			m.certificateAuthorities = nil
+			for len(cas) > 0 {
+				if len(cas) < 2 {
+					return alertDecodeError
+				}
+				caLen := uint16(cas[0])<<8 | uint16(cas[1])
+				cas = cas[2:]
+
+				if len(cas) < int(caLen) {
+					return alertDecodeError
+				}
+
+				m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
+				cas = cas[caLen:]
+			}
+		}
+		data = data[length:]
+	}
+
+	if len(m.supportedSignatureAlgorithms) == 0 {
+		return alertDecodeError
+	}
+	return alertSuccess
+}
+
+func (m *certificateRequestMsg13) getSignatureAlgorithmsCert() []SignatureScheme {
+	return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
+}
+
+type certificateVerifyMsg struct {
+	raw                 []byte
+	hasSignatureAndHash bool
+	signatureAlgorithm  SignatureScheme
+	signature           []byte
+}
+
+func (m *certificateVerifyMsg) equal(i interface{}) bool {
+	m1, ok := i.(*certificateVerifyMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.hasSignatureAndHash == m1.hasSignatureAndHash &&
+		m.signatureAlgorithm == m1.signatureAlgorithm &&
+		bytes.Equal(m.signature, m1.signature)
+}
+
+func (m *certificateVerifyMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See http://tools.ietf.org/html/rfc4346#section-7.4.8
+	siglength := len(m.signature)
+	length := 2 + siglength
+	if m.hasSignatureAndHash {
+		length += 2
+	}
+	x = make([]byte, 4+length)
+	x[0] = typeCertificateVerify
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	y := x[4:]
+	if m.hasSignatureAndHash {
+		y[0] = uint8(m.signatureAlgorithm >> 8)
+		y[1] = uint8(m.signatureAlgorithm)
+		y = y[2:]
+	}
+	y[0] = uint8(siglength >> 8)
+	y[1] = uint8(siglength)
+	copy(y[2:], m.signature)
+
+	m.raw = x
+
+	return
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) alert {
+	m.raw = data
+
+	if len(data) < 6 {
+		return alertDecodeError
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return alertDecodeError
+	}
+
+	data = data[4:]
+	if m.hasSignatureAndHash {
+		m.signatureAlgorithm = SignatureScheme(data[0])<<8 | SignatureScheme(data[1])
+		data = data[2:]
+	}
+
+	if len(data) < 2 {
+		return alertDecodeError
+	}
+	siglength := int(data[0])<<8 + int(data[1])
+	data = data[2:]
+	if len(data) != siglength {
+		return alertDecodeError
+	}
+
+	m.signature = data
+
+	return alertSuccess
+}
+
+type newSessionTicketMsg struct {
+	raw    []byte
+	ticket []byte
+}
+
+func (m *newSessionTicketMsg) equal(i interface{}) bool {
+	m1, ok := i.(*newSessionTicketMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.ticket, m1.ticket)
+}
+
+func (m *newSessionTicketMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See http://tools.ietf.org/html/rfc5077#section-3.3
+	ticketLen := len(m.ticket)
+	length := 2 + 4 + ticketLen
+	x = make([]byte, 4+length)
+	x[0] = typeNewSessionTicket
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	x[8] = uint8(ticketLen >> 8)
+	x[9] = uint8(ticketLen)
+	copy(x[10:], m.ticket)
+
+	// [Psiphon]
+	// Set lifetime hint to a more typical value.
+	if obfuscateSessionTickets {
+		hints := []int{300, 1200, 7200, 10800, 64800, 100800, 129600}
+		randomInt, err := rand.Int(rand.Reader, big.NewInt(int64(len(hints))))
+		index := 0
+		if err == nil {
+			index = int(randomInt.Int64())
+		} else {
+			index = math_rand.Intn(len(hints))
+		}
+		hint := hints[index]
+		x[4] = uint8(hint >> 24)
+		x[5] = uint8(hint >> 16)
+		x[6] = uint8(hint >> 8)
+		x[7] = uint8(hint)
+	}
+
+	m.raw = x
+
+	return
+}
+
+func (m *newSessionTicketMsg) unmarshal(data []byte) alert {
+	m.raw = data
+
+	if len(data) < 10 {
+		return alertDecodeError
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return alertDecodeError
+	}
+
+	ticketLen := int(data[8])<<8 + int(data[9])
+	if len(data)-10 != ticketLen {
+		return alertDecodeError
+	}
+
+	m.ticket = data[10:]
+
+	return alertSuccess
+}
+
+type newSessionTicketMsg13 struct {
+	raw                []byte
+	lifetime           uint32
+	ageAdd             uint32
+	nonce              []byte
+	ticket             []byte
+	withEarlyDataInfo  bool
+	maxEarlyDataLength uint32
+}
+
+func (m *newSessionTicketMsg13) equal(i interface{}) bool {
+	m1, ok := i.(*newSessionTicketMsg13)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.lifetime == m1.lifetime &&
+		m.ageAdd == m1.ageAdd &&
+		bytes.Equal(m.nonce, m1.nonce) &&
+		bytes.Equal(m.ticket, m1.ticket) &&
+		m.withEarlyDataInfo == m1.withEarlyDataInfo &&
+		m.maxEarlyDataLength == m1.maxEarlyDataLength
+}
+
+func (m *newSessionTicketMsg13) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.6.1
+	nonceLen := len(m.nonce)
+	ticketLen := len(m.ticket)
+	length := 13 + nonceLen + ticketLen
+	if m.withEarlyDataInfo {
+		length += 8
+	}
+	x = make([]byte, 4+length)
+	x[0] = typeNewSessionTicket
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	x[4] = uint8(m.lifetime >> 24)
+	x[5] = uint8(m.lifetime >> 16)
+	x[6] = uint8(m.lifetime >> 8)
+	x[7] = uint8(m.lifetime)
+	x[8] = uint8(m.ageAdd >> 24)
+	x[9] = uint8(m.ageAdd >> 16)
+	x[10] = uint8(m.ageAdd >> 8)
+	x[11] = uint8(m.ageAdd)
+
+	x[12] = uint8(nonceLen)
+	copy(x[13:13+nonceLen], m.nonce)
+
+	y := x[13+nonceLen:]
+	y[0] = uint8(ticketLen >> 8)
+	y[1] = uint8(ticketLen)
+	copy(y[2:2+ticketLen], m.ticket)
+
+	if m.withEarlyDataInfo {
+		z := y[2+ticketLen:]
+		// z[0] is already 0, this is the extensions vector length.
+		z[1] = 8
+		z[2] = uint8(extensionEarlyData >> 8)
+		z[3] = uint8(extensionEarlyData)
+		z[5] = 4
+		z[6] = uint8(m.maxEarlyDataLength >> 24)
+		z[7] = uint8(m.maxEarlyDataLength >> 16)
+		z[8] = uint8(m.maxEarlyDataLength >> 8)
+		z[9] = uint8(m.maxEarlyDataLength)
+	}
+
+	m.raw = x
+
+	return
+}
+
+func (m *newSessionTicketMsg13) unmarshal(data []byte) alert {
+	m.raw = data
+	m.maxEarlyDataLength = 0
+	m.withEarlyDataInfo = false
+
+	if len(data) < 17 {
+		return alertDecodeError
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return alertDecodeError
+	}
+
+	m.lifetime = uint32(data[4])<<24 | uint32(data[5])<<16 |
+		uint32(data[6])<<8 | uint32(data[7])
+	m.ageAdd = uint32(data[8])<<24 | uint32(data[9])<<16 |
+		uint32(data[10])<<8 | uint32(data[11])
+
+	nonceLen := int(data[12])
+	if nonceLen == 0 || 13+nonceLen+2 > len(data) {
+		return alertDecodeError
+	}
+	m.nonce = data[13 : 13+nonceLen]
+
+	data = data[13+nonceLen:]
+	ticketLen := int(data[0])<<8 + int(data[1])
+	if ticketLen == 0 || 2+ticketLen+2 > len(data) {
+		return alertDecodeError
+	}
+	m.ticket = data[2 : 2+ticketLen]
+
+	data = data[2+ticketLen:]
+	extLen := int(data[0])<<8 + int(data[1])
+	if extLen != len(data)-2 {
+		return alertDecodeError
+	}
+
+	data = data[2:]
+	for len(data) > 0 {
+		if len(data) < 4 {
+			return alertDecodeError
+		}
+		extType := uint16(data[0])<<8 + uint16(data[1])
+		length := int(data[2])<<8 + int(data[3])
+		data = data[4:]
+
+		switch extType {
+		case extensionEarlyData:
+			if length != 4 {
+				return alertDecodeError
+			}
+			m.withEarlyDataInfo = true
+			m.maxEarlyDataLength = uint32(data[0])<<24 | uint32(data[1])<<16 |
+				uint32(data[2])<<8 | uint32(data[3])
+		}
+		data = data[length:]
+	}
+
+	return alertSuccess
+}
+
+type endOfEarlyDataMsg struct {
+}
+
+func (*endOfEarlyDataMsg) marshal() []byte {
+	return []byte{typeEndOfEarlyData, 0, 0, 0}
+}
+
+func (*endOfEarlyDataMsg) unmarshal(data []byte) alert {
+	if len(data) != 4 {
+		return alertDecodeError
+	}
+	return alertSuccess
+}
+
+type helloRequestMsg struct {
+}
+
+func (*helloRequestMsg) marshal() []byte {
+	return []byte{typeHelloRequest, 0, 0, 0}
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) alert {
+	if len(data) != 4 {
+		return alertDecodeError
+	}
+	return alertSuccess
+}
+
+func eqUint16s(x, y []uint16) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if y[i] != v {
+			return false
+		}
+	}
+	return true
+}
+
+func eqCurveIDs(x, y []CurveID) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if y[i] != v {
+			return false
+		}
+	}
+	return true
+}
+
+func eqStrings(x, y []string) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if y[i] != v {
+			return false
+		}
+	}
+	return true
+}
+
+func eqByteSlices(x, y [][]byte) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if !bytes.Equal(v, y[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+func eqSignatureAlgorithms(x, y []SignatureScheme) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if v != y[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func eqKeyShares(x, y []keyShare) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i := range x {
+		if x[i].group != y[i].group {
+			return false
+		}
+		if !bytes.Equal(x[i].data, y[i].data) {
+			return false
+		}
+	}
+	return true
+}
+
+func findExtension(data []byte, extensionType uint16) []byte {
+	for len(data) != 0 {
+		if len(data) < 4 {
+			return nil
+		}
+		extension := uint16(data[0])<<8 | uint16(data[1])
+		length := int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		if len(data) < length {
+			return nil
+		}
+		if extension == extensionType {
+			return data[:length]
+		}
+		data = data[length:]
+	}
+	return nil
+}

+ 927 - 0
vendor/github.com/Psiphon-Labs/tls-tris/handshake_server.go

@@ -0,0 +1,927 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/subtle"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"io"
+	"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 {
+	c                     *Conn
+	suite                 *cipherSuite
+	masterSecret          []byte
+	cachedClientHelloInfo *ClientHelloInfo
+	clientHello           *clientHelloMsg
+	hello                 *serverHelloMsg
+	cert                  *Certificate
+	privateKey            crypto.PrivateKey
+
+	// A marshalled DelegatedCredential to be sent to the client in the
+	// handshake.
+	delegatedCredential []byte
+
+	// TLS 1.0-1.2 fields
+	ellipticOk      bool
+	ecdsaOk         bool
+	rsaDecryptOk    bool
+	rsaSignOk       bool
+	sessionState    *sessionState
+	finishedHash    finishedHash
+	certsFromClient [][]byte
+
+	// TLS 1.3 fields
+	hello13Enc        *encryptedExtensionsMsg
+	keySchedule       *keySchedule13
+	clientFinishedKey []byte
+	hsClientCipher    interface{}
+	appClientCipher   interface{}
+}
+
+// serverHandshake performs a TLS handshake as a server.
+// c.out.Mutex <= L; c.handshakeMutex <= L.
+func (c *Conn) serverHandshake() error {
+	// If this is the first server handshake, we generate a random key to
+	// encrypt the tickets with.
+	c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
+
+	hs := serverHandshakeState{
+		c: c,
+	}
+	c.in.traceErr = hs.traceErr
+	c.out.traceErr = hs.traceErr
+	isResume, err := hs.readClientHello()
+	if err != nil {
+		return err
+	}
+
+	// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
+	// and https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-2
+	c.buffering = true
+	if c.vers >= VersionTLS13 {
+		if err := hs.doTLS13Handshake(); err != nil {
+			return err
+		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+		c.hs = &hs
+		// If the client is sending early data while the server expects
+		// it, delay the Finished check until HandshakeConfirmed() is
+		// called or until all early data is Read(). Otherwise, complete
+		// authenticating the client now (there is no support for
+		// sending 0.5-RTT data to a potential unauthenticated client).
+		if c.phase != readingEarlyData {
+			if err := hs.readClientFinished13(false); err != nil {
+				return err
+			}
+		}
+		c.handshakeComplete = true
+		return nil
+	} else if isResume {
+		// The client has included a session ticket and so we do an abbreviated handshake.
+		if err := hs.doResumeHandshake(); err != nil {
+			return err
+		}
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		// ticketSupported is set in a resumption handshake if the
+		// ticket from the client was encrypted with an old session
+		// ticket key and thus a refreshed ticket should be sent.
+		if hs.hello.ticketSupported {
+			if err := hs.sendSessionTicket(); err != nil {
+				return err
+			}
+		}
+		if err := hs.sendFinished(c.serverFinished[:]); err != nil {
+			return err
+		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = false
+		if err := hs.readFinished(nil); err != nil {
+			return err
+		}
+		c.didResume = true
+	} else {
+		// The client didn't include a session ticket, or it wasn't
+		// valid so we do a full handshake.
+		if err := hs.doFullHandshake(); err != nil {
+			return err
+		}
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(c.clientFinished[:]); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = true
+		c.buffering = true
+		if err := hs.sendSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(nil); err != nil {
+			return err
+		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+	}
+	if c.hand.Len() > 0 {
+		return c.sendAlert(alertUnexpectedMessage)
+	}
+	c.phase = handshakeConfirmed
+	atomic.StoreInt32(&c.handshakeConfirmed, 1)
+	c.handshakeComplete = true
+
+	return nil
+}
+
+// readClientHello reads a ClientHello message from the client and decides
+// whether we will perform session resumption.
+func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
+	c := hs.c
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return false, err
+	}
+	var ok bool
+	hs.clientHello, ok = msg.(*clientHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return false, unexpectedMessageError(hs.clientHello, msg)
+	}
+
+	if c.config.GetConfigForClient != nil {
+		if newConfig, err := c.config.GetConfigForClient(hs.clientHelloInfo()); err != nil {
+			c.out.traceErr, c.in.traceErr = nil, nil // disable tracing
+			c.sendAlert(alertInternalError)
+			return false, err
+		} else if newConfig != nil {
+			newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
+			c.config = newConfig
+		}
+	}
+
+	var keyShares []CurveID
+	for _, ks := range hs.clientHello.keyShares {
+		keyShares = append(keyShares, ks.group)
+	}
+
+	if hs.clientHello.supportedVersions != nil {
+		c.vers, ok = c.config.pickVersion(hs.clientHello.supportedVersions)
+		if !ok {
+			c.sendAlert(alertProtocolVersion)
+			return false, fmt.Errorf("tls: none of the client versions (%x) are supported", hs.clientHello.supportedVersions)
+		}
+	} else {
+		c.vers, ok = c.config.mutualVersion(hs.clientHello.vers)
+		if !ok {
+			c.sendAlert(alertProtocolVersion)
+			return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
+		}
+	}
+	c.haveVers = true
+
+	preferredCurves := c.config.curvePreferences()
+Curves:
+	for _, curve := range hs.clientHello.supportedCurves {
+		for _, supported := range preferredCurves {
+			if supported == curve {
+				hs.ellipticOk = true
+				break Curves
+			}
+		}
+	}
+
+	// If present, the supported points extension must include uncompressed.
+	// Can be absent. This behavior mirrors BoringSSL.
+	if hs.clientHello.supportedPoints != nil {
+		supportedPointFormat := false
+		for _, pointFormat := range hs.clientHello.supportedPoints {
+			if pointFormat == pointFormatUncompressed {
+				supportedPointFormat = true
+				break
+			}
+		}
+		if !supportedPointFormat {
+			c.sendAlert(alertHandshakeFailure)
+			return false, errors.New("tls: client does not support uncompressed points")
+		}
+	}
+
+	foundCompression := false
+	// We only support null compression, so check that the client offered it.
+	for _, compression := range hs.clientHello.compressionMethods {
+		if compression == compressionNone {
+			foundCompression = true
+			break
+		}
+	}
+
+	if !foundCompression {
+		c.sendAlert(alertIllegalParameter)
+		return false, errors.New("tls: client does not support uncompressed connections")
+	}
+	if len(hs.clientHello.compressionMethods) != 1 && c.vers >= VersionTLS13 {
+		c.sendAlert(alertIllegalParameter)
+		return false, errors.New("tls: 1.3 client offered compression")
+	}
+
+	if len(hs.clientHello.secureRenegotiation) != 0 {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+	}
+
+	if c.vers < VersionTLS13 {
+		hs.hello = new(serverHelloMsg)
+		hs.hello.vers = c.vers
+		hs.hello.random = make([]byte, 32)
+		_, err = io.ReadFull(c.config.rand(), hs.hello.random)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return false, err
+		}
+		hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
+		hs.hello.compressionMethod = compressionNone
+	} else {
+		hs.hello = new(serverHelloMsg)
+		hs.hello13Enc = new(encryptedExtensionsMsg)
+		hs.hello.vers = c.vers
+		hs.hello.random = make([]byte, 32)
+		hs.hello.sessionId = hs.clientHello.sessionId
+		_, err = io.ReadFull(c.config.rand(), hs.hello.random)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return false, err
+		}
+	}
+
+	if len(hs.clientHello.serverName) > 0 {
+		c.serverName = hs.clientHello.serverName
+	}
+
+	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 {
+				hs.hello13Enc.alpnProtocol = selectedProto
+			}
+			c.clientProtocol = selectedProto
+		}
+	} else {
+		// Although sending an empty NPN extension is reasonable, Firefox has
+		// had a bug around this. Best to send nothing at all if
+		// c.config.NextProtos is empty. See
+		// https://golang.org/issue/5445.
+		if hs.clientHello.nextProtoNeg && len(c.config.NextProtos) > 0 && c.vers < VersionTLS13 {
+			hs.hello.nextProtoNeg = true
+			hs.hello.nextProtos = c.config.NextProtos
+		}
+	}
+
+	hs.cert, err = c.config.getCertificate(hs.clientHelloInfo())
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return false, err
+	}
+
+	// Set the private key for this handshake to the certificate's secret key.
+	hs.privateKey = hs.cert.PrivateKey
+
+	if hs.clientHello.scts {
+		hs.hello.scts = hs.cert.SignedCertificateTimestamps
+	}
+
+	// Set the private key to the DC private key if the client and server are
+	// willing to negotiate the delegated credential extension.
+	//
+	// Check to see if a DelegatedCredential is available and should be used.
+	// If one is available, the session is using TLS >= 1.2, and the client
+	// accepts the delegated credential extension, then set the handshake
+	// private key to the DC private key.
+	if c.config.GetDelegatedCredential != nil && hs.clientHello.delegatedCredential && c.vers >= VersionTLS12 {
+		dc, sk, err := c.config.GetDelegatedCredential(hs.clientHelloInfo(), c.vers)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return false, err
+		}
+
+		// Set the handshake private key.
+		if dc != nil {
+			hs.privateKey = sk
+			hs.delegatedCredential = dc
+		}
+	}
+
+	if priv, ok := hs.privateKey.(crypto.Signer); ok {
+		switch priv.Public().(type) {
+		case *ecdsa.PublicKey:
+			hs.ecdsaOk = true
+		case *rsa.PublicKey:
+			hs.rsaSignOk = true
+		default:
+			c.sendAlert(alertInternalError)
+			return false, fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
+		}
+	}
+	if priv, ok := hs.privateKey.(crypto.Decrypter); ok {
+		switch priv.Public().(type) {
+		case *rsa.PublicKey:
+			hs.rsaDecryptOk = true
+		default:
+			c.sendAlert(alertInternalError)
+			return false, fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
+		}
+	}
+
+	if c.vers != VersionTLS13 && hs.checkForResumption() {
+		return true, nil
+	}
+
+	var preferenceList, supportedList []uint16
+	if c.config.PreferServerCipherSuites {
+		preferenceList = c.config.cipherSuites()
+		supportedList = hs.clientHello.cipherSuites
+	} else {
+		preferenceList = hs.clientHello.cipherSuites
+		supportedList = c.config.cipherSuites()
+	}
+
+	for _, id := range preferenceList {
+		if hs.setCipherSuite(id, supportedList, c.vers) {
+			break
+		}
+	}
+
+	if hs.suite == nil {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: no cipher suite supported by both client and server")
+	}
+
+	// See https://tools.ietf.org/html/rfc7507.
+	for _, id := range hs.clientHello.cipherSuites {
+		if id == TLS_FALLBACK_SCSV {
+			// The client is doing a fallback connection.
+			if c.vers < c.config.maxVersion() {
+				c.sendAlert(alertInappropriateFallback)
+				return false, errors.New("tls: client using inappropriate protocol fallback")
+			}
+			break
+		}
+	}
+
+	return false, nil
+}
+
+// checkForResumption reports whether we should perform resumption on this connection.
+func (hs *serverHandshakeState) checkForResumption() bool {
+	c := hs.c
+
+	if c.config.SessionTicketsDisabled {
+		return false
+	}
+
+	sessionTicket := append([]uint8{}, hs.clientHello.sessionTicket...)
+	serializedState, usedOldKey := c.decryptTicket(sessionTicket)
+	hs.sessionState = &sessionState{usedOldKey: usedOldKey}
+	if hs.sessionState.unmarshal(serializedState) != alertSuccess {
+		return false
+	}
+
+	// Never resume a session for a different TLS version.
+	if c.vers != hs.sessionState.vers {
+		return false
+	}
+
+	cipherSuiteOk := false
+	// Check that the client is still offering the ciphersuite in the session.
+	for _, id := range hs.clientHello.cipherSuites {
+		if id == hs.sessionState.cipherSuite {
+			cipherSuiteOk = true
+			break
+		}
+	}
+	if !cipherSuiteOk {
+		return false
+	}
+
+	// Check that we also support the ciphersuite from the session.
+	if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) {
+		return false
+	}
+
+	sessionHasClientCerts := len(hs.sessionState.certificates) != 0
+	needClientCerts := c.config.ClientAuth == RequireAnyClientCert || c.config.ClientAuth == RequireAndVerifyClientCert
+	if needClientCerts && !sessionHasClientCerts {
+		return false
+	}
+	if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+		return false
+	}
+
+	return true
+}
+
+func (hs *serverHandshakeState) doResumeHandshake() error {
+	c := hs.c
+
+	hs.hello.cipherSuite = hs.suite.id
+	// We echo the client's session ID in the ServerHello to let it know
+	// that we're doing a resumption.
+	hs.hello.sessionId = hs.clientHello.sessionId
+	hs.hello.ticketSupported = hs.sessionState.usedOldKey
+	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash.discardHandshakeBuffer()
+	hs.finishedHash.Write(hs.clientHello.marshal())
+	hs.finishedHash.Write(hs.hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
+
+	if len(hs.sessionState.certificates) > 0 {
+		if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
+			return err
+		}
+	}
+
+	hs.masterSecret = hs.sessionState.masterSecret
+
+	return nil
+}
+
+func (hs *serverHandshakeState) doFullHandshake() error {
+	c := hs.c
+
+	if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+		hs.hello.ocspStapling = true
+	}
+
+	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
+	hs.hello.cipherSuite = hs.suite.id
+
+	hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
+	if c.config.ClientAuth == NoClientCert {
+		// No need to keep a full record of the handshake if client
+		// certificates won't be used.
+		hs.finishedHash.discardHandshakeBuffer()
+	}
+	hs.finishedHash.Write(hs.clientHello.marshal())
+	hs.finishedHash.Write(hs.hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
+
+	certMsg := new(certificateMsg)
+	certMsg.certificates = hs.cert.Certificate
+	hs.finishedHash.Write(certMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+		return err
+	}
+
+	if hs.hello.ocspStapling {
+		certStatus := new(certificateStatusMsg)
+		certStatus.statusType = statusTypeOCSP
+		certStatus.response = hs.cert.OCSPStaple
+		hs.finishedHash.Write(certStatus.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil {
+			return err
+		}
+	}
+
+	keyAgreement := hs.suite.ka(c.vers)
+	skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.privateKey, hs.clientHello, hs.hello)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	if skx != nil {
+		hs.finishedHash.Write(skx.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil {
+			return err
+		}
+	}
+
+	if c.config.ClientAuth >= RequestClientCert {
+		// Request a client certificate
+		certReq := new(certificateRequestMsg)
+		certReq.certificateTypes = []byte{
+			byte(certTypeRSASign),
+			byte(certTypeECDSASign),
+		}
+		if c.vers >= VersionTLS12 {
+			certReq.hasSignatureAndHash = true
+			certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+		}
+
+		// An empty list of certificateAuthorities signals to
+		// the client that it may send any certificate in response
+		// to our request. When we know the CAs we trust, then
+		// we can send them down, so that the client can choose
+		// an appropriate certificate to give to us.
+		if c.config.ClientCAs != nil {
+			certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
+		}
+		hs.finishedHash.Write(certReq.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
+			return err
+		}
+	}
+
+	helloDone := new(serverHelloDoneMsg)
+	hs.finishedHash.Write(helloDone.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil {
+		return err
+	}
+
+	if _, err := c.flush(); err != nil {
+		return err
+	}
+
+	var pub crypto.PublicKey // public key for client auth, if any
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	var ok bool
+	// If we requested a client certificate, then the client must send a
+	// certificate message, even if it's empty.
+	if c.config.ClientAuth >= RequestClientCert {
+		if certMsg, ok = msg.(*certificateMsg); !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certMsg, msg)
+		}
+		hs.finishedHash.Write(certMsg.marshal())
+
+		if len(certMsg.certificates) == 0 {
+			// The client didn't actually send a certificate
+			switch c.config.ClientAuth {
+			case RequireAnyClientCert, RequireAndVerifyClientCert:
+				c.sendAlert(alertBadCertificate)
+				return errors.New("tls: client didn't provide a certificate")
+			}
+		}
+
+		pub, err = hs.processCertsFromClient(certMsg.certificates)
+		if err != nil {
+			return err
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	// Get client key exchange
+	ckx, ok := msg.(*clientKeyExchangeMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(ckx, msg)
+	}
+	hs.finishedHash.Write(ckx.marshal())
+
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.privateKey, ckx, c.vers)
+	if err != nil {
+		if err == errClientKeyExchange {
+			c.sendAlert(alertDecodeError)
+		} else {
+			c.sendAlert(alertInternalError)
+		}
+		return err
+	}
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+	if err := c.config.writeKeyLog("CLIENT_RANDOM", hs.clientHello.random, hs.masterSecret); err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+
+	// If we received a client cert in response to our certificate request message,
+	// the client will send us a certificateVerifyMsg immediately after the
+	// clientKeyExchangeMsg. This message is a digest of all preceding
+	// handshake-layer messages that is signed using the private key corresponding
+	// to the client's certificate. This allows us to verify that the client is in
+	// possession of the private key of the certificate.
+	if len(c.peerCertificates) > 0 {
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+		certVerify, ok := msg.(*certificateVerifyMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certVerify, msg)
+		}
+
+		// Determine the signature type.
+		_, sigType, hashFunc, err := pickSignatureAlgorithm(pub, []SignatureScheme{certVerify.signatureAlgorithm}, supportedSignatureAlgorithms, c.vers)
+		if err != nil {
+			c.sendAlert(alertIllegalParameter)
+			return err
+		}
+
+		var digest []byte
+		if digest, err = hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret); err == nil {
+			err = verifyHandshakeSignature(sigType, pub, hashFunc, digest, certVerify.signature)
+		}
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: could not validate signature of connection nonces: " + err.Error())
+		}
+
+		hs.finishedHash.Write(certVerify.marshal())
+	}
+
+	hs.finishedHash.discardHandshakeBuffer()
+
+	return nil
+}
+
+func (hs *serverHandshakeState) establishKeys() error {
+	c := hs.c
+
+	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+
+	var clientCipher, serverCipher interface{}
+	var clientHash, serverHash macFunction
+
+	if hs.suite.aead == nil {
+		clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
+		clientHash = hs.suite.mac(c.vers, clientMAC)
+		serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
+		serverHash = hs.suite.mac(c.vers, serverMAC)
+	} else {
+		clientCipher = hs.suite.aead(clientKey, clientIV)
+		serverCipher = hs.suite.aead(serverKey, serverIV)
+	}
+
+	c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
+	c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
+
+	return nil
+}
+
+func (hs *serverHandshakeState) readFinished(out []byte) error {
+	c := hs.c
+
+	c.readRecord(recordTypeChangeCipherSpec)
+	if c.in.err != nil {
+		return c.in.err
+	}
+
+	if hs.hello.nextProtoNeg {
+		msg, err := c.readHandshake()
+		if err != nil {
+			return err
+		}
+		nextProto, ok := msg.(*nextProtoMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(nextProto, msg)
+		}
+		hs.finishedHash.Write(nextProto.marshal())
+		c.clientProtocol = nextProto.proto
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	clientFinished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(clientFinished, msg)
+	}
+
+	verify := hs.finishedHash.clientSum(hs.masterSecret)
+	if len(verify) != len(clientFinished.verifyData) ||
+		subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+		c.sendAlert(alertDecryptError)
+		return errors.New("tls: client's Finished message is incorrect")
+	}
+
+	hs.finishedHash.Write(clientFinished.marshal())
+	copy(out, verify)
+	return nil
+}
+
+func (hs *serverHandshakeState) sendSessionTicket() error {
+	if !hs.hello.ticketSupported {
+		return nil
+	}
+
+	c := hs.c
+	m := new(newSessionTicketMsg)
+
+	var err error
+	state := sessionState{
+		vers:         c.vers,
+		cipherSuite:  hs.suite.id,
+		masterSecret: hs.masterSecret,
+		certificates: hs.certsFromClient,
+	}
+	m.ticket, err = c.encryptTicket(state.marshal())
+	if err != nil {
+		return err
+	}
+
+	hs.finishedHash.Write(m.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeState) sendFinished(out []byte) error {
+	c := hs.c
+
+	if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+		return err
+	}
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+	hs.finishedHash.Write(finished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+		return err
+	}
+
+	c.cipherSuite = hs.suite.id
+	copy(out, finished.verifyData)
+
+	return nil
+}
+
+// processCertsFromClient takes a chain of client certificates either from a
+// Certificates message or from a sessionState and verifies them. It returns
+// the public key of the leaf certificate.
+func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (crypto.PublicKey, error) {
+	c := hs.c
+
+	hs.certsFromClient = certificates
+	certs := make([]*x509.Certificate, len(certificates))
+	var err error
+	for i, asn1Data := range certificates {
+		if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return nil, errors.New("tls: failed to parse client certificate: " + err.Error())
+		}
+	}
+
+	if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
+		opts := x509.VerifyOptions{
+			Roots:         c.config.ClientCAs,
+			CurrentTime:   c.config.time(),
+			Intermediates: x509.NewCertPool(),
+			KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+		}
+
+		for _, cert := range certs[1:] {
+			opts.Intermediates.AddCert(cert)
+		}
+
+		chains, err := certs[0].Verify(opts)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return nil, errors.New("tls: failed to verify client's certificate: " + err.Error())
+		}
+
+		c.verifiedChains = chains
+	}
+
+	if c.config.VerifyPeerCertificate != nil {
+		if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return nil, err
+		}
+	}
+
+	if len(certs) == 0 {
+		return nil, nil
+	}
+
+	var pub crypto.PublicKey
+	switch key := certs[0].PublicKey.(type) {
+	case *ecdsa.PublicKey, *rsa.PublicKey:
+		pub = key
+	default:
+		c.sendAlert(alertUnsupportedCertificate)
+		return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+	}
+	c.peerCertificates = certs
+	return pub, nil
+}
+
+// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
+// suite if that cipher suite is acceptable to use.
+// It returns a bool indicating if the suite was set.
+func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool {
+	for _, supported := range supportedCipherSuites {
+		if id == supported {
+			var candidate *cipherSuite
+
+			for _, s := range cipherSuites {
+				if s.id == id {
+					candidate = s
+					break
+				}
+			}
+			if candidate == nil {
+				continue
+			}
+
+			if version >= VersionTLS13 && candidate.flags&suiteTLS13 != 0 {
+				hs.suite = candidate
+				return true
+			}
+			if version < VersionTLS13 && candidate.flags&suiteTLS13 != 0 {
+				continue
+			}
+
+			// Don't select a ciphersuite which we can't
+			// support for this client.
+			if candidate.flags&suiteECDHE != 0 {
+				if !hs.ellipticOk {
+					continue
+				}
+				if candidate.flags&suiteECDSA != 0 {
+					if !hs.ecdsaOk {
+						continue
+					}
+				} else if !hs.rsaSignOk {
+					continue
+				}
+			} else if !hs.rsaDecryptOk {
+				continue
+			}
+			if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
+				continue
+			}
+			hs.suite = candidate
+			return true
+		}
+	}
+	return false
+}
+
+// suppVersArray is the backing array of ClientHelloInfo.SupportedVersions
+var suppVersArray = [...]uint16{VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
+
+func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo {
+	if hs.cachedClientHelloInfo != nil {
+		return hs.cachedClientHelloInfo
+	}
+
+	var supportedVersions []uint16
+	if hs.clientHello.supportedVersions != nil {
+		supportedVersions = hs.clientHello.supportedVersions
+	} else if hs.clientHello.vers > VersionTLS12 {
+		supportedVersions = suppVersArray[:]
+	} else if hs.clientHello.vers >= VersionSSL30 {
+		supportedVersions = suppVersArray[VersionTLS12-hs.clientHello.vers:]
+	}
+
+	var pskBinder []byte
+	if len(hs.clientHello.psks) > 0 {
+		pskBinder = hs.clientHello.psks[0].binder
+	}
+
+	hs.cachedClientHelloInfo = &ClientHelloInfo{
+		CipherSuites:               hs.clientHello.cipherSuites,
+		ServerName:                 hs.clientHello.serverName,
+		SupportedCurves:            hs.clientHello.supportedCurves,
+		SupportedPoints:            hs.clientHello.supportedPoints,
+		SignatureSchemes:           hs.clientHello.supportedSignatureAlgorithms,
+		SupportedProtos:            hs.clientHello.alpnProtocols,
+		SupportedVersions:          supportedVersions,
+		Conn:                       hs.c.conn,
+		Offered0RTTData:            hs.clientHello.earlyData,
+		AcceptsDelegatedCredential: hs.clientHello.delegatedCredential,
+		Fingerprint:                pskBinder,
+	}
+
+	return hs.cachedClientHelloInfo
+}

+ 58 - 0
vendor/github.com/Psiphon-Labs/tls-tris/hkdf.go

@@ -0,0 +1,58 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+// Mostly derived from golang.org/x/crypto/hkdf, but with an exposed
+// Extract API.
+//
+// HKDF is a cryptographic key derivation function (KDF) with the goal of
+// expanding limited input keying material into one or more cryptographically
+// strong secret keys.
+//
+// RFC 5869: https://tools.ietf.org/html/rfc5869
+
+import (
+	"crypto"
+	"crypto/hmac"
+)
+
+func hkdfExpand(hash crypto.Hash, prk, info []byte, l int) []byte {
+	var (
+		expander = hmac.New(hash.New, prk)
+		res      = make([]byte, l)
+		counter  = byte(1)
+		prev     []byte
+	)
+
+	if l > 255*expander.Size() {
+		panic("hkdf: requested too much output")
+	}
+
+	p := res
+	for len(p) > 0 {
+		expander.Reset()
+		expander.Write(prev)
+		expander.Write(info)
+		expander.Write([]byte{counter})
+		prev = expander.Sum(prev[:0])
+		counter++
+		n := copy(p, prev)
+		p = p[n:]
+	}
+
+	return res
+}
+
+func hkdfExtract(hash crypto.Hash, secret, salt []byte) []byte {
+	if salt == nil {
+		salt = make([]byte, hash.Size())
+	}
+	if secret == nil {
+		secret = make([]byte, hash.Size())
+	}
+	extractor := hmac.New(hash.New, salt)
+	extractor.Write(secret)
+	return extractor.Sum(nil)
+}

+ 402 - 0
vendor/github.com/Psiphon-Labs/tls-tris/key_agreement.go

@@ -0,0 +1,402 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"crypto"
+	"crypto/elliptic"
+	"crypto/md5"
+	"crypto/rsa"
+	"crypto/sha1"
+	"errors"
+	"io"
+	"math/big"
+
+	"golang.org/x/crypto/curve25519"
+)
+
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
+// rsaKeyAgreement implements the standard TLS key agreement where the client
+// encrypts the pre-master secret to the server's public key.
+type rsaKeyAgreement struct{}
+
+func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, sk crypto.PrivateKey, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	return nil, nil
+}
+
+func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, sk crypto.PrivateKey, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	if len(ckx.ciphertext) < 2 {
+		return nil, errClientKeyExchange
+	}
+
+	ciphertext := ckx.ciphertext
+	if version != VersionSSL30 {
+		ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+		if ciphertextLen != len(ckx.ciphertext)-2 {
+			return nil, errClientKeyExchange
+		}
+		ciphertext = ckx.ciphertext[2:]
+	}
+	priv, ok := sk.(crypto.Decrypter)
+	if !ok {
+		return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
+	}
+	// Perform constant time RSA PKCS#1 v1.5 decryption
+	preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
+	if err != nil {
+		return nil, err
+	}
+	// We don't check the version number in the premaster secret. For one,
+	// by checking it, we would leak information about the validity of the
+	// encrypted pre-master secret. Secondly, it provides only a small
+	// benefit against a downgrade attack and some implementations send the
+	// wrong version anyway. See the discussion at the end of section
+	// 7.4.7.1 of RFC 4346.
+	return preMasterSecret, nil
+}
+
+func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, pk crypto.PublicKey, skx *serverKeyExchangeMsg) error {
+	return errors.New("tls: unexpected ServerKeyExchange")
+}
+
+func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, pk crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error) {
+	preMasterSecret := make([]byte, 48)
+	preMasterSecret[0] = byte(clientHello.vers >> 8)
+	preMasterSecret[1] = byte(clientHello.vers)
+	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+	if err != nil {
+		return nil, nil, err
+	}
+
+	encrypted, err := rsa.EncryptPKCS1v15(config.rand(), pk.(*rsa.PublicKey), preMasterSecret)
+	if err != nil {
+		return nil, nil, err
+	}
+	ckx := new(clientKeyExchangeMsg)
+	ckx.ciphertext = make([]byte, len(encrypted)+2)
+	ckx.ciphertext[0] = byte(len(encrypted) >> 8)
+	ckx.ciphertext[1] = byte(len(encrypted))
+	copy(ckx.ciphertext[2:], encrypted)
+	return preMasterSecret, ckx, nil
+}
+
+// sha1Hash calculates a SHA1 hash over the given byte slices.
+func sha1Hash(slices [][]byte) []byte {
+	hsha1 := sha1.New()
+	for _, slice := range slices {
+		hsha1.Write(slice)
+	}
+	return hsha1.Sum(nil)
+}
+
+// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
+// concatenation of an MD5 and SHA1 hash.
+func md5SHA1Hash(slices [][]byte) []byte {
+	md5sha1 := make([]byte, md5.Size+sha1.Size)
+	hmd5 := md5.New()
+	for _, slice := range slices {
+		hmd5.Write(slice)
+	}
+	copy(md5sha1, hmd5.Sum(nil))
+	copy(md5sha1[md5.Size:], sha1Hash(slices))
+	return md5sha1
+}
+
+// hashForServerKeyExchange hashes the given slices and returns their digest
+// using the given hash function.
+func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) ([]byte, error) {
+	if version >= VersionTLS12 {
+		h := hashFunc.New()
+		for _, slice := range slices {
+			h.Write(slice)
+		}
+		digest := h.Sum(nil)
+		return digest, nil
+	}
+	if sigType == signatureECDSA {
+		return sha1Hash(slices), nil
+	}
+	return md5SHA1Hash(slices), nil
+}
+
+func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
+	switch id {
+	case CurveP256:
+		return elliptic.P256(), true
+	case CurveP384:
+		return elliptic.P384(), true
+	case CurveP521:
+		return elliptic.P521(), true
+	default:
+		return nil, false
+	}
+
+}
+
+// ecdheKeyAgreement implements a TLS key agreement where the server
+// generates an ephemeral EC public/private key pair and signs it. The
+// pre-master secret is then calculated using ECDH. The signature may
+// either be ECDSA or RSA.
+type ecdheKeyAgreement struct {
+	version    uint16
+	isRSA      bool
+	privateKey []byte
+	curveid    CurveID
+
+	// publicKey is used to store the peer's public value when X25519 is
+	// being used.
+	publicKey []byte
+	// x and y are used to store the peer's public value when one of the
+	// NIST curves is being used.
+	x, y *big.Int
+}
+
+func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, sk crypto.PrivateKey, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	preferredCurves := config.curvePreferences()
+
+NextCandidate:
+	for _, candidate := range preferredCurves {
+		for _, c := range clientHello.supportedCurves {
+			if candidate == c {
+				ka.curveid = c
+				break NextCandidate
+			}
+		}
+	}
+
+	if ka.curveid == 0 {
+		return nil, errors.New("tls: no supported elliptic curves offered")
+	}
+
+	var ecdhePublic []byte
+
+	if ka.curveid == X25519 {
+		var scalar, public [32]byte
+		if _, err := io.ReadFull(config.rand(), scalar[:]); err != nil {
+			return nil, err
+		}
+
+		curve25519.ScalarBaseMult(&public, &scalar)
+		ka.privateKey = scalar[:]
+		ecdhePublic = public[:]
+	} else {
+		curve, ok := curveForCurveID(ka.curveid)
+		if !ok {
+			return nil, errors.New("tls: preferredCurves includes unsupported curve")
+		}
+
+		var x, y *big.Int
+		var err error
+		ka.privateKey, x, y, err = elliptic.GenerateKey(curve, config.rand())
+		if err != nil {
+			return nil, err
+		}
+		ecdhePublic = elliptic.Marshal(curve, x, y)
+	}
+
+	// http://tools.ietf.org/html/rfc4492#section-5.4
+	serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
+	serverECDHParams[0] = 3 // named curve
+	serverECDHParams[1] = byte(ka.curveid >> 8)
+	serverECDHParams[2] = byte(ka.curveid)
+	serverECDHParams[3] = byte(len(ecdhePublic))
+	copy(serverECDHParams[4:], ecdhePublic)
+
+	priv, ok := sk.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("tls: certificate private key does not implement crypto.Signer")
+	}
+
+	signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(priv.Public(), clientHello.supportedSignatureAlgorithms, supportedSignatureAlgorithms, ka.version)
+	if err != nil {
+		return nil, err
+	}
+	if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
+		return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
+	}
+
+	digest, err := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, hello.random, serverECDHParams)
+	if err != nil {
+		return nil, err
+	}
+
+	var sig []byte
+	signOpts := crypto.SignerOpts(hashFunc)
+	if sigType == signatureRSAPSS {
+		signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
+	}
+	sig, err = priv.Sign(config.rand(), digest, signOpts)
+	if err != nil {
+		return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
+	}
+
+	skx := new(serverKeyExchangeMsg)
+	sigAndHashLen := 0
+	if ka.version >= VersionTLS12 {
+		sigAndHashLen = 2
+	}
+	skx.key = make([]byte, len(serverECDHParams)+sigAndHashLen+2+len(sig))
+	copy(skx.key, serverECDHParams)
+	k := skx.key[len(serverECDHParams):]
+	if ka.version >= VersionTLS12 {
+		k[0] = byte(signatureAlgorithm >> 8)
+		k[1] = byte(signatureAlgorithm)
+		k = k[2:]
+	}
+	k[0] = byte(len(sig) >> 8)
+	k[1] = byte(len(sig))
+	copy(k[2:], sig)
+
+	return skx, nil
+}
+
+func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, sk crypto.PrivateKey, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
+		return nil, errClientKeyExchange
+	}
+
+	if ka.curveid == X25519 {
+		if len(ckx.ciphertext) != 1+32 {
+			return nil, errClientKeyExchange
+		}
+
+		var theirPublic, sharedKey, scalar [32]byte
+		copy(theirPublic[:], ckx.ciphertext[1:])
+		copy(scalar[:], ka.privateKey)
+		curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
+		return sharedKey[:], nil
+	}
+
+	curve, ok := curveForCurveID(ka.curveid)
+	if !ok {
+		panic("internal error")
+	}
+	x, y := elliptic.Unmarshal(curve, ckx.ciphertext[1:]) // Unmarshal also checks whether the given point is on the curve
+	if x == nil {
+		return nil, errClientKeyExchange
+	}
+	x, _ = curve.ScalarMult(x, y, ka.privateKey)
+	curveSize := (curve.Params().BitSize + 7) >> 3
+	xBytes := x.Bytes()
+	if len(xBytes) == curveSize {
+		return xBytes, nil
+	}
+	preMasterSecret := make([]byte, curveSize)
+	copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+	return preMasterSecret, nil
+}
+
+func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, pk crypto.PublicKey, skx *serverKeyExchangeMsg) error {
+	if len(skx.key) < 4 {
+		return errServerKeyExchange
+	}
+	if skx.key[0] != 3 { // named curve
+		return errors.New("tls: server selected unsupported curve")
+	}
+	ka.curveid = CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
+
+	publicLen := int(skx.key[3])
+	if publicLen+4 > len(skx.key) {
+		return errServerKeyExchange
+	}
+	serverECDHParams := skx.key[:4+publicLen]
+	publicKey := serverECDHParams[4:]
+
+	sig := skx.key[4+publicLen:]
+	if len(sig) < 2 {
+		return errServerKeyExchange
+	}
+
+	if ka.curveid == X25519 {
+		if len(publicKey) != 32 {
+			return errors.New("tls: bad X25519 public value")
+		}
+		ka.publicKey = publicKey
+	} else {
+		curve, ok := curveForCurveID(ka.curveid)
+		if !ok {
+			return errors.New("tls: server selected unsupported curve")
+		}
+		ka.x, ka.y = elliptic.Unmarshal(curve, publicKey) // Unmarshal also checks whether the given point is on the curve
+		if ka.x == nil {
+			return errServerKeyExchange
+		}
+	}
+
+	var signatureAlgorithm SignatureScheme
+	if ka.version >= VersionTLS12 {
+		// handle SignatureAndHashAlgorithm
+		signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
+		sig = sig[2:]
+		if len(sig) < 2 {
+			return errServerKeyExchange
+		}
+	}
+	_, sigType, hashFunc, err := pickSignatureAlgorithm(pk, []SignatureScheme{signatureAlgorithm}, clientHello.supportedSignatureAlgorithms, ka.version)
+	if err != nil {
+		return err
+	}
+	if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
+		return errServerKeyExchange
+	}
+
+	sigLen := int(sig[0])<<8 | int(sig[1])
+	if sigLen+2 != len(sig) {
+		return errServerKeyExchange
+	}
+	sig = sig[2:]
+
+	digest, err := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, serverHello.random, serverECDHParams)
+	if err != nil {
+		return err
+	}
+	return verifyHandshakeSignature(sigType, pk, hashFunc, digest, sig)
+}
+
+func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, pk crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error) {
+	if ka.curveid == 0 {
+		return nil, nil, errors.New("tls: missing ServerKeyExchange message")
+	}
+
+	var serialized, preMasterSecret []byte
+
+	if ka.curveid == X25519 {
+		var ourPublic, theirPublic, sharedKey, scalar [32]byte
+
+		if _, err := io.ReadFull(config.rand(), scalar[:]); err != nil {
+			return nil, nil, err
+		}
+
+		copy(theirPublic[:], ka.publicKey)
+		curve25519.ScalarBaseMult(&ourPublic, &scalar)
+		curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
+		serialized = ourPublic[:]
+		preMasterSecret = sharedKey[:]
+	} else {
+		curve, ok := curveForCurveID(ka.curveid)
+		if !ok {
+			panic("internal error")
+		}
+		priv, mx, my, err := elliptic.GenerateKey(curve, config.rand())
+		if err != nil {
+			return nil, nil, err
+		}
+		x, _ := curve.ScalarMult(ka.x, ka.y, priv)
+		preMasterSecret = make([]byte, (curve.Params().BitSize+7)>>3)
+		xBytes := x.Bytes()
+		copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+		serialized = elliptic.Marshal(curve, mx, my)
+	}
+
+	ckx := new(clientKeyExchangeMsg)
+	ckx.ciphertext = make([]byte, 1+len(serialized))
+	ckx.ciphertext[0] = byte(len(serialized))
+	copy(ckx.ciphertext[1:], serialized)
+
+	return preMasterSecret, ckx, nil
+}

+ 132 - 0
vendor/github.com/Psiphon-Labs/tls-tris/obfuscated.go

@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package tls
+
+import (
+	"crypto/rand"
+)
+
+// NewObfuscatedClientSessionCache produces obfuscated session tickets.
+//
+// [Psiphon]
+// Obfuscated Session Tickets
+//
+// Obfuscated session tickets is a network traffic obfuscation protocol that appears
+// to be valid TLS using session tickets. The client actually generates the session
+// ticket and encrypts it with a shared secret, enabling a TLS session that entirely
+// skips the most fingerprintable aspects of TLS.
+// The scheme is described here:
+// https://lists.torproject.org/pipermail/tor-dev/2016-September/011354.html
+//
+// Circumvention notes:
+//  - TLS session ticket implementations are widespread:
+//    https://istlsfastyet.com/#cdn-paas.
+//  - An adversary cannot easily block session ticket capability, as this requires
+//    a downgrade attack against TLS.
+//  - Anti-probing defence is provided, as the adversary must use the correct obfuscation
+//    shared secret to form valid obfuscation session ticket; otherwise server offers
+//    standard session tickets.
+//  - Limitation: TLS protocol and session ticket size correspond to golang implementation
+//    and not more common OpenSSL.
+//  - Limitation: an adversary with the obfuscation shared secret can decrypt the session
+//    ticket and observe the plaintext traffic. It's assumed that the adversary will not
+//    learn the obfuscated shared secret without also learning the address of the TLS
+//    server and blocking it anyway; it's also assumed that the TLS payload is not
+//    plaintext but is protected with some other security layer (e.g., SSH).
+//
+// Implementation notes:
+//   - Client should set its ClientSessionCache to a NewObfuscatedTLSClientSessionCache.
+//     This cache ignores the session key and always produces obfuscated session tickets.
+//   - The TLS ClientHello includes an SNI field, even when using session tickets, so
+//     the client should populate the ServerName.
+//   - Server should set its SetSessionTicketKeys with first a standard key, followed by
+//     the obfuscation shared secret.
+//   - Since the client creates the session ticket, it selects parameters that were not
+//     negotiated with the server, such as the cipher suite. It's implicitly assumed that
+//     the server can support the selected parameters.
+//
+func NewObfuscatedClientSessionCache(sharedSecret [32]byte) ClientSessionCache {
+	return &obfuscatedClientSessionCache{
+		sharedSecret: sharedSecret,
+		realTickets:  NewLRUClientSessionCache(-1),
+	}
+}
+
+type obfuscatedClientSessionCache struct {
+	sharedSecret [32]byte
+	realTickets  ClientSessionCache
+}
+
+func (cache *obfuscatedClientSessionCache) Put(key string, state *ClientSessionState) {
+	// When new, real session tickets are issued, use them.
+	cache.realTickets.Put(key, state)
+}
+
+func (cache *obfuscatedClientSessionCache) Get(key string) (*ClientSessionState, bool) {
+	clientSessionState, ok := cache.realTickets.Get(key)
+	if ok {
+		return clientSessionState, true
+	}
+	// Bootstrap with an obfuscated session ticket.
+	clientSessionState, err := NewObfuscatedClientSessionState(cache.sharedSecret)
+	if err != nil {
+		// TODO: log error
+		// This will fall back to regular TLS
+		return nil, false
+	}
+	return clientSessionState, true
+}
+
+func NewObfuscatedClientSessionState(sharedSecret [32]byte) (*ClientSessionState, error) {
+
+	// Create a session ticket that wasn't actually issued by the server.
+	vers := uint16(VersionTLS12)
+	cipherSuite := TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+	masterSecret := make([]byte, masterSecretLength)
+	_, err := rand.Read(masterSecret)
+	if err != nil {
+		return nil, err
+	}
+	serverState := &sessionState{
+		vers:         vers,
+		cipherSuite:  cipherSuite,
+		masterSecret: masterSecret,
+		certificates: nil,
+	}
+	c := &Conn{
+		config: &Config{
+			sessionTicketKeys: []ticketKey{ticketKeyFromBytes(sharedSecret)},
+		},
+	}
+	sessionTicket, err := c.encryptTicket(serverState.marshal())
+	if err != nil {
+		return nil, err
+	}
+
+	// Pretend we got that session ticket from the server.
+	clientState := &ClientSessionState{
+		sessionTicket: sessionTicket,
+		vers:          vers,
+		cipherSuite:   cipherSuite,
+		masterSecret:  masterSecret,
+	}
+
+	return clientState, nil
+}

+ 347 - 0
vendor/github.com/Psiphon-Labs/tls-tris/prf.go

@@ -0,0 +1,347 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"crypto"
+	"crypto/hmac"
+	"crypto/md5"
+	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
+	"errors"
+	"fmt"
+	"hash"
+)
+
+// Split a premaster secret in two as specified in RFC 4346, section 5.
+func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
+	s1 = secret[0 : (len(secret)+1)/2]
+	s2 = secret[len(secret)/2:]
+	return
+}
+
+// pHash implements the P_hash function, as defined in RFC 4346, section 5.
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
+	h := hmac.New(hash, secret)
+	h.Write(seed)
+	a := h.Sum(nil)
+
+	j := 0
+	for j < len(result) {
+		h.Reset()
+		h.Write(a)
+		h.Write(seed)
+		b := h.Sum(nil)
+		copy(result[j:], b)
+		j += len(b)
+
+		h.Reset()
+		h.Write(a)
+		a = h.Sum(nil)
+	}
+}
+
+// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
+func prf10(result, secret, label, seed []byte) {
+	hashSHA1 := sha1.New
+	hashMD5 := md5.New
+
+	labelAndSeed := make([]byte, len(label)+len(seed))
+	copy(labelAndSeed, label)
+	copy(labelAndSeed[len(label):], seed)
+
+	s1, s2 := splitPreMasterSecret(secret)
+	pHash(result, s1, labelAndSeed, hashMD5)
+	result2 := make([]byte, len(result))
+	pHash(result2, s2, labelAndSeed, hashSHA1)
+
+	for i, b := range result2 {
+		result[i] ^= b
+	}
+}
+
+// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
+func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
+	return func(result, secret, label, seed []byte) {
+		labelAndSeed := make([]byte, len(label)+len(seed))
+		copy(labelAndSeed, label)
+		copy(labelAndSeed[len(label):], seed)
+
+		pHash(result, secret, labelAndSeed, hashFunc)
+	}
+}
+
+// prf30 implements the SSL 3.0 pseudo-random function, as defined in
+// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
+func prf30(result, secret, label, seed []byte) {
+	hashSHA1 := sha1.New()
+	hashMD5 := md5.New()
+
+	done := 0
+	i := 0
+	// RFC 5246 section 6.3 says that the largest PRF output needed is 128
+	// bytes. Since no more ciphersuites will be added to SSLv3, this will
+	// remain true. Each iteration gives us 16 bytes so 10 iterations will
+	// be sufficient.
+	var b [11]byte
+	for done < len(result) {
+		for j := 0; j <= i; j++ {
+			b[j] = 'A' + byte(i)
+		}
+
+		hashSHA1.Reset()
+		hashSHA1.Write(b[:i+1])
+		hashSHA1.Write(secret)
+		hashSHA1.Write(seed)
+		digest := hashSHA1.Sum(nil)
+
+		hashMD5.Reset()
+		hashMD5.Write(secret)
+		hashMD5.Write(digest)
+
+		done += copy(result[done:], hashMD5.Sum(nil))
+		i++
+	}
+}
+
+const (
+	tlsRandomLength      = 32 // Length of a random nonce in TLS 1.1.
+	masterSecretLength   = 48 // Length of a master secret in TLS 1.1.
+	finishedVerifyLength = 12 // Length of verify_data in a Finished message.
+)
+
+var masterSecretLabel = []byte("master secret")
+var keyExpansionLabel = []byte("key expansion")
+var clientFinishedLabel = []byte("client finished")
+var serverFinishedLabel = []byte("server finished")
+
+func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
+	switch version {
+	case VersionSSL30:
+		return prf30, crypto.Hash(0)
+	case VersionTLS10, VersionTLS11:
+		return prf10, crypto.Hash(0)
+	case VersionTLS12:
+		if suite.flags&suiteSHA384 != 0 {
+			return prf12(sha512.New384), crypto.SHA384
+		}
+		return prf12(sha256.New), crypto.SHA256
+	default:
+		panic("unknown version")
+	}
+}
+
+func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
+	prf, _ := prfAndHashForVersion(version, suite)
+	return prf
+}
+
+// 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
+}
+
+// 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.
+func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+	seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
+	seed = append(seed, serverRandom...)
+	seed = append(seed, clientRandom...)
+
+	n := 2*macLen + 2*keyLen + 2*ivLen
+	keyMaterial := make([]byte, n)
+	prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed)
+	clientMAC = keyMaterial[:macLen]
+	keyMaterial = keyMaterial[macLen:]
+	serverMAC = keyMaterial[:macLen]
+	keyMaterial = keyMaterial[macLen:]
+	clientKey = keyMaterial[:keyLen]
+	keyMaterial = keyMaterial[keyLen:]
+	serverKey = keyMaterial[:keyLen]
+	keyMaterial = keyMaterial[keyLen:]
+	clientIV = keyMaterial[:ivLen]
+	keyMaterial = keyMaterial[ivLen:]
+	serverIV = keyMaterial[:ivLen]
+	return
+}
+
+// lookupTLSHash looks up the corresponding crypto.Hash for a given
+// hash from a TLS SignatureScheme.
+func lookupTLSHash(signatureAlgorithm SignatureScheme) (crypto.Hash, error) {
+	switch signatureAlgorithm {
+	case PKCS1WithSHA1, ECDSAWithSHA1:
+		return crypto.SHA1, nil
+	case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
+		return crypto.SHA256, nil
+	case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
+		return crypto.SHA384, nil
+	case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
+		return crypto.SHA512, nil
+	default:
+		return 0, fmt.Errorf("tls: unsupported signature algorithm: %#04x", signatureAlgorithm)
+	}
+}
+
+func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
+	var buffer []byte
+	if version == VersionSSL30 || version >= VersionTLS12 {
+		buffer = []byte{}
+	}
+
+	prf, hash := prfAndHashForVersion(version, cipherSuite)
+	if hash != 0 {
+		return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
+	}
+
+	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
+}
+
+// A finishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type finishedHash struct {
+	client hash.Hash
+	server hash.Hash
+
+	// Prior to TLS 1.2, an additional MD5 hash is required.
+	clientMD5 hash.Hash
+	serverMD5 hash.Hash
+
+	// In TLS 1.2, a full buffer is sadly required.
+	buffer []byte
+
+	version uint16
+	prf     func(result, secret, label, seed []byte)
+}
+
+func (h *finishedHash) Write(msg []byte) (n int, err error) {
+	h.client.Write(msg)
+	h.server.Write(msg)
+
+	if h.version < VersionTLS12 {
+		h.clientMD5.Write(msg)
+		h.serverMD5.Write(msg)
+	}
+
+	if h.buffer != nil {
+		h.buffer = append(h.buffer, msg...)
+	}
+
+	return len(msg), nil
+}
+
+func (h finishedHash) Sum() []byte {
+	if h.version >= VersionTLS12 {
+		return h.client.Sum(nil)
+	}
+
+	out := make([]byte, 0, md5.Size+sha1.Size)
+	out = h.clientMD5.Sum(out)
+	return h.client.Sum(out)
+}
+
+// finishedSum30 calculates the contents of the verify_data member of a SSLv3
+// Finished message given the MD5 and SHA1 hashes of a set of handshake
+// messages.
+func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
+	md5.Write(magic)
+	md5.Write(masterSecret)
+	md5.Write(ssl30Pad1[:])
+	md5Digest := md5.Sum(nil)
+
+	md5.Reset()
+	md5.Write(masterSecret)
+	md5.Write(ssl30Pad2[:])
+	md5.Write(md5Digest)
+	md5Digest = md5.Sum(nil)
+
+	sha1.Write(magic)
+	sha1.Write(masterSecret)
+	sha1.Write(ssl30Pad1[:40])
+	sha1Digest := sha1.Sum(nil)
+
+	sha1.Reset()
+	sha1.Write(masterSecret)
+	sha1.Write(ssl30Pad2[:40])
+	sha1.Write(sha1Digest)
+	sha1Digest = sha1.Sum(nil)
+
+	ret := make([]byte, len(md5Digest)+len(sha1Digest))
+	copy(ret, md5Digest)
+	copy(ret[len(md5Digest):], sha1Digest)
+	return ret
+}
+
+var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
+var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
+
+// clientSum returns the contents of the verify_data member of a client's
+// Finished message.
+func (h finishedHash) clientSum(masterSecret []byte) []byte {
+	if h.version == VersionSSL30 {
+		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
+	}
+
+	out := make([]byte, finishedVerifyLength)
+	h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
+	return out
+}
+
+// serverSum returns the contents of the verify_data member of a server's
+// Finished message.
+func (h finishedHash) serverSum(masterSecret []byte) []byte {
+	if h.version == VersionSSL30 {
+		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
+	}
+
+	out := make([]byte, finishedVerifyLength)
+	h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
+	return out
+}
+
+// hashForClientCertificate returns a digest over the handshake messages so far,
+// suitable for signing by a TLS client certificate.
+func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) ([]byte, error) {
+	if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
+		panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
+	}
+
+	if h.version == VersionSSL30 {
+		if sigType != signaturePKCS1v15 {
+			return nil, errors.New("tls: unsupported signature type for client certificate")
+		}
+
+		md5Hash := md5.New()
+		md5Hash.Write(h.buffer)
+		sha1Hash := sha1.New()
+		sha1Hash.Write(h.buffer)
+		return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), nil
+	}
+	if h.version >= VersionTLS12 {
+		hash := hashAlg.New()
+		hash.Write(h.buffer)
+		return hash.Sum(nil), nil
+	}
+
+	if sigType == signatureECDSA {
+		return h.server.Sum(nil), nil
+	}
+
+	return h.Sum(), nil
+}
+
+// discardHandshakeBuffer is called when there is no more need to
+// buffer the entirety of the handshake messages.
+func (h *finishedHash) discardHandshakeBuffer() {
+	h.buffer = nil
+}

+ 392 - 0
vendor/github.com/Psiphon-Labs/tls-tris/subcerts.go

@@ -0,0 +1,392 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+// Delegated credentials for TLS
+// (https://tools.ietf.org/html/draft-ietf-tls-subcerts-02) is an IETF Internet
+// draft and proposed TLS extension. This allows a backend server to delegate
+// TLS termination to a trusted frontend. If the client supports this extension,
+// then the frontend may use a "delegated credential" as the signing key in the
+// handshake. A delegated credential is a short lived key pair delegated to the
+// server by an entity trusted by the client. Once issued, credentials can't be
+// revoked; in order to mitigate risk in case the frontend is compromised, the
+// credential is only valid for a short time (days, hours, or even minutes).
+//
+// This implements draft 02. This draft doesn't specify an object identifier for
+// the X.509 extension; we use one assigned by Cloudflare. In addition, IANA has
+// not assigned an extension ID for this extension; we picked up one that's not
+// yet taken.
+//
+// TODO(cjpatton) Only ECDSA is supported with delegated credentials for now;
+// we'd like to suppoort for EcDSA signatures once these have better support
+// upstream.
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/x509"
+	"encoding/asn1"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"time"
+)
+
+const (
+	// length of the public key field
+	dcPubKeyFieldLen  = 3
+	dcMaxTTLSeconds   = 60 * 60 * 24 * 7 // 7 days
+	dcMaxTTL          = time.Duration(dcMaxTTLSeconds * time.Second)
+	dcMaxPublicKeyLen = 1 << 24 // Bytes
+	dcMaxSignatureLen = 1 << 16 // Bytes
+)
+
+var errNoDelegationUsage = errors.New("certificate not authorized for delegation")
+
+// delegationUsageId is the DelegationUsage X.509 extension OID
+//
+// NOTE(cjpatton) This OID is a child of Cloudflare's IANA-assigned OID.
+var delegationUsageId = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 44}
+
+// canDelegate returns true if a certificate can be used for delegated
+// credentials.
+func canDelegate(cert *x509.Certificate) bool {
+	// Check that the digitalSignature key usage is set.
+	if (cert.KeyUsage & x509.KeyUsageDigitalSignature) == 0 {
+		return false
+	}
+
+	// Check that the certificate has the DelegationUsage extension and that
+	// it's non-critical (per the spec).
+	for _, extension := range cert.Extensions {
+		if extension.Id.Equal(delegationUsageId) {
+			return true
+		}
+	}
+	return false
+}
+
+// credential stores the public components of a credential.
+type credential struct {
+	// The serialized form of the credential.
+	raw []byte
+
+	// The amount of time for which the credential is valid. Specifically, the
+	// the credential expires `ValidTime` seconds after the `notBefore` of the
+	// delegation certificate. The delegator shall not issue delegated
+	// credentials that are valid for more than 7 days from the current time.
+	//
+	// When this data structure is serialized, this value is converted to a
+	// uint32 representing the duration in seconds.
+	validTime time.Duration
+
+	// The signature scheme associated with the delegated credential public key.
+	expectedCertVerifyAlgorithm SignatureScheme
+
+	// The version of TLS in which the credential will be used.
+	expectedVersion uint16
+
+	// The credential public key.
+	publicKey crypto.PublicKey
+}
+
+// isExpired returns true if the credential has expired. The end of the validity
+// interval is defined as the delegator certificate's notBefore field (`start`)
+// plus ValidTime seconds. This function simply checks that the current time
+// (`now`) is before the end of the valdity interval.
+func (cred *credential) isExpired(start, now time.Time) bool {
+	end := start.Add(cred.validTime)
+	return !now.Before(end)
+}
+
+// invalidTTL returns true if the credential's validity period is longer than the
+// maximum permitted. This is defined by the certificate's notBefore field
+// (`start`) plus the ValidTime, minus the current time (`now`).
+func (cred *credential) invalidTTL(start, now time.Time) bool {
+	return cred.validTime > (now.Sub(start) + dcMaxTTL).Round(time.Second)
+}
+
+// marshalSubjectPublicKeyInfo returns a DER encoded SubjectPublicKeyInfo structure
+// (as defined in the X.509 standard) for the credential.
+func (cred *credential) marshalSubjectPublicKeyInfo() ([]byte, error) {
+	switch cred.expectedCertVerifyAlgorithm {
+	case ECDSAWithP256AndSHA256,
+		ECDSAWithP384AndSHA384,
+		ECDSAWithP521AndSHA512:
+		serializedPublicKey, err := x509.MarshalPKIXPublicKey(cred.publicKey)
+		if err != nil {
+			return nil, err
+		}
+		return serializedPublicKey, nil
+
+	default:
+		return nil, fmt.Errorf("unsupported signature scheme: 0x%04x", cred.expectedCertVerifyAlgorithm)
+	}
+}
+
+// marshal encodes a credential in the wire format specified in
+// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
+func (cred *credential) marshal() ([]byte, error) {
+	// The number of bytes comprising the DC parameters, which includes the
+	// validity time (4 bytes), the signature scheme of the public key (2 bytes), and
+	// the protocol version (2 bytes).
+	paramsLen := 8
+
+	// The first 4 bytes are the valid_time, scheme, and version fields.
+	serialized := make([]byte, paramsLen+dcPubKeyFieldLen)
+	binary.BigEndian.PutUint32(serialized, uint32(cred.validTime/time.Second))
+	binary.BigEndian.PutUint16(serialized[4:], uint16(cred.expectedCertVerifyAlgorithm))
+	binary.BigEndian.PutUint16(serialized[6:], cred.expectedVersion)
+
+	// Encode the public key and assert that the encoding is no longer than 2^16
+	// bytes (per the spec).
+	serializedPublicKey, err := cred.marshalSubjectPublicKeyInfo()
+	if err != nil {
+		return nil, err
+	}
+	if len(serializedPublicKey) > dcMaxPublicKeyLen {
+		return nil, errors.New("public key is too long")
+	}
+
+	// The next 3 bytes are the length of the public key field, which may be up
+	// to 2^24 bytes long.
+	putUint24(serialized[paramsLen:], len(serializedPublicKey))
+
+	// The remaining bytes are the public key itself.
+	serialized = append(serialized, serializedPublicKey...)
+	cred.raw = serialized
+	return serialized, nil
+}
+
+// unmarshalCredential decodes a credential and returns it.
+func unmarshalCredential(serialized []byte) (*credential, error) {
+	// The number of bytes comprising the DC parameters.
+	paramsLen := 8
+
+	if len(serialized) < paramsLen+dcPubKeyFieldLen {
+		return nil, errors.New("credential is too short")
+	}
+
+	// Parse the valid_time, scheme, and version fields.
+	validTime := time.Duration(binary.BigEndian.Uint32(serialized)) * time.Second
+	scheme := SignatureScheme(binary.BigEndian.Uint16(serialized[4:]))
+	version := binary.BigEndian.Uint16(serialized[6:])
+
+	// Parse the SubjectPublicKeyInfo.
+	pk, err := x509.ParsePKIXPublicKey(serialized[paramsLen+dcPubKeyFieldLen:])
+	if err != nil {
+		return nil, err
+	}
+
+	if _, ok := pk.(*ecdsa.PublicKey); !ok {
+		return nil, fmt.Errorf("unsupported delegation key type: %T", pk)
+	}
+
+	return &credential{
+		raw:                         serialized,
+		validTime:                   validTime,
+		expectedCertVerifyAlgorithm: scheme,
+		expectedVersion:             version,
+		publicKey:                   pk,
+	}, nil
+}
+
+// getCredentialLen returns the number of bytes comprising the serialized
+// credential that starts at the beginning of the input slice. It returns an
+// error if the input is too short to contain a credential.
+func getCredentialLen(serialized []byte) (int, error) {
+	paramsLen := 8
+	if len(serialized) < paramsLen+dcPubKeyFieldLen {
+		return 0, errors.New("credential is too short")
+	}
+	// First several bytes are the valid_time, scheme, and version fields.
+	serialized = serialized[paramsLen:]
+
+	// The next 3 bytes are the length of the serialized public key, which may
+	// be up to 2^24 bytes in length.
+	serializedPublicKeyLen := getUint24(serialized)
+	serialized = serialized[dcPubKeyFieldLen:]
+
+	if len(serialized) < serializedPublicKeyLen {
+		return 0, errors.New("public key of credential is too short")
+	}
+
+	return paramsLen + dcPubKeyFieldLen + serializedPublicKeyLen, nil
+}
+
+// delegatedCredential stores a credential and its delegation.
+type delegatedCredential struct {
+	raw []byte
+
+	// The credential, which contains a public and its validity time.
+	cred *credential
+
+	// The signature scheme used to sign the credential.
+	algorithm SignatureScheme
+
+	// The credential's delegation.
+	signature []byte
+}
+
+// ensureCertificateHasLeaf parses the leaf certificate if needed.
+func ensureCertificateHasLeaf(cert *Certificate) error {
+	var err error
+	if cert.Leaf == nil {
+		if len(cert.Certificate[0]) == 0 {
+			return errors.New("missing leaf certificate")
+		}
+		cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// validate checks that that the signature is valid, that the credential hasn't
+// expired, and that the TTL is valid. It also checks that certificate can be
+// used for delegation.
+func (dc *delegatedCredential) validate(cert *x509.Certificate, now time.Time) (bool, error) {
+	// Check that the cert can delegate.
+	if !canDelegate(cert) {
+		return false, errNoDelegationUsage
+	}
+
+	if dc.cred.isExpired(cert.NotBefore, now) {
+		return false, errors.New("credential has expired")
+	}
+
+	if dc.cred.invalidTTL(cert.NotBefore, now) {
+		return false, errors.New("credential TTL is invalid")
+	}
+
+	// Prepare the credential for verification.
+	rawCred, err := dc.cred.marshal()
+	if err != nil {
+		return false, err
+	}
+	hash := getHash(dc.algorithm)
+	in := prepareDelegation(hash, rawCred, cert.Raw, dc.algorithm)
+
+	// TODO(any) This code overlaps significantly with verifyHandshakeSignature()
+	// in ../auth.go. This should be refactored.
+	switch dc.algorithm {
+	case ECDSAWithP256AndSHA256,
+		ECDSAWithP384AndSHA384,
+		ECDSAWithP521AndSHA512:
+		pk, ok := cert.PublicKey.(*ecdsa.PublicKey)
+		if !ok {
+			return false, errors.New("expected ECDSA public key")
+		}
+		sig := new(ecdsaSignature)
+		if _, err = asn1.Unmarshal(dc.signature, sig); err != nil {
+			return false, err
+		}
+		return ecdsa.Verify(pk, in, sig.R, sig.S), nil
+
+	default:
+		return false, fmt.Errorf(
+			"unsupported signature scheme: 0x%04x", dc.algorithm)
+	}
+}
+
+// unmarshalDelegatedCredential decodes a DelegatedCredential structure.
+func unmarshalDelegatedCredential(serialized []byte) (*delegatedCredential, error) {
+	// Get the length of the serialized credential that begins at the start of
+	// the input slice.
+	serializedCredentialLen, err := getCredentialLen(serialized)
+	if err != nil {
+		return nil, err
+	}
+
+	// Parse the credential.
+	cred, err := unmarshalCredential(serialized[:serializedCredentialLen])
+	if err != nil {
+		return nil, err
+	}
+
+	// Parse the signature scheme.
+	serialized = serialized[serializedCredentialLen:]
+	if len(serialized) < 4 {
+		return nil, errors.New("delegated credential is too short")
+	}
+	scheme := SignatureScheme(binary.BigEndian.Uint16(serialized))
+
+	// Parse the signature length.
+	serialized = serialized[2:]
+	serializedSignatureLen := binary.BigEndian.Uint16(serialized)
+
+	// Prase the signature.
+	serialized = serialized[2:]
+	if len(serialized) < int(serializedSignatureLen) {
+		return nil, errors.New("signature of delegated credential is too short")
+	}
+	sig := serialized[:serializedSignatureLen]
+
+	return &delegatedCredential{
+		raw:       serialized,
+		cred:      cred,
+		algorithm: scheme,
+		signature: sig,
+	}, nil
+}
+
+// getCurve maps the SignatureScheme to its corresponding elliptic.Curve.
+func getCurve(scheme SignatureScheme) elliptic.Curve {
+	switch scheme {
+	case ECDSAWithP256AndSHA256:
+		return elliptic.P256()
+	case ECDSAWithP384AndSHA384:
+		return elliptic.P384()
+	case ECDSAWithP521AndSHA512:
+		return elliptic.P521()
+	default:
+		return nil
+	}
+}
+
+// getHash maps the SignatureScheme to its corresponding hash function.
+//
+// TODO(any) This function overlaps with hashForSignatureScheme in 13.go.
+func getHash(scheme SignatureScheme) crypto.Hash {
+	switch scheme {
+	case ECDSAWithP256AndSHA256:
+		return crypto.SHA256
+	case ECDSAWithP384AndSHA384:
+		return crypto.SHA384
+	case ECDSAWithP521AndSHA512:
+		return crypto.SHA512
+	default:
+		return 0 // Unknown hash function
+	}
+}
+
+// prepareDelegation returns a hash of the message that the delegator is to
+// sign. The inputs are the credential (`cred`), the DER-encoded delegator
+// certificate (`delegatorCert`) and the signature scheme of the delegator
+// (`delegatorAlgorithm`).
+func prepareDelegation(hash crypto.Hash, cred, delegatorCert []byte, delegatorAlgorithm SignatureScheme) []byte {
+	h := hash.New()
+
+	// The header.
+	h.Write(bytes.Repeat([]byte{0x20}, 64))
+	h.Write([]byte("TLS, server delegated credentials"))
+	h.Write([]byte{0x00})
+
+	// The delegation certificate.
+	h.Write(delegatorCert)
+
+	// The credential.
+	h.Write(cred)
+
+	// The delegator signature scheme.
+	var serializedScheme [2]byte
+	binary.BigEndian.PutUint16(serializedScheme[:], uint16(delegatorAlgorithm))
+	h.Write(serializedScheme[:])
+
+	return h.Sum(nil)
+}

+ 344 - 0
vendor/github.com/Psiphon-Labs/tls-tris/ticket.go

@@ -0,0 +1,344 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/sha256"
+	"crypto/subtle"
+	"errors"
+	"io"
+
+	// [Psiphon]
+	"crypto/rand"
+	"math/big"
+	math_rand "math/rand"
+)
+
+// [Psiphon]
+var obfuscateSessionTickets = true
+
+// A SessionTicketSealer provides a way to securely encapsulate
+// session state for storage on the client. All methods are safe for
+// concurrent use.
+type SessionTicketSealer interface {
+	// Seal returns a session ticket value that can be later passed to Unseal
+	// to recover the content, usually by encrypting it. The ticket will be sent
+	// to the client to be stored, and will be sent back in plaintext, so it can
+	// be read and modified by an attacker.
+	Seal(cs *ConnectionState, content []byte) (ticket []byte, err error)
+
+	// Unseal returns a session ticket contents. The ticket can't be safely
+	// assumed to have been generated by Seal.
+	// If unable to unseal the ticket, the connection will proceed with a
+	// complete handshake.
+	Unseal(chi *ClientHelloInfo, ticket []byte) (content []byte, success bool)
+}
+
+// sessionState contains the information that is serialized into a session
+// ticket in order to later resume a connection.
+type sessionState struct {
+	vers         uint16
+	cipherSuite  uint16
+	masterSecret []byte
+	certificates [][]byte
+	// usedOldKey is true if the ticket from which this session came from
+	// was encrypted with an older key and thus should be refreshed.
+	usedOldKey bool
+}
+
+func (s *sessionState) equal(i interface{}) bool {
+	s1, ok := i.(*sessionState)
+	if !ok {
+		return false
+	}
+
+	if s.vers != s1.vers ||
+		s.cipherSuite != s1.cipherSuite ||
+		!bytes.Equal(s.masterSecret, s1.masterSecret) {
+		return false
+	}
+
+	if len(s.certificates) != len(s1.certificates) {
+		return false
+	}
+
+	for i := range s.certificates {
+		if !bytes.Equal(s.certificates[i], s1.certificates[i]) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (s *sessionState) marshal() []byte {
+	length := 2 + 2 + 2 + len(s.masterSecret) + 2
+	for _, cert := range s.certificates {
+		length += 4 + len(cert)
+	}
+
+	// [Psiphon]
+	// Pad golang TLS session ticket to a more typical size.
+	if obfuscateSessionTickets {
+		paddedSizes := []int{160, 176, 192, 208, 218, 224, 240, 255}
+		initialSize := 120
+		randomInt, err := rand.Int(rand.Reader, big.NewInt(int64(len(paddedSizes))))
+		index := 0
+		if err == nil {
+			index = int(randomInt.Int64())
+		} else {
+			index = math_rand.Intn(len(paddedSizes))
+		}
+		paddingSize := paddedSizes[index] - initialSize
+		length += paddingSize
+	}
+
+	ret := make([]byte, length)
+	x := ret
+	x[0] = byte(s.vers >> 8)
+	x[1] = byte(s.vers)
+	x[2] = byte(s.cipherSuite >> 8)
+	x[3] = byte(s.cipherSuite)
+	x[4] = byte(len(s.masterSecret) >> 8)
+	x[5] = byte(len(s.masterSecret))
+	x = x[6:]
+	copy(x, s.masterSecret)
+	x = x[len(s.masterSecret):]
+
+	x[0] = byte(len(s.certificates) >> 8)
+	x[1] = byte(len(s.certificates))
+	x = x[2:]
+
+	for _, cert := range s.certificates {
+		x[0] = byte(len(cert) >> 24)
+		x[1] = byte(len(cert) >> 16)
+		x[2] = byte(len(cert) >> 8)
+		x[3] = byte(len(cert))
+		copy(x[4:], cert)
+		x = x[4+len(cert):]
+	}
+
+	return ret
+}
+
+func (s *sessionState) unmarshal(data []byte) alert {
+	if len(data) < 8 {
+		return alertDecodeError
+	}
+
+	s.vers = uint16(data[0])<<8 | uint16(data[1])
+	s.cipherSuite = uint16(data[2])<<8 | uint16(data[3])
+	masterSecretLen := int(data[4])<<8 | int(data[5])
+	data = data[6:]
+	if len(data) < masterSecretLen {
+		return alertDecodeError
+	}
+
+	s.masterSecret = data[:masterSecretLen]
+	data = data[masterSecretLen:]
+
+	if len(data) < 2 {
+		return alertDecodeError
+	}
+
+	numCerts := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+
+	s.certificates = make([][]byte, numCerts)
+	for i := range s.certificates {
+		if len(data) < 4 {
+			return alertDecodeError
+		}
+		certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		if certLen < 0 {
+			return alertDecodeError
+		}
+		if len(data) < certLen {
+			return alertDecodeError
+		}
+		s.certificates[i] = data[:certLen]
+		data = data[certLen:]
+	}
+
+	// [Psiphon]
+	// Ignore padding for obfuscated session tickets
+	//if len(data) != 0 {
+	//	return alertDecodeError
+	//}
+	return alertSuccess
+}
+
+type sessionState13 struct {
+	vers            uint16
+	suite           uint16
+	ageAdd          uint32
+	createdAt       uint64
+	maxEarlyDataLen uint32
+	pskSecret       []byte
+	alpnProtocol    string
+	SNI             string
+}
+
+func (s *sessionState13) equal(i interface{}) bool {
+	s1, ok := i.(*sessionState13)
+	if !ok {
+		return false
+	}
+
+	return s.vers == s1.vers &&
+		s.suite == s1.suite &&
+		s.ageAdd == s1.ageAdd &&
+		s.createdAt == s1.createdAt &&
+		s.maxEarlyDataLen == s1.maxEarlyDataLen &&
+		subtle.ConstantTimeCompare(s.pskSecret, s1.pskSecret) == 1 &&
+		s.alpnProtocol == s1.alpnProtocol &&
+		s.SNI == s1.SNI
+}
+
+func (s *sessionState13) marshal() []byte {
+	length := 2 + 2 + 4 + 8 + 4 + 2 + len(s.pskSecret) + 2 + len(s.alpnProtocol) + 2 + len(s.SNI)
+
+	x := make([]byte, length)
+	x[0] = byte(s.vers >> 8)
+	x[1] = byte(s.vers)
+	x[2] = byte(s.suite >> 8)
+	x[3] = byte(s.suite)
+	x[4] = byte(s.ageAdd >> 24)
+	x[5] = byte(s.ageAdd >> 16)
+	x[6] = byte(s.ageAdd >> 8)
+	x[7] = byte(s.ageAdd)
+	x[8] = byte(s.createdAt >> 56)
+	x[9] = byte(s.createdAt >> 48)
+	x[10] = byte(s.createdAt >> 40)
+	x[11] = byte(s.createdAt >> 32)
+	x[12] = byte(s.createdAt >> 24)
+	x[13] = byte(s.createdAt >> 16)
+	x[14] = byte(s.createdAt >> 8)
+	x[15] = byte(s.createdAt)
+	x[16] = byte(s.maxEarlyDataLen >> 24)
+	x[17] = byte(s.maxEarlyDataLen >> 16)
+	x[18] = byte(s.maxEarlyDataLen >> 8)
+	x[19] = byte(s.maxEarlyDataLen)
+	x[20] = byte(len(s.pskSecret) >> 8)
+	x[21] = byte(len(s.pskSecret))
+	copy(x[22:], s.pskSecret)
+	z := x[22+len(s.pskSecret):]
+	z[0] = byte(len(s.alpnProtocol) >> 8)
+	z[1] = byte(len(s.alpnProtocol))
+	copy(z[2:], s.alpnProtocol)
+	z = z[2+len(s.alpnProtocol):]
+	z[0] = byte(len(s.SNI) >> 8)
+	z[1] = byte(len(s.SNI))
+	copy(z[2:], s.SNI)
+
+	return x
+}
+
+func (s *sessionState13) unmarshal(data []byte) alert {
+	if len(data) < 24 {
+		return alertDecodeError
+	}
+
+	s.vers = uint16(data[0])<<8 | uint16(data[1])
+	s.suite = uint16(data[2])<<8 | uint16(data[3])
+	s.ageAdd = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+	s.createdAt = uint64(data[8])<<56 | uint64(data[9])<<48 | uint64(data[10])<<40 | uint64(data[11])<<32 |
+		uint64(data[12])<<24 | uint64(data[13])<<16 | uint64(data[14])<<8 | uint64(data[15])
+	s.maxEarlyDataLen = uint32(data[16])<<24 | uint32(data[17])<<16 | uint32(data[18])<<8 | uint32(data[19])
+
+	l := int(data[20])<<8 | int(data[21])
+	if len(data) < 22+l+2 {
+		return alertDecodeError
+	}
+	s.pskSecret = data[22 : 22+l]
+	z := data[22+l:]
+
+	l = int(z[0])<<8 | int(z[1])
+	if len(z) < 2+l+2 {
+		return alertDecodeError
+	}
+	s.alpnProtocol = string(z[2 : 2+l])
+	z = z[2+l:]
+
+	l = int(z[0])<<8 | int(z[1])
+	if len(z) != 2+l {
+		return alertDecodeError
+	}
+	s.SNI = string(z[2 : 2+l])
+
+	return alertSuccess
+}
+
+func (c *Conn) encryptTicket(serialized []byte) ([]byte, error) {
+	encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size)
+	keyName := encrypted[:ticketKeyNameLen]
+	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
+	macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
+		return nil, err
+	}
+	key := c.config.ticketKeys()[0]
+	copy(keyName, key.keyName[:])
+	block, err := aes.NewCipher(key.aesKey[:])
+	if err != nil {
+		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
+	}
+	cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized)
+
+	mac := hmac.New(sha256.New, key.hmacKey[:])
+	mac.Write(encrypted[:len(encrypted)-sha256.Size])
+	mac.Sum(macBytes[:0])
+
+	return encrypted, nil
+}
+
+func (c *Conn) decryptTicket(encrypted []byte) (serialized []byte, usedOldKey bool) {
+	if c.config.SessionTicketsDisabled ||
+		len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
+		return nil, false
+	}
+
+	keyName := encrypted[:ticketKeyNameLen]
+	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
+	macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+	keys := c.config.ticketKeys()
+	keyIndex := -1
+	for i, candidateKey := range keys {
+		if bytes.Equal(keyName, candidateKey.keyName[:]) {
+			keyIndex = i
+			break
+		}
+	}
+
+	if keyIndex == -1 {
+		return nil, false
+	}
+	key := &keys[keyIndex]
+
+	mac := hmac.New(sha256.New, key.hmacKey[:])
+	mac.Write(encrypted[:len(encrypted)-sha256.Size])
+	expected := mac.Sum(nil)
+
+	if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
+		return nil, false
+	}
+
+	block, err := aes.NewCipher(key.aesKey[:])
+	if err != nil {
+		return nil, false
+	}
+	ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
+	plaintext := ciphertext
+	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
+
+	return plaintext, keyIndex > 0
+}

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

@@ -0,0 +1,297 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tls partially implements TLS 1.2, as specified in RFC 5246.
+package tls
+
+// BUG(agl): The crypto/tls package only implements some countermeasures
+// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
+// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"net"
+	"strings"
+	"time"
+)
+
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func Server(conn net.Conn, config *Config) *Conn {
+	return &Conn{conn: conn, config: config}
+}
+
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// The config cannot be nil: users must set either ServerName or
+// InsecureSkipVerify in the config.
+func Client(conn net.Conn, config *Config) *Conn {
+	return &Conn{conn: conn, config: config, isClient: true}
+}
+
+// A listener implements a network listener (net.Listener) for TLS connections.
+type listener struct {
+	net.Listener
+	config *Config
+}
+
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection is of type *Conn.
+func (l *listener) Accept() (net.Conn, error) {
+	c, err := l.Listener.Accept()
+	if err != nil {
+		return nil, err
+	}
+	return Server(c, l.config), nil
+}
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func NewListener(inner net.Listener, config *Config) net.Listener {
+	l := new(listener)
+	l.Listener = inner
+	l.config = config
+	return l
+}
+
+// Listen creates a TLS listener accepting connections on the
+// given network address using net.Listen.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func Listen(network, laddr string, config *Config) (net.Listener, error) {
+	if config == nil || (len(config.Certificates) == 0 && config.GetCertificate == nil) {
+		return nil, errors.New("tls: neither Certificates nor GetCertificate set in Config")
+	}
+	l, err := net.Listen(network, laddr)
+	if err != nil {
+		return nil, err
+	}
+	return NewListener(l, config), nil
+}
+
+type timeoutError struct{}
+
+func (timeoutError) Error() string   { return "tls: DialWithDialer timed out" }
+func (timeoutError) Timeout() bool   { return true }
+func (timeoutError) Temporary() bool { return true }
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of Config for the defaults.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+	// We want the Timeout and Deadline values from dialer to cover the
+	// whole process: TCP connection and TLS handshake. This means that we
+	// also need to start our own timers now.
+	timeout := dialer.Timeout
+
+	if !dialer.Deadline.IsZero() {
+		deadlineTimeout := time.Until(dialer.Deadline)
+		if timeout == 0 || deadlineTimeout < timeout {
+			timeout = deadlineTimeout
+		}
+	}
+
+	var errChannel chan error
+
+	if timeout != 0 {
+		errChannel = make(chan error, 2)
+		time.AfterFunc(timeout, func() {
+			errChannel <- timeoutError{}
+		})
+	}
+
+	rawConn, err := dialer.Dial(network, addr)
+	if err != nil {
+		return nil, err
+	}
+
+	colonPos := strings.LastIndex(addr, ":")
+	if colonPos == -1 {
+		colonPos = len(addr)
+	}
+	hostname := addr[:colonPos]
+
+	if config == nil {
+		config = defaultConfig()
+	}
+	// If no ServerName is set, infer the ServerName
+	// from the hostname we're connecting to.
+	if config.ServerName == "" {
+		// Make a copy to avoid polluting argument or default.
+		c := config.Clone()
+		c.ServerName = hostname
+		config = c
+	}
+
+	conn := Client(rawConn, config)
+
+	if timeout == 0 {
+		err = conn.Handshake()
+	} else {
+		go func() {
+			errChannel <- conn.Handshake()
+		}()
+
+		err = <-errChannel
+	}
+
+	if err != nil {
+		rawConn.Close()
+		return nil, err
+	}
+
+	return conn, nil
+}
+
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, error) {
+	return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair
+// of files. The files must contain PEM encoded data. The certificate file
+// may contain intermediate certificates following the leaf certificate to
+// form a certificate chain. On successful return, Certificate.Leaf will
+// be nil because the parsed form of the certificate is not retained.
+func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
+	certPEMBlock, err := ioutil.ReadFile(certFile)
+	if err != nil {
+		return Certificate{}, err
+	}
+	keyPEMBlock, err := ioutil.ReadFile(keyFile)
+	if err != nil {
+		return Certificate{}, err
+	}
+	return X509KeyPair(certPEMBlock, keyPEMBlock)
+}
+
+// X509KeyPair parses a public/private key pair from a pair of
+// PEM encoded data. On successful return, Certificate.Leaf will be nil because
+// the parsed form of the certificate is not retained.
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
+	fail := func(err error) (Certificate, error) { return Certificate{}, err }
+
+	var cert Certificate
+	var skippedBlockTypes []string
+	for {
+		var certDERBlock *pem.Block
+		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
+		if certDERBlock == nil {
+			break
+		}
+		if certDERBlock.Type == "CERTIFICATE" {
+			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
+		} else {
+			skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
+		}
+	}
+
+	if len(cert.Certificate) == 0 {
+		if len(skippedBlockTypes) == 0 {
+			return fail(errors.New("tls: failed to find any PEM data in certificate input"))
+		}
+		if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
+			return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
+		}
+		return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+	}
+
+	skippedBlockTypes = skippedBlockTypes[:0]
+	var keyDERBlock *pem.Block
+	for {
+		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
+		if keyDERBlock == nil {
+			if len(skippedBlockTypes) == 0 {
+				return fail(errors.New("tls: failed to find any PEM data in key input"))
+			}
+			if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
+				return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key"))
+			}
+			return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+		}
+		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
+			break
+		}
+		skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type)
+	}
+
+	var err error
+	cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
+	if err != nil {
+		return fail(err)
+	}
+
+	// We don't need to parse the public key for TLS, but we so do anyway
+	// to check that it looks sane and matches the private key.
+	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+	if err != nil {
+		return fail(err)
+	}
+
+	switch pub := x509Cert.PublicKey.(type) {
+	case *rsa.PublicKey:
+		priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
+		if !ok {
+			return fail(errors.New("tls: private key type does not match public key type"))
+		}
+		if pub.N.Cmp(priv.N) != 0 {
+			return fail(errors.New("tls: private key does not match public key"))
+		}
+	case *ecdsa.PublicKey:
+		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+		if !ok {
+			return fail(errors.New("tls: private key type does not match public key type"))
+		}
+		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
+			return fail(errors.New("tls: private key does not match public key"))
+		}
+	default:
+		return fail(errors.New("tls: unknown public key algorithm"))
+	}
+
+	return cert, nil
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
+	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+		return key, nil
+	}
+	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+		switch key := key.(type) {
+		case *rsa.PrivateKey, *ecdsa.PrivateKey:
+			return key, nil
+		default:
+			return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
+		}
+	}
+	if key, err := x509.ParseECPrivateKey(der); err == nil {
+		return key, nil
+	}
+
+	return nil, errors.New("tls: failed to parse private key")
+}

+ 32 - 0
vendor/golang.org/x/crypto/internal/subtle/aliasing.go

@@ -0,0 +1,32 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+
+// Package subtle implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+package subtle // import "golang.org/x/crypto/internal/subtle"
+
+import "unsafe"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+	return len(x) > 0 && len(y) > 0 &&
+		uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+		uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+	if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+		return false
+	}
+	return AnyOverlap(x, y)
+}

+ 35 - 0
vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go

@@ -0,0 +1,35 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build appengine
+
+// Package subtle implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+package subtle // import "golang.org/x/crypto/internal/subtle"
+
+// This is the Google App Engine standard variant based on reflect
+// because the unsafe package and cgo are disallowed.
+
+import "reflect"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+	return len(x) > 0 && len(y) > 0 &&
+		reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
+		reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+	if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+		return false
+	}
+	return AnyOverlap(x, y)
+}

+ 38 - 0
vendor/golang.org/x/sys/cpu/cpu.go

@@ -0,0 +1,38 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cpu implements processor feature detection for
+// various CPU architectures.
+package cpu
+
+// CacheLinePad is used to pad structs to avoid false sharing.
+type CacheLinePad struct{ _ [cacheLineSize]byte }
+
+// X86 contains the supported CPU features of the
+// current X86/AMD64 platform. If the current platform
+// is not X86/AMD64 then all feature flags are false.
+//
+// X86 is padded to avoid false sharing. Further the HasAVX
+// and HasAVX2 are only set if the OS supports XMM and YMM
+// registers in addition to the CPUID feature bit being set.
+var X86 struct {
+	_            CacheLinePad
+	HasAES       bool // AES hardware implementation (AES NI)
+	HasADX       bool // Multi-precision add-carry instruction extensions
+	HasAVX       bool // Advanced vector extension
+	HasAVX2      bool // Advanced vector extension 2
+	HasBMI1      bool // Bit manipulation instruction set 1
+	HasBMI2      bool // Bit manipulation instruction set 2
+	HasERMS      bool // Enhanced REP for MOVSB and STOSB
+	HasFMA       bool // Fused-multiply-add instructions
+	HasOSXSAVE   bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
+	HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
+	HasPOPCNT    bool // Hamming weight instruction POPCNT.
+	HasSSE2      bool // Streaming SIMD extension 2 (always available on amd64)
+	HasSSE3      bool // Streaming SIMD extension 3
+	HasSSSE3     bool // Supplemental streaming SIMD extension 3
+	HasSSE41     bool // Streaming SIMD extension 4 and 4.1
+	HasSSE42     bool // Streaming SIMD extension 4 and 4.2
+	_            CacheLinePad
+}

+ 7 - 0
vendor/golang.org/x/sys/cpu/cpu_arm.go

@@ -0,0 +1,7 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const cacheLineSize = 32

+ 7 - 0
vendor/golang.org/x/sys/cpu/cpu_arm64.go

@@ -0,0 +1,7 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const cacheLineSize = 64

+ 16 - 0
vendor/golang.org/x/sys/cpu/cpu_gc_x86.go

@@ -0,0 +1,16 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32
+// +build !gccgo
+
+package cpu
+
+// cpuid is implemented in cpu_x86.s for gc compiler
+// and in cpu_gccgo.c for gccgo.
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
+
+// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler
+// and in cpu_gccgo.c for gccgo.
+func xgetbv() (eax, edx uint32)

+ 43 - 0
vendor/golang.org/x/sys/cpu/cpu_gccgo.c

@@ -0,0 +1,43 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32
+// +build gccgo
+
+#include <cpuid.h>
+#include <stdint.h>
+
+// Need to wrap __get_cpuid_count because it's declared as static.
+int
+gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf,
+                   uint32_t *eax, uint32_t *ebx,
+                   uint32_t *ecx, uint32_t *edx)
+{
+	return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx);
+}
+
+// xgetbv reads the contents of an XCR (Extended Control Register)
+// specified in the ECX register into registers EDX:EAX.
+// Currently, the only supported value for XCR is 0.
+//
+// TODO: Replace with a better alternative:
+//
+//     #include <xsaveintrin.h>
+//
+//     #pragma GCC target("xsave")
+//
+//     void gccgoXgetbv(uint32_t *eax, uint32_t *edx) {
+//       unsigned long long x = _xgetbv(0);
+//       *eax = x & 0xffffffff;
+//       *edx = (x >> 32) & 0xffffffff;
+//     }
+//
+// Note that _xgetbv is defined starting with GCC 8.
+void
+gccgoXgetbv(uint32_t *eax, uint32_t *edx)
+{
+	__asm("  xorl %%ecx, %%ecx\n"
+	      "  xgetbv"
+	    : "=a"(*eax), "=d"(*edx));
+}

+ 26 - 0
vendor/golang.org/x/sys/cpu/cpu_gccgo.go

@@ -0,0 +1,26 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32
+// +build gccgo
+
+package cpu
+
+//extern gccgoGetCpuidCount
+func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32)
+
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) {
+	var a, b, c, d uint32
+	gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d)
+	return a, b, c, d
+}
+
+//extern gccgoXgetbv
+func gccgoXgetbv(eax, edx *uint32)
+
+func xgetbv() (eax, edx uint32) {
+	var a, d uint32
+	gccgoXgetbv(&a, &d)
+	return a, d
+}

+ 9 - 0
vendor/golang.org/x/sys/cpu/cpu_mips64x.go

@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips64 mips64le
+
+package cpu
+
+const cacheLineSize = 32

+ 9 - 0
vendor/golang.org/x/sys/cpu/cpu_mipsx.go

@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+package cpu
+
+const cacheLineSize = 32

+ 9 - 0
vendor/golang.org/x/sys/cpu/cpu_ppc64x.go

@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ppc64 ppc64le
+
+package cpu
+
+const cacheLineSize = 128

+ 7 - 0
vendor/golang.org/x/sys/cpu/cpu_s390x.go

@@ -0,0 +1,7 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const cacheLineSize = 256

+ 55 - 0
vendor/golang.org/x/sys/cpu/cpu_x86.go

@@ -0,0 +1,55 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32
+
+package cpu
+
+const cacheLineSize = 64
+
+func init() {
+	maxID, _, _, _ := cpuid(0, 0)
+
+	if maxID < 1 {
+		return
+	}
+
+	_, _, ecx1, edx1 := cpuid(1, 0)
+	X86.HasSSE2 = isSet(26, edx1)
+
+	X86.HasSSE3 = isSet(0, ecx1)
+	X86.HasPCLMULQDQ = isSet(1, ecx1)
+	X86.HasSSSE3 = isSet(9, ecx1)
+	X86.HasFMA = isSet(12, ecx1)
+	X86.HasSSE41 = isSet(19, ecx1)
+	X86.HasSSE42 = isSet(20, ecx1)
+	X86.HasPOPCNT = isSet(23, ecx1)
+	X86.HasAES = isSet(25, ecx1)
+	X86.HasOSXSAVE = isSet(27, ecx1)
+
+	osSupportsAVX := false
+	// For XGETBV, OSXSAVE bit is required and sufficient.
+	if X86.HasOSXSAVE {
+		eax, _ := xgetbv()
+		// Check if XMM and YMM registers have OS support.
+		osSupportsAVX = isSet(1, eax) && isSet(2, eax)
+	}
+
+	X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
+
+	if maxID < 7 {
+		return
+	}
+
+	_, ebx7, _, _ := cpuid(7, 0)
+	X86.HasBMI1 = isSet(3, ebx7)
+	X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
+	X86.HasBMI2 = isSet(8, ebx7)
+	X86.HasERMS = isSet(9, ebx7)
+	X86.HasADX = isSet(19, ebx7)
+}
+
+func isSet(bitpos uint, value uint32) bool {
+	return value&(1<<bitpos) != 0
+}

+ 27 - 0
vendor/golang.org/x/sys/cpu/cpu_x86.s

@@ -0,0 +1,27 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32
+// +build !gccgo
+
+#include "textflag.h"
+
+// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
+TEXT ·cpuid(SB), NOSPLIT, $0-24
+	MOVL eaxArg+0(FP), AX
+	MOVL ecxArg+4(FP), CX
+	CPUID
+	MOVL AX, eax+8(FP)
+	MOVL BX, ebx+12(FP)
+	MOVL CX, ecx+16(FP)
+	MOVL DX, edx+20(FP)
+	RET
+
+// func xgetbv() (eax, edx uint32)
+TEXT ·xgetbv(SB),NOSPLIT,$0-8
+	MOVL $0, CX
+	XGETBV
+	MOVL AX, eax+0(FP)
+	MOVL DX, edx+4(FP)
+	RET

+ 18 - 0
vendor/vendor.json

@@ -56,6 +56,12 @@
 			"revision": "18963be5f9c52609b1dd6960d1370d34e63fc3fb",
 			"revisionTime": "2018-04-26T17:24:40Z"
 		},
+		{
+			"checksumSHA1": "dNsok0tfyatNVVcK1tdGQAPvOFI=",
+			"path": "github.com/Psiphon-Labs/tls-tris",
+			"revision": "5cce86280f391cc1c66f19f60b6e53b5b3c56f3b",
+			"revisionTime": "2018-08-30T17:38:46Z"
+		},
 		{
 			"checksumSHA1": "OBN3dfn0yx9L3I2RPo58o27my2k=",
 			"path": "github.com/Psiphon-Labs/utls",
@@ -585,6 +591,12 @@
 			"revision": "b0697eccbea9adec5b7ba8008f4c33d98d733388",
 			"revisionTime": "2018-04-23T13:30:03Z"
 		},
+		{
+			"checksumSHA1": "/U7f2gaH6DnEmLguVLDbipU6kXU=",
+			"path": "golang.org/x/crypto/internal/subtle",
+			"revision": "614d502a4dac94afa3a6ce146bd1736da82514c6",
+			"revisionTime": "2018-07-28T08:01:47Z"
+		},
 		{
 			"checksumSHA1": "kVKE0OX1Xdw5mG7XKT86DLLKE2I=",
 			"path": "golang.org/x/crypto/poly1305",
@@ -657,6 +669,12 @@
 			"revision": "1d60e4601c6fd243af51cc01ddf169918a5407ca",
 			"revisionTime": "2018-03-14T17:21:19Z"
 		},
+		{
+			"checksumSHA1": "REkmyB368pIiip76LiqMLspgCRk=",
+			"path": "golang.org/x/sys/cpu",
+			"revision": "49385e6e15226593f68b26af201feec29d5bba22",
+			"revisionTime": "2018-08-30T14:08:21Z"
+		},
 		{
 			"checksumSHA1": "uggjqMBFNJd11oNco2kbkAT641w=",
 			"path": "golang.org/x/sys/unix",