tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

transportlayersrtp.cpp (6979B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // Original author: ekr@rtfm.com
      8 
      9 #include "transportlayersrtp.h"
     10 
     11 #include "logging.h"
     12 #include "mozilla/Assertions.h"
     13 #include "nsError.h"
     14 #include "transportlayerdtls.h"
     15 
     16 namespace mozilla {
     17 
     18 MOZ_MTLOG_MODULE("mtransport")
     19 
     20 static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
     21 
     22 TransportLayerSrtp::TransportLayerSrtp(TransportLayerDtls& dtls) {
     23  // We need to connect to the dtls layer, not the ice layer, because even
     24  // though the packets that DTLS decrypts don't flow through us, we do base our
     25  // keying information on the keying information established by the DTLS layer.
     26  dtls.SignalStateChange.connect(this, &TransportLayerSrtp::StateChange);
     27 
     28  TL_SET_STATE(dtls.state());
     29 }
     30 
     31 void TransportLayerSrtp::WasInserted() {
     32  // Connect to the lower layers
     33  if (!Setup()) {
     34    TL_SET_STATE(TS_ERROR);
     35  }
     36 }
     37 
     38 bool TransportLayerSrtp::Setup() {
     39  CheckThread();
     40  if (!downward_) {
     41    MOZ_MTLOG(ML_ERROR, "SRTP layer with nothing below. This is useless");
     42    return false;
     43  }
     44 
     45  // downward_ is the TransportLayerIce
     46  downward_->SignalPacketReceived.connect(this,
     47                                          &TransportLayerSrtp::PacketReceived);
     48 
     49  return true;
     50 }
     51 
     52 TransportResult TransportLayerSrtp::SendPacket(MediaPacket& packet) {
     53  if (state() != TS_OPEN) {
     54    return TE_ERROR;
     55  }
     56 
     57  if (packet.len() < 4) {
     58    MOZ_ASSERT(false);
     59    return TE_ERROR;
     60  }
     61 
     62  MOZ_ASSERT(packet.capacity() - packet.len() >= SRTP_MAX_EXPANSION);
     63 
     64  int out_len;
     65  nsresult res;
     66  switch (packet.type()) {
     67    case MediaPacket::RTP:
     68      res = mSendSrtp->ProtectRtp(packet.data(), packet.len(),
     69                                  packet.capacity(), &out_len);
     70      packet.SetType(MediaPacket::SRTP);
     71      break;
     72    case MediaPacket::RTCP:
     73      res = mSendSrtp->ProtectRtcp(packet.data(), packet.len(),
     74                                   packet.capacity(), &out_len);
     75      packet.SetType(MediaPacket::SRTCP);
     76      break;
     77    default:
     78      MOZ_CRASH("SRTP layer asked to send packet that is neither RTP or RTCP");
     79  }
     80 
     81  if (NS_FAILED(res)) {
     82    MOZ_MTLOG(ML_ERROR,
     83              "Error protecting "
     84                  << (packet.type() == MediaPacket::RTP ? "RTP" : "RTCP")
     85                  << " len=" << packet.len() << "[" << std::hex
     86                  << packet.data()[0] << " " << packet.data()[1] << " "
     87                  << packet.data()[2] << " " << packet.data()[3] << "]");
     88    return TE_ERROR;
     89  }
     90 
     91  size_t unencrypted_len = packet.len();
     92  packet.SetLength(out_len);
     93 
     94  TransportResult bytes = downward_->SendPacket(packet);
     95  if (bytes == out_len) {
     96    // Whole packet was written, but the encrypted length might be different.
     97    // Don't confuse the caller.
     98    return unencrypted_len;
     99  }
    100 
    101  if (bytes == TE_WOULDBLOCK) {
    102    return TE_WOULDBLOCK;
    103  }
    104 
    105  return TE_ERROR;
    106 }
    107 
    108 void TransportLayerSrtp::StateChange(TransportLayer* layer, State state) {
    109  if (state == TS_OPEN && !mSendSrtp) {
    110    TransportLayerDtls* dtls = static_cast<TransportLayerDtls*>(layer);
    111    MOZ_ASSERT(dtls);  // DTLS is mandatory
    112 
    113    uint16_t cipher_suite;
    114    nsresult res = dtls->GetSrtpCipher(&cipher_suite);
    115    if (NS_FAILED(res)) {
    116      MOZ_MTLOG(ML_DEBUG, "DTLS-SRTP disabled");
    117      TL_SET_STATE(TS_ERROR);
    118      return;
    119    }
    120 
    121    unsigned int key_size = SrtpFlow::KeySize(cipher_suite);
    122    unsigned int salt_size = SrtpFlow::SaltSize(cipher_suite);
    123    unsigned int master_key_size = key_size + salt_size;
    124    MOZ_ASSERT(master_key_size <= SRTP_MAX_KEY_LENGTH);
    125 
    126    // SRTP Key Exporter as per RFC 5764 S 4.2
    127    unsigned char srtp_block[master_key_size * 2];
    128    res = dtls->ExportKeyingMaterial(kDTLSExporterLabel, false, "", srtp_block,
    129                                     sizeof(srtp_block));
    130    if (NS_FAILED(res)) {
    131      MOZ_MTLOG(ML_ERROR, "Failed to compute DTLS-SRTP keys. This is an error");
    132      TL_SET_STATE(TS_ERROR);
    133      return;
    134    }
    135 
    136    // Slice and dice as per RFC 5764 S 4.2
    137    unsigned char client_write_key[master_key_size];
    138    unsigned char server_write_key[master_key_size];
    139    unsigned int offset = 0;
    140    memcpy(client_write_key, srtp_block + offset, key_size);
    141    offset += key_size;
    142    memcpy(server_write_key, srtp_block + offset, key_size);
    143    offset += key_size;
    144    memcpy(client_write_key + key_size, srtp_block + offset, salt_size);
    145    offset += salt_size;
    146    memcpy(server_write_key + key_size, srtp_block + offset, salt_size);
    147    MOZ_ASSERT((offset + salt_size) == (2 * master_key_size));
    148 
    149    unsigned char* write_key;
    150    unsigned char* read_key;
    151 
    152    if (dtls->role() == TransportLayerDtls::CLIENT) {
    153      write_key = client_write_key;
    154      read_key = server_write_key;
    155    } else {
    156      write_key = server_write_key;
    157      read_key = client_write_key;
    158    }
    159 
    160    MOZ_ASSERT(!mSendSrtp && !mRecvSrtp);
    161    mSendSrtp =
    162        SrtpFlow::Create(cipher_suite, false, write_key, master_key_size);
    163    mRecvSrtp = SrtpFlow::Create(cipher_suite, true, read_key, master_key_size);
    164    if (!mSendSrtp || !mRecvSrtp) {
    165      MOZ_MTLOG(ML_ERROR, "Couldn't create SRTP flow.");
    166      TL_SET_STATE(TS_ERROR);
    167      return;
    168    }
    169 
    170    MOZ_MTLOG(ML_INFO, "Created SRTP flow!");
    171  }
    172 
    173  TL_SET_STATE(state);
    174 }
    175 
    176 void TransportLayerSrtp::PacketReceived(TransportLayer* layer,
    177                                        MediaPacket& packet) {
    178  if (state() != TS_OPEN) {
    179    return;
    180  }
    181 
    182  if (!packet.data()) {
    183    // Something ate this, probably the DTLS layer
    184    return;
    185  }
    186 
    187  if (packet.type() != MediaPacket::SRTP &&
    188      packet.type() != MediaPacket::SRTCP) {
    189    return;
    190  }
    191 
    192  // We want to keep the encrypted packet around for packet dumping
    193  packet.CopyDataToEncrypted();
    194  int outLen;
    195  nsresult res;
    196 
    197  if (packet.type() == MediaPacket::SRTP) {
    198    packet.SetType(MediaPacket::RTP);
    199    res = mRecvSrtp->UnprotectRtp(packet.data(), packet.len(), packet.len(),
    200                                  &outLen);
    201  } else {
    202    packet.SetType(MediaPacket::RTCP);
    203    res = mRecvSrtp->UnprotectRtcp(packet.data(), packet.len(), packet.len(),
    204                                   &outLen);
    205  }
    206 
    207  if (NS_SUCCEEDED(res)) {
    208    packet.SetLength(outLen);
    209    SignalPacketReceived(this, packet);
    210  } else {
    211    // TODO: What do we do wrt packet dumping here? Maybe signal an empty
    212    // packet? Signal the still-encrypted packet?
    213    MOZ_MTLOG(ML_ERROR,
    214              "Error unprotecting "
    215                  << (packet.type() == MediaPacket::RTP ? "RTP" : "RTCP")
    216                  << " len=" << packet.len() << "[" << std::hex
    217                  << packet.data()[0] << " " << packet.data()[1] << " "
    218                  << packet.data()[2] << " " << packet.data()[3] << "]");
    219  }
    220 }
    221 
    222 }  // namespace mozilla