package tls
import (
)
type Conn struct {
conn net.Conn
isClient bool
handshakeFn func() error
handshakeStatus uint32
handshakeMutex sync.Mutex
handshakeErr error
vers uint16
haveVers bool
config *Config
handshakes int
didResume bool
cipherSuite uint16
ocspResponse []byte
scts [][]byte
peerCertificates []*x509.Certificate
verifiedChains [][]*x509.Certificate
serverName string
secureRenegotiation bool
ekm func(label string, context []byte, length int) ([]byte, error)
resumptionSecret []byte
ticketKeys []ticketKey
clientFinishedIsFirst bool
closeNotifyErr error
closeNotifySent bool
clientFinished [12]byte
serverFinished [12]byte
clientProtocol string
in, out halfConn
rawInput bytes.Buffer
input bytes.Reader
hand bytes.Buffer
buffering bool
sendBuf []byte
bytesSent int64
packetsSent int64
retryCount int
activeCall int32
tmp [16]byte
}
func ( *Conn) () net.Addr {
return .conn.LocalAddr()
}
func ( *Conn) () net.Addr {
return .conn.RemoteAddr()
}
func ( *Conn) ( time.Time) error {
return .conn.SetDeadline()
}
func ( *Conn) ( time.Time) error {
return .conn.SetReadDeadline()
}
func ( *Conn) ( time.Time) error {
return .conn.SetWriteDeadline()
}
type halfConn struct {
sync.Mutex
err error
version uint16
cipher interface{}
mac hash.Hash
seq [8]byte
scratchBuf [13]byte
nextCipher interface{}
nextMac hash.Hash
trafficSecret []byte
}
type permanentError struct {
err net.Error
}
func ( *permanentError) () string { return .err.Error() }
func ( *permanentError) () error { return .err }
func ( *permanentError) () bool { return .err.Timeout() }
func ( *permanentError) () bool { return false }
func ( *halfConn) ( error) error {
if , := .(net.Error); {
.err = &permanentError{err: }
} else {
.err =
}
return .err
}
func ( *halfConn) ( uint16, interface{}, hash.Hash) {
.version =
.nextCipher =
.nextMac =
}
func ( *halfConn) () error {
if .nextCipher == nil || .version == VersionTLS13 {
return alertInternalError
}
.cipher = .nextCipher
.mac = .nextMac
.nextCipher = nil
.nextMac = nil
for := range .seq {
.seq[] = 0
}
return nil
}
func ( *halfConn) ( *cipherSuiteTLS13, []byte) {
.trafficSecret =
, := .trafficKey()
.cipher = .aead(, )
for := range .seq {
.seq[] = 0
}
}
func ( *halfConn) () {
for := 7; >= 0; -- {
.seq[]++
if .seq[] != 0 {
return
}
}
panic("TLS: sequence number wraparound")
}
func ( *halfConn) () int {
if .cipher == nil {
return 0
}
switch c := .cipher.(type) {
case cipher.Stream:
return 0
case aead:
return .explicitNonceLen()
case cbcMode:
if .version >= VersionTLS11 {
return .BlockSize()
}
return 0
default:
panic("unknown cipher type")
}
}
func ( []byte) ( int, byte) {
if len() < 1 {
return 0, 0
}
:= [len()-1]
:= uint(len()-1) - uint()
= byte(int32(^) >> 31)
:= 256
if > len() {
= len()
}
for := 0; < ; ++ {
:= uint() - uint()
:= byte(int32(^) >> 31)
:= [len()-1-]
&^= & ^ &
}
&= << 4
&= << 2
&= << 1
= uint8(int8() >> 7)
&=
= int() + 1
return
}
func (, int) int {
return + (-%)%
}
type cbcMode interface {
cipher.BlockMode
SetIV([]byte)
}
func ( *halfConn) ( []byte) ([]byte, recordType, error) {
var []byte
:= recordType([0])
:= [recordHeaderLen:]
if .version == VersionTLS13 && == recordTypeChangeCipherSpec {
return , , nil
}
:= byte(255)
:= 0
:= .explicitNonceLen()
if .cipher != nil {
switch c := .cipher.(type) {
case cipher.Stream:
.XORKeyStream(, )
case aead:
if len() < {
return nil, 0, alertBadRecordMAC
}
:= [:]
if len() == 0 {
= .seq[:]
}
= [:]
var []byte
if .version == VersionTLS13 {
= [:recordHeaderLen]
} else {
= append(.scratchBuf[:0], .seq[:]...)
= append(, [:3]...)
:= len() - .Overhead()
= append(, byte(>>8), byte())
}
var error
, = .Open([:0], , , )
if != nil {
return nil, 0, alertBadRecordMAC
}
case cbcMode:
:= .BlockSize()
:= + roundUp(.mac.Size()+1, )
if len()% != 0 || len() < {
return nil, 0, alertBadRecordMAC
}
if > 0 {
.SetIV([:])
= [:]
}
.CryptBlocks(, )
, = extractPadding()
default:
panic("unknown cipher type")
}
if .version == VersionTLS13 {
if != recordTypeApplicationData {
return nil, 0, alertUnexpectedMessage
}
if len() > maxPlaintext+1 {
return nil, 0, alertRecordOverflow
}
for := len() - 1; >= 0; -- {
if [] != 0 {
= recordType([])
= [:]
break
}
if == 0 {
return nil, 0, alertUnexpectedMessage
}
}
}
} else {
=
}
if .mac != nil {
:= .mac.Size()
if len() < {
return nil, 0, alertBadRecordMAC
}
:= len() - -
= subtle.ConstantTimeSelect(int(uint32()>>31), 0, )
[3] = byte( >> 8)
[4] = byte()
:= [ : +]
:= tls10MAC(.mac, .scratchBuf[:0], .seq[:], [:recordHeaderLen], [:], [+:])
:= subtle.ConstantTimeCompare(, ) & int()
if != 1 {
return nil, 0, alertBadRecordMAC
}
= [:]
}
.incSeq()
return , , nil
}
func ( []byte, int) (, []byte) {
if := len() + ; cap() >= {
= [:]
} else {
= make([]byte, )
copy(, )
}
= [len():]
return
}
func ( *halfConn) (, []byte, io.Reader) ([]byte, error) {
if .cipher == nil {
return append(, ...), nil
}
var []byte
if := .explicitNonceLen(); > 0 {
, = sliceForAppend(, )
if , := .cipher.(cbcMode); ! && < 16 {
copy(, .seq[:])
} else {
if , := io.ReadFull(, ); != nil {
return nil,
}
}
}
var []byte
switch c := .cipher.(type) {
case cipher.Stream:
:= tls10MAC(.mac, .scratchBuf[:0], .seq[:], [:recordHeaderLen], , nil)
, = sliceForAppend(, len()+len())
.XORKeyStream([:len()], )
.XORKeyStream([len():], )
case aead:
:=
if len() == 0 {
= .seq[:]
}
if .version == VersionTLS13 {
= append(, ...)
= append(, [0])
[0] = byte(recordTypeApplicationData)
:= len() + 1 + .Overhead()
[3] = byte( >> 8)
[4] = byte()
= .Seal([:recordHeaderLen],
, [recordHeaderLen:], [:recordHeaderLen])
} else {
:= append(.scratchBuf[:0], .seq[:]...)
= append(, [:recordHeaderLen]...)
= .Seal(, , , )
}
case cbcMode:
:= tls10MAC(.mac, .scratchBuf[:0], .seq[:], [:recordHeaderLen], , nil)
:= .BlockSize()
:= len() + len()
:= - %
, = sliceForAppend(, +)
copy(, )
copy([len():], )
for := ; < len(); ++ {
[] = byte( - 1)
}
if len() > 0 {
.SetIV()
}
.CryptBlocks(, )
default:
panic("unknown cipher type")
}
:= len() - recordHeaderLen
[3] = byte( >> 8)
[4] = byte()
.incSeq()
return , nil
}
type RecordHeaderError struct {
Msg string
RecordHeader [5]byte
Conn net.Conn
}
func ( RecordHeaderError) () string { return "tls: " + .Msg }
func ( *Conn) ( net.Conn, string) ( RecordHeaderError) {
.Msg =
.Conn =
copy(.RecordHeader[:], .rawInput.Bytes())
return
}
func ( *Conn) () error {
return .readRecordOrCCS(false)
}
func ( *Conn) () error {
return .readRecordOrCCS(true)
}
func ( *Conn) ( bool) error {
if .in.err != nil {
return .in.err
}
:= .handshakeComplete()
if .input.Len() != 0 {
return .in.setErrorLocked(errors.New("tls: internal error: attempted to read record with pending application data"))
}
.input.Reset(nil)
if := .readFromUntil(.conn, recordHeaderLen); != nil {
if == io.ErrUnexpectedEOF && .rawInput.Len() == 0 {
= io.EOF
}
if , := .(net.Error); ! || !.Temporary() {
.in.setErrorLocked()
}
return
}
:= .rawInput.Bytes()[:recordHeaderLen]
:= recordType([0])
if ! && == 0x80 {
.sendAlert(alertProtocolVersion)
return .in.setErrorLocked(.newRecordHeaderError(nil, "unsupported SSLv2 handshake received"))
}
:= uint16([1])<<8 | uint16([2])
:= int([3])<<8 | int([4])
if .haveVers && .vers != VersionTLS13 && != .vers {
.sendAlert(alertProtocolVersion)
:= fmt.Sprintf("received record with version %x when expecting version %x", , .vers)
return .in.setErrorLocked(.newRecordHeaderError(nil, ))
}
if !.haveVers {
if ( != recordTypeAlert && != recordTypeHandshake) || >= 0x1000 {
return .in.setErrorLocked(.newRecordHeaderError(.conn, "first record does not look like a TLS handshake"))
}
}
if .vers == VersionTLS13 && > maxCiphertextTLS13 || > maxCiphertext {
.sendAlert(alertRecordOverflow)
:= fmt.Sprintf("oversized record received with length %d", )
return .in.setErrorLocked(.newRecordHeaderError(nil, ))
}
if := .readFromUntil(.conn, recordHeaderLen+); != nil {
if , := .(net.Error); ! || !.Temporary() {
.in.setErrorLocked()
}
return
}
:= .rawInput.Next(recordHeaderLen + )
, , := .in.decrypt()
if != nil {
return .in.setErrorLocked(.sendAlert(.(alert)))
}
if len() > maxPlaintext {
return .in.setErrorLocked(.sendAlert(alertRecordOverflow))
}
if .in.cipher == nil && == recordTypeApplicationData {
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
if != recordTypeAlert && != recordTypeChangeCipherSpec && len() > 0 {
.retryCount = 0
}
if .vers == VersionTLS13 && != recordTypeHandshake && .hand.Len() > 0 {
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
switch {
default:
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
case recordTypeAlert:
if len() != 2 {
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
if alert([1]) == alertCloseNotify {
return .in.setErrorLocked(io.EOF)
}
if .vers == VersionTLS13 {
return .in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert([1])})
}
switch [0] {
case alertLevelWarning:
return .retryReadRecord()
case alertLevelError:
return .in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert([1])})
default:
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
case recordTypeChangeCipherSpec:
if len() != 1 || [0] != 1 {
return .in.setErrorLocked(.sendAlert(alertDecodeError))
}
if .hand.Len() > 0 {
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
if .vers == VersionTLS13 {
return .retryReadRecord()
}
if ! {
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
if := .in.changeCipherSpec(); != nil {
return .in.setErrorLocked(.sendAlert(.(alert)))
}
case recordTypeApplicationData:
if ! || {
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
if len() == 0 {
return .retryReadRecord()
}
.input.Reset()
case recordTypeHandshake:
if len() == 0 || {
return .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
.hand.Write()
}
return nil
}
func ( *Conn) ( bool) error {
.retryCount++
if .retryCount > maxUselessRecords {
.sendAlert(alertUnexpectedMessage)
return .in.setErrorLocked(errors.New("tls: too many ignored records"))
}
return .readRecordOrCCS()
}
type atLeastReader struct {
R io.Reader
N int64
}
func ( *atLeastReader) ( []byte) (int, error) {
if .N <= 0 {
return 0, io.EOF
}
, := .R.Read()
.N -= int64()
if .N > 0 && == io.EOF {
return , io.ErrUnexpectedEOF
}
if .N <= 0 && == nil {
return , io.EOF
}
return ,
}
func ( *Conn) ( io.Reader, int) error {
if .rawInput.Len() >= {
return nil
}
:= - .rawInput.Len()
.rawInput.Grow( + bytes.MinRead)
, := .rawInput.ReadFrom(&atLeastReader{, int64()})
return
}
func ( *Conn) ( alert) error {
switch {
case alertNoRenegotiation, alertCloseNotify:
.tmp[0] = alertLevelWarning
default:
.tmp[0] = alertLevelError
}
.tmp[1] = byte()
, := .writeRecordLocked(recordTypeAlert, .tmp[0:2])
if == alertCloseNotify {
return
}
return .out.setErrorLocked(&net.OpError{Op: "local error", Err: })
}
func ( *Conn) ( alert) error {
.out.Lock()
defer .out.Unlock()
return .sendAlertLocked()
}
const (
tcpMSSEstimate = 1208
recordSizeBoostThreshold = 128 * 1024
)
func ( *Conn) ( recordType) int {
if .config.DynamicRecordSizingDisabled || != recordTypeApplicationData {
return maxPlaintext
}
if .bytesSent >= recordSizeBoostThreshold {
return maxPlaintext
}
:= tcpMSSEstimate - recordHeaderLen - .out.explicitNonceLen()
if .out.cipher != nil {
switch ciph := .out.cipher.(type) {
case cipher.Stream:
-= .out.mac.Size()
case cipher.AEAD:
-= .Overhead()
case cbcMode:
:= .BlockSize()
= ( & ^( - 1)) - 1
-= .out.mac.Size()
default:
panic("unknown cipher type")
}
}
if .vers == VersionTLS13 {
--
}
:= .packetsSent
.packetsSent++
if > 1000 {
return maxPlaintext
}
:= * int(+1)
if > maxPlaintext {
= maxPlaintext
}
return
}
func ( *Conn) ( []byte) (int, error) {
if .buffering {
.sendBuf = append(.sendBuf, ...)
return len(), nil
}
, := .conn.Write()
.bytesSent += int64()
return ,
}
func ( *Conn) () (int, error) {
if len(.sendBuf) == 0 {
return 0, nil
}
, := .conn.Write(.sendBuf)
.bytesSent += int64()
.sendBuf = nil
.buffering = false
return ,
}
var outBufPool = sync.Pool{
New: func() interface{} {
return new([]byte)
},
}
func ( *Conn) ( recordType, []byte) (int, error) {
:= outBufPool.Get().(*[]byte)
:= *
defer func() {
* =
outBufPool.Put()
}()
var int
for len() > 0 {
:= len()
if := .maxPayloadSizeForWrite(); > {
=
}
_, = sliceForAppend([:0], recordHeaderLen)
[0] = byte()
:= .vers
if == 0 {
= VersionTLS10
} else if == VersionTLS13 {
= VersionTLS12
}
[1] = byte( >> 8)
[2] = byte()
[3] = byte( >> 8)
[4] = byte()
var error
, = .out.encrypt(, [:], .config.rand())
if != nil {
return ,
}
if , := .write(); != nil {
return ,
}
+=
= [:]
}
if == recordTypeChangeCipherSpec && .vers != VersionTLS13 {
if := .out.changeCipherSpec(); != nil {
return , .sendAlertLocked(.(alert))
}
}
return , nil
}
func ( *Conn) ( recordType, []byte) (int, error) {
.out.Lock()
defer .out.Unlock()
return .writeRecordLocked(, )
}
func ( *Conn) () (interface{}, error) {
for .hand.Len() < 4 {
if := .readRecord(); != nil {
return nil,
}
}
:= .hand.Bytes()
:= int([1])<<16 | int([2])<<8 | int([3])
if > maxHandshake {
.sendAlertLocked(alertInternalError)
return nil, .in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", , maxHandshake))
}
for .hand.Len() < 4+ {
if := .readRecord(); != nil {
return nil,
}
}
= .hand.Next(4 + )
var handshakeMessage
switch [0] {
case typeHelloRequest:
= new(helloRequestMsg)
case typeClientHello:
= new(clientHelloMsg)
case typeServerHello:
= new(serverHelloMsg)
case typeNewSessionTicket:
if .vers == VersionTLS13 {
= new(newSessionTicketMsgTLS13)
} else {
= new(newSessionTicketMsg)
}
case typeCertificate:
if .vers == VersionTLS13 {
= new(certificateMsgTLS13)
} else {
= new(certificateMsg)
}
case typeCertificateRequest:
if .vers == VersionTLS13 {
= new(certificateRequestMsgTLS13)
} else {
= &certificateRequestMsg{
hasSignatureAlgorithm: .vers >= VersionTLS12,
}
}
case typeCertificateStatus:
= new(certificateStatusMsg)
case typeServerKeyExchange:
= new(serverKeyExchangeMsg)
case typeServerHelloDone:
= new(serverHelloDoneMsg)
case typeClientKeyExchange:
= new(clientKeyExchangeMsg)
case typeCertificateVerify:
= &certificateVerifyMsg{
hasSignatureAlgorithm: .vers >= VersionTLS12,
}
case typeFinished:
= new(finishedMsg)
case typeEncryptedExtensions:
= new(encryptedExtensionsMsg)
case typeEndOfEarlyData:
= new(endOfEarlyDataMsg)
case typeKeyUpdate:
= new(keyUpdateMsg)
default:
return nil, .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
= append([]byte(nil), ...)
if !.unmarshal() {
return nil, .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
}
return , nil
}
var (
errShutdown = errors.New("tls: protocol is shutdown")
)
func ( *Conn) ( []byte) (int, error) {
for {
:= atomic.LoadInt32(&.activeCall)
if &1 != 0 {
return 0, net.ErrClosed
}
if atomic.CompareAndSwapInt32(&.activeCall, , +2) {
break
}
}
defer atomic.AddInt32(&.activeCall, -2)
if := .Handshake(); != nil {
return 0,
}
.out.Lock()
defer .out.Unlock()
if := .out.err; != nil {
return 0,
}
if !.handshakeComplete() {
return 0, alertInternalError
}
if .closeNotifySent {
return 0, errShutdown
}
var int
if len() > 1 && .vers == VersionTLS10 {
if , := .out.cipher.(cipher.BlockMode); {
, := .writeRecordLocked(recordTypeApplicationData, [:1])
if != nil {
return , .out.setErrorLocked()
}
, = 1, [1:]
}
}
, := .writeRecordLocked(recordTypeApplicationData, )
return + , .out.setErrorLocked()
}
func ( *Conn) () error {
if .vers == VersionTLS13 {
return errors.New("tls: internal error: unexpected renegotiation")
}
, := .readHandshake()
if != nil {
return
}
, := .(*helloRequestMsg)
if ! {
.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(, )
}
if !.isClient {
return .sendAlert(alertNoRenegotiation)
}
switch .config.Renegotiation {
case RenegotiateNever:
return .sendAlert(alertNoRenegotiation)
case RenegotiateOnceAsClient:
if .handshakes > 1 {
return .sendAlert(alertNoRenegotiation)
}
case RenegotiateFreelyAsClient:
default:
.sendAlert(alertInternalError)
return errors.New("tls: unknown Renegotiation value")
}
.handshakeMutex.Lock()
defer .handshakeMutex.Unlock()
atomic.StoreUint32(&.handshakeStatus, 0)
if .handshakeErr = .clientHandshake(); .handshakeErr == nil {
.handshakes++
}
return .handshakeErr
}
func ( *Conn) () error {
if .vers != VersionTLS13 {
return .handleRenegotiation()
}
, := .readHandshake()
if != nil {
return
}
.retryCount++
if .retryCount > maxUselessRecords {
.sendAlert(alertUnexpectedMessage)
return .in.setErrorLocked(errors.New("tls: too many non-advancing records"))
}
switch msg := .(type) {
case *newSessionTicketMsgTLS13:
return .handleNewSessionTicket()
case *keyUpdateMsg:
return .handleKeyUpdate()
default:
.sendAlert(alertUnexpectedMessage)
return fmt.Errorf("tls: received unexpected handshake message of type %T", )
}
}
func ( *Conn) ( *keyUpdateMsg) error {
:= cipherSuiteTLS13ByID(.cipherSuite)
if == nil {
return .in.setErrorLocked(.sendAlert(alertInternalError))
}
:= .nextTrafficSecret(.in.trafficSecret)
.in.setTrafficSecret(, )
if .updateRequested {
.out.Lock()
defer .out.Unlock()
:= &keyUpdateMsg{}
, := .writeRecordLocked(recordTypeHandshake, .marshal())
if != nil {
.out.setErrorLocked()
return nil
}
:= .nextTrafficSecret(.out.trafficSecret)
.out.setTrafficSecret(, )
}
return nil
}
func ( *Conn) ( []byte) (int, error) {
if := .Handshake(); != nil {
return 0,
}
if len() == 0 {
return 0, nil
}
.in.Lock()
defer .in.Unlock()
for .input.Len() == 0 {
if := .readRecord(); != nil {
return 0,
}
for .hand.Len() > 0 {
if := .handlePostHandshakeMessage(); != nil {
return 0,
}
}
}
, := .input.Read()
if != 0 && .input.Len() == 0 && .rawInput.Len() > 0 &&
recordType(.rawInput.Bytes()[0]) == recordTypeAlert {
if := .readRecord(); != nil {
return ,
}
}
return , nil
}
func ( *Conn) () error {
var int32
for {
= atomic.LoadInt32(&.activeCall)
if &1 != 0 {
return net.ErrClosed
}
if atomic.CompareAndSwapInt32(&.activeCall, , |1) {
break
}
}
if != 0 {
return .conn.Close()
}
var error
if .handshakeComplete() {
if := .closeNotify(); != nil {
= fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", )
}
}
if := .conn.Close(); != nil {
return
}
return
}
var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete")
func ( *Conn) () error {
if !.handshakeComplete() {
return errEarlyCloseWrite
}
return .closeNotify()
}
func ( *Conn) () error {
.out.Lock()
defer .out.Unlock()
if !.closeNotifySent {
.SetWriteDeadline(time.Now().Add(time.Second * 5))
.closeNotifyErr = .sendAlertLocked(alertCloseNotify)
.closeNotifySent = true
.SetWriteDeadline(time.Now())
}
return .closeNotifyErr
}
func ( *Conn) () error {
.handshakeMutex.Lock()
defer .handshakeMutex.Unlock()
if := .handshakeErr; != nil {
return
}
if .handshakeComplete() {
return nil
}
.in.Lock()
defer .in.Unlock()
.handshakeErr = .handshakeFn()
if .handshakeErr == nil {
.handshakes++
} else {
.flush()
}
if .handshakeErr == nil && !.handshakeComplete() {
.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
}
return .handshakeErr
}
func ( *Conn) () ConnectionState {
.handshakeMutex.Lock()
defer .handshakeMutex.Unlock()
return .connectionStateLocked()
}
func ( *Conn) () ConnectionState {
var ConnectionState
.HandshakeComplete = .handshakeComplete()
.Version = .vers
.NegotiatedProtocol = .clientProtocol
.DidResume = .didResume
.NegotiatedProtocolIsMutual = true
.ServerName = .serverName
.CipherSuite = .cipherSuite
.PeerCertificates = .peerCertificates
.VerifiedChains = .verifiedChains
.SignedCertificateTimestamps = .scts
.OCSPResponse = .ocspResponse
if !.didResume && .vers != VersionTLS13 {
if .clientFinishedIsFirst {
.TLSUnique = .clientFinished[:]
} else {
.TLSUnique = .serverFinished[:]
}
}
if .config.Renegotiation != RenegotiateNever {
.ekm = noExportedKeyingMaterial
} else {
.ekm = .ekm
}
return
}
func ( *Conn) () []byte {
.handshakeMutex.Lock()
defer .handshakeMutex.Unlock()
return .ocspResponse
}
func ( *Conn) ( string) error {
.handshakeMutex.Lock()
defer .handshakeMutex.Unlock()
if !.isClient {
return errors.New("tls: VerifyHostname called on TLS server connection")
}
if !.handshakeComplete() {
return errors.New("tls: handshake has not yet been performed")
}
if len(.verifiedChains) == 0 {
return errors.New("tls: handshake did not verify certificate chain")
}
return .peerCertificates[0].VerifyHostname()
}
func ( *Conn) () bool {
return atomic.LoadUint32(&.handshakeStatus) == 1
}