package tls
import (
"bytes"
"context"
"crypto"
"crypto/hmac"
"crypto/internal/mlkem768"
"crypto/rsa"
"crypto/subtle"
"errors"
"hash"
"slices"
"time"
)
type clientHandshakeStateTLS13 struct {
c *Conn
ctx context .Context
serverHello *serverHelloMsg
hello *clientHelloMsg
keyShareKeys *keySharePrivateKeys
session *SessionState
earlySecret []byte
binderKey []byte
certReq *certificateRequestMsgTLS13
usingPSK bool
sentDummyCCS bool
suite *cipherSuiteTLS13
transcript hash .Hash
masterSecret []byte
trafficSecret []byte
echContext *echContext
}
func (hs *clientHandshakeStateTLS13 ) handshake () error {
c := hs .c
if needFIPS () {
return errors .New ("tls: internal error: TLS 1.3 reached in FIPS mode" )
}
if c .handshakes > 0 {
c .sendAlert (alertProtocolVersion )
return errors .New ("tls: server selected TLS 1.3 in a renegotiation" )
}
if hs .keyShareKeys == nil || hs .keyShareKeys .ecdhe == nil || len (hs .hello .keyShares ) == 0 {
return c .sendAlert (alertInternalError )
}
if err := hs .checkServerHelloOrHRR (); err != nil {
return err
}
hs .transcript = hs .suite .hash .New ()
if err := transcriptMsg (hs .hello , hs .transcript ); err != nil {
return err
}
if hs .echContext != nil {
hs .echContext .innerTranscript = hs .suite .hash .New ()
if err := transcriptMsg (hs .echContext .innerHello , hs .echContext .innerTranscript ); err != nil {
return err
}
}
if bytes .Equal (hs .serverHello .random , helloRetryRequestRandom ) {
if err := hs .sendDummyChangeCipherSpec (); err != nil {
return err
}
if err := hs .processHelloRetryRequest (); err != nil {
return err
}
}
var echRetryConfigList []byte
if hs .echContext != nil {
confTranscript := cloneHash (hs .echContext .innerTranscript , hs .suite .hash )
confTranscript .Write (hs .serverHello .original [:30 ])
confTranscript .Write (make ([]byte , 8 ))
confTranscript .Write (hs .serverHello .original [38 :])
acceptConfirmation := hs .suite .expandLabel (
hs .suite .extract (hs .echContext .innerHello .random , nil ),
"ech accept confirmation" ,
confTranscript .Sum (nil ),
8 ,
)
if subtle .ConstantTimeCompare (acceptConfirmation , hs .serverHello .random [len (hs .serverHello .random )-8 :]) == 1 {
hs .hello = hs .echContext .innerHello
c .serverName = c .config .ServerName
hs .transcript = hs .echContext .innerTranscript
c .echAccepted = true
if hs .serverHello .encryptedClientHello != nil {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: unexpected encrypted_client_hello extension in server hello despite ECH being accepted" )
}
if hs .hello .serverName == "" && hs .serverHello .serverNameAck {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: unexpected server_name extension in server hello" )
}
} else {
hs .echContext .echRejected = true
echRetryConfigList = hs .serverHello .encryptedClientHello
}
}
if err := transcriptMsg (hs .serverHello , hs .transcript ); err != nil {
return err
}
c .buffering = true
if err := hs .processServerHello (); err != nil {
return err
}
if err := hs .sendDummyChangeCipherSpec (); err != nil {
return err
}
if err := hs .establishHandshakeKeys (); err != nil {
return err
}
if err := hs .readServerParameters (); err != nil {
return err
}
if err := hs .readServerCertificate (); err != nil {
return err
}
if err := hs .readServerFinished (); err != nil {
return err
}
if err := hs .sendClientCertificate (); err != nil {
return err
}
if err := hs .sendClientFinished (); err != nil {
return err
}
if _ , err := c .flush (); err != nil {
return err
}
if hs .echContext != nil && hs .echContext .echRejected {
c .sendAlert (alertECHRequired )
return &ECHRejectionError {echRetryConfigList }
}
c .isHandshakeComplete .Store (true )
return nil
}
func (hs *clientHandshakeStateTLS13 ) checkServerHelloOrHRR () error {
c := hs .c
if hs .serverHello .supportedVersion == 0 {
c .sendAlert (alertMissingExtension )
return errors .New ("tls: server selected TLS 1.3 using the legacy version field" )
}
if hs .serverHello .supportedVersion != VersionTLS13 {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server selected an invalid version after a HelloRetryRequest" )
}
if hs .serverHello .vers != VersionTLS12 {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server sent an incorrect legacy version" )
}
if hs .serverHello .ocspStapling ||
hs .serverHello .ticketSupported ||
hs .serverHello .extendedMasterSecret ||
hs .serverHello .secureRenegotiationSupported ||
len (hs .serverHello .secureRenegotiation ) != 0 ||
len (hs .serverHello .alpnProtocol ) != 0 ||
len (hs .serverHello .scts ) != 0 {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: server sent a ServerHello extension forbidden in TLS 1.3" )
}
if !bytes .Equal (hs .hello .sessionId , hs .serverHello .sessionId ) {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server did not echo the legacy session ID" )
}
if hs .serverHello .compressionMethod != compressionNone {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server selected unsupported compression format" )
}
selectedSuite := mutualCipherSuiteTLS13 (hs .hello .cipherSuites , hs .serverHello .cipherSuite )
if hs .suite != nil && selectedSuite != hs .suite {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server changed cipher suite after a HelloRetryRequest" )
}
if selectedSuite == nil {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server chose an unconfigured cipher suite" )
}
hs .suite = selectedSuite
c .cipherSuite = hs .suite .id
return nil
}
func (hs *clientHandshakeStateTLS13 ) sendDummyChangeCipherSpec () error {
if hs .c .quic != nil {
return nil
}
if hs .sentDummyCCS {
return nil
}
hs .sentDummyCCS = true
return hs .c .writeChangeCipherRecord ()
}
func (hs *clientHandshakeStateTLS13 ) processHelloRetryRequest () error {
c := hs .c
chHash := hs .transcript .Sum (nil )
hs .transcript .Reset ()
hs .transcript .Write ([]byte {typeMessageHash , 0 , 0 , uint8 (len (chHash ))})
hs .transcript .Write (chHash )
if err := transcriptMsg (hs .serverHello , hs .transcript ); err != nil {
return err
}
var isInnerHello bool
hello := hs .hello
if hs .echContext != nil {
chHash = hs .echContext .innerTranscript .Sum (nil )
hs .echContext .innerTranscript .Reset ()
hs .echContext .innerTranscript .Write ([]byte {typeMessageHash , 0 , 0 , uint8 (len (chHash ))})
hs .echContext .innerTranscript .Write (chHash )
if hs .serverHello .encryptedClientHello != nil {
if len (hs .serverHello .encryptedClientHello ) != 8 {
hs .c .sendAlert (alertDecodeError )
return errors .New ("tls: malformed encrypted client hello extension" )
}
confTranscript := cloneHash (hs .echContext .innerTranscript , hs .suite .hash )
hrrHello := make ([]byte , len (hs .serverHello .original ))
copy (hrrHello , hs .serverHello .original )
hrrHello = bytes .Replace (hrrHello , hs .serverHello .encryptedClientHello , make ([]byte , 8 ), 1 )
confTranscript .Write (hrrHello )
acceptConfirmation := hs .suite .expandLabel (
hs .suite .extract (hs .echContext .innerHello .random , nil ),
"hrr ech accept confirmation" ,
confTranscript .Sum (nil ),
8 ,
)
if subtle .ConstantTimeCompare (acceptConfirmation , hs .serverHello .encryptedClientHello ) == 1 {
hello = hs .echContext .innerHello
c .serverName = c .config .ServerName
isInnerHello = true
c .echAccepted = true
}
}
if err := transcriptMsg (hs .serverHello , hs .echContext .innerTranscript ); err != nil {
return err
}
} else if hs .serverHello .encryptedClientHello != nil {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: unexpected ECH extension in serverHello" )
}
if hs .serverHello .selectedGroup == 0 && hs .serverHello .cookie == nil {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server sent an unnecessary HelloRetryRequest message" )
}
if hs .serverHello .cookie != nil {
hello .cookie = hs .serverHello .cookie
}
if hs .serverHello .serverShare .group != 0 {
c .sendAlert (alertDecodeError )
return errors .New ("tls: received malformed key_share extension" )
}
if curveID := hs .serverHello .selectedGroup ; curveID != 0 {
if !slices .Contains (hello .supportedCurves , curveID ) {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server selected unsupported group" )
}
if slices .ContainsFunc (hs .hello .keyShares , func (ks keyShare ) bool {
return ks .group == curveID
}) {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server sent an unnecessary HelloRetryRequest key_share" )
}
if _ , ok := curveForCurveID (curveID ); !ok {
c .sendAlert (alertInternalError )
return errors .New ("tls: CurvePreferences includes unsupported curve" )
}
key , err := generateECDHEKey (c .config .rand (), curveID )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
hs .keyShareKeys = &keySharePrivateKeys {curveID : curveID , ecdhe : key }
hello .keyShares = []keyShare {{group : curveID , data : key .PublicKey ().Bytes ()}}
}
if len (hello .pskIdentities ) > 0 {
pskSuite := cipherSuiteTLS13ByID (hs .session .cipherSuite )
if pskSuite == nil {
return c .sendAlert (alertInternalError )
}
if pskSuite .hash == hs .suite .hash {
ticketAge := c .config .time ().Sub (time .Unix (int64 (hs .session .createdAt ), 0 ))
hello .pskIdentities [0 ].obfuscatedTicketAge = uint32 (ticketAge /time .Millisecond ) + hs .session .ageAdd
transcript := hs .suite .hash .New ()
transcript .Write ([]byte {typeMessageHash , 0 , 0 , uint8 (len (chHash ))})
transcript .Write (chHash )
if err := transcriptMsg (hs .serverHello , transcript ); err != nil {
return err
}
if err := computeAndUpdatePSK (hello , hs .binderKey , transcript , hs .suite .finishedHash ); err != nil {
return err
}
} else {
hello .pskIdentities = nil
hello .pskBinders = nil
}
}
if hello .earlyData {
hello .earlyData = false
c .quicRejectedEarlyData ()
}
if isInnerHello {
hs .hello .keyShares = hello .keyShares
hs .echContext .innerHello = hello
if err := transcriptMsg (hs .echContext .innerHello , hs .echContext .innerTranscript ); err != nil {
return err
}
if err := computeAndUpdateOuterECHExtension (hs .hello , hs .echContext .innerHello , hs .echContext , false ); err != nil {
return err
}
} else {
hs .hello = hello
}
if _ , err := hs .c .writeHandshakeRecord (hs .hello , hs .transcript ); err != nil {
return err
}
msg , err := c .readHandshake (nil )
if err != nil {
return err
}
serverHello , ok := msg .(*serverHelloMsg )
if !ok {
c .sendAlert (alertUnexpectedMessage )
return unexpectedMessageError (serverHello , msg )
}
hs .serverHello = serverHello
if err := hs .checkServerHelloOrHRR (); err != nil {
return err
}
c .didHRR = true
return nil
}
func (hs *clientHandshakeStateTLS13 ) processServerHello () error {
c := hs .c
if bytes .Equal (hs .serverHello .random , helloRetryRequestRandom ) {
c .sendAlert (alertUnexpectedMessage )
return errors .New ("tls: server sent two HelloRetryRequest messages" )
}
if len (hs .serverHello .cookie ) != 0 {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: server sent a cookie in a normal ServerHello" )
}
if hs .serverHello .selectedGroup != 0 {
c .sendAlert (alertDecodeError )
return errors .New ("tls: malformed key_share extension" )
}
if hs .serverHello .serverShare .group == 0 {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server did not send a key share" )
}
if !slices .ContainsFunc (hs .hello .keyShares , func (ks keyShare ) bool {
return ks .group == hs .serverHello .serverShare .group
}) {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server selected unsupported group" )
}
if !hs .serverHello .selectedIdentityPresent {
return nil
}
if int (hs .serverHello .selectedIdentity ) >= len (hs .hello .pskIdentities ) {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server selected an invalid PSK" )
}
if len (hs .hello .pskIdentities ) != 1 || hs .session == nil {
return c .sendAlert (alertInternalError )
}
pskSuite := cipherSuiteTLS13ByID (hs .session .cipherSuite )
if pskSuite == nil {
return c .sendAlert (alertInternalError )
}
if pskSuite .hash != hs .suite .hash {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: server selected an invalid PSK and cipher suite pair" )
}
hs .usingPSK = true
c .didResume = true
c .peerCertificates = hs .session .peerCertificates
c .activeCertHandles = hs .session .activeCertHandles
c .verifiedChains = hs .session .verifiedChains
c .ocspResponse = hs .session .ocspResponse
c .scts = hs .session .scts
return nil
}
func (hs *clientHandshakeStateTLS13 ) establishHandshakeKeys () error {
c := hs .c
ecdhePeerData := hs .serverHello .serverShare .data
if hs .serverHello .serverShare .group == x25519Kyber768Draft00 {
if len (ecdhePeerData ) != x25519PublicKeySize +mlkem768 .CiphertextSize {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid server key share" )
}
ecdhePeerData = hs .serverHello .serverShare .data [:x25519PublicKeySize ]
}
peerKey , err := hs .keyShareKeys .ecdhe .Curve ().NewPublicKey (ecdhePeerData )
if err != nil {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid server key share" )
}
sharedKey , err := hs .keyShareKeys .ecdhe .ECDH (peerKey )
if err != nil {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid server key share" )
}
if hs .serverHello .serverShare .group == x25519Kyber768Draft00 {
if hs .keyShareKeys .kyber == nil {
return c .sendAlert (alertInternalError )
}
ciphertext := hs .serverHello .serverShare .data [x25519PublicKeySize :]
kyberShared , err := kyberDecapsulate (hs .keyShareKeys .kyber , ciphertext )
if err != nil {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid Kyber server key share" )
}
sharedKey = append (sharedKey , kyberShared ...)
}
c .curveID = hs .serverHello .serverShare .group
earlySecret := hs .earlySecret
if !hs .usingPSK {
earlySecret = hs .suite .extract (nil , nil )
}
handshakeSecret := hs .suite .extract (sharedKey ,
hs .suite .deriveSecret (earlySecret , "derived" , nil ))
clientSecret := hs .suite .deriveSecret (handshakeSecret ,
clientHandshakeTrafficLabel , hs .transcript )
c .out .setTrafficSecret (hs .suite , QUICEncryptionLevelHandshake , clientSecret )
serverSecret := hs .suite .deriveSecret (handshakeSecret ,
serverHandshakeTrafficLabel , hs .transcript )
c .in .setTrafficSecret (hs .suite , QUICEncryptionLevelHandshake , serverSecret )
if c .quic != nil {
if c .hand .Len () != 0 {
c .sendAlert (alertUnexpectedMessage )
}
c .quicSetWriteSecret (QUICEncryptionLevelHandshake , hs .suite .id , clientSecret )
c .quicSetReadSecret (QUICEncryptionLevelHandshake , hs .suite .id , serverSecret )
}
err = c .config .writeKeyLog (keyLogLabelClientHandshake , hs .hello .random , clientSecret )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
err = c .config .writeKeyLog (keyLogLabelServerHandshake , hs .hello .random , serverSecret )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
hs .masterSecret = hs .suite .extract (nil ,
hs .suite .deriveSecret (handshakeSecret , "derived" , nil ))
return nil
}
func (hs *clientHandshakeStateTLS13 ) readServerParameters () error {
c := hs .c
msg , err := c .readHandshake (hs .transcript )
if err != nil {
return err
}
encryptedExtensions , ok := msg .(*encryptedExtensionsMsg )
if !ok {
c .sendAlert (alertUnexpectedMessage )
return unexpectedMessageError (encryptedExtensions , msg )
}
if err := checkALPN (hs .hello .alpnProtocols , encryptedExtensions .alpnProtocol , c .quic != nil ); err != nil {
c .sendAlert (alertNoApplicationProtocol )
return err
}
c .clientProtocol = encryptedExtensions .alpnProtocol
if c .quic != nil {
if encryptedExtensions .quicTransportParameters == nil {
c .sendAlert (alertMissingExtension )
return errors .New ("tls: server did not send a quic_transport_parameters extension" )
}
c .quicSetTransportParameters (encryptedExtensions .quicTransportParameters )
} else {
if encryptedExtensions .quicTransportParameters != nil {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: server sent an unexpected quic_transport_parameters extension" )
}
}
if !hs .hello .earlyData && encryptedExtensions .earlyData {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: server sent an unexpected early_data extension" )
}
if hs .hello .earlyData && !encryptedExtensions .earlyData {
c .quicRejectedEarlyData ()
}
if encryptedExtensions .earlyData {
if hs .session .cipherSuite != c .cipherSuite {
c .sendAlert (alertHandshakeFailure )
return errors .New ("tls: server accepted 0-RTT with the wrong cipher suite" )
}
if hs .session .alpnProtocol != c .clientProtocol {
c .sendAlert (alertHandshakeFailure )
return errors .New ("tls: server accepted 0-RTT with the wrong ALPN" )
}
}
if hs .echContext != nil && !hs .echContext .echRejected && encryptedExtensions .echRetryConfigs != nil {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: server sent ECH retry configs after accepting ECH" )
}
return nil
}
func (hs *clientHandshakeStateTLS13 ) readServerCertificate () error {
c := hs .c
if hs .usingPSK {
if c .config .VerifyConnection != nil {
if err := c .config .VerifyConnection (c .connectionStateLocked ()); err != nil {
c .sendAlert (alertBadCertificate )
return err
}
}
return nil
}
msg , err := c .readHandshake (hs .transcript )
if err != nil {
return err
}
certReq , ok := msg .(*certificateRequestMsgTLS13 )
if ok {
hs .certReq = certReq
msg , err = c .readHandshake (hs .transcript )
if err != nil {
return err
}
}
certMsg , ok := msg .(*certificateMsgTLS13 )
if !ok {
c .sendAlert (alertUnexpectedMessage )
return unexpectedMessageError (certMsg , msg )
}
if len (certMsg .certificate .Certificate ) == 0 {
c .sendAlert (alertDecodeError )
return errors .New ("tls: received empty certificates message" )
}
c .scts = certMsg .certificate .SignedCertificateTimestamps
c .ocspResponse = certMsg .certificate .OCSPStaple
if err := c .verifyServerCertificate (certMsg .certificate .Certificate ); err != nil {
return err
}
msg , err = c .readHandshake (nil )
if err != nil {
return err
}
certVerify , ok := msg .(*certificateVerifyMsg )
if !ok {
c .sendAlert (alertUnexpectedMessage )
return unexpectedMessageError (certVerify , msg )
}
if !isSupportedSignatureAlgorithm (certVerify .signatureAlgorithm , supportedSignatureAlgorithms ()) {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: certificate used with invalid signature algorithm" )
}
sigType , sigHash , err := typeAndHashFromSignatureScheme (certVerify .signatureAlgorithm )
if err != nil {
return c .sendAlert (alertInternalError )
}
if sigType == signaturePKCS1v15 || sigHash == crypto .SHA1 {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: certificate used with invalid signature algorithm" )
}
signed := signedMessage (sigHash , serverSignatureContext , hs .transcript )
if err := verifyHandshakeSignature (sigType , c .peerCertificates [0 ].PublicKey ,
sigHash , signed , certVerify .signature ); err != nil {
c .sendAlert (alertDecryptError )
return errors .New ("tls: invalid signature by the server certificate: " + err .Error())
}
if err := transcriptMsg (certVerify , hs .transcript ); err != nil {
return err
}
return nil
}
func (hs *clientHandshakeStateTLS13 ) readServerFinished () error {
c := hs .c
msg , err := c .readHandshake (nil )
if err != nil {
return err
}
finished , ok := msg .(*finishedMsg )
if !ok {
c .sendAlert (alertUnexpectedMessage )
return unexpectedMessageError (finished , msg )
}
expectedMAC := hs .suite .finishedHash (c .in .trafficSecret , hs .transcript )
if !hmac .Equal (expectedMAC , finished .verifyData ) {
c .sendAlert (alertDecryptError )
return errors .New ("tls: invalid server finished hash" )
}
if err := transcriptMsg (finished , hs .transcript ); err != nil {
return err
}
hs .trafficSecret = hs .suite .deriveSecret (hs .masterSecret ,
clientApplicationTrafficLabel , hs .transcript )
serverSecret := hs .suite .deriveSecret (hs .masterSecret ,
serverApplicationTrafficLabel , hs .transcript )
c .in .setTrafficSecret (hs .suite , QUICEncryptionLevelApplication , serverSecret )
err = c .config .writeKeyLog (keyLogLabelClientTraffic , hs .hello .random , hs .trafficSecret )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
err = c .config .writeKeyLog (keyLogLabelServerTraffic , hs .hello .random , serverSecret )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
c .ekm = hs .suite .exportKeyingMaterial (hs .masterSecret , hs .transcript )
return nil
}
func (hs *clientHandshakeStateTLS13 ) sendClientCertificate () error {
c := hs .c
if hs .certReq == nil {
return nil
}
if hs .echContext != nil && hs .echContext .echRejected {
if _ , err := hs .c .writeHandshakeRecord (&certificateMsgTLS13 {}, hs .transcript ); err != nil {
return err
}
return nil
}
cert , err := c .getClientCertificate (&CertificateRequestInfo {
AcceptableCAs : hs .certReq .certificateAuthorities ,
SignatureSchemes : hs .certReq .supportedSignatureAlgorithms ,
Version : c .vers ,
ctx : hs .ctx ,
})
if err != nil {
return err
}
certMsg := new (certificateMsgTLS13 )
certMsg .certificate = *cert
certMsg .scts = hs .certReq .scts && len (cert .SignedCertificateTimestamps ) > 0
certMsg .ocspStapling = hs .certReq .ocspStapling && len (cert .OCSPStaple ) > 0
if _ , err := hs .c .writeHandshakeRecord (certMsg , hs .transcript ); err != nil {
return err
}
if len (cert .Certificate ) == 0 {
return nil
}
certVerifyMsg := new (certificateVerifyMsg )
certVerifyMsg .hasSignatureAlgorithm = true
certVerifyMsg .signatureAlgorithm , err = selectSignatureScheme (c .vers , cert , hs .certReq .supportedSignatureAlgorithms )
if err != nil {
c .sendAlert (alertHandshakeFailure )
return err
}
sigType , sigHash , err := typeAndHashFromSignatureScheme (certVerifyMsg .signatureAlgorithm )
if err != nil {
return c .sendAlert (alertInternalError )
}
signed := signedMessage (sigHash , clientSignatureContext , hs .transcript )
signOpts := crypto .SignerOpts (sigHash )
if sigType == signatureRSAPSS {
signOpts = &rsa .PSSOptions {SaltLength : rsa .PSSSaltLengthEqualsHash , Hash : sigHash }
}
sig , err := cert .PrivateKey .(crypto .Signer ).Sign (c .config .rand (), signed , signOpts )
if err != nil {
c .sendAlert (alertInternalError )
return errors .New ("tls: failed to sign handshake: " + err .Error())
}
certVerifyMsg .signature = sig
if _ , err := hs .c .writeHandshakeRecord (certVerifyMsg , hs .transcript ); err != nil {
return err
}
return nil
}
func (hs *clientHandshakeStateTLS13 ) sendClientFinished () error {
c := hs .c
finished := &finishedMsg {
verifyData : hs .suite .finishedHash (c .out .trafficSecret , hs .transcript ),
}
if _ , err := hs .c .writeHandshakeRecord (finished , hs .transcript ); err != nil {
return err
}
c .out .setTrafficSecret (hs .suite , QUICEncryptionLevelApplication , hs .trafficSecret )
if !c .config .SessionTicketsDisabled && c .config .ClientSessionCache != nil {
c .resumptionSecret = hs .suite .deriveSecret (hs .masterSecret ,
resumptionLabel , hs .transcript )
}
if c .quic != nil {
if c .hand .Len () != 0 {
c .sendAlert (alertUnexpectedMessage )
}
c .quicSetWriteSecret (QUICEncryptionLevelApplication , hs .suite .id , hs .trafficSecret )
}
return nil
}
func (c *Conn ) handleNewSessionTicket (msg *newSessionTicketMsgTLS13 ) error {
if !c .isClient {
c .sendAlert (alertUnexpectedMessage )
return errors .New ("tls: received new session ticket from a client" )
}
if c .config .SessionTicketsDisabled || c .config .ClientSessionCache == nil {
return nil
}
if msg .lifetime == 0 {
return nil
}
lifetime := time .Duration (msg .lifetime ) * time .Second
if lifetime > maxSessionTicketLifetime {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: received a session ticket with invalid lifetime" )
}
if c .quic != nil && msg .maxEarlyData != 0 && msg .maxEarlyData != 0xffffffff {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid early data for QUIC connection" )
}
cipherSuite := cipherSuiteTLS13ByID (c .cipherSuite )
if cipherSuite == nil || c .resumptionSecret == nil {
return c .sendAlert (alertInternalError )
}
psk := cipherSuite .expandLabel (c .resumptionSecret , "resumption" ,
msg .nonce , cipherSuite .hash .Size ())
session := c .sessionState ()
session .secret = psk
session .useBy = uint64 (c .config .time ().Add (lifetime ).Unix ())
session .ageAdd = msg .ageAdd
session .EarlyData = c .quic != nil && msg .maxEarlyData == 0xffffffff
session .ticket = msg .label
if c .quic != nil && c .quic .enableSessionEvents {
c .quicStoreSession (session )
return nil
}
cs := &ClientSessionState {session : session }
if cacheKey := c .clientSessionCacheKey (); cacheKey != "" {
c .config .ClientSessionCache .Put (cacheKey , cs )
}
return nil
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .