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 <iomanip>
14 
15 #include "absl/base/attributes.h"
16 #include "media/base/rtp_utils.h"
17 #include "pc/external_hmac.h"
18 #include "rtc_base/logging.h"
19 #include "rtc_base/ssl_stream_adapter.h"
20 #include "rtc_base/string_encode.h"
21 #include "rtc_base/time_utils.h"
22 #include "system_wrappers/include/field_trial.h"
23 #include "system_wrappers/include/metrics.h"
24 #include "third_party/libsrtp/include/srtp.h"
25 #include "third_party/libsrtp/include/srtp_priv.h"
26 
27 namespace cricket {
28 
29 // One more than the maximum libsrtp error code. Required by
30 // RTC_HISTOGRAM_ENUMERATION. Keep this in sync with srtp_error_status_t defined
31 // in srtp.h.
32 constexpr int kSrtpErrorCodeBoundary = 28;
33 
SrtpSession()34 SrtpSession::SrtpSession() {
35   dump_plain_rtp_ = webrtc::field_trial::IsEnabled("WebRTC-Debugging-RtpDump");
36 }
37 
~SrtpSession()38 SrtpSession::~SrtpSession() {
39   if (session_) {
40     srtp_set_user_data(session_, nullptr);
41     srtp_dealloc(session_);
42   }
43   if (inited_) {
44     DecrementLibsrtpUsageCountAndMaybeDeinit();
45   }
46 }
47 
SetSend(int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)48 bool SrtpSession::SetSend(int cs,
49                           const uint8_t* key,
50                           size_t len,
51                           const std::vector<int>& extension_ids) {
52   return SetKey(ssrc_any_outbound, cs, key, len, extension_ids);
53 }
54 
UpdateSend(int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)55 bool SrtpSession::UpdateSend(int cs,
56                              const uint8_t* key,
57                              size_t len,
58                              const std::vector<int>& extension_ids) {
59   return UpdateKey(ssrc_any_outbound, cs, key, len, extension_ids);
60 }
61 
SetRecv(int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)62 bool SrtpSession::SetRecv(int cs,
63                           const uint8_t* key,
64                           size_t len,
65                           const std::vector<int>& extension_ids) {
66   return SetKey(ssrc_any_inbound, cs, key, len, extension_ids);
67 }
68 
UpdateRecv(int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)69 bool SrtpSession::UpdateRecv(int cs,
70                              const uint8_t* key,
71                              size_t len,
72                              const std::vector<int>& extension_ids) {
73   return UpdateKey(ssrc_any_inbound, cs, key, len, extension_ids);
74 }
75 
ProtectRtp(void * p,int in_len,int max_len,int * out_len)76 bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
77   RTC_DCHECK(thread_checker_.IsCurrent());
78   if (!session_) {
79     RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session";
80     return false;
81   }
82 
83   // Note: the need_len differs from the libsrtp recommendatіon to ensure
84   // SRTP_MAX_TRAILER_LEN bytes of free space after the data. WebRTC
85   // never includes a MKI, therefore the amount of bytes added by the
86   // srtp_protect call is known in advance and depends on the cipher suite.
87   int need_len = in_len + rtp_auth_tag_len_;  // NOLINT
88   if (max_len < need_len) {
89     RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length "
90                         << max_len << " is less than the needed " << need_len;
91     return false;
92   }
93   if (dump_plain_rtp_) {
94     DumpPacket(p, in_len, /*outbound=*/true);
95   }
96 
97   *out_len = in_len;
98   int err = srtp_protect(session_, p, out_len);
99   int seq_num;
100   GetRtpSeqNum(p, in_len, &seq_num);
101   if (err != srtp_err_status_ok) {
102     RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet, seqnum=" << seq_num
103                         << ", err=" << err
104                         << ", last seqnum=" << last_send_seq_num_;
105     return false;
106   }
107   last_send_seq_num_ = seq_num;
108   return true;
109 }
110 
ProtectRtp(void * p,int in_len,int max_len,int * out_len,int64_t * index)111 bool SrtpSession::ProtectRtp(void* p,
112                              int in_len,
113                              int max_len,
114                              int* out_len,
115                              int64_t* index) {
116   if (!ProtectRtp(p, in_len, max_len, out_len)) {
117     return false;
118   }
119   return (index) ? GetSendStreamPacketIndex(p, in_len, index) : true;
120 }
121 
ProtectRtcp(void * p,int in_len,int max_len,int * out_len)122 bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
123   RTC_DCHECK(thread_checker_.IsCurrent());
124   if (!session_) {
125     RTC_LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session";
126     return false;
127   }
128 
129   // Note: the need_len differs from the libsrtp recommendatіon to ensure
130   // SRTP_MAX_TRAILER_LEN bytes of free space after the data. WebRTC
131   // never includes a MKI, therefore the amount of bytes added by the
132   // srtp_protect_rtp call is known in advance and depends on the cipher suite.
133   int need_len = in_len + sizeof(uint32_t) + rtcp_auth_tag_len_;  // NOLINT
134   if (max_len < need_len) {
135     RTC_LOG(LS_WARNING) << "Failed to protect SRTCP packet: The buffer length "
136                         << max_len << " is less than the needed " << need_len;
137     return false;
138   }
139   if (dump_plain_rtp_) {
140     DumpPacket(p, in_len, /*outbound=*/true);
141   }
142 
143   *out_len = in_len;
144   int err = srtp_protect_rtcp(session_, p, out_len);
145   if (err != srtp_err_status_ok) {
146     RTC_LOG(LS_WARNING) << "Failed to protect SRTCP packet, err=" << err;
147     return false;
148   }
149   return true;
150 }
151 
UnprotectRtp(void * p,int in_len,int * out_len)152 bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) {
153   RTC_DCHECK(thread_checker_.IsCurrent());
154   if (!session_) {
155     RTC_LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session";
156     return false;
157   }
158 
159   *out_len = in_len;
160   int err = srtp_unprotect(session_, p, out_len);
161   if (err != srtp_err_status_ok) {
162     // Limit the error logging to avoid excessive logs when there are lots of
163     // bad packets.
164     const int kFailureLogThrottleCount = 100;
165     if (decryption_failure_count_ % kFailureLogThrottleCount == 0) {
166       RTC_LOG(LS_WARNING) << "Failed to unprotect SRTP packet, err=" << err
167                           << ", previous failure count: "
168                           << decryption_failure_count_;
169     }
170     ++decryption_failure_count_;
171     RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SrtpUnprotectError",
172                               static_cast<int>(err), kSrtpErrorCodeBoundary);
173     return false;
174   }
175   if (dump_plain_rtp_) {
176     DumpPacket(p, *out_len, /*outbound=*/false);
177   }
178   return true;
179 }
180 
UnprotectRtcp(void * p,int in_len,int * out_len)181 bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
182   RTC_DCHECK(thread_checker_.IsCurrent());
183   if (!session_) {
184     RTC_LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session";
185     return false;
186   }
187 
188   *out_len = in_len;
189   int err = srtp_unprotect_rtcp(session_, p, out_len);
190   if (err != srtp_err_status_ok) {
191     RTC_LOG(LS_WARNING) << "Failed to unprotect SRTCP packet, err=" << err;
192     RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SrtcpUnprotectError",
193                               static_cast<int>(err), kSrtpErrorCodeBoundary);
194     return false;
195   }
196   if (dump_plain_rtp_) {
197     DumpPacket(p, *out_len, /*outbound=*/false);
198   }
199   return true;
200 }
201 
GetRtpAuthParams(uint8_t ** key,int * key_len,int * tag_len)202 bool SrtpSession::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) {
203   RTC_DCHECK(thread_checker_.IsCurrent());
204   RTC_DCHECK(IsExternalAuthActive());
205   if (!IsExternalAuthActive()) {
206     return false;
207   }
208 
209   ExternalHmacContext* external_hmac = nullptr;
210   // stream_template will be the reference context for other streams.
211   // Let's use it for getting the keys.
212   srtp_stream_ctx_t* srtp_context = session_->stream_template;
213   if (srtp_context && srtp_context->session_keys &&
214       srtp_context->session_keys->rtp_auth) {
215     external_hmac = reinterpret_cast<ExternalHmacContext*>(
216         srtp_context->session_keys->rtp_auth->state);
217   }
218 
219   if (!external_hmac) {
220     RTC_LOG(LS_ERROR) << "Failed to get auth keys from libsrtp!.";
221     return false;
222   }
223 
224   *key = external_hmac->key;
225   *key_len = external_hmac->key_length;
226   *tag_len = rtp_auth_tag_len_;
227   return true;
228 }
229 
GetSrtpOverhead() const230 int SrtpSession::GetSrtpOverhead() const {
231   return rtp_auth_tag_len_;
232 }
233 
EnableExternalAuth()234 void SrtpSession::EnableExternalAuth() {
235   RTC_DCHECK(!session_);
236   external_auth_enabled_ = true;
237 }
238 
IsExternalAuthEnabled() const239 bool SrtpSession::IsExternalAuthEnabled() const {
240   return external_auth_enabled_;
241 }
242 
IsExternalAuthActive() const243 bool SrtpSession::IsExternalAuthActive() const {
244   return external_auth_active_;
245 }
246 
GetSendStreamPacketIndex(void * p,int in_len,int64_t * index)247 bool SrtpSession::GetSendStreamPacketIndex(void* p,
248                                            int in_len,
249                                            int64_t* index) {
250   RTC_DCHECK(thread_checker_.IsCurrent());
251   srtp_hdr_t* hdr = reinterpret_cast<srtp_hdr_t*>(p);
252   srtp_stream_ctx_t* stream = srtp_get_stream(session_, hdr->ssrc);
253   if (!stream) {
254     return false;
255   }
256 
257   // Shift packet index, put into network byte order
258   *index = static_cast<int64_t>(rtc::NetworkToHost64(
259       srtp_rdbx_get_packet_index(&stream->rtp_rdbx) << 16));
260   return true;
261 }
262 
DoSetKey(int type,int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)263 bool SrtpSession::DoSetKey(int type,
264                            int cs,
265                            const uint8_t* key,
266                            size_t len,
267                            const std::vector<int>& extension_ids) {
268   RTC_DCHECK(thread_checker_.IsCurrent());
269 
270   srtp_policy_t policy;
271   memset(&policy, 0, sizeof(policy));
272   if (!(srtp_crypto_policy_set_from_profile_for_rtp(
273             &policy.rtp, (srtp_profile_t)cs) == srtp_err_status_ok &&
274         srtp_crypto_policy_set_from_profile_for_rtcp(
275             &policy.rtcp, (srtp_profile_t)cs) == srtp_err_status_ok)) {
276     RTC_LOG(LS_ERROR) << "Failed to " << (session_ ? "update" : "create")
277                       << " SRTP session: unsupported cipher_suite " << cs;
278     return false;
279   }
280 
281   int expected_key_len;
282   int expected_salt_len;
283   if (!rtc::GetSrtpKeyAndSaltLengths(cs, &expected_key_len,
284                                      &expected_salt_len)) {
285     // This should never happen.
286     RTC_NOTREACHED();
287     RTC_LOG(LS_WARNING)
288         << "Failed to " << (session_ ? "update" : "create")
289         << " SRTP session: unsupported cipher_suite without length information"
290         << cs;
291     return false;
292   }
293 
294   if (!key ||
295       len != static_cast<size_t>(expected_key_len + expected_salt_len)) {
296     RTC_LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create")
297                         << " SRTP session: invalid key";
298     return false;
299   }
300 
301   policy.ssrc.type = static_cast<srtp_ssrc_type_t>(type);
302   policy.ssrc.value = 0;
303   policy.key = const_cast<uint8_t*>(key);
304   // TODO(astor) parse window size from WSH session-param
305   policy.window_size = 1024;
306   policy.allow_repeat_tx = 1;
307   // If external authentication option is enabled, supply custom auth module
308   // id EXTERNAL_HMAC_SHA1 in the policy structure.
309   // We want to set this option only for rtp packets.
310   // By default policy structure is initialized to HMAC_SHA1.
311   // Enable external HMAC authentication only for outgoing streams and only
312   // for cipher suites that support it (i.e. only non-GCM cipher suites).
313   if (type == ssrc_any_outbound && IsExternalAuthEnabled() &&
314       !rtc::IsGcmCryptoSuite(cs)) {
315     policy.rtp.auth_type = EXTERNAL_HMAC_SHA1;
316   }
317   if (!extension_ids.empty()) {
318     policy.enc_xtn_hdr = const_cast<int*>(&extension_ids[0]);
319     policy.enc_xtn_hdr_count = static_cast<int>(extension_ids.size());
320   }
321   policy.next = nullptr;
322 
323   if (!session_) {
324     int err = srtp_create(&session_, &policy);
325     if (err != srtp_err_status_ok) {
326       session_ = nullptr;
327       RTC_LOG(LS_ERROR) << "Failed to create SRTP session, err=" << err;
328       return false;
329     }
330     srtp_set_user_data(session_, this);
331   } else {
332     int err = srtp_update(session_, &policy);
333     if (err != srtp_err_status_ok) {
334       RTC_LOG(LS_ERROR) << "Failed to update SRTP session, err=" << err;
335       return false;
336     }
337   }
338 
339   rtp_auth_tag_len_ = policy.rtp.auth_tag_len;
340   rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len;
341   external_auth_active_ = (policy.rtp.auth_type == EXTERNAL_HMAC_SHA1);
342   return true;
343 }
344 
SetKey(int type,int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)345 bool SrtpSession::SetKey(int type,
346                          int cs,
347                          const uint8_t* key,
348                          size_t len,
349                          const std::vector<int>& extension_ids) {
350   RTC_DCHECK(thread_checker_.IsCurrent());
351   if (session_) {
352     RTC_LOG(LS_ERROR) << "Failed to create SRTP session: "
353                          "SRTP session already created";
354     return false;
355   }
356 
357   // This is the first time we need to actually interact with libsrtp, so
358   // initialize it if needed.
359   if (IncrementLibsrtpUsageCountAndMaybeInit()) {
360     inited_ = true;
361   } else {
362     return false;
363   }
364 
365   return DoSetKey(type, cs, key, len, extension_ids);
366 }
367 
UpdateKey(int type,int cs,const uint8_t * key,size_t len,const std::vector<int> & extension_ids)368 bool SrtpSession::UpdateKey(int type,
369                             int cs,
370                             const uint8_t* key,
371                             size_t len,
372                             const std::vector<int>& extension_ids) {
373   RTC_DCHECK(thread_checker_.IsCurrent());
374   if (!session_) {
375     RTC_LOG(LS_ERROR) << "Failed to update non-existing SRTP session";
376     return false;
377   }
378 
379   return DoSetKey(type, cs, key, len, extension_ids);
380 }
381 
382 ABSL_CONST_INIT int g_libsrtp_usage_count = 0;
383 ABSL_CONST_INIT webrtc::GlobalMutex g_libsrtp_lock(absl::kConstInit);
384 
ProhibitLibsrtpInitialization()385 void ProhibitLibsrtpInitialization() {
386   webrtc::GlobalMutexLock ls(&g_libsrtp_lock);
387   ++g_libsrtp_usage_count;
388 }
389 
390 // static
IncrementLibsrtpUsageCountAndMaybeInit()391 bool SrtpSession::IncrementLibsrtpUsageCountAndMaybeInit() {
392   webrtc::GlobalMutexLock ls(&g_libsrtp_lock);
393 
394   RTC_DCHECK_GE(g_libsrtp_usage_count, 0);
395   if (g_libsrtp_usage_count == 0) {
396     int err;
397     err = srtp_init();
398     if (err != srtp_err_status_ok) {
399       RTC_LOG(LS_ERROR) << "Failed to init SRTP, err=" << err;
400       return false;
401     }
402 
403     err = srtp_install_event_handler(&SrtpSession::HandleEventThunk);
404     if (err != srtp_err_status_ok) {
405       RTC_LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err;
406       return false;
407     }
408 
409     err = external_crypto_init();
410     if (err != srtp_err_status_ok) {
411       RTC_LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err;
412       return false;
413     }
414   }
415   ++g_libsrtp_usage_count;
416   return true;
417 }
418 
419 // static
DecrementLibsrtpUsageCountAndMaybeDeinit()420 void SrtpSession::DecrementLibsrtpUsageCountAndMaybeDeinit() {
421   webrtc::GlobalMutexLock ls(&g_libsrtp_lock);
422 
423   RTC_DCHECK_GE(g_libsrtp_usage_count, 1);
424   if (--g_libsrtp_usage_count == 0) {
425     int err = srtp_shutdown();
426     if (err) {
427       RTC_LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err;
428     }
429   }
430 }
431 
HandleEvent(const srtp_event_data_t * ev)432 void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
433   RTC_DCHECK(thread_checker_.IsCurrent());
434   switch (ev->event) {
435     case event_ssrc_collision:
436       RTC_LOG(LS_INFO) << "SRTP event: SSRC collision";
437       break;
438     case event_key_soft_limit:
439       RTC_LOG(LS_INFO) << "SRTP event: reached soft key usage limit";
440       break;
441     case event_key_hard_limit:
442       RTC_LOG(LS_INFO) << "SRTP event: reached hard key usage limit";
443       break;
444     case event_packet_index_limit:
445       RTC_LOG(LS_INFO)
446           << "SRTP event: reached hard packet limit (2^48 packets)";
447       break;
448     default:
449       RTC_LOG(LS_INFO) << "SRTP event: unknown " << ev->event;
450       break;
451   }
452 }
453 
HandleEventThunk(srtp_event_data_t * ev)454 void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) {
455   // Callback will be executed from same thread that calls the "srtp_protect"
456   // and "srtp_unprotect" functions.
457   SrtpSession* session =
458       static_cast<SrtpSession*>(srtp_get_user_data(ev->session));
459   if (session) {
460     session->HandleEvent(ev);
461   }
462 }
463 
464 // Logs the unencrypted packet in text2pcap format. This can then be
465 // extracted by searching for RTP_DUMP
466 //   grep RTP_DUMP chrome_debug.log > in.txt
467 // and converted to pcap using
468 //   text2pcap -D -u 1000,2000 -t %H:%M:%S. in.txt out.pcap
469 // The resulting file can be replayed using the WebRTC video_replay tool and
470 // be inspected in Wireshark using the RTP, VP8 and H264 dissectors.
DumpPacket(const void * buf,int len,bool outbound)471 void SrtpSession::DumpPacket(const void* buf, int len, bool outbound) {
472   int64_t time_of_day = rtc::TimeUTCMillis() % (24 * 3600 * 1000);
473   int64_t hours = time_of_day / (3600 * 1000);
474   int64_t minutes = (time_of_day / (60 * 1000)) % 60;
475   int64_t seconds = (time_of_day / 1000) % 60;
476   int64_t millis = time_of_day % 1000;
477   RTC_LOG(LS_VERBOSE) << "\n" << (outbound ? "O" : "I") << " "
478     << std::setfill('0') << std::setw(2) << hours << ":"
479     << std::setfill('0') << std::setw(2) << minutes << ":"
480     << std::setfill('0') << std::setw(2) << seconds << "."
481     << std::setfill('0') << std::setw(3) << millis << " "
482     << "000000 " << rtc::hex_encode_with_delimiter((const char *)buf, len, ' ')
483     << " # RTP_DUMP";
484 }
485 
486 }  // namespace cricket
487