Home | History | Annotate | Download | only in network
      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
    508