• 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 #ifndef WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
12 #define WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
13 
14 #include "webrtc/p2p/base/dtlstransportchannel.h"
15 #include "webrtc/p2p/base/transport.h"
16 
17 namespace rtc {
18 class SSLIdentity;
19 }
20 
21 namespace cricket {
22 
23 class PortAllocator;
24 
25 // Base should be a descendant of cricket::Transport and have a constructor
26 // that takes a transport name and PortAllocator.
27 //
28 // Everything in this class should be called on the worker thread.
29 template<class Base>
30 class DtlsTransport : public Base {
31  public:
DtlsTransport(const std::string & name,PortAllocator * allocator,const rtc::scoped_refptr<rtc::RTCCertificate> & certificate)32   DtlsTransport(const std::string& name,
33                 PortAllocator* allocator,
34                 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate)
35       : Base(name, allocator),
36         certificate_(certificate),
37         secure_role_(rtc::SSL_CLIENT),
38         ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_12) {}
39 
~DtlsTransport()40   ~DtlsTransport() {
41     Base::DestroyAllChannels();
42   }
43 
SetLocalCertificate(const rtc::scoped_refptr<rtc::RTCCertificate> & certificate)44   void SetLocalCertificate(
45       const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override {
46     certificate_ = certificate;
47   }
GetLocalCertificate(rtc::scoped_refptr<rtc::RTCCertificate> * certificate)48   bool GetLocalCertificate(
49       rtc::scoped_refptr<rtc::RTCCertificate>* certificate) override {
50     if (!certificate_)
51       return false;
52 
53     *certificate = certificate_;
54     return true;
55   }
56 
SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version)57   bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override {
58     ssl_max_version_ = version;
59     return true;
60   }
61 
ApplyLocalTransportDescription(TransportChannelImpl * channel,std::string * error_desc)62   bool ApplyLocalTransportDescription(TransportChannelImpl* channel,
63                                       std::string* error_desc) override {
64     rtc::SSLFingerprint* local_fp =
65         Base::local_description()->identity_fingerprint.get();
66 
67     if (local_fp) {
68       // Sanity check local fingerprint.
69       if (certificate_) {
70         rtc::scoped_ptr<rtc::SSLFingerprint> local_fp_tmp(
71             rtc::SSLFingerprint::Create(local_fp->algorithm,
72                                         certificate_->identity()));
73         ASSERT(local_fp_tmp.get() != NULL);
74         if (!(*local_fp_tmp == *local_fp)) {
75           std::ostringstream desc;
76           desc << "Local fingerprint does not match identity. Expected: ";
77           desc << local_fp_tmp->ToString();
78           desc << " Got: " << local_fp->ToString();
79           return BadTransportDescription(desc.str(), error_desc);
80         }
81       } else {
82         return BadTransportDescription(
83             "Local fingerprint provided but no identity available.",
84             error_desc);
85       }
86     } else {
87       certificate_ = nullptr;
88     }
89 
90     if (!channel->SetLocalCertificate(certificate_)) {
91       return BadTransportDescription("Failed to set local identity.",
92                                      error_desc);
93     }
94 
95     // Apply the description in the base class.
96     return Base::ApplyLocalTransportDescription(channel, error_desc);
97   }
98 
NegotiateTransportDescription(ContentAction local_role,std::string * error_desc)99   bool NegotiateTransportDescription(ContentAction local_role,
100                                      std::string* error_desc) override {
101     if (!Base::local_description() || !Base::remote_description()) {
102       const std::string msg = "Local and Remote description must be set before "
103                               "transport descriptions are negotiated";
104       return BadTransportDescription(msg, error_desc);
105     }
106 
107     rtc::SSLFingerprint* local_fp =
108         Base::local_description()->identity_fingerprint.get();
109     rtc::SSLFingerprint* remote_fp =
110         Base::remote_description()->identity_fingerprint.get();
111 
112     if (remote_fp && local_fp) {
113       remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp));
114 
115       // From RFC 4145, section-4.1, The following are the values that the
116       // 'setup' attribute can take in an offer/answer exchange:
117       //       Offer      Answer
118       //      ________________
119       //      active     passive / holdconn
120       //      passive    active / holdconn
121       //      actpass    active / passive / holdconn
122       //      holdconn   holdconn
123       //
124       // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
125       // The endpoint MUST use the setup attribute defined in [RFC4145].
126       // The endpoint that is the offerer MUST use the setup attribute
127       // value of setup:actpass and be prepared to receive a client_hello
128       // before it receives the answer.  The answerer MUST use either a
129       // setup attribute value of setup:active or setup:passive.  Note that
130       // if the answerer uses setup:passive, then the DTLS handshake will
131       // not begin until the answerer is received, which adds additional
132       // latency. setup:active allows the answer and the DTLS handshake to
133       // occur in parallel.  Thus, setup:active is RECOMMENDED.  Whichever
134       // party is active MUST initiate a DTLS handshake by sending a
135       // ClientHello over each flow (host/port quartet).
136       // IOW - actpass and passive modes should be treated as server and
137       // active as client.
138       ConnectionRole local_connection_role =
139           Base::local_description()->connection_role;
140       ConnectionRole remote_connection_role =
141           Base::remote_description()->connection_role;
142 
143       bool is_remote_server = false;
144       if (local_role == CA_OFFER) {
145         if (local_connection_role != CONNECTIONROLE_ACTPASS) {
146           return BadTransportDescription(
147               "Offerer must use actpass value for setup attribute.",
148               error_desc);
149         }
150 
151         if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
152             remote_connection_role == CONNECTIONROLE_PASSIVE ||
153             remote_connection_role == CONNECTIONROLE_NONE) {
154           is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
155         } else {
156           const std::string msg =
157               "Answerer must use either active or passive value "
158               "for setup attribute.";
159           return BadTransportDescription(msg, error_desc);
160         }
161         // If remote is NONE or ACTIVE it will act as client.
162       } else {
163         if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
164             remote_connection_role != CONNECTIONROLE_NONE) {
165           return BadTransportDescription(
166               "Offerer must use actpass value for setup attribute.",
167               error_desc);
168         }
169 
170         if (local_connection_role == CONNECTIONROLE_ACTIVE ||
171             local_connection_role == CONNECTIONROLE_PASSIVE) {
172           is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
173         } else {
174           const std::string msg =
175               "Answerer must use either active or passive value "
176               "for setup attribute.";
177           return BadTransportDescription(msg, error_desc);
178         }
179 
180         // If local is passive, local will act as server.
181       }
182 
183       secure_role_ = is_remote_server ? rtc::SSL_CLIENT :
184                                         rtc::SSL_SERVER;
185 
186     } else if (local_fp && (local_role == CA_ANSWER)) {
187       return BadTransportDescription(
188           "Local fingerprint supplied when caller didn't offer DTLS.",
189           error_desc);
190     } else {
191       // We are not doing DTLS
192       remote_fingerprint_.reset(new rtc::SSLFingerprint(
193           "", NULL, 0));
194     }
195 
196     // Now run the negotiation for the base class.
197     return Base::NegotiateTransportDescription(local_role, error_desc);
198   }
199 
CreateTransportChannel(int component)200   DtlsTransportChannelWrapper* CreateTransportChannel(int component) override {
201     DtlsTransportChannelWrapper* channel = new DtlsTransportChannelWrapper(
202         this, Base::CreateTransportChannel(component));
203     channel->SetSslMaxProtocolVersion(ssl_max_version_);
204     return channel;
205   }
206 
DestroyTransportChannel(TransportChannelImpl * channel)207   void DestroyTransportChannel(TransportChannelImpl* channel) override {
208     // Kind of ugly, but this lets us do the exact inverse of the create.
209     DtlsTransportChannelWrapper* dtls_channel =
210         static_cast<DtlsTransportChannelWrapper*>(channel);
211     TransportChannelImpl* base_channel = dtls_channel->channel();
212     delete dtls_channel;
213     Base::DestroyTransportChannel(base_channel);
214   }
215 
GetSslRole(rtc::SSLRole * ssl_role)216   bool GetSslRole(rtc::SSLRole* ssl_role) const override {
217     ASSERT(ssl_role != NULL);
218     *ssl_role = secure_role_;
219     return true;
220   }
221 
222  private:
ApplyNegotiatedTransportDescription(TransportChannelImpl * channel,std::string * error_desc)223   bool ApplyNegotiatedTransportDescription(TransportChannelImpl* channel,
224                                            std::string* error_desc) override {
225     // Set ssl role. Role must be set before fingerprint is applied, which
226     // initiates DTLS setup.
227     if (!channel->SetSslRole(secure_role_)) {
228       return BadTransportDescription("Failed to set ssl role for the channel.",
229                                      error_desc);
230     }
231     // Apply remote fingerprint.
232     if (!channel->SetRemoteFingerprint(remote_fingerprint_->algorithm,
233                                        reinterpret_cast<const uint8_t*>(
234                                            remote_fingerprint_->digest.data()),
235                                        remote_fingerprint_->digest.size())) {
236       return BadTransportDescription("Failed to apply remote fingerprint.",
237                                      error_desc);
238     }
239     return Base::ApplyNegotiatedTransportDescription(channel, error_desc);
240   }
241 
242   rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
243   rtc::SSLRole secure_role_;
244   rtc::SSLProtocolVersion ssl_max_version_;
245   rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint_;
246 };
247 
248 }  // namespace cricket
249 
250 #endif  // WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
251