blob: c3dfd32464ded2579a194c01d7ec1da8102f6dd5 [file] [log] [blame]
Zhi Huange818b6e2018-02-22 23:26:271/*
2 * Copyright 2018 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
Zhi Huang365381f2018-04-13 23:44:3411#include "pc/jseptransport.h"
Zhi Huange818b6e2018-02-22 23:26:2712
13#include <memory>
14#include <utility> // for std::pair
15
Karl Wiberg918f50c2018-07-05 09:40:3316#include "absl/memory/memory.h"
Zhi Huange818b6e2018-02-22 23:26:2717#include "api/candidate.h"
18#include "p2p/base/p2pconstants.h"
19#include "p2p/base/p2ptransportchannel.h"
20#include "p2p/base/port.h"
21#include "rtc_base/bind.h"
22#include "rtc_base/checks.h"
23#include "rtc_base/logging.h"
Zhi Huang365381f2018-04-13 23:44:3424#include "rtc_base/strings/string_builder.h"
Zhi Huange818b6e2018-02-22 23:26:2725
26using webrtc::SdpType;
27
28namespace cricket {
29
30static bool VerifyIceParams(const JsepTransportDescription& jsep_description) {
31 // For legacy protocols.
32 // TODO(zhihuang): Remove this once the legacy protocol is no longer
33 // supported.
34 if (jsep_description.transport_desc.ice_ufrag.empty() &&
35 jsep_description.transport_desc.ice_pwd.empty()) {
36 return true;
37 }
38
39 if (jsep_description.transport_desc.ice_ufrag.length() <
40 ICE_UFRAG_MIN_LENGTH ||
41 jsep_description.transport_desc.ice_ufrag.length() >
42 ICE_UFRAG_MAX_LENGTH) {
43 return false;
44 }
45 if (jsep_description.transport_desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
46 jsep_description.transport_desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
47 return false;
48 }
49 return true;
50}
51
52JsepTransportDescription::JsepTransportDescription() {}
53
54JsepTransportDescription::JsepTransportDescription(
55 bool rtcp_mux_enabled,
56 const std::vector<CryptoParams>& cryptos,
57 const std::vector<int>& encrypted_header_extension_ids,
Zhi Huange830e682018-03-30 17:48:3558 int rtp_abs_sendtime_extn_id,
Zhi Huange818b6e2018-02-22 23:26:2759 const TransportDescription& transport_desc)
60 : rtcp_mux_enabled(rtcp_mux_enabled),
61 cryptos(cryptos),
62 encrypted_header_extension_ids(encrypted_header_extension_ids),
Zhi Huange830e682018-03-30 17:48:3563 rtp_abs_sendtime_extn_id(rtp_abs_sendtime_extn_id),
Zhi Huange818b6e2018-02-22 23:26:2764 transport_desc(transport_desc) {}
65
66JsepTransportDescription::JsepTransportDescription(
67 const JsepTransportDescription& from)
68 : rtcp_mux_enabled(from.rtcp_mux_enabled),
69 cryptos(from.cryptos),
70 encrypted_header_extension_ids(from.encrypted_header_extension_ids),
Zhi Huange830e682018-03-30 17:48:3571 rtp_abs_sendtime_extn_id(from.rtp_abs_sendtime_extn_id),
Zhi Huange818b6e2018-02-22 23:26:2772 transport_desc(from.transport_desc) {}
73
74JsepTransportDescription::~JsepTransportDescription() = default;
75
76JsepTransportDescription& JsepTransportDescription::operator=(
77 const JsepTransportDescription& from) {
78 if (this == &from) {
79 return *this;
80 }
81 rtcp_mux_enabled = from.rtcp_mux_enabled;
82 cryptos = from.cryptos;
83 encrypted_header_extension_ids = from.encrypted_header_extension_ids;
Zhi Huange830e682018-03-30 17:48:3584 rtp_abs_sendtime_extn_id = from.rtp_abs_sendtime_extn_id;
Zhi Huange818b6e2018-02-22 23:26:2785 transport_desc = from.transport_desc;
86
87 return *this;
88}
89
Zhi Huang365381f2018-04-13 23:44:3490JsepTransport::JsepTransport(
Zhi Huange818b6e2018-02-22 23:26:2791 const std::string& mid,
92 const rtc::scoped_refptr<rtc::RTCCertificate>& local_certificate,
93 std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
94 std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
95 std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
96 std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
97 std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport)
98 : mid_(mid),
99 local_certificate_(local_certificate),
100 rtp_dtls_transport_(std::move(rtp_dtls_transport)),
101 rtcp_dtls_transport_(std::move(rtcp_dtls_transport)) {
102 RTC_DCHECK(rtp_dtls_transport_);
103 if (unencrypted_rtp_transport) {
104 RTC_DCHECK(!sdes_transport);
105 RTC_DCHECK(!dtls_srtp_transport);
106 unencrypted_rtp_transport_ = std::move(unencrypted_rtp_transport);
107 } else if (sdes_transport) {
108 RTC_DCHECK(!unencrypted_rtp_transport);
109 RTC_DCHECK(!dtls_srtp_transport);
110 sdes_transport_ = std::move(sdes_transport);
111 } else {
112 RTC_DCHECK(dtls_srtp_transport);
113 RTC_DCHECK(!unencrypted_rtp_transport);
114 RTC_DCHECK(!sdes_transport);
115 dtls_srtp_transport_ = std::move(dtls_srtp_transport);
116 }
117}
118
Zhi Huang365381f2018-04-13 23:44:34119JsepTransport::~JsepTransport() {}
Zhi Huange818b6e2018-02-22 23:26:27120
Zhi Huang365381f2018-04-13 23:44:34121webrtc::RTCError JsepTransport::SetLocalJsepTransportDescription(
Zhi Huange818b6e2018-02-22 23:26:27122 const JsepTransportDescription& jsep_description,
123 SdpType type) {
124 webrtc::RTCError error;
125
126 if (!VerifyIceParams(jsep_description)) {
127 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
128 "Invalid ice-ufrag or ice-pwd length.");
129 }
130
131 if (!SetRtcpMux(jsep_description.rtcp_mux_enabled, type,
132 ContentSource::CS_LOCAL)) {
133 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
134 "Failed to setup RTCP mux.");
135 }
136
137 // If doing SDES, setup the SDES crypto parameters.
138 if (sdes_transport_) {
139 RTC_DCHECK(!unencrypted_rtp_transport_);
140 RTC_DCHECK(!dtls_srtp_transport_);
141 if (!SetSdes(jsep_description.cryptos,
142 jsep_description.encrypted_header_extension_ids, type,
143 ContentSource::CS_LOCAL)) {
144 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
145 "Failed to setup SDES crypto parameters.");
146 }
147 } else if (dtls_srtp_transport_) {
148 RTC_DCHECK(!unencrypted_rtp_transport_);
149 RTC_DCHECK(!sdes_transport_);
150 dtls_srtp_transport_->UpdateRecvEncryptedHeaderExtensionIds(
151 jsep_description.encrypted_header_extension_ids);
152 }
153
154 bool ice_restarting =
155 local_description_ != nullptr &&
156 IceCredentialsChanged(local_description_->transport_desc.ice_ufrag,
157 local_description_->transport_desc.ice_pwd,
158 jsep_description.transport_desc.ice_ufrag,
159 jsep_description.transport_desc.ice_pwd);
160 local_description_.reset(new JsepTransportDescription(jsep_description));
161
162 rtc::SSLFingerprint* local_fp =
163 local_description_->transport_desc.identity_fingerprint.get();
164
165 if (!local_fp) {
166 local_certificate_ = nullptr;
167 } else {
168 error = VerifyCertificateFingerprint(local_certificate_.get(), local_fp);
169 if (!error.ok()) {
170 local_description_.reset();
171 return error;
172 }
173 }
174
175 SetLocalIceParameters(rtp_dtls_transport_->ice_transport());
176
177 if (rtcp_dtls_transport_) {
178 SetLocalIceParameters(rtcp_dtls_transport_->ice_transport());
179 }
180
181 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
182 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
183 error = NegotiateAndSetDtlsParameters(type);
184 }
185 if (!error.ok()) {
186 local_description_.reset();
187 return error;
188 }
189
190 if (needs_ice_restart_ && ice_restarting) {
191 needs_ice_restart_ = false;
192 RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag cleared for transport "
193 << mid();
194 }
195
196 return webrtc::RTCError::OK();
197}
198
Zhi Huang365381f2018-04-13 23:44:34199webrtc::RTCError JsepTransport::SetRemoteJsepTransportDescription(
Zhi Huange818b6e2018-02-22 23:26:27200 const JsepTransportDescription& jsep_description,
201 webrtc::SdpType type) {
202 webrtc::RTCError error;
203
204 if (!VerifyIceParams(jsep_description)) {
205 remote_description_.reset();
206 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
207 "Invalid ice-ufrag or ice-pwd length.");
208 }
209
210 if (!SetRtcpMux(jsep_description.rtcp_mux_enabled, type,
211 ContentSource::CS_REMOTE)) {
212 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
213 "Failed to setup RTCP mux.");
214 }
215
216 // If doing SDES, setup the SDES crypto parameters.
217 if (sdes_transport_) {
218 RTC_DCHECK(!unencrypted_rtp_transport_);
219 RTC_DCHECK(!dtls_srtp_transport_);
220 if (!SetSdes(jsep_description.cryptos,
221 jsep_description.encrypted_header_extension_ids, type,
222 ContentSource::CS_REMOTE)) {
223 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
224 "Failed to setup SDES crypto parameters.");
225 }
Zhi Huange830e682018-03-30 17:48:35226 sdes_transport_->CacheRtpAbsSendTimeHeaderExtension(
227 jsep_description.rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 23:26:27228 } else if (dtls_srtp_transport_) {
229 RTC_DCHECK(!unencrypted_rtp_transport_);
230 RTC_DCHECK(!sdes_transport_);
231 dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds(
232 jsep_description.encrypted_header_extension_ids);
Zhi Huange830e682018-03-30 17:48:35233 dtls_srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
234 jsep_description.rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 23:26:27235 }
236
237 remote_description_.reset(new JsepTransportDescription(jsep_description));
238 SetRemoteIceParameters(rtp_dtls_transport_->ice_transport());
239
240 if (rtcp_dtls_transport_) {
241 SetRemoteIceParameters(rtcp_dtls_transport_->ice_transport());
242 }
243
244 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
245 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
246 error = NegotiateAndSetDtlsParameters(SdpType::kOffer);
247 }
248 if (!error.ok()) {
249 remote_description_.reset();
250 return error;
251 }
252 return webrtc::RTCError::OK();
253}
254
Zhi Huang365381f2018-04-13 23:44:34255webrtc::RTCError JsepTransport::AddRemoteCandidates(
Zhi Huange818b6e2018-02-22 23:26:27256 const Candidates& candidates) {
Henrik Boström5d8f8fa2018-04-13 15:22:50257 if (!local_description_ || !remote_description_) {
Zhi Huange818b6e2018-02-22 23:26:27258 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE,
259 mid() +
260 " is not ready to use the remote candidate "
Henrik Boström5d8f8fa2018-04-13 15:22:50261 "because the local or remote description is "
262 "not set.");
Zhi Huange818b6e2018-02-22 23:26:27263 }
264
265 for (const cricket::Candidate& candidate : candidates) {
266 auto transport =
267 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
268 ? rtp_dtls_transport_.get()
269 : rtcp_dtls_transport_.get();
270 if (!transport) {
271 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
272 "Candidate has an unknown component: " +
273 candidate.ToString() + " for mid " + mid());
274 }
275 transport->ice_transport()->AddRemoteCandidate(candidate);
276 }
277 return webrtc::RTCError::OK();
278}
279
Zhi Huang365381f2018-04-13 23:44:34280void JsepTransport::SetNeedsIceRestartFlag() {
Zhi Huange818b6e2018-02-22 23:26:27281 if (!needs_ice_restart_) {
282 needs_ice_restart_ = true;
283 RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag set for transport " << mid();
284 }
285}
286
Danil Chapovalov66cadcc2018-06-19 14:47:43287absl::optional<rtc::SSLRole> JsepTransport::GetDtlsRole() const {
Zhi Huange818b6e2018-02-22 23:26:27288 RTC_DCHECK(rtp_dtls_transport_);
289 rtc::SSLRole dtls_role;
290 if (!rtp_dtls_transport_->GetDtlsRole(&dtls_role)) {
Danil Chapovalov66cadcc2018-06-19 14:47:43291 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 23:26:27292 }
293
Danil Chapovalov66cadcc2018-06-19 14:47:43294 return absl::optional<rtc::SSLRole>(dtls_role);
Zhi Huange818b6e2018-02-22 23:26:27295}
296
Zhi Huang365381f2018-04-13 23:44:34297bool JsepTransport::GetStats(TransportStats* stats) {
Zhi Huange818b6e2018-02-22 23:26:27298 stats->transport_name = mid();
299 stats->channel_stats.clear();
300 bool ret = GetTransportStats(rtp_dtls_transport_.get(), stats);
301 if (rtcp_dtls_transport_) {
302 ret &= GetTransportStats(rtcp_dtls_transport_.get(), stats);
303 }
304 return ret;
305}
306
Zhi Huang365381f2018-04-13 23:44:34307webrtc::RTCError JsepTransport::VerifyCertificateFingerprint(
Zhi Huange818b6e2018-02-22 23:26:27308 const rtc::RTCCertificate* certificate,
309 const rtc::SSLFingerprint* fingerprint) const {
310 if (!fingerprint) {
311 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
312 "No fingerprint");
313 }
314 if (!certificate) {
315 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
316 "Fingerprint provided but no identity available.");
317 }
318 std::unique_ptr<rtc::SSLFingerprint> fp_tmp(rtc::SSLFingerprint::Create(
319 fingerprint->algorithm, certificate->identity()));
320 RTC_DCHECK(fp_tmp.get() != NULL);
321 if (*fp_tmp == *fingerprint) {
322 return webrtc::RTCError::OK();
323 }
Zhi Huang365381f2018-04-13 23:44:34324 char ss_buf[1024];
325 rtc::SimpleStringBuilder desc(ss_buf);
Zhi Huange818b6e2018-02-22 23:26:27326 desc << "Local fingerprint does not match identity. Expected: ";
327 desc << fp_tmp->ToString();
328 desc << " Got: " << fingerprint->ToString();
Zhi Huang365381f2018-04-13 23:44:34329 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
330 std::string(desc.str()));
Zhi Huange818b6e2018-02-22 23:26:27331}
332
Zhi Huangb57e1692018-06-12 18:41:11333void JsepTransport::SetActiveResetSrtpParams(bool active_reset_srtp_params) {
334 if (dtls_srtp_transport_) {
335 RTC_LOG(INFO)
336 << "Setting active_reset_srtp_params of DtlsSrtpTransport to: "
337 << active_reset_srtp_params;
338 dtls_srtp_transport_->SetActiveResetSrtpParams(active_reset_srtp_params);
339 }
340}
341
Zhi Huang365381f2018-04-13 23:44:34342void JsepTransport::SetLocalIceParameters(IceTransportInternal* ice_transport) {
Zhi Huange818b6e2018-02-22 23:26:27343 RTC_DCHECK(ice_transport);
344 RTC_DCHECK(local_description_);
345 ice_transport->SetIceParameters(
346 local_description_->transport_desc.GetIceParameters());
347}
348
Zhi Huang365381f2018-04-13 23:44:34349void JsepTransport::SetRemoteIceParameters(
Zhi Huange818b6e2018-02-22 23:26:27350 IceTransportInternal* ice_transport) {
351 RTC_DCHECK(ice_transport);
352 RTC_DCHECK(remote_description_);
353 ice_transport->SetRemoteIceParameters(
354 remote_description_->transport_desc.GetIceParameters());
355 ice_transport->SetRemoteIceMode(remote_description_->transport_desc.ice_mode);
356}
357
Zhi Huang365381f2018-04-13 23:44:34358webrtc::RTCError JsepTransport::SetNegotiatedDtlsParameters(
Zhi Huange818b6e2018-02-22 23:26:27359 DtlsTransportInternal* dtls_transport,
Danil Chapovalov66cadcc2018-06-19 14:47:43360 absl::optional<rtc::SSLRole> dtls_role,
Zhi Huange818b6e2018-02-22 23:26:27361 rtc::SSLFingerprint* remote_fingerprint) {
362 RTC_DCHECK(dtls_transport);
363 // Set SSL role. Role must be set before fingerprint is applied, which
364 // initiates DTLS setup.
365 if (dtls_role && !dtls_transport->SetDtlsRole(*dtls_role)) {
366 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
367 "Failed to set SSL role for the transport.");
368 }
369 // Apply remote fingerprint.
370 if (!remote_fingerprint ||
371 !dtls_transport->SetRemoteFingerprint(
372 remote_fingerprint->algorithm,
373 reinterpret_cast<const uint8_t*>(remote_fingerprint->digest.data()),
374 remote_fingerprint->digest.size())) {
375 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
376 "Failed to apply remote fingerprint.");
377 }
378 return webrtc::RTCError::OK();
379}
380
Zhi Huang365381f2018-04-13 23:44:34381bool JsepTransport::SetRtcpMux(bool enable,
382 webrtc::SdpType type,
383 ContentSource source) {
Zhi Huange818b6e2018-02-22 23:26:27384 bool ret = false;
385 switch (type) {
386 case SdpType::kOffer:
387 ret = rtcp_mux_negotiator_.SetOffer(enable, source);
388 break;
389 case SdpType::kPrAnswer:
390 // This may activate RTCP muxing, but we don't yet destroy the transport
391 // because the final answer may deactivate it.
392 ret = rtcp_mux_negotiator_.SetProvisionalAnswer(enable, source);
393 break;
394 case SdpType::kAnswer:
395 ret = rtcp_mux_negotiator_.SetAnswer(enable, source);
396 if (ret && rtcp_mux_negotiator_.IsActive()) {
397 ActivateRtcpMux();
398 }
399 break;
400 default:
401 RTC_NOTREACHED();
402 }
403
404 if (!ret) {
405 return false;
406 }
407
408 auto transport = rtp_transport();
409 transport->SetRtcpMuxEnabled(rtcp_mux_negotiator_.IsActive());
410 return ret;
411}
412
Zhi Huang365381f2018-04-13 23:44:34413void JsepTransport::ActivateRtcpMux() {
Zhi Huange818b6e2018-02-22 23:26:27414 if (unencrypted_rtp_transport_) {
415 RTC_DCHECK(!sdes_transport_);
416 RTC_DCHECK(!dtls_srtp_transport_);
417 unencrypted_rtp_transport_->SetRtcpPacketTransport(nullptr);
418 } else if (sdes_transport_) {
419 RTC_DCHECK(!unencrypted_rtp_transport_);
420 RTC_DCHECK(!dtls_srtp_transport_);
421 sdes_transport_->SetRtcpPacketTransport(nullptr);
422 } else {
423 RTC_DCHECK(dtls_srtp_transport_);
424 RTC_DCHECK(!unencrypted_rtp_transport_);
425 RTC_DCHECK(!sdes_transport_);
426 dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport(),
427 /*rtcp_dtls_transport=*/nullptr);
428 }
429 rtcp_dtls_transport_.reset();
430 // Notify the JsepTransportController to update the aggregate states.
431 SignalRtcpMuxActive();
432}
433
Zhi Huang365381f2018-04-13 23:44:34434bool JsepTransport::SetSdes(const std::vector<CryptoParams>& cryptos,
435 const std::vector<int>& encrypted_extension_ids,
436 webrtc::SdpType type,
437 ContentSource source) {
Zhi Huange818b6e2018-02-22 23:26:27438 bool ret = false;
439 ret = sdes_negotiator_.Process(cryptos, type, source);
440 if (!ret) {
441 return ret;
442 }
443
444 if (source == ContentSource::CS_LOCAL) {
445 recv_extension_ids_ = std::move(encrypted_extension_ids);
446 } else {
447 send_extension_ids_ = std::move(encrypted_extension_ids);
448 }
449
450 // If setting an SDES answer succeeded, apply the negotiated parameters
451 // to the SRTP transport.
452 if ((type == SdpType::kPrAnswer || type == SdpType::kAnswer) && ret) {
453 if (sdes_negotiator_.send_cipher_suite() &&
454 sdes_negotiator_.recv_cipher_suite()) {
455 RTC_DCHECK(send_extension_ids_);
456 RTC_DCHECK(recv_extension_ids_);
457 ret = sdes_transport_->SetRtpParams(
458 *(sdes_negotiator_.send_cipher_suite()),
459 sdes_negotiator_.send_key().data(),
460 static_cast<int>(sdes_negotiator_.send_key().size()),
461 *(send_extension_ids_), *(sdes_negotiator_.recv_cipher_suite()),
462 sdes_negotiator_.recv_key().data(),
463 static_cast<int>(sdes_negotiator_.recv_key().size()),
464 *(recv_extension_ids_));
465 } else {
466 RTC_LOG(LS_INFO) << "No crypto keys are provided for SDES.";
467 if (type == SdpType::kAnswer) {
468 // Explicitly reset the |sdes_transport_| if no crypto param is
469 // provided in the answer. No need to call |ResetParams()| for
470 // |sdes_negotiator_| because it resets the params inside |SetAnswer|.
471 sdes_transport_->ResetParams();
472 }
473 }
474 }
475 return ret;
476}
477
Zhi Huang365381f2018-04-13 23:44:34478webrtc::RTCError JsepTransport::NegotiateAndSetDtlsParameters(
Zhi Huange818b6e2018-02-22 23:26:27479 SdpType local_description_type) {
480 if (!local_description_ || !remote_description_) {
481 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE,
482 "Applying an answer transport description "
483 "without applying any offer.");
484 }
485 std::unique_ptr<rtc::SSLFingerprint> remote_fingerprint;
Danil Chapovalov66cadcc2018-06-19 14:47:43486 absl::optional<rtc::SSLRole> negotiated_dtls_role;
Zhi Huange818b6e2018-02-22 23:26:27487
488 rtc::SSLFingerprint* local_fp =
489 local_description_->transport_desc.identity_fingerprint.get();
490 rtc::SSLFingerprint* remote_fp =
491 remote_description_->transport_desc.identity_fingerprint.get();
492 if (remote_fp && local_fp) {
Karl Wiberg918f50c2018-07-05 09:40:33493 remote_fingerprint = absl::make_unique<rtc::SSLFingerprint>(*remote_fp);
Zhi Huange818b6e2018-02-22 23:26:27494 webrtc::RTCError error =
495 NegotiateDtlsRole(local_description_type,
496 local_description_->transport_desc.connection_role,
497 remote_description_->transport_desc.connection_role,
498 &negotiated_dtls_role);
499 if (!error.ok()) {
500 return error;
501 }
502 } else if (local_fp && (local_description_type == SdpType::kAnswer)) {
503 return webrtc::RTCError(
504 webrtc::RTCErrorType::INVALID_PARAMETER,
505 "Local fingerprint supplied when caller didn't offer DTLS.");
506 } else {
507 // We are not doing DTLS
Karl Wiberg918f50c2018-07-05 09:40:33508 remote_fingerprint = absl::make_unique<rtc::SSLFingerprint>("", nullptr, 0);
Zhi Huange818b6e2018-02-22 23:26:27509 }
510 // Now that we have negotiated everything, push it downward.
511 // Note that we cache the result so that if we have race conditions
512 // between future SetRemote/SetLocal invocations and new transport
513 // creation, we have the negotiation state saved until a new
514 // negotiation happens.
515 webrtc::RTCError error = SetNegotiatedDtlsParameters(
516 rtp_dtls_transport_.get(), negotiated_dtls_role,
517 remote_fingerprint.get());
518 if (!error.ok()) {
519 return error;
520 }
521
522 if (rtcp_dtls_transport_) {
523 error = SetNegotiatedDtlsParameters(rtcp_dtls_transport_.get(),
524 negotiated_dtls_role,
525 remote_fingerprint.get());
526 }
527 return error;
528}
529
Zhi Huang365381f2018-04-13 23:44:34530webrtc::RTCError JsepTransport::NegotiateDtlsRole(
Zhi Huange818b6e2018-02-22 23:26:27531 SdpType local_description_type,
532 ConnectionRole local_connection_role,
533 ConnectionRole remote_connection_role,
Danil Chapovalov66cadcc2018-06-19 14:47:43534 absl::optional<rtc::SSLRole>* negotiated_dtls_role) {
Zhi Huange818b6e2018-02-22 23:26:27535 // From RFC 4145, section-4.1, The following are the values that the
536 // 'setup' attribute can take in an offer/answer exchange:
537 // Offer Answer
538 // ________________
539 // active passive / holdconn
540 // passive active / holdconn
541 // actpass active / passive / holdconn
542 // holdconn holdconn
543 //
544 // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
545 // The endpoint MUST use the setup attribute defined in [RFC4145].
546 // The endpoint that is the offerer MUST use the setup attribute
547 // value of setup:actpass and be prepared to receive a client_hello
548 // before it receives the answer. The answerer MUST use either a
549 // setup attribute value of setup:active or setup:passive. Note that
550 // if the answerer uses setup:passive, then the DTLS handshake will
551 // not begin until the answerer is received, which adds additional
552 // latency. setup:active allows the answer and the DTLS handshake to
553 // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever
554 // party is active MUST initiate a DTLS handshake by sending a
555 // ClientHello over each flow (host/port quartet).
556 // IOW - actpass and passive modes should be treated as server and
557 // active as client.
558 bool is_remote_server = false;
559 if (local_description_type == SdpType::kOffer) {
560 if (local_connection_role != CONNECTIONROLE_ACTPASS) {
561 return webrtc::RTCError(
562 webrtc::RTCErrorType::INVALID_PARAMETER,
563 "Offerer must use actpass value for setup attribute.");
564 }
565
566 if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
567 remote_connection_role == CONNECTIONROLE_PASSIVE ||
568 remote_connection_role == CONNECTIONROLE_NONE) {
569 is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
570 } else {
571 return webrtc::RTCError(
572 webrtc::RTCErrorType::INVALID_PARAMETER,
573 "Answerer must use either active or passive value "
574 "for setup attribute.");
575 }
576 // If remote is NONE or ACTIVE it will act as client.
577 } else {
578 if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
579 remote_connection_role != CONNECTIONROLE_NONE) {
580 // Accept a remote role attribute that's not "actpass", but matches the
581 // current negotiated role. This is allowed by dtls-sdp, though our
582 // implementation will never generate such an offer as it's not
583 // recommended.
584 //
585 // See https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-dtls-sdp,
586 // section 5.5.
587 auto current_dtls_role = GetDtlsRole();
588 if (!current_dtls_role ||
589 (*current_dtls_role == rtc::SSL_CLIENT &&
590 remote_connection_role == CONNECTIONROLE_ACTIVE) ||
591 (*current_dtls_role == rtc::SSL_SERVER &&
592 remote_connection_role == CONNECTIONROLE_PASSIVE)) {
593 return webrtc::RTCError(
594 webrtc::RTCErrorType::INVALID_PARAMETER,
595 "Offerer must use actpass value or current negotiated role for "
596 "setup attribute.");
597 }
598 }
599
600 if (local_connection_role == CONNECTIONROLE_ACTIVE ||
601 local_connection_role == CONNECTIONROLE_PASSIVE) {
602 is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
603 } else {
604 return webrtc::RTCError(
605 webrtc::RTCErrorType::INVALID_PARAMETER,
606 "Answerer must use either active or passive value "
607 "for setup attribute.");
608 }
609
610 // If local is passive, local will act as server.
611 }
612
613 *negotiated_dtls_role = (is_remote_server ? std::move(rtc::SSL_CLIENT)
614 : std::move(rtc::SSL_SERVER));
615 return webrtc::RTCError::OK();
616}
617
Zhi Huang365381f2018-04-13 23:44:34618bool JsepTransport::GetTransportStats(DtlsTransportInternal* dtls_transport,
619 TransportStats* stats) {
Zhi Huange818b6e2018-02-22 23:26:27620 RTC_DCHECK(dtls_transport);
621 TransportChannelStats substats;
622 substats.component = dtls_transport == rtcp_dtls_transport_.get()
623 ? ICE_CANDIDATE_COMPONENT_RTCP
624 : ICE_CANDIDATE_COMPONENT_RTP;
625 dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
626 dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
627 substats.dtls_state = dtls_transport->dtls_state();
628 if (!dtls_transport->ice_transport()->GetStats(
629 &substats.connection_infos, &substats.candidate_stats_list)) {
630 return false;
631 }
632 stats->channel_stats.push_back(substats);
633 return true;
634}
635
636} // namespace cricket