package tls
import (
)
type clientHandshakeStateTLS13 struct {
c *Conn
ctx context.Context
serverHello *serverHelloMsg
hello *clientHelloMsg
keyShareKeys *keySharePrivateKeys
session *SessionState
earlySecret *tls13.EarlySecret
binderKey []byte
certReq *certificateRequestMsgTLS13
usingPSK bool
sentDummyCCS bool
suite *cipherSuiteTLS13
transcript hash.Hash
masterSecret *tls13.MasterSecret
trafficSecret []byte
echContext *echClientContext
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
if .handshakes > 0 {
.sendAlert(alertProtocolVersion)
return errors.New("tls: server selected TLS 1.3 in a renegotiation")
}
if .keyShareKeys == nil || .keyShareKeys.ecdhe == nil || len(.hello.keyShares) == 0 {
return .sendAlert(alertInternalError)
}
if := .checkServerHelloOrHRR(); != nil {
return
}
.transcript = .suite.hash.New()
if := transcriptMsg(.hello, .transcript); != nil {
return
}
if .echContext != nil {
.echContext.innerTranscript = .suite.hash.New()
if := transcriptMsg(.echContext.innerHello, .echContext.innerTranscript); != nil {
return
}
}
if bytes.Equal(.serverHello.random, helloRetryRequestRandom) {
if := .sendDummyChangeCipherSpec(); != nil {
return
}
if := .processHelloRetryRequest(); != nil {
return
}
}
if .echContext != nil {
:= cloneHash(.echContext.innerTranscript, .suite.hash)
.Write(.serverHello.original[:30])
.Write(make([]byte, 8))
.Write(.serverHello.original[38:])
:= tls13.ExpandLabel(.suite.hash.New,
hkdf.Extract(.suite.hash.New, .echContext.innerHello.random, nil),
"ech accept confirmation",
.Sum(nil),
8,
)
if subtle.ConstantTimeCompare(, .serverHello.random[len(.serverHello.random)-8:]) == 1 {
.hello = .echContext.innerHello
.serverName = .config.ServerName
.transcript = .echContext.innerTranscript
.echAccepted = true
if .serverHello.encryptedClientHello != nil {
.sendAlert(alertUnsupportedExtension)
return errors.New("tls: unexpected encrypted client hello extension in server hello despite ECH being accepted")
}
if .hello.serverName == "" && .serverHello.serverNameAck {
.sendAlert(alertUnsupportedExtension)
return errors.New("tls: unexpected server_name extension in server hello")
}
} else {
.echContext.echRejected = true
}
}
if := transcriptMsg(.serverHello, .transcript); != nil {
return
}
.buffering = true
if := .processServerHello(); != nil {
return
}
if := .sendDummyChangeCipherSpec(); != nil {
return
}
if := .establishHandshakeKeys(); != nil {
return
}
if := .readServerParameters(); != nil {
return
}
if := .readServerCertificate(); != nil {
return
}
if := .readServerFinished(); != nil {
return
}
if := .sendClientCertificate(); != nil {
return
}
if := .sendClientFinished(); != nil {
return
}
if , := .flush(); != nil {
return
}
if .echContext != nil && .echContext.echRejected {
.sendAlert(alertECHRequired)
return &ECHRejectionError{.echContext.retryConfigs}
}
.isHandshakeComplete.Store(true)
return nil
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
if .serverHello.supportedVersion == 0 {
.sendAlert(alertMissingExtension)
return errors.New("tls: server selected TLS 1.3 using the legacy version field")
}
if .serverHello.supportedVersion != VersionTLS13 {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected an invalid version after a HelloRetryRequest")
}
if .serverHello.vers != VersionTLS12 {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server sent an incorrect legacy version")
}
if .serverHello.ocspStapling ||
.serverHello.ticketSupported ||
.serverHello.extendedMasterSecret ||
.serverHello.secureRenegotiationSupported ||
len(.serverHello.secureRenegotiation) != 0 ||
len(.serverHello.alpnProtocol) != 0 ||
len(.serverHello.scts) != 0 {
.sendAlert(alertUnsupportedExtension)
return errors.New("tls: server sent a ServerHello extension forbidden in TLS 1.3")
}
if !bytes.Equal(.hello.sessionId, .serverHello.sessionId) {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server did not echo the legacy session ID")
}
if .serverHello.compressionMethod != compressionNone {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected unsupported compression format")
}
:= mutualCipherSuiteTLS13(.hello.cipherSuites, .serverHello.cipherSuite)
if .suite != nil && != .suite {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server changed cipher suite after a HelloRetryRequest")
}
if == nil {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server chose an unconfigured cipher suite")
}
.suite =
.cipherSuite = .suite.id
return nil
}
func ( *clientHandshakeStateTLS13) () error {
if .c.quic != nil {
return nil
}
if .sentDummyCCS {
return nil
}
.sentDummyCCS = true
return .c.writeChangeCipherRecord()
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
:= .transcript.Sum(nil)
.transcript.Reset()
.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len())})
.transcript.Write()
if := transcriptMsg(.serverHello, .transcript); != nil {
return
}
var bool
:= .hello
if .echContext != nil {
= .echContext.innerTranscript.Sum(nil)
.echContext.innerTranscript.Reset()
.echContext.innerTranscript.Write([]byte{typeMessageHash, 0, 0, uint8(len())})
.echContext.innerTranscript.Write()
if .serverHello.encryptedClientHello != nil {
if len(.serverHello.encryptedClientHello) != 8 {
.c.sendAlert(alertDecodeError)
return errors.New("tls: malformed encrypted client hello extension")
}
:= cloneHash(.echContext.innerTranscript, .suite.hash)
:= make([]byte, len(.serverHello.original))
copy(, .serverHello.original)
= bytes.Replace(, .serverHello.encryptedClientHello, make([]byte, 8), 1)
.Write()
:= tls13.ExpandLabel(.suite.hash.New,
hkdf.Extract(.suite.hash.New, .echContext.innerHello.random, nil),
"hrr ech accept confirmation",
.Sum(nil),
8,
)
if subtle.ConstantTimeCompare(, .serverHello.encryptedClientHello) == 1 {
= .echContext.innerHello
.serverName = .config.ServerName
= true
.echAccepted = true
}
}
if := transcriptMsg(.serverHello, .echContext.innerTranscript); != nil {
return
}
} else if .serverHello.encryptedClientHello != nil {
.sendAlert(alertUnsupportedExtension)
return errors.New("tls: unexpected encrypted client hello extension in serverHello")
}
if .serverHello.selectedGroup == 0 && .serverHello.cookie == nil {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
}
if .serverHello.cookie != nil {
.cookie = .serverHello.cookie
}
if .serverHello.serverShare.group != 0 {
.sendAlert(alertDecodeError)
return errors.New("tls: received malformed key_share extension")
}
if := .serverHello.selectedGroup; != 0 {
if !slices.Contains(.supportedCurves, ) {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected unsupported group")
}
if slices.ContainsFunc(.hello.keyShares, func( keyShare) bool {
return .group ==
}) {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
}
if , := curveForCurveID(); ! {
.sendAlert(alertInternalError)
return errors.New("tls: CurvePreferences includes unsupported curve")
}
, := generateECDHEKey(.config.rand(), )
if != nil {
.sendAlert(alertInternalError)
return
}
.keyShareKeys = &keySharePrivateKeys{curveID: , ecdhe: }
.keyShares = []keyShare{{group: , data: .PublicKey().Bytes()}}
}
if len(.pskIdentities) > 0 {
:= cipherSuiteTLS13ByID(.session.cipherSuite)
if == nil {
return .sendAlert(alertInternalError)
}
if .hash == .suite.hash {
:= .config.time().Sub(time.Unix(int64(.session.createdAt), 0))
.pskIdentities[0].obfuscatedTicketAge = uint32(/time.Millisecond) + .session.ageAdd
:= .suite.hash.New()
.Write([]byte{typeMessageHash, 0, 0, uint8(len())})
.Write()
if := transcriptMsg(.serverHello, ); != nil {
return
}
if := computeAndUpdatePSK(, .binderKey, , .suite.finishedHash); != nil {
return
}
} else {
.pskIdentities = nil
.pskBinders = nil
}
}
if .earlyData {
.earlyData = false
.quicRejectedEarlyData()
}
if {
.hello.keyShares = .keyShares
.echContext.innerHello =
if := transcriptMsg(.echContext.innerHello, .echContext.innerTranscript); != nil {
return
}
if := computeAndUpdateOuterECHExtension(.hello, .echContext.innerHello, .echContext, false); != nil {
return
}
} else {
.hello =
}
if , := .c.writeHandshakeRecord(.hello, .transcript); != nil {
return
}
, := .readHandshake(nil)
if != nil {
return
}
, := .(*serverHelloMsg)
if ! {
.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(, )
}
.serverHello =
if := .checkServerHelloOrHRR(); != nil {
return
}
.didHRR = true
return nil
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
if bytes.Equal(.serverHello.random, helloRetryRequestRandom) {
.sendAlert(alertUnexpectedMessage)
return errors.New("tls: server sent two HelloRetryRequest messages")
}
if len(.serverHello.cookie) != 0 {
.sendAlert(alertUnsupportedExtension)
return errors.New("tls: server sent a cookie in a normal ServerHello")
}
if .serverHello.selectedGroup != 0 {
.sendAlert(alertDecodeError)
return errors.New("tls: malformed key_share extension")
}
if .serverHello.serverShare.group == 0 {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server did not send a key share")
}
if !slices.ContainsFunc(.hello.keyShares, func( keyShare) bool {
return .group == .serverHello.serverShare.group
}) {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected unsupported group")
}
if !.serverHello.selectedIdentityPresent {
return nil
}
if int(.serverHello.selectedIdentity) >= len(.hello.pskIdentities) {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected an invalid PSK")
}
if len(.hello.pskIdentities) != 1 || .session == nil {
return .sendAlert(alertInternalError)
}
:= cipherSuiteTLS13ByID(.session.cipherSuite)
if == nil {
return .sendAlert(alertInternalError)
}
if .hash != .suite.hash {
.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected an invalid PSK and cipher suite pair")
}
.usingPSK = true
.didResume = true
.peerCertificates = .session.peerCertificates
.activeCertHandles = .session.activeCertHandles
.verifiedChains = .session.verifiedChains
.ocspResponse = .session.ocspResponse
.scts = .session.scts
return nil
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
:= .serverHello.serverShare.data
if .serverHello.serverShare.group == X25519MLKEM768 {
if len() != mlkem.CiphertextSize768+x25519PublicKeySize {
.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid server X25519MLKEM768 key share")
}
= .serverHello.serverShare.data[mlkem.CiphertextSize768:]
}
, := .keyShareKeys.ecdhe.Curve().NewPublicKey()
if != nil {
.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid server key share")
}
, := .keyShareKeys.ecdhe.ECDH()
if != nil {
.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid server key share")
}
if .serverHello.serverShare.group == X25519MLKEM768 {
if .keyShareKeys.mlkem == nil {
return .sendAlert(alertInternalError)
}
:= .serverHello.serverShare.data[:mlkem.CiphertextSize768]
, := .keyShareKeys.mlkem.Decapsulate()
if != nil {
.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid X25519MLKEM768 server key share")
}
= append(, ...)
}
.curveID = .serverHello.serverShare.group
:= .earlySecret
if !.usingPSK {
= tls13.NewEarlySecret(.suite.hash.New, nil)
}
:= .HandshakeSecret()
:= .ClientHandshakeTrafficSecret(.transcript)
.out.setTrafficSecret(.suite, QUICEncryptionLevelHandshake, )
:= .ServerHandshakeTrafficSecret(.transcript)
.in.setTrafficSecret(.suite, QUICEncryptionLevelHandshake, )
if .quic != nil {
if .hand.Len() != 0 {
.sendAlert(alertUnexpectedMessage)
}
.quicSetWriteSecret(QUICEncryptionLevelHandshake, .suite.id, )
.quicSetReadSecret(QUICEncryptionLevelHandshake, .suite.id, )
}
= .config.writeKeyLog(keyLogLabelClientHandshake, .hello.random, )
if != nil {
.sendAlert(alertInternalError)
return
}
= .config.writeKeyLog(keyLogLabelServerHandshake, .hello.random, )
if != nil {
.sendAlert(alertInternalError)
return
}
.masterSecret = .MasterSecret()
return nil
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
, := .readHandshake(.transcript)
if != nil {
return
}
, := .(*encryptedExtensionsMsg)
if ! {
.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(, )
}
if := checkALPN(.hello.alpnProtocols, .alpnProtocol, .quic != nil); != nil {
.sendAlert(alertNoApplicationProtocol)
return
}
.clientProtocol = .alpnProtocol
if .quic != nil {
if .quicTransportParameters == nil {
.sendAlert(alertMissingExtension)
return errors.New("tls: server did not send a quic_transport_parameters extension")
}
.quicSetTransportParameters(.quicTransportParameters)
} else {
if .quicTransportParameters != nil {
.sendAlert(alertUnsupportedExtension)
return errors.New("tls: server sent an unexpected quic_transport_parameters extension")
}
}
if !.hello.earlyData && .earlyData {
.sendAlert(alertUnsupportedExtension)
return errors.New("tls: server sent an unexpected early_data extension")
}
if .hello.earlyData && !.earlyData {
.quicRejectedEarlyData()
}
if .earlyData {
if .session.cipherSuite != .cipherSuite {
.sendAlert(alertHandshakeFailure)
return errors.New("tls: server accepted 0-RTT with the wrong cipher suite")
}
if .session.alpnProtocol != .clientProtocol {
.sendAlert(alertHandshakeFailure)
return errors.New("tls: server accepted 0-RTT with the wrong ALPN")
}
}
if .echContext != nil {
if .echContext.echRejected {
.echContext.retryConfigs = .echRetryConfigs
} else if .echRetryConfigs != nil {
.sendAlert(alertUnsupportedExtension)
return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello")
}
}
return nil
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
if .usingPSK {
if .config.VerifyConnection != nil {
if := .config.VerifyConnection(.connectionStateLocked()); != nil {
.sendAlert(alertBadCertificate)
return
}
}
return nil
}
, := .readHandshake(.transcript)
if != nil {
return
}
, := .(*certificateRequestMsgTLS13)
if {
.certReq =
, = .readHandshake(.transcript)
if != nil {
return
}
}
, := .(*certificateMsgTLS13)
if ! {
.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(, )
}
if len(.certificate.Certificate) == 0 {
.sendAlert(alertDecodeError)
return errors.New("tls: received empty certificates message")
}
.scts = .certificate.SignedCertificateTimestamps
.ocspResponse = .certificate.OCSPStaple
if := .verifyServerCertificate(.certificate.Certificate); != nil {
return
}
, = .readHandshake(nil)
if != nil {
return
}
, := .(*certificateVerifyMsg)
if ! {
.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(, )
}
if !isSupportedSignatureAlgorithm(.signatureAlgorithm, supportedSignatureAlgorithms()) {
.sendAlert(alertIllegalParameter)
return errors.New("tls: certificate used with invalid signature algorithm")
}
, , := typeAndHashFromSignatureScheme(.signatureAlgorithm)
if != nil {
return .sendAlert(alertInternalError)
}
if == signaturePKCS1v15 || == crypto.SHA1 {
.sendAlert(alertIllegalParameter)
return errors.New("tls: certificate used with invalid signature algorithm")
}
:= signedMessage(, serverSignatureContext, .transcript)
if := verifyHandshakeSignature(, .peerCertificates[0].PublicKey,
, , .signature); != nil {
.sendAlert(alertDecryptError)
return errors.New("tls: invalid signature by the server certificate: " + .Error())
}
if := transcriptMsg(, .transcript); != nil {
return
}
return nil
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
, := .readHandshake(nil)
if != nil {
return
}
, := .(*finishedMsg)
if ! {
.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(, )
}
:= .suite.finishedHash(.in.trafficSecret, .transcript)
if !hmac.Equal(, .verifyData) {
.sendAlert(alertDecryptError)
return errors.New("tls: invalid server finished hash")
}
if := transcriptMsg(, .transcript); != nil {
return
}
.trafficSecret = .masterSecret.ClientApplicationTrafficSecret(.transcript)
:= .masterSecret.ServerApplicationTrafficSecret(.transcript)
.in.setTrafficSecret(.suite, QUICEncryptionLevelApplication, )
= .config.writeKeyLog(keyLogLabelClientTraffic, .hello.random, .trafficSecret)
if != nil {
.sendAlert(alertInternalError)
return
}
= .config.writeKeyLog(keyLogLabelServerTraffic, .hello.random, )
if != nil {
.sendAlert(alertInternalError)
return
}
.ekm = .suite.exportKeyingMaterial(.masterSecret, .transcript)
return nil
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
if .certReq == nil {
return nil
}
if .echContext != nil && .echContext.echRejected {
if , := .c.writeHandshakeRecord(&certificateMsgTLS13{}, .transcript); != nil {
return
}
return nil
}
, := .getClientCertificate(&CertificateRequestInfo{
AcceptableCAs: .certReq.certificateAuthorities,
SignatureSchemes: .certReq.supportedSignatureAlgorithms,
Version: .vers,
ctx: .ctx,
})
if != nil {
return
}
:= new(certificateMsgTLS13)
.certificate = *
.scts = .certReq.scts && len(.SignedCertificateTimestamps) > 0
.ocspStapling = .certReq.ocspStapling && len(.OCSPStaple) > 0
if , := .c.writeHandshakeRecord(, .transcript); != nil {
return
}
if len(.Certificate) == 0 {
return nil
}
:= new(certificateVerifyMsg)
.hasSignatureAlgorithm = true
.signatureAlgorithm, = selectSignatureScheme(.vers, , .certReq.supportedSignatureAlgorithms)
if != nil {
.sendAlert(alertHandshakeFailure)
return
}
, , := typeAndHashFromSignatureScheme(.signatureAlgorithm)
if != nil {
return .sendAlert(alertInternalError)
}
:= signedMessage(, clientSignatureContext, .transcript)
:= crypto.SignerOpts()
if == signatureRSAPSS {
= &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: }
}
, := .PrivateKey.(crypto.Signer).Sign(.config.rand(), , )
if != nil {
.sendAlert(alertInternalError)
return errors.New("tls: failed to sign handshake: " + .Error())
}
.signature =
if , := .c.writeHandshakeRecord(, .transcript); != nil {
return
}
return nil
}
func ( *clientHandshakeStateTLS13) () error {
:= .c
:= &finishedMsg{
verifyData: .suite.finishedHash(.out.trafficSecret, .transcript),
}
if , := .c.writeHandshakeRecord(, .transcript); != nil {
return
}
.out.setTrafficSecret(.suite, QUICEncryptionLevelApplication, .trafficSecret)
if !.config.SessionTicketsDisabled && .config.ClientSessionCache != nil {
.resumptionSecret = .masterSecret.ResumptionMasterSecret(.transcript)
}
if .quic != nil {
if .hand.Len() != 0 {
.sendAlert(alertUnexpectedMessage)
}
.quicSetWriteSecret(QUICEncryptionLevelApplication, .suite.id, .trafficSecret)
}
return nil
}
func ( *Conn) ( *newSessionTicketMsgTLS13) error {
if !.isClient {
.sendAlert(alertUnexpectedMessage)
return errors.New("tls: received new session ticket from a client")
}
if .config.SessionTicketsDisabled || .config.ClientSessionCache == nil {
return nil
}
if .lifetime == 0 {
return nil
}
:= time.Duration(.lifetime) * time.Second
if > maxSessionTicketLifetime {
.sendAlert(alertIllegalParameter)
return errors.New("tls: received a session ticket with invalid lifetime")
}
if .quic != nil && .maxEarlyData != 0 && .maxEarlyData != 0xffffffff {
.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid early data for QUIC connection")
}
:= cipherSuiteTLS13ByID(.cipherSuite)
if == nil || .resumptionSecret == nil {
return .sendAlert(alertInternalError)
}
:= tls13.ExpandLabel(.hash.New, .resumptionSecret, "resumption",
.nonce, .hash.Size())
:= .sessionState()
.secret =
.useBy = uint64(.config.time().Add().Unix())
.ageAdd = .ageAdd
.EarlyData = .quic != nil && .maxEarlyData == 0xffffffff
.ticket = .label
if .quic != nil && .quic.enableSessionEvents {
.quicStoreSession()
return nil
}
:= &ClientSessionState{session: }
if := .clientSessionCacheKey(); != "" {
.config.ClientSessionCache.Put(, )
}
return nil
}