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
17namespace rtc {
18class SSLIdentity;
19}
20
21namespace cricket {
22
23class 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.
29template<class Base>
30class DtlsTransport : public Base {
31 public:
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
40  ~DtlsTransport() {
41    Base::DestroyAllChannels();
42  }
43
44  void SetLocalCertificate(
45      const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override {
46    certificate_ = certificate;
47  }
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
57  bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override {
58    ssl_max_version_ = version;
59    return true;
60  }
61
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
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
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
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
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:
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