3 * Copyright 2012, Google, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #ifndef WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
29 #define WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
31 #include "webrtc/p2p/base/dtlstransportchannel.h"
32 #include "webrtc/p2p/base/transport.h"
42 // Base should be a descendant of cricket::Transport
44 class DtlsTransport : public Base {
46 DtlsTransport(rtc::Thread* signaling_thread,
47 rtc::Thread* worker_thread,
48 const std::string& content_name,
49 PortAllocator* allocator,
50 rtc::SSLIdentity* identity)
51 : Base(signaling_thread, worker_thread, content_name, allocator),
53 secure_role_(rtc::SSL_CLIENT) {
57 Base::DestroyAllChannels();
59 virtual void SetIdentity_w(rtc::SSLIdentity* identity) {
62 virtual bool GetIdentity_w(rtc::SSLIdentity** identity) {
66 *identity = identity_->GetReference();
70 virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
71 std::string* error_desc) {
72 rtc::SSLFingerprint* local_fp =
73 Base::local_description()->identity_fingerprint.get();
76 // Sanity check local fingerprint.
78 rtc::scoped_ptr<rtc::SSLFingerprint> local_fp_tmp(
79 rtc::SSLFingerprint::Create(local_fp->algorithm,
81 ASSERT(local_fp_tmp.get() != NULL);
82 if (!(*local_fp_tmp == *local_fp)) {
83 std::ostringstream desc;
84 desc << "Local fingerprint does not match identity. Expected: ";
85 desc << local_fp_tmp->ToString();
86 desc << " Got: " << local_fp->ToString();
87 return BadTransportDescription(desc.str(), error_desc);
90 return BadTransportDescription(
91 "Local fingerprint provided but no identity available.",
98 if (!channel->SetLocalIdentity(identity_)) {
99 return BadTransportDescription("Failed to set local identity.",
103 // Apply the description in the base class.
104 return Base::ApplyLocalTransportDescription_w(channel, error_desc);
107 virtual bool NegotiateTransportDescription_w(ContentAction local_role,
108 std::string* error_desc) {
109 if (!Base::local_description() || !Base::remote_description()) {
110 const std::string msg = "Local and Remote description must be set before "
111 "transport descriptions are negotiated";
112 return BadTransportDescription(msg, error_desc);
115 rtc::SSLFingerprint* local_fp =
116 Base::local_description()->identity_fingerprint.get();
117 rtc::SSLFingerprint* remote_fp =
118 Base::remote_description()->identity_fingerprint.get();
120 if (remote_fp && local_fp) {
121 remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp));
123 // From RFC 4145, section-4.1, The following are the values that the
124 // 'setup' attribute can take in an offer/answer exchange:
127 // active passive / holdconn
128 // passive active / holdconn
129 // actpass active / passive / holdconn
132 // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
133 // The endpoint MUST use the setup attribute defined in [RFC4145].
134 // The endpoint that is the offerer MUST use the setup attribute
135 // value of setup:actpass and be prepared to receive a client_hello
136 // before it receives the answer. The answerer MUST use either a
137 // setup attribute value of setup:active or setup:passive. Note that
138 // if the answerer uses setup:passive, then the DTLS handshake will
139 // not begin until the answerer is received, which adds additional
140 // latency. setup:active allows the answer and the DTLS handshake to
141 // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever
142 // party is active MUST initiate a DTLS handshake by sending a
143 // ClientHello over each flow (host/port quartet).
144 // IOW - actpass and passive modes should be treated as server and
146 ConnectionRole local_connection_role =
147 Base::local_description()->connection_role;
148 ConnectionRole remote_connection_role =
149 Base::remote_description()->connection_role;
151 bool is_remote_server = false;
152 if (local_role == CA_OFFER) {
153 if (local_connection_role != CONNECTIONROLE_ACTPASS) {
154 return BadTransportDescription(
155 "Offerer must use actpass value for setup attribute.",
159 if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
160 remote_connection_role == CONNECTIONROLE_PASSIVE ||
161 remote_connection_role == CONNECTIONROLE_NONE) {
162 is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
164 const std::string msg =
165 "Answerer must use either active or passive value "
166 "for setup attribute.";
167 return BadTransportDescription(msg, error_desc);
169 // If remote is NONE or ACTIVE it will act as client.
171 if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
172 remote_connection_role != CONNECTIONROLE_NONE) {
173 return BadTransportDescription(
174 "Offerer must use actpass value for setup attribute.",
178 if (local_connection_role == CONNECTIONROLE_ACTIVE ||
179 local_connection_role == CONNECTIONROLE_PASSIVE) {
180 is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
182 const std::string msg =
183 "Answerer must use either active or passive value "
184 "for setup attribute.";
185 return BadTransportDescription(msg, error_desc);
188 // If local is passive, local will act as server.
191 secure_role_ = is_remote_server ? rtc::SSL_CLIENT :
194 } else if (local_fp && (local_role == CA_ANSWER)) {
195 return BadTransportDescription(
196 "Local fingerprint supplied when caller didn't offer DTLS.",
199 // We are not doing DTLS
200 remote_fingerprint_.reset(new rtc::SSLFingerprint(
204 // Now run the negotiation for the base class.
205 return Base::NegotiateTransportDescription_w(local_role, error_desc);
208 virtual DtlsTransportChannelWrapper* CreateTransportChannel(int component) {
209 return new DtlsTransportChannelWrapper(
210 this, Base::CreateTransportChannel(component));
213 virtual void DestroyTransportChannel(TransportChannelImpl* channel) {
214 // Kind of ugly, but this lets us do the exact inverse of the create.
215 DtlsTransportChannelWrapper* dtls_channel =
216 static_cast<DtlsTransportChannelWrapper*>(channel);
217 TransportChannelImpl* base_channel = dtls_channel->channel();
219 Base::DestroyTransportChannel(base_channel);
222 virtual bool GetSslRole_w(rtc::SSLRole* ssl_role) const {
223 ASSERT(ssl_role != NULL);
224 *ssl_role = secure_role_;
229 virtual bool ApplyNegotiatedTransportDescription_w(
230 TransportChannelImpl* channel,
231 std::string* error_desc) {
232 // Set ssl role. Role must be set before fingerprint is applied, which
233 // initiates DTLS setup.
234 if (!channel->SetSslRole(secure_role_)) {
235 return BadTransportDescription("Failed to set ssl role for the channel.",
238 // Apply remote fingerprint.
239 if (!channel->SetRemoteFingerprint(
240 remote_fingerprint_->algorithm,
241 reinterpret_cast<const uint8 *>(remote_fingerprint_->
243 remote_fingerprint_->digest.length())) {
244 return BadTransportDescription("Failed to apply remote fingerprint.",
247 return Base::ApplyNegotiatedTransportDescription_w(channel, error_desc);
250 rtc::SSLIdentity* identity_;
251 rtc::SSLRole secure_role_;
252 rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint_;
255 } // namespace cricket
257 #endif // WEBRTC_P2P_BASE_DTLSTRANSPORT_H_