Home | History | Annotate | Download | only in base
      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:
     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