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.
5 #include "chromeos/network/network_cert_migrator.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "chromeos/cert_loader.h"
14 #include "chromeos/dbus/dbus_thread_manager.h"
15 #include "chromeos/dbus/shill_profile_client.h"
16 #include "chromeos/dbus/shill_service_client.h"
17 #include "chromeos/network/network_state_handler.h"
18 #include "chromeos/tpm_token_loader.h"
19 #include "crypto/nss_util_internal.h"
20 #include "crypto/scoped_test_nss_chromeos_user.h"
21 #include "net/base/crypto_module.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/test_data_directory.h"
24 #include "net/cert/nss_cert_database_chromeos.h"
25 #include "net/cert/x509_certificate.h"
26 #include "net/test/cert_test_util.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
34 const char* kWifiStub
= "wifi_stub";
35 const char* kEthernetEapStub
= "ethernet_eap_stub";
36 const char* kVPNStub
= "vpn_stub";
37 const char* kNSSNickname
= "nss_nickname";
38 const char* kFakePEM
= "pem";
39 const char* kProfile
= "/profile/profile1";
43 class NetworkCertMigratorTest
: public testing::Test
{
45 NetworkCertMigratorTest() : service_test_(NULL
),
48 virtual ~NetworkCertMigratorTest() {}
50 virtual void SetUp() OVERRIDE
{
51 // Initialize NSS db for the user.
52 ASSERT_TRUE(user_
.constructed_successfully());
54 test_nssdb_
.reset(new net::NSSCertDatabaseChromeOS(
55 crypto::GetPublicSlotForChromeOSUser(user_
.username_hash()),
56 crypto::GetPrivateSlotForChromeOSUser(
57 user_
.username_hash(),
58 base::Callback
<void(crypto::ScopedPK11Slot
)>())));
59 test_nssdb_
->SetSlowTaskRunnerForTest(message_loop_
.message_loop_proxy());
61 DBusThreadManager::Initialize();
63 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
64 DBusThreadManager::Get()
65 ->GetShillProfileClient()
67 ->AddProfile(kProfile
, "" /* userhash */);
68 base::RunLoop().RunUntilIdle();
69 service_test_
->ClearServices();
70 base::RunLoop().RunUntilIdle();
72 CertLoader::Initialize();
73 CertLoader
* cert_loader_
= CertLoader::Get();
74 cert_loader_
->StartWithNSSDB(test_nssdb_
.get());
77 virtual void TearDown() OVERRIDE
{
78 network_cert_migrator_
.reset();
79 network_state_handler_
.reset();
80 CertLoader::Shutdown();
81 DBusThreadManager::Shutdown();
86 void SetupTestCACert() {
87 scoped_refptr
<net::X509Certificate
> cert_wo_nickname
=
88 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
90 net::X509Certificate::FORMAT_AUTO
)
92 net::X509Certificate::GetPEMEncoded(cert_wo_nickname
->os_cert_handle(),
94 std::string der_encoded
;
95 net::X509Certificate::GetDEREncoded(cert_wo_nickname
->os_cert_handle(),
97 cert_wo_nickname
= NULL
;
99 test_ca_cert_
= net::X509Certificate::CreateFromBytesWithNickname(
100 der_encoded
.data(), der_encoded
.size(), kNSSNickname
);
101 net::CertificateList cert_list
;
102 cert_list
.push_back(test_ca_cert_
);
103 net::NSSCertDatabase::ImportCertFailureList failures
;
104 EXPECT_TRUE(test_nssdb_
->ImportCACerts(
105 cert_list
, net::NSSCertDatabase::TRUST_DEFAULT
, &failures
));
106 ASSERT_TRUE(failures
.empty()) << net::ErrorToString(failures
[0].net_error
);
109 void SetupTestClientCert() {
110 std::string pkcs12_data
;
111 ASSERT_TRUE(base::ReadFileToString(
112 net::GetTestCertsDirectory().Append("websocket_client_cert.p12"),
115 net::CertificateList client_cert_list
;
116 scoped_refptr
<net::CryptoModule
> module(net::CryptoModule::CreateFromHandle(
117 test_nssdb_
->GetPrivateSlot().get()));
119 test_nssdb_
->ImportFromPKCS12(module
.get(),
124 ASSERT_TRUE(!client_cert_list
.empty());
125 test_client_cert_
= client_cert_list
[0];
128 test_client_cert_pkcs11_id_
= CertLoader::GetPkcs11IdAndSlotForCert(
129 *test_client_cert_
, &slot_id
);
130 ASSERT_FALSE(test_client_cert_pkcs11_id_
.empty());
131 ASSERT_NE(-1, slot_id
);
132 test_client_cert_slot_id_
= base::IntToString(slot_id
);
135 void SetupNetworkHandlers() {
136 network_state_handler_
.reset(NetworkStateHandler::InitializeForTest());
137 network_cert_migrator_
.reset(new NetworkCertMigrator
);
138 network_cert_migrator_
->Init(network_state_handler_
.get());
141 void AddService(const std::string
& network_id
,
142 const std::string
& type
,
143 const std::string
& state
) {
144 service_test_
->AddService(network_id
/* service_path */,
145 network_id
/* guid */,
146 network_id
/* name */,
149 true /* add_to_visible */);
151 // Ensure that the service appears as 'configured', i.e. is associated to a
153 service_test_
->SetServiceProperty(
154 network_id
, shill::kProfileProperty
, base::StringValue(kProfile
));
157 void SetupWifiWithNss() {
158 AddService(kWifiStub
, shill::kTypeWifi
, shill::kStateOnline
);
159 service_test_
->SetServiceProperty(kWifiStub
,
160 shill::kEapCaCertNssProperty
,
161 base::StringValue(kNSSNickname
));
164 void SetupNetworkWithEapCertId(bool wifi
, const std::string
& cert_id
) {
165 std::string type
= wifi
? shill::kTypeWifi
: shill::kTypeEthernetEap
;
166 std::string name
= wifi
? kWifiStub
: kEthernetEapStub
;
167 AddService(name
, type
, shill::kStateOnline
);
168 service_test_
->SetServiceProperty(
169 name
, shill::kEapCertIdProperty
, base::StringValue(cert_id
));
170 service_test_
->SetServiceProperty(
171 name
, shill::kEapKeyIdProperty
, base::StringValue(cert_id
));
174 service_test_
->SetServiceProperty(
176 shill::kSecurityProperty
,
177 base::StringValue(shill::kSecurity8021x
));
181 void GetEapCertId(bool wifi
, std::string
* cert_id
) {
184 std::string name
= wifi
? kWifiStub
: kEthernetEapStub
;
185 const base::DictionaryValue
* properties
=
186 service_test_
->GetServiceProperties(name
);
187 properties
->GetStringWithoutPathExpansion(shill::kEapCertIdProperty
,
191 void SetupVpnWithCertId(bool open_vpn
,
192 const std::string
& slot_id
,
193 const std::string
& pkcs11_id
) {
194 AddService(kVPNStub
, shill::kTypeVPN
, shill::kStateIdle
);
195 base::DictionaryValue provider
;
197 provider
.SetStringWithoutPathExpansion(shill::kTypeProperty
,
198 shill::kProviderOpenVpn
);
199 provider
.SetStringWithoutPathExpansion(
200 shill::kOpenVPNClientCertIdProperty
, pkcs11_id
);
202 provider
.SetStringWithoutPathExpansion(shill::kTypeProperty
,
203 shill::kProviderL2tpIpsec
);
204 provider
.SetStringWithoutPathExpansion(
205 shill::kL2tpIpsecClientCertSlotProperty
, slot_id
);
206 provider
.SetStringWithoutPathExpansion(
207 shill::kL2tpIpsecClientCertIdProperty
, pkcs11_id
);
209 service_test_
->SetServiceProperty(
210 kVPNStub
, shill::kProviderProperty
, provider
);
213 void GetVpnCertId(bool open_vpn
,
214 std::string
* slot_id
,
215 std::string
* pkcs11_id
) {
219 const base::DictionaryValue
* properties
=
220 service_test_
->GetServiceProperties(kVPNStub
);
221 ASSERT_TRUE(properties
);
222 const base::DictionaryValue
* provider
= NULL
;
223 properties
->GetDictionaryWithoutPathExpansion(shill::kProviderProperty
,
228 provider
->GetStringWithoutPathExpansion(
229 shill::kOpenVPNClientCertIdProperty
, pkcs11_id
);
231 provider
->GetStringWithoutPathExpansion(
232 shill::kL2tpIpsecClientCertSlotProperty
, slot_id
);
233 provider
->GetStringWithoutPathExpansion(
234 shill::kL2tpIpsecClientCertIdProperty
, pkcs11_id
);
238 void GetEapCACertProperties(std::string
* nss_nickname
, std::string
* ca_pem
) {
239 nss_nickname
->clear();
241 const base::DictionaryValue
* properties
=
242 service_test_
->GetServiceProperties(kWifiStub
);
243 properties
->GetStringWithoutPathExpansion(shill::kEapCaCertNssProperty
,
245 const base::ListValue
* ca_pems
= NULL
;
246 properties
->GetListWithoutPathExpansion(shill::kEapCaCertPemProperty
,
248 if (ca_pems
&& !ca_pems
->empty())
249 ca_pems
->GetString(0, ca_pem
);
252 void SetupVpnWithNss(bool open_vpn
) {
253 AddService(kVPNStub
, shill::kTypeVPN
, shill::kStateIdle
);
254 base::DictionaryValue provider
;
255 const char* nss_property
= open_vpn
? shill::kOpenVPNCaCertNSSProperty
256 : shill::kL2tpIpsecCaCertNssProperty
;
257 provider
.SetStringWithoutPathExpansion(nss_property
, kNSSNickname
);
258 service_test_
->SetServiceProperty(
259 kVPNStub
, shill::kProviderProperty
, provider
);
262 void GetVpnCACertProperties(bool open_vpn
,
263 std::string
* nss_nickname
,
264 std::string
* ca_pem
) {
265 nss_nickname
->clear();
267 const base::DictionaryValue
* properties
=
268 service_test_
->GetServiceProperties(kVPNStub
);
269 const base::DictionaryValue
* provider
= NULL
;
270 properties
->GetDictionaryWithoutPathExpansion(shill::kProviderProperty
,
274 const char* nss_property
= open_vpn
? shill::kOpenVPNCaCertNSSProperty
275 : shill::kL2tpIpsecCaCertNssProperty
;
276 provider
->GetStringWithoutPathExpansion(nss_property
, nss_nickname
);
277 const base::ListValue
* ca_pems
= NULL
;
278 const char* pem_property
= open_vpn
? shill::kOpenVPNCaCertPemProperty
279 : shill::kL2tpIpsecCaCertPemProperty
;
280 provider
->GetListWithoutPathExpansion(pem_property
, &ca_pems
);
281 if (ca_pems
&& !ca_pems
->empty())
282 ca_pems
->GetString(0, ca_pem
);
285 ShillServiceClient::TestInterface
* service_test_
;
286 scoped_refptr
<net::X509Certificate
> test_ca_cert_
;
287 scoped_refptr
<net::X509Certificate
> test_client_cert_
;
288 std::string test_client_cert_pkcs11_id_
;
289 std::string test_client_cert_slot_id_
;
290 std::string test_ca_cert_pem_
;
291 base::MessageLoop message_loop_
;
294 void CleanupTestCert() {
295 if (test_ca_cert_
.get())
296 ASSERT_TRUE(test_nssdb_
->DeleteCertAndKey(test_ca_cert_
.get()));
298 if (test_client_cert_
.get())
299 ASSERT_TRUE(test_nssdb_
->DeleteCertAndKey(test_client_cert_
.get()));
302 scoped_ptr
<NetworkStateHandler
> network_state_handler_
;
303 scoped_ptr
<NetworkCertMigrator
> network_cert_migrator_
;
304 crypto::ScopedTestNSSChromeOSUser user_
;
305 scoped_ptr
<net::NSSCertDatabaseChromeOS
> test_nssdb_
;
307 DISALLOW_COPY_AND_ASSIGN(NetworkCertMigratorTest
);
310 TEST_F(NetworkCertMigratorTest
, MigrateNssOnInitialization
) {
311 // Add a new network for migration before the handlers are initialized.
314 SetupNetworkHandlers();
316 base::RunLoop().RunUntilIdle();
317 std::string nss_nickname
, ca_pem
;
318 GetEapCACertProperties(&nss_nickname
, &ca_pem
);
319 EXPECT_TRUE(nss_nickname
.empty());
320 EXPECT_EQ(test_ca_cert_pem_
, ca_pem
);
323 TEST_F(NetworkCertMigratorTest
, MigrateNssOnNetworkAppearance
) {
325 SetupNetworkHandlers();
326 base::RunLoop().RunUntilIdle();
328 // Add a new network for migration after the handlers are initialized.
331 base::RunLoop().RunUntilIdle();
332 std::string nss_nickname
, ca_pem
;
333 GetEapCACertProperties(&nss_nickname
, &ca_pem
);
334 EXPECT_TRUE(nss_nickname
.empty());
335 EXPECT_EQ(test_ca_cert_pem_
, ca_pem
);
338 TEST_F(NetworkCertMigratorTest
, DoNotMigrateNssIfPemSet
) {
339 // Add a new network with an already set PEM property.
341 base::ListValue ca_pems
;
342 ca_pems
.AppendString(kFakePEM
);
343 service_test_
->SetServiceProperty(
344 kWifiStub
, shill::kEapCaCertPemProperty
, ca_pems
);
347 SetupNetworkHandlers();
348 base::RunLoop().RunUntilIdle();
350 std::string nss_nickname
, ca_pem
;
351 GetEapCACertProperties(&nss_nickname
, &ca_pem
);
352 EXPECT_TRUE(nss_nickname
.empty());
353 EXPECT_EQ(kFakePEM
, ca_pem
);
356 TEST_F(NetworkCertMigratorTest
, MigrateNssOpenVpn
) {
357 // Add a new network for migration before the handlers are initialized.
358 SetupVpnWithNss(true /* OpenVPN */);
361 SetupNetworkHandlers();
363 base::RunLoop().RunUntilIdle();
364 std::string nss_nickname
, ca_pem
;
365 GetVpnCACertProperties(true /* OpenVPN */, &nss_nickname
, &ca_pem
);
366 EXPECT_TRUE(nss_nickname
.empty());
367 EXPECT_EQ(test_ca_cert_pem_
, ca_pem
);
370 TEST_F(NetworkCertMigratorTest
, MigrateNssIpsecVpn
) {
371 // Add a new network for migration before the handlers are initialized.
372 SetupVpnWithNss(false /* not OpenVPN */);
375 SetupNetworkHandlers();
377 base::RunLoop().RunUntilIdle();
378 std::string nss_nickname
, ca_pem
;
379 GetVpnCACertProperties(false /* not OpenVPN */, &nss_nickname
, &ca_pem
);
380 EXPECT_TRUE(nss_nickname
.empty());
381 EXPECT_EQ(test_ca_cert_pem_
, ca_pem
);
384 TEST_F(NetworkCertMigratorTest
, MigrateEapCertIdNoMatchingCert
) {
385 SetupTestClientCert();
386 SetupNetworkHandlers();
387 base::RunLoop().RunUntilIdle();
389 // Add a new network for migration after the handlers are initialized.
390 SetupNetworkWithEapCertId(true /* wifi */, "unknown pkcs11 id");
392 base::RunLoop().RunUntilIdle();
393 // Since the PKCS11 ID is unknown, the certificate configuration will be
396 GetEapCertId(true /* wifi */, &cert_id
);
397 EXPECT_EQ(std::string(), cert_id
);
400 TEST_F(NetworkCertMigratorTest
, MigrateEapCertIdNoSlotId
) {
401 SetupTestClientCert();
402 SetupNetworkHandlers();
403 base::RunLoop().RunUntilIdle();
405 // Add a new network for migration after the handlers are initialized.
406 SetupNetworkWithEapCertId(true /* wifi */, test_client_cert_pkcs11_id_
);
408 base::RunLoop().RunUntilIdle();
411 GetEapCertId(true /* wifi */, &cert_id
);
412 std::string expected_cert_id
=
413 test_client_cert_slot_id_
+ ":" + test_client_cert_pkcs11_id_
;
414 EXPECT_EQ(expected_cert_id
, cert_id
);
417 TEST_F(NetworkCertMigratorTest
, MigrateWifiEapCertIdWrongSlotId
) {
418 SetupTestClientCert();
419 SetupNetworkHandlers();
420 base::RunLoop().RunUntilIdle();
422 // Add a new network for migration after the handlers are initialized.
423 SetupNetworkWithEapCertId(true /* wifi */,
424 "123:" + test_client_cert_pkcs11_id_
);
426 base::RunLoop().RunUntilIdle();
429 GetEapCertId(true /* wifi */, &cert_id
);
430 std::string expected_cert_id
=
431 test_client_cert_slot_id_
+ ":" + test_client_cert_pkcs11_id_
;
432 EXPECT_EQ(expected_cert_id
, cert_id
);
435 TEST_F(NetworkCertMigratorTest
, DoNotChangeEapCertIdWithCorrectSlotId
) {
436 SetupTestClientCert();
437 SetupNetworkHandlers();
438 base::RunLoop().RunUntilIdle();
440 std::string expected_cert_id
=
441 test_client_cert_slot_id_
+ ":" + test_client_cert_pkcs11_id_
;
443 // Add a new network for migration after the handlers are initialized.
444 SetupNetworkWithEapCertId(true /* wifi */, expected_cert_id
);
446 base::RunLoop().RunUntilIdle();
449 GetEapCertId(true /* wifi */, &cert_id
);
450 EXPECT_EQ(expected_cert_id
, cert_id
);
453 TEST_F(NetworkCertMigratorTest
, IgnoreOpenVPNCertId
) {
454 SetupTestClientCert();
455 SetupNetworkHandlers();
456 base::RunLoop().RunUntilIdle();
458 const char kPkcs11Id
[] = "any slot id";
460 // Add a new network for migration after the handlers are initialized.
462 true /* OpenVPN */, std::string() /* no slot id */, kPkcs11Id
);
464 base::RunLoop().RunUntilIdle();
466 std::string pkcs11_id
;
467 std::string unused_slot_id
;
468 GetVpnCertId(true /* OpenVPN */, &unused_slot_id
, &pkcs11_id
);
469 EXPECT_EQ(kPkcs11Id
, pkcs11_id
);
472 TEST_F(NetworkCertMigratorTest
, MigrateEthernetEapCertIdWrongSlotId
) {
473 SetupTestClientCert();
474 SetupNetworkHandlers();
475 base::RunLoop().RunUntilIdle();
477 // Add a new network for migration after the handlers are initialized.
478 SetupNetworkWithEapCertId(
479 false /* ethernet */, "123:" + test_client_cert_pkcs11_id_
);
481 base::RunLoop().RunUntilIdle();
484 GetEapCertId(false /* ethernet */, &cert_id
);
485 std::string expected_cert_id
=
486 test_client_cert_slot_id_
+ ":" + test_client_cert_pkcs11_id_
;
487 EXPECT_EQ(expected_cert_id
, cert_id
);
490 TEST_F(NetworkCertMigratorTest
, MigrateIpsecCertIdWrongSlotId
) {
491 SetupTestClientCert();
492 SetupNetworkHandlers();
493 base::RunLoop().RunUntilIdle();
495 // Add a new network for migration after the handlers are initialized.
496 SetupVpnWithCertId(false /* IPsec */, "123", test_client_cert_pkcs11_id_
);
498 base::RunLoop().RunUntilIdle();
500 std::string pkcs11_id
;
502 GetVpnCertId(false /* IPsec */, &slot_id
, &pkcs11_id
);
503 EXPECT_EQ(test_client_cert_pkcs11_id_
, pkcs11_id
);
504 EXPECT_EQ(test_client_cert_slot_id_
, slot_id
);
507 } // namespace chromeos