blob: 98a3beab307221b2e2ca0f6709d8542260e60118 [file] [log] [blame]
zstein398c3fd2017-07-19 13:38:02 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/srtptransport.h"
zstein398c3fd2017-07-19 13:38:02 -070012
13#include <string>
Steve Anton36b29d12017-10-30 09:57:42 -070014#include <vector>
zstein398c3fd2017-07-19 13:38:02 -070015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "media/base/rtputils.h"
17#include "pc/rtptransport.h"
18#include "pc/srtpsession.h"
19#include "rtc_base/asyncpacketsocket.h"
Zhi Huangcf990f52017-09-22 12:12:30 -070020#include "rtc_base/base64.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/copyonwritebuffer.h"
22#include "rtc_base/ptr_util.h"
23#include "rtc_base/trace_event.h"
zstein398c3fd2017-07-19 13:38:02 -070024
25namespace webrtc {
26
27SrtpTransport::SrtpTransport(bool rtcp_mux_enabled,
28 const std::string& content_name)
Zhi Huangf2d7beb2017-11-20 14:35:11 -080029 : RtpTransportInternalAdapter(new RtpTransport(rtcp_mux_enabled)),
30 content_name_(content_name) {
31 // Own the raw pointer |transport| from the base class.
32 rtp_transport_.reset(transport_);
33 RTC_DCHECK(rtp_transport_);
zstein398c3fd2017-07-19 13:38:02 -070034 ConnectToRtpTransport();
35}
36
Zhi Huangf2d7beb2017-11-20 14:35:11 -080037SrtpTransport::SrtpTransport(
38 std::unique_ptr<RtpTransportInternal> rtp_transport,
39 const std::string& content_name)
40 : RtpTransportInternalAdapter(rtp_transport.get()),
41 content_name_(content_name),
42 rtp_transport_(std::move(rtp_transport)) {
43 RTC_DCHECK(rtp_transport_);
zstein398c3fd2017-07-19 13:38:02 -070044 ConnectToRtpTransport();
45}
46
47void SrtpTransport::ConnectToRtpTransport() {
48 rtp_transport_->SignalPacketReceived.connect(
49 this, &SrtpTransport::OnPacketReceived);
50 rtp_transport_->SignalReadyToSend.connect(this,
51 &SrtpTransport::OnReadyToSend);
Zhi Huang942bc2e2017-11-13 13:26:07 -080052 rtp_transport_->SignalNetworkRouteChanged.connect(
53 this, &SrtpTransport::OnNetworkRouteChanged);
zstein398c3fd2017-07-19 13:38:02 -070054}
55
Zhi Huangcf990f52017-09-22 12:12:30 -070056bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
57 const rtc::PacketOptions& options,
58 int flags) {
59 return SendPacket(false, packet, options, flags);
60}
61
62bool SrtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
63 const rtc::PacketOptions& options,
64 int flags) {
65 return SendPacket(true, packet, options, flags);
66}
67
zstein398c3fd2017-07-19 13:38:02 -070068bool SrtpTransport::SendPacket(bool rtcp,
69 rtc::CopyOnWriteBuffer* packet,
70 const rtc::PacketOptions& options,
71 int flags) {
Zhi Huangcf990f52017-09-22 12:12:30 -070072 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010073 RTC_LOG(LS_ERROR)
Zhi Huangcf990f52017-09-22 12:12:30 -070074 << "Failed to send the packet because SRTP transport is inactive.";
75 return false;
76 }
zstein398c3fd2017-07-19 13:38:02 -070077
Zhi Huangcf990f52017-09-22 12:12:30 -070078 rtc::PacketOptions updated_options = options;
79 rtc::CopyOnWriteBuffer cp = *packet;
80 TRACE_EVENT0("webrtc", "SRTP Encode");
81 bool res;
82 uint8_t* data = packet->data();
83 int len = static_cast<int>(packet->size());
84 if (!rtcp) {
85// If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
86// inside libsrtp for a RTP packet. A external HMAC module will be writing
87// a fake HMAC value. This is ONLY done for a RTP packet.
88// Socket layer will update rtp sendtime extension header if present in
89// packet with current time before updating the HMAC.
90#if !defined(ENABLE_EXTERNAL_AUTH)
91 res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
92#else
93 if (!IsExternalAuthActive()) {
94 res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
95 } else {
96 updated_options.packet_time_params.rtp_sendtime_extension_id =
97 rtp_abs_sendtime_extn_id_;
98 res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len,
99 &updated_options.packet_time_params.srtp_packet_index);
100 // If protection succeeds, let's get auth params from srtp.
101 if (res) {
102 uint8_t* auth_key = NULL;
103 int key_len;
104 res = GetRtpAuthParams(
105 &auth_key, &key_len,
106 &updated_options.packet_time_params.srtp_auth_tag_len);
107 if (res) {
108 updated_options.packet_time_params.srtp_auth_key.resize(key_len);
109 updated_options.packet_time_params.srtp_auth_key.assign(
110 auth_key, auth_key + key_len);
111 }
112 }
113 }
114#endif
115 if (!res) {
116 int seq_num = -1;
117 uint32_t ssrc = 0;
118 cricket::GetRtpSeqNum(data, len, &seq_num);
119 cricket::GetRtpSsrc(data, len, &ssrc);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100120 RTC_LOG(LS_ERROR) << "Failed to protect " << content_name_
121 << " RTP packet: size=" << len << ", seqnum=" << seq_num
122 << ", SSRC=" << ssrc;
Zhi Huangcf990f52017-09-22 12:12:30 -0700123 return false;
124 }
125 } else {
126 res = ProtectRtcp(data, len, static_cast<int>(packet->capacity()), &len);
127 if (!res) {
128 int type = -1;
129 cricket::GetRtcpType(data, len, &type);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100130 RTC_LOG(LS_ERROR) << "Failed to protect " << content_name_
131 << " RTCP packet: size=" << len << ", type=" << type;
Zhi Huangcf990f52017-09-22 12:12:30 -0700132 return false;
133 }
134 }
135
136 // Update the length of the packet now that we've added the auth tag.
137 packet->SetSize(len);
138 return rtcp ? rtp_transport_->SendRtcpPacket(packet, updated_options, flags)
139 : rtp_transport_->SendRtpPacket(packet, updated_options, flags);
zstein398c3fd2017-07-19 13:38:02 -0700140}
141
142void SrtpTransport::OnPacketReceived(bool rtcp,
143 rtc::CopyOnWriteBuffer* packet,
144 const rtc::PacketTime& packet_time) {
Zhi Huangcf990f52017-09-22 12:12:30 -0700145 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100146 RTC_LOG(LS_WARNING)
147 << "Inactive SRTP transport received a packet. Drop it.";
Zhi Huangcf990f52017-09-22 12:12:30 -0700148 return;
149 }
zstein398c3fd2017-07-19 13:38:02 -0700150
Zhi Huangcf990f52017-09-22 12:12:30 -0700151 TRACE_EVENT0("webrtc", "SRTP Decode");
152 char* data = packet->data<char>();
153 int len = static_cast<int>(packet->size());
154 bool res;
155 if (!rtcp) {
156 res = UnprotectRtp(data, len, &len);
157 if (!res) {
158 int seq_num = -1;
159 uint32_t ssrc = 0;
160 cricket::GetRtpSeqNum(data, len, &seq_num);
161 cricket::GetRtpSsrc(data, len, &ssrc);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100162 RTC_LOG(LS_ERROR) << "Failed to unprotect " << content_name_
163 << " RTP packet: size=" << len << ", seqnum=" << seq_num
164 << ", SSRC=" << ssrc;
Zhi Huangcf990f52017-09-22 12:12:30 -0700165 return;
166 }
167 } else {
168 res = UnprotectRtcp(data, len, &len);
169 if (!res) {
170 int type = -1;
171 cricket::GetRtcpType(data, len, &type);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100172 RTC_LOG(LS_ERROR) << "Failed to unprotect " << content_name_
173 << " RTCP packet: size=" << len << ", type=" << type;
Zhi Huangcf990f52017-09-22 12:12:30 -0700174 return;
175 }
176 }
177
178 packet->SetSize(len);
zstein398c3fd2017-07-19 13:38:02 -0700179 SignalPacketReceived(rtcp, packet, packet_time);
180}
181
Zhi Huang942bc2e2017-11-13 13:26:07 -0800182void SrtpTransport::OnNetworkRouteChanged(
183
184 rtc::Optional<rtc::NetworkRoute> network_route) {
185 // Only append the SRTP overhead when there is a selected network route.
186 if (network_route) {
187 int srtp_overhead = 0;
188 if (IsActive()) {
189 GetSrtpOverhead(&srtp_overhead);
190 }
191 network_route->packet_overhead += srtp_overhead;
192 }
193 SignalNetworkRouteChanged(network_route);
194}
195
Zhi Huangcf990f52017-09-22 12:12:30 -0700196bool SrtpTransport::SetRtpParams(int send_cs,
197 const uint8_t* send_key,
198 int send_key_len,
Zhi Huangc99b6c72017-11-10 16:44:46 -0800199 const std::vector<int>& send_extension_ids,
Zhi Huangcf990f52017-09-22 12:12:30 -0700200 int recv_cs,
201 const uint8_t* recv_key,
Zhi Huangc99b6c72017-11-10 16:44:46 -0800202 int recv_key_len,
203 const std::vector<int>& recv_extension_ids) {
Zhi Huangcf990f52017-09-22 12:12:30 -0700204 // If parameters are being set for the first time, we should create new SRTP
205 // sessions and call "SetSend/SetRecv". Otherwise we should call
206 // "UpdateSend"/"UpdateRecv" on the existing sessions, which will internally
207 // call "srtp_update".
208 bool new_sessions = false;
209 if (!send_session_) {
210 RTC_DCHECK(!recv_session_);
211 CreateSrtpSessions();
212 new_sessions = true;
213 }
Zhi Huangcf990f52017-09-22 12:12:30 -0700214 bool ret = new_sessions
Zhi Huangc99b6c72017-11-10 16:44:46 -0800215 ? send_session_->SetSend(send_cs, send_key, send_key_len,
216 send_extension_ids)
217 : send_session_->UpdateSend(send_cs, send_key, send_key_len,
218 send_extension_ids);
Zhi Huangcf990f52017-09-22 12:12:30 -0700219 if (!ret) {
220 ResetParams();
221 return false;
222 }
223
Zhi Huangc99b6c72017-11-10 16:44:46 -0800224 ret = new_sessions ? recv_session_->SetRecv(recv_cs, recv_key, recv_key_len,
225 recv_extension_ids)
226 : recv_session_->UpdateRecv(
227 recv_cs, recv_key, recv_key_len, recv_extension_ids);
Zhi Huangcf990f52017-09-22 12:12:30 -0700228 if (!ret) {
229 ResetParams();
230 return false;
231 }
232
Mirko Bonadei675513b2017-11-09 11:09:25 +0100233 RTC_LOG(LS_INFO) << "SRTP " << (new_sessions ? "activated" : "updated")
234 << " with negotiated parameters:"
235 << " send cipher_suite " << send_cs << " recv cipher_suite "
236 << recv_cs;
Zhi Huangcf990f52017-09-22 12:12:30 -0700237 return true;
238}
239
240bool SrtpTransport::SetRtcpParams(int send_cs,
241 const uint8_t* send_key,
242 int send_key_len,
Zhi Huangc99b6c72017-11-10 16:44:46 -0800243 const std::vector<int>& send_extension_ids,
Zhi Huangcf990f52017-09-22 12:12:30 -0700244 int recv_cs,
245 const uint8_t* recv_key,
Zhi Huangc99b6c72017-11-10 16:44:46 -0800246 int recv_key_len,
247 const std::vector<int>& recv_extension_ids) {
Zhi Huangcf990f52017-09-22 12:12:30 -0700248 // This can only be called once, but can be safely called after
249 // SetRtpParams
250 if (send_rtcp_session_ || recv_rtcp_session_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100251 RTC_LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700252 return false;
253 }
254
255 send_rtcp_session_.reset(new cricket::SrtpSession());
Zhi Huangc99b6c72017-11-10 16:44:46 -0800256 if (!send_rtcp_session_->SetSend(send_cs, send_key, send_key_len,
257 send_extension_ids)) {
Zhi Huangcf990f52017-09-22 12:12:30 -0700258 return false;
259 }
260
261 recv_rtcp_session_.reset(new cricket::SrtpSession());
Zhi Huangc99b6c72017-11-10 16:44:46 -0800262 if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len,
263 recv_extension_ids)) {
Zhi Huangcf990f52017-09-22 12:12:30 -0700264 return false;
265 }
266
Mirko Bonadei675513b2017-11-09 11:09:25 +0100267 RTC_LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
268 << " send cipher_suite " << send_cs << " recv cipher_suite "
269 << recv_cs;
Zhi Huangcf990f52017-09-22 12:12:30 -0700270
271 return true;
272}
273
274bool SrtpTransport::IsActive() const {
275 return send_session_ && recv_session_;
276}
277
278void SrtpTransport::ResetParams() {
279 send_session_ = nullptr;
280 recv_session_ = nullptr;
281 send_rtcp_session_ = nullptr;
282 recv_rtcp_session_ = nullptr;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100283 RTC_LOG(LS_INFO) << "The params in SRTP transport are reset.";
Zhi Huangcf990f52017-09-22 12:12:30 -0700284}
285
Zhi Huangcf990f52017-09-22 12:12:30 -0700286void SrtpTransport::CreateSrtpSessions() {
287 send_session_.reset(new cricket::SrtpSession());
288 recv_session_.reset(new cricket::SrtpSession());
289
290 if (external_auth_enabled_) {
291 send_session_->EnableExternalAuth();
292 }
293}
294
295bool SrtpTransport::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
296 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100297 RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700298 return false;
299 }
300 RTC_CHECK(send_session_);
301 return send_session_->ProtectRtp(p, in_len, max_len, out_len);
302}
303
304bool SrtpTransport::ProtectRtp(void* p,
305 int in_len,
306 int max_len,
307 int* out_len,
308 int64_t* index) {
309 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100310 RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700311 return false;
312 }
313 RTC_CHECK(send_session_);
314 return send_session_->ProtectRtp(p, in_len, max_len, out_len, index);
315}
316
317bool SrtpTransport::ProtectRtcp(void* p,
318 int in_len,
319 int max_len,
320 int* out_len) {
321 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100322 RTC_LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700323 return false;
324 }
325 if (send_rtcp_session_) {
326 return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
327 } else {
328 RTC_CHECK(send_session_);
329 return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
330 }
331}
332
333bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) {
334 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100335 RTC_LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700336 return false;
337 }
338 RTC_CHECK(recv_session_);
339 return recv_session_->UnprotectRtp(p, in_len, out_len);
340}
341
342bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) {
343 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100344 RTC_LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700345 return false;
346 }
347 if (recv_rtcp_session_) {
348 return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
349 } else {
350 RTC_CHECK(recv_session_);
351 return recv_session_->UnprotectRtcp(p, in_len, out_len);
352 }
353}
354
355bool SrtpTransport::GetRtpAuthParams(uint8_t** key,
356 int* key_len,
357 int* tag_len) {
358 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100359 RTC_LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700360 return false;
361 }
362
363 RTC_CHECK(send_session_);
364 return send_session_->GetRtpAuthParams(key, key_len, tag_len);
365}
366
367bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const {
368 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100369 RTC_LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700370 return false;
371 }
372
373 RTC_CHECK(send_session_);
374 *srtp_overhead = send_session_->GetSrtpOverhead();
375 return true;
376}
377
378void SrtpTransport::EnableExternalAuth() {
379 RTC_DCHECK(!IsActive());
380 external_auth_enabled_ = true;
381}
382
383bool SrtpTransport::IsExternalAuthEnabled() const {
384 return external_auth_enabled_;
385}
386
387bool SrtpTransport::IsExternalAuthActive() const {
388 if (!IsActive()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100389 RTC_LOG(LS_WARNING)
390 << "Failed to check IsExternalAuthActive: SRTP not active";
Zhi Huangcf990f52017-09-22 12:12:30 -0700391 return false;
392 }
393
394 RTC_CHECK(send_session_);
395 return send_session_->IsExternalAuthActive();
396}
397
zstein398c3fd2017-07-19 13:38:02 -0700398} // namespace webrtc