1/*
2 * libjingle
3 * Copyright 2011, Google Inc.
4 * Copyright 2011, RTFM, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 *  1. Redistributions of source code must retain the above copyright notice,
10 *     this list of conditions and the following disclaimer.
11 *  2. Redistributions in binary form must reproduce the above copyright notice,
12 *     this list of conditions and the following disclaimer in the documentation
13 *     and/or other materials provided with the distribution.
14 *  3. The name of the author may not be used to endorse or promote products
15 *     derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef TALK_P2P_BASE_DTLSTRANSPORTCHANNEL_H_
30#define TALK_P2P_BASE_DTLSTRANSPORTCHANNEL_H_
31
32#include <string>
33#include <vector>
34
35#include "talk/base/buffer.h"
36#include "talk/base/scoped_ptr.h"
37#include "talk/base/sslstreamadapter.h"
38#include "talk/base/stream.h"
39#include "talk/p2p/base/transportchannelimpl.h"
40
41namespace cricket {
42
43// A bridge between a packet-oriented/channel-type interface on
44// the bottom and a StreamInterface on the top.
45class StreamInterfaceChannel : public talk_base::StreamInterface,
46                               public sigslot::has_slots<> {
47 public:
48  StreamInterfaceChannel(talk_base::Thread* owner, TransportChannel* channel)
49      : channel_(channel),
50        state_(talk_base::SS_OPEN),
51        fifo_(kFifoSize, owner) {
52    fifo_.SignalEvent.connect(this, &StreamInterfaceChannel::OnEvent);
53  }
54
55  // Push in a packet; this gets pulled out from Read().
56  bool OnPacketReceived(const char* data, size_t size);
57
58  // Implementations of StreamInterface
59  virtual talk_base::StreamState GetState() const { return state_; }
60  virtual void Close() { state_ = talk_base::SS_CLOSED; }
61  virtual talk_base::StreamResult Read(void* buffer, size_t buffer_len,
62                                       size_t* read, int* error);
63  virtual talk_base::StreamResult Write(const void* data, size_t data_len,
64                                        size_t* written, int* error);
65
66 private:
67  static const size_t kFifoSize = 8192;
68
69  // Forward events
70  virtual void OnEvent(talk_base::StreamInterface* stream, int sig, int err);
71
72  TransportChannel* channel_;  // owned by DtlsTransportChannelWrapper
73  talk_base::StreamState state_;
74  talk_base::FifoBuffer fifo_;
75
76  DISALLOW_COPY_AND_ASSIGN(StreamInterfaceChannel);
77};
78
79
80// This class provides a DTLS SSLStreamAdapter inside a TransportChannel-style
81// packet-based interface, wrapping an existing TransportChannel instance
82// (e.g a P2PTransportChannel)
83// Here's the way this works:
84//
85//   DtlsTransportChannelWrapper {
86//       SSLStreamAdapter* dtls_ {
87//           StreamInterfaceChannel downward_ {
88//               TransportChannelImpl* channel_;
89//           }
90//       }
91//   }
92//
93//   - Data which comes into DtlsTransportChannelWrapper from the underlying
94//     channel_ via OnReadPacket() is checked for whether it is DTLS
95//     or not, and if it is, is passed to DtlsTransportChannelWrapper::
96//     HandleDtlsPacket, which pushes it into to downward_.
97//     dtls_ is listening for events on downward_, so it immediately calls
98//     downward_->Read().
99//
100//   - Data written to DtlsTransportChannelWrapper is passed either to
101//      downward_ or directly to channel_, depending on whether DTLS is
102//     negotiated and whether the flags include PF_SRTP_BYPASS
103//
104//   - The SSLStreamAdapter writes to downward_->Write()
105//     which translates it into packet writes on channel_.
106class DtlsTransportChannelWrapper : public TransportChannelImpl {
107 public:
108    enum State {
109      STATE_NONE,      // No state or rejected.
110      STATE_OFFERED,   // Our identity has been set.
111      STATE_ACCEPTED,  // The other side sent a fingerprint.
112      STATE_STARTED,   // We are negotiating.
113      STATE_OPEN,      // Negotiation complete.
114      STATE_CLOSED     // Connection closed.
115    };
116
117  // The parameters here are:
118  // transport -- the DtlsTransport that created us
119  // channel -- the TransportChannel we are wrapping
120  DtlsTransportChannelWrapper(Transport* transport,
121                              TransportChannelImpl* channel);
122  virtual ~DtlsTransportChannelWrapper();
123
124  virtual void SetIceRole(IceRole role) {
125    channel_->SetIceRole(role);
126  }
127  virtual IceRole GetIceRole() const {
128    return channel_->GetIceRole();
129  }
130  virtual bool SetLocalIdentity(talk_base::SSLIdentity *identity);
131  virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const;
132
133  virtual bool SetRemoteFingerprint(const std::string& digest_alg,
134                                    const uint8* digest,
135                                    size_t digest_len);
136  virtual bool IsDtlsActive() const { return dtls_state_ != STATE_NONE; }
137
138  // Called to send a packet (via DTLS, if turned on).
139  virtual int SendPacket(const char* data, size_t size,
140                         talk_base::DiffServCodePoint dscp,
141                         int flags);
142
143  // TransportChannel calls that we forward to the wrapped transport.
144  virtual int SetOption(talk_base::Socket::Option opt, int value) {
145    return channel_->SetOption(opt, value);
146  }
147  virtual int GetError() {
148    return channel_->GetError();
149  }
150  virtual bool GetStats(ConnectionInfos* infos) {
151    return channel_->GetStats(infos);
152  }
153  virtual const std::string SessionId() const {
154    return channel_->SessionId();
155  }
156
157  // Set up the ciphers to use for DTLS-SRTP. If this method is not called
158  // before DTLS starts, or |ciphers| is empty, SRTP keys won't be negotiated.
159  // This method should be called before SetupDtls.
160  virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers);
161
162  // Find out which DTLS-SRTP cipher was negotiated
163  virtual bool GetSrtpCipher(std::string* cipher);
164
165  virtual bool GetSslRole(talk_base::SSLRole* role) const;
166  virtual bool SetSslRole(talk_base::SSLRole role);
167
168  // Once DTLS has been established, this method retrieves the certificate in
169  // use by the remote peer, for use in external identity verification.
170  virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const;
171
172  // Once DTLS has established (i.e., this channel is writable), this method
173  // extracts the keys negotiated during the DTLS handshake, for use in external
174  // encryption. DTLS-SRTP uses this to extract the needed SRTP keys.
175  // See the SSLStreamAdapter documentation for info on the specific parameters.
176  virtual bool ExportKeyingMaterial(const std::string& label,
177                                    const uint8* context,
178                                    size_t context_len,
179                                    bool use_context,
180                                    uint8* result,
181                                    size_t result_len) {
182    return (dtls_.get()) ? dtls_->ExportKeyingMaterial(label, context,
183                                                       context_len,
184                                                       use_context,
185                                                       result, result_len)
186        : false;
187  }
188
189  // TransportChannelImpl calls.
190  virtual Transport* GetTransport() {
191    return transport_;
192  }
193  virtual void SetIceTiebreaker(uint64 tiebreaker) {
194    channel_->SetIceTiebreaker(tiebreaker);
195  }
196  virtual void SetIceProtocolType(IceProtocolType type) {
197    channel_->SetIceProtocolType(type);
198  }
199  virtual void SetIceCredentials(const std::string& ice_ufrag,
200                                 const std::string& ice_pwd) {
201    channel_->SetIceCredentials(ice_ufrag, ice_pwd);
202  }
203  virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
204                                       const std::string& ice_pwd) {
205    channel_->SetRemoteIceCredentials(ice_ufrag, ice_pwd);
206  }
207  virtual void SetRemoteIceMode(IceMode mode) {
208    channel_->SetRemoteIceMode(mode);
209  }
210
211  virtual void Connect();
212  virtual void Reset();
213
214  virtual void OnSignalingReady() {
215    channel_->OnSignalingReady();
216  }
217  virtual void OnCandidate(const Candidate& candidate) {
218    channel_->OnCandidate(candidate);
219  }
220
221  // Needed by DtlsTransport.
222  TransportChannelImpl* channel() { return channel_; }
223
224 private:
225  void OnReadableState(TransportChannel* channel);
226  void OnWritableState(TransportChannel* channel);
227  void OnReadPacket(TransportChannel* channel, const char* data, size_t size,
228                    const talk_base::PacketTime& packet_time, int flags);
229  void OnReadyToSend(TransportChannel* channel);
230  void OnDtlsEvent(talk_base::StreamInterface* stream_, int sig, int err);
231  bool SetupDtls();
232  bool MaybeStartDtls();
233  bool HandleDtlsPacket(const char* data, size_t size);
234  void OnRequestSignaling(TransportChannelImpl* channel);
235  void OnCandidateReady(TransportChannelImpl* channel, const Candidate& c);
236  void OnCandidatesAllocationDone(TransportChannelImpl* channel);
237  void OnRoleConflict(TransportChannelImpl* channel);
238  void OnRouteChange(TransportChannel* channel, const Candidate& candidate);
239
240  Transport* transport_;  // The transport_ that created us.
241  talk_base::Thread* worker_thread_;  // Everything should occur on this thread.
242  TransportChannelImpl* channel_;  // Underlying channel, owned by transport_.
243  talk_base::scoped_ptr<talk_base::SSLStreamAdapter> dtls_;  // The DTLS stream
244  StreamInterfaceChannel* downward_;  // Wrapper for channel_, owned by dtls_.
245  std::vector<std::string> srtp_ciphers_;  // SRTP ciphers to use with DTLS.
246  State dtls_state_;
247  talk_base::SSLIdentity* local_identity_;
248  talk_base::SSLRole ssl_role_;
249  talk_base::Buffer remote_fingerprint_value_;
250  std::string remote_fingerprint_algorithm_;
251
252  DISALLOW_COPY_AND_ASSIGN(DtlsTransportChannelWrapper);
253};
254
255}  // namespace cricket
256
257#endif  // TALK_P2P_BASE_DTLSTRANSPORTCHANNEL_H_
258