Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/media/mtransport/transportlayersrtp.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "transportlayerdtls.h"
11
12
#include "logging.h"
13
#include "nsError.h"
14
#include "mozilla/Assertions.h"
15
#include "transportlayerdtls.h"
16
#include "srtp.h"
17
#include "nsAutoPtr.h"
18
19
namespace mozilla {
20
21
MOZ_MTLOG_MODULE("mtransport")
22
23
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
24
25
TransportLayerSrtp::TransportLayerSrtp(TransportLayerDtls& dtls)
26
0
{
27
0
  // We need to connect to the dtls layer, not the ice layer, because even
28
0
  // though the packets that DTLS decrypts don't flow through us, we do base our
29
0
  // keying information on the keying information established by the DTLS layer.
30
0
  dtls.SignalStateChange.connect(this, &TransportLayerSrtp::StateChange);
31
0
32
0
  TL_SET_STATE(dtls.state());
33
0
}
34
35
void
36
TransportLayerSrtp::WasInserted()
37
0
{
38
0
  // Connect to the lower layers
39
0
  if (!Setup()) {
40
0
    TL_SET_STATE(TS_ERROR);
41
0
  }
42
0
}
43
44
bool
45
TransportLayerSrtp::Setup()
46
0
{
47
0
  CheckThread();
48
0
  if (!downward_) {
49
0
    MOZ_MTLOG(ML_ERROR, "SRTP layer with nothing below. This is useless");
50
0
    return false;
51
0
  }
52
0
53
0
  // downward_ is the TransportLayerIce
54
0
  downward_->SignalPacketReceived.connect(this, &TransportLayerSrtp::PacketReceived);
55
0
56
0
  return true;
57
0
}
58
59
static bool IsRtp(const unsigned char* data, size_t len)
60
0
{
61
0
  if (len < 2)
62
0
    return false;
63
0
64
0
  // Check if this is a RTCP packet. Logic based on the types listed in
65
0
  // media/webrtc/trunk/src/modules/rtp_rtcp/source/rtp_utility.cc
66
0
67
0
  // Anything outside this range is RTP.
68
0
  if ((data[1] < 192) || (data[1] > 207))
69
0
    return true;
70
0
71
0
  if (data[1] == 192) // FIR
72
0
    return false;
73
0
74
0
  if (data[1] == 193) // NACK, but could also be RTP. This makes us sad
75
0
    return true;      // but it's how webrtc.org behaves.
76
0
77
0
  if (data[1] == 194)
78
0
    return true;
79
0
80
0
  if (data[1] == 195) // IJ.
81
0
    return false;
82
0
83
0
  if ((data[1] > 195) && (data[1] < 200)) // the > 195 is redundant
84
0
    return true;
85
0
86
0
  if ((data[1] >= 200) && (data[1] <= 207)) // SR, RR, SDES, BYE,
87
0
    return false;                           // APP, RTPFB, PSFB, XR
88
0
89
0
  MOZ_ASSERT(false); // Not reached, belt and suspenders.
90
0
  return true;
91
0
}
92
93
TransportResult
94
TransportLayerSrtp::SendPacket(MediaPacket& packet)
95
0
{
96
0
  if (packet.len() < 4) {
97
0
    MOZ_ASSERT(false);
98
0
    return TE_ERROR;
99
0
  }
100
0
101
0
  MOZ_ASSERT(packet.capacity() - packet.len() >= SRTP_MAX_EXPANSION);
102
0
103
0
  int out_len;
104
0
  nsresult res;
105
0
  switch (packet.type()) {
106
0
    case MediaPacket::RTP:
107
0
      res = mSendSrtp->ProtectRtp(packet.data(), packet.len(), packet.capacity(), &out_len);
108
0
      break;
109
0
    case MediaPacket::RTCP:
110
0
      res = mSendSrtp->ProtectRtcp(packet.data(), packet.len(), packet.capacity(), &out_len);
111
0
      break;
112
0
    default:
113
0
      MOZ_CRASH("SRTP layer asked to send packet that is neither RTP or RTCP");
114
0
  }
115
0
116
0
  if (NS_FAILED(res)) {
117
0
    MOZ_MTLOG(ML_ERROR,
118
0
                "Error protecting "
119
0
                << (packet.type() == MediaPacket::RTP ? "RTP" : "RTCP")
120
0
                << " len=" << packet.len()
121
0
                << "[" << std::hex
122
0
                << packet.data()[0] << " "
123
0
                << packet.data()[1] << " "
124
0
                << packet.data()[2] << " "
125
0
                << packet.data()[3]
126
0
                << "]");
127
0
    return TE_ERROR;
128
0
  }
129
0
130
0
  size_t unencrypted_len = packet.len();
131
0
  packet.SetLength(out_len);
132
0
133
0
  TransportResult bytes = downward_->SendPacket(packet);
134
0
  if (bytes == out_len) {
135
0
    // Whole packet was written, but the encrypted length might be different.
136
0
    // Don't confuse the caller.
137
0
    return unencrypted_len;
138
0
  }
139
0
140
0
  if (bytes == TE_WOULDBLOCK) {
141
0
    return TE_WOULDBLOCK;
142
0
  }
143
0
144
0
  return TE_ERROR;
145
0
}
146
147
void
148
TransportLayerSrtp::StateChange(TransportLayer* layer, State state)
149
0
{
150
0
  if (state == TS_OPEN) {
151
0
    TransportLayerDtls* dtls = static_cast<TransportLayerDtls*>(layer);
152
0
    MOZ_ASSERT(dtls); // DTLS is mandatory
153
0
154
0
    uint16_t cipher_suite;
155
0
    nsresult res = dtls->GetSrtpCipher(&cipher_suite);
156
0
    if (NS_FAILED(res)) {
157
0
      MOZ_MTLOG(ML_ERROR, "Failed to negotiate DTLS-SRTP. This is an error");
158
0
      TL_SET_STATE(TS_ERROR);
159
0
      return;
160
0
    }
161
0
162
0
    unsigned int key_size = SrtpFlow::KeySize(cipher_suite);
163
0
    unsigned int salt_size = SrtpFlow::SaltSize(cipher_suite);
164
0
    unsigned int master_key_size = key_size + salt_size;
165
0
    MOZ_ASSERT(master_key_size <= SRTP_MAX_KEY_LENGTH);
166
0
167
0
    // SRTP Key Exporter as per RFC 5764 S 4.2
168
0
    unsigned char srtp_block[SRTP_MAX_KEY_LENGTH * 2];
169
0
    res = dtls->ExportKeyingMaterial(
170
0
      kDTLSExporterLabel, false, "", srtp_block, sizeof(srtp_block));
171
0
    if (NS_FAILED(res)) {
172
0
      MOZ_MTLOG(ML_ERROR, "Failed to compute DTLS-SRTP keys. This is an error");
173
0
      TL_SET_STATE(TS_ERROR);
174
0
      return;
175
0
    }
176
0
177
0
    // Slice and dice as per RFC 5764 S 4.2
178
0
    unsigned char client_write_key[SRTP_MAX_KEY_LENGTH];
179
0
    unsigned char server_write_key[SRTP_MAX_KEY_LENGTH];
180
0
    unsigned int offset = 0;
181
0
    memcpy(client_write_key, srtp_block + offset, key_size);
182
0
    offset += key_size;
183
0
    memcpy(server_write_key, srtp_block + offset, key_size);
184
0
    offset += key_size;
185
0
    memcpy(client_write_key + key_size, srtp_block + offset, salt_size);
186
0
    offset += salt_size;
187
0
    memcpy(server_write_key + key_size, srtp_block + offset, salt_size);
188
0
    MOZ_ASSERT((offset + salt_size) == (2 * master_key_size));
189
0
190
0
    unsigned char* write_key;
191
0
    unsigned char* read_key;
192
0
193
0
    if (dtls->role() == TransportLayerDtls::CLIENT) {
194
0
      write_key = client_write_key;
195
0
      read_key = server_write_key;
196
0
    } else {
197
0
      write_key = server_write_key;
198
0
      read_key = client_write_key;
199
0
    }
200
0
201
0
    MOZ_ASSERT(!mSendSrtp && !mRecvSrtp);
202
0
    mSendSrtp =
203
0
      SrtpFlow::Create(cipher_suite, false, write_key, master_key_size);
204
0
    mRecvSrtp =
205
0
      SrtpFlow::Create(cipher_suite, true, read_key, master_key_size);
206
0
    if (!mSendSrtp || !mRecvSrtp) {
207
0
      MOZ_MTLOG(ML_ERROR, "Couldn't create SRTP flow.");
208
0
      TL_SET_STATE(TS_ERROR);
209
0
      return;
210
0
    }
211
0
212
0
    MOZ_MTLOG(ML_INFO, "Created SRTP flow!");
213
0
  }
214
0
215
0
  TL_SET_STATE(state);
216
0
}
217
218
void
219
TransportLayerSrtp::PacketReceived(TransportLayer* layer, MediaPacket& packet)
220
0
{
221
0
  if (state() != TS_OPEN) {
222
0
    return;
223
0
  }
224
0
225
0
  if (!packet.data()) {
226
0
    // Something ate this, probably the DTLS layer
227
0
    return;
228
0
  }
229
0
230
0
  if (packet.len() < 4) {
231
0
    return;
232
0
  }
233
0
234
0
  // not RTP/RTCP per RFC 7983
235
0
  if (packet.data()[0] <= 127 || packet.data()[0] >= 192) {
236
0
    return;
237
0
  }
238
0
239
0
  // We want to keep the encrypted packet around for packet dumping
240
0
  packet.CopyDataToEncrypted();
241
0
  int outLen;
242
0
  nsresult res;
243
0
244
0
  if (IsRtp(packet.data(), packet.len())) {
245
0
    packet.SetType(MediaPacket::RTP);
246
0
    res = mRecvSrtp->UnprotectRtp(packet.data(), packet.len(), packet.len(), &outLen);
247
0
  } else {
248
0
    packet.SetType(MediaPacket::RTCP);
249
0
    res = mRecvSrtp->UnprotectRtcp(packet.data(), packet.len(), packet.len(), &outLen);
250
0
  }
251
0
252
0
  if (NS_SUCCEEDED(res)) {
253
0
    packet.SetLength(outLen);
254
0
    SignalPacketReceived(this, packet);
255
0
  } else {
256
0
    // TODO: What do we do wrt packet dumping here? Maybe signal an empty
257
0
    // packet? Signal the still-encrypted packet?
258
0
    MOZ_MTLOG(ML_ERROR,
259
0
                "Error unprotecting "
260
0
                << (packet.type() == MediaPacket::RTP ? "RTP" : "RTCP")
261
0
                << " len=" << packet.len()
262
0
                << "[" << std::hex
263
0
                << packet.data()[0] << " "
264
0
                << packet.data()[1] << " "
265
0
                << packet.data()[2] << " "
266
0
                << packet.data()[3]
267
0
                << "]");
268
0
  }
269
0
}
270
271
} // namespace mozilla
272
273