blob: 12aad7a3f07e64b7aa4a5d4d5c8b1ce34ead63dd [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 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
Taylor Brandstetter6e2e7ce2017-12-19 10:26:23 -080011#include "pc/jseptransport.h"
zhihuangb2cdd932017-01-19 16:54:25 -080012
jbauch555604a2016-04-26 03:13:22 -070013#include <memory>
deadbeefcbecd352015-09-23 11:50:27 -070014#include <utility> // for std::pair
15
Patrik Höglunde2d6a062017-10-05 14:53:33 +020016#include "api/candidate.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "p2p/base/p2pconstants.h"
18#include "p2p/base/p2ptransportchannel.h"
19#include "p2p/base/port.h"
20#include "rtc_base/bind.h"
21#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000023
Steve Anton3828c062017-12-06 10:34:51 -080024using webrtc::SdpType;
25
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000026namespace cricket {
27
Taylor Brandstetter6e2e7ce2017-12-19 10:26:23 -080028TransportChannelStats::TransportChannelStats() = default;
29
30TransportChannelStats::TransportChannelStats(const TransportChannelStats&) =
31 default;
32
33TransportChannelStats::~TransportChannelStats() = default;
34
35TransportStats::TransportStats() = default;
36
37TransportStats::~TransportStats() = default;
38
39bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
40 if (err_desc) {
41 *err_desc = desc;
42 }
43 RTC_LOG(LS_ERROR) << desc;
44 return false;
45}
46
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000047static bool VerifyIceParams(const TransportDescription& desc) {
48 // For legacy protocols.
49 if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
50 return true;
51
52 if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH ||
53 desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) {
54 return false;
55 }
56 if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
57 desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
58 return false;
59 }
60 return true;
61}
62
deadbeef49f34fd2016-12-06 16:22:06 -080063JsepTransport::JsepTransport(
64 const std::string& mid,
65 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate)
66 : mid_(mid), certificate_(certificate) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000067
Steve Antonf2737d22017-10-31 16:27:34 -070068JsepTransport::~JsepTransport() = default;
69
zhihuangb2cdd932017-01-19 16:54:25 -080070bool JsepTransport::AddChannel(DtlsTransportInternal* dtls, int component) {
deadbeef49f34fd2016-12-06 16:22:06 -080071 if (channels_.find(component) != channels_.end()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010072 RTC_LOG(LS_ERROR) << "Adding channel for component " << component
73 << " twice.";
deadbeef49f34fd2016-12-06 16:22:06 -080074 return false;
75 }
76 channels_[component] = dtls;
77 // Something's wrong if a channel is being added after a description is set.
78 // This may currently occur if rtcp-mux is negotiated, then a new m= section
79 // is added in a later offer/answer. But this is suboptimal and should be
80 // changed; we shouldn't support going from muxed to non-muxed.
81 // TODO(deadbeef): Once this is fixed, make the warning an error, and remove
82 // the calls to "ApplyXTransportDescription" below.
83 if (local_description_set_ || remote_description_set_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010084 RTC_LOG(LS_WARNING) << "Adding new transport channel after "
85 "transport description already applied.";
deadbeef49f34fd2016-12-06 16:22:06 -080086 }
87 bool ret = true;
88 std::string err;
89 if (local_description_set_) {
90 ret &= ApplyLocalTransportDescription(channels_[component], &err);
91 }
92 if (remote_description_set_) {
93 ret &= ApplyRemoteTransportDescription(channels_[component], &err);
94 }
95 if (local_description_set_ && remote_description_set_) {
96 ret &= ApplyNegotiatedTransportDescription(channels_[component], &err);
97 }
98 return ret;
99}
100
101bool JsepTransport::RemoveChannel(int component) {
102 auto it = channels_.find(component);
103 if (it == channels_.end()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100104 RTC_LOG(LS_ERROR) << "Trying to remove channel for component " << component
105 << ", which doesn't exist.";
deadbeef49f34fd2016-12-06 16:22:06 -0800106 return false;
107 }
108 channels_.erase(component);
109 return true;
110}
111
112bool JsepTransport::HasChannels() const {
113 return !channels_.empty();
114}
115
116void JsepTransport::SetLocalCertificate(
117 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
118 certificate_ = certificate;
119}
120
121bool JsepTransport::GetLocalCertificate(
122 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const {
123 if (!certificate_) {
124 return false;
125 }
126
127 *certificate = certificate_;
128 return true;
129}
130
131bool JsepTransport::SetLocalTransportDescription(
132 const TransportDescription& description,
Steve Anton3828c062017-12-06 10:34:51 -0800133 SdpType type,
deadbeef49f34fd2016-12-06 16:22:06 -0800134 std::string* error_desc) {
135 bool ret = true;
136
137 if (!VerifyIceParams(description)) {
138 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
139 error_desc);
140 }
141
deadbeefd1a38b52016-12-10 13:15:33 -0800142 bool ice_restarting =
143 local_description_set_ &&
144 IceCredentialsChanged(local_description_->ice_ufrag,
145 local_description_->ice_pwd, description.ice_ufrag,
146 description.ice_pwd);
deadbeef49f34fd2016-12-06 16:22:06 -0800147 local_description_.reset(new TransportDescription(description));
148
149 rtc::SSLFingerprint* local_fp =
150 local_description_->identity_fingerprint.get();
151
152 if (!local_fp) {
153 certificate_ = nullptr;
154 } else if (!VerifyCertificateFingerprint(certificate_.get(), local_fp,
155 error_desc)) {
156 return false;
157 }
158
159 for (const auto& kv : channels_) {
160 ret &= ApplyLocalTransportDescription(kv.second, error_desc);
161 }
162 if (!ret) {
163 return false;
164 }
165
166 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
Steve Anton3828c062017-12-06 10:34:51 -0800167 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
168 ret &= NegotiateTransportDescription(type, error_desc);
deadbeef49f34fd2016-12-06 16:22:06 -0800169 }
deadbeefd1a38b52016-12-10 13:15:33 -0800170 if (!ret) {
171 return false;
deadbeef49f34fd2016-12-06 16:22:06 -0800172 }
173
deadbeefd1a38b52016-12-10 13:15:33 -0800174 if (needs_ice_restart_ && ice_restarting) {
175 needs_ice_restart_ = false;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100176 RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag cleared for transport "
177 << mid();
deadbeefd1a38b52016-12-10 13:15:33 -0800178 }
179
180 local_description_set_ = true;
181 return true;
deadbeef49f34fd2016-12-06 16:22:06 -0800182}
183
184bool JsepTransport::SetRemoteTransportDescription(
185 const TransportDescription& description,
Steve Anton3828c062017-12-06 10:34:51 -0800186 SdpType type,
deadbeef49f34fd2016-12-06 16:22:06 -0800187 std::string* error_desc) {
188 bool ret = true;
189
190 if (!VerifyIceParams(description)) {
191 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
192 error_desc);
193 }
194
195 remote_description_.reset(new TransportDescription(description));
196 for (const auto& kv : channels_) {
197 ret &= ApplyRemoteTransportDescription(kv.second, error_desc);
198 }
199
200 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
Steve Anton3828c062017-12-06 10:34:51 -0800201 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
202 ret = NegotiateTransportDescription(SdpType::kOffer, error_desc);
deadbeef49f34fd2016-12-06 16:22:06 -0800203 }
204 if (ret) {
205 remote_description_set_ = true;
206 }
207
208 return ret;
209}
210
deadbeefd1a38b52016-12-10 13:15:33 -0800211void JsepTransport::SetNeedsIceRestartFlag() {
212 if (!needs_ice_restart_) {
213 needs_ice_restart_ = true;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100214 RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag set for transport " << mid();
deadbeefd1a38b52016-12-10 13:15:33 -0800215 }
216}
217
218bool JsepTransport::NeedsIceRestart() const {
219 return needs_ice_restart_;
220}
221
deadbeefd8cfa1a2017-03-27 10:33:26 -0700222rtc::Optional<rtc::SSLRole> JsepTransport::GetSslRole() const {
223 return ssl_role_;
deadbeef49f34fd2016-12-06 16:22:06 -0800224}
225
226bool JsepTransport::GetStats(TransportStats* stats) {
227 stats->transport_name = mid();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000228 stats->channel_stats.clear();
deadbeef49f34fd2016-12-06 16:22:06 -0800229 for (auto& kv : channels_) {
zhihuangb2cdd932017-01-19 16:54:25 -0800230 DtlsTransportInternal* dtls_transport = kv.second;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000231 TransportChannelStats substats;
deadbeef49f34fd2016-12-06 16:22:06 -0800232 substats.component = kv.first;
zhihuangb2cdd932017-01-19 16:54:25 -0800233 dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
234 dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
235 substats.dtls_state = dtls_transport->dtls_state();
236 if (!dtls_transport->ice_transport()->GetStats(
237 &substats.connection_infos)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000238 return false;
239 }
240 stats->channel_stats.push_back(substats);
241 }
242 return true;
243}
244
deadbeef49f34fd2016-12-06 16:22:06 -0800245bool JsepTransport::VerifyCertificateFingerprint(
mikescarlette7748672016-04-29 20:20:54 -0700246 const rtc::RTCCertificate* certificate,
247 const rtc::SSLFingerprint* fingerprint,
248 std::string* error_desc) const {
249 if (!fingerprint) {
250 return BadTransportDescription("No fingerprint.", error_desc);
251 }
252 if (!certificate) {
253 return BadTransportDescription(
254 "Fingerprint provided but no identity available.", error_desc);
255 }
kwibergbfefb032016-05-01 14:53:46 -0700256 std::unique_ptr<rtc::SSLFingerprint> fp_tmp(rtc::SSLFingerprint::Create(
mikescarlette7748672016-04-29 20:20:54 -0700257 fingerprint->algorithm, certificate->identity()));
nisseede5da42017-01-12 05:15:36 -0800258 RTC_DCHECK(fp_tmp.get() != NULL);
mikescarlette7748672016-04-29 20:20:54 -0700259 if (*fp_tmp == *fingerprint) {
260 return true;
261 }
262 std::ostringstream desc;
263 desc << "Local fingerprint does not match identity. Expected: ";
264 desc << fp_tmp->ToString();
265 desc << " Got: " << fingerprint->ToString();
266 return BadTransportDescription(desc.str(), error_desc);
267}
268
deadbeef49f34fd2016-12-06 16:22:06 -0800269bool JsepTransport::ApplyLocalTransportDescription(
zhihuangb2cdd932017-01-19 16:54:25 -0800270 DtlsTransportInternal* dtls_transport,
deadbeef49f34fd2016-12-06 16:22:06 -0800271 std::string* error_desc) {
zhihuangb2cdd932017-01-19 16:54:25 -0800272 dtls_transport->ice_transport()->SetIceParameters(
273 local_description_->GetIceParameters());
zhihuangb19012e2017-09-19 13:47:59 -0700274 return true;
deadbeef49f34fd2016-12-06 16:22:06 -0800275}
276
277bool JsepTransport::ApplyRemoteTransportDescription(
zhihuangb2cdd932017-01-19 16:54:25 -0800278 DtlsTransportInternal* dtls_transport,
deadbeef49f34fd2016-12-06 16:22:06 -0800279 std::string* error_desc) {
zhihuangb2cdd932017-01-19 16:54:25 -0800280 dtls_transport->ice_transport()->SetRemoteIceParameters(
281 remote_description_->GetIceParameters());
282 dtls_transport->ice_transport()->SetRemoteIceMode(
283 remote_description_->ice_mode);
deadbeef49f34fd2016-12-06 16:22:06 -0800284 return true;
285}
286
287bool JsepTransport::ApplyNegotiatedTransportDescription(
zhihuangb2cdd932017-01-19 16:54:25 -0800288 DtlsTransportInternal* dtls_transport,
deadbeef49f34fd2016-12-06 16:22:06 -0800289 std::string* error_desc) {
290 // Set SSL role. Role must be set before fingerprint is applied, which
291 // initiates DTLS setup.
deadbeefd8cfa1a2017-03-27 10:33:26 -0700292 if (ssl_role_ && !dtls_transport->SetSslRole(*ssl_role_)) {
deadbeef49f34fd2016-12-06 16:22:06 -0800293 return BadTransportDescription("Failed to set SSL role for the channel.",
294 error_desc);
295 }
296 // Apply remote fingerprint.
zhihuangb2cdd932017-01-19 16:54:25 -0800297 if (!dtls_transport->SetRemoteFingerprint(
deadbeef49f34fd2016-12-06 16:22:06 -0800298 remote_fingerprint_->algorithm,
299 reinterpret_cast<const uint8_t*>(remote_fingerprint_->digest.data()),
300 remote_fingerprint_->digest.size())) {
301 return BadTransportDescription("Failed to apply remote fingerprint.",
302 error_desc);
303 }
304 return true;
305}
306
deadbeefd8cfa1a2017-03-27 10:33:26 -0700307bool JsepTransport::NegotiateTransportDescription(
Steve Anton3828c062017-12-06 10:34:51 -0800308 SdpType local_description_type,
deadbeefd8cfa1a2017-03-27 10:33:26 -0700309 std::string* error_desc) {
deadbeef49f34fd2016-12-06 16:22:06 -0800310 if (!local_description_ || !remote_description_) {
311 const std::string msg =
312 "Applying an answer transport description "
313 "without applying any offer.";
314 return BadTransportDescription(msg, error_desc);
315 }
316 rtc::SSLFingerprint* local_fp =
317 local_description_->identity_fingerprint.get();
318 rtc::SSLFingerprint* remote_fp =
319 remote_description_->identity_fingerprint.get();
320 if (remote_fp && local_fp) {
321 remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp));
deadbeefd8cfa1a2017-03-27 10:33:26 -0700322 if (!NegotiateRole(local_description_type, error_desc)) {
deadbeef49f34fd2016-12-06 16:22:06 -0800323 return false;
324 }
Steve Anton3828c062017-12-06 10:34:51 -0800325 } else if (local_fp && (local_description_type == SdpType::kAnswer)) {
deadbeef49f34fd2016-12-06 16:22:06 -0800326 return BadTransportDescription(
327 "Local fingerprint supplied when caller didn't offer DTLS.",
328 error_desc);
329 } else {
330 // We are not doing DTLS
331 remote_fingerprint_.reset(new rtc::SSLFingerprint("", nullptr, 0));
332 }
333 // Now that we have negotiated everything, push it downward.
334 // Note that we cache the result so that if we have race conditions
335 // between future SetRemote/SetLocal invocations and new channel
336 // creation, we have the negotiation state saved until a new
337 // negotiation happens.
338 for (const auto& kv : channels_) {
339 if (!ApplyNegotiatedTransportDescription(kv.second, error_desc)) {
340 return false;
341 }
342 }
343 return true;
344}
345
Steve Anton3828c062017-12-06 10:34:51 -0800346bool JsepTransport::NegotiateRole(SdpType local_description_type,
deadbeefd8cfa1a2017-03-27 10:33:26 -0700347 std::string* error_desc) {
deadbeef49f34fd2016-12-06 16:22:06 -0800348 if (!local_description_ || !remote_description_) {
mikescarlette7748672016-04-29 20:20:54 -0700349 const std::string msg =
350 "Local and Remote description must be set before "
351 "transport descriptions are negotiated";
352 return BadTransportDescription(msg, error_desc);
353 }
354
355 // From RFC 4145, section-4.1, The following are the values that the
356 // 'setup' attribute can take in an offer/answer exchange:
357 // Offer Answer
358 // ________________
359 // active passive / holdconn
360 // passive active / holdconn
361 // actpass active / passive / holdconn
362 // holdconn holdconn
363 //
364 // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
365 // The endpoint MUST use the setup attribute defined in [RFC4145].
366 // The endpoint that is the offerer MUST use the setup attribute
367 // value of setup:actpass and be prepared to receive a client_hello
368 // before it receives the answer. The answerer MUST use either a
369 // setup attribute value of setup:active or setup:passive. Note that
370 // if the answerer uses setup:passive, then the DTLS handshake will
371 // not begin until the answerer is received, which adds additional
372 // latency. setup:active allows the answer and the DTLS handshake to
373 // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever
374 // party is active MUST initiate a DTLS handshake by sending a
375 // ClientHello over each flow (host/port quartet).
376 // IOW - actpass and passive modes should be treated as server and
377 // active as client.
deadbeef49f34fd2016-12-06 16:22:06 -0800378 ConnectionRole local_connection_role = local_description_->connection_role;
379 ConnectionRole remote_connection_role = remote_description_->connection_role;
mikescarlette7748672016-04-29 20:20:54 -0700380
381 bool is_remote_server = false;
Steve Anton3828c062017-12-06 10:34:51 -0800382 if (local_description_type == SdpType::kOffer) {
mikescarlette7748672016-04-29 20:20:54 -0700383 if (local_connection_role != CONNECTIONROLE_ACTPASS) {
384 return BadTransportDescription(
385 "Offerer must use actpass value for setup attribute.", error_desc);
386 }
387
388 if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
389 remote_connection_role == CONNECTIONROLE_PASSIVE ||
390 remote_connection_role == CONNECTIONROLE_NONE) {
391 is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
392 } else {
393 const std::string msg =
394 "Answerer must use either active or passive value "
395 "for setup attribute.";
396 return BadTransportDescription(msg, error_desc);
397 }
398 // If remote is NONE or ACTIVE it will act as client.
399 } else {
400 if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
401 remote_connection_role != CONNECTIONROLE_NONE) {
deadbeefd8cfa1a2017-03-27 10:33:26 -0700402 // Accept a remote role attribute that's not "actpass", but matches the
403 // current negotiated role. This is allowed by dtls-sdp, though our
404 // implementation will never generate such an offer as it's not
405 // recommended.
406 //
407 // See https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-dtls-sdp,
408 // section 5.5.
409 if (!ssl_role_ ||
410 (*ssl_role_ == rtc::SSL_CLIENT &&
411 remote_connection_role == CONNECTIONROLE_ACTIVE) ||
412 (*ssl_role_ == rtc::SSL_SERVER &&
413 remote_connection_role == CONNECTIONROLE_PASSIVE)) {
414 return BadTransportDescription(
415 "Offerer must use actpass value or current negotiated role for "
416 "setup attribute.",
417 error_desc);
418 }
mikescarlette7748672016-04-29 20:20:54 -0700419 }
420
421 if (local_connection_role == CONNECTIONROLE_ACTIVE ||
422 local_connection_role == CONNECTIONROLE_PASSIVE) {
423 is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
424 } else {
425 const std::string msg =
426 "Answerer must use either active or passive value "
427 "for setup attribute.";
428 return BadTransportDescription(msg, error_desc);
429 }
430
431 // If local is passive, local will act as server.
432 }
433
deadbeefd8cfa1a2017-03-27 10:33:26 -0700434 ssl_role_.emplace(is_remote_server ? rtc::SSL_CLIENT : rtc::SSL_SERVER);
mikescarlette7748672016-04-29 20:20:54 -0700435 return true;
436}
437
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000438} // namespace cricket