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