1 /* 2 * libjingle 3 * Copyright 2012, Google, Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #ifndef TALK_P2P_BASE_DTLSTRANSPORT_H_ 29 #define TALK_P2P_BASE_DTLSTRANSPORT_H_ 30 31 #include "talk/p2p/base/dtlstransportchannel.h" 32 #include "talk/p2p/base/transport.h" 33 34 namespace rtc { 35 class SSLIdentity; 36 } 37 38 namespace cricket { 39 40 class PortAllocator; 41 42 // Base should be a descendant of cricket::Transport 43 template<class Base> 44 class DtlsTransport : public Base { 45 public: 46 DtlsTransport(rtc::Thread* signaling_thread, 47 rtc::Thread* worker_thread, 48 const std::string& content_name, 49 PortAllocator* allocator, 50 rtc::SSLIdentity* identity) 51 : Base(signaling_thread, worker_thread, content_name, allocator), 52 identity_(identity), 53 secure_role_(rtc::SSL_CLIENT) { 54 } 55 56 ~DtlsTransport() { 57 Base::DestroyAllChannels(); 58 } 59 virtual void SetIdentity_w(rtc::SSLIdentity* identity) { 60 identity_ = identity; 61 } 62 virtual bool GetIdentity_w(rtc::SSLIdentity** identity) { 63 if (!identity_) 64 return false; 65 66 *identity = identity_->GetReference(); 67 return true; 68 } 69 70 virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel, 71 std::string* error_desc) { 72 rtc::SSLFingerprint* local_fp = 73 Base::local_description()->identity_fingerprint.get(); 74 75 if (local_fp) { 76 // Sanity check local fingerprint. 77 if (identity_) { 78 rtc::scoped_ptr<rtc::SSLFingerprint> local_fp_tmp( 79 rtc::SSLFingerprint::Create(local_fp->algorithm, 80 identity_)); 81 ASSERT(local_fp_tmp.get() != NULL); 82 if (!(*local_fp_tmp == *local_fp)) { 83 std::ostringstream desc; 84 desc << "Local fingerprint does not match identity. Expected: "; 85 desc << local_fp_tmp->ToString(); 86 desc << " Got: " << local_fp->ToString(); 87 return BadTransportDescription(desc.str(), error_desc); 88 } 89 } else { 90 return BadTransportDescription( 91 "Local fingerprint provided but no identity available.", 92 error_desc); 93 } 94 } else { 95 identity_ = NULL; 96 } 97 98 if (!channel->SetLocalIdentity(identity_)) { 99 return BadTransportDescription("Failed to set local identity.", 100 error_desc); 101 } 102 103 // Apply the description in the base class. 104 return Base::ApplyLocalTransportDescription_w(channel, error_desc); 105 } 106 107 virtual bool NegotiateTransportDescription_w(ContentAction local_role, 108 std::string* error_desc) { 109 if (!Base::local_description() || !Base::remote_description()) { 110 const std::string msg = "Local and Remote description must be set before " 111 "transport descriptions are negotiated"; 112 return BadTransportDescription(msg, error_desc); 113 } 114 115 rtc::SSLFingerprint* local_fp = 116 Base::local_description()->identity_fingerprint.get(); 117 rtc::SSLFingerprint* remote_fp = 118 Base::remote_description()->identity_fingerprint.get(); 119 120 if (remote_fp && local_fp) { 121 remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp)); 122 123 // From RFC 4145, section-4.1, The following are the values that the 124 // 'setup' attribute can take in an offer/answer exchange: 125 // Offer Answer 126 // ________________ 127 // active passive / holdconn 128 // passive active / holdconn 129 // actpass active / passive / holdconn 130 // holdconn holdconn 131 // 132 // Set the role that is most conformant with RFC 5763, Section 5, bullet 1 133 // The endpoint MUST use the setup attribute defined in [RFC4145]. 134 // The endpoint that is the offerer MUST use the setup attribute 135 // value of setup:actpass and be prepared to receive a client_hello 136 // before it receives the answer. The answerer MUST use either a 137 // setup attribute value of setup:active or setup:passive. Note that 138 // if the answerer uses setup:passive, then the DTLS handshake will 139 // not begin until the answerer is received, which adds additional 140 // latency. setup:active allows the answer and the DTLS handshake to 141 // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever 142 // party is active MUST initiate a DTLS handshake by sending a 143 // ClientHello over each flow (host/port quartet). 144 // IOW - actpass and passive modes should be treated as server and 145 // active as client. 146 ConnectionRole local_connection_role = 147 Base::local_description()->connection_role; 148 ConnectionRole remote_connection_role = 149 Base::remote_description()->connection_role; 150 151 bool is_remote_server = false; 152 if (local_role == CA_OFFER) { 153 if (local_connection_role != CONNECTIONROLE_ACTPASS) { 154 return BadTransportDescription( 155 "Offerer must use actpass value for setup attribute.", 156 error_desc); 157 } 158 159 if (remote_connection_role == CONNECTIONROLE_ACTIVE || 160 remote_connection_role == CONNECTIONROLE_PASSIVE || 161 remote_connection_role == CONNECTIONROLE_NONE) { 162 is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE); 163 } else { 164 const std::string msg = 165 "Answerer must use either active or passive value " 166 "for setup attribute."; 167 return BadTransportDescription(msg, error_desc); 168 } 169 // If remote is NONE or ACTIVE it will act as client. 170 } else { 171 if (remote_connection_role != CONNECTIONROLE_ACTPASS && 172 remote_connection_role != CONNECTIONROLE_NONE) { 173 return BadTransportDescription( 174 "Offerer must use actpass value for setup attribute.", 175 error_desc); 176 } 177 178 if (local_connection_role == CONNECTIONROLE_ACTIVE || 179 local_connection_role == CONNECTIONROLE_PASSIVE) { 180 is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE); 181 } else { 182 const std::string msg = 183 "Answerer must use either active or passive value " 184 "for setup attribute."; 185 return BadTransportDescription(msg, error_desc); 186 } 187 188 // If local is passive, local will act as server. 189 } 190 191 secure_role_ = is_remote_server ? rtc::SSL_CLIENT : 192 rtc::SSL_SERVER; 193 194 } else if (local_fp && (local_role == CA_ANSWER)) { 195 return BadTransportDescription( 196 "Local fingerprint supplied when caller didn't offer DTLS.", 197 error_desc); 198 } else { 199 // We are not doing DTLS 200 remote_fingerprint_.reset(new rtc::SSLFingerprint( 201 "", NULL, 0)); 202 } 203 204 // Now run the negotiation for the base class. 205 return Base::NegotiateTransportDescription_w(local_role, error_desc); 206 } 207 208 virtual DtlsTransportChannelWrapper* CreateTransportChannel(int component) { 209 return new DtlsTransportChannelWrapper( 210 this, Base::CreateTransportChannel(component)); 211 } 212 213 virtual void DestroyTransportChannel(TransportChannelImpl* channel) { 214 // Kind of ugly, but this lets us do the exact inverse of the create. 215 DtlsTransportChannelWrapper* dtls_channel = 216 static_cast<DtlsTransportChannelWrapper*>(channel); 217 TransportChannelImpl* base_channel = dtls_channel->channel(); 218 delete dtls_channel; 219 Base::DestroyTransportChannel(base_channel); 220 } 221 222 virtual bool GetSslRole_w(rtc::SSLRole* ssl_role) const { 223 ASSERT(ssl_role != NULL); 224 *ssl_role = secure_role_; 225 return true; 226 } 227 228 private: 229 virtual bool ApplyNegotiatedTransportDescription_w( 230 TransportChannelImpl* channel, 231 std::string* error_desc) { 232 // Set ssl role. Role must be set before fingerprint is applied, which 233 // initiates DTLS setup. 234 if (!channel->SetSslRole(secure_role_)) { 235 return BadTransportDescription("Failed to set ssl role for the channel.", 236 error_desc); 237 } 238 // Apply remote fingerprint. 239 if (!channel->SetRemoteFingerprint( 240 remote_fingerprint_->algorithm, 241 reinterpret_cast<const uint8 *>(remote_fingerprint_-> 242 digest.data()), 243 remote_fingerprint_->digest.length())) { 244 return BadTransportDescription("Failed to apply remote fingerprint.", 245 error_desc); 246 } 247 return Base::ApplyNegotiatedTransportDescription_w(channel, error_desc); 248 } 249 250 rtc::SSLIdentity* identity_; 251 rtc::SSLRole secure_role_; 252 rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint_; 253 }; 254 255 } // namespace cricket 256 257 #endif // TALK_P2P_BASE_DTLSTRANSPORT_H_ 258