package dtls
import (
"context"
"crypto/rand"
"github.com/pion/dtls/v3/pkg/crypto/elliptic"
"github.com/pion/dtls/v3/pkg/protocol"
"github.com/pion/dtls/v3/pkg/protocol/alert"
"github.com/pion/dtls/v3/pkg/protocol/extension"
"github.com/pion/dtls/v3/pkg/protocol/handshake"
)
func flight0Parse(
_ context .Context ,
_ flightConn ,
state *State ,
cache *handshakeCache ,
cfg *handshakeConfig ,
) (flightVal , *alert .Alert , error ) {
seq , msgs , ok := cache .fullPullMap (0 , state .cipherSuite ,
handshakeCachePullRule {handshake .TypeClientHello , cfg .initialEpoch , true , false },
)
if !ok {
return 0 , nil , nil
}
state .setLocalConnectionID (nil )
state .remoteConnectionID = nil
state .handshakeRecvSequence = seq
var clientHello *handshake .MessageClientHello
if clientHello , ok = msgs [handshake .TypeClientHello ].(*handshake .MessageClientHello ); !ok {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InternalError }, nil
}
if !clientHello .Version .Equal (protocol .Version1_2 ) {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .ProtocolVersion }, errUnsupportedProtocolVersion
}
state .remoteRandom = clientHello .Random
cipherSuites := []CipherSuite {}
for _ , id := range clientHello .CipherSuiteIDs {
if c := cipherSuiteForID (CipherSuiteID (id ), cfg .customCipherSuites ); c != nil {
cipherSuites = append (cipherSuites , c )
}
}
if state .cipherSuite , ok = findMatchingCipherSuite (cipherSuites , cfg .localCipherSuites ); !ok {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errCipherSuiteNoIntersection
}
for _ , val := range clientHello .Extensions {
switch ext := val .(type ) {
case *extension .SupportedEllipticCurves :
if len (ext .EllipticCurves ) == 0 {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errNoSupportedEllipticCurves
}
state .namedCurve = ext .EllipticCurves [0 ]
case *extension .UseSRTP :
profile , ok := findMatchingSRTPProfile (ext .ProtectionProfiles , cfg .localSRTPProtectionProfiles )
if !ok {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errServerNoMatchingSRTPProfile
}
state .setSRTPProtectionProfile (profile )
state .remoteSRTPMasterKeyIdentifier = ext .MasterKeyIdentifier
case *extension .UseExtendedMasterSecret :
if cfg .extendedMasterSecret != DisableExtendedMasterSecret {
state .extendedMasterSecret = true
}
case *extension .ServerName :
state .serverName = ext .ServerName
case *extension .ALPN :
state .peerSupportedProtocols = ext .ProtocolNameList
case *extension .ConnectionID :
if cfg .connectionIDGenerator != nil {
state .remoteConnectionID = ext .CID
}
}
}
if state .remoteConnectionID == nil {
state .setLocalConnectionID (nil )
}
if cfg .extendedMasterSecret == RequireExtendedMasterSecret && !state .extendedMasterSecret {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errServerRequiredButNoClientEMS
}
if state .localKeypair == nil {
var err error
state .localKeypair , err = elliptic .GenerateKeypair (state .namedCurve )
if err != nil {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .IllegalParameter }, err
}
}
nextFlight := flight2
if cfg .insecureSkipHelloVerify {
nextFlight = flight4
}
return handleHelloResume (clientHello .SessionID , state , cfg , nextFlight )
}
func handleHelloResume(
sessionID []byte ,
state *State ,
cfg *handshakeConfig ,
next flightVal ,
) (flightVal , *alert .Alert , error ) {
if len (sessionID ) > 0 && cfg .sessionStore != nil {
if s , err := cfg .sessionStore .Get (sessionID ); err != nil {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InternalError }, err
} else if s .ID != nil {
cfg .log .Tracef ("[handshake] resume session: %x" , sessionID )
state .SessionID = sessionID
state .masterSecret = s .Secret
if err := state .initCipherSuite (); err != nil {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InternalError }, err
}
clientRandom := state .localRandom .MarshalFixed ()
cfg .writeKeyLog (keyLogLabelTLS12 , clientRandom [:], state .masterSecret )
return flight4b , nil , nil
}
}
return next , nil , nil
}
func flight0Generate(
_ flightConn ,
state *State ,
_ *handshakeCache ,
cfg *handshakeConfig ,
) ([]*packet , *alert .Alert , error ) {
if !cfg .insecureSkipHelloVerify {
state .cookie = make ([]byte , cookieLength )
if _ , err := rand .Read (state .cookie ); err != nil {
return nil , nil , err
}
}
var zeroEpoch uint16
state .localEpoch .Store (zeroEpoch )
state .remoteEpoch .Store (zeroEpoch )
state .namedCurve = defaultNamedCurve
if err := state .localRandom .Populate (); err != nil {
return nil , nil , err
}
return nil , nil , nil
}
The pages are generated with Golds v0.8.2 . (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 .