1 /*
2 * Copyright 2012 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
11 #include "p2p/base/transport_description_factory.h"
12
13 #include <stddef.h>
14
15 #include <memory>
16 #include <string>
17
18 #include "p2p/base/transport_description.h"
19 #include "rtc_base/logging.h"
20 #include "rtc_base/ssl_fingerprint.h"
21
22 namespace cricket {
23
TransportDescriptionFactory(const webrtc::FieldTrialsView & field_trials)24 TransportDescriptionFactory::TransportDescriptionFactory(
25 const webrtc::FieldTrialsView& field_trials)
26 : secure_(SEC_DISABLED), field_trials_(field_trials) {}
27
28 TransportDescriptionFactory::~TransportDescriptionFactory() = default;
29
CreateOffer(const TransportOptions & options,const TransportDescription * current_description,IceCredentialsIterator * ice_credentials) const30 std::unique_ptr<TransportDescription> TransportDescriptionFactory::CreateOffer(
31 const TransportOptions& options,
32 const TransportDescription* current_description,
33 IceCredentialsIterator* ice_credentials) const {
34 auto desc = std::make_unique<TransportDescription>();
35
36 // Generate the ICE credentials if we don't already have them.
37 if (!current_description || options.ice_restart) {
38 IceParameters credentials = ice_credentials->GetIceCredentials();
39 desc->ice_ufrag = credentials.ufrag;
40 desc->ice_pwd = credentials.pwd;
41 } else {
42 desc->ice_ufrag = current_description->ice_ufrag;
43 desc->ice_pwd = current_description->ice_pwd;
44 }
45 desc->AddOption(ICE_OPTION_TRICKLE);
46 if (options.enable_ice_renomination) {
47 desc->AddOption(ICE_OPTION_RENOMINATION);
48 }
49
50 // If we are trying to establish a secure transport, add a fingerprint.
51 if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
52 // Fail if we can't create the fingerprint.
53 // If we are the initiator set role to "actpass".
54 if (!SetSecurityInfo(desc.get(), CONNECTIONROLE_ACTPASS)) {
55 return NULL;
56 }
57 }
58
59 return desc;
60 }
61
CreateAnswer(const TransportDescription * offer,const TransportOptions & options,bool require_transport_attributes,const TransportDescription * current_description,IceCredentialsIterator * ice_credentials) const62 std::unique_ptr<TransportDescription> TransportDescriptionFactory::CreateAnswer(
63 const TransportDescription* offer,
64 const TransportOptions& options,
65 bool require_transport_attributes,
66 const TransportDescription* current_description,
67 IceCredentialsIterator* ice_credentials) const {
68 // TODO(juberti): Figure out why we get NULL offers, and fix this upstream.
69 if (!offer) {
70 RTC_LOG(LS_WARNING) << "Failed to create TransportDescription answer "
71 "because offer is NULL";
72 return NULL;
73 }
74
75 auto desc = std::make_unique<TransportDescription>();
76 // Generate the ICE credentials if we don't already have them or ice is
77 // being restarted.
78 if (!current_description || options.ice_restart) {
79 IceParameters credentials = ice_credentials->GetIceCredentials();
80 desc->ice_ufrag = credentials.ufrag;
81 desc->ice_pwd = credentials.pwd;
82 } else {
83 desc->ice_ufrag = current_description->ice_ufrag;
84 desc->ice_pwd = current_description->ice_pwd;
85 }
86 desc->AddOption(ICE_OPTION_TRICKLE);
87 if (options.enable_ice_renomination) {
88 desc->AddOption(ICE_OPTION_RENOMINATION);
89 }
90
91 // Negotiate security params.
92 if (offer && offer->identity_fingerprint.get()) {
93 // The offer supports DTLS, so answer with DTLS, as long as we support it.
94 if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
95 ConnectionRole role = CONNECTIONROLE_NONE;
96 // If the offer does not constrain the role, go with preference.
97 if (offer->connection_role == CONNECTIONROLE_ACTPASS) {
98 role = (options.prefer_passive_role) ? CONNECTIONROLE_PASSIVE
99 : CONNECTIONROLE_ACTIVE;
100 } else if (offer->connection_role == CONNECTIONROLE_ACTIVE) {
101 role = CONNECTIONROLE_PASSIVE;
102 } else if (offer->connection_role == CONNECTIONROLE_PASSIVE) {
103 role = CONNECTIONROLE_ACTIVE;
104 } else if (offer->connection_role == CONNECTIONROLE_NONE) {
105 // This case may be reached if a=setup is not present in the SDP.
106 RTC_LOG(LS_WARNING) << "Remote offer connection role is NONE, which is "
107 "a protocol violation";
108 role = (options.prefer_passive_role) ? CONNECTIONROLE_PASSIVE
109 : CONNECTIONROLE_ACTIVE;
110 } else {
111 RTC_LOG(LS_ERROR) << "Remote offer connection role is " << role
112 << " which is a protocol violation";
113 RTC_DCHECK_NOTREACHED();
114 }
115
116 if (!SetSecurityInfo(desc.get(), role)) {
117 return NULL;
118 }
119 }
120 } else if (require_transport_attributes && secure_ == SEC_REQUIRED) {
121 // We require DTLS, but the other side didn't offer it. Fail.
122 RTC_LOG(LS_WARNING) << "Failed to create TransportDescription answer "
123 "because of incompatible security settings";
124 return NULL;
125 }
126
127 return desc;
128 }
129
SetSecurityInfo(TransportDescription * desc,ConnectionRole role) const130 bool TransportDescriptionFactory::SetSecurityInfo(TransportDescription* desc,
131 ConnectionRole role) const {
132 if (!certificate_) {
133 RTC_LOG(LS_ERROR) << "Cannot create identity digest with no certificate";
134 return false;
135 }
136
137 // This digest algorithm is used to produce the a=fingerprint lines in SDP.
138 // RFC 4572 Section 5 requires that those lines use the same hash function as
139 // the certificate's signature, which is what CreateFromCertificate does.
140 desc->identity_fingerprint =
141 rtc::SSLFingerprint::CreateFromCertificate(*certificate_);
142 if (!desc->identity_fingerprint) {
143 return false;
144 }
145
146 // Assign security role.
147 desc->connection_role = role;
148 return true;
149 }
150
151 } // namespace cricket
152