text: /*
   *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  #include "pc/dtls_srtp_transport.h"
  
  #include <string.h>
  #include <cstdint>
  #include <memory>
  #include <set>
  
  #include "absl/memory/memory.h"
  #include "call/rtp_demuxer.h"
  #include "media/base/fake_rtp.h"
  #include "p2p/base/dtls_transport_internal.h"
  #include "p2p/base/fake_dtls_transport.h"
  #include "p2p/base/fake_ice_transport.h"
  #include "p2p/base/p2p_constants.h"
  #include "pc/rtp_transport.h"
  #include "pc/test/rtp_transport_test_util.h"
  #include "rtc_base/async_packet_socket.h"
  #include "rtc_base/byte_order.h"
  #include "rtc_base/copy_on_write_buffer.h"
  #include "rtc_base/rtc_certificate.h"
  #include "rtc_base/ssl_identity.h"
  #include "test/gtest.h"
  
  using cricket::FakeDtlsTransport;
  using cricket::FakeIceTransport;
  using webrtc::DtlsSrtpTransport;
  using webrtc::SrtpTransport;
  using webrtc::RtpTransport;
  
  const int kRtpAuthTagLen = 10;
  
  class DtlsSrtpTransportTest : public ::testing::Test,
                                public sigslot::has_slots<> {
   protected:
    DtlsSrtpTransportTest() {}
  
    ~DtlsSrtpTransportTest() {
      if (dtls_srtp_transport1_) {
        dtls_srtp_transport1_->UnregisterRtpDemuxerSink(&transport_observer1_);
      }
      if (dtls_srtp_transport2_) {
        dtls_srtp_transport2_->UnregisterRtpDemuxerSink(&transport_observer2_);
      }
    }
  
    std::unique_ptr<DtlsSrtpTransport> MakeDtlsSrtpTransport(
        FakeDtlsTransport* rtp_dtls,
        FakeDtlsTransport* rtcp_dtls,
        bool rtcp_mux_enabled) {
      auto dtls_srtp_transport =
          absl::make_unique<DtlsSrtpTransport>(rtcp_mux_enabled);
  
      dtls_srtp_transport->SetDtlsTransports(rtp_dtls, rtcp_dtls);
  
      return dtls_srtp_transport;
    }
  
    void MakeDtlsSrtpTransports(FakeDtlsTransport* rtp_dtls1,
                                FakeDtlsTransport* rtcp_dtls1,
                                FakeDtlsTransport* rtp_dtls2,
                                FakeDtlsTransport* rtcp_dtls2,
                                bool rtcp_mux_enabled) {
      dtls_srtp_transport1_ =
          MakeDtlsSrtpTransport(rtp_dtls1, rtcp_dtls1, rtcp_mux_enabled);
      dtls_srtp_transport2_ =
          MakeDtlsSrtpTransport(rtp_dtls2, rtcp_dtls2, rtcp_mux_enabled);
  
      dtls_srtp_transport1_->SignalRtcpPacketReceived.connect(
          &transport_observer1_,
          &webrtc::TransportObserver::OnRtcpPacketReceived);
      dtls_srtp_transport1_->SignalReadyToSend.connect(
          &transport_observer1_, &webrtc::TransportObserver::OnReadyToSend);
  
      dtls_srtp_transport2_->SignalRtcpPacketReceived.connect(
          &transport_observer2_,
          &webrtc::TransportObserver::OnRtcpPacketReceived);
      dtls_srtp_transport2_->SignalReadyToSend.connect(
          &transport_observer2_, &webrtc::TransportObserver::OnReadyToSend);
      webrtc::RtpDemuxerCriteria demuxer_criteria;
      // 0x00 is the payload type used in kPcmuFrame.
      demuxer_criteria.payload_types = {0x00};
      dtls_srtp_transport1_->RegisterRtpDemuxerSink(demuxer_criteria,
                                                    &transport_observer1_);
      dtls_srtp_transport2_->RegisterRtpDemuxerSink(demuxer_criteria,
                                                    &transport_observer2_);
    }
  
    void CompleteDtlsHandshake(FakeDtlsTransport* fake_dtls1,
                               FakeDtlsTransport* fake_dtls2) {
      auto cert1 = rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
          rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
      fake_dtls1->SetLocalCertificate(cert1);
      auto cert2 = rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
          rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
      fake_dtls2->SetLocalCertificate(cert2);
      fake_dtls1->SetDestination(fake_dtls2);
    }
  
    void SendRecvRtpPackets() {
      ASSERT_TRUE(dtls_srtp_transport1_);
      ASSERT_TRUE(dtls_srtp_transport2_);
      ASSERT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
      ASSERT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
  
      size_t rtp_len = sizeof(kPcmuFrame);
      size_t packet_size = rtp_len + kRtpAuthTagLen;
      rtc::Buffer rtp_packet_buffer(packet_size);
      char* rtp_packet_data = rtp_packet_buffer.data<char>();
      memcpy(rtp_packet_data, kPcmuFrame, rtp_len);
      // In order to be able to run this test function multiple times we can not
      // use the same sequence number twice. Increase the sequence number by one.
      rtc::SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_data) + 2,
                   ++sequence_number_);
      rtc::CopyOnWriteBuffer rtp_packet1to2(rtp_packet_data, rtp_len,
                                            packet_size);
      rtc::CopyOnWriteBuffer rtp_packet2to1(rtp_packet_data, rtp_len,
                                            packet_size);
  
      rtc::PacketOptions options;
      // Send a packet from |srtp_transport1_| to |srtp_transport2_| and verify
      // that the packet can be successfully received and decrypted.
      int prev_received_packets = transport_observer2_.rtp_count();
      ASSERT_TRUE(dtls_srtp_transport1_->SendRtpPacket(&rtp_packet1to2, options,
                                                       cricket::PF_SRTP_BYPASS));
      ASSERT_TRUE(transport_observer2_.last_recv_rtp_packet().data());
      EXPECT_EQ(0, memcmp(transport_observer2_.last_recv_rtp_packet().data(),
                          kPcmuFrame, rtp_len));
      EXPECT_EQ(prev_received_packets + 1, transport_observer2_.rtp_count());
  
      prev_received_packets = transport_observer1_.rtp_count();
      ASSERT_TRUE(dtls_srtp_transport2_->SendRtpPacket(&rtp_packet2to1, options,
                                                       cricket::PF_SRTP_BYPASS));
      ASSERT_TRUE(transport_observer1_.last_recv_rtp_packet().data());
      EXPECT_EQ(0, memcmp(transport_observer1_.last_recv_rtp_packet().data(),
                          kPcmuFrame, rtp_len));
      EXPECT_EQ(prev_received_packets + 1, transport_observer1_.rtp_count());
    }
  
    void SendRecvRtcpPackets() {
      size_t rtcp_len = sizeof(kRtcpReport);
      size_t packet_size = rtcp_len + 4 + kRtpAuthTagLen;
      rtc::Buffer rtcp_packet_buffer(packet_size);
  
      // TODO(zhihuang): Remove the extra copy when the SendRtpPacket method
      // doesn't take the CopyOnWriteBuffer by pointer.
      rtc::CopyOnWriteBuffer rtcp_packet1to2(kRtcpReport, rtcp_len, packet_size);
      rtc::CopyOnWriteBuffer rtcp_packet2to1(kRtcpReport, rtcp_len, packet_size);
  
      rtc::PacketOptions options;
      // Send a packet from |srtp_transport1_| to |srtp_transport2_| and verify
      // that the packet can be successfully received and decrypted.
      int prev_received_packets = transport_observer2_.rtcp_count();
      ASSERT_TRUE(dtls_srtp_transport1_->SendRtcpPacket(&rtcp_packet1to2, options,
                                                        cricket::PF_SRTP_BYPASS));
      ASSERT_TRUE(transport_observer2_.last_recv_rtcp_packet().data());
      EXPECT_EQ(0, memcmp(transport_observer2_.last_recv_rtcp_packet().data(),
                          kRtcpReport, rtcp_len));
      EXPECT_EQ(prev_received_packets + 1, transport_observer2_.rtcp_count());
  
      // Do the same thing in the opposite direction;
      prev_received_packets = transport_observer1_.rtcp_count();
      ASSERT_TRUE(dtls_srtp_transport2_->SendRtcpPacket(&rtcp_packet2to1, options,
                                                        cricket::PF_SRTP_BYPASS));
      ASSERT_TRUE(transport_observer1_.last_recv_rtcp_packet().data());
      EXPECT_EQ(0, memcmp(transport_observer1_.last_recv_rtcp_packet().data(),
                          kRtcpReport, rtcp_len));
      EXPECT_EQ(prev_received_packets + 1, transport_observer1_.rtcp_count());
    }
  
    void SendRecvRtpPacketsWithHeaderExtension(
        const std::vector<int>& encrypted_header_ids) {
      ASSERT_TRUE(dtls_srtp_transport1_);
      ASSERT_TRUE(dtls_srtp_transport2_);
      ASSERT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
      ASSERT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
  
      size_t rtp_len = sizeof(kPcmuFrameWithExtensions);
      size_t packet_size = rtp_len + kRtpAuthTagLen;
      rtc::Buffer rtp_packet_buffer(packet_size);
      char* rtp_packet_data = rtp_packet_buffer.data<char>();
      memcpy(rtp_packet_data, kPcmuFrameWithExtensions, rtp_len);
      // In order to be able to run this test function multiple times we can not
      // use the same sequence number twice. Increase the sequence number by one.
      rtc::SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_data) + 2,
                   ++sequence_number_);
      rtc::CopyOnWriteBuffer rtp_packet1to2(rtp_packet_data, rtp_len,
                                            packet_size);
      rtc::CopyOnWriteBuffer rtp_packet2to1(rtp_packet_data, rtp_len,
                                            packet_size);
  
      char original_rtp_data[sizeof(kPcmuFrameWithExtensions)];
      memcpy(original_rtp_data, rtp_packet_data, rtp_len);
  
      rtc::PacketOptions options;
      // Send a packet from |srtp_transport1_| to |srtp_transport2_| and verify
      // that the packet can be successfully received and decrypted.
      ASSERT_TRUE(dtls_srtp_transport1_->SendRtpPacket(&rtp_packet1to2, options,
                                                       cricket::PF_SRTP_BYPASS));
      ASSERT_TRUE(transport_observer2_.last_recv_rtp_packet().data());
      EXPECT_EQ(0, memcmp(transport_observer2_.last_recv_rtp_packet().data(),
                          original_rtp_data, rtp_len));
      // Get the encrypted packet from underneath packet transport and verify the
      // data and header extension are actually encrypted.
      auto fake_dtls_transport = static_cast<FakeDtlsTransport*>(
          dtls_srtp_transport1_->rtp_packet_transport());
      auto fake_ice_transport =
          static_cast<FakeIceTransport*>(fake_dtls_transport->ice_transport());
      EXPECT_NE(0, memcmp(fake_ice_transport->last_sent_packet().data(),
                          original_rtp_data, rtp_len));
      CompareHeaderExtensions(reinterpret_cast<const char*>(
                                  fake_ice_transport->last_sent_packet().data()),
                              fake_ice_transport->last_sent_packet().size(),
                              original_rtp_data, rtp_len, encrypted_header_ids,
                              false);
  
      // Do the same thing in the opposite direction.
      ASSERT_TRUE(dtls_srtp_transport2_->SendRtpPacket(&rtp_packet2to1, options,
                                                       cricket::PF_SRTP_BYPASS));
      ASSERT_TRUE(transport_observer1_.last_recv_rtp_packet().data());
      EXPECT_EQ(0, memcmp(transport_observer1_.last_recv_rtp_packet().data(),
                          original_rtp_data, rtp_len));
      // Get the encrypted packet from underneath packet transport and verify the
      // data and header extension are actually encrypted.
      fake_dtls_transport = static_cast<FakeDtlsTransport*>(
          dtls_srtp_transport2_->rtp_packet_transport());
      fake_ice_transport =
          static_cast<FakeIceTransport*>(fake_dtls_transport->ice_transport());
      EXPECT_NE(0, memcmp(fake_ice_transport->last_sent_packet().data(),
                          original_rtp_data, rtp_len));
      CompareHeaderExtensions(reinterpret_cast<const char*>(
                                  fake_ice_transport->last_sent_packet().data()),
                              fake_ice_transport->last_sent_packet().size(),
                              original_rtp_data, rtp_len, encrypted_header_ids,
                              false);
    }
  
    void SendRecvPackets() {
      SendRecvRtpPackets();
      SendRecvRtcpPackets();
    }
  
    std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport1_;
    std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport2_;
    webrtc::TransportObserver transport_observer1_;
    webrtc::TransportObserver transport_observer2_;
  
    int sequence_number_ = 0;
  };
  
  // Tests that if RTCP muxing is enabled and transports are set after RTP
  // transport finished the handshake, SRTP is set up.
  TEST_F(DtlsSrtpTransportTest, SetTransportsAfterHandshakeCompleteWithRtcpMux) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "video", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "video", cricket::ICE_CANDIDATE_COMPONENT_RTP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), nullptr, rtp_dtls2.get(), nullptr,
                           /*rtcp_mux_enabled=*/true);
  
    auto rtp_dtls3 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtp_dtls4 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
  
    CompleteDtlsHandshake(rtp_dtls3.get(), rtp_dtls4.get());
  
    dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls3.get(), nullptr);
    dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls4.get(), nullptr);
  
    SendRecvPackets();
  }
  
  // Tests that if RTCP muxing is not enabled and transports are set after both
  // RTP and RTCP transports finished the handshake, SRTP is set up.
  TEST_F(DtlsSrtpTransportTest,
         SetTransportsAfterHandshakeCompleteWithoutRtcpMux) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "video", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "video", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "video", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "video", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
                           rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
  
    auto rtp_dtls3 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls3 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    auto rtp_dtls4 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls4 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    CompleteDtlsHandshake(rtp_dtls3.get(), rtp_dtls4.get());
    CompleteDtlsHandshake(rtcp_dtls3.get(), rtcp_dtls4.get());
  
    dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls3.get(), rtcp_dtls3.get());
    dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls4.get(), rtcp_dtls4.get());
  
    SendRecvPackets();
  }
  
  // Tests if RTCP muxing is enabled, SRTP is set up as soon as the RTP DTLS
  // handshake is finished.
  TEST_F(DtlsSrtpTransportTest, SetTransportsBeforeHandshakeCompleteWithRtcpMux) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
                           rtcp_dtls2.get(),
                           /*rtcp_mux_enabled=*/false);
  
    dtls_srtp_transport1_->SetRtcpMuxEnabled(true);
    dtls_srtp_transport2_->SetRtcpMuxEnabled(true);
    CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
    SendRecvPackets();
  }
  
  // Tests if RTCP muxing is not enabled, SRTP is set up when both the RTP and
  // RTCP DTLS handshake are finished.
  TEST_F(DtlsSrtpTransportTest,
         SetTransportsBeforeHandshakeCompleteWithoutRtcpMux) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
                           rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
  
    CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
    EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
    EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
    CompleteDtlsHandshake(rtcp_dtls1.get(), rtcp_dtls2.get());
    SendRecvPackets();
  }
  
  // Tests that if the DtlsTransport underneath is changed, the previous DTLS-SRTP
  // context will be reset and will be re-setup once the new transports' handshake
  // complete.
  TEST_F(DtlsSrtpTransportTest, DtlsSrtpResetAfterDtlsTransportChange) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), nullptr, rtp_dtls2.get(), nullptr,
                           /*rtcp_mux_enabled=*/true);
  
    CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
    EXPECT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
    EXPECT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
  
    auto rtp_dtls3 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtp_dtls4 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
  
    // The previous context is reset.
    dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls3.get(), nullptr);
    dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls4.get(), nullptr);
    EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
    EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
  
    // Re-setup.
    CompleteDtlsHandshake(rtp_dtls3.get(), rtp_dtls4.get());
    SendRecvPackets();
  }
  
  // Tests if only the RTP DTLS handshake complete, and then RTCP muxing is
  // enabled, SRTP is set up.
  TEST_F(DtlsSrtpTransportTest,
         RtcpMuxEnabledAfterRtpTransportHandshakeComplete) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
                           rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
  
    CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
    // Inactive because the RTCP transport handshake didn't complete.
    EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
    EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
  
    dtls_srtp_transport1_->SetRtcpMuxEnabled(true);
    dtls_srtp_transport2_->SetRtcpMuxEnabled(true);
    // The transports should be active and be able to send packets when the
    // RTCP muxing is enabled.
    SendRecvPackets();
  }
  
  // Tests that when SetSend/RecvEncryptedHeaderExtensionIds is called, the SRTP
  // sessions are updated with new encryped header extension IDs immediately.
  TEST_F(DtlsSrtpTransportTest, EncryptedHeaderExtensionIdUpdated) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), nullptr, rtp_dtls2.get(), nullptr,
                           /*rtcp_mux_enabled=*/true);
    CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
  
    std::vector<int> encrypted_headers;
    encrypted_headers.push_back(kHeaderExtensionIDs[0]);
    encrypted_headers.push_back(kHeaderExtensionIDs[1]);
  
    dtls_srtp_transport1_->UpdateSendEncryptedHeaderExtensionIds(
        encrypted_headers);
    dtls_srtp_transport1_->UpdateRecvEncryptedHeaderExtensionIds(
        encrypted_headers);
    dtls_srtp_transport2_->UpdateSendEncryptedHeaderExtensionIds(
        encrypted_headers);
    dtls_srtp_transport2_->UpdateRecvEncryptedHeaderExtensionIds(
        encrypted_headers);
  }
  
  // Tests if RTCP muxing is enabled. DtlsSrtpTransport is ready to send once the
  // RTP DtlsTransport is ready.
  TEST_F(DtlsSrtpTransportTest, SignalReadyToSendFiredWithRtcpMux) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), nullptr, rtp_dtls2.get(), nullptr,
                           /*rtcp_mux_enabled=*/true);
  
    rtp_dtls1->SetDestination(rtp_dtls2.get());
    EXPECT_TRUE(transport_observer1_.ready_to_send());
    EXPECT_TRUE(transport_observer2_.ready_to_send());
  }
  
  // Tests if RTCP muxing is not enabled. DtlsSrtpTransport is ready to send once
  // both the RTP and RTCP DtlsTransport are ready.
  TEST_F(DtlsSrtpTransportTest, SignalReadyToSendFiredWithoutRtcpMux) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
                           rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
  
    rtp_dtls1->SetDestination(rtp_dtls2.get());
    EXPECT_FALSE(transport_observer1_.ready_to_send());
    EXPECT_FALSE(transport_observer2_.ready_to_send());
  
    rtcp_dtls1->SetDestination(rtcp_dtls2.get());
    EXPECT_TRUE(transport_observer1_.ready_to_send());
    EXPECT_TRUE(transport_observer2_.ready_to_send());
  }
  
  // Test that if an endpoint "fully" enables RTCP mux, setting the RTCP
  // transport to null, it *doesn't* reset its SRTP context. That would cause the
  // ROC and SRTCP index to be reset, causing replay detection and other errors
  // when attempting to unprotect packets.
  // Regression test for bugs.webrtc.org/8996
  TEST_F(DtlsSrtpTransportTest, SrtpSessionNotResetWhenRtcpTransportRemoved) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
                           rtcp_dtls2.get(), /*rtcp_mux_enabled=*/true);
    CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
    CompleteDtlsHandshake(rtcp_dtls1.get(), rtcp_dtls2.get());
  
    // Send some RTCP packets, causing the SRTCP index to be incremented.
    SendRecvRtcpPackets();
  
    // Set RTCP transport to null, which previously would trigger this problem.
    dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls1.get(), nullptr);
  
    // Attempt to send more RTCP packets. If the issue occurred, one side would
    // reset its context while the other would not, causing replay detection
    // errors when a packet with a duplicate SRTCP index is received.
    SendRecvRtcpPackets();
  }
  
  // Tests that RTCP packets can be sent and received if both sides actively reset
  // the SRTP parameters with the |active_reset_srtp_params_| flag.
  TEST_F(DtlsSrtpTransportTest, ActivelyResetSrtpParams) {
    auto rtp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls1 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
    auto rtp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
    auto rtcp_dtls2 = absl::make_unique<FakeDtlsTransport>(
        "audio", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
  
    MakeDtlsSrtpTransports(rtp_dtls1.get(), rtcp_dtls1.get(), rtp_dtls2.get(),
                           rtcp_dtls2.get(), /*rtcp_mux_enabled=*/true);
    CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
    CompleteDtlsHandshake(rtcp_dtls1.get(), rtcp_dtls2.get());
  
    // Send some RTCP packets, causing the SRTCP index to be incremented.
    SendRecvRtcpPackets();
  
    // Only set the |active_reset_srtp_params_| flag to be true one side.
    dtls_srtp_transport1_->SetActiveResetSrtpParams(true);
    // Set RTCP transport to null to trigger the SRTP parameters update.
    dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls1.get(), nullptr);
    dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls2.get(), nullptr);
  
    // Sending some RTCP packets.
    size_t rtcp_len = sizeof(kRtcpReport);
    size_t packet_size = rtcp_len + 4 + kRtpAuthTagLen;
    rtc::Buffer rtcp_packet_buffer(packet_size);
    rtc::CopyOnWriteBuffer rtcp_packet(kRtcpReport, rtcp_len, packet_size);
    int prev_received_packets = transport_observer2_.rtcp_count();
    ASSERT_TRUE(dtls_srtp_transport1_->SendRtcpPacket(
        &rtcp_packet, rtc::PacketOptions(), cricket::PF_SRTP_BYPASS));
    // The RTCP packet is not exepected to be received because the SRTP parameters
    // are only reset on one side and the SRTCP index is out of sync.
    EXPECT_EQ(prev_received_packets, transport_observer2_.rtcp_count());
  
    // Set the flag to be true on the other side.
    dtls_srtp_transport2_->SetActiveResetSrtpParams(true);
    // Set RTCP transport to null to trigger the SRTP parameters update.
    dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls1.get(), nullptr);
    dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls2.get(), nullptr);
  
    // RTCP packets flow is expected to work just fine.
    SendRecvRtcpPackets();
  }
  