1 // Copyright 2013 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 #include "chromeos/network/client_cert_resolver.h"
10 #include "base/bind_helpers.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/json/json_reader.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/values.h"
18 #include "chromeos/cert_loader.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/shill_manager_client.h"
21 #include "chromeos/dbus/shill_profile_client.h"
22 #include "chromeos/dbus/shill_service_client.h"
23 #include "chromeos/network/managed_network_configuration_handler_impl.h"
24 #include "chromeos/network/network_configuration_handler.h"
25 #include "chromeos/network/network_profile_handler.h"
26 #include "chromeos/network/network_state_handler.h"
27 #include "components/onc/onc_constants.h"
28 #include "crypto/scoped_nss_types.h"
29 #include "crypto/scoped_test_nss_db.h"
30 #include "net/base/net_errors.h"
31 #include "net/base/test_data_directory.h"
32 #include "net/cert/nss_cert_database_chromeos.h"
33 #include "net/cert/x509_certificate.h"
34 #include "net/test/cert_test_util.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "third_party/cros_system_api/dbus/service_constants.h"
42 const char* kWifiStub
= "wifi_stub";
43 const char* kWifiSSID
= "wifi_ssid";
44 const char* kUserProfilePath
= "user_profile";
45 const char* kUserHash
= "user_hash";
49 class ClientCertResolverTest
: public testing::Test
,
50 public ClientCertResolver::Observer
{
52 ClientCertResolverTest()
53 : network_properties_changed_count_(0),
57 ~ClientCertResolverTest() override
{}
59 void SetUp() override
{
60 ASSERT_TRUE(test_nssdb_
.is_open());
62 // Use the same DB for public and private slot.
63 test_nsscertdb_
.reset(new net::NSSCertDatabaseChromeOS(
64 crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_
.slot())),
65 crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_
.slot()))));
66 test_nsscertdb_
->SetSlowTaskRunnerForTest(
67 message_loop_
.message_loop_proxy());
69 DBusThreadManager::Initialize();
71 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
73 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
74 profile_test_
->AddProfile(kUserProfilePath
, kUserHash
);
75 base::RunLoop().RunUntilIdle();
76 service_test_
->ClearServices();
77 base::RunLoop().RunUntilIdle();
79 CertLoader::Initialize();
80 cert_loader_
= CertLoader::Get();
81 CertLoader::ForceHardwareBackedForTesting();
84 void TearDown() override
{
85 client_cert_resolver_
->RemoveObserver(this);
86 client_cert_resolver_
.reset();
87 managed_config_handler_
.reset();
88 network_config_handler_
.reset();
89 network_profile_handler_
.reset();
90 network_state_handler_
.reset();
91 CertLoader::Shutdown();
92 DBusThreadManager::Shutdown();
96 void StartCertLoader() {
97 cert_loader_
->StartWithNSSDB(test_nsscertdb_
.get());
98 if (test_client_cert_
.get()) {
100 const std::string pkcs11_id
=
101 CertLoader::GetPkcs11IdAndSlotForCert(*test_client_cert_
, &slot_id
);
102 test_cert_id_
= base::StringPrintf("%i:%s", slot_id
, pkcs11_id
.c_str());
106 // Imports a CA cert (stored as PEM in test_ca_cert_pem_) and a client
107 // certificate signed by that CA. Its PKCS#11 ID is stored in
109 void SetupTestCerts() {
111 net::CertificateList ca_cert_list
=
112 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
114 net::X509Certificate::FORMAT_AUTO
);
115 ASSERT_TRUE(!ca_cert_list
.empty());
116 net::NSSCertDatabase::ImportCertFailureList failures
;
117 EXPECT_TRUE(test_nsscertdb_
->ImportCACerts(
118 ca_cert_list
, net::NSSCertDatabase::TRUST_DEFAULT
, &failures
));
119 ASSERT_TRUE(failures
.empty()) << net::ErrorToString(failures
[0].net_error
);
121 net::X509Certificate::GetPEMEncoded(ca_cert_list
[0]->os_cert_handle(),
123 ASSERT_TRUE(!test_ca_cert_pem_
.empty());
125 // Import a client cert signed by that CA.
127 net::ImportClientCertAndKeyFromFile(net::GetTestCertsDirectory(),
131 ASSERT_TRUE(test_client_cert_
.get());
134 void SetupNetworkHandlers() {
135 network_state_handler_
.reset(NetworkStateHandler::InitializeForTest());
136 network_profile_handler_
.reset(new NetworkProfileHandler());
137 network_config_handler_
.reset(new NetworkConfigurationHandler());
138 managed_config_handler_
.reset(new ManagedNetworkConfigurationHandlerImpl());
139 client_cert_resolver_
.reset(new ClientCertResolver());
141 network_profile_handler_
->Init();
142 network_config_handler_
->Init(network_state_handler_
.get(),
143 NULL
/* network_device_handler */);
144 managed_config_handler_
->Init(network_state_handler_
.get(),
145 network_profile_handler_
.get(),
146 network_config_handler_
.get(),
147 NULL
/* network_device_handler */);
148 // Run all notifications before starting the cert loader to reduce run time.
149 base::RunLoop().RunUntilIdle();
151 client_cert_resolver_
->Init(network_state_handler_
.get(),
152 managed_config_handler_
.get());
153 client_cert_resolver_
->AddObserver(this);
154 client_cert_resolver_
->SetSlowTaskRunnerForTest(
155 message_loop_
.message_loop_proxy());
159 service_test_
->SetServiceProperties(kWifiStub
,
165 // Set an arbitrary cert id, so that we can check afterwards whether we
166 // cleared the property or not.
167 service_test_
->SetServiceProperty(
168 kWifiStub
, shill::kEapCertIdProperty
, base::StringValue("invalid id"));
169 profile_test_
->AddService(kUserProfilePath
, kWifiStub
);
171 DBusThreadManager::Get()
172 ->GetShillManagerClient()
174 ->AddManagerService(kWifiStub
, true);
177 // Setup a policy with a certificate pattern that matches any client cert that
178 // is signed by the test CA cert (stored in |test_ca_cert_pem_|). In
179 // particular it will match the test client cert.
181 const char* kTestPolicyTemplate
=
182 "[ { \"GUID\": \"wifi_stub\","
183 " \"Name\": \"wifi_stub\","
184 " \"Type\": \"WiFi\","
186 " \"Security\": \"WPA-EAP\","
187 " \"SSID\": \"wifi_ssid\","
189 " \"Outer\": \"EAP-TLS\","
190 " \"ClientCertType\": \"Pattern\","
191 " \"ClientCertPattern\": {"
192 " \"IssuerCAPEMs\": [ \"%s\" ]"
197 std::string policy_json
=
198 base::StringPrintf(kTestPolicyTemplate
, test_ca_cert_pem_
.c_str());
201 scoped_ptr
<base::Value
> policy_value(base::JSONReader::ReadAndReturnError(
202 policy_json
, base::JSON_ALLOW_TRAILING_COMMAS
, NULL
, &error
));
203 ASSERT_TRUE(policy_value
) << error
;
205 base::ListValue
* policy
= NULL
;
206 ASSERT_TRUE(policy_value
->GetAsList(&policy
));
208 managed_config_handler_
->SetPolicy(
209 onc::ONC_SOURCE_USER_POLICY
,
212 base::DictionaryValue() /* no global network config */);
215 void GetClientCertProperties(std::string
* pkcs11_id
) {
217 const base::DictionaryValue
* properties
=
218 service_test_
->GetServiceProperties(kWifiStub
);
221 properties
->GetStringWithoutPathExpansion(shill::kEapCertIdProperty
,
225 int network_properties_changed_count_
;
226 std::string test_cert_id_
;
227 scoped_ptr
<ClientCertResolver
> client_cert_resolver_
;
230 // ClientCertResolver::Observer:
231 void ResolveRequestCompleted(bool network_properties_changed
) override
{
232 if (network_properties_changed
)
233 ++network_properties_changed_count_
;
236 ShillServiceClient::TestInterface
* service_test_
;
237 ShillProfileClient::TestInterface
* profile_test_
;
238 CertLoader
* cert_loader_
;
239 scoped_ptr
<NetworkStateHandler
> network_state_handler_
;
240 scoped_ptr
<NetworkProfileHandler
> network_profile_handler_
;
241 scoped_ptr
<NetworkConfigurationHandler
> network_config_handler_
;
242 scoped_ptr
<ManagedNetworkConfigurationHandlerImpl
> managed_config_handler_
;
243 base::MessageLoop message_loop_
;
244 scoped_refptr
<net::X509Certificate
> test_client_cert_
;
245 std::string test_ca_cert_pem_
;
246 crypto::ScopedTestNSSDB test_nssdb_
;
247 scoped_ptr
<net::NSSCertDatabaseChromeOS
> test_nsscertdb_
;
249 DISALLOW_COPY_AND_ASSIGN(ClientCertResolverTest
);
252 TEST_F(ClientCertResolverTest
, NoMatchingCertificates
) {
255 base::RunLoop().RunUntilIdle();
256 network_properties_changed_count_
= 0;
257 SetupNetworkHandlers();
259 base::RunLoop().RunUntilIdle();
261 // Verify that no client certificate was configured.
262 std::string pkcs11_id
;
263 GetClientCertProperties(&pkcs11_id
);
264 EXPECT_EQ(std::string(), pkcs11_id
);
265 EXPECT_EQ(1, network_properties_changed_count_
);
266 EXPECT_FALSE(client_cert_resolver_
->IsAnyResolveTaskRunning());
269 TEST_F(ClientCertResolverTest
, ResolveOnCertificatesLoaded
) {
272 base::RunLoop().RunUntilIdle();
274 SetupNetworkHandlers();
276 base::RunLoop().RunUntilIdle();
278 network_properties_changed_count_
= 0;
280 base::RunLoop().RunUntilIdle();
282 // Verify that the resolver positively matched the pattern in the policy with
283 // the test client cert and configured the network.
284 std::string pkcs11_id
;
285 GetClientCertProperties(&pkcs11_id
);
286 EXPECT_EQ(test_cert_id_
, pkcs11_id
);
287 EXPECT_EQ(1, network_properties_changed_count_
);
290 TEST_F(ClientCertResolverTest
, ResolveAfterPolicyApplication
) {
293 base::RunLoop().RunUntilIdle();
295 SetupNetworkHandlers();
296 base::RunLoop().RunUntilIdle();
298 // Policy application will trigger the ClientCertResolver.
299 network_properties_changed_count_
= 0;
301 base::RunLoop().RunUntilIdle();
303 // Verify that the resolver positively matched the pattern in the policy with
304 // the test client cert and configured the network.
305 std::string pkcs11_id
;
306 GetClientCertProperties(&pkcs11_id
);
307 EXPECT_EQ(test_cert_id_
, pkcs11_id
);
308 EXPECT_EQ(1, network_properties_changed_count_
);
311 } // namespace chromeos