Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chromeos / network / network_cert_migrator_unittest.cc
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
5 #include "chromeos/network/network_cert_migrator.h"
6
7 #include <cert.h>
8
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"
29
30 namespace chromeos {
31
32 namespace {
33
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";
40
41 }  // namespace
42
43 class NetworkCertMigratorTest : public testing::Test {
44  public:
45   NetworkCertMigratorTest() : service_test_(NULL),
46                               user_("user_hash") {
47   }
48   virtual ~NetworkCertMigratorTest() {}
49
50   virtual void SetUp() OVERRIDE {
51     // Initialize NSS db for the user.
52     ASSERT_TRUE(user_.constructed_successfully());
53     user_.FinishInit();
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());
60
61     DBusThreadManager::Initialize();
62     service_test_ =
63         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
64     DBusThreadManager::Get()
65         ->GetShillProfileClient()
66         ->GetTestInterface()
67         ->AddProfile(kProfile, "" /* userhash */);
68     base::RunLoop().RunUntilIdle();
69     service_test_->ClearServices();
70     base::RunLoop().RunUntilIdle();
71
72     CertLoader::Initialize();
73     CertLoader* cert_loader_ = CertLoader::Get();
74     cert_loader_->StartWithNSSDB(test_nssdb_.get());
75   }
76
77   virtual void TearDown() OVERRIDE {
78     network_cert_migrator_.reset();
79     network_state_handler_.reset();
80     CertLoader::Shutdown();
81     DBusThreadManager::Shutdown();
82     CleanupTestCert();
83   }
84
85  protected:
86   void SetupTestCACert() {
87     scoped_refptr<net::X509Certificate> cert_wo_nickname =
88         net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
89                                            "eku-test-root.pem",
90                                            net::X509Certificate::FORMAT_AUTO)
91             .back();
92     net::X509Certificate::GetPEMEncoded(cert_wo_nickname->os_cert_handle(),
93                                         &test_ca_cert_pem_);
94     std::string der_encoded;
95     net::X509Certificate::GetDEREncoded(cert_wo_nickname->os_cert_handle(),
96                                         &der_encoded);
97     cert_wo_nickname = NULL;
98
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);
107   }
108
109   void SetupTestClientCert() {
110     std::string pkcs12_data;
111     ASSERT_TRUE(base::ReadFileToString(
112         net::GetTestCertsDirectory().Append("websocket_client_cert.p12"),
113         &pkcs12_data));
114
115     net::CertificateList client_cert_list;
116     scoped_refptr<net::CryptoModule> module(net::CryptoModule::CreateFromHandle(
117         test_nssdb_->GetPrivateSlot().get()));
118     ASSERT_EQ(net::OK,
119               test_nssdb_->ImportFromPKCS12(module.get(),
120                                             pkcs12_data,
121                                             base::string16(),
122                                             false,
123                                             &client_cert_list));
124     ASSERT_TRUE(!client_cert_list.empty());
125     test_client_cert_ = client_cert_list[0];
126
127     int slot_id = -1;
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);
133   }
134
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());
139   }
140
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 */,
147                               type,
148                               state,
149                               true /* add_to_visible */);
150
151     // Ensure that the service appears as 'configured', i.e. is associated to a
152     // Shill profile.
153     service_test_->SetServiceProperty(
154         network_id, shill::kProfileProperty, base::StringValue(kProfile));
155   }
156
157   void SetupWifiWithNss() {
158     AddService(kWifiStub, shill::kTypeWifi, shill::kStateOnline);
159     service_test_->SetServiceProperty(kWifiStub,
160                                       shill::kEapCaCertNssProperty,
161                                       base::StringValue(kNSSNickname));
162   }
163
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));
172
173     if (wifi) {
174       service_test_->SetServiceProperty(
175           name,
176           shill::kSecurityProperty,
177           base::StringValue(shill::kSecurity8021x));
178     }
179   }
180
181   void GetEapCertId(bool wifi, std::string* cert_id) {
182     cert_id->clear();
183
184     std::string name = wifi ? kWifiStub : kEthernetEapStub;
185     const base::DictionaryValue* properties =
186         service_test_->GetServiceProperties(name);
187     properties->GetStringWithoutPathExpansion(shill::kEapCertIdProperty,
188                                               cert_id);
189   }
190
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;
196     if (open_vpn) {
197       provider.SetStringWithoutPathExpansion(shill::kTypeProperty,
198                                              shill::kProviderOpenVpn);
199       provider.SetStringWithoutPathExpansion(
200           shill::kOpenVPNClientCertIdProperty, pkcs11_id);
201     } else {
202       provider.SetStringWithoutPathExpansion(shill::kTypeProperty,
203                                              shill::kProviderL2tpIpsec);
204       provider.SetStringWithoutPathExpansion(
205           shill::kL2tpIpsecClientCertSlotProperty, slot_id);
206       provider.SetStringWithoutPathExpansion(
207           shill::kL2tpIpsecClientCertIdProperty, pkcs11_id);
208     }
209     service_test_->SetServiceProperty(
210         kVPNStub, shill::kProviderProperty, provider);
211   }
212
213   void GetVpnCertId(bool open_vpn,
214                     std::string* slot_id,
215                     std::string* pkcs11_id) {
216     slot_id->clear();
217     pkcs11_id->clear();
218
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,
224                                                   &provider);
225     if (!provider)
226       return;
227     if (open_vpn) {
228       provider->GetStringWithoutPathExpansion(
229           shill::kOpenVPNClientCertIdProperty, pkcs11_id);
230     } else {
231       provider->GetStringWithoutPathExpansion(
232           shill::kL2tpIpsecClientCertSlotProperty, slot_id);
233       provider->GetStringWithoutPathExpansion(
234           shill::kL2tpIpsecClientCertIdProperty, pkcs11_id);
235     }
236   }
237
238   void GetEapCACertProperties(std::string* nss_nickname, std::string* ca_pem) {
239     nss_nickname->clear();
240     ca_pem->clear();
241     const base::DictionaryValue* properties =
242         service_test_->GetServiceProperties(kWifiStub);
243     properties->GetStringWithoutPathExpansion(shill::kEapCaCertNssProperty,
244                                               nss_nickname);
245     const base::ListValue* ca_pems = NULL;
246     properties->GetListWithoutPathExpansion(shill::kEapCaCertPemProperty,
247                                             &ca_pems);
248     if (ca_pems && !ca_pems->empty())
249       ca_pems->GetString(0, ca_pem);
250   }
251
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);
260   }
261
262   void GetVpnCACertProperties(bool open_vpn,
263                               std::string* nss_nickname,
264                               std::string* ca_pem) {
265     nss_nickname->clear();
266     ca_pem->clear();
267     const base::DictionaryValue* properties =
268         service_test_->GetServiceProperties(kVPNStub);
269     const base::DictionaryValue* provider = NULL;
270     properties->GetDictionaryWithoutPathExpansion(shill::kProviderProperty,
271                                                   &provider);
272     if (!provider)
273       return;
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);
283   }
284
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_;
292
293  private:
294   void CleanupTestCert() {
295     if (test_ca_cert_.get())
296       ASSERT_TRUE(test_nssdb_->DeleteCertAndKey(test_ca_cert_.get()));
297
298     if (test_client_cert_.get())
299       ASSERT_TRUE(test_nssdb_->DeleteCertAndKey(test_client_cert_.get()));
300   }
301
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_;
306
307   DISALLOW_COPY_AND_ASSIGN(NetworkCertMigratorTest);
308 };
309
310 TEST_F(NetworkCertMigratorTest, MigrateNssOnInitialization) {
311   // Add a new network for migration before the handlers are initialized.
312   SetupWifiWithNss();
313   SetupTestCACert();
314   SetupNetworkHandlers();
315
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);
321 }
322
323 TEST_F(NetworkCertMigratorTest, MigrateNssOnNetworkAppearance) {
324   SetupTestCACert();
325   SetupNetworkHandlers();
326   base::RunLoop().RunUntilIdle();
327
328   // Add a new network for migration after the handlers are initialized.
329   SetupWifiWithNss();
330
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);
336 }
337
338 TEST_F(NetworkCertMigratorTest, DoNotMigrateNssIfPemSet) {
339   // Add a new network with an already set PEM property.
340   SetupWifiWithNss();
341   base::ListValue ca_pems;
342   ca_pems.AppendString(kFakePEM);
343   service_test_->SetServiceProperty(
344       kWifiStub, shill::kEapCaCertPemProperty, ca_pems);
345
346   SetupTestCACert();
347   SetupNetworkHandlers();
348   base::RunLoop().RunUntilIdle();
349
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);
354 }
355
356 TEST_F(NetworkCertMigratorTest, MigrateNssOpenVpn) {
357   // Add a new network for migration before the handlers are initialized.
358   SetupVpnWithNss(true /* OpenVPN */);
359
360   SetupTestCACert();
361   SetupNetworkHandlers();
362
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);
368 }
369
370 TEST_F(NetworkCertMigratorTest, MigrateNssIpsecVpn) {
371   // Add a new network for migration before the handlers are initialized.
372   SetupVpnWithNss(false /* not OpenVPN */);
373
374   SetupTestCACert();
375   SetupNetworkHandlers();
376
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);
382 }
383
384 TEST_F(NetworkCertMigratorTest, MigrateEapCertIdNoMatchingCert) {
385   SetupTestClientCert();
386   SetupNetworkHandlers();
387   base::RunLoop().RunUntilIdle();
388
389   // Add a new network for migration after the handlers are initialized.
390   SetupNetworkWithEapCertId(true /* wifi */, "unknown pkcs11 id");
391
392   base::RunLoop().RunUntilIdle();
393   // Since the PKCS11 ID is unknown, the certificate configuration will be
394   // cleared.
395   std::string cert_id;
396   GetEapCertId(true /* wifi */, &cert_id);
397   EXPECT_EQ(std::string(), cert_id);
398 }
399
400 TEST_F(NetworkCertMigratorTest, MigrateEapCertIdNoSlotId) {
401   SetupTestClientCert();
402   SetupNetworkHandlers();
403   base::RunLoop().RunUntilIdle();
404
405   // Add a new network for migration after the handlers are initialized.
406   SetupNetworkWithEapCertId(true /* wifi */, test_client_cert_pkcs11_id_);
407
408   base::RunLoop().RunUntilIdle();
409
410   std::string cert_id;
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);
415 }
416
417 TEST_F(NetworkCertMigratorTest, MigrateWifiEapCertIdWrongSlotId) {
418   SetupTestClientCert();
419   SetupNetworkHandlers();
420   base::RunLoop().RunUntilIdle();
421
422   // Add a new network for migration after the handlers are initialized.
423   SetupNetworkWithEapCertId(true /* wifi */,
424                             "123:" + test_client_cert_pkcs11_id_);
425
426   base::RunLoop().RunUntilIdle();
427
428   std::string cert_id;
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);
433 }
434
435 TEST_F(NetworkCertMigratorTest, DoNotChangeEapCertIdWithCorrectSlotId) {
436   SetupTestClientCert();
437   SetupNetworkHandlers();
438   base::RunLoop().RunUntilIdle();
439
440   std::string expected_cert_id =
441       test_client_cert_slot_id_ + ":" + test_client_cert_pkcs11_id_;
442
443   // Add a new network for migration after the handlers are initialized.
444   SetupNetworkWithEapCertId(true /* wifi */, expected_cert_id);
445
446   base::RunLoop().RunUntilIdle();
447
448   std::string cert_id;
449   GetEapCertId(true /* wifi */, &cert_id);
450   EXPECT_EQ(expected_cert_id, cert_id);
451 }
452
453 TEST_F(NetworkCertMigratorTest, IgnoreOpenVPNCertId) {
454   SetupTestClientCert();
455   SetupNetworkHandlers();
456   base::RunLoop().RunUntilIdle();
457
458   const char kPkcs11Id[] = "any slot id";
459
460   // Add a new network for migration after the handlers are initialized.
461   SetupVpnWithCertId(
462       true /* OpenVPN */, std::string() /* no slot id */, kPkcs11Id);
463
464   base::RunLoop().RunUntilIdle();
465
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);
470 }
471
472 TEST_F(NetworkCertMigratorTest, MigrateEthernetEapCertIdWrongSlotId) {
473   SetupTestClientCert();
474   SetupNetworkHandlers();
475   base::RunLoop().RunUntilIdle();
476
477   // Add a new network for migration after the handlers are initialized.
478   SetupNetworkWithEapCertId(
479       false /* ethernet */, "123:" + test_client_cert_pkcs11_id_);
480
481   base::RunLoop().RunUntilIdle();
482
483   std::string cert_id;
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);
488 }
489
490 TEST_F(NetworkCertMigratorTest, MigrateIpsecCertIdWrongSlotId) {
491   SetupTestClientCert();
492   SetupNetworkHandlers();
493   base::RunLoop().RunUntilIdle();
494
495   // Add a new network for migration after the handlers are initialized.
496   SetupVpnWithCertId(false /* IPsec */, "123", test_client_cert_pkcs11_id_);
497
498   base::RunLoop().RunUntilIdle();
499
500   std::string pkcs11_id;
501   std::string slot_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);
505 }
506
507 }  // namespace chromeos