Coverage Report

Created: 2018-09-25 14:53

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