1 /*
2  *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
3  *
parallel(int a,int b)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 "webrtc/p2p/base/transportdescriptionfactory.h"
12 
13 #include "webrtc/p2p/base/transportdescription.h"
14 #include "webrtc/base/helpers.h"
15 #include "webrtc/base/logging.h"
16 #include "webrtc/base/messagedigest.h"
17 #include "webrtc/base/scoped_ptr.h"
18 #include "webrtc/base/sslfingerprint.h"
19 
20 namespace cricket {
21 
22 static TransportProtocol kDefaultProtocol = ICEPROTO_RFC5245;
23 
24 TransportDescriptionFactory::TransportDescriptionFactory()
25     : protocol_(kDefaultProtocol),
26       secure_(SEC_DISABLED),
27       identity_(NULL) {
28 }
29 
30 TransportDescription* TransportDescriptionFactory::CreateOffer(
31     const TransportOptions& options,
32     const TransportDescription* current_description) const {
33   rtc::scoped_ptr<TransportDescription> desc(new TransportDescription());
34 
35   // Set the transport type depending on the selected protocol.
36   if (protocol_ == ICEPROTO_RFC5245) {
37     desc->transport_type = NS_JINGLE_ICE_UDP;
38   } else if (protocol_ == ICEPROTO_HYBRID) {
39     desc->transport_type = NS_JINGLE_ICE_UDP;
40     desc->AddOption(ICE_OPTION_GICE);
41   } else if (protocol_ == ICEPROTO_GOOGLE) {
42     desc->transport_type = NS_GINGLE_P2P;
43   }
44 
45   // Generate the ICE credentials if we don't already have them.
46   if (!current_description || options.ice_restart) {
47     desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
48     desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH);
49   } else {
50     desc->ice_ufrag = current_description->ice_ufrag;
51     desc->ice_pwd = current_description->ice_pwd;
52   }
53 
54   // If we are trying to establish a secure transport, add a fingerprint.
55   if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
56     // Fail if we can't create the fingerprint.
57     // If we are the initiator set role to "actpass".
58     if (!SetSecurityInfo(desc.get(), CONNECTIONROLE_ACTPASS)) {
59       return NULL;
60     }
61   }
62 
63   return desc.release();
64 }
65 
66 TransportDescription* TransportDescriptionFactory::CreateAnswer(
67     const TransportDescription* offer,
68     const TransportOptions& options,
69     const TransportDescription* current_description) const {
70   // A NULL offer is treated as a GICE transport description.
71   // TODO(juberti): Figure out why we get NULL offers, and fix this upstream.
72   rtc::scoped_ptr<TransportDescription> desc(new TransportDescription());
73 
74   // Figure out which ICE variant to negotiate; prefer RFC 5245 ICE, but fall
75   // back to G-ICE if needed. Note that we never create a hybrid answer, since
76   // we know what the other side can support already.
77   if (offer && offer->transport_type == NS_JINGLE_ICE_UDP &&
78       (protocol_ == ICEPROTO_RFC5245 || protocol_ == ICEPROTO_HYBRID)) {
79     // Offer is ICE or hybrid, we support ICE or hybrid: use ICE.
80     desc->transport_type = NS_JINGLE_ICE_UDP;
81   } else if (offer && offer->transport_type == NS_JINGLE_ICE_UDP &&
82              offer->HasOption(ICE_OPTION_GICE) &&
83              protocol_ == ICEPROTO_GOOGLE) {
84     desc->transport_type = NS_GINGLE_P2P;
85     // Offer is hybrid, we support GICE: use GICE.
86   } else if ((!offer || offer->transport_type == NS_GINGLE_P2P) &&
87              (protocol_ == ICEPROTO_HYBRID || protocol_ == ICEPROTO_GOOGLE)) {
88     // Offer is GICE, we support hybrid or GICE: use GICE.
89     desc->transport_type = NS_GINGLE_P2P;
90   } else {
91     // Mismatch.
92     LOG(LS_WARNING) << "Failed to create TransportDescription answer "
93                        "because of incompatible transport types";
94     return NULL;
95   }
96 
97   // Generate the ICE credentials if we don't already have them or ice is
98   // being restarted.
99   if (!current_description || options.ice_restart) {
100     desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
101     desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH);
102   } else {
103     desc->ice_ufrag = current_description->ice_ufrag;
104     desc->ice_pwd = current_description->ice_pwd;
105   }
106 
107   // Negotiate security params.
108   if (offer && offer->identity_fingerprint.get()) {
109     // The offer supports DTLS, so answer with DTLS, as long as we support it.
110     if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
111       // Fail if we can't create the fingerprint.
112       // Setting DTLS role to active.
113       ConnectionRole role = (options.prefer_passive_role) ?
114           CONNECTIONROLE_PASSIVE : CONNECTIONROLE_ACTIVE;
115 
116       if (!SetSecurityInfo(desc.get(), role)) {
117         return NULL;
118       }
119     }
120   } else if (secure_ == SEC_REQUIRED) {
121     // We require DTLS, but the other side didn't offer it. Fail.
122     LOG(LS_WARNING) << "Failed to create TransportDescription answer "
123                        "because of incompatible security settings";
124     return NULL;
125   }
126 
127   return desc.release();
128 }
129 
130 bool TransportDescriptionFactory::SetSecurityInfo(
131     TransportDescription* desc, ConnectionRole role) const {
132   if (!identity_) {
133     LOG(LS_ERROR) << "Cannot create identity digest with no identity";
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.
140   std::string digest_alg;
141   if (!identity_->certificate().GetSignatureDigestAlgorithm(&digest_alg)) {
142     LOG(LS_ERROR) << "Failed to retrieve the certificate's digest algorithm";
143     return false;
144   }
145 
146   desc->identity_fingerprint.reset(
147       rtc::SSLFingerprint::Create(digest_alg, identity_));
148   if (!desc->identity_fingerprint.get()) {
149     LOG(LS_ERROR) << "Failed to create identity fingerprint, alg="
150                   << digest_alg;
151     return false;
152   }
153 
154   // Assign security role.
155   desc->connection_role = role;
156   return true;
157 }
158 
159 }  // namespace cricket
160 
161