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"
30 // http://crbug.com/418369
37 const char* kWifiStub
= "wifi_stub";
38 const char* kEthernetEapStub
= "ethernet_eap_stub";
39 const char* kVPNStub
= "vpn_stub";
40 const char* kNSSNickname
= "nss_nickname";
41 const char* kFakePEM
= "pem";
42 const char* kProfile
= "/profile/profile1";
46 class NetworkCertMigratorTest
: public testing::Test
{
48 NetworkCertMigratorTest() : service_test_(NULL
),
51 virtual ~NetworkCertMigratorTest() {}
53 virtual void SetUp() override
{
54 // Initialize NSS db for the user.
55 ASSERT_TRUE(user_
.constructed_successfully());
57 test_nssdb_
.reset(new net::NSSCertDatabaseChromeOS(
58 crypto::GetPublicSlotForChromeOSUser(user_
.username_hash()),
59 crypto::GetPrivateSlotForChromeOSUser(
60 user_
.username_hash(),
61 base::Callback
<void(crypto::ScopedPK11Slot
)>())));
62 test_nssdb_
->SetSlowTaskRunnerForTest(message_loop_
.message_loop_proxy());
64 DBusThreadManager::Initialize();
66 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
67 DBusThreadManager::Get()
68 ->GetShillProfileClient()
70 ->AddProfile(kProfile
, "" /* userhash */);
71 base::RunLoop().RunUntilIdle();
72 service_test_
->ClearServices();
73 base::RunLoop().RunUntilIdle();
75 CertLoader::Initialize();
76 CertLoader
* cert_loader_
= CertLoader::Get();
77 cert_loader_
->StartWithNSSDB(test_nssdb_
.get());
80 virtual void TearDown() override
{
81 network_cert_migrator_
.reset();
82 network_state_handler_
.reset();
83 CertLoader::Shutdown();
84 DBusThreadManager::Shutdown();
89 void SetupTestCACert() {
90 scoped_refptr
<net::X509Certificate
> cert_wo_nickname
=
91 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
93 net::X509Certificate::FORMAT_AUTO
)
95 net::X509Certificate::GetPEMEncoded(cert_wo_nickname
->os_cert_handle(),
97 std::string der_encoded
;
98 net::X509Certificate::GetDEREncoded(cert_wo_nickname
->os_cert_handle(),
100 cert_wo_nickname
= NULL
;
102 test_ca_cert_
= net::X509Certificate::CreateFromBytesWithNickname(
103 der_encoded
.data(), der_encoded
.size(), kNSSNickname
);
104 net::CertificateList cert_list
;
105 cert_list
.push_back(test_ca_cert_
);
106 net::NSSCertDatabase::ImportCertFailureList failures
;
107 EXPECT_TRUE(test_nssdb_
->ImportCACerts(
108 cert_list
, net::NSSCertDatabase::TRUST_DEFAULT
, &failures
));
109 ASSERT_TRUE(failures
.empty()) << net::ErrorToString(failures
[0].net_error
);
112 void SetupTestClientCert() {
113 std::string pkcs12_data
;
114 ASSERT_TRUE(base::ReadFileToString(
115 net::GetTestCertsDirectory().Append("websocket_client_cert.p12"),
118 net::CertificateList client_cert_list
;
119 scoped_refptr
<net::CryptoModule
> module(net::CryptoModule::CreateFromHandle(
120 test_nssdb_
->GetPrivateSlot().get()));
122 test_nssdb_
->ImportFromPKCS12(module
.get(),
127 ASSERT_TRUE(!client_cert_list
.empty());
128 test_client_cert_
= client_cert_list
[0];
131 test_client_cert_pkcs11_id_
= CertLoader::GetPkcs11IdAndSlotForCert(
132 *test_client_cert_
, &slot_id
);
133 ASSERT_FALSE(test_client_cert_pkcs11_id_
.empty());
134 ASSERT_NE(-1, slot_id
);
135 test_client_cert_slot_id_
= base::IntToString(slot_id
);
138 void SetupNetworkHandlers() {
139 network_state_handler_
.reset(NetworkStateHandler::InitializeForTest());
140 network_cert_migrator_
.reset(new NetworkCertMigrator
);
141 network_cert_migrator_
->Init(network_state_handler_
.get());
144 void AddService(const std::string
& network_id
,
145 const std::string
& type
,
146 const std::string
& state
) {
147 service_test_
->AddService(network_id
/* service_path */,
148 network_id
/* guid */,
149 network_id
/* name */,
152 true /* add_to_visible */);
154 // Ensure that the service appears as 'configured', i.e. is associated to a
156 service_test_
->SetServiceProperty(
157 network_id
, shill::kProfileProperty
, base::StringValue(kProfile
));
160 void SetupWifiWithNss() {
161 AddService(kWifiStub
, shill::kTypeWifi
, shill::kStateOnline
);
162 service_test_
->SetServiceProperty(kWifiStub
,
163 shill::kEapCaCertNssProperty
,
164 base::StringValue(kNSSNickname
));
167 void SetupNetworkWithEapCertId(bool wifi
, const std::string
& cert_id
) {
168 std::string type
= wifi
? shill::kTypeWifi
: shill::kTypeEthernetEap
;
169 std::string name
= wifi
? kWifiStub
: kEthernetEapStub
;
170 AddService(name
, type
, shill::kStateOnline
);
171 service_test_
->SetServiceProperty(
172 name
, shill::kEapCertIdProperty
, base::StringValue(cert_id
));
173 service_test_
->SetServiceProperty(
174 name
, shill::kEapKeyIdProperty
, base::StringValue(cert_id
));
177 service_test_
->SetServiceProperty(
179 shill::kSecurityProperty
,
180 base::StringValue(shill::kSecurity8021x
));
184 void GetEapCertId(bool wifi
, std::string
* cert_id
) {
187 std::string name
= wifi
? kWifiStub
: kEthernetEapStub
;
188 const base::DictionaryValue
* properties
=
189 service_test_
->GetServiceProperties(name
);
190 properties
->GetStringWithoutPathExpansion(shill::kEapCertIdProperty
,
194 void SetupVpnWithCertId(bool open_vpn
,
195 const std::string
& slot_id
,
196 const std::string
& pkcs11_id
) {
197 AddService(kVPNStub
, shill::kTypeVPN
, shill::kStateIdle
);
198 base::DictionaryValue provider
;
200 provider
.SetStringWithoutPathExpansion(shill::kTypeProperty
,
201 shill::kProviderOpenVpn
);
202 provider
.SetStringWithoutPathExpansion(
203 shill::kOpenVPNClientCertIdProperty
, pkcs11_id
);
205 provider
.SetStringWithoutPathExpansion(shill::kTypeProperty
,
206 shill::kProviderL2tpIpsec
);
207 provider
.SetStringWithoutPathExpansion(
208 shill::kL2tpIpsecClientCertSlotProperty
, slot_id
);
209 provider
.SetStringWithoutPathExpansion(
210 shill::kL2tpIpsecClientCertIdProperty
, pkcs11_id
);
212 service_test_
->SetServiceProperty(
213 kVPNStub
, shill::kProviderProperty
, provider
);
216 void GetVpnCertId(bool open_vpn
,
217 std::string
* slot_id
,
218 std::string
* pkcs11_id
) {
222 const base::DictionaryValue
* properties
=
223 service_test_
->GetServiceProperties(kVPNStub
);
224 ASSERT_TRUE(properties
);
225 const base::DictionaryValue
* provider
= NULL
;
226 properties
->GetDictionaryWithoutPathExpansion(shill::kProviderProperty
,
231 provider
->GetStringWithoutPathExpansion(
232 shill::kOpenVPNClientCertIdProperty
, pkcs11_id
);
234 provider
->GetStringWithoutPathExpansion(
235 shill::kL2tpIpsecClientCertSlotProperty
, slot_id
);
236 provider
->GetStringWithoutPathExpansion(
237 shill::kL2tpIpsecClientCertIdProperty
, pkcs11_id
);
241 void GetEapCACertProperties(std::string
* nss_nickname
, std::string
* ca_pem
) {
242 nss_nickname
->clear();
244 const base::DictionaryValue
* properties
=
245 service_test_
->GetServiceProperties(kWifiStub
);
246 properties
->GetStringWithoutPathExpansion(shill::kEapCaCertNssProperty
,
248 const base::ListValue
* ca_pems
= NULL
;
249 properties
->GetListWithoutPathExpansion(shill::kEapCaCertPemProperty
,
251 if (ca_pems
&& !ca_pems
->empty())
252 ca_pems
->GetString(0, ca_pem
);
255 void SetupVpnWithNss(bool open_vpn
) {
256 AddService(kVPNStub
, shill::kTypeVPN
, shill::kStateIdle
);
257 base::DictionaryValue provider
;
258 const char* nss_property
= open_vpn
? shill::kOpenVPNCaCertNSSProperty
259 : shill::kL2tpIpsecCaCertNssProperty
;
260 provider
.SetStringWithoutPathExpansion(nss_property
, kNSSNickname
);
261 service_test_
->SetServiceProperty(
262 kVPNStub
, shill::kProviderProperty
, provider
);
265 void GetVpnCACertProperties(bool open_vpn
,
266 std::string
* nss_nickname
,
267 std::string
* ca_pem
) {
268 nss_nickname
->clear();
270 const base::DictionaryValue
* properties
=
271 service_test_
->GetServiceProperties(kVPNStub
);
272 const base::DictionaryValue
* provider
= NULL
;
273 properties
->GetDictionaryWithoutPathExpansion(shill::kProviderProperty
,
277 const char* nss_property
= open_vpn
? shill::kOpenVPNCaCertNSSProperty
278 : shill::kL2tpIpsecCaCertNssProperty
;
279 provider
->GetStringWithoutPathExpansion(nss_property
, nss_nickname
);
280 const base::ListValue
* ca_pems
= NULL
;
281 const char* pem_property
= open_vpn
? shill::kOpenVPNCaCertPemProperty
282 : shill::kL2tpIpsecCaCertPemProperty
;
283 provider
->GetListWithoutPathExpansion(pem_property
, &ca_pems
);
284 if (ca_pems
&& !ca_pems
->empty())
285 ca_pems
->GetString(0, ca_pem
);
288 ShillServiceClient::TestInterface
* service_test_
;
289 scoped_refptr
<net::X509Certificate
> test_ca_cert_
;
290 scoped_refptr
<net::X509Certificate
> test_client_cert_
;
291 std::string test_client_cert_pkcs11_id_
;
292 std::string test_client_cert_slot_id_
;
293 std::string test_ca_cert_pem_
;
294 base::MessageLoop message_loop_
;
297 void CleanupTestCert() {
298 if (test_ca_cert_
.get())
299 ASSERT_TRUE(test_nssdb_
->DeleteCertAndKey(test_ca_cert_
.get()));
301 if (test_client_cert_
.get())
302 ASSERT_TRUE(test_nssdb_
->DeleteCertAndKey(test_client_cert_
.get()));
305 scoped_ptr
<NetworkStateHandler
> network_state_handler_
;
306 scoped_ptr
<NetworkCertMigrator
> network_cert_migrator_
;
307 crypto::ScopedTestNSSChromeOSUser user_
;
308 scoped_ptr
<net::NSSCertDatabaseChromeOS
> test_nssdb_
;
310 DISALLOW_COPY_AND_ASSIGN(NetworkCertMigratorTest
);
313 TEST_F(NetworkCertMigratorTest
, MigrateNssOnInitialization
) {
314 // Add a new network for migration before the handlers are initialized.
317 SetupNetworkHandlers();
319 base::RunLoop().RunUntilIdle();
320 std::string nss_nickname
, ca_pem
;
321 GetEapCACertProperties(&nss_nickname
, &ca_pem
);
322 EXPECT_TRUE(nss_nickname
.empty());
323 EXPECT_EQ(test_ca_cert_pem_
, ca_pem
);
326 TEST_F(NetworkCertMigratorTest
, MigrateNssOnNetworkAppearance
) {
328 SetupNetworkHandlers();
329 base::RunLoop().RunUntilIdle();
331 // Add a new network for migration after the handlers are initialized.
334 base::RunLoop().RunUntilIdle();
335 std::string nss_nickname
, ca_pem
;
336 GetEapCACertProperties(&nss_nickname
, &ca_pem
);
337 EXPECT_TRUE(nss_nickname
.empty());
338 EXPECT_EQ(test_ca_cert_pem_
, ca_pem
);
341 TEST_F(NetworkCertMigratorTest
, DoNotMigrateNssIfPemSet
) {
342 // Add a new network with an already set PEM property.
344 base::ListValue ca_pems
;
345 ca_pems
.AppendString(kFakePEM
);
346 service_test_
->SetServiceProperty(
347 kWifiStub
, shill::kEapCaCertPemProperty
, ca_pems
);
350 SetupNetworkHandlers();
351 base::RunLoop().RunUntilIdle();
353 std::string nss_nickname
, ca_pem
;
354 GetEapCACertProperties(&nss_nickname
, &ca_pem
);
355 EXPECT_TRUE(nss_nickname
.empty());
356 EXPECT_EQ(kFakePEM
, ca_pem
);
359 TEST_F(NetworkCertMigratorTest
, MigrateNssOpenVpn
) {
360 // Add a new network for migration before the handlers are initialized.
361 SetupVpnWithNss(true /* OpenVPN */);
364 SetupNetworkHandlers();
366 base::RunLoop().RunUntilIdle();
367 std::string nss_nickname
, ca_pem
;
368 GetVpnCACertProperties(true /* OpenVPN */, &nss_nickname
, &ca_pem
);
369 EXPECT_TRUE(nss_nickname
.empty());
370 EXPECT_EQ(test_ca_cert_pem_
, ca_pem
);
373 TEST_F(NetworkCertMigratorTest
, MigrateNssIpsecVpn
) {
374 // Add a new network for migration before the handlers are initialized.
375 SetupVpnWithNss(false /* not OpenVPN */);
378 SetupNetworkHandlers();
380 base::RunLoop().RunUntilIdle();
381 std::string nss_nickname
, ca_pem
;
382 GetVpnCACertProperties(false /* not OpenVPN */, &nss_nickname
, &ca_pem
);
383 EXPECT_TRUE(nss_nickname
.empty());
384 EXPECT_EQ(test_ca_cert_pem_
, ca_pem
);
387 TEST_F(NetworkCertMigratorTest
, MigrateEapCertIdNoMatchingCert
) {
388 SetupTestClientCert();
389 SetupNetworkHandlers();
390 base::RunLoop().RunUntilIdle();
392 // Add a new network for migration after the handlers are initialized.
393 SetupNetworkWithEapCertId(true /* wifi */, "unknown pkcs11 id");
395 base::RunLoop().RunUntilIdle();
396 // Since the PKCS11 ID is unknown, the certificate configuration will be
399 GetEapCertId(true /* wifi */, &cert_id
);
400 EXPECT_EQ(std::string(), cert_id
);
403 TEST_F(NetworkCertMigratorTest
, MigrateEapCertIdNoSlotId
) {
404 SetupTestClientCert();
405 SetupNetworkHandlers();
406 base::RunLoop().RunUntilIdle();
408 // Add a new network for migration after the handlers are initialized.
409 SetupNetworkWithEapCertId(true /* wifi */, test_client_cert_pkcs11_id_
);
411 base::RunLoop().RunUntilIdle();
414 GetEapCertId(true /* wifi */, &cert_id
);
415 std::string expected_cert_id
=
416 test_client_cert_slot_id_
+ ":" + test_client_cert_pkcs11_id_
;
417 EXPECT_EQ(expected_cert_id
, cert_id
);
420 TEST_F(NetworkCertMigratorTest
, MigrateWifiEapCertIdWrongSlotId
) {
421 SetupTestClientCert();
422 SetupNetworkHandlers();
423 base::RunLoop().RunUntilIdle();
425 // Add a new network for migration after the handlers are initialized.
426 SetupNetworkWithEapCertId(true /* wifi */,
427 "123:" + test_client_cert_pkcs11_id_
);
429 base::RunLoop().RunUntilIdle();
432 GetEapCertId(true /* wifi */, &cert_id
);
433 std::string expected_cert_id
=
434 test_client_cert_slot_id_
+ ":" + test_client_cert_pkcs11_id_
;
435 EXPECT_EQ(expected_cert_id
, cert_id
);
438 TEST_F(NetworkCertMigratorTest
, DoNotChangeEapCertIdWithCorrectSlotId
) {
439 SetupTestClientCert();
440 SetupNetworkHandlers();
441 base::RunLoop().RunUntilIdle();
443 std::string expected_cert_id
=
444 test_client_cert_slot_id_
+ ":" + test_client_cert_pkcs11_id_
;
446 // Add a new network for migration after the handlers are initialized.
447 SetupNetworkWithEapCertId(true /* wifi */, expected_cert_id
);
449 base::RunLoop().RunUntilIdle();
452 GetEapCertId(true /* wifi */, &cert_id
);
453 EXPECT_EQ(expected_cert_id
, cert_id
);
456 TEST_F(NetworkCertMigratorTest
, IgnoreOpenVPNCertId
) {
457 SetupTestClientCert();
458 SetupNetworkHandlers();
459 base::RunLoop().RunUntilIdle();
461 const char kPkcs11Id
[] = "any slot id";
463 // Add a new network for migration after the handlers are initialized.
465 true /* OpenVPN */, std::string() /* no slot id */, kPkcs11Id
);
467 base::RunLoop().RunUntilIdle();
469 std::string pkcs11_id
;
470 std::string unused_slot_id
;
471 GetVpnCertId(true /* OpenVPN */, &unused_slot_id
, &pkcs11_id
);
472 EXPECT_EQ(kPkcs11Id
, pkcs11_id
);
475 TEST_F(NetworkCertMigratorTest
, MigrateEthernetEapCertIdWrongSlotId
) {
476 SetupTestClientCert();
477 SetupNetworkHandlers();
478 base::RunLoop().RunUntilIdle();
480 // Add a new network for migration after the handlers are initialized.
481 SetupNetworkWithEapCertId(
482 false /* ethernet */, "123:" + test_client_cert_pkcs11_id_
);
484 base::RunLoop().RunUntilIdle();
487 GetEapCertId(false /* ethernet */, &cert_id
);
488 std::string expected_cert_id
=
489 test_client_cert_slot_id_
+ ":" + test_client_cert_pkcs11_id_
;
490 EXPECT_EQ(expected_cert_id
, cert_id
);
493 TEST_F(NetworkCertMigratorTest
, MigrateIpsecCertIdWrongSlotId
) {
494 SetupTestClientCert();
495 SetupNetworkHandlers();
496 base::RunLoop().RunUntilIdle();
498 // Add a new network for migration after the handlers are initialized.
499 SetupVpnWithCertId(false /* IPsec */, "123", test_client_cert_pkcs11_id_
);
501 base::RunLoop().RunUntilIdle();
503 std::string pkcs11_id
;
505 GetVpnCertId(false /* IPsec */, &slot_id
, &pkcs11_id
);
506 EXPECT_EQ(test_client_cert_pkcs11_id_
, pkcs11_id
);
507 EXPECT_EQ(test_client_cert_slot_id_
, slot_id
);
510 } // namespace chromeos