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