| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/openscreen_platform/tls_connection_factory.h" |
| |
| #include <openssl/pool.h> |
| #include <utility> |
| |
| #include "base/logging.h" |
| #include "components/openscreen_platform/network_util.h" |
| #include "components/openscreen_platform/tls_client_connection.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/net_errors.h" |
| #include "net/ssl/ssl_info.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| #include "third_party/openscreen/src/platform/api/tls_connection.h" |
| #include "third_party/openscreen/src/platform/base/tls_connect_options.h" |
| #include "third_party/openscreen/src/platform/base/tls_credentials.h" |
| #include "third_party/openscreen/src/platform/base/tls_listen_options.h" |
| |
| namespace openscreen { |
| |
| std::unique_ptr<TlsConnectionFactory> TlsConnectionFactory::CreateFactory( |
| Client* client, |
| TaskRunner* task_runner) { |
| return std::make_unique<openscreen_platform::TlsConnectionFactory>( |
| client, task_runner, nullptr /* network context */); |
| } |
| |
| } // namespace openscreen |
| |
| namespace openscreen_platform { |
| |
| namespace { |
| |
| using openscreen::IPEndpoint; |
| using openscreen::TlsConnectOptions; |
| using openscreen::TlsCredentials; |
| using openscreen::TlsListenOptions; |
| |
| constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation = |
| net::DefineNetworkTrafficAnnotation("openscreen_tls_message", R"( |
| semantics { |
| sender: "Open Screen" |
| description: |
| "Open Screen TLS messages are used by the third_party Open Screen " |
| "library, primarily for the libcast CastSocket implementation." |
| trigger: |
| "Any TLS encrypted message that needs to be sent or received by " |
| "the Open Screen library." |
| data: |
| "Messages defined by the Open Screen Protocol specification." |
| destination: OTHER |
| destination_other: |
| "The connection is made to an Open Screen endpoint on the LAN " |
| "selected by the user, i.e. via a dialog." |
| } |
| policy { |
| cookies_allowed: NO |
| setting: |
| "This request cannot be disabled, but it would not be sent if user " |
| "does not connect to a Open Screen endpoint on the local network." |
| policy_exception_justification: "Not implemented." |
| })"); |
| |
| } // namespace |
| |
| TlsConnectionFactory::~TlsConnectionFactory() = default; |
| |
| void TlsConnectionFactory::Connect(const IPEndpoint& remote_address, |
| const TlsConnectOptions& options) { |
| network::mojom::NetworkContext* network_context = network_context_; |
| // TODO(btolsch): Add fall-back lookup in follow-up NetworkContext patch. |
| if (!network_context) { |
| client_->OnError(this, openscreen::Error::Code::kItemNotFound); |
| return; |
| } |
| |
| TcpConnectRequest request(options, remote_address, |
| mojo::Remote<network::mojom::TCPConnectedSocket>{}); |
| |
| const net::AddressList address_list( |
| openscreen_platform::ToNetEndPoint(remote_address)); |
| |
| mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver = |
| request.tcp_socket.BindNewPipeAndPassReceiver(); |
| |
| network_context->CreateTCPConnectedSocket( |
| base::nullopt /* local_addr */, address_list, |
| nullptr /* tcp_connected_socket_options */, |
| net::MutableNetworkTrafficAnnotationTag(kTrafficAnnotation), |
| std::move(receiver), mojo::NullRemote(), /* observer */ |
| base::BindOnce(&TlsConnectionFactory::OnTcpConnect, |
| weak_factory_.GetWeakPtr(), std::move(request))); |
| } |
| |
| void TlsConnectionFactory::SetListenCredentials( |
| const TlsCredentials& credentials) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void TlsConnectionFactory::Listen(const IPEndpoint& local_address, |
| const TlsListenOptions& options) { |
| NOTIMPLEMENTED(); |
| } |
| |
| TlsConnectionFactory::TlsConnectionFactory( |
| openscreen::TlsConnectionFactory::Client* client, |
| openscreen::TaskRunner* task_runner, |
| network::mojom::NetworkContext* network_context) |
| : client_(client), |
| task_runner_(task_runner), |
| network_context_(network_context) {} |
| |
| TlsConnectionFactory::TcpConnectRequest::TcpConnectRequest( |
| openscreen::TlsConnectOptions options_in, |
| openscreen::IPEndpoint remote_address_in, |
| mojo::Remote<network::mojom::TCPConnectedSocket> tcp_socket_in) |
| : options(std::move(options_in)), |
| remote_address(std::move(remote_address_in)), |
| tcp_socket(std::move(tcp_socket_in)) {} |
| TlsConnectionFactory::TcpConnectRequest::TcpConnectRequest( |
| TcpConnectRequest&&) = default; |
| TlsConnectionFactory::TcpConnectRequest& |
| TlsConnectionFactory::TcpConnectRequest::operator=(TcpConnectRequest&&) = |
| default; |
| |
| TlsConnectionFactory::TcpConnectRequest::~TcpConnectRequest() = default; |
| |
| TlsConnectionFactory::TlsUpgradeRequest::TlsUpgradeRequest( |
| openscreen::IPEndpoint local_address_in, |
| openscreen::IPEndpoint remote_address_in, |
| mojo::Remote<network::mojom::TCPConnectedSocket> tcp_socket_in, |
| mojo::Remote<network::mojom::TLSClientSocket> tls_socket_in) |
| : local_address(std::move(local_address_in)), |
| remote_address(std::move(remote_address_in)), |
| tcp_socket(std::move(tcp_socket_in)), |
| tls_socket(std::move(tls_socket_in)) {} |
| TlsConnectionFactory::TlsUpgradeRequest::TlsUpgradeRequest( |
| TlsUpgradeRequest&&) = default; |
| TlsConnectionFactory::TlsUpgradeRequest& |
| TlsConnectionFactory::TlsUpgradeRequest::operator=(TlsUpgradeRequest&&) = |
| default; |
| TlsConnectionFactory::TlsUpgradeRequest::~TlsUpgradeRequest() = default; |
| |
| void TlsConnectionFactory::OnTcpConnect( |
| TcpConnectRequest request, |
| int32_t net_result, |
| const base::Optional<net::IPEndPoint>& local_address, |
| const base::Optional<net::IPEndPoint>& remote_address, |
| mojo::ScopedDataPipeConsumerHandle receive_stream, |
| mojo::ScopedDataPipeProducerHandle send_stream) { |
| // We only care about net_result, since local_address doesn't matter, |
| // remote_address should be 1 out of 1 addresses provided in the connect |
| // call, and the streams must be closed before upgrading is allowed. |
| if (net_result != net::OK) { |
| client_->OnConnectionFailed(this, request.remote_address); |
| return; |
| } |
| |
| net::HostPortPair host_port_pair = net::HostPortPair::FromIPEndPoint( |
| openscreen_platform::ToNetEndPoint(request.remote_address)); |
| network::mojom::TLSClientSocketOptionsPtr options = |
| network::mojom::TLSClientSocketOptions::New(); |
| options->unsafely_skip_cert_verification = |
| request.options.unsafely_skip_certificate_validation; |
| |
| openscreen::IPEndpoint local_endpoint{}; |
| if (local_address) { |
| local_endpoint = |
| openscreen_platform::ToOpenScreenEndPoint(local_address.value()); |
| } |
| |
| TlsUpgradeRequest upgrade_request( |
| std::move(local_endpoint), std::move(request.remote_address), |
| std::move(request.tcp_socket), |
| mojo::Remote<network::mojom::TLSClientSocket>{}); |
| |
| network::mojom::TCPConnectedSocket* tcp_socket = |
| upgrade_request.tcp_socket.get(); |
| mojo::PendingReceiver<network::mojom::TLSClientSocket> tls_receiver = |
| upgrade_request.tls_socket.BindNewPipeAndPassReceiver(); |
| |
| tcp_socket->UpgradeToTLS( |
| host_port_pair, std::move(options), |
| net::MutableNetworkTrafficAnnotationTag(kTrafficAnnotation), |
| std::move(tls_receiver), mojo::NullRemote() /* observer */, |
| base::BindOnce(&TlsConnectionFactory::OnTlsUpgrade, |
| weak_factory_.GetWeakPtr(), std::move(upgrade_request))); |
| } |
| |
| void TlsConnectionFactory::OnTlsUpgrade( |
| TlsUpgradeRequest request, |
| int32_t net_result, |
| mojo::ScopedDataPipeConsumerHandle receive_stream, |
| mojo::ScopedDataPipeProducerHandle send_stream, |
| const base::Optional<net::SSLInfo>& ssl_info) { |
| if (net_result != net::OK) { |
| client_->OnConnectionFailed(this, request.remote_address); |
| return; |
| } |
| |
| auto tls_connection = std::make_unique<TlsClientConnection>( |
| task_runner_, request.local_address, request.remote_address, |
| std::move(receive_stream), std::move(send_stream), |
| std::move(request.tcp_socket), std::move(request.tls_socket)); |
| |
| CRYPTO_BUFFER* der_buffer = ssl_info.value().unverified_cert->cert_buffer(); |
| const uint8_t* data = CRYPTO_BUFFER_data(der_buffer); |
| std::vector<uint8_t> der_x509_certificate( |
| data, data + CRYPTO_BUFFER_len(der_buffer)); |
| client_->OnConnected(this, std::move(der_x509_certificate), |
| std::move(tls_connection)); |
| } |
| |
| } // namespace openscreen_platform |