tor-browser

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

SrtpFlow.cpp (7443B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 // Original author: ekr@rtfm.com
      6 
      7 #include "SrtpFlow.h"
      8 
      9 #include "logging.h"
     10 #include "mozilla/RefPtr.h"
     11 #include "srtp.h"
     12 #include "transportlayerdtls.h"
     13 
     14 using namespace mozilla;
     15 
     16 namespace mozilla {
     17 
     18 MOZ_MTLOG_MODULE("mtransport")
     19 bool SrtpFlow::initialized;  // Static
     20 
     21 SrtpFlow::~SrtpFlow() {
     22  if (session_) {
     23    srtp_dealloc(session_);
     24  }
     25 }
     26 
     27 unsigned int SrtpFlow::KeySize(int cipher_suite) {
     28  srtp_profile_t profile = static_cast<srtp_profile_t>(cipher_suite);
     29  return srtp_profile_get_master_key_length(profile);
     30 }
     31 
     32 unsigned int SrtpFlow::SaltSize(int cipher_suite) {
     33  srtp_profile_t profile = static_cast<srtp_profile_t>(cipher_suite);
     34  return srtp_profile_get_master_salt_length(profile);
     35 }
     36 
     37 RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite, bool inbound,
     38                                  const void* key, size_t key_len) {
     39  nsresult res = Init();
     40  if (!NS_SUCCEEDED(res)) return nullptr;
     41 
     42  RefPtr<SrtpFlow> flow = new SrtpFlow();
     43 
     44  if (!key) {
     45    MOZ_MTLOG(ML_ERROR, "Null SRTP key specified");
     46    return nullptr;
     47  }
     48 
     49  if ((key_len > SRTP_MAX_KEY_LENGTH) || (key_len < SRTP_MIN_KEY_LENGTH)) {
     50    MOZ_ASSERT(false, "Invalid SRTP key length");
     51    return nullptr;
     52  }
     53 
     54  srtp_policy_t policy;
     55  memset(&policy, 0, sizeof(srtp_policy_t));
     56 
     57  // Note that we set the same cipher suite for RTP and RTCP
     58  // since any flow can only have one cipher suite with DTLS-SRTP
     59  switch (cipher_suite) {
     60    case kDtlsSrtpAeadAes256Gcm:
     61      MOZ_MTLOG(ML_DEBUG, "Setting SRTP cipher suite SRTP_AEAD_AES_256_GCM");
     62      srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
     63      srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp);
     64      break;
     65    case kDtlsSrtpAeadAes128Gcm:
     66      MOZ_MTLOG(ML_DEBUG, "Setting SRTP cipher suite SRTP_AEAD_AES_128_GCM");
     67      srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
     68      srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
     69      break;
     70    case kDtlsSrtpAes128CmHmacSha1_80:
     71      MOZ_MTLOG(ML_DEBUG,
     72                "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_80");
     73      srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
     74      srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
     75      break;
     76    case kDtlsSrtpAes128CmHmacSha1_32:
     77      MOZ_MTLOG(ML_DEBUG,
     78                "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_32");
     79      srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
     80      srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(
     81          &policy.rtcp);  // 80-bit per RFC 5764
     82      break;              // S 4.1.2.
     83    default:
     84      MOZ_MTLOG(ML_ERROR, "Request to set unknown SRTP cipher suite");
     85      return nullptr;
     86  }
     87  // This key is copied into the srtp_t object, so we don't
     88  // need to keep it.
     89  policy.key =
     90      const_cast<unsigned char*>(static_cast<const unsigned char*>(key));
     91  policy.ssrc.type = inbound ? ssrc_any_inbound : ssrc_any_outbound;
     92  policy.ssrc.value = 0;
     93  policy.window_size =
     94      1024;  // Use the Chrome value.  Needs to be revisited.  Default is 128
     95  policy.allow_repeat_tx = 1;  // Use Chrome value; needed for NACK mode to work
     96  policy.next = nullptr;
     97 
     98  // Now make the session
     99  srtp_err_status_t r = srtp_create(&flow->session_, &policy);
    100  if (r != srtp_err_status_ok) {
    101    MOZ_MTLOG(ML_ERROR, "Error creating srtp session");
    102    return nullptr;
    103  }
    104 
    105  return flow;
    106 }
    107 
    108 nsresult SrtpFlow::CheckInputs(bool protect, void* in, int in_len, int max_len,
    109                               int* out_len) {
    110  MOZ_ASSERT(in);
    111  if (!in) {
    112    MOZ_MTLOG(ML_ERROR, "NULL input value");
    113    return NS_ERROR_NULL_POINTER;
    114  }
    115 
    116  if (in_len < 0) {
    117    MOZ_MTLOG(ML_ERROR, "Input length is negative");
    118    return NS_ERROR_ILLEGAL_VALUE;
    119  }
    120 
    121  if (max_len < 0) {
    122    MOZ_MTLOG(ML_ERROR, "Max output length is negative");
    123    return NS_ERROR_ILLEGAL_VALUE;
    124  }
    125 
    126  if (protect) {
    127    if ((max_len < SRTP_MAX_EXPANSION) ||
    128        ((max_len - SRTP_MAX_EXPANSION) < in_len)) {
    129      MOZ_MTLOG(ML_ERROR, "Output too short");
    130      return NS_ERROR_ILLEGAL_VALUE;
    131    }
    132  } else {
    133    if (in_len > max_len) {
    134      MOZ_MTLOG(ML_ERROR, "Output too short");
    135      return NS_ERROR_ILLEGAL_VALUE;
    136    }
    137  }
    138 
    139  return NS_OK;
    140 }
    141 
    142 nsresult SrtpFlow::ProtectRtp(void* in, int in_len, int max_len, int* out_len) {
    143  nsresult res = CheckInputs(true, in, in_len, max_len, out_len);
    144  if (NS_FAILED(res)) return res;
    145 
    146  int len = in_len;
    147  srtp_err_status_t r = srtp_protect(session_, in, &len);
    148 
    149  if (r != srtp_err_status_ok) {
    150    MOZ_MTLOG(ML_ERROR, "Error protecting SRTP packet");
    151    return NS_ERROR_FAILURE;
    152  }
    153 
    154  MOZ_ASSERT(len <= max_len);
    155  *out_len = len;
    156 
    157  MOZ_MTLOG(ML_DEBUG,
    158            "Successfully protected an SRTP packet of len " << *out_len);
    159 
    160  return NS_OK;
    161 }
    162 
    163 nsresult SrtpFlow::UnprotectRtp(void* in, int in_len, int max_len,
    164                                int* out_len) {
    165  nsresult res = CheckInputs(false, in, in_len, max_len, out_len);
    166  if (NS_FAILED(res)) return res;
    167 
    168  int len = in_len;
    169  srtp_err_status_t r = srtp_unprotect(session_, in, &len);
    170 
    171  if (r != srtp_err_status_ok) {
    172    MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTP packet error=" << (int)r);
    173    return NS_ERROR_FAILURE;
    174  }
    175 
    176  MOZ_ASSERT(len <= max_len);
    177  *out_len = len;
    178 
    179  MOZ_MTLOG(ML_DEBUG,
    180            "Successfully unprotected an SRTP packet of len " << *out_len);
    181 
    182  return NS_OK;
    183 }
    184 
    185 nsresult SrtpFlow::ProtectRtcp(void* in, int in_len, int max_len,
    186                               int* out_len) {
    187  nsresult res = CheckInputs(true, in, in_len, max_len, out_len);
    188  if (NS_FAILED(res)) return res;
    189 
    190  int len = in_len;
    191  srtp_err_status_t r = srtp_protect_rtcp(session_, in, &len);
    192 
    193  if (r != srtp_err_status_ok) {
    194    MOZ_MTLOG(ML_ERROR, "Error protecting SRTCP packet");
    195    return NS_ERROR_FAILURE;
    196  }
    197 
    198  MOZ_ASSERT(len <= max_len);
    199  *out_len = len;
    200 
    201  MOZ_MTLOG(ML_DEBUG,
    202            "Successfully protected an SRTCP packet of len " << *out_len);
    203 
    204  return NS_OK;
    205 }
    206 
    207 nsresult SrtpFlow::UnprotectRtcp(void* in, int in_len, int max_len,
    208                                 int* out_len) {
    209  nsresult res = CheckInputs(false, in, in_len, max_len, out_len);
    210  if (NS_FAILED(res)) return res;
    211 
    212  int len = in_len;
    213  srtp_err_status_t r = srtp_unprotect_rtcp(session_, in, &len);
    214 
    215  if (r != srtp_err_status_ok) {
    216    MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTCP packet error=" << (int)r);
    217    return NS_ERROR_FAILURE;
    218  }
    219 
    220  MOZ_ASSERT(len <= max_len);
    221  *out_len = len;
    222 
    223  MOZ_MTLOG(ML_DEBUG,
    224            "Successfully unprotected an SRTCP packet of len " << *out_len);
    225 
    226  return NS_OK;
    227 }
    228 
    229 // Statics
    230 void SrtpFlow::srtp_event_handler(srtp_event_data_t* data) {
    231  // TODO(ekr@rtfm.com): Implement this
    232  MOZ_CRASH();
    233 }
    234 
    235 nsresult SrtpFlow::Init() {
    236  if (!initialized) {
    237    srtp_err_status_t r = srtp_init();
    238    if (r != srtp_err_status_ok) {
    239      MOZ_MTLOG(ML_ERROR, "Could not initialize SRTP");
    240      MOZ_ASSERT(PR_FALSE);
    241      return NS_ERROR_FAILURE;
    242    }
    243 
    244    r = srtp_install_event_handler(&SrtpFlow::srtp_event_handler);
    245    if (r != srtp_err_status_ok) {
    246      MOZ_MTLOG(ML_ERROR, "Could not install SRTP event handler");
    247      MOZ_ASSERT(PR_FALSE);
    248      return NS_ERROR_FAILURE;
    249    }
    250 
    251    initialized = true;
    252  }
    253 
    254  return NS_OK;
    255 }
    256 
    257 }  // namespace mozilla