Chromium Code Reviews| 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 |