• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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/sslfingerprint.h"
18 
19 namespace cricket {
20 
TransportDescriptionFactory()21 TransportDescriptionFactory::TransportDescriptionFactory()
22     : secure_(SEC_DISABLED) {
23 }
24 
CreateOffer(const TransportOptions & options,const TransportDescription * current_description) const25 TransportDescription* TransportDescriptionFactory::CreateOffer(
26     const TransportOptions& options,
27     const TransportDescription* current_description) const {
28   rtc::scoped_ptr<TransportDescription> desc(new TransportDescription());
29 
30   // Generate the ICE credentials if we don't already have them.
31   if (!current_description || options.ice_restart) {
32     desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
33     desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH);
34   } else {
35     desc->ice_ufrag = current_description->ice_ufrag;
36     desc->ice_pwd = current_description->ice_pwd;
37   }
38 
39   // If we are trying to establish a secure transport, add a fingerprint.
40   if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
41     // Fail if we can't create the fingerprint.
42     // If we are the initiator set role to "actpass".
43     if (!SetSecurityInfo(desc.get(), CONNECTIONROLE_ACTPASS)) {
44       return NULL;
45     }
46   }
47 
48   return desc.release();
49 }
50 
CreateAnswer(const TransportDescription * offer,const TransportOptions & options,const TransportDescription * current_description) const51 TransportDescription* TransportDescriptionFactory::CreateAnswer(
52     const TransportDescription* offer,
53     const TransportOptions& options,
54     const TransportDescription* current_description) const {
55   // TODO(juberti): Figure out why we get NULL offers, and fix this upstream.
56   if (!offer) {
57     LOG(LS_WARNING) << "Failed to create TransportDescription answer " <<
58         "because offer is NULL";
59     return NULL;
60   }
61 
62   rtc::scoped_ptr<TransportDescription> desc(new TransportDescription());
63   // Generate the ICE credentials if we don't already have them or ice is
64   // being restarted.
65   if (!current_description || options.ice_restart) {
66     desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
67     desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH);
68   } else {
69     desc->ice_ufrag = current_description->ice_ufrag;
70     desc->ice_pwd = current_description->ice_pwd;
71   }
72 
73   // Negotiate security params.
74   if (offer && offer->identity_fingerprint.get()) {
75     // The offer supports DTLS, so answer with DTLS, as long as we support it.
76     if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
77       // Fail if we can't create the fingerprint.
78       // Setting DTLS role to active.
79       ConnectionRole role = (options.prefer_passive_role) ?
80           CONNECTIONROLE_PASSIVE : CONNECTIONROLE_ACTIVE;
81 
82       if (!SetSecurityInfo(desc.get(), role)) {
83         return NULL;
84       }
85     }
86   } else if (secure_ == SEC_REQUIRED) {
87     // We require DTLS, but the other side didn't offer it. Fail.
88     LOG(LS_WARNING) << "Failed to create TransportDescription answer "
89                        "because of incompatible security settings";
90     return NULL;
91   }
92 
93   return desc.release();
94 }
95 
SetSecurityInfo(TransportDescription * desc,ConnectionRole role) const96 bool TransportDescriptionFactory::SetSecurityInfo(
97     TransportDescription* desc, ConnectionRole role) const {
98   if (!certificate_) {
99     LOG(LS_ERROR) << "Cannot create identity digest with no certificate";
100     return false;
101   }
102 
103   // This digest algorithm is used to produce the a=fingerprint lines in SDP.
104   // RFC 4572 Section 5 requires that those lines use the same hash function as
105   // the certificate's signature.
106   std::string digest_alg;
107   if (!certificate_->ssl_certificate().GetSignatureDigestAlgorithm(
108           &digest_alg)) {
109     LOG(LS_ERROR) << "Failed to retrieve the certificate's digest algorithm";
110     return false;
111   }
112 
113   desc->identity_fingerprint.reset(
114       rtc::SSLFingerprint::Create(digest_alg, certificate_->identity()));
115   if (!desc->identity_fingerprint.get()) {
116     LOG(LS_ERROR) << "Failed to create identity fingerprint, alg="
117                   << digest_alg;
118     return false;
119   }
120 
121   // Assign security role.
122   desc->connection_role = role;
123   return true;
124 }
125 
126 }  // namespace cricket
127