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