xref: /aosp_15_r20/external/webrtc/p2p/base/transport_description_factory.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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