flight4handler.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package dtls
  4. import (
  5. "context"
  6. "crypto/rand"
  7. "crypto/x509"
  8. "github.com/pion/dtls/v2/internal/ciphersuite"
  9. "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
  10. "github.com/pion/dtls/v2/pkg/crypto/elliptic"
  11. "github.com/pion/dtls/v2/pkg/crypto/prf"
  12. "github.com/pion/dtls/v2/pkg/crypto/signaturehash"
  13. "github.com/pion/dtls/v2/pkg/protocol"
  14. "github.com/pion/dtls/v2/pkg/protocol/alert"
  15. "github.com/pion/dtls/v2/pkg/protocol/extension"
  16. "github.com/pion/dtls/v2/pkg/protocol/handshake"
  17. "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
  18. )
  19. func flight4Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) { //nolint:gocognit
  20. seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence, state.cipherSuite,
  21. handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, true},
  22. handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
  23. handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, true},
  24. )
  25. if !ok {
  26. // No valid message received. Keep reading
  27. return 0, nil, nil
  28. }
  29. // Validate type
  30. var clientKeyExchange *handshake.MessageClientKeyExchange
  31. if clientKeyExchange, ok = msgs[handshake.TypeClientKeyExchange].(*handshake.MessageClientKeyExchange); !ok {
  32. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
  33. }
  34. if h, hasCert := msgs[handshake.TypeCertificate].(*handshake.MessageCertificate); hasCert {
  35. state.PeerCertificates = h.Certificate
  36. // If the client offer its certificate, just disable session resumption.
  37. // Otherwise, we have to store the certificate identitfication and expire time.
  38. // And we have to check whether this certificate expired, revoked or changed.
  39. //
  40. // https://curl.se/docs/CVE-2016-5419.html
  41. state.SessionID = nil
  42. }
  43. if h, hasCertVerify := msgs[handshake.TypeCertificateVerify].(*handshake.MessageCertificateVerify); hasCertVerify {
  44. if state.PeerCertificates == nil {
  45. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errCertificateVerifyNoCertificate
  46. }
  47. plainText := cache.pullAndMerge(
  48. handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
  49. handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
  50. handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
  51. handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
  52. handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
  53. handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
  54. handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
  55. handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
  56. )
  57. // Verify that the pair of hash algorithm and signiture is listed.
  58. var validSignatureScheme bool
  59. for _, ss := range cfg.localSignatureSchemes {
  60. if ss.Hash == h.HashAlgorithm && ss.Signature == h.SignatureAlgorithm {
  61. validSignatureScheme = true
  62. break
  63. }
  64. }
  65. if !validSignatureScheme {
  66. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoAvailableSignatureSchemes
  67. }
  68. if err := verifyCertificateVerify(plainText, h.HashAlgorithm, h.Signature, state.PeerCertificates); err != nil {
  69. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
  70. }
  71. var chains [][]*x509.Certificate
  72. var err error
  73. var verified bool
  74. if cfg.clientAuth >= VerifyClientCertIfGiven {
  75. if chains, err = verifyClientCert(state.PeerCertificates, cfg.clientCAs); err != nil {
  76. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
  77. }
  78. verified = true
  79. }
  80. if cfg.verifyPeerCertificate != nil {
  81. if err := cfg.verifyPeerCertificate(state.PeerCertificates, chains); err != nil {
  82. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
  83. }
  84. }
  85. state.peerCertificatesVerified = verified
  86. } else if state.PeerCertificates != nil {
  87. // A certificate was received, but we haven't seen a CertificateVerify
  88. // keep reading until we receive one
  89. return 0, nil, nil
  90. }
  91. if !state.cipherSuite.IsInitialized() {
  92. serverRandom := state.localRandom.MarshalFixed()
  93. clientRandom := state.remoteRandom.MarshalFixed()
  94. var err error
  95. var preMasterSecret []byte
  96. if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypePreSharedKey {
  97. var psk []byte
  98. if psk, err = cfg.localPSKCallback(clientKeyExchange.IdentityHint); err != nil {
  99. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  100. }
  101. state.IdentityHint = clientKeyExchange.IdentityHint
  102. switch state.cipherSuite.KeyExchangeAlgorithm() {
  103. case CipherSuiteKeyExchangeAlgorithmPsk:
  104. preMasterSecret = prf.PSKPreMasterSecret(psk)
  105. case (CipherSuiteKeyExchangeAlgorithmPsk | CipherSuiteKeyExchangeAlgorithmEcdhe):
  106. if preMasterSecret, err = prf.EcdhePSKPreMasterSecret(psk, clientKeyExchange.PublicKey, state.localKeypair.PrivateKey, state.localKeypair.Curve); err != nil {
  107. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  108. }
  109. default:
  110. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, errInvalidCipherSuite
  111. }
  112. } else {
  113. preMasterSecret, err = prf.PreMasterSecret(clientKeyExchange.PublicKey, state.localKeypair.PrivateKey, state.localKeypair.Curve)
  114. if err != nil {
  115. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, err
  116. }
  117. }
  118. if state.extendedMasterSecret {
  119. var sessionHash []byte
  120. sessionHash, err = cache.sessionHash(state.cipherSuite.HashFunc(), cfg.initialEpoch)
  121. if err != nil {
  122. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  123. }
  124. state.masterSecret, err = prf.ExtendedMasterSecret(preMasterSecret, sessionHash, state.cipherSuite.HashFunc())
  125. if err != nil {
  126. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  127. }
  128. } else {
  129. state.masterSecret, err = prf.MasterSecret(preMasterSecret, clientRandom[:], serverRandom[:], state.cipherSuite.HashFunc())
  130. if err != nil {
  131. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  132. }
  133. }
  134. if err := state.cipherSuite.Init(state.masterSecret, clientRandom[:], serverRandom[:], false); err != nil {
  135. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  136. }
  137. cfg.writeKeyLog(keyLogLabelTLS12, clientRandom[:], state.masterSecret)
  138. }
  139. if len(state.SessionID) > 0 {
  140. s := Session{
  141. ID: state.SessionID,
  142. Secret: state.masterSecret,
  143. }
  144. cfg.log.Tracef("[handshake] save new session: %x", s.ID)
  145. if err := cfg.sessionStore.Set(state.SessionID, s); err != nil {
  146. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  147. }
  148. }
  149. // Now, encrypted packets can be handled
  150. if err := c.handleQueuedPackets(ctx); err != nil {
  151. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  152. }
  153. seq, msgs, ok = cache.fullPullMap(seq, state.cipherSuite,
  154. handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
  155. )
  156. if !ok {
  157. // No valid message received. Keep reading
  158. return 0, nil, nil
  159. }
  160. state.handshakeRecvSequence = seq
  161. if _, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
  162. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
  163. }
  164. if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeAnonymous {
  165. if cfg.verifyConnection != nil {
  166. if err := cfg.verifyConnection(state.clone()); err != nil {
  167. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
  168. }
  169. }
  170. return flight6, nil, nil
  171. }
  172. switch cfg.clientAuth {
  173. case RequireAnyClientCert:
  174. if state.PeerCertificates == nil {
  175. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errClientCertificateRequired
  176. }
  177. case VerifyClientCertIfGiven:
  178. if state.PeerCertificates != nil && !state.peerCertificatesVerified {
  179. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, errClientCertificateNotVerified
  180. }
  181. case RequireAndVerifyClientCert:
  182. if state.PeerCertificates == nil {
  183. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errClientCertificateRequired
  184. }
  185. if !state.peerCertificatesVerified {
  186. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, errClientCertificateNotVerified
  187. }
  188. case NoClientCert, RequestClientCert:
  189. // go to flight6
  190. }
  191. if cfg.verifyConnection != nil {
  192. if err := cfg.verifyConnection(state.clone()); err != nil {
  193. return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
  194. }
  195. }
  196. return flight6, nil, nil
  197. }
  198. func flight4Generate(_ flightConn, state *State, _ *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
  199. extensions := []extension.Extension{&extension.RenegotiationInfo{
  200. RenegotiatedConnection: 0,
  201. }}
  202. if (cfg.extendedMasterSecret == RequestExtendedMasterSecret ||
  203. cfg.extendedMasterSecret == RequireExtendedMasterSecret) && state.extendedMasterSecret {
  204. extensions = append(extensions, &extension.UseExtendedMasterSecret{
  205. Supported: true,
  206. })
  207. }
  208. if state.srtpProtectionProfile != 0 {
  209. extensions = append(extensions, &extension.UseSRTP{
  210. ProtectionProfiles: []SRTPProtectionProfile{state.srtpProtectionProfile},
  211. })
  212. }
  213. if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {
  214. extensions = append(extensions, &extension.SupportedPointFormats{
  215. PointFormats: []elliptic.CurvePointFormat{elliptic.CurvePointFormatUncompressed},
  216. })
  217. }
  218. selectedProto, err := extension.ALPNProtocolSelection(cfg.supportedProtocols, state.peerSupportedProtocols)
  219. if err != nil {
  220. return nil, &alert.Alert{Level: alert.Fatal, Description: alert.NoApplicationProtocol}, err
  221. }
  222. if selectedProto != "" {
  223. extensions = append(extensions, &extension.ALPN{
  224. ProtocolNameList: []string{selectedProto},
  225. })
  226. state.NegotiatedProtocol = selectedProto
  227. }
  228. var pkts []*packet
  229. cipherSuiteID := uint16(state.cipherSuite.ID())
  230. if cfg.sessionStore != nil {
  231. state.SessionID = make([]byte, sessionLength)
  232. if _, err := rand.Read(state.SessionID); err != nil {
  233. return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  234. }
  235. }
  236. pkts = append(pkts, &packet{
  237. record: &recordlayer.RecordLayer{
  238. Header: recordlayer.Header{
  239. Version: protocol.Version1_2,
  240. },
  241. Content: &handshake.Handshake{
  242. Message: &handshake.MessageServerHello{
  243. Version: protocol.Version1_2,
  244. Random: state.localRandom,
  245. SessionID: state.SessionID,
  246. CipherSuiteID: &cipherSuiteID,
  247. CompressionMethod: defaultCompressionMethods()[0],
  248. Extensions: extensions,
  249. },
  250. },
  251. },
  252. })
  253. switch {
  254. case state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate:
  255. certificate, err := cfg.getCertificate(&ClientHelloInfo{
  256. ServerName: state.serverName,
  257. CipherSuites: []ciphersuite.ID{state.cipherSuite.ID()},
  258. RandomBytes: state.remoteRandom.RandomBytes,
  259. })
  260. if err != nil {
  261. return nil, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, err
  262. }
  263. pkts = append(pkts, &packet{
  264. record: &recordlayer.RecordLayer{
  265. Header: recordlayer.Header{
  266. Version: protocol.Version1_2,
  267. },
  268. Content: &handshake.Handshake{
  269. Message: &handshake.MessageCertificate{
  270. Certificate: certificate.Certificate,
  271. },
  272. },
  273. },
  274. })
  275. serverRandom := state.localRandom.MarshalFixed()
  276. clientRandom := state.remoteRandom.MarshalFixed()
  277. // Find compatible signature scheme
  278. signatureHashAlgo, err := signaturehash.SelectSignatureScheme(cfg.localSignatureSchemes, certificate.PrivateKey)
  279. if err != nil {
  280. return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, err
  281. }
  282. signature, err := generateKeySignature(clientRandom[:], serverRandom[:], state.localKeypair.PublicKey, state.namedCurve, certificate.PrivateKey, signatureHashAlgo.Hash)
  283. if err != nil {
  284. return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
  285. }
  286. state.localKeySignature = signature
  287. pkts = append(pkts, &packet{
  288. record: &recordlayer.RecordLayer{
  289. Header: recordlayer.Header{
  290. Version: protocol.Version1_2,
  291. },
  292. Content: &handshake.Handshake{
  293. Message: &handshake.MessageServerKeyExchange{
  294. EllipticCurveType: elliptic.CurveTypeNamedCurve,
  295. NamedCurve: state.namedCurve,
  296. PublicKey: state.localKeypair.PublicKey,
  297. HashAlgorithm: signatureHashAlgo.Hash,
  298. SignatureAlgorithm: signatureHashAlgo.Signature,
  299. Signature: state.localKeySignature,
  300. },
  301. },
  302. },
  303. })
  304. if cfg.clientAuth > NoClientCert {
  305. // An empty list of certificateAuthorities signals to
  306. // the client that it may send any certificate in response
  307. // to our request. When we know the CAs we trust, then
  308. // we can send them down, so that the client can choose
  309. // an appropriate certificate to give to us.
  310. var certificateAuthorities [][]byte
  311. if cfg.clientCAs != nil {
  312. // nolint:staticcheck // ignoring tlsCert.RootCAs.Subjects is deprecated ERR because cert does not come from SystemCertPool and it's ok if certificate authorities is empty.
  313. certificateAuthorities = cfg.clientCAs.Subjects()
  314. }
  315. pkts = append(pkts, &packet{
  316. record: &recordlayer.RecordLayer{
  317. Header: recordlayer.Header{
  318. Version: protocol.Version1_2,
  319. },
  320. Content: &handshake.Handshake{
  321. Message: &handshake.MessageCertificateRequest{
  322. CertificateTypes: []clientcertificate.Type{clientcertificate.RSASign, clientcertificate.ECDSASign},
  323. SignatureHashAlgorithms: cfg.localSignatureSchemes,
  324. CertificateAuthoritiesNames: certificateAuthorities,
  325. },
  326. },
  327. },
  328. })
  329. }
  330. case cfg.localPSKIdentityHint != nil || state.cipherSuite.KeyExchangeAlgorithm().Has(CipherSuiteKeyExchangeAlgorithmEcdhe):
  331. // To help the client in selecting which identity to use, the server
  332. // can provide a "PSK identity hint" in the ServerKeyExchange message.
  333. // If no hint is provided and cipher suite doesn't use elliptic curve,
  334. // the ServerKeyExchange message is omitted.
  335. //
  336. // https://tools.ietf.org/html/rfc4279#section-2
  337. srvExchange := &handshake.MessageServerKeyExchange{
  338. IdentityHint: cfg.localPSKIdentityHint,
  339. }
  340. if state.cipherSuite.KeyExchangeAlgorithm().Has(CipherSuiteKeyExchangeAlgorithmEcdhe) {
  341. srvExchange.EllipticCurveType = elliptic.CurveTypeNamedCurve
  342. srvExchange.NamedCurve = state.namedCurve
  343. srvExchange.PublicKey = state.localKeypair.PublicKey
  344. }
  345. pkts = append(pkts, &packet{
  346. record: &recordlayer.RecordLayer{
  347. Header: recordlayer.Header{
  348. Version: protocol.Version1_2,
  349. },
  350. Content: &handshake.Handshake{
  351. Message: srvExchange,
  352. },
  353. },
  354. })
  355. }
  356. pkts = append(pkts, &packet{
  357. record: &recordlayer.RecordLayer{
  358. Header: recordlayer.Header{
  359. Version: protocol.Version1_2,
  360. },
  361. Content: &handshake.Handshake{
  362. Message: &handshake.MessageServerHelloDone{},
  363. },
  364. },
  365. })
  366. return pkts, nil, nil
  367. }