• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "pc/srtp_session.h"
12 
13 #include "absl/base/attributes.h"
14 #include "media/base/rtp_utils.h"
15 #include "pc/external_hmac.h"
16 #include "rtc_base/logging.h"
17 #include "rtc_base/ssl_stream_adapter.h"
18 #include "system_wrappers/include/metrics.h"
19 #include "third_party/libsrtp/include/srtp.h"
20 #include "third_party/libsrtp/include/srtp_priv.h"
21 
22 namespace cricket {
23 
24 // One more than the maximum libsrtp error code. Required by
25 // RTC_HISTOGRAM_ENUMERATION. Keep this in sync with srtp_error_status_t defined
26 // in srtp.h.
27 constexpr int kSrtpErrorCodeBoundary = 28;
28 
SrtpSession()29 SrtpSession::SrtpSession() {}
30 
~SrtpSession()31 SrtpSession::~SrtpSession() {
32   if (session_) {
33     srtp_set_user_data(session_, nullptr);
34     srtp_dealloc(session_);
35   }
36   if (inited_) {
37     DecrementLibsrtpUsageCountAndMaybeDeinit();
38   }
39 }
40 
SetSend(int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)41 bool SrtpSession::SetSend(int cs,
42                           const uint8_t* key,
43                           size_t len,
44                           const std::vector<int>& extension_ids) {
45   return SetKey(ssrc_any_outbound, cs, key, len, extension_ids);
46 }
47 
UpdateSend(int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)48 bool SrtpSession::UpdateSend(int cs,
49                              const uint8_t* key,
50                              size_t len,
51                              const std::vector<int>& extension_ids) {
52   return UpdateKey(ssrc_any_outbound, cs, key, len, extension_ids);
53 }
54 
SetRecv(int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)55 bool SrtpSession::SetRecv(int cs,
56                           const uint8_t* key,
57                           size_t len,
58                           const std::vector<int>& extension_ids) {
59   return SetKey(ssrc_any_inbound, cs, key, len, extension_ids);
60 }
61 
UpdateRecv(int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)62 bool SrtpSession::UpdateRecv(int cs,
63                              const uint8_t* key,
64                              size_t len,
65                              const std::vector<int>& extension_ids) {
66   return UpdateKey(ssrc_any_inbound, cs, key, len, extension_ids);
67 }
68 
ProtectRtp(void * p,int in_len,int max_len,int * out_len)69 bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
70   RTC_DCHECK(thread_checker_.IsCurrent());
71   if (!session_) {
72     RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session";
73     return false;
74   }
75 
76   int need_len = in_len + rtp_auth_tag_len_;  // NOLINT
77   if (max_len < need_len) {
78     RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length "
79                         << max_len << " is less than the needed " << need_len;
80     return false;
81   }
82 
83   *out_len = in_len;
84   int err = srtp_protect(session_, p, out_len);
85   int seq_num;
86   GetRtpSeqNum(p, in_len, &seq_num);
87   if (err != srtp_err_status_ok) {
88     RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet, seqnum=" << seq_num
89                         << ", err=" << err
90                         << ", last seqnum=" << last_send_seq_num_;
91     return false;
92   }
93   last_send_seq_num_ = seq_num;
94   return true;
95 }
96 
ProtectRtp(void * p,int in_len,int max_len,int * out_len,int64_t * index)97 bool SrtpSession::ProtectRtp(void* p,
98                              int in_len,
99                              int max_len,
100                              int* out_len,
101                              int64_t* index) {
102   if (!ProtectRtp(p, in_len, max_len, out_len)) {
103     return false;
104   }
105   return (index) ? GetSendStreamPacketIndex(p, in_len, index) : true;
106 }
107 
ProtectRtcp(void * p,int in_len,int max_len,int * out_len)108 bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
109   RTC_DCHECK(thread_checker_.IsCurrent());
110   if (!session_) {
111     RTC_LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session";
112     return false;
113   }
114 
115   int need_len = in_len + sizeof(uint32_t) + rtcp_auth_tag_len_;  // NOLINT
116   if (max_len < need_len) {
117     RTC_LOG(LS_WARNING) << "Failed to protect SRTCP packet: The buffer length "
118                         << max_len << " is less than the needed " << need_len;
119     return false;
120   }
121 
122   *out_len = in_len;
123   int err = srtp_protect_rtcp(session_, p, out_len);
124   if (err != srtp_err_status_ok) {
125     RTC_LOG(LS_WARNING) << "Failed to protect SRTCP packet, err=" << err;
126     return false;
127   }
128   return true;
129 }
130 
UnprotectRtp(void * p,int in_len,int * out_len)131 bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) {
132   RTC_DCHECK(thread_checker_.IsCurrent());
133   if (!session_) {
134     RTC_LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session";
135     return false;
136   }
137 
138   *out_len = in_len;
139   int err = srtp_unprotect(session_, p, out_len);
140   if (err != srtp_err_status_ok) {
141     // Limit the error logging to avoid excessive logs when there are lots of
142     // bad packets.
143     const int kFailureLogThrottleCount = 100;
144     if (decryption_failure_count_ % kFailureLogThrottleCount == 0) {
145       RTC_LOG(LS_WARNING) << "Failed to unprotect SRTP packet, err=" << err
146                           << ", previous failure count: "
147                           << decryption_failure_count_;
148     }
149     ++decryption_failure_count_;
150     RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SrtpUnprotectError",
151                               static_cast<int>(err), kSrtpErrorCodeBoundary);
152     return false;
153   }
154   return true;
155 }
156 
UnprotectRtcp(void * p,int in_len,int * out_len)157 bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
158   RTC_DCHECK(thread_checker_.IsCurrent());
159   if (!session_) {
160     RTC_LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session";
161     return false;
162   }
163 
164   *out_len = in_len;
165   int err = srtp_unprotect_rtcp(session_, p, out_len);
166   if (err != srtp_err_status_ok) {
167     RTC_LOG(LS_WARNING) << "Failed to unprotect SRTCP packet, err=" << err;
168     RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SrtcpUnprotectError",
169                               static_cast<int>(err), kSrtpErrorCodeBoundary);
170     return false;
171   }
172   return true;
173 }
174 
GetRtpAuthParams(uint8_t ** key,int * key_len,int * tag_len)175 bool SrtpSession::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) {
176   RTC_DCHECK(thread_checker_.IsCurrent());
177   RTC_DCHECK(IsExternalAuthActive());
178   if (!IsExternalAuthActive()) {
179     return false;
180   }
181 
182   ExternalHmacContext* external_hmac = nullptr;
183   // stream_template will be the reference context for other streams.
184   // Let's use it for getting the keys.
185   srtp_stream_ctx_t* srtp_context = session_->stream_template;
186   if (srtp_context && srtp_context->session_keys &&
187       srtp_context->session_keys->rtp_auth) {
188     external_hmac = reinterpret_cast<ExternalHmacContext*>(
189         srtp_context->session_keys->rtp_auth->state);
190   }
191 
192   if (!external_hmac) {
193     RTC_LOG(LS_ERROR) << "Failed to get auth keys from libsrtp!.";
194     return false;
195   }
196 
197   *key = external_hmac->key;
198   *key_len = external_hmac->key_length;
199   *tag_len = rtp_auth_tag_len_;
200   return true;
201 }
202 
GetSrtpOverhead() const203 int SrtpSession::GetSrtpOverhead() const {
204   return rtp_auth_tag_len_;
205 }
206 
EnableExternalAuth()207 void SrtpSession::EnableExternalAuth() {
208   RTC_DCHECK(!session_);
209   external_auth_enabled_ = true;
210 }
211 
IsExternalAuthEnabled() const212 bool SrtpSession::IsExternalAuthEnabled() const {
213   return external_auth_enabled_;
214 }
215 
IsExternalAuthActive() const216 bool SrtpSession::IsExternalAuthActive() const {
217   return external_auth_active_;
218 }
219 
GetSendStreamPacketIndex(void * p,int in_len,int64_t * index)220 bool SrtpSession::GetSendStreamPacketIndex(void* p,
221                                            int in_len,
222                                            int64_t* index) {
223   RTC_DCHECK(thread_checker_.IsCurrent());
224   srtp_hdr_t* hdr = reinterpret_cast<srtp_hdr_t*>(p);
225   srtp_stream_ctx_t* stream = srtp_get_stream(session_, hdr->ssrc);
226   if (!stream) {
227     return false;
228   }
229 
230   // Shift packet index, put into network byte order
231   *index = static_cast<int64_t>(rtc::NetworkToHost64(
232       srtp_rdbx_get_packet_index(&stream->rtp_rdbx) << 16));
233   return true;
234 }
235 
DoSetKey(int type,int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)236 bool SrtpSession::DoSetKey(int type,
237                            int cs,
238                            const uint8_t* key,
239                            size_t len,
240                            const std::vector<int>& extension_ids) {
241   RTC_DCHECK(thread_checker_.IsCurrent());
242 
243   srtp_policy_t policy;
244   memset(&policy, 0, sizeof(policy));
245   if (cs == rtc::SRTP_AES128_CM_SHA1_80) {
246     srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
247     srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
248   } else if (cs == rtc::SRTP_AES128_CM_SHA1_32) {
249     // RTP HMAC is shortened to 32 bits, but RTCP remains 80 bits.
250     srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
251     srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
252   } else if (cs == rtc::SRTP_AEAD_AES_128_GCM) {
253     srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
254     srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
255   } else if (cs == rtc::SRTP_AEAD_AES_256_GCM) {
256     srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
257     srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp);
258   } else {
259     RTC_LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create")
260                         << " SRTP session: unsupported cipher_suite " << cs;
261     return false;
262   }
263 
264   int expected_key_len;
265   int expected_salt_len;
266   if (!rtc::GetSrtpKeyAndSaltLengths(cs, &expected_key_len,
267                                      &expected_salt_len)) {
268     // This should never happen.
269     RTC_NOTREACHED();
270     RTC_LOG(LS_WARNING)
271         << "Failed to " << (session_ ? "update" : "create")
272         << " SRTP session: unsupported cipher_suite without length information"
273         << cs;
274     return false;
275   }
276 
277   if (!key ||
278       len != static_cast<size_t>(expected_key_len + expected_salt_len)) {
279     RTC_LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create")
280                         << " SRTP session: invalid key";
281     return false;
282   }
283 
284   policy.ssrc.type = static_cast<srtp_ssrc_type_t>(type);
285   policy.ssrc.value = 0;
286   policy.key = const_cast<uint8_t*>(key);
287   // TODO(astor) parse window size from WSH session-param
288   policy.window_size = 1024;
289   policy.allow_repeat_tx = 1;
290   // If external authentication option is enabled, supply custom auth module
291   // id EXTERNAL_HMAC_SHA1 in the policy structure.
292   // We want to set this option only for rtp packets.
293   // By default policy structure is initialized to HMAC_SHA1.
294   // Enable external HMAC authentication only for outgoing streams and only
295   // for cipher suites that support it (i.e. only non-GCM cipher suites).
296   if (type == ssrc_any_outbound && IsExternalAuthEnabled() &&
297       !rtc::IsGcmCryptoSuite(cs)) {
298     policy.rtp.auth_type = EXTERNAL_HMAC_SHA1;
299   }
300   if (!extension_ids.empty()) {
301     policy.enc_xtn_hdr = const_cast<int*>(&extension_ids[0]);
302     policy.enc_xtn_hdr_count = static_cast<int>(extension_ids.size());
303   }
304   policy.next = nullptr;
305 
306   if (!session_) {
307     int err = srtp_create(&session_, &policy);
308     if (err != srtp_err_status_ok) {
309       session_ = nullptr;
310       RTC_LOG(LS_ERROR) << "Failed to create SRTP session, err=" << err;
311       return false;
312     }
313     srtp_set_user_data(session_, this);
314   } else {
315     int err = srtp_update(session_, &policy);
316     if (err != srtp_err_status_ok) {
317       RTC_LOG(LS_ERROR) << "Failed to update SRTP session, err=" << err;
318       return false;
319     }
320   }
321 
322   rtp_auth_tag_len_ = policy.rtp.auth_tag_len;
323   rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len;
324   external_auth_active_ = (policy.rtp.auth_type == EXTERNAL_HMAC_SHA1);
325   return true;
326 }
327 
SetKey(int type,int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)328 bool SrtpSession::SetKey(int type,
329                          int cs,
330                          const uint8_t* key,
331                          size_t len,
332                          const std::vector<int>& extension_ids) {
333   RTC_DCHECK(thread_checker_.IsCurrent());
334   if (session_) {
335     RTC_LOG(LS_ERROR) << "Failed to create SRTP session: "
336                          "SRTP session already created";
337     return false;
338   }
339 
340   // This is the first time we need to actually interact with libsrtp, so
341   // initialize it if needed.
342   if (IncrementLibsrtpUsageCountAndMaybeInit()) {
343     inited_ = true;
344   } else {
345     return false;
346   }
347 
348   return DoSetKey(type, cs, key, len, extension_ids);
349 }
350 
UpdateKey(int type,int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)351 bool SrtpSession::UpdateKey(int type,
352                             int cs,
353                             const uint8_t* key,
354                             size_t len,
355                             const std::vector<int>& extension_ids) {
356   RTC_DCHECK(thread_checker_.IsCurrent());
357   if (!session_) {
358     RTC_LOG(LS_ERROR) << "Failed to update non-existing SRTP session";
359     return false;
360   }
361 
362   return DoSetKey(type, cs, key, len, extension_ids);
363 }
364 
365 ABSL_CONST_INIT int g_libsrtp_usage_count = 0;
366 ABSL_CONST_INIT webrtc::GlobalMutex g_libsrtp_lock(absl::kConstInit);
367 
ProhibitLibsrtpInitialization()368 void ProhibitLibsrtpInitialization() {
369   webrtc::GlobalMutexLock ls(&g_libsrtp_lock);
370   ++g_libsrtp_usage_count;
371 }
372 
373 // static
IncrementLibsrtpUsageCountAndMaybeInit()374 bool SrtpSession::IncrementLibsrtpUsageCountAndMaybeInit() {
375   webrtc::GlobalMutexLock ls(&g_libsrtp_lock);
376 
377   RTC_DCHECK_GE(g_libsrtp_usage_count, 0);
378   if (g_libsrtp_usage_count == 0) {
379     int err;
380     err = srtp_init();
381     if (err != srtp_err_status_ok) {
382       RTC_LOG(LS_ERROR) << "Failed to init SRTP, err=" << err;
383       return false;
384     }
385 
386     err = srtp_install_event_handler(&SrtpSession::HandleEventThunk);
387     if (err != srtp_err_status_ok) {
388       RTC_LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err;
389       return false;
390     }
391 
392     err = external_crypto_init();
393     if (err != srtp_err_status_ok) {
394       RTC_LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err;
395       return false;
396     }
397   }
398   ++g_libsrtp_usage_count;
399   return true;
400 }
401 
402 // static
DecrementLibsrtpUsageCountAndMaybeDeinit()403 void SrtpSession::DecrementLibsrtpUsageCountAndMaybeDeinit() {
404   webrtc::GlobalMutexLock ls(&g_libsrtp_lock);
405 
406   RTC_DCHECK_GE(g_libsrtp_usage_count, 1);
407   if (--g_libsrtp_usage_count == 0) {
408     int err = srtp_shutdown();
409     if (err) {
410       RTC_LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err;
411     }
412   }
413 }
414 
HandleEvent(const srtp_event_data_t * ev)415 void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
416   RTC_DCHECK(thread_checker_.IsCurrent());
417   switch (ev->event) {
418     case event_ssrc_collision:
419       RTC_LOG(LS_INFO) << "SRTP event: SSRC collision";
420       break;
421     case event_key_soft_limit:
422       RTC_LOG(LS_INFO) << "SRTP event: reached soft key usage limit";
423       break;
424     case event_key_hard_limit:
425       RTC_LOG(LS_INFO) << "SRTP event: reached hard key usage limit";
426       break;
427     case event_packet_index_limit:
428       RTC_LOG(LS_INFO)
429           << "SRTP event: reached hard packet limit (2^48 packets)";
430       break;
431     default:
432       RTC_LOG(LS_INFO) << "SRTP event: unknown " << ev->event;
433       break;
434   }
435 }
436 
HandleEventThunk(srtp_event_data_t * ev)437 void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) {
438   // Callback will be executed from same thread that calls the "srtp_protect"
439   // and "srtp_unprotect" functions.
440   SrtpSession* session =
441       static_cast<SrtpSession*>(srtp_get_user_data(ev->session));
442   if (session) {
443     session->HandleEvent(ev);
444   }
445 }
446 
447 }  // namespace cricket
448