flight4handler.go 15 KB

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