/*
 *  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/dtlssrtptransport.h"

#include <memory>
#include <string>
#include <utility>

#include "media/base/rtputils.h"
#include "rtc_base/sslstreamadapter.h"

namespace {
// Value specified in RFC 5764.
static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
}  // namespace

namespace webrtc {

DtlsSrtpTransport::DtlsSrtpTransport(
    std::unique_ptr<webrtc::SrtpTransport> srtp_transport)
    : RtpTransportInternalAdapter(srtp_transport.get()) {
  srtp_transport_ = std::move(srtp_transport);
  RTC_DCHECK(srtp_transport_);
  srtp_transport_->SignalPacketReceived.connect(
      this, &DtlsSrtpTransport::OnPacketReceived);
  srtp_transport_->SignalReadyToSend.connect(this,
                                             &DtlsSrtpTransport::OnReadyToSend);
  srtp_transport_->SignalNetworkRouteChanged.connect(
      this, &DtlsSrtpTransport::OnNetworkRouteChanged);
  srtp_transport_->SignalWritableState.connect(
      this, &DtlsSrtpTransport::OnWritableState);
  srtp_transport_->SignalSentPacket.connect(this,
                                            &DtlsSrtpTransport::OnSentPacket);
}

void DtlsSrtpTransport::SetDtlsTransports(
    cricket::DtlsTransportInternal* rtp_dtls_transport,
    cricket::DtlsTransportInternal* rtcp_dtls_transport) {
  // Transport names should be the same.
  if (rtp_dtls_transport && rtcp_dtls_transport) {
    RTC_DCHECK(rtp_dtls_transport->transport_name() ==
               rtcp_dtls_transport->transport_name());
  }

  // When using DTLS-SRTP, we must reset the SrtpTransport every time the
  // DtlsTransport changes and wait until the DTLS handshake is complete to set
  // the newly negotiated parameters.
  if (IsActive()) {
    srtp_transport_->ResetParams();
  }

  const std::string transport_name =
      rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null";

  // This would only be possible if using BUNDLE but not rtcp-mux, which isn't
  // allowed according to the BUNDLE spec.
  RTC_CHECK(!(IsActive()))
      << "Setting RTCP for DTLS/SRTP after the DTLS is active "
         "should never happen.";

  RTC_LOG(LS_INFO) << "Setting RTCP Transport on " << transport_name
                   << " transport " << rtcp_dtls_transport;
  SetRtcpDtlsTransport(rtcp_dtls_transport);
  SetRtcpPacketTransport(rtcp_dtls_transport);

  RTC_LOG(LS_INFO) << "Setting RTP Transport on " << transport_name
                   << " transport " << rtp_dtls_transport;
  SetRtpDtlsTransport(rtp_dtls_transport);
  SetRtpPacketTransport(rtp_dtls_transport);

  UpdateWritableStateAndMaybeSetupDtlsSrtp();
}

void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
  srtp_transport_->SetRtcpMuxEnabled(enable);
  if (enable) {
    UpdateWritableStateAndMaybeSetupDtlsSrtp();
  }
}

void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds(
    const std::vector<int>& send_extension_ids) {
  if (send_extension_ids_ == send_extension_ids) {
    return;
  }
  send_extension_ids_.emplace(send_extension_ids);
  if (DtlsHandshakeCompleted()) {
    // Reset the crypto parameters to update the send extension IDs.
    SetupRtpDtlsSrtp();
  }
}

void DtlsSrtpTransport::UpdateRecvEncryptedHeaderExtensionIds(
    const std::vector<int>& recv_extension_ids) {
  if (recv_extension_ids_ == recv_extension_ids) {
    return;
  }
  recv_extension_ids_.emplace(recv_extension_ids);
  if (DtlsHandshakeCompleted()) {
    // Reset the crypto parameters to update the receive extension IDs.
    SetupRtpDtlsSrtp();
  }
}

bool DtlsSrtpTransport::IsDtlsActive() {
  auto rtcp_dtls_transport =
      rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
  return (rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive() &&
          (!rtcp_dtls_transport || rtcp_dtls_transport->IsDtlsActive()));
}

bool DtlsSrtpTransport::IsDtlsConnected() {
  auto rtcp_dtls_transport =
      rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
  return (rtp_dtls_transport_ &&
          rtp_dtls_transport_->dtls_state() ==
              cricket::DTLS_TRANSPORT_CONNECTED &&
          (!rtcp_dtls_transport || rtcp_dtls_transport->dtls_state() ==
                                       cricket::DTLS_TRANSPORT_CONNECTED));
}

bool DtlsSrtpTransport::IsDtlsWritable() {
  auto rtp_packet_transport = srtp_transport_->rtp_packet_transport();
  auto rtcp_packet_transport =
      rtcp_mux_enabled() ? nullptr : srtp_transport_->rtcp_packet_transport();
  return rtp_packet_transport && rtp_packet_transport->writable() &&
         (!rtcp_packet_transport || rtcp_packet_transport->writable());
}

bool DtlsSrtpTransport::DtlsHandshakeCompleted() {
  return IsDtlsActive() && IsDtlsConnected();
}

void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
  if (IsActive() || !DtlsHandshakeCompleted()) {
    return;
  }

  SetupRtpDtlsSrtp();

  if (!rtcp_mux_enabled() && rtcp_dtls_transport_) {
    SetupRtcpDtlsSrtp();
  }
}

void DtlsSrtpTransport::SetupRtpDtlsSrtp() {
  // Use an empty encrypted header extension ID vector if not set. This could
  // happen when the DTLS handshake is completed before processing the
  // Offer/Answer which contains the encrypted header extension IDs.
  std::vector<int> send_extension_ids;
  std::vector<int> recv_extension_ids;
  if (send_extension_ids_) {
    send_extension_ids = *send_extension_ids_;
  }
  if (recv_extension_ids_) {
    recv_extension_ids = *recv_extension_ids_;
  }

  int selected_crypto_suite;
  rtc::ZeroOnFreeBuffer<unsigned char> send_key;
  rtc::ZeroOnFreeBuffer<unsigned char> recv_key;

  if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
                     &recv_key) ||
      !srtp_transport_->SetRtpParams(
          selected_crypto_suite, &send_key[0],
          static_cast<int>(send_key.size()), send_extension_ids,
          selected_crypto_suite, &recv_key[0],
          static_cast<int>(recv_key.size()), recv_extension_ids)) {
    SignalDtlsSrtpSetupFailure(this, /*rtcp=*/false);
    RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
  }
}

void DtlsSrtpTransport::SetupRtcpDtlsSrtp() {
  // Return if the DTLS-SRTP is active because the encrypted header extension
  // IDs don't need to be updated for RTCP and the crypto params don't need to
  // be reset.
  if (IsActive()) {
    return;
  }

  std::vector<int> send_extension_ids;
  std::vector<int> recv_extension_ids;
  if (send_extension_ids_) {
    send_extension_ids = *send_extension_ids_;
  }
  if (recv_extension_ids_) {
    recv_extension_ids = *recv_extension_ids_;
  }

  int selected_crypto_suite;
  rtc::ZeroOnFreeBuffer<unsigned char> rtcp_send_key;
  rtc::ZeroOnFreeBuffer<unsigned char> rtcp_recv_key;
  if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
                     &rtcp_send_key, &rtcp_recv_key) ||
      !srtp_transport_->SetRtcpParams(
          selected_crypto_suite, &rtcp_send_key[0],
          static_cast<int>(rtcp_send_key.size()), send_extension_ids,
          selected_crypto_suite, &rtcp_recv_key[0],
          static_cast<int>(rtcp_recv_key.size()), recv_extension_ids)) {
    SignalDtlsSrtpSetupFailure(this, /*rtcp=*/true);
    RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
  }
}

bool DtlsSrtpTransport::ExtractParams(
    cricket::DtlsTransportInternal* dtls_transport,
    int* selected_crypto_suite,
    rtc::ZeroOnFreeBuffer<unsigned char>* send_key,
    rtc::ZeroOnFreeBuffer<unsigned char>* recv_key) {
  if (!dtls_transport || !dtls_transport->IsDtlsActive()) {
    return false;
  }

  if (!dtls_transport->GetSrtpCryptoSuite(selected_crypto_suite)) {
    RTC_LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite";
    return false;
  }

  RTC_LOG(LS_INFO) << "Extracting keys from transport: "
                   << dtls_transport->transport_name();

  int key_len;
  int salt_len;
  if (!rtc::GetSrtpKeyAndSaltLengths((*selected_crypto_suite), &key_len,
                                     &salt_len)) {
    RTC_LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite"
                      << selected_crypto_suite;
    return false;
  }

  // OK, we're now doing DTLS (RFC 5764)
  rtc::ZeroOnFreeBuffer<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);

  // RFC 5705 exporter using the RFC 5764 parameters
  if (!dtls_transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0,
                                            false, &dtls_buffer[0],
                                            dtls_buffer.size())) {
    RTC_LOG(LS_WARNING) << "DTLS-SRTP key export failed";
    RTC_NOTREACHED();  // This should never happen
    return false;
  }

  // Sync up the keys with the DTLS-SRTP interface
  rtc::ZeroOnFreeBuffer<unsigned char> client_write_key(key_len + salt_len);
  rtc::ZeroOnFreeBuffer<unsigned char> server_write_key(key_len + salt_len);
  size_t offset = 0;
  memcpy(&client_write_key[0], &dtls_buffer[offset], key_len);
  offset += key_len;
  memcpy(&server_write_key[0], &dtls_buffer[offset], key_len);
  offset += key_len;
  memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len);
  offset += salt_len;
  memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len);

  rtc::SSLRole role;
  if (!dtls_transport->GetDtlsRole(&role)) {
    RTC_LOG(LS_WARNING) << "Failed to get the DTLS role.";
    return false;
  }

  if (role == rtc::SSL_SERVER) {
    *send_key = std::move(server_write_key);
    *recv_key = std::move(client_write_key);
  } else {
    *send_key = std::move(client_write_key);
    *recv_key = std::move(server_write_key);
  }
  return true;
}

void DtlsSrtpTransport::SetDtlsTransport(
    cricket::DtlsTransportInternal* new_dtls_transport,
    cricket::DtlsTransportInternal** old_dtls_transport) {
  if (*old_dtls_transport == new_dtls_transport) {
    return;
  }

  if (*old_dtls_transport) {
    (*old_dtls_transport)->SignalDtlsState.disconnect(this);
  }

  *old_dtls_transport = new_dtls_transport;

  if (new_dtls_transport) {
    new_dtls_transport->SignalDtlsState.connect(
        this, &DtlsSrtpTransport::OnDtlsState);
  }
}

void DtlsSrtpTransport::SetRtpDtlsTransport(
    cricket::DtlsTransportInternal* rtp_dtls_transport) {
  SetDtlsTransport(rtp_dtls_transport, &rtp_dtls_transport_);
}

void DtlsSrtpTransport::SetRtcpDtlsTransport(
    cricket::DtlsTransportInternal* rtcp_dtls_transport) {
  SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
}

void DtlsSrtpTransport::UpdateWritableStateAndMaybeSetupDtlsSrtp() {
  bool writable = IsDtlsWritable();
  SetWritable(writable);
  if (writable) {
    MaybeSetupDtlsSrtp();
  }
}

void DtlsSrtpTransport::SetWritable(bool writable) {
  // Only fire the signal if the writable state changes.
  if (writable_ != writable) {
    writable_ = writable;
    SignalWritableState(writable_);
  }
}

void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
                                    cricket::DtlsTransportState state) {
  RTC_DCHECK(transport == rtp_dtls_transport_ ||
             transport == rtcp_dtls_transport_);

  if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
    srtp_transport_->ResetParams();
    return;
  }

  MaybeSetupDtlsSrtp();
}

void DtlsSrtpTransport::OnWritableState(bool writable) {
  SetWritable(writable);
  if (writable) {
    MaybeSetupDtlsSrtp();
  }
}

void DtlsSrtpTransport::OnSentPacket(const rtc::SentPacket& sent_packet) {
  SignalSentPacket(sent_packet);
}

void DtlsSrtpTransport::OnPacketReceived(bool rtcp,
                                         rtc::CopyOnWriteBuffer* packet,
                                         const rtc::PacketTime& packet_time) {
  SignalPacketReceived(rtcp, packet, packet_time);
}

void DtlsSrtpTransport::OnReadyToSend(bool ready) {
  SignalReadyToSend(ready);
}

void DtlsSrtpTransport::OnNetworkRouteChanged(
    rtc::Optional<rtc::NetworkRoute> network_route) {
  SignalNetworkRouteChanged(network_route);
}

}  // namespace webrtc
