package dtls
import (
"context"
"crypto/rand"
"github.com/pion/dtls/v2/pkg/crypto/elliptic"
"github.com/pion/dtls/v2/pkg/protocol"
"github.com/pion/dtls/v2/pkg/protocol/alert"
"github.com/pion/dtls/v2/pkg/protocol/extension"
"github.com/pion/dtls/v2/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 .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 e := val .(type ) {
case *extension .SupportedEllipticCurves :
if len (e .EllipticCurves ) == 0 {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errNoSupportedEllipticCurves
}
state .namedCurve = e .EllipticCurves [0 ]
case *extension .UseSRTP :
profile , ok := findMatchingSRTPProfile (e .ProtectionProfiles , cfg .localSRTPProtectionProfiles )
if !ok {
return 0 , &alert .Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errServerNoMatchingSRTPProfile
}
state .setSRTPProtectionProfile (profile )
case *extension .UseExtendedMasterSecret :
if cfg .extendedMasterSecret != DisableExtendedMasterSecret {
state .extendedMasterSecret = true
}
case *extension .ServerName :
state .serverName = e .ServerName
case *extension .ALPN :
state .peerSupportedProtocols = e .ProtocolNameList
}
}
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 .