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