Split the TLS session cache by NetworkIsolationKey
Bug: 974910
Change-Id: I953e55aa4ef55d2d4bf0d74848e9354eddd15531
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1672233
Commit-Queue: David Benjamin <davidben@chromium.org>
Reviewed-by: Matt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672717}
diff --git a/net/base/features.cc b/net/base/features.cc
index 0e66209..4cc6a52 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -31,6 +31,10 @@
"PartitionConnectionsByNetworkIsolationKey",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPartitionSSLSessionsByNetworkIsolationKey{
+ "PartitionSSLSessionsByNetworkIsolationKey",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kTLS13KeyUpdate{"TLS13KeyUpdate",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/net/base/features.h b/net/base/features.h
index 6a9526f..6e387b22 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -44,6 +44,14 @@
NET_EXPORT extern const base::Feature
kPartitionConnectionsByNetworkIsolationKey;
+// Partitions TLS sessions and QUIC server configs based on the
+// NetworkIsolationKey associated with a request.
+//
+// This feature requires kPartitionConnectionsByNetworkIsolationKey to be
+// enabled to work.
+NET_EXPORT extern const base::Feature
+ kPartitionSSLSessionsByNetworkIsolationKey;
+
// Enables sending TLS 1.3 Key Update messages on TLS 1.3 connections in order
// to ensure that this corner of the spec is exercised. This is currently
// disabled by default because we discovered incompatibilities with some
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 7de86957..388842c8 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -21235,4 +21235,220 @@
}
}
+// Test that the NetworkIsolationKey is passed down to SSLConfig so the session
+// cache is isolated.
+TEST_F(HttpNetworkTransactionTest, NetworkIsolationSSL) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ {features::kPartitionConnectionsByNetworkIsolationKey,
+ features::kPartitionSSLSessionsByNetworkIsolationKey},
+ {});
+
+ const NetworkIsolationKey kNetworkIsolationKey1(
+ url::Origin::Create(GURL("http://origin1/")));
+ const NetworkIsolationKey kNetworkIsolationKey2(
+ url::Origin::Create(GURL("http://origin2/")));
+ std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+ // The server always sends Connection: close, so each request goes over a
+ // distinct socket.
+
+ const MockWrite kWrites1[] = {
+ MockWrite("GET /1 HTTP/1.1\r\n"
+ "Host: foo.test\r\n"
+ "Connection: keep-alive\r\n\r\n")};
+
+ const MockRead kReads1[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: 1\r\n\r\n"
+ "1")};
+
+ const MockWrite kWrites2[] = {
+ MockWrite("GET /2 HTTP/1.1\r\n"
+ "Host: foo.test\r\n"
+ "Connection: keep-alive\r\n\r\n")};
+
+ const MockRead kReads2[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: 1\r\n\r\n"
+ "2")};
+
+ const MockWrite kWrites3[] = {
+ MockWrite("GET /3 HTTP/1.1\r\n"
+ "Host: foo.test\r\n"
+ "Connection: keep-alive\r\n\r\n")};
+
+ const MockRead kReads3[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: 1\r\n\r\n"
+ "3")};
+
+ StaticSocketDataProvider data1(kReads1, kWrites1);
+ StaticSocketDataProvider data2(kReads2, kWrites2);
+ StaticSocketDataProvider data3(kReads3, kWrites3);
+ session_deps_.socket_factory->AddSocketDataProvider(&data1);
+ session_deps_.socket_factory->AddSocketDataProvider(&data2);
+ session_deps_.socket_factory->AddSocketDataProvider(&data3);
+
+ SSLSocketDataProvider ssl_data1(ASYNC, OK);
+ ssl_data1.expected_host_and_port = HostPortPair("foo.test", 443);
+ ssl_data1.expected_network_isolation_key = kNetworkIsolationKey1;
+ SSLSocketDataProvider ssl_data2(ASYNC, OK);
+ ssl_data2.expected_host_and_port = HostPortPair("foo.test", 443);
+ ssl_data2.expected_network_isolation_key = kNetworkIsolationKey2;
+ SSLSocketDataProvider ssl_data3(ASYNC, OK);
+ ssl_data3.expected_host_and_port = HostPortPair("foo.test", 443);
+ ssl_data3.expected_network_isolation_key = kNetworkIsolationKey1;
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data3);
+
+ TestCompletionCallback callback;
+ HttpRequestInfo request1;
+ request1.method = "GET";
+ request1.url = GURL("https://foo.test/1");
+ request1.traffic_annotation =
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+ request1.network_isolation_key = kNetworkIsolationKey1;
+ auto trans1 =
+ std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
+ int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+ std::string response_data1;
+ EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
+ EXPECT_EQ("1", response_data1);
+ trans1.reset();
+
+ HttpRequestInfo request2;
+ request2.method = "GET";
+ request2.url = GURL("https://foo.test/2");
+ request2.traffic_annotation =
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+ request2.network_isolation_key = kNetworkIsolationKey2;
+ auto trans2 =
+ std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
+ rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+ std::string response_data2;
+ EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
+ EXPECT_EQ("2", response_data2);
+ trans2.reset();
+
+ HttpRequestInfo request3;
+ request3.method = "GET";
+ request3.url = GURL("https://foo.test/3");
+ request3.traffic_annotation =
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+ request3.network_isolation_key = kNetworkIsolationKey1;
+ auto trans3 =
+ std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
+ rv = trans3->Start(&request3, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+ std::string response_data3;
+ EXPECT_THAT(ReadTransaction(trans3.get(), &response_data3), IsOk());
+ EXPECT_EQ("3", response_data3);
+ trans3.reset();
+}
+
+// Test that the NetworkIsolationKey is passed down to SSLConfig so the session
+// cache is isolated, for both origins and proxies.
+TEST_F(HttpNetworkTransactionTest, NetworkIsolationSSLProxy) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ {features::kPartitionConnectionsByNetworkIsolationKey,
+ features::kPartitionSSLSessionsByNetworkIsolationKey},
+ {});
+
+ session_deps_.proxy_resolution_service = ProxyResolutionService::CreateFixed(
+ "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
+
+ const NetworkIsolationKey kNetworkIsolationKey1(
+ url::Origin::Create(GURL("http://origin1/")));
+ const NetworkIsolationKey kNetworkIsolationKey2(
+ url::Origin::Create(GURL("http://origin2/")));
+ std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+ // Make both a tunneled and non-tunneled request.
+ HttpRequestInfo request1;
+ request1.method = "GET";
+ request1.url = GURL("https://foo.test/1");
+ request1.traffic_annotation =
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+ request1.network_isolation_key = kNetworkIsolationKey1;
+
+ HttpRequestInfo request2;
+ request2.method = "GET";
+ request2.url = GURL("http://foo.test/2");
+ request2.traffic_annotation =
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+ request2.network_isolation_key = kNetworkIsolationKey2;
+
+ const MockWrite kWrites1[] = {
+ MockWrite("CONNECT foo.test:443 HTTP/1.1\r\n"
+ "Host: foo.test:443\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"),
+ MockWrite("GET /1 HTTP/1.1\r\n"
+ "Host: foo.test\r\n"
+ "Connection: keep-alive\r\n\r\n")};
+
+ const MockRead kReads1[] = {
+ MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: 1\r\n\r\n"
+ "1")};
+
+ const MockWrite kWrites2[] = {
+ MockWrite("GET http://foo.test/2 HTTP/1.1\r\n"
+ "Host: foo.test\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n")};
+
+ const MockRead kReads2[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: 1\r\n\r\n"
+ "2")};
+
+ StaticSocketDataProvider data1(kReads1, kWrites1);
+ StaticSocketDataProvider data2(kReads2, kWrites2);
+ session_deps_.socket_factory->AddSocketDataProvider(&data1);
+ session_deps_.socket_factory->AddSocketDataProvider(&data2);
+ session_deps_.socket_factory->AddSocketDataProvider(&data2);
+
+ SSLSocketDataProvider ssl_proxy1(ASYNC, OK);
+ ssl_proxy1.expected_host_and_port = HostPortPair("myproxy", 70);
+ ssl_proxy1.expected_network_isolation_key = kNetworkIsolationKey1;
+ SSLSocketDataProvider ssl_origin1(ASYNC, OK);
+ ssl_origin1.expected_host_and_port = HostPortPair("foo.test", 443);
+ ssl_origin1.expected_network_isolation_key = kNetworkIsolationKey1;
+ SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
+ ssl_proxy2.expected_host_and_port = HostPortPair("myproxy", 70);
+ ssl_proxy2.expected_network_isolation_key = kNetworkIsolationKey2;
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin1);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
+
+ TestCompletionCallback callback;
+ auto trans1 =
+ std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
+ int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+ std::string response_data1;
+ EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
+ EXPECT_EQ("1", response_data1);
+ trans1.reset();
+
+ auto trans2 =
+ std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
+ rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+ std::string response_data2;
+ EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
+ EXPECT_EQ("2", response_data2);
+ trans2.reset();
+}
+
} // namespace net
diff --git a/net/http/http_proxy_connect_job_unittest.cc b/net/http/http_proxy_connect_job_unittest.cc
index f555b9f1..560525e 100644
--- a/net/http/http_proxy_connect_job_unittest.cc
+++ b/net/http/http_proxy_connect_job_unittest.cc
@@ -125,7 +125,7 @@
base::MakeRefCounted<TransportSocketParams>(
HostPortPair(kHttpsProxyHost, 443), OnHostResolutionCallback()),
nullptr, nullptr, HostPortPair(kHttpsProxyHost, 443), SSLConfig(),
- PRIVACY_MODE_DISABLED);
+ PRIVACY_MODE_DISABLED, NetworkIsolationKey());
}
// Returns a correctly constructed HttpProxyParams for the HTTP or HTTPS
diff --git a/net/socket/connect_job.cc b/net/socket/connect_job.cc
index 871d0f5..015b416 100644
--- a/net/socket/connect_job.cc
+++ b/net/socket/connect_job.cc
@@ -129,7 +129,7 @@
ssl_params = base::MakeRefCounted<SSLSocketParams>(
std::move(proxy_tcp_params), nullptr, nullptr,
proxy_server.host_port_pair(), *ssl_config_for_proxy,
- PRIVACY_MODE_DISABLED);
+ PRIVACY_MODE_DISABLED, network_isolation_key);
proxy_tcp_params = nullptr;
}
@@ -158,7 +158,7 @@
auto ssl_params = base::MakeRefCounted<SSLSocketParams>(
std::move(ssl_tcp_params), std::move(socks_params),
std::move(http_proxy_params), endpoint, *ssl_config_for_origin,
- privacy_mode);
+ privacy_mode, network_isolation_key);
return std::make_unique<SSLConnectJob>(
request_priority, socket_tag, common_connect_job_params,
std::move(ssl_params), delegate, nullptr /* net_log */);
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index c371d50..69c1f95 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -824,6 +824,13 @@
EXPECT_EQ(*next_ssl_data->expected_false_start_enabled,
ssl_config.false_start_enabled);
}
+ if (next_ssl_data->expected_host_and_port) {
+ EXPECT_EQ(*next_ssl_data->expected_host_and_port, host_and_port);
+ }
+ if (next_ssl_data->expected_network_isolation_key) {
+ EXPECT_EQ(*next_ssl_data->expected_network_isolation_key,
+ ssl_config.network_isolation_key);
+ }
return std::unique_ptr<SSLClientSocket>(new MockSSLClientSocket(
std::move(stream_socket), host_and_port, ssl_config, next_ssl_data));
}
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index d4ae682..9a53e1c 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -495,6 +495,8 @@
base::Optional<bool> expected_send_client_cert;
scoped_refptr<X509Certificate> expected_client_cert;
base::Optional<bool> expected_false_start_enabled;
+ base::Optional<HostPortPair> expected_host_and_port;
+ base::Optional<NetworkIsolationKey> expected_network_isolation_key;
bool is_connect_data_consumed = false;
bool is_confirm_data_consumed = false;
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 857dc8a0..119863e 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -14,6 +14,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/containers/span.h"
+#include "base/feature_list.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
@@ -1622,6 +1623,11 @@
}
std::string SSLClientSocketImpl::GetSessionCacheKey() const {
+ if (base::FeatureList::IsEnabled(
+ features::kPartitionSSLSessionsByNetworkIsolationKey)) {
+ return host_and_port_.ToString() + '/' +
+ ssl_config_.network_isolation_key.ToString();
+ }
return host_and_port_.ToString();
}
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index f07bdcd..108be75 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -34,6 +34,7 @@
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
+#include "net/base/network_isolation_key.h"
#include "net/base/test_completion_callback.h"
#include "net/cert/asn1_util.h"
#include "net/cert/ct_policy_enforcer.h"
@@ -85,6 +86,8 @@
#include "third_party/boringssl/src/include/openssl/bio.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/pem.h"
+#include "url/gurl.h"
+#include "url/origin.h"
using net::test::IsError;
using net::test::IsOk;
@@ -3170,6 +3173,120 @@
EXPECT_EQ(kProtoHTTP11, sock_->GetNegotiatedProtocol());
}
+// Tests that the session cache is not sharded by NetworkIsolationKey if the
+// feature is disabled.
+TEST_F(SSLClientSocketTest, SessionResumptionNetworkIsolationKeyDisabled) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ features::kPartitionSSLSessionsByNetworkIsolationKey);
+
+ SpawnedTestServer::SSLOptions ssl_options;
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ // First, perform a full handshake.
+ SSLConfig ssl_config;
+ int rv;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ SSLInfo ssl_info;
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
+
+ // The next connection should resume.
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+ sock_.reset();
+
+ // Using a different NetworkIsolationKey shares session cache key because
+ // sharding is disabled.
+ ssl_config.network_isolation_key =
+ NetworkIsolationKey(url::Origin::Create(GURL("https://a.test")));
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+ sock_.reset();
+
+ ssl_config.network_isolation_key =
+ NetworkIsolationKey(url::Origin::Create(GURL("https://b.test")));
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+ sock_.reset();
+}
+
+// Tests that the session cache is sharded by NetworkIsolationKey if the
+// feature is enabled.
+TEST_F(SSLClientSocketTest, SessionResumptionNetworkIsolationKeyEnabled) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kPartitionSSLSessionsByNetworkIsolationKey);
+
+ const NetworkIsolationKey kNetworkIsolationKeyA(
+ url::Origin::Create(GURL("https://a.test")));
+ const NetworkIsolationKey kNetworkIsolationKeyB(
+ url::Origin::Create(GURL("https://b.test")));
+
+ SpawnedTestServer::SSLOptions ssl_options;
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ // First, perform a full handshake.
+ SSLConfig ssl_config;
+ int rv;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ SSLInfo ssl_info;
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
+
+ // The next connection should resume.
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+ sock_.reset();
+
+ // Using a different NetworkIsolationKey uses a different session cache key.
+ ssl_config.network_isolation_key = kNetworkIsolationKeyA;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
+ sock_.reset();
+
+ // We, however, can resume under that newly-established session.
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+ sock_.reset();
+
+ // Repeat with another non-null key.
+ ssl_config.network_isolation_key = kNetworkIsolationKeyB;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
+ sock_.reset();
+
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+ sock_.reset();
+
+ // b.test does not evict a.test's session.
+ ssl_config.network_isolation_key = kNetworkIsolationKeyA;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+ sock_.reset();
+}
+
// Tests that connections with certificate errors do not add entries to the
// session cache.
TEST_F(SSLClientSocketTest, CertificateErrorNoResume) {
diff --git a/net/socket/ssl_connect_job.cc b/net/socket/ssl_connect_job.cc
index 3c512cd..c5c936b 100644
--- a/net/socket/ssl_connect_job.cc
+++ b/net/socket/ssl_connect_job.cc
@@ -46,13 +46,15 @@
scoped_refptr<HttpProxySocketParams> http_proxy_params,
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
- PrivacyMode privacy_mode)
+ PrivacyMode privacy_mode,
+ NetworkIsolationKey network_isolation_key)
: direct_params_(std::move(direct_params)),
socks_proxy_params_(std::move(socks_proxy_params)),
http_proxy_params_(std::move(http_proxy_params)),
host_and_port_(host_and_port),
ssl_config_(ssl_config),
- privacy_mode_(privacy_mode) {
+ privacy_mode_(privacy_mode),
+ network_isolation_key_(network_isolation_key) {
// Only one set of lower level ConnectJob params should be non-NULL.
DCHECK((direct_params_ && !socks_proxy_params_ && !http_proxy_params_) ||
(!direct_params_ && socks_proxy_params_ && !http_proxy_params_) ||
@@ -355,9 +357,10 @@
? ssl_client_socket_context_privacy_mode()
: ssl_client_socket_context();
+ SSLConfig ssl_config = params_->ssl_config();
+ ssl_config.network_isolation_key = params_->network_isolation_key();
ssl_socket_ = client_socket_factory()->CreateSSLClientSocket(
- std::move(nested_socket_), params_->host_and_port(),
- params_->ssl_config(), context);
+ std::move(nested_socket_), params_->host_and_port(), ssl_config, context);
nested_connect_job_.reset();
return ssl_socket_->Connect(callback_);
}
diff --git a/net/socket/ssl_connect_job.h b/net/socket/ssl_connect_job.h
index bc19886..575f4293 100644
--- a/net/socket/ssl_connect_job.h
+++ b/net/socket/ssl_connect_job.h
@@ -14,6 +14,7 @@
#include "net/base/completion_once_callback.h"
#include "net/base/completion_repeating_callback.h"
#include "net/base/net_export.h"
+#include "net/base/network_isolation_key.h"
#include "net/base/privacy_mode.h"
#include "net/socket/connect_job.h"
#include "net/socket/connection_attempts.h"
@@ -41,7 +42,8 @@
scoped_refptr<HttpProxySocketParams> http_proxy_params,
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
- PrivacyMode privacy_mode);
+ PrivacyMode privacy_mode,
+ NetworkIsolationKey network_isolation_key);
// Returns the type of the underlying connection.
ConnectionType GetConnectionType() const;
@@ -59,6 +61,9 @@
const HostPortPair& host_and_port() const { return host_and_port_; }
const SSLConfig& ssl_config() const { return ssl_config_; }
PrivacyMode privacy_mode() const { return privacy_mode_; }
+ const NetworkIsolationKey& network_isolation_key() const {
+ return network_isolation_key_;
+ }
private:
friend class base::RefCounted<SSLSocketParams>;
@@ -70,6 +75,7 @@
const HostPortPair host_and_port_;
const SSLConfig ssl_config_;
const PrivacyMode privacy_mode_;
+ const NetworkIsolationKey network_isolation_key_;
DISALLOW_COPY_AND_ASSIGN(SSLSocketParams);
};
diff --git a/net/socket/ssl_connect_job_unittest.cc b/net/socket/ssl_connect_job_unittest.cc
index 799d232..06f4d2e 100644
--- a/net/socket/ssl_connect_job_unittest.cc
+++ b/net/socket/ssl_connect_job_unittest.cc
@@ -135,7 +135,8 @@
: nullptr,
proxy == ProxyServer::SCHEME_SOCKS5 ? socks_socket_params_ : nullptr,
proxy == ProxyServer::SCHEME_HTTP ? http_proxy_socket_params_ : nullptr,
- HostPortPair("host", 443), ssl_config_, PRIVACY_MODE_DISABLED);
+ HostPortPair("host", 443), ssl_config_, PRIVACY_MODE_DISABLED,
+ NetworkIsolationKey());
}
void AddAuthToCache() {
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index 3570796..743eb6b 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -98,7 +98,7 @@
SSLConfig ssl_config;
auto ssl_params = base::MakeRefCounted<SSLSocketParams>(
transport_params, nullptr, nullptr, key.host_port_pair(), ssl_config,
- key.privacy_mode());
+ key.privacy_mode(), key.network_isolation_key());
TestConnectJobDelegate connect_job_delegate;
SSLConnectJob connect_job(MEDIUM, SocketTag(), common_connect_job_params,
ssl_params, &connect_job_delegate,
diff --git a/net/ssl/ssl_config.h b/net/ssl/ssl_config.h
index 7a23fc4..c31d970 100644
--- a/net/ssl/ssl_config.h
+++ b/net/ssl/ssl_config.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "net/base/net_export.h"
+#include "net/base/network_isolation_key.h"
#include "net/cert/x509_certificate.h"
#include "net/socket/next_proto.h"
#include "net/ssl/ssl_private_key.h"
@@ -135,6 +136,10 @@
scoped_refptr<X509Certificate> client_cert;
scoped_refptr<SSLPrivateKey> client_private_key;
+
+ // If the PartitionSSLSessionsByNetworkIsolationKey feature is enabled, the
+ // session cache is partitioned by this value.
+ NetworkIsolationKey network_isolation_key;
};
} // namespace net