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