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