1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "extensions/browser/api/socket/tls_socket.h" 6 7 #include "base/callback_helpers.h" 8 #include "base/logging.h" 9 #include "extensions/browser/api/api_resource.h" 10 #include "net/base/address_list.h" 11 #include "net/base/ip_endpoint.h" 12 #include "net/base/net_errors.h" 13 #include "net/base/rand_callback.h" 14 #include "net/socket/client_socket_factory.h" 15 #include "net/socket/client_socket_handle.h" 16 #include "net/socket/ssl_client_socket.h" 17 #include "net/socket/tcp_client_socket.h" 18 #include "url/url_canon.h" 19 20 namespace { 21 22 // Returns the SSL protocol version (as a uint16) represented by a string. 23 // Returns 0 if the string is invalid. 24 uint16 SSLProtocolVersionFromString(const std::string& version_str) { 25 uint16 version = 0; // Invalid. 26 if (version_str == "ssl3") { 27 version = net::SSL_PROTOCOL_VERSION_SSL3; 28 } else if (version_str == "tls1") { 29 version = net::SSL_PROTOCOL_VERSION_TLS1; 30 } else if (version_str == "tls1.1") { 31 version = net::SSL_PROTOCOL_VERSION_TLS1_1; 32 } else if (version_str == "tls1.2") { 33 version = net::SSL_PROTOCOL_VERSION_TLS1_2; 34 } 35 return version; 36 } 37 38 void TlsConnectDone(scoped_ptr<net::SSLClientSocket> ssl_socket, 39 const std::string& extension_id, 40 const extensions::TLSSocket::SecureCallback& callback, 41 int result) { 42 DVLOG(1) << "Got back result " << result << " " << net::ErrorToString(result); 43 44 // No matter how the TLS connection attempt went, the underlying socket's 45 // no longer bound to the original TCPSocket. It belongs to |ssl_socket|, 46 // which is promoted here to a new API-accessible socket (via a TLSSocket 47 // wrapper), or deleted. 48 if (result != net::OK) { 49 callback.Run(scoped_ptr<extensions::TLSSocket>(), result); 50 return; 51 }; 52 53 // Wrap the StreamSocket in a TLSSocket, which matches the extension socket 54 // API. Set the handle of the socket to the new value, so that it can be 55 // used for read/write/close/etc. 56 scoped_ptr<extensions::TLSSocket> wrapper(new extensions::TLSSocket( 57 ssl_socket.PassAs<net::StreamSocket>(), extension_id)); 58 59 // Caller will end up deleting the prior TCPSocket, once it calls 60 // SetSocket(..,wrapper). 61 callback.Run(wrapper.Pass(), result); 62 } 63 64 } // namespace 65 66 namespace extensions { 67 68 const char kTLSSocketTypeInvalidError[] = 69 "Cannot listen on a socket that is already connected."; 70 71 TLSSocket::TLSSocket(scoped_ptr<net::StreamSocket> tls_socket, 72 const std::string& owner_extension_id) 73 : ResumableTCPSocket(owner_extension_id), tls_socket_(tls_socket.Pass()) { 74 } 75 76 TLSSocket::~TLSSocket() { 77 Disconnect(); 78 } 79 80 void TLSSocket::Connect(const std::string& address, 81 int port, 82 const CompletionCallback& callback) { 83 callback.Run(net::ERR_CONNECTION_FAILED); 84 } 85 86 void TLSSocket::Disconnect() { 87 if (tls_socket_) { 88 tls_socket_->Disconnect(); 89 tls_socket_.reset(); 90 } 91 } 92 93 void TLSSocket::Read(int count, const ReadCompletionCallback& callback) { 94 DCHECK(!callback.is_null()); 95 96 if (!read_callback_.is_null()) { 97 callback.Run(net::ERR_IO_PENDING, NULL); 98 return; 99 } 100 101 if (count <= 0) { 102 callback.Run(net::ERR_INVALID_ARGUMENT, NULL); 103 return; 104 } 105 106 if (!tls_socket_.get() || !IsConnected()) { 107 callback.Run(net::ERR_SOCKET_NOT_CONNECTED, NULL); 108 return; 109 } 110 111 read_callback_ = callback; 112 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(count)); 113 // |tls_socket_| is owned by this class and the callback won't be run once 114 // |tls_socket_| is gone (as in an a call to Disconnect()). Therefore, it is 115 // safe to use base::Unretained() here. 116 int result = tls_socket_->Read( 117 io_buffer.get(), 118 count, 119 base::Bind( 120 &TLSSocket::OnReadComplete, base::Unretained(this), io_buffer)); 121 122 if (result != net::ERR_IO_PENDING) { 123 OnReadComplete(io_buffer, result); 124 } 125 } 126 127 void TLSSocket::OnReadComplete(const scoped_refptr<net::IOBuffer>& io_buffer, 128 int result) { 129 DCHECK(!read_callback_.is_null()); 130 base::ResetAndReturn(&read_callback_).Run(result, io_buffer); 131 } 132 133 int TLSSocket::WriteImpl(net::IOBuffer* io_buffer, 134 int io_buffer_size, 135 const net::CompletionCallback& callback) { 136 if (!IsConnected()) { 137 return net::ERR_SOCKET_NOT_CONNECTED; 138 } 139 return tls_socket_->Write(io_buffer, io_buffer_size, callback); 140 } 141 142 bool TLSSocket::SetKeepAlive(bool enable, int delay) { 143 return false; 144 } 145 146 bool TLSSocket::SetNoDelay(bool no_delay) { 147 return false; 148 } 149 150 int TLSSocket::Listen(const std::string& address, 151 int port, 152 int backlog, 153 std::string* error_msg) { 154 *error_msg = kTLSSocketTypeInvalidError; 155 return net::ERR_NOT_IMPLEMENTED; 156 } 157 158 void TLSSocket::Accept(const AcceptCompletionCallback& callback) { 159 callback.Run(net::ERR_FAILED, NULL); 160 } 161 162 bool TLSSocket::IsConnected() { 163 return tls_socket_.get() && tls_socket_->IsConnected(); 164 } 165 166 bool TLSSocket::GetPeerAddress(net::IPEndPoint* address) { 167 return IsConnected() && tls_socket_->GetPeerAddress(address); 168 } 169 170 bool TLSSocket::GetLocalAddress(net::IPEndPoint* address) { 171 return IsConnected() && tls_socket_->GetLocalAddress(address); 172 } 173 174 Socket::SocketType TLSSocket::GetSocketType() const { 175 return Socket::TYPE_TLS; 176 } 177 178 // static 179 void TLSSocket::UpgradeSocketToTLS( 180 Socket* socket, 181 scoped_refptr<net::SSLConfigService> ssl_config_service, 182 net::CertVerifier* cert_verifier, 183 net::TransportSecurityState* transport_security_state, 184 const std::string& extension_id, 185 core_api::socket::SecureOptions* options, 186 const TLSSocket::SecureCallback& callback) { 187 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 188 TCPSocket* tcp_socket = static_cast<TCPSocket*>(socket); 189 scoped_ptr<net::SSLClientSocket> null_sock; 190 191 if (!tcp_socket || tcp_socket->GetSocketType() != Socket::TYPE_TCP || 192 !tcp_socket->ClientStream() || !tcp_socket->IsConnected() || 193 tcp_socket->HasPendingRead()) { 194 DVLOG(1) << "Failing before trying. socket is " << tcp_socket; 195 if (tcp_socket) { 196 DVLOG(1) << "type: " << tcp_socket->GetSocketType() 197 << ", ClientStream is " << tcp_socket->ClientStream() 198 << ", IsConnected: " << tcp_socket->IsConnected() 199 << ", HasPendingRead: " << tcp_socket->HasPendingRead(); 200 } 201 TlsConnectDone( 202 null_sock.Pass(), extension_id, callback, net::ERR_INVALID_ARGUMENT); 203 return; 204 } 205 206 net::IPEndPoint dest_host_port_pair; 207 if (!tcp_socket->GetPeerAddress(&dest_host_port_pair)) { 208 DVLOG(1) << "Could not get peer address."; 209 TlsConnectDone( 210 null_sock.Pass(), extension_id, callback, net::ERR_INVALID_ARGUMENT); 211 return; 212 } 213 214 // Convert any U-LABELs to A-LABELs. 215 url::CanonHostInfo host_info; 216 std::string canon_host = 217 net::CanonicalizeHost(tcp_socket->hostname(), &host_info); 218 219 // Canonicalization shouldn't fail: the socket is already connected with a 220 // host, using this hostname. 221 if (host_info.family == url::CanonHostInfo::BROKEN) { 222 DVLOG(1) << "Could not canonicalize hostname"; 223 TlsConnectDone( 224 null_sock.Pass(), extension_id, callback, net::ERR_INVALID_ARGUMENT); 225 return; 226 } 227 228 net::HostPortPair host_and_port(canon_host, dest_host_port_pair.port()); 229 230 scoped_ptr<net::ClientSocketHandle> socket_handle( 231 new net::ClientSocketHandle()); 232 233 // Set the socket handle to the socket's client stream (that should be the 234 // only one active here). Then have the old socket release ownership on 235 // that client stream. 236 socket_handle->SetSocket( 237 scoped_ptr<net::StreamSocket>(tcp_socket->ClientStream())); 238 tcp_socket->Release(); 239 240 DCHECK(transport_security_state); 241 net::SSLClientSocketContext context; 242 context.cert_verifier = cert_verifier; 243 context.transport_security_state = transport_security_state; 244 245 // Fill in the SSL socket params. 246 net::SSLConfig ssl_config; 247 ssl_config_service->GetSSLConfig(&ssl_config); 248 if (options && options->tls_version.get()) { 249 uint16 version_min = 0, version_max = 0; 250 core_api::socket::TLSVersionConstraints* versions = 251 options->tls_version.get(); 252 if (versions->min.get()) { 253 version_min = SSLProtocolVersionFromString(*versions->min.get()); 254 } 255 if (versions->max.get()) { 256 version_max = SSLProtocolVersionFromString(*versions->max.get()); 257 } 258 if (version_min) { 259 ssl_config.version_min = version_min; 260 } 261 if (version_max) { 262 ssl_config.version_max = version_max; 263 } 264 } 265 266 net::ClientSocketFactory* socket_factory = 267 net::ClientSocketFactory::GetDefaultFactory(); 268 269 // Create the socket. 270 scoped_ptr<net::SSLClientSocket> ssl_socket( 271 socket_factory->CreateSSLClientSocket( 272 socket_handle.Pass(), host_and_port, ssl_config, context)); 273 274 DVLOG(1) << "Attempting to secure a connection to " << tcp_socket->hostname() 275 << ":" << dest_host_port_pair.port(); 276 277 // We need the contents of |ssl_socket| in order to invoke its Connect() 278 // method. It belongs to |ssl_socket|, and we own that until our internal 279 // callback (|connect_cb|, below) is invoked. 280 net::SSLClientSocket* saved_ssl_socket = ssl_socket.get(); 281 282 // Try establish a TLS connection. Pass ownership of |ssl_socket| to 283 // TlsConnectDone, which will pass it on to |callback|. |connect_cb| below 284 // is only for UpgradeSocketToTLS use, and not be confused with the 285 // argument |callback|, which gets invoked by TlsConnectDone() after 286 // Connect() below returns. 287 base::Callback<void(int)> connect_cb(base::Bind( 288 &TlsConnectDone, base::Passed(&ssl_socket), extension_id, callback)); 289 int status = saved_ssl_socket->Connect(connect_cb); 290 saved_ssl_socket = NULL; 291 292 // Connect completed synchronously, or failed. 293 if (status != net::ERR_IO_PENDING) { 294 // Note: this can't recurse -- if |socket| is already a connected 295 // TLSSocket, it will return TYPE_TLS instead of TYPE_TCP, causing 296 // UpgradeSocketToTLS() to fail with an error above. If 297 // UpgradeSocketToTLS() is called on |socket| twice, the call to 298 // Release() on |socket| above causes the additional call to 299 // fail with an error above. 300 if (status != net::OK) { 301 DVLOG(1) << "Status is not OK or IO-pending: " 302 << net::ErrorToString(status); 303 } 304 connect_cb.Run(status); 305 } 306 } 307 308 } // namespace extensions 309 310