| /* | 
 |  *  Copyright 2012 The WebRTC Project Authors. All rights reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #ifndef WEBRTC_P2P_BASE_DTLSTRANSPORT_H_ | 
 | #define WEBRTC_P2P_BASE_DTLSTRANSPORT_H_ | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "webrtc/p2p/base/dtlstransportchannel.h" | 
 | #include "webrtc/p2p/base/transport.h" | 
 |  | 
 | namespace rtc { | 
 | class SSLIdentity; | 
 | } | 
 |  | 
 | namespace cricket { | 
 |  | 
 | class PortAllocator; | 
 |  | 
 | // Base should be a descendant of cricket::Transport and have a constructor | 
 | // that takes a transport name and PortAllocator. | 
 | // | 
 | // Everything in this class should be called on the worker thread. | 
 | template<class Base> | 
 | class DtlsTransport : public Base { | 
 |  public: | 
 |   DtlsTransport(const std::string& name, | 
 |                 PortAllocator* allocator, | 
 |                 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) | 
 |       : Base(name, allocator), | 
 |         certificate_(certificate), | 
 |         secure_role_(rtc::SSL_CLIENT), | 
 |         ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_12) {} | 
 |  | 
 |   ~DtlsTransport() { | 
 |     Base::DestroyAllChannels(); | 
 |   } | 
 |  | 
 |   void SetLocalCertificate( | 
 |       const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override { | 
 |     certificate_ = certificate; | 
 |   } | 
 |   bool GetLocalCertificate( | 
 |       rtc::scoped_refptr<rtc::RTCCertificate>* certificate) override { | 
 |     if (!certificate_) | 
 |       return false; | 
 |  | 
 |     *certificate = certificate_; | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override { | 
 |     ssl_max_version_ = version; | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool ApplyLocalTransportDescription(TransportChannelImpl* channel, | 
 |                                       std::string* error_desc) override { | 
 |     rtc::SSLFingerprint* local_fp = | 
 |         Base::local_description()->identity_fingerprint.get(); | 
 |  | 
 |     if (!local_fp) { | 
 |       certificate_ = nullptr; | 
 |     } else if (!Base::VerifyCertificateFingerprint(certificate_.get(), local_fp, | 
 |                                                    error_desc)) { | 
 |       return false; | 
 |     } | 
 |  | 
 |     if (!channel->SetLocalCertificate(certificate_)) { | 
 |       return BadTransportDescription("Failed to set local identity.", | 
 |                                      error_desc); | 
 |     } | 
 |  | 
 |     // Apply the description in the base class. | 
 |     return Base::ApplyLocalTransportDescription(channel, error_desc); | 
 |   } | 
 |  | 
 |   bool NegotiateTransportDescription(ContentAction local_role, | 
 |                                      std::string* error_desc) override { | 
 |     if (!Base::local_description() || !Base::remote_description()) { | 
 |       const std::string msg = "Local and Remote description must be set before " | 
 |                               "transport descriptions are negotiated"; | 
 |       return BadTransportDescription(msg, error_desc); | 
 |     } | 
 |     rtc::SSLFingerprint* local_fp = | 
 |         Base::local_description()->identity_fingerprint.get(); | 
 |     rtc::SSLFingerprint* remote_fp = | 
 |         Base::remote_description()->identity_fingerprint.get(); | 
 |     if (remote_fp && local_fp) { | 
 |       remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp)); | 
 |       if (!Base::NegotiateRole(local_role, &secure_role_, error_desc)) { | 
 |         return false; | 
 |       } | 
 |     } else if (local_fp && (local_role == CA_ANSWER)) { | 
 |       return BadTransportDescription( | 
 |           "Local fingerprint supplied when caller didn't offer DTLS.", | 
 |           error_desc); | 
 |     } else { | 
 |       // We are not doing DTLS | 
 |       remote_fingerprint_.reset(new rtc::SSLFingerprint("", nullptr, 0)); | 
 |     } | 
 |     // Now run the negotiation for the base class. | 
 |     return Base::NegotiateTransportDescription(local_role, error_desc); | 
 |   } | 
 |  | 
 |   DtlsTransportChannelWrapper* CreateTransportChannel(int component) override { | 
 |     DtlsTransportChannelWrapper* channel = new DtlsTransportChannelWrapper( | 
 |         Base::CreateTransportChannel(component)); | 
 |     channel->SetSslMaxProtocolVersion(ssl_max_version_); | 
 |     return channel; | 
 |   } | 
 |  | 
 |   void DestroyTransportChannel(TransportChannelImpl* channel) override { | 
 |     // Kind of ugly, but this lets us do the exact inverse of the create. | 
 |     DtlsTransportChannelWrapper* dtls_channel = | 
 |         static_cast<DtlsTransportChannelWrapper*>(channel); | 
 |     TransportChannelImpl* base_channel = dtls_channel->channel(); | 
 |     delete dtls_channel; | 
 |     Base::DestroyTransportChannel(base_channel); | 
 |   } | 
 |  | 
 |   bool GetSslRole(rtc::SSLRole* ssl_role) const override { | 
 |     ASSERT(ssl_role != NULL); | 
 |     *ssl_role = secure_role_; | 
 |     return true; | 
 |   } | 
 |  | 
 |  private: | 
 |   bool ApplyNegotiatedTransportDescription(TransportChannelImpl* channel, | 
 |                                            std::string* error_desc) override { | 
 |     // Set ssl role. Role must be set before fingerprint is applied, which | 
 |     // initiates DTLS setup. | 
 |     if (!channel->SetSslRole(secure_role_)) { | 
 |       return BadTransportDescription("Failed to set ssl role for the channel.", | 
 |                                      error_desc); | 
 |     } | 
 |     // Apply remote fingerprint. | 
 |     if (!channel->SetRemoteFingerprint(remote_fingerprint_->algorithm, | 
 |                                        reinterpret_cast<const uint8_t*>( | 
 |                                            remote_fingerprint_->digest.data()), | 
 |                                        remote_fingerprint_->digest.size())) { | 
 |       return BadTransportDescription("Failed to apply remote fingerprint.", | 
 |                                      error_desc); | 
 |     } | 
 |     return Base::ApplyNegotiatedTransportDescription(channel, error_desc); | 
 |   } | 
 |  | 
 |   rtc::scoped_refptr<rtc::RTCCertificate> certificate_; | 
 |   rtc::SSLRole secure_role_; | 
 |   rtc::SSLProtocolVersion ssl_max_version_; | 
 |   std::unique_ptr<rtc::SSLFingerprint> remote_fingerprint_; | 
 | }; | 
 |  | 
 | }  // namespace cricket | 
 |  | 
 | #endif  // WEBRTC_P2P_BASE_DTLSTRANSPORT_H_ |