• 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_transport.h"
12 
13 #include <stdint.h>
14 #include <string.h>
15 
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 #include "absl/strings/match.h"
21 #include "media/base/rtp_utils.h"
22 #include "pc/rtp_transport.h"
23 #include "pc/srtp_session.h"
24 #include "rtc_base/async_packet_socket.h"
25 #include "rtc_base/checks.h"
26 #include "rtc_base/copy_on_write_buffer.h"
27 #include "rtc_base/logging.h"
28 #include "rtc_base/numerics/safe_conversions.h"
29 #include "rtc_base/ssl_stream_adapter.h"
30 #include "rtc_base/third_party/base64/base64.h"
31 #include "rtc_base/third_party/sigslot/sigslot.h"
32 #include "rtc_base/trace_event.h"
33 #include "rtc_base/zero_memory.h"
34 
35 namespace webrtc {
36 
SrtpTransport(bool rtcp_mux_enabled)37 SrtpTransport::SrtpTransport(bool rtcp_mux_enabled)
38     : RtpTransport(rtcp_mux_enabled) {}
39 
SetSrtpSendKey(const cricket::CryptoParams & params)40 RTCError SrtpTransport::SetSrtpSendKey(const cricket::CryptoParams& params) {
41   if (send_params_) {
42     LOG_AND_RETURN_ERROR(
43         webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
44         "Setting the SRTP send key twice is currently unsupported.");
45   }
46   if (recv_params_ && recv_params_->cipher_suite != params.cipher_suite) {
47     LOG_AND_RETURN_ERROR(
48         webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
49         "The send key and receive key must have the same cipher suite.");
50   }
51 
52   send_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite);
53   if (*send_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) {
54     return RTCError(RTCErrorType::INVALID_PARAMETER,
55                     "Invalid SRTP crypto suite");
56   }
57 
58   int send_key_len, send_salt_len;
59   if (!rtc::GetSrtpKeyAndSaltLengths(*send_cipher_suite_, &send_key_len,
60                                      &send_salt_len)) {
61     return RTCError(RTCErrorType::INVALID_PARAMETER,
62                     "Could not get lengths for crypto suite(s):"
63                     " send cipher_suite ");
64   }
65 
66   send_key_ = rtc::ZeroOnFreeBuffer<uint8_t>(send_key_len + send_salt_len);
67   if (!ParseKeyParams(params.key_params, send_key_.data(), send_key_.size())) {
68     return RTCError(RTCErrorType::INVALID_PARAMETER,
69                     "Failed to parse the crypto key params");
70   }
71 
72   if (!MaybeSetKeyParams()) {
73     return RTCError(RTCErrorType::INVALID_PARAMETER,
74                     "Failed to set the crypto key params");
75   }
76   send_params_ = params;
77   return RTCError::OK();
78 }
79 
SetSrtpReceiveKey(const cricket::CryptoParams & params)80 RTCError SrtpTransport::SetSrtpReceiveKey(const cricket::CryptoParams& params) {
81   if (recv_params_) {
82     LOG_AND_RETURN_ERROR(
83         webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
84         "Setting the SRTP send key twice is currently unsupported.");
85   }
86   if (send_params_ && send_params_->cipher_suite != params.cipher_suite) {
87     LOG_AND_RETURN_ERROR(
88         webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
89         "The send key and receive key must have the same cipher suite.");
90   }
91 
92   recv_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite);
93   if (*recv_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) {
94     return RTCError(RTCErrorType::INVALID_PARAMETER,
95                     "Invalid SRTP crypto suite");
96   }
97 
98   int recv_key_len, recv_salt_len;
99   if (!rtc::GetSrtpKeyAndSaltLengths(*recv_cipher_suite_, &recv_key_len,
100                                      &recv_salt_len)) {
101     return RTCError(RTCErrorType::INVALID_PARAMETER,
102                     "Could not get lengths for crypto suite(s):"
103                     " recv cipher_suite ");
104   }
105 
106   recv_key_ = rtc::ZeroOnFreeBuffer<uint8_t>(recv_key_len + recv_salt_len);
107   if (!ParseKeyParams(params.key_params, recv_key_.data(), recv_key_.size())) {
108     return RTCError(RTCErrorType::INVALID_PARAMETER,
109                     "Failed to parse the crypto key params");
110   }
111 
112   if (!MaybeSetKeyParams()) {
113     return RTCError(RTCErrorType::INVALID_PARAMETER,
114                     "Failed to set the crypto key params");
115   }
116   recv_params_ = params;
117   return RTCError::OK();
118 }
119 
SendRtpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)120 bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
121                                   const rtc::PacketOptions& options,
122                                   int flags) {
123   if (!IsSrtpActive()) {
124     RTC_LOG(LS_ERROR)
125         << "Failed to send the packet because SRTP transport is inactive.";
126     return false;
127   }
128   rtc::PacketOptions updated_options = options;
129   TRACE_EVENT0("webrtc", "SRTP Encode");
130   bool res;
131   uint8_t* data = packet->data();
132   int len = rtc::checked_cast<int>(packet->size());
133 // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
134 // inside libsrtp for a RTP packet. A external HMAC module will be writing
135 // a fake HMAC value. This is ONLY done for a RTP packet.
136 // Socket layer will update rtp sendtime extension header if present in
137 // packet with current time before updating the HMAC.
138 #if !defined(ENABLE_EXTERNAL_AUTH)
139   res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
140 #else
141   if (!IsExternalAuthActive()) {
142     res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
143   } else {
144     updated_options.packet_time_params.rtp_sendtime_extension_id =
145         rtp_abs_sendtime_extn_id_;
146     res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len,
147                      &updated_options.packet_time_params.srtp_packet_index);
148     // If protection succeeds, let's get auth params from srtp.
149     if (res) {
150       uint8_t* auth_key = nullptr;
151       int key_len = 0;
152       res = GetRtpAuthParams(
153           &auth_key, &key_len,
154           &updated_options.packet_time_params.srtp_auth_tag_len);
155       if (res) {
156         updated_options.packet_time_params.srtp_auth_key.resize(key_len);
157         updated_options.packet_time_params.srtp_auth_key.assign(
158             auth_key, auth_key + key_len);
159       }
160     }
161   }
162 #endif
163   if (!res) {
164     int seq_num = -1;
165     uint32_t ssrc = 0;
166     cricket::GetRtpSeqNum(data, len, &seq_num);
167     cricket::GetRtpSsrc(data, len, &ssrc);
168     RTC_LOG(LS_ERROR) << "Failed to protect RTP packet: size=" << len
169                       << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
170     return false;
171   }
172 
173   // Update the length of the packet now that we've added the auth tag.
174   packet->SetSize(len);
175   return SendPacket(/*rtcp=*/false, packet, updated_options, flags);
176 }
177 
SendRtcpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)178 bool SrtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
179                                    const rtc::PacketOptions& options,
180                                    int flags) {
181   if (!IsSrtpActive()) {
182     RTC_LOG(LS_ERROR)
183         << "Failed to send the packet because SRTP transport is inactive.";
184     return false;
185   }
186 
187   TRACE_EVENT0("webrtc", "SRTP Encode");
188   uint8_t* data = packet->data();
189   int len = rtc::checked_cast<int>(packet->size());
190   if (!ProtectRtcp(data, len, static_cast<int>(packet->capacity()), &len)) {
191     int type = -1;
192     cricket::GetRtcpType(data, len, &type);
193     RTC_LOG(LS_ERROR) << "Failed to protect RTCP packet: size=" << len
194                       << ", type=" << type;
195     return false;
196   }
197   // Update the length of the packet now that we've added the auth tag.
198   packet->SetSize(len);
199 
200   return SendPacket(/*rtcp=*/true, packet, options, flags);
201 }
202 
OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet,int64_t packet_time_us)203 void SrtpTransport::OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet,
204                                         int64_t packet_time_us) {
205   if (!IsSrtpActive()) {
206     RTC_LOG(LS_WARNING)
207         << "Inactive SRTP transport received an RTP packet. Drop it.";
208     return;
209   }
210   TRACE_EVENT0("webrtc", "SRTP Decode");
211   char* data = packet.data<char>();
212   int len = rtc::checked_cast<int>(packet.size());
213   if (!UnprotectRtp(data, len, &len)) {
214     int seq_num = -1;
215     uint32_t ssrc = 0;
216     cricket::GetRtpSeqNum(data, len, &seq_num);
217     cricket::GetRtpSsrc(data, len, &ssrc);
218 
219     // Limit the error logging to avoid excessive logs when there are lots of
220     // bad packets.
221     const int kFailureLogThrottleCount = 100;
222     if (decryption_failure_count_ % kFailureLogThrottleCount == 0) {
223       RTC_LOG(LS_ERROR) << "Failed to unprotect RTP packet: size=" << len
224                         << ", seqnum=" << seq_num << ", SSRC=" << ssrc
225                         << ", previous failure count: "
226                         << decryption_failure_count_;
227     }
228     ++decryption_failure_count_;
229     return;
230   }
231   packet.SetSize(len);
232   DemuxPacket(std::move(packet), packet_time_us);
233 }
234 
OnRtcpPacketReceived(rtc::CopyOnWriteBuffer packet,int64_t packet_time_us)235 void SrtpTransport::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer packet,
236                                          int64_t packet_time_us) {
237   if (!IsSrtpActive()) {
238     RTC_LOG(LS_WARNING)
239         << "Inactive SRTP transport received an RTCP packet. Drop it.";
240     return;
241   }
242   TRACE_EVENT0("webrtc", "SRTP Decode");
243   char* data = packet.data<char>();
244   int len = rtc::checked_cast<int>(packet.size());
245   if (!UnprotectRtcp(data, len, &len)) {
246     int type = -1;
247     cricket::GetRtcpType(data, len, &type);
248     RTC_LOG(LS_ERROR) << "Failed to unprotect RTCP packet: size=" << len
249                       << ", type=" << type;
250     return;
251   }
252   packet.SetSize(len);
253   SignalRtcpPacketReceived(&packet, packet_time_us);
254 }
255 
OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route)256 void SrtpTransport::OnNetworkRouteChanged(
257     absl::optional<rtc::NetworkRoute> network_route) {
258   // Only append the SRTP overhead when there is a selected network route.
259   if (network_route) {
260     int srtp_overhead = 0;
261     if (IsSrtpActive()) {
262       GetSrtpOverhead(&srtp_overhead);
263     }
264     network_route->packet_overhead += srtp_overhead;
265   }
266   SignalNetworkRouteChanged(network_route);
267 }
268 
OnWritableState(rtc::PacketTransportInternal * packet_transport)269 void SrtpTransport::OnWritableState(
270     rtc::PacketTransportInternal* packet_transport) {
271   SignalWritableState(IsWritable(/*rtcp=*/true) && IsWritable(/*rtcp=*/true));
272 }
273 
SetRtpParams(int send_cs,const uint8_t * send_key,int send_key_len,const std::vector<int> & send_extension_ids,int recv_cs,const uint8_t * recv_key,int recv_key_len,const std::vector<int> & recv_extension_ids)274 bool SrtpTransport::SetRtpParams(int send_cs,
275                                  const uint8_t* send_key,
276                                  int send_key_len,
277                                  const std::vector<int>& send_extension_ids,
278                                  int recv_cs,
279                                  const uint8_t* recv_key,
280                                  int recv_key_len,
281                                  const std::vector<int>& recv_extension_ids) {
282   // If parameters are being set for the first time, we should create new SRTP
283   // sessions and call "SetSend/SetRecv". Otherwise we should call
284   // "UpdateSend"/"UpdateRecv" on the existing sessions, which will internally
285   // call "srtp_update".
286   bool new_sessions = false;
287   if (!send_session_) {
288     RTC_DCHECK(!recv_session_);
289     CreateSrtpSessions();
290     new_sessions = true;
291   }
292   bool ret = new_sessions
293                  ? send_session_->SetSend(send_cs, send_key, send_key_len,
294                                           send_extension_ids)
295                  : send_session_->UpdateSend(send_cs, send_key, send_key_len,
296                                              send_extension_ids);
297   if (!ret) {
298     ResetParams();
299     return false;
300   }
301 
302   ret = new_sessions ? recv_session_->SetRecv(recv_cs, recv_key, recv_key_len,
303                                               recv_extension_ids)
304                      : recv_session_->UpdateRecv(
305                            recv_cs, recv_key, recv_key_len, recv_extension_ids);
306   if (!ret) {
307     ResetParams();
308     return false;
309   }
310 
311   RTC_LOG(LS_INFO) << "SRTP " << (new_sessions ? "activated" : "updated")
312                    << " with negotiated parameters: send cipher_suite "
313                    << send_cs << " recv cipher_suite " << recv_cs;
314   MaybeUpdateWritableState();
315   return true;
316 }
317 
SetRtcpParams(int send_cs,const uint8_t * send_key,int send_key_len,const std::vector<int> & send_extension_ids,int recv_cs,const uint8_t * recv_key,int recv_key_len,const std::vector<int> & recv_extension_ids)318 bool SrtpTransport::SetRtcpParams(int send_cs,
319                                   const uint8_t* send_key,
320                                   int send_key_len,
321                                   const std::vector<int>& send_extension_ids,
322                                   int recv_cs,
323                                   const uint8_t* recv_key,
324                                   int recv_key_len,
325                                   const std::vector<int>& recv_extension_ids) {
326   // This can only be called once, but can be safely called after
327   // SetRtpParams
328   if (send_rtcp_session_ || recv_rtcp_session_) {
329     RTC_LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
330     return false;
331   }
332 
333   send_rtcp_session_.reset(new cricket::SrtpSession());
334   if (!send_rtcp_session_->SetSend(send_cs, send_key, send_key_len,
335                                    send_extension_ids)) {
336     return false;
337   }
338 
339   recv_rtcp_session_.reset(new cricket::SrtpSession());
340   if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len,
341                                    recv_extension_ids)) {
342     return false;
343   }
344 
345   RTC_LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
346                       " send cipher_suite "
347                    << send_cs << " recv cipher_suite " << recv_cs;
348   MaybeUpdateWritableState();
349   return true;
350 }
351 
IsSrtpActive() const352 bool SrtpTransport::IsSrtpActive() const {
353   return send_session_ && recv_session_;
354 }
355 
IsWritable(bool rtcp) const356 bool SrtpTransport::IsWritable(bool rtcp) const {
357   return IsSrtpActive() && RtpTransport::IsWritable(rtcp);
358 }
359 
ResetParams()360 void SrtpTransport::ResetParams() {
361   send_session_ = nullptr;
362   recv_session_ = nullptr;
363   send_rtcp_session_ = nullptr;
364   recv_rtcp_session_ = nullptr;
365   MaybeUpdateWritableState();
366   RTC_LOG(LS_INFO) << "The params in SRTP transport are reset.";
367 }
368 
CreateSrtpSessions()369 void SrtpTransport::CreateSrtpSessions() {
370   send_session_.reset(new cricket::SrtpSession());
371   recv_session_.reset(new cricket::SrtpSession());
372   if (external_auth_enabled_) {
373     send_session_->EnableExternalAuth();
374   }
375 }
376 
ProtectRtp(void * p,int in_len,int max_len,int * out_len)377 bool SrtpTransport::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
378   if (!IsSrtpActive()) {
379     RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
380     return false;
381   }
382   RTC_CHECK(send_session_);
383   return send_session_->ProtectRtp(p, in_len, max_len, out_len);
384 }
385 
ProtectRtp(void * p,int in_len,int max_len,int * out_len,int64_t * index)386 bool SrtpTransport::ProtectRtp(void* p,
387                                int in_len,
388                                int max_len,
389                                int* out_len,
390                                int64_t* index) {
391   if (!IsSrtpActive()) {
392     RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
393     return false;
394   }
395   RTC_CHECK(send_session_);
396   return send_session_->ProtectRtp(p, in_len, max_len, out_len, index);
397 }
398 
ProtectRtcp(void * p,int in_len,int max_len,int * out_len)399 bool SrtpTransport::ProtectRtcp(void* p,
400                                 int in_len,
401                                 int max_len,
402                                 int* out_len) {
403   if (!IsSrtpActive()) {
404     RTC_LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
405     return false;
406   }
407   if (send_rtcp_session_) {
408     return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
409   } else {
410     RTC_CHECK(send_session_);
411     return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
412   }
413 }
414 
UnprotectRtp(void * p,int in_len,int * out_len)415 bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) {
416   if (!IsSrtpActive()) {
417     RTC_LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
418     return false;
419   }
420   RTC_CHECK(recv_session_);
421   return recv_session_->UnprotectRtp(p, in_len, out_len);
422 }
423 
UnprotectRtcp(void * p,int in_len,int * out_len)424 bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) {
425   if (!IsSrtpActive()) {
426     RTC_LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
427     return false;
428   }
429   if (recv_rtcp_session_) {
430     return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
431   } else {
432     RTC_CHECK(recv_session_);
433     return recv_session_->UnprotectRtcp(p, in_len, out_len);
434   }
435 }
436 
GetRtpAuthParams(uint8_t ** key,int * key_len,int * tag_len)437 bool SrtpTransport::GetRtpAuthParams(uint8_t** key,
438                                      int* key_len,
439                                      int* tag_len) {
440   if (!IsSrtpActive()) {
441     RTC_LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
442     return false;
443   }
444 
445   RTC_CHECK(send_session_);
446   return send_session_->GetRtpAuthParams(key, key_len, tag_len);
447 }
448 
GetSrtpOverhead(int * srtp_overhead) const449 bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const {
450   if (!IsSrtpActive()) {
451     RTC_LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active";
452     return false;
453   }
454 
455   RTC_CHECK(send_session_);
456   *srtp_overhead = send_session_->GetSrtpOverhead();
457   return true;
458 }
459 
EnableExternalAuth()460 void SrtpTransport::EnableExternalAuth() {
461   RTC_DCHECK(!IsSrtpActive());
462   external_auth_enabled_ = true;
463 }
464 
IsExternalAuthEnabled() const465 bool SrtpTransport::IsExternalAuthEnabled() const {
466   return external_auth_enabled_;
467 }
468 
IsExternalAuthActive() const469 bool SrtpTransport::IsExternalAuthActive() const {
470   if (!IsSrtpActive()) {
471     RTC_LOG(LS_WARNING)
472         << "Failed to check IsExternalAuthActive: SRTP not active";
473     return false;
474   }
475 
476   RTC_CHECK(send_session_);
477   return send_session_->IsExternalAuthActive();
478 }
479 
MaybeSetKeyParams()480 bool SrtpTransport::MaybeSetKeyParams() {
481   if (!send_cipher_suite_ || !recv_cipher_suite_) {
482     return true;
483   }
484 
485   return SetRtpParams(*send_cipher_suite_, send_key_.data(),
486                       static_cast<int>(send_key_.size()), std::vector<int>(),
487                       *recv_cipher_suite_, recv_key_.data(),
488                       static_cast<int>(recv_key_.size()), std::vector<int>());
489 }
490 
ParseKeyParams(const std::string & key_params,uint8_t * key,size_t len)491 bool SrtpTransport::ParseKeyParams(const std::string& key_params,
492                                    uint8_t* key,
493                                    size_t len) {
494   // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
495 
496   // Fail if key-method is wrong.
497   if (!absl::StartsWith(key_params, "inline:")) {
498     return false;
499   }
500 
501   // Fail if base64 decode fails, or the key is the wrong size.
502   std::string key_b64(key_params.substr(7)), key_str;
503   if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, &key_str,
504                            nullptr) ||
505       key_str.size() != len) {
506     return false;
507   }
508 
509   memcpy(key, key_str.c_str(), len);
510   // TODO(bugs.webrtc.org/8905): Switch to ZeroOnFreeBuffer for storing
511   // sensitive data.
512   rtc::ExplicitZeroMemory(&key_str[0], key_str.size());
513   return true;
514 }
515 
MaybeUpdateWritableState()516 void SrtpTransport::MaybeUpdateWritableState() {
517   bool writable = IsWritable(/*rtcp=*/true) && IsWritable(/*rtcp=*/false);
518   // Only fire the signal if the writable state changes.
519   if (writable_ != writable) {
520     writable_ = writable;
521     SignalWritableState(writable_);
522   }
523 }
524 
525 }  // namespace webrtc
526