44package dtls
55
66import (
7- "crypto/rand"
7+ "context"
8+ "slices"
89
10+ "github.com/pion/dtls/v3/pkg/crypto/elliptic"
11+ "github.com/pion/dtls/v3/pkg/protocol"
912 "github.com/pion/dtls/v3/pkg/protocol/alert"
13+ "github.com/pion/dtls/v3/pkg/protocol/extension"
14+ "github.com/pion/dtls/v3/pkg/protocol/handshake"
1015)
1116
1217// we'll add the flight handlers for the DTLS 1.3 server here.
@@ -33,31 +38,144 @@ import (
3338// | Flight 4c |
3439// +-----------+
3540
36- func flight13_0Generate (
41+ //nolint:cyclop,gocognit
42+ func flight13_0Parse (
43+ _ context.Context ,
3744 _ flightConn ,
3845 state * State ,
39- _ * handshakeCache ,
46+ cache * handshakeCache ,
4047 cfg * handshakeConfig ,
41- ) ([]* packet , * alert.Alert , error ) { //nolint:unparam
42- // Initialize
43- if ! cfg .insecureSkipHelloVerify {
44- state .cookie = make ([]byte , cookieLength )
45- if _ , err := rand .Read (state .cookie ); err != nil {
46- return nil , nil , err
48+ ) (flightVal13 , * alert.Alert , error ) {
49+ if state .localVersion != protocol .Version1_3 {
50+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .InternalError }, errInvalidProtocolVersionState
51+ }
52+ seq , msgs , ok := cache .fullPullMap (0 , state .cipherSuite ,
53+ handshakeCachePullRule {handshake .TypeClientHello , cfg .initialEpoch , true , false },
54+ )
55+ if ! ok {
56+ // No valid message received. Keep reading
57+ return 0 , nil , nil
58+ }
59+
60+ // Connection Identifiers must be negotiated afresh on session resumption.
61+ // https://datatracker.ietf.org/doc/html/rfc9146#name-the-connection_id-extension
62+ state .setLocalConnectionID (nil )
63+ state .remoteConnectionID = nil
64+
65+ state .handshakeRecvSequence = seq
66+
67+ var clientHello * handshake.MessageClientHello
68+
69+ // Validate type
70+ if clientHello , ok = msgs [handshake .TypeClientHello ].(* handshake.MessageClientHello ); ! ok {
71+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .InternalError }, nil
72+ }
73+
74+ if ! clientHello .Version .Equal (protocol .Version1_2 ) {
75+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .ProtocolVersion }, errUnsupportedProtocolVersion
76+ }
77+
78+ state .remoteRandom = clientHello .Random
79+
80+ cipherSuites := []CipherSuite {}
81+ for _ , id := range clientHello .CipherSuiteIDs {
82+ if id == renegotiationInfoSCSV {
83+ state .remoteSupportsRenegotiation = true
84+
85+ continue
4786 }
87+ if c := cipherSuiteForID (CipherSuiteID (id ), cfg .customCipherSuites ); c != nil {
88+ cipherSuites = append (cipherSuites , c )
89+ }
90+ }
91+
92+ // Check for DTLS 1.3 cipher suites?
93+ if state .cipherSuite , ok = findMatchingCipherSuite (cipherSuites , cfg .localCipherSuites ); ! ok {
94+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errCipherSuiteNoIntersection
4895 }
4996
50- var zeroEpoch uint16
51- state .localEpoch .Store (zeroEpoch )
52- state .remoteEpoch .Store (zeroEpoch )
53- if len (cfg .ellipticCurves ) < 1 {
54- return nil , nil , errEmptyEllipticCurves
97+ for _ , val := range clientHello .Extensions {
98+ switch ext := val .(type ) {
99+ case * extension.SupportedEllipticCurves :
100+ if len (ext .EllipticCurves ) == 0 {
101+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errNoSupportedEllipticCurves
102+ }
103+ state .remoteGroups = ext .EllipticCurves
104+ case * extension.UseSRTP :
105+ profile , ok := findMatchingSRTPProfile (cfg .localSRTPProtectionProfiles , ext .ProtectionProfiles )
106+ if ! ok {
107+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errServerNoMatchingSRTPProfile
108+ }
109+ state .setSRTPProtectionProfile (profile )
110+ state .remoteSRTPMasterKeyIdentifier = ext .MasterKeyIdentifier
111+ case * extension.UseExtendedMasterSecret :
112+ if cfg .extendedMasterSecret != DisableExtendedMasterSecret {
113+ state .extendedMasterSecret = true
114+ }
115+ case * extension.ServerName :
116+ state .serverName = ext .ServerName // remote server name
117+ case * extension.RenegotiationInfo :
118+ state .remoteSupportsRenegotiation = true
119+ case * extension.ALPN :
120+ state .peerSupportedProtocols = ext .ProtocolNameList
121+ case * extension.ConnectionID :
122+ // Only set connection ID to be sent if server supports connection
123+ // IDs.
124+ if cfg .connectionIDGenerator != nil {
125+ state .remoteConnectionID = ext .CID
126+ }
127+ case * extension.SignatureAlgorithmsCert :
128+ // Store the client's certificate signature schemes for later validation
129+ state .remoteCertSignatureSchemes = ext .SignatureHashAlgorithms
130+ case * extension.SupportedVersions :
131+ state .remoteVersions = ext .Versions
132+ case * extension.KeyShare :
133+ state .remoteKeyEntries = ext .ClientShares
134+ }
135+ }
136+
137+ if ! slices .Contains (state .remoteVersions , protocol .Version1_3 ) {
138+ // nolint:godox
139+ // TODO: This should actually handover the state machine to DTLS 1.2
140+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .InternalError }, errInvalidProtocolVersionState
141+ }
142+
143+ // If the client doesn't support connection IDs, the server should not
144+ // expect one to be sent.
145+ if state .remoteConnectionID == nil {
146+ state .setLocalConnectionID (nil )
147+ }
148+
149+ if cfg .extendedMasterSecret == RequireExtendedMasterSecret && ! state .extendedMasterSecret {
150+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .InsufficientSecurity }, errServerRequiredButNoClientEMS
151+ }
152+
153+ if state .localKeypair == nil {
154+ var err error
155+ state .localKeypair , err = elliptic .GenerateKeypair (state .namedCurve )
156+ if err != nil {
157+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .IllegalParameter }, err
158+ }
159+ }
160+
161+ nextFlight := flight13_2
162+
163+ var groups []elliptic.Curve
164+ for _ , entry := range state .remoteKeyEntries {
165+ // Clients MUST NOT offer any KeyShareEntry values
166+ // for groups not listed in the client's "supported_groups" extension.
167+ // Servers MAY check for violations of these rules and abort the
168+ // handshake with an "illegal_parameter" alert if one is violated.
169+ if ! slices .Contains (state .remoteGroups , entry .Group ) {
170+ return 0 , & alert.Alert {Level : alert .Fatal , Description : alert .IllegalParameter }, errInvalidGroupInKeyShare
171+ }
172+ groups = append (groups , entry .Group )
55173 }
56- state .namedCurve = cfg .ellipticCurves [ 0 ]
174+ state .namedCurve , _ = findMatchingGroup ( groups , cfg .ellipticCurves )
57175
58- if err := state . localRandom . Populate (); err != nil {
59- return nil , nil , err
176+ if cfg . insecureSkipHelloVerify {
177+ nextFlight = flight13_4
60178 }
61179
62- return nil , nil , nil
180+ return nextFlight , nil , nil
63181}
0 commit comments