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 <string.h>
14
15 #include <string>
16 #include <utility>
17 #include <vector>
18
19 #include "absl/strings/match.h"
20 #include "media/base/rtp_utils.h"
21 #include "modules/rtp_rtcp/source/rtp_util.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/trace_event.h"
32 #include "rtc_base/zero_memory.h"
33
34 namespace webrtc {
35
SrtpTransport(bool rtcp_mux_enabled,const FieldTrialsView & field_trials)36 SrtpTransport::SrtpTransport(bool rtcp_mux_enabled,
37 const FieldTrialsView& field_trials)
38 : RtpTransport(rtcp_mux_enabled), field_trials_(field_trials) {}
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::kSrtpInvalidCryptoSuite) {
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::kSrtpInvalidCryptoSuite) {
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->MutableData();
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 uint16_t seq_num = ParseRtpSequenceNumber(*packet);
165 uint32_t ssrc = ParseRtpSsrc(*packet);
166 RTC_LOG(LS_ERROR) << "Failed to protect RTP packet: size=" << len
167 << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
168 return false;
169 }
170
171 // Update the length of the packet now that we've added the auth tag.
172 packet->SetSize(len);
173 return SendPacket(/*rtcp=*/false, packet, updated_options, flags);
174 }
175
SendRtcpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)176 bool SrtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
177 const rtc::PacketOptions& options,
178 int flags) {
179 if (!IsSrtpActive()) {
180 RTC_LOG(LS_ERROR)
181 << "Failed to send the packet because SRTP transport is inactive.";
182 return false;
183 }
184
185 TRACE_EVENT0("webrtc", "SRTP Encode");
186 uint8_t* data = packet->MutableData();
187 int len = rtc::checked_cast<int>(packet->size());
188 if (!ProtectRtcp(data, len, static_cast<int>(packet->capacity()), &len)) {
189 int type = -1;
190 cricket::GetRtcpType(data, len, &type);
191 RTC_LOG(LS_ERROR) << "Failed to protect RTCP packet: size=" << len
192 << ", type=" << type;
193 return false;
194 }
195 // Update the length of the packet now that we've added the auth tag.
196 packet->SetSize(len);
197
198 return SendPacket(/*rtcp=*/true, packet, options, flags);
199 }
200
OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet,int64_t packet_time_us)201 void SrtpTransport::OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet,
202 int64_t packet_time_us) {
203 TRACE_EVENT0("webrtc", "SrtpTransport::OnRtpPacketReceived");
204 if (!IsSrtpActive()) {
205 RTC_LOG(LS_WARNING)
206 << "Inactive SRTP transport received an RTP packet. Drop it.";
207 return;
208 }
209 char* data = packet.MutableData<char>();
210 int len = rtc::checked_cast<int>(packet.size());
211 if (!UnprotectRtp(data, len, &len)) {
212 // Limit the error logging to avoid excessive logs when there are lots of
213 // bad packets.
214 const int kFailureLogThrottleCount = 100;
215 if (decryption_failure_count_ % kFailureLogThrottleCount == 0) {
216 RTC_LOG(LS_ERROR) << "Failed to unprotect RTP packet: size=" << len
217 << ", seqnum=" << ParseRtpSequenceNumber(packet)
218 << ", SSRC=" << ParseRtpSsrc(packet)
219 << ", previous failure count: "
220 << decryption_failure_count_;
221 }
222 ++decryption_failure_count_;
223 return;
224 }
225 packet.SetSize(len);
226 DemuxPacket(std::move(packet), packet_time_us);
227 }
228
OnRtcpPacketReceived(rtc::CopyOnWriteBuffer packet,int64_t packet_time_us)229 void SrtpTransport::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer packet,
230 int64_t packet_time_us) {
231 TRACE_EVENT0("webrtc", "SrtpTransport::OnRtcpPacketReceived");
232 if (!IsSrtpActive()) {
233 RTC_LOG(LS_WARNING)
234 << "Inactive SRTP transport received an RTCP packet. Drop it.";
235 return;
236 }
237 char* data = packet.MutableData<char>();
238 int len = rtc::checked_cast<int>(packet.size());
239 if (!UnprotectRtcp(data, len, &len)) {
240 int type = -1;
241 cricket::GetRtcpType(data, len, &type);
242 RTC_LOG(LS_ERROR) << "Failed to unprotect RTCP packet: size=" << len
243 << ", type=" << type;
244 return;
245 }
246 packet.SetSize(len);
247 SignalRtcpPacketReceived(&packet, packet_time_us);
248 }
249
OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route)250 void SrtpTransport::OnNetworkRouteChanged(
251 absl::optional<rtc::NetworkRoute> network_route) {
252 // Only append the SRTP overhead when there is a selected network route.
253 if (network_route) {
254 int srtp_overhead = 0;
255 if (IsSrtpActive()) {
256 GetSrtpOverhead(&srtp_overhead);
257 }
258 network_route->packet_overhead += srtp_overhead;
259 }
260 SignalNetworkRouteChanged(network_route);
261 }
262
OnWritableState(rtc::PacketTransportInternal * packet_transport)263 void SrtpTransport::OnWritableState(
264 rtc::PacketTransportInternal* packet_transport) {
265 SignalWritableState(IsWritable(/*rtcp=*/false) && IsWritable(/*rtcp=*/true));
266 }
267
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)268 bool SrtpTransport::SetRtpParams(int send_cs,
269 const uint8_t* send_key,
270 int send_key_len,
271 const std::vector<int>& send_extension_ids,
272 int recv_cs,
273 const uint8_t* recv_key,
274 int recv_key_len,
275 const std::vector<int>& recv_extension_ids) {
276 // If parameters are being set for the first time, we should create new SRTP
277 // sessions and call "SetSend/SetRecv". Otherwise we should call
278 // "UpdateSend"/"UpdateRecv" on the existing sessions, which will internally
279 // call "srtp_update".
280 bool new_sessions = false;
281 if (!send_session_) {
282 RTC_DCHECK(!recv_session_);
283 CreateSrtpSessions();
284 new_sessions = true;
285 }
286 bool ret = new_sessions
287 ? send_session_->SetSend(send_cs, send_key, send_key_len,
288 send_extension_ids)
289 : send_session_->UpdateSend(send_cs, send_key, send_key_len,
290 send_extension_ids);
291 if (!ret) {
292 ResetParams();
293 return false;
294 }
295
296 ret = new_sessions ? recv_session_->SetRecv(recv_cs, recv_key, recv_key_len,
297 recv_extension_ids)
298 : recv_session_->UpdateRecv(
299 recv_cs, recv_key, recv_key_len, recv_extension_ids);
300 if (!ret) {
301 ResetParams();
302 return false;
303 }
304
305 RTC_LOG(LS_INFO) << "SRTP " << (new_sessions ? "activated" : "updated")
306 << " with negotiated parameters: send cipher_suite "
307 << send_cs << " recv cipher_suite " << recv_cs;
308 MaybeUpdateWritableState();
309 return true;
310 }
311
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)312 bool SrtpTransport::SetRtcpParams(int send_cs,
313 const uint8_t* send_key,
314 int send_key_len,
315 const std::vector<int>& send_extension_ids,
316 int recv_cs,
317 const uint8_t* recv_key,
318 int recv_key_len,
319 const std::vector<int>& recv_extension_ids) {
320 // This can only be called once, but can be safely called after
321 // SetRtpParams
322 if (send_rtcp_session_ || recv_rtcp_session_) {
323 RTC_LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
324 return false;
325 }
326
327 send_rtcp_session_.reset(new cricket::SrtpSession(field_trials_));
328 if (!send_rtcp_session_->SetSend(send_cs, send_key, send_key_len,
329 send_extension_ids)) {
330 return false;
331 }
332
333 recv_rtcp_session_.reset(new cricket::SrtpSession(field_trials_));
334 if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len,
335 recv_extension_ids)) {
336 return false;
337 }
338
339 RTC_LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
340 " send cipher_suite "
341 << send_cs << " recv cipher_suite " << recv_cs;
342 MaybeUpdateWritableState();
343 return true;
344 }
345
IsSrtpActive() const346 bool SrtpTransport::IsSrtpActive() const {
347 return send_session_ && recv_session_;
348 }
349
IsWritable(bool rtcp) const350 bool SrtpTransport::IsWritable(bool rtcp) const {
351 return IsSrtpActive() && RtpTransport::IsWritable(rtcp);
352 }
353
ResetParams()354 void SrtpTransport::ResetParams() {
355 send_session_ = nullptr;
356 recv_session_ = nullptr;
357 send_rtcp_session_ = nullptr;
358 recv_rtcp_session_ = nullptr;
359 MaybeUpdateWritableState();
360 RTC_LOG(LS_INFO) << "The params in SRTP transport are reset.";
361 }
362
CreateSrtpSessions()363 void SrtpTransport::CreateSrtpSessions() {
364 send_session_.reset(new cricket::SrtpSession(field_trials_));
365 recv_session_.reset(new cricket::SrtpSession(field_trials_));
366 if (external_auth_enabled_) {
367 send_session_->EnableExternalAuth();
368 }
369 }
370
ProtectRtp(void * p,int in_len,int max_len,int * out_len)371 bool SrtpTransport::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
372 if (!IsSrtpActive()) {
373 RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
374 return false;
375 }
376 RTC_CHECK(send_session_);
377 return send_session_->ProtectRtp(p, in_len, max_len, out_len);
378 }
379
ProtectRtp(void * p,int in_len,int max_len,int * out_len,int64_t * index)380 bool SrtpTransport::ProtectRtp(void* p,
381 int in_len,
382 int max_len,
383 int* out_len,
384 int64_t* index) {
385 if (!IsSrtpActive()) {
386 RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
387 return false;
388 }
389 RTC_CHECK(send_session_);
390 return send_session_->ProtectRtp(p, in_len, max_len, out_len, index);
391 }
392
ProtectRtcp(void * p,int in_len,int max_len,int * out_len)393 bool SrtpTransport::ProtectRtcp(void* p,
394 int in_len,
395 int max_len,
396 int* out_len) {
397 if (!IsSrtpActive()) {
398 RTC_LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
399 return false;
400 }
401 if (send_rtcp_session_) {
402 return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
403 } else {
404 RTC_CHECK(send_session_);
405 return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
406 }
407 }
408
UnprotectRtp(void * p,int in_len,int * out_len)409 bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) {
410 if (!IsSrtpActive()) {
411 RTC_LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
412 return false;
413 }
414 RTC_CHECK(recv_session_);
415 return recv_session_->UnprotectRtp(p, in_len, out_len);
416 }
417
UnprotectRtcp(void * p,int in_len,int * out_len)418 bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) {
419 if (!IsSrtpActive()) {
420 RTC_LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
421 return false;
422 }
423 if (recv_rtcp_session_) {
424 return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
425 } else {
426 RTC_CHECK(recv_session_);
427 return recv_session_->UnprotectRtcp(p, in_len, out_len);
428 }
429 }
430
GetRtpAuthParams(uint8_t ** key,int * key_len,int * tag_len)431 bool SrtpTransport::GetRtpAuthParams(uint8_t** key,
432 int* key_len,
433 int* tag_len) {
434 if (!IsSrtpActive()) {
435 RTC_LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
436 return false;
437 }
438
439 RTC_CHECK(send_session_);
440 return send_session_->GetRtpAuthParams(key, key_len, tag_len);
441 }
442
GetSrtpOverhead(int * srtp_overhead) const443 bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const {
444 if (!IsSrtpActive()) {
445 RTC_LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active";
446 return false;
447 }
448
449 RTC_CHECK(send_session_);
450 *srtp_overhead = send_session_->GetSrtpOverhead();
451 return true;
452 }
453
EnableExternalAuth()454 void SrtpTransport::EnableExternalAuth() {
455 RTC_DCHECK(!IsSrtpActive());
456 external_auth_enabled_ = true;
457 }
458
IsExternalAuthEnabled() const459 bool SrtpTransport::IsExternalAuthEnabled() const {
460 return external_auth_enabled_;
461 }
462
IsExternalAuthActive() const463 bool SrtpTransport::IsExternalAuthActive() const {
464 if (!IsSrtpActive()) {
465 RTC_LOG(LS_WARNING)
466 << "Failed to check IsExternalAuthActive: SRTP not active";
467 return false;
468 }
469
470 RTC_CHECK(send_session_);
471 return send_session_->IsExternalAuthActive();
472 }
473
MaybeSetKeyParams()474 bool SrtpTransport::MaybeSetKeyParams() {
475 if (!send_cipher_suite_ || !recv_cipher_suite_) {
476 return true;
477 }
478
479 return SetRtpParams(*send_cipher_suite_, send_key_.data(),
480 static_cast<int>(send_key_.size()), std::vector<int>(),
481 *recv_cipher_suite_, recv_key_.data(),
482 static_cast<int>(recv_key_.size()), std::vector<int>());
483 }
484
ParseKeyParams(const std::string & key_params,uint8_t * key,size_t len)485 bool SrtpTransport::ParseKeyParams(const std::string& key_params,
486 uint8_t* key,
487 size_t len) {
488 // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
489
490 // Fail if key-method is wrong.
491 if (!absl::StartsWith(key_params, "inline:")) {
492 return false;
493 }
494
495 // Fail if base64 decode fails, or the key is the wrong size.
496 std::string key_b64(key_params.substr(7)), key_str;
497 if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, &key_str,
498 nullptr) ||
499 key_str.size() != len) {
500 return false;
501 }
502
503 memcpy(key, key_str.c_str(), len);
504 // TODO(bugs.webrtc.org/8905): Switch to ZeroOnFreeBuffer for storing
505 // sensitive data.
506 rtc::ExplicitZeroMemory(&key_str[0], key_str.size());
507 return true;
508 }
509
MaybeUpdateWritableState()510 void SrtpTransport::MaybeUpdateWritableState() {
511 bool writable = IsWritable(/*rtcp=*/true) && IsWritable(/*rtcp=*/false);
512 // Only fire the signal if the writable state changes.
513 if (writable_ != writable) {
514 writable_ = writable;
515 SignalWritableState(writable_);
516 }
517 }
518
519 } // namespace webrtc
520