package tls
import (
"bytes"
"context"
"crypto"
"crypto/hmac"
"crypto/internal/mlkem768"
"crypto/rsa"
"errors"
"hash"
"internal/byteorder"
"io"
"slices"
"time"
)
const maxClientPSKIdentities = 5
type serverHandshakeStateTLS13 struct {
c *Conn
ctx context .Context
clientHello *clientHelloMsg
hello *serverHelloMsg
sentDummyCCS bool
usingPSK bool
earlyData bool
suite *cipherSuiteTLS13
cert *Certificate
sigAlg SignatureScheme
earlySecret []byte
sharedKey []byte
handshakeSecret []byte
masterSecret []byte
trafficSecret []byte
transcript hash .Hash
clientFinished []byte
}
func (hs *serverHandshakeStateTLS13 ) handshake () error {
c := hs .c
if needFIPS () {
return errors .New ("tls: internal error: TLS 1.3 reached in FIPS mode" )
}
if err := hs .processClientHello (); err != nil {
return err
}
if err := hs .checkForResumption (); err != nil {
return err
}
if err := hs .pickCertificate (); err != nil {
return err
}
c .buffering = true
if err := hs .sendServerParameters (); err != nil {
return err
}
if err := hs .sendServerCertificate (); err != nil {
return err
}
if err := hs .sendServerFinished (); err != nil {
return err
}
if _ , err := c .flush (); err != nil {
return err
}
if err := hs .readClientCertificate (); err != nil {
return err
}
if err := hs .readClientFinished (); err != nil {
return err
}
c .isHandshakeComplete .Store (true )
return nil
}
func (hs *serverHandshakeStateTLS13 ) processClientHello () error {
c := hs .c
hs .hello = new (serverHelloMsg )
hs .hello .vers = VersionTLS12
hs .hello .supportedVersion = c .vers
if len (hs .clientHello .supportedVersions ) == 0 {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: client used the legacy version field to negotiate TLS 1.3" )
}
for _ , id := range hs .clientHello .cipherSuites {
if id == TLS_FALLBACK_SCSV {
if c .vers < c .config .maxSupportedVersion (roleServer ) {
c .sendAlert (alertInappropriateFallback )
return errors .New ("tls: client using inappropriate protocol fallback" )
}
break
}
}
if len (hs .clientHello .compressionMethods ) != 1 ||
hs .clientHello .compressionMethods [0 ] != compressionNone {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: TLS 1.3 client supports illegal compression methods" )
}
hs .hello .random = make ([]byte , 32 )
if _ , err := io .ReadFull (c .config .rand (), hs .hello .random ); err != nil {
c .sendAlert (alertInternalError )
return err
}
if len (hs .clientHello .secureRenegotiation ) != 0 {
c .sendAlert (alertHandshakeFailure )
return errors .New ("tls: initial handshake had non-empty renegotiation extension" )
}
if hs .clientHello .earlyData && c .quic != nil {
if len (hs .clientHello .pskIdentities ) == 0 {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: early_data without pre_shared_key" )
}
} else if hs .clientHello .earlyData {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: client sent unexpected early data" )
}
hs .hello .sessionId = hs .clientHello .sessionId
hs .hello .compressionMethod = compressionNone
preferenceList := defaultCipherSuitesTLS13
if !hasAESGCMHardwareSupport || !aesgcmPreferred (hs .clientHello .cipherSuites ) {
preferenceList = defaultCipherSuitesTLS13NoAES
}
for _ , suiteID := range preferenceList {
hs .suite = mutualCipherSuiteTLS13 (hs .clientHello .cipherSuites , suiteID )
if hs .suite != nil {
break
}
}
if hs .suite == nil {
c .sendAlert (alertHandshakeFailure )
return errors .New ("tls: no cipher suite supported by both client and server" )
}
c .cipherSuite = hs .suite .id
hs .hello .cipherSuite = hs .suite .id
hs .transcript = hs .suite .hash .New ()
var selectedGroup CurveID
var clientKeyShare *keyShare
preferredGroups := c .config .curvePreferences (c .vers )
for _ , preferredGroup := range preferredGroups {
ki := slices .IndexFunc (hs .clientHello .keyShares , func (ks keyShare ) bool {
return ks .group == preferredGroup
})
if ki != -1 {
clientKeyShare = &hs .clientHello .keyShares [ki ]
selectedGroup = clientKeyShare .group
if !slices .Contains (hs .clientHello .supportedCurves , selectedGroup ) {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: client sent key share for group it does not support" )
}
break
}
}
if selectedGroup == 0 {
for _ , preferredGroup := range preferredGroups {
if slices .Contains (hs .clientHello .supportedCurves , preferredGroup ) {
selectedGroup = preferredGroup
break
}
}
}
if selectedGroup == 0 {
c .sendAlert (alertHandshakeFailure )
return errors .New ("tls: no ECDHE curve supported by both client and server" )
}
if clientKeyShare == nil {
ks , err := hs .doHelloRetryRequest (selectedGroup )
if err != nil {
return err
}
clientKeyShare = ks
}
c .curveID = selectedGroup
ecdhGroup := selectedGroup
ecdhData := clientKeyShare .data
if selectedGroup == x25519Kyber768Draft00 {
ecdhGroup = X25519
if len (ecdhData ) != x25519PublicKeySize +mlkem768 .EncapsulationKeySize {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid Kyber client key share" )
}
ecdhData = ecdhData [:x25519PublicKeySize ]
}
if _ , ok := curveForCurveID (ecdhGroup ); !ok {
c .sendAlert (alertInternalError )
return errors .New ("tls: CurvePreferences includes unsupported curve" )
}
key , err := generateECDHEKey (c .config .rand (), ecdhGroup )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
hs .hello .serverShare = keyShare {group : selectedGroup , data : key .PublicKey ().Bytes ()}
peerKey , err := key .Curve ().NewPublicKey (ecdhData )
if err != nil {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid client key share" )
}
hs .sharedKey , err = key .ECDH (peerKey )
if err != nil {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid client key share" )
}
if selectedGroup == x25519Kyber768Draft00 {
ciphertext , kyberShared , err := kyberEncapsulate (clientKeyShare .data [x25519PublicKeySize :])
if err != nil {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid Kyber client key share" )
}
hs .sharedKey = append (hs .sharedKey , kyberShared ...)
hs .hello .serverShare .data = append (hs .hello .serverShare .data , ciphertext ...)
}
selectedProto , err := negotiateALPN (c .config .NextProtos , hs .clientHello .alpnProtocols , c .quic != nil )
if err != nil {
c .sendAlert (alertNoApplicationProtocol )
return err
}
c .clientProtocol = selectedProto
if c .quic != nil {
for _ , v := range hs .clientHello .supportedVersions {
if v < VersionTLS13 {
c .sendAlert (alertProtocolVersion )
return errors .New ("tls: client offered TLS version older than TLS 1.3" )
}
}
if hs .clientHello .quicTransportParameters == nil {
c .sendAlert (alertMissingExtension )
return errors .New ("tls: client did not send a quic_transport_parameters extension" )
}
c .quicSetTransportParameters (hs .clientHello .quicTransportParameters )
} else {
if hs .clientHello .quicTransportParameters != nil {
c .sendAlert (alertUnsupportedExtension )
return errors .New ("tls: client sent an unexpected quic_transport_parameters extension" )
}
}
c .serverName = hs .clientHello .serverName
return nil
}
func (hs *serverHandshakeStateTLS13 ) checkForResumption () error {
c := hs .c
if c .config .SessionTicketsDisabled {
return nil
}
modeOK := false
for _ , mode := range hs .clientHello .pskModes {
if mode == pskModeDHE {
modeOK = true
break
}
}
if !modeOK {
return nil
}
if len (hs .clientHello .pskIdentities ) != len (hs .clientHello .pskBinders ) {
c .sendAlert (alertIllegalParameter )
return errors .New ("tls: invalid or missing PSK binders" )
}
if len (hs .clientHello .pskIdentities ) == 0 {
return nil
}
for i , identity := range hs .clientHello .pskIdentities {
if i >= maxClientPSKIdentities {
break
}
var sessionState *SessionState
if c .config .UnwrapSession != nil {
var err error
sessionState , err = c .config .UnwrapSession (identity .label , c .connectionStateLocked ())
if err != nil {
return err
}
if sessionState == nil {
continue
}
} else {
plaintext := c .config .decryptTicket (identity .label , c .ticketKeys )
if plaintext == nil {
continue
}
var err error
sessionState , err = ParseSessionState (plaintext )
if err != nil {
continue
}
}
if sessionState .version != VersionTLS13 {
continue
}
createdAt := time .Unix (int64 (sessionState .createdAt ), 0 )
if c .config .time ().Sub (createdAt ) > maxSessionTicketLifetime {
continue
}
pskSuite := cipherSuiteTLS13ByID (sessionState .cipherSuite )
if pskSuite == nil || pskSuite .hash != hs .suite .hash {
continue
}
sessionHasClientCerts := len (sessionState .peerCertificates ) != 0
needClientCerts := requiresClientCert (c .config .ClientAuth )
if needClientCerts && !sessionHasClientCerts {
continue
}
if sessionHasClientCerts && c .config .ClientAuth == NoClientCert {
continue
}
if sessionHasClientCerts && c .config .time ().After (sessionState .peerCertificates [0 ].NotAfter ) {
continue
}
if sessionHasClientCerts && c .config .ClientAuth >= VerifyClientCertIfGiven &&
len (sessionState .verifiedChains ) == 0 {
continue
}
if c .quic != nil && c .quic .enableSessionEvents {
if err := c .quicResumeSession (sessionState ); err != nil {
return err
}
}
hs .earlySecret = hs .suite .extract (sessionState .secret , nil )
binderKey := hs .suite .deriveSecret (hs .earlySecret , resumptionBinderLabel , nil )
transcript := cloneHash (hs .transcript , hs .suite .hash )
if transcript == nil {
c .sendAlert (alertInternalError )
return errors .New ("tls: internal error: failed to clone hash" )
}
clientHelloBytes , err := hs .clientHello .marshalWithoutBinders ()
if err != nil {
c .sendAlert (alertInternalError )
return err
}
transcript .Write (clientHelloBytes )
pskBinder := hs .suite .finishedHash (binderKey , transcript )
if !hmac .Equal (hs .clientHello .pskBinders [i ], pskBinder ) {
c .sendAlert (alertDecryptError )
return errors .New ("tls: invalid PSK binder" )
}
if c .quic != nil && hs .clientHello .earlyData && i == 0 &&
sessionState .EarlyData && sessionState .cipherSuite == hs .suite .id &&
sessionState .alpnProtocol == c .clientProtocol {
hs .earlyData = true
transcript := hs .suite .hash .New ()
if err := transcriptMsg (hs .clientHello , transcript ); err != nil {
return err
}
earlyTrafficSecret := hs .suite .deriveSecret (hs .earlySecret , clientEarlyTrafficLabel , transcript )
c .quicSetReadSecret (QUICEncryptionLevelEarly , hs .suite .id , earlyTrafficSecret )
}
c .didResume = true
c .peerCertificates = sessionState .peerCertificates
c .ocspResponse = sessionState .ocspResponse
c .scts = sessionState .scts
c .verifiedChains = sessionState .verifiedChains
hs .hello .selectedIdentityPresent = true
hs .hello .selectedIdentity = uint16 (i )
hs .usingPSK = true
return nil
}
return nil
}
func cloneHash(in hash .Hash , h crypto .Hash ) hash .Hash {
type binaryMarshaler interface {
MarshalBinary () (data []byte , err error )
UnmarshalBinary (data []byte ) error
}
marshaler , ok := in .(binaryMarshaler )
if !ok {
return nil
}
state , err := marshaler .MarshalBinary ()
if err != nil {
return nil
}
out := h .New ()
unmarshaler , ok := out .(binaryMarshaler )
if !ok {
return nil
}
if err := unmarshaler .UnmarshalBinary (state ); err != nil {
return nil
}
return out
}
func (hs *serverHandshakeStateTLS13 ) pickCertificate () error {
c := hs .c
if hs .usingPSK {
return nil
}
if len (hs .clientHello .supportedSignatureAlgorithms ) == 0 {
return c .sendAlert (alertMissingExtension )
}
certificate , err := c .config .getCertificate (clientHelloInfo (hs .ctx , c , hs .clientHello ))
if err != nil {
if err == errNoCertificates {
c .sendAlert (alertUnrecognizedName )
} else {
c .sendAlert (alertInternalError )
}
return err
}
hs .sigAlg , err = selectSignatureScheme (c .vers , certificate , hs .clientHello .supportedSignatureAlgorithms )
if err != nil {
c .sendAlert (alertHandshakeFailure )
return err
}
hs .cert = certificate
return nil
}
func (hs *serverHandshakeStateTLS13 ) sendDummyChangeCipherSpec () error {
if hs .c .quic != nil {
return nil
}
if hs .sentDummyCCS {
return nil
}
hs .sentDummyCCS = true
return hs .c .writeChangeCipherRecord ()
}
func (hs *serverHandshakeStateTLS13 ) doHelloRetryRequest (selectedGroup CurveID ) (*keyShare , error ) {
c := hs .c
if err := transcriptMsg (hs .clientHello , hs .transcript ); err != nil {
return nil , err
}
chHash := hs .transcript .Sum (nil )
hs .transcript .Reset ()
hs .transcript .Write ([]byte {typeMessageHash , 0 , 0 , uint8 (len (chHash ))})
hs .transcript .Write (chHash )
helloRetryRequest := &serverHelloMsg {
vers : hs .hello .vers ,
random : helloRetryRequestRandom ,
sessionId : hs .hello .sessionId ,
cipherSuite : hs .hello .cipherSuite ,
compressionMethod : hs .hello .compressionMethod ,
supportedVersion : hs .hello .supportedVersion ,
selectedGroup : selectedGroup ,
}
if _ , err := hs .c .writeHandshakeRecord (helloRetryRequest , hs .transcript ); err != nil {
return nil , err
}
if err := hs .sendDummyChangeCipherSpec (); err != nil {
return nil , err
}
msg , err := c .readHandshake (nil )
if err != nil {
return nil , err
}
clientHello , ok := msg .(*clientHelloMsg )
if !ok {
c .sendAlert (alertUnexpectedMessage )
return nil , unexpectedMessageError (clientHello , msg )
}
if len (clientHello .keyShares ) != 1 {
c .sendAlert (alertIllegalParameter )
return nil , errors .New ("tls: client didn't send one key share in second ClientHello" )
}
ks := &clientHello .keyShares [0 ]
if ks .group != selectedGroup {
c .sendAlert (alertIllegalParameter )
return nil , errors .New ("tls: client sent unexpected key share in second ClientHello" )
}
if clientHello .earlyData {
c .sendAlert (alertIllegalParameter )
return nil , errors .New ("tls: client indicated early data in second ClientHello" )
}
if illegalClientHelloChange (clientHello , hs .clientHello ) {
c .sendAlert (alertIllegalParameter )
return nil , errors .New ("tls: client illegally modified second ClientHello" )
}
c .didHRR = true
hs .clientHello = clientHello
return ks , nil
}
func illegalClientHelloChange(ch , ch1 *clientHelloMsg ) bool {
if len (ch .supportedVersions ) != len (ch1 .supportedVersions ) ||
len (ch .cipherSuites ) != len (ch1 .cipherSuites ) ||
len (ch .supportedCurves ) != len (ch1 .supportedCurves ) ||
len (ch .supportedSignatureAlgorithms ) != len (ch1 .supportedSignatureAlgorithms ) ||
len (ch .supportedSignatureAlgorithmsCert ) != len (ch1 .supportedSignatureAlgorithmsCert ) ||
len (ch .alpnProtocols ) != len (ch1 .alpnProtocols ) {
return true
}
for i := range ch .supportedVersions {
if ch .supportedVersions [i ] != ch1 .supportedVersions [i ] {
return true
}
}
for i := range ch .cipherSuites {
if ch .cipherSuites [i ] != ch1 .cipherSuites [i ] {
return true
}
}
for i := range ch .supportedCurves {
if ch .supportedCurves [i ] != ch1 .supportedCurves [i ] {
return true
}
}
for i := range ch .supportedSignatureAlgorithms {
if ch .supportedSignatureAlgorithms [i ] != ch1 .supportedSignatureAlgorithms [i ] {
return true
}
}
for i := range ch .supportedSignatureAlgorithmsCert {
if ch .supportedSignatureAlgorithmsCert [i ] != ch1 .supportedSignatureAlgorithmsCert [i ] {
return true
}
}
for i := range ch .alpnProtocols {
if ch .alpnProtocols [i ] != ch1 .alpnProtocols [i ] {
return true
}
}
return ch .vers != ch1 .vers ||
!bytes .Equal (ch .random , ch1 .random ) ||
!bytes .Equal (ch .sessionId , ch1 .sessionId ) ||
!bytes .Equal (ch .compressionMethods , ch1 .compressionMethods ) ||
ch .serverName != ch1 .serverName ||
ch .ocspStapling != ch1 .ocspStapling ||
!bytes .Equal (ch .supportedPoints , ch1 .supportedPoints ) ||
ch .ticketSupported != ch1 .ticketSupported ||
!bytes .Equal (ch .sessionTicket , ch1 .sessionTicket ) ||
ch .secureRenegotiationSupported != ch1 .secureRenegotiationSupported ||
!bytes .Equal (ch .secureRenegotiation , ch1 .secureRenegotiation ) ||
ch .scts != ch1 .scts ||
!bytes .Equal (ch .cookie , ch1 .cookie ) ||
!bytes .Equal (ch .pskModes , ch1 .pskModes )
}
func (hs *serverHandshakeStateTLS13 ) sendServerParameters () error {
c := hs .c
if err := transcriptMsg (hs .clientHello , hs .transcript ); err != nil {
return err
}
if _ , err := hs .c .writeHandshakeRecord (hs .hello , hs .transcript ); err != nil {
return err
}
if err := hs .sendDummyChangeCipherSpec (); err != nil {
return err
}
earlySecret := hs .earlySecret
if earlySecret == nil {
earlySecret = hs .suite .extract (nil , nil )
}
hs .handshakeSecret = hs .suite .extract (hs .sharedKey ,
hs .suite .deriveSecret (earlySecret , "derived" , nil ))
clientSecret := hs .suite .deriveSecret (hs .handshakeSecret ,
clientHandshakeTrafficLabel , hs .transcript )
c .in .setTrafficSecret (hs .suite , QUICEncryptionLevelHandshake , clientSecret )
serverSecret := hs .suite .deriveSecret (hs .handshakeSecret ,
serverHandshakeTrafficLabel , hs .transcript )
c .out .setTrafficSecret (hs .suite , QUICEncryptionLevelHandshake , serverSecret )
if c .quic != nil {
if c .hand .Len () != 0 {
c .sendAlert (alertUnexpectedMessage )
}
c .quicSetWriteSecret (QUICEncryptionLevelHandshake , hs .suite .id , serverSecret )
c .quicSetReadSecret (QUICEncryptionLevelHandshake , hs .suite .id , clientSecret )
}
err := c .config .writeKeyLog (keyLogLabelClientHandshake , hs .clientHello .random , clientSecret )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
err = c .config .writeKeyLog (keyLogLabelServerHandshake , hs .clientHello .random , serverSecret )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
encryptedExtensions := new (encryptedExtensionsMsg )
encryptedExtensions .alpnProtocol = c .clientProtocol
if c .quic != nil {
p , err := c .quicGetTransportParameters ()
if err != nil {
return err
}
encryptedExtensions .quicTransportParameters = p
encryptedExtensions .earlyData = hs .earlyData
}
if _ , err := hs .c .writeHandshakeRecord (encryptedExtensions , hs .transcript ); err != nil {
return err
}
return nil
}
func (hs *serverHandshakeStateTLS13 ) requestClientCert () bool {
return hs .c .config .ClientAuth >= RequestClientCert && !hs .usingPSK
}
func (hs *serverHandshakeStateTLS13 ) sendServerCertificate () error {
c := hs .c
if hs .usingPSK {
return nil
}
if hs .requestClientCert () {
certReq := new (certificateRequestMsgTLS13 )
certReq .ocspStapling = true
certReq .scts = true
certReq .supportedSignatureAlgorithms = supportedSignatureAlgorithms ()
if c .config .ClientCAs != nil {
certReq .certificateAuthorities = c .config .ClientCAs .Subjects ()
}
if _ , err := hs .c .writeHandshakeRecord (certReq , hs .transcript ); err != nil {
return err
}
}
certMsg := new (certificateMsgTLS13 )
certMsg .certificate = *hs .cert
certMsg .scts = hs .clientHello .scts && len (hs .cert .SignedCertificateTimestamps ) > 0
certMsg .ocspStapling = hs .clientHello .ocspStapling && len (hs .cert .OCSPStaple ) > 0
if _ , err := hs .c .writeHandshakeRecord (certMsg , hs .transcript ); err != nil {
return err
}
certVerifyMsg := new (certificateVerifyMsg )
certVerifyMsg .hasSignatureAlgorithm = true
certVerifyMsg .signatureAlgorithm = hs .sigAlg
sigType , sigHash , err := typeAndHashFromSignatureScheme (hs .sigAlg )
if err != nil {
return c .sendAlert (alertInternalError )
}
signed := signedMessage (sigHash , serverSignatureContext , hs .transcript )
signOpts := crypto .SignerOpts (sigHash )
if sigType == signatureRSAPSS {
signOpts = &rsa .PSSOptions {SaltLength : rsa .PSSSaltLengthEqualsHash , Hash : sigHash }
}
sig , err := hs .cert .PrivateKey .(crypto .Signer ).Sign (c .config .rand (), signed , signOpts )
if err != nil {
public := hs .cert .PrivateKey .(crypto .Signer ).Public ()
if rsaKey , ok := public .(*rsa .PublicKey ); ok && sigType == signatureRSAPSS &&
rsaKey .N .BitLen ()/8 < sigHash .Size ()*2 +2 {
c .sendAlert (alertHandshakeFailure )
} else {
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 *serverHandshakeStateTLS13 ) sendServerFinished () 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
}
hs .masterSecret = hs .suite .extract (nil ,
hs .suite .deriveSecret (hs .handshakeSecret , "derived" , nil ))
hs .trafficSecret = hs .suite .deriveSecret (hs .masterSecret ,
clientApplicationTrafficLabel , hs .transcript )
serverSecret := hs .suite .deriveSecret (hs .masterSecret ,
serverApplicationTrafficLabel , hs .transcript )
c .out .setTrafficSecret (hs .suite , QUICEncryptionLevelApplication , serverSecret )
if c .quic != nil {
if c .hand .Len () != 0 {
c .sendAlert (alertUnexpectedMessage )
}
c .quicSetWriteSecret (QUICEncryptionLevelApplication , hs .suite .id , serverSecret )
}
err := c .config .writeKeyLog (keyLogLabelClientTraffic , hs .clientHello .random , hs .trafficSecret )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
err = c .config .writeKeyLog (keyLogLabelServerTraffic , hs .clientHello .random , serverSecret )
if err != nil {
c .sendAlert (alertInternalError )
return err
}
c .ekm = hs .suite .exportKeyingMaterial (hs .masterSecret , hs .transcript )
if !hs .requestClientCert () {
if err := hs .sendSessionTickets (); err != nil {
return err
}
}
return nil
}
func (hs *serverHandshakeStateTLS13 ) shouldSendSessionTickets () bool {
if hs .c .config .SessionTicketsDisabled {
return false
}
if hs .c .quic != nil {
return false
}
for _ , pskMode := range hs .clientHello .pskModes {
if pskMode == pskModeDHE {
return true
}
}
return false
}
func (hs *serverHandshakeStateTLS13 ) sendSessionTickets () error {
c := hs .c
hs .clientFinished = hs .suite .finishedHash (c .in .trafficSecret , hs .transcript )
finishedMsg := &finishedMsg {
verifyData : hs .clientFinished ,
}
if err := transcriptMsg (finishedMsg , hs .transcript ); err != nil {
return err
}
c .resumptionSecret = hs .suite .deriveSecret (hs .masterSecret ,
resumptionLabel , hs .transcript )
if !hs .shouldSendSessionTickets () {
return nil
}
return c .sendSessionTicket (false , nil )
}
func (c *Conn ) sendSessionTicket (earlyData bool , extra [][]byte ) error {
suite := cipherSuiteTLS13ByID (c .cipherSuite )
if suite == nil {
return errors .New ("tls: internal error: unknown cipher suite" )
}
psk := suite .expandLabel (c .resumptionSecret , "resumption" ,
nil , suite .hash .Size ())
m := new (newSessionTicketMsgTLS13 )
state := c .sessionState ()
state .secret = psk
state .EarlyData = earlyData
state .Extra = extra
if c .config .WrapSession != nil {
var err error
m .label , err = c .config .WrapSession (c .connectionStateLocked (), state )
if err != nil {
return err
}
} else {
stateBytes , err := state .Bytes ()
if err != nil {
c .sendAlert (alertInternalError )
return err
}
m .label , err = c .config .encryptTicket (stateBytes , c .ticketKeys )
if err != nil {
return err
}
}
m .lifetime = uint32 (maxSessionTicketLifetime / time .Second )
ageAdd := make ([]byte , 4 )
if _ , err := c .config .rand ().Read (ageAdd ); err != nil {
return err
}
m .ageAdd = byteorder .LeUint32 (ageAdd )
if earlyData {
m .maxEarlyData = 0xffffffff
}
if _ , err := c .writeHandshakeRecord (m , nil ); err != nil {
return err
}
return nil
}
func (hs *serverHandshakeStateTLS13 ) readClientCertificate () error {
c := hs .c
if !hs .requestClientCert () {
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
}
certMsg , ok := msg .(*certificateMsgTLS13 )
if !ok {
c .sendAlert (alertUnexpectedMessage )
return unexpectedMessageError (certMsg , msg )
}
if err := c .processCertsFromClient (certMsg .certificate ); err != nil {
return err
}
if c .config .VerifyConnection != nil {
if err := c .config .VerifyConnection (c .connectionStateLocked ()); err != nil {
c .sendAlert (alertBadCertificate )
return err
}
}
if len (certMsg .certificate .Certificate ) != 0 {
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: client 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: client certificate used with invalid signature algorithm" )
}
signed := signedMessage (sigHash , clientSignatureContext , 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 client certificate: " + err .Error())
}
if err := transcriptMsg (certVerify , hs .transcript ); err != nil {
return err
}
}
if err := hs .sendSessionTickets (); err != nil {
return err
}
return nil
}
func (hs *serverHandshakeStateTLS13 ) readClientFinished () 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 )
}
if !hmac .Equal (hs .clientFinished , finished .verifyData ) {
c .sendAlert (alertDecryptError )
return errors .New ("tls: invalid client finished hash" )
}
c .in .setTrafficSecret (hs .suite , QUICEncryptionLevelApplication , hs .trafficSecret )
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 .