Commit af125a51 authored by Adam Langley's avatar Adam Langley

crypto/tls: allow renegotiation to be handled by a client.

This change adds Config.Renegotiation which controls whether a TLS
client will accept renegotiation requests from a server. This is used,
for example, by some web servers that wish to “add” a client certificate
to an HTTPS connection.

This is disabled by default because it significantly complicates the
state machine.

Originally, handshakeMutex was taken before locking either Conn.in or
Conn.out. However, if renegotiation is permitted then a handshake may
be triggered during a Read() call. If Conn.in were unlocked before
taking handshakeMutex then a concurrent Read() call could see an
intermediate state and trigger an error. Thus handshakeMutex is now
locked after Conn.in and the handshake functions assume that Conn.in is
locked for the duration of the handshake.

Additionally, handshakeMutex used to protect Conn.out also. With the
possibility of renegotiation that's no longer viable and so
writeRecordLocked has been split off.

Fixes #5742.

Change-Id: I935914db1f185d507ff39bba8274c148d756a1c8
Reviewed-on: https://go-review.googlesource.com/22475
Run-TryBot: Adam Langley <agl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent d610d304
......@@ -48,6 +48,7 @@ const (
// TLS handshake message types.
const (
typeHelloRequest uint8 = 0
typeClientHello uint8 = 1
typeServerHello uint8 = 2
typeNewSessionTicket uint8 = 4
......@@ -238,6 +239,33 @@ type ClientHelloInfo struct {
SupportedPoints []uint8
}
// 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
......@@ -355,6 +383,10 @@ type Config struct {
// 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
serverInitOnce sync.Once // guards calling (*Config).serverInit
// mutex protects sessionTicketKeys
......
This diff is collapsed.
......@@ -29,11 +29,16 @@ type clientHandshakeState struct {
session *ClientSessionState
}
// 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
if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
}
......@@ -51,17 +56,21 @@ func (c *Conn) clientHandshake() error {
}
hello := &clientHelloMsg{
vers: c.config.maxVersion(),
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
ocspStapling: true,
scts: true,
serverName: hostnameInSNI(c.config.ServerName),
supportedCurves: c.config.curvePreferences(),
supportedPoints: []uint8{pointFormatUncompressed},
nextProtoNeg: len(c.config.NextProtos) > 0,
secureRenegotiation: true,
alpnProtocols: c.config.NextProtos,
vers: c.config.maxVersion(),
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
ocspStapling: true,
scts: true,
serverName: hostnameInSNI(c.config.ServerName),
supportedCurves: c.config.curvePreferences(),
supportedPoints: []uint8{pointFormatUncompressed},
nextProtoNeg: len(c.config.NextProtos) > 0,
secureRenegotiationSupported: true,
alpnProtocols: c.config.NextProtos,
}
if c.handshakes > 0 {
hello.secureRenegotiation = c.clientFinished[:]
}
possibleCipherSuites := c.config.cipherSuites()
......@@ -102,7 +111,12 @@ NextCipherSuite:
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 occured.
if sessionCache != nil && c.handshakes == 0 {
// Try to resume a previously negotiated TLS session, if
// available.
cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
......@@ -199,10 +213,11 @@ NextCipherSuite:
if err := hs.readSessionTicket(); err != nil {
return err
}
if err := hs.readFinished(c.firstFinished[:]); err != nil {
if err := hs.readFinished(c.serverFinished[:]); err != nil {
return err
}
if err := hs.sendFinished(nil); err != nil {
c.clientFinishedIsFirst = false
if err := hs.sendFinished(c.clientFinished[:]); err != nil {
return err
}
} else {
......@@ -212,13 +227,14 @@ NextCipherSuite:
if err := hs.establishKeys(); err != nil {
return err
}
if err := hs.sendFinished(c.firstFinished[:]); err != nil {
if err := hs.sendFinished(c.clientFinished[:]); err != nil {
return err
}
c.clientFinishedIsFirst = true
if err := hs.readSessionTicket(); err != nil {
return err
}
if err := hs.readFinished(nil); err != nil {
if err := hs.readFinished(c.serverFinished[:]); err != nil {
return err
}
}
......@@ -247,47 +263,62 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
hs.finishedHash.Write(certMsg.marshal())
certs := make([]*x509.Certificate, len(certMsg.certificates))
for i, asn1Data := range certMsg.certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
return errors.New("tls: failed to parse certificate from server: " + err.Error())
if c.handshakes == 0 {
// If this is the first handshake on a connection, process and
// (optionally) verify the server's certificates.
certs := make([]*x509.Certificate, len(certMsg.certificates))
for i, asn1Data := range certMsg.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
}
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(),
}
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
for i, cert := range certs {
if i == 0 {
continue
}
opts.Intermediates.AddCert(cert)
}
c.verifiedChains, err = certs[0].Verify(opts)
if err != nil {
c.sendAlert(alertBadCertificate)
return err
}
opts.Intermediates.AddCert(cert)
}
c.verifiedChains, err = certs[0].Verify(opts)
if 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)
}
}
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
} 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")
}
}
c.peerCertificates = certs
if hs.serverHello.ocspStapling {
msg, err = c.readHandshake()
if err != nil {
......@@ -315,7 +346,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
skx, ok := msg.(*serverKeyExchangeMsg)
if ok {
hs.finishedHash.Write(skx.marshal())
err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
if err != nil {
c.sendAlert(alertUnexpectedMessage)
return err
......@@ -426,7 +457,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
}
preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0])
if err != nil {
c.sendAlert(alertInternalError)
return err
......@@ -526,6 +557,24 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
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
......@@ -577,8 +626,8 @@ func (hs *clientHandshakeState) readFinished(out []byte) error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
if err := c.in.error(); err != nil {
return err
if c.in.err != nil {
return c.in.err
}
msg, err := c.readHandshake()
......
This diff is collapsed.
......@@ -7,23 +7,24 @@ package tls
import "bytes"
type clientHelloMsg struct {
raw []byte
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
signatureAndHashes []signatureAndHash
secureRenegotiation bool
alpnProtocols []string
raw []byte
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
signatureAndHashes []signatureAndHash
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocols []string
}
func (m *clientHelloMsg) equal(i interface{}) bool {
......@@ -47,7 +48,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
m.secureRenegotiation == m1.secureRenegotiation &&
m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
eqStrings(m.alpnProtocols, m1.alpnProtocols)
}
......@@ -86,8 +88,8 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.signatureAndHashes)
numExtensions++
}
if m.secureRenegotiation {
extensionsLength += 1
if m.secureRenegotiationSupported {
extensionsLength += 1 + len(m.secureRenegotiation)
numExtensions++
}
if len(m.alpnProtocols) > 0 {
......@@ -248,12 +250,15 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[2:]
}
}
if m.secureRenegotiation {
if m.secureRenegotiationSupported {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
z[2] = 0
z[3] = 1
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)
......@@ -316,7 +321,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
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.secureRenegotiation = true
m.secureRenegotiationSupported = true
}
}
data = data[2+cipherSuiteLen:]
......@@ -448,10 +453,18 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
d = d[2:]
}
case extensionRenegotiationInfo:
if length != 1 || data[0] != 0 {
if length == 0 {
return false
}
d := data[:length]
l := int(d[0])
d = d[1:]
if l != len(d) {
return false
}
m.secureRenegotiation = true
m.secureRenegotiation = d
m.secureRenegotiationSupported = true
case extensionALPN:
if length < 2 {
return false
......@@ -483,19 +496,20 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
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 bool
alpnProtocol string
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
}
func (m *serverHelloMsg) equal(i interface{}) bool {
......@@ -523,7 +537,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
eqStrings(m.nextProtos, m1.nextProtos) &&
m.ocspStapling == m1.ocspStapling &&
m.ticketSupported == m1.ticketSupported &&
m.secureRenegotiation == m1.secureRenegotiation &&
m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
m.alpnProtocol == m1.alpnProtocol
}
......@@ -551,8 +566,8 @@ func (m *serverHelloMsg) marshal() []byte {
if m.ticketSupported {
numExtensions++
}
if m.secureRenegotiation {
extensionsLength += 1
if m.secureRenegotiationSupported {
extensionsLength += 1 + len(m.secureRenegotiation)
numExtensions++
}
if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
......@@ -624,12 +639,15 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = byte(extensionSessionTicket)
z = z[4:]
}
if m.secureRenegotiation {
if m.secureRenegotiationSupported {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
z[2] = 0
z[3] = 1
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)
......@@ -744,10 +762,18 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
m.ticketSupported = true
case extensionRenegotiationInfo:
if length != 1 || data[0] != 0 {
if length == 0 {
return false
}
m.secureRenegotiation = true
d := data[:length]
l := int(d[0])
d = d[1:]
if l != len(d) {
return false
}
m.secureRenegotiation = d
m.secureRenegotiationSupported = true
case extensionALPN:
d := data[:length]
if len(d) < 3 {
......@@ -1463,6 +1489,17 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
return true
}
type helloRequestMsg struct {
}
func (*helloRequestMsg) marshal() []byte {
return []byte{typeHelloRequest, 0, 0, 0}
}
func (*helloRequestMsg) unmarshal(data []byte) bool {
return len(data) == 4
}
func eqUint16s(x, y []uint16) bool {
if len(x) != len(y) {
return false
......
......@@ -35,6 +35,7 @@ type serverHandshakeState struct {
}
// serverHandshake performs a TLS handshake as a server.
// c.out.Mutex <= L; c.handshakeMutex <= L.
func (c *Conn) serverHandshake() error {
config := c.config
......@@ -67,9 +68,10 @@ func (c *Conn) serverHandshake() error {
return err
}
}
if err := hs.sendFinished(c.firstFinished[:]); err != nil {
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
return err
}
c.clientFinishedIsFirst = false
if err := hs.readFinished(nil); err != nil {
return err
}
......@@ -83,9 +85,10 @@ func (c *Conn) serverHandshake() error {
if err := hs.establishKeys(); err != nil {
return err
}
if err := hs.readFinished(c.firstFinished[:]); err != nil {
if err := hs.readFinished(c.clientFinished[:]); err != nil {
return err
}
c.clientFinishedIsFirst = true
if err := hs.sendSessionTicket(); err != nil {
return err
}
......@@ -165,7 +168,13 @@ Curves:
c.sendAlert(alertInternalError)
return false, err
}
hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
if len(hs.clientHello.secureRenegotiation) != 0 {
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
}
hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
hs.hello.compressionMethod = compressionNone
if len(hs.clientHello.serverName) > 0 {
c.serverName = hs.clientHello.serverName
......@@ -586,8 +595,8 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
if err := c.in.error(); err != nil {
return err
if c.in.err != nil {
return c.in.err
}
if hs.hello.nextProtoNeg {
......
......@@ -188,11 +188,11 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {
func TestRenegotiationExtension(t *testing.T) {
clientHello := &clientHelloMsg{
vers: VersionTLS12,
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
secureRenegotiation: true,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
vers: VersionTLS12,
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
secureRenegotiationSupported: true,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
}
var buf []byte
......@@ -229,7 +229,7 @@ func TestRenegotiationExtension(t *testing.T) {
t.Fatalf("Failed to parse ServerHello")
}
if !serverHello.secureRenegotiation {
if !serverHello.secureRenegotiationSupported {
t.Errorf("Secure renegotiation extension was not echoed.")
}
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
>>> Flow 1 (client to server)
00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
>>> Flow 2 (server to client)
00000000 16 03 03 00 59 02 00 00 55 03 03 b1 7d c5 82 a4 |....Y...U...}...|
00000010 f7 1d 3a b9 c0 da 13 7c 2f 75 22 a4 5f 2e 58 2a |..:....|/u"._.X*|
00000020 39 eb 18 7c bb 0d 98 ba 51 2e 4a 20 41 40 2f 53 |9..|....Q.J A@/S|
00000030 bc 16 e0 a4 44 07 f0 5e 8f 43 a3 69 87 0b 94 dd |....D..^.C.i....|
00000040 60 a0 20 d0 25 e1 a1 a0 b8 0d d8 00 c0 2f 00 00 |`. .%......../..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..|
00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......|
000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
000002e0 41 04 62 2a a7 2d 1f 7a 8d 7e 8a 9e 84 db df e2 |A.b*.-.z.~......|
000002f0 7c 35 d8 a1 9f ec 23 ef c7 c2 9a c5 45 02 6f eb ||5....#.....E.o.|
00000300 24 ed 77 e1 ca fe 9a be 06 1e ea 30 5a e7 13 00 |$.w........0Z...|
00000310 47 52 a4 a2 d8 ee 9d 4e 87 f5 48 83 6f 5d 8e 02 |GR.....N..H.o]..|
00000320 ff f5 04 01 00 80 19 f6 63 a1 47 d1 cf 4d 28 73 |........c.G..M(s|
00000330 4e 31 03 78 b5 17 ba 53 64 d0 b8 3f 04 77 9d 6b |N1.x...Sd..?.w.k|
00000340 85 d0 d4 1e 02 90 b9 ab 10 dc d7 b1 79 1b 12 80 |............y...|
00000350 e1 5a 4b 69 80 2d 2a 37 4c fd 72 a9 c3 8e 2a 1f |.ZKi.-*7L.r...*.|
00000360 1a 3f 74 49 c6 49 ce 2f 02 58 3f 68 f0 f6 b5 8a |.?tI.I./.X?h....|
00000370 16 11 8b 63 15 6a f2 91 f1 74 a8 f0 6d dc 91 0a |...c.j...t..m...|
00000380 b4 e2 4e 10 14 1d b9 da 05 29 bf 31 30 ee 7d a5 |..N......).10.}.|
00000390 75 4e da ff db 43 04 a7 55 4b dd 93 4c 5f 32 be |uN...C..UK..L_2.|
000003a0 e9 23 c9 a1 23 86 16 03 03 00 04 0e 00 00 00 |.#..#..........|
>>> Flow 3 (client to server)
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 d4 cb |.....(..........|
00000060 e2 c0 1e fe cb b0 d6 fe da 7c 8f 8c b2 2f f7 c1 |.........|.../..|
00000070 3d e9 52 6e 70 c1 13 13 87 ff 12 85 6c 2c |=.Rnp.......l,|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 28 0a 86 ff b2 73 |..........(....s|
00000010 35 40 a1 89 9f 21 1f 0b 2f 79 50 70 eb 74 e1 2f |5@...!../yPp.t./|
00000020 4d bc 5c 3c 85 0b 60 cc 73 36 e4 08 01 0a 4c 75 |M.\<..`.s6....Lu|
00000030 0f a2 9c |...|
>>> Flow 5 (client to server)
00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 c9 78 b7 |..............x.|
00000010 07 d1 a9 95 fc b4 aa 57 16 77 86 fb c7 a9 c6 12 |.......W.w......|
00000020 bc bd 09 |...|
>>> Flow 6 (server to client)
00000000 16 03 03 00 1c 0a 86 ff b2 73 35 40 a2 4d b1 9b |.........s5@.M..|
00000010 eb 51 76 71 6b b8 88 fe 21 60 bb 8b 2a cc e3 3e |.Qvqk...!`..*..>|
00000020 d5 |.|
>>> Flow 7 (client to server)
00000000 15 03 03 00 1a 00 00 00 00 00 00 00 02 0e da c6 |................|
00000010 01 09 cc 0f bb 7d de c9 41 8d 30 b5 d5 b7 f2 15 |.....}..A.0.....|
00000020 03 03 00 1a 00 00 00 00 00 00 00 03 a7 0e 24 98 |..............$.|
00000030 32 62 1b a9 98 17 b6 b3 71 af 88 7a a3 6b |2b......q..z.k|
......@@ -1893,5 +1893,6 @@ func cloneTLSClientConfig(cfg *tls.Config) *tls.Config {
MinVersion: cfg.MinVersion,
MaxVersion: cfg.MaxVersion,
CurvePreferences: cfg.CurvePreferences,
Renegotiation: cfg.Renegotiation,
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment