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"
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/json/json_reader.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chromeos/cert_loader.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "chromeos/dbus/shill_profile_client.h"
18 #include "chromeos/dbus/shill_service_client.h"
19 #include "chromeos/login/login_state.h"
20 #include "chromeos/network/managed_network_configuration_handler_impl.h"
21 #include "chromeos/network/network_configuration_handler.h"
22 #include "chromeos/network/network_profile_handler.h"
23 #include "chromeos/network/network_state_handler.h"
24 #include "chromeos/tpm_token_loader.h"
25 #include "crypto/nss_util.h"
26 #include "net/base/crypto_module.h"
27 #include "net/base/net_errors.h"
28 #include "net/base/test_data_directory.h"
29 #include "net/cert/nss_cert_database.h"
30 #include "net/cert/x509_certificate.h"
31 #include "net/test/cert_test_util.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "third_party/cros_system_api/dbus/service_constants.h"
39 const char* kWifiStub
= "wifi_stub";
40 const char* kWifiSSID
= "wifi_ssid";
41 const char* kUserProfilePath
= "user_profile";
42 const char* kUserHash
= "user_hash";
46 class ClientCertResolverTest
: public testing::Test
{
48 ClientCertResolverTest() {}
49 virtual ~ClientCertResolverTest() {}
51 virtual void SetUp() OVERRIDE
{
52 ASSERT_TRUE(test_nssdb_
.is_open());
53 slot_
= net::NSSCertDatabase::GetInstance()->GetPublicModule();
54 ASSERT_TRUE(slot_
->os_module_handle());
56 LoginState::Initialize();
58 DBusThreadManager::InitializeWithStub();
60 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
62 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
63 message_loop_
.RunUntilIdle();
64 service_test_
->ClearServices();
65 message_loop_
.RunUntilIdle();
67 TPMTokenLoader::Initialize();
68 TPMTokenLoader
* tpm_token_loader
= TPMTokenLoader::Get();
69 tpm_token_loader
->InitializeTPMForTest();
70 tpm_token_loader
->SetCryptoTaskRunner(message_loop_
.message_loop_proxy());
72 CertLoader::Initialize();
73 CertLoader::Get()->SetSlowTaskRunnerForTest(
74 message_loop_
.message_loop_proxy());
77 virtual void TearDown() OVERRIDE
{
78 client_cert_resolver_
.reset();
79 managed_config_handler_
.reset();
80 network_config_handler_
.reset();
81 network_profile_handler_
.reset();
82 network_state_handler_
.reset();
83 CertLoader::Shutdown();
84 TPMTokenLoader::Shutdown();
85 DBusThreadManager::Shutdown();
86 LoginState::Shutdown();
87 CleanupSlotContents();
91 // Imports a CA cert (stored as PEM in test_ca_cert_pem_) and a client
92 // certificate signed by that CA. Its PKCS#11 ID is stored in
94 void SetupTestCerts() {
96 net::NSSCertDatabase
* cert_db
= net::NSSCertDatabase::GetInstance();
97 net::CertificateList ca_cert_list
=
98 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
99 "websocket_cacert.pem",
100 net::X509Certificate::FORMAT_AUTO
);
101 ASSERT_TRUE(!ca_cert_list
.empty());
102 net::NSSCertDatabase::ImportCertFailureList failures
;
103 EXPECT_TRUE(cert_db
->ImportCACerts(
104 ca_cert_list
, net::NSSCertDatabase::TRUST_DEFAULT
, &failures
));
105 ASSERT_TRUE(failures
.empty()) << net::ErrorToString(failures
[0].net_error
);
107 net::X509Certificate::GetPEMEncoded(ca_cert_list
[0]->os_cert_handle(),
109 ASSERT_TRUE(!test_ca_cert_pem_
.empty());
111 // Import a client cert signed by that CA.
112 scoped_refptr
<net::CryptoModule
> crypt_module
= cert_db
->GetPrivateModule();
113 std::string pkcs12_data
;
114 ASSERT_TRUE(base::ReadFileToString(
115 net::GetTestCertsDirectory().Append("websocket_client_cert.p12"),
118 net::CertificateList client_cert_list
;
120 cert_db
->ImportFromPKCS12(crypt_module
.get(),
125 ASSERT_TRUE(!client_cert_list
.empty());
126 test_pkcs11_id_
= CertLoader::GetPkcs11IdForCert(*client_cert_list
[0]);
127 ASSERT_TRUE(!test_pkcs11_id_
.empty());
130 void SetupNetworkHandlers() {
131 network_state_handler_
.reset(NetworkStateHandler::InitializeForTest());
132 network_profile_handler_
.reset(new NetworkProfileHandler());
133 network_config_handler_
.reset(new NetworkConfigurationHandler());
134 managed_config_handler_
.reset(new ManagedNetworkConfigurationHandlerImpl());
135 client_cert_resolver_
.reset(new ClientCertResolver());
137 network_profile_handler_
->Init(network_state_handler_
.get());
138 network_config_handler_
->Init(network_state_handler_
.get());
139 managed_config_handler_
->Init(network_state_handler_
.get(),
140 network_profile_handler_
.get(),
141 network_config_handler_
.get());
142 client_cert_resolver_
->Init(network_state_handler_
.get(),
143 managed_config_handler_
.get());
144 client_cert_resolver_
->SetSlowTaskRunnerForTest(
145 message_loop_
.message_loop_proxy());
147 profile_test_
->AddProfile(kUserProfilePath
, kUserHash
);
151 const bool add_to_visible
= true;
152 const bool add_to_watchlist
= true;
153 service_test_
->AddService(kWifiStub
,
159 service_test_
->SetServiceProperty(
160 kWifiStub
, shill::kGuidProperty
, base::StringValue(kWifiStub
));
162 profile_test_
->AddService(kUserProfilePath
, kWifiStub
);
165 // Setup a policy with a certificate pattern that matches any client cert that
166 // is signed by the test CA cert (stored in |test_ca_cert_pem_|). In
167 // particular it will match the test client cert.
169 const char* kTestPolicyTemplate
=
170 "[ { \"GUID\": \"wifi_stub\","
171 " \"Name\": \"wifi_stub\","
172 " \"Type\": \"WiFi\","
174 " \"Security\": \"WPA-EAP\","
175 " \"SSID\": \"wifi_ssid\","
177 " \"Outer\": \"EAP-TLS\","
178 " \"ClientCertType\": \"Pattern\","
179 " \"ClientCertPattern\": {"
180 " \"IssuerCAPEMs\": [ \"%s\" ]"
185 std::string policy_json
=
186 base::StringPrintf(kTestPolicyTemplate
, test_ca_cert_pem_
.c_str());
189 scoped_ptr
<base::Value
> policy_value(base::JSONReader::ReadAndReturnError(
190 policy_json
, base::JSON_ALLOW_TRAILING_COMMAS
, NULL
, &error
));
191 ASSERT_TRUE(policy_value
) << error
;
193 base::ListValue
* policy
= NULL
;
194 ASSERT_TRUE(policy_value
->GetAsList(&policy
));
196 managed_config_handler_
->SetPolicy(
197 onc::ONC_SOURCE_USER_POLICY
,
200 base::DictionaryValue() /* no global network config */);
203 void GetClientCertProperties(std::string
* pkcs11_id
) {
205 const base::DictionaryValue
* properties
=
206 service_test_
->GetServiceProperties(kWifiStub
);
209 properties
->GetStringWithoutPathExpansion(shill::kEapCertIdProperty
,
213 ShillServiceClient::TestInterface
* service_test_
;
214 ShillProfileClient::TestInterface
* profile_test_
;
215 std::string test_pkcs11_id_
;
216 scoped_refptr
<net::X509Certificate
> test_ca_cert_
;
217 std::string test_ca_cert_pem_
;
218 base::MessageLoop message_loop_
;
221 void CleanupSlotContents() {
222 CERTCertList
* cert_list
= PK11_ListCertsInSlot(slot_
->os_module_handle());
223 for (CERTCertListNode
* node
= CERT_LIST_HEAD(cert_list
);
224 !CERT_LIST_END(node
, cert_list
);
225 node
= CERT_LIST_NEXT(node
)) {
226 scoped_refptr
<net::X509Certificate
> cert(
227 net::X509Certificate::CreateFromHandle(
228 node
->cert
, net::X509Certificate::OSCertHandles()));
229 net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(cert
.get());
231 CERT_DestroyCertList(cert_list
);
234 scoped_ptr
<NetworkStateHandler
> network_state_handler_
;
235 scoped_ptr
<NetworkProfileHandler
> network_profile_handler_
;
236 scoped_ptr
<NetworkConfigurationHandler
> network_config_handler_
;
237 scoped_ptr
<ManagedNetworkConfigurationHandlerImpl
> managed_config_handler_
;
238 scoped_ptr
<ClientCertResolver
> client_cert_resolver_
;
239 scoped_refptr
<net::CryptoModule
> slot_
;
240 crypto::ScopedTestNSSDB test_nssdb_
;
242 DISALLOW_COPY_AND_ASSIGN(ClientCertResolverTest
);
245 TEST_F(ClientCertResolverTest
, NoMatchingCertificates
) {
246 SetupNetworkHandlers();
248 message_loop_
.RunUntilIdle();
251 message_loop_
.RunUntilIdle();
253 // Verify that no client certificate was configured.
254 std::string pkcs11_id
;
255 GetClientCertProperties(&pkcs11_id
);
256 EXPECT_TRUE(pkcs11_id
.empty());
259 TEST_F(ClientCertResolverTest
, ResolveOnInitialization
) {
261 SetupNetworkHandlers();
263 message_loop_
.RunUntilIdle();
266 message_loop_
.RunUntilIdle();
268 // Verify that the resolver positively matched the pattern in the policy with
269 // the test client cert and configured the network.
270 std::string pkcs11_id
;
271 GetClientCertProperties(&pkcs11_id
);
272 EXPECT_EQ(test_pkcs11_id_
, pkcs11_id
);
275 TEST_F(ClientCertResolverTest
, ResolveAfterPolicyApplication
) {
277 SetupNetworkHandlers();
278 message_loop_
.RunUntilIdle();
280 // The policy will trigger the creation of a new wifi service.
282 message_loop_
.RunUntilIdle();
284 // Verify that the resolver positively matched the pattern in the policy with
285 // the test client cert and configured the network.
286 std::string pkcs11_id
;
287 GetClientCertProperties(&pkcs11_id
);
288 EXPECT_EQ(test_pkcs11_id_
, pkcs11_id
);
291 } // namespace chromeos