github.com/pion/dtls/v2@v2.2.12/flight0handler.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  package dtls
     5  
     6  import (
     7  	"context"
     8  	"crypto/rand"
     9  
    10  	"github.com/pion/dtls/v2/pkg/crypto/elliptic"
    11  	"github.com/pion/dtls/v2/pkg/protocol"
    12  	"github.com/pion/dtls/v2/pkg/protocol/alert"
    13  	"github.com/pion/dtls/v2/pkg/protocol/extension"
    14  	"github.com/pion/dtls/v2/pkg/protocol/handshake"
    15  )
    16  
    17  func flight0Parse(_ context.Context, _ flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
    18  	seq, msgs, ok := cache.fullPullMap(0, state.cipherSuite,
    19  		handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
    20  	)
    21  	if !ok {
    22  		// No valid message received. Keep reading
    23  		return 0, nil, nil
    24  	}
    25  	state.handshakeRecvSequence = seq
    26  
    27  	var clientHello *handshake.MessageClientHello
    28  
    29  	// Validate type
    30  	if clientHello, ok = msgs[handshake.TypeClientHello].(*handshake.MessageClientHello); !ok {
    31  		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
    32  	}
    33  
    34  	if !clientHello.Version.Equal(protocol.Version1_2) {
    35  		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
    36  	}
    37  
    38  	state.remoteRandom = clientHello.Random
    39  
    40  	cipherSuites := []CipherSuite{}
    41  	for _, id := range clientHello.CipherSuiteIDs {
    42  		if c := cipherSuiteForID(CipherSuiteID(id), cfg.customCipherSuites); c != nil {
    43  			cipherSuites = append(cipherSuites, c)
    44  		}
    45  	}
    46  
    47  	if state.cipherSuite, ok = findMatchingCipherSuite(cipherSuites, cfg.localCipherSuites); !ok {
    48  		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errCipherSuiteNoIntersection
    49  	}
    50  
    51  	for _, val := range clientHello.Extensions {
    52  		switch e := val.(type) {
    53  		case *extension.SupportedEllipticCurves:
    54  			if len(e.EllipticCurves) == 0 {
    55  				return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoSupportedEllipticCurves
    56  			}
    57  			state.namedCurve = e.EllipticCurves[0]
    58  		case *extension.UseSRTP:
    59  			profile, ok := findMatchingSRTPProfile(e.ProtectionProfiles, cfg.localSRTPProtectionProfiles)
    60  			if !ok {
    61  				return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerNoMatchingSRTPProfile
    62  			}
    63  			state.setSRTPProtectionProfile(profile)
    64  		case *extension.UseExtendedMasterSecret:
    65  			if cfg.extendedMasterSecret != DisableExtendedMasterSecret {
    66  				state.extendedMasterSecret = true
    67  			}
    68  		case *extension.ServerName:
    69  			state.serverName = e.ServerName // remote server name
    70  		case *extension.ALPN:
    71  			state.peerSupportedProtocols = e.ProtocolNameList
    72  		}
    73  	}
    74  
    75  	if cfg.extendedMasterSecret == RequireExtendedMasterSecret && !state.extendedMasterSecret {
    76  		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerRequiredButNoClientEMS
    77  	}
    78  
    79  	if state.localKeypair == nil {
    80  		var err error
    81  		state.localKeypair, err = elliptic.GenerateKeypair(state.namedCurve)
    82  		if err != nil {
    83  			return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, err
    84  		}
    85  	}
    86  
    87  	nextFlight := flight2
    88  
    89  	if cfg.insecureSkipHelloVerify {
    90  		nextFlight = flight4
    91  	}
    92  
    93  	return handleHelloResume(clientHello.SessionID, state, cfg, nextFlight)
    94  }
    95  
    96  func handleHelloResume(sessionID []byte, state *State, cfg *handshakeConfig, next flightVal) (flightVal, *alert.Alert, error) {
    97  	if len(sessionID) > 0 && cfg.sessionStore != nil {
    98  		if s, err := cfg.sessionStore.Get(sessionID); err != nil {
    99  			return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
   100  		} else if s.ID != nil {
   101  			cfg.log.Tracef("[handshake] resume session: %x", sessionID)
   102  
   103  			state.SessionID = sessionID
   104  			state.masterSecret = s.Secret
   105  
   106  			if err := state.initCipherSuite(); err != nil {
   107  				return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
   108  			}
   109  
   110  			clientRandom := state.localRandom.MarshalFixed()
   111  			cfg.writeKeyLog(keyLogLabelTLS12, clientRandom[:], state.masterSecret)
   112  
   113  			return flight4b, nil, nil
   114  		}
   115  	}
   116  	return next, nil, nil
   117  }
   118  
   119  func flight0Generate(_ flightConn, state *State, _ *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
   120  	// Initialize
   121  	if !cfg.insecureSkipHelloVerify {
   122  		state.cookie = make([]byte, cookieLength)
   123  		if _, err := rand.Read(state.cookie); err != nil {
   124  			return nil, nil, err
   125  		}
   126  	}
   127  
   128  	var zeroEpoch uint16
   129  	state.localEpoch.Store(zeroEpoch)
   130  	state.remoteEpoch.Store(zeroEpoch)
   131  	state.namedCurve = defaultNamedCurve
   132  
   133  	if err := state.localRandom.Populate(); err != nil {
   134  		return nil, nil, err
   135  	}
   136  
   137  	return nil, nil, nil
   138  }