blob: 94a9f49da9f71f20c48c048eb6f45db20bceae4f [file] [log] [blame]
// 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