blob: 0270da27fa82e3a57581b816c6af251f1c28d9fd [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)
29 : content_name_(content_name),
30 rtp_transport_(rtc::MakeUnique<RtpTransport>(rtcp_mux_enabled)) {
31 ConnectToRtpTransport();
32}
33
34SrtpTransport::SrtpTransport(std::unique_ptr<RtpTransportInternal> transport,
35 const std::string& content_name)
36 : content_name_(content_name), rtp_transport_(std::move(transport)) {
37 ConnectToRtpTransport();
38}
39
40void SrtpTransport::ConnectToRtpTransport() {
41 rtp_transport_->SignalPacketReceived.connect(
42 this, &SrtpTransport::OnPacketReceived);
43 rtp_transport_->SignalReadyToSend.connect(this,
44 &SrtpTransport::OnReadyToSend);
45}
46
Zhi Huangcf990f52017-09-22 12:12:30 -070047bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
48 const rtc::PacketOptions& options,
49 int flags) {
50 return SendPacket(false, packet, options, flags);
51}
52
53bool SrtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
54 const rtc::PacketOptions& options,
55 int flags) {
56 return SendPacket(true, packet, options, flags);
57}
58
zstein398c3fd2017-07-19 13:38:02 -070059bool SrtpTransport::SendPacket(bool rtcp,
60 rtc::CopyOnWriteBuffer* packet,
61 const rtc::PacketOptions& options,
62 int flags) {
Zhi Huangcf990f52017-09-22 12:12:30 -070063 if (!IsActive()) {
64 LOG(LS_ERROR)
65 << "Failed to send the packet because SRTP transport is inactive.";
66 return false;
67 }
zstein398c3fd2017-07-19 13:38:02 -070068
Zhi Huangcf990f52017-09-22 12:12:30 -070069 rtc::PacketOptions updated_options = options;
70 rtc::CopyOnWriteBuffer cp = *packet;
71 TRACE_EVENT0("webrtc", "SRTP Encode");
72 bool res;
73 uint8_t* data = packet->data();
74 int len = static_cast<int>(packet->size());
75 if (!rtcp) {
76// If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
77// inside libsrtp for a RTP packet. A external HMAC module will be writing
78// a fake HMAC value. This is ONLY done for a RTP packet.
79// Socket layer will update rtp sendtime extension header if present in
80// packet with current time before updating the HMAC.
81#if !defined(ENABLE_EXTERNAL_AUTH)
82 res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
83#else
84 if (!IsExternalAuthActive()) {
85 res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
86 } else {
87 updated_options.packet_time_params.rtp_sendtime_extension_id =
88 rtp_abs_sendtime_extn_id_;
89 res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len,
90 &updated_options.packet_time_params.srtp_packet_index);
91 // If protection succeeds, let's get auth params from srtp.
92 if (res) {
93 uint8_t* auth_key = NULL;
94 int key_len;
95 res = GetRtpAuthParams(
96 &auth_key, &key_len,
97 &updated_options.packet_time_params.srtp_auth_tag_len);
98 if (res) {
99 updated_options.packet_time_params.srtp_auth_key.resize(key_len);
100 updated_options.packet_time_params.srtp_auth_key.assign(
101 auth_key, auth_key + key_len);
102 }
103 }
104 }
105#endif
106 if (!res) {
107 int seq_num = -1;
108 uint32_t ssrc = 0;
109 cricket::GetRtpSeqNum(data, len, &seq_num);
110 cricket::GetRtpSsrc(data, len, &ssrc);
111 LOG(LS_ERROR) << "Failed to protect " << content_name_
112 << " RTP packet: size=" << len << ", seqnum=" << seq_num
113 << ", SSRC=" << ssrc;
114 return false;
115 }
116 } else {
117 res = ProtectRtcp(data, len, static_cast<int>(packet->capacity()), &len);
118 if (!res) {
119 int type = -1;
120 cricket::GetRtcpType(data, len, &type);
121 LOG(LS_ERROR) << "Failed to protect " << content_name_
122 << " RTCP packet: size=" << len << ", type=" << type;
123 return false;
124 }
125 }
126
127 // Update the length of the packet now that we've added the auth tag.
128 packet->SetSize(len);
129 return rtcp ? rtp_transport_->SendRtcpPacket(packet, updated_options, flags)
130 : rtp_transport_->SendRtpPacket(packet, updated_options, flags);
zstein398c3fd2017-07-19 13:38:02 -0700131}
132
133void SrtpTransport::OnPacketReceived(bool rtcp,
134 rtc::CopyOnWriteBuffer* packet,
135 const rtc::PacketTime& packet_time) {
Zhi Huangcf990f52017-09-22 12:12:30 -0700136 if (!IsActive()) {
137 LOG(LS_WARNING) << "Inactive SRTP transport received a packet. Drop it.";
138 return;
139 }
zstein398c3fd2017-07-19 13:38:02 -0700140
Zhi Huangcf990f52017-09-22 12:12:30 -0700141 TRACE_EVENT0("webrtc", "SRTP Decode");
142 char* data = packet->data<char>();
143 int len = static_cast<int>(packet->size());
144 bool res;
145 if (!rtcp) {
146 res = UnprotectRtp(data, len, &len);
147 if (!res) {
148 int seq_num = -1;
149 uint32_t ssrc = 0;
150 cricket::GetRtpSeqNum(data, len, &seq_num);
151 cricket::GetRtpSsrc(data, len, &ssrc);
152 LOG(LS_ERROR) << "Failed to unprotect " << content_name_
153 << " RTP packet: size=" << len << ", seqnum=" << seq_num
154 << ", SSRC=" << ssrc;
155 return;
156 }
157 } else {
158 res = UnprotectRtcp(data, len, &len);
159 if (!res) {
160 int type = -1;
161 cricket::GetRtcpType(data, len, &type);
162 LOG(LS_ERROR) << "Failed to unprotect " << content_name_
163 << " RTCP packet: size=" << len << ", type=" << type;
164 return;
165 }
166 }
167
168 packet->SetSize(len);
zstein398c3fd2017-07-19 13:38:02 -0700169 SignalPacketReceived(rtcp, packet, packet_time);
170}
171
Zhi Huangcf990f52017-09-22 12:12:30 -0700172bool SrtpTransport::SetRtpParams(int send_cs,
173 const uint8_t* send_key,
174 int send_key_len,
175 int recv_cs,
176 const uint8_t* recv_key,
177 int recv_key_len) {
178 // If parameters are being set for the first time, we should create new SRTP
179 // sessions and call "SetSend/SetRecv". Otherwise we should call
180 // "UpdateSend"/"UpdateRecv" on the existing sessions, which will internally
181 // call "srtp_update".
182 bool new_sessions = false;
183 if (!send_session_) {
184 RTC_DCHECK(!recv_session_);
185 CreateSrtpSessions();
186 new_sessions = true;
187 }
188 send_session_->SetEncryptedHeaderExtensionIds(
189 send_encrypted_header_extension_ids_);
190 bool ret = new_sessions
191 ? send_session_->SetSend(send_cs, send_key, send_key_len)
192 : send_session_->UpdateSend(send_cs, send_key, send_key_len);
193 if (!ret) {
194 ResetParams();
195 return false;
196 }
197
198 recv_session_->SetEncryptedHeaderExtensionIds(
199 recv_encrypted_header_extension_ids_);
200 ret = new_sessions
201 ? recv_session_->SetRecv(recv_cs, recv_key, recv_key_len)
202 : recv_session_->UpdateRecv(recv_cs, recv_key, recv_key_len);
203 if (!ret) {
204 ResetParams();
205 return false;
206 }
207
Zhi Huangef48df92017-10-22 16:17:47 -0700208 LOG(LS_INFO) << "SRTP " << (new_sessions ? "activated" : "updated")
Zhi Huangcf990f52017-09-22 12:12:30 -0700209 << " with negotiated parameters:"
210 << " send cipher_suite " << send_cs << " recv cipher_suite "
211 << recv_cs;
212 return true;
213}
214
215bool SrtpTransport::SetRtcpParams(int send_cs,
216 const uint8_t* send_key,
217 int send_key_len,
218 int recv_cs,
219 const uint8_t* recv_key,
220 int recv_key_len) {
221 // This can only be called once, but can be safely called after
222 // SetRtpParams
223 if (send_rtcp_session_ || recv_rtcp_session_) {
224 LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
225 return false;
226 }
227
228 send_rtcp_session_.reset(new cricket::SrtpSession());
Zhi Huangef48df92017-10-22 16:17:47 -0700229 if (!send_rtcp_session_->SetSend(send_cs, send_key, send_key_len)) {
Zhi Huangcf990f52017-09-22 12:12:30 -0700230 return false;
231 }
232
233 recv_rtcp_session_.reset(new cricket::SrtpSession());
234 if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len)) {
235 return false;
236 }
237
238 LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
239 << " send cipher_suite " << send_cs << " recv cipher_suite "
240 << recv_cs;
241
242 return true;
243}
244
245bool SrtpTransport::IsActive() const {
246 return send_session_ && recv_session_;
247}
248
249void SrtpTransport::ResetParams() {
250 send_session_ = nullptr;
251 recv_session_ = nullptr;
252 send_rtcp_session_ = nullptr;
253 recv_rtcp_session_ = nullptr;
254 LOG(LS_INFO) << "The params in SRTP transport are reset.";
255}
256
257void SrtpTransport::SetEncryptedHeaderExtensionIds(
258 cricket::ContentSource source,
259 const std::vector<int>& extension_ids) {
260 if (source == cricket::CS_LOCAL) {
261 recv_encrypted_header_extension_ids_ = extension_ids;
262 } else {
263 send_encrypted_header_extension_ids_ = extension_ids;
264 }
265}
266
267void SrtpTransport::CreateSrtpSessions() {
268 send_session_.reset(new cricket::SrtpSession());
269 recv_session_.reset(new cricket::SrtpSession());
270
271 if (external_auth_enabled_) {
272 send_session_->EnableExternalAuth();
273 }
274}
275
276bool SrtpTransport::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
277 if (!IsActive()) {
278 LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
279 return false;
280 }
281 RTC_CHECK(send_session_);
282 return send_session_->ProtectRtp(p, in_len, max_len, out_len);
283}
284
285bool SrtpTransport::ProtectRtp(void* p,
286 int in_len,
287 int max_len,
288 int* out_len,
289 int64_t* index) {
290 if (!IsActive()) {
291 LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
292 return false;
293 }
294 RTC_CHECK(send_session_);
295 return send_session_->ProtectRtp(p, in_len, max_len, out_len, index);
296}
297
298bool SrtpTransport::ProtectRtcp(void* p,
299 int in_len,
300 int max_len,
301 int* out_len) {
302 if (!IsActive()) {
303 LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
304 return false;
305 }
306 if (send_rtcp_session_) {
307 return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
308 } else {
309 RTC_CHECK(send_session_);
310 return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
311 }
312}
313
314bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) {
315 if (!IsActive()) {
316 LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
317 return false;
318 }
319 RTC_CHECK(recv_session_);
320 return recv_session_->UnprotectRtp(p, in_len, out_len);
321}
322
323bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) {
324 if (!IsActive()) {
325 LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
326 return false;
327 }
328 if (recv_rtcp_session_) {
329 return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
330 } else {
331 RTC_CHECK(recv_session_);
332 return recv_session_->UnprotectRtcp(p, in_len, out_len);
333 }
334}
335
336bool SrtpTransport::GetRtpAuthParams(uint8_t** key,
337 int* key_len,
338 int* tag_len) {
339 if (!IsActive()) {
340 LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
341 return false;
342 }
343
344 RTC_CHECK(send_session_);
345 return send_session_->GetRtpAuthParams(key, key_len, tag_len);
346}
347
348bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const {
349 if (!IsActive()) {
350 LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active";
351 return false;
352 }
353
354 RTC_CHECK(send_session_);
355 *srtp_overhead = send_session_->GetSrtpOverhead();
356 return true;
357}
358
359void SrtpTransport::EnableExternalAuth() {
360 RTC_DCHECK(!IsActive());
361 external_auth_enabled_ = true;
362}
363
364bool SrtpTransport::IsExternalAuthEnabled() const {
365 return external_auth_enabled_;
366}
367
368bool SrtpTransport::IsExternalAuthActive() const {
369 if (!IsActive()) {
370 LOG(LS_WARNING) << "Failed to check IsExternalAuthActive: SRTP not active";
371 return false;
372 }
373
374 RTC_CHECK(send_session_);
375 return send_session_->IsExternalAuthActive();
376}
377
zstein398c3fd2017-07-19 13:38:02 -0700378} // namespace webrtc