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/file_util.h"
     10 #include "base/files/file_path.h"
     11 #include "base/run_loop.h"
     12 #include "chromeos/dbus/dbus_thread_manager.h"
     13 #include "chromeos/dbus/shill_service_client.h"
     14 #include "chromeos/login/login_state.h"
     15 #include "chromeos/network/network_state_handler.h"
     16 #include "crypto/nss_util.h"
     17 #include "net/base/crypto_module.h"
     18 #include "net/base/net_errors.h"
     19 #include "net/base/test_data_directory.h"
     20 #include "net/cert/nss_cert_database.h"
     21 #include "net/cert/x509_certificate.h"
     22 #include "net/test/cert_test_util.h"
     23 #include "testing/gtest/include/gtest/gtest.h"
     24 #include "third_party/cros_system_api/dbus/service_constants.h"
     25 
     26 namespace chromeos {
     27 
     28 namespace {
     29 
     30 const char* kWifiStub = "wifi_stub";
     31 const char* kVPNStub = "vpn_stub";
     32 const char* kNSSNickname = "nss_nickname";
     33 const char* kFakePEM = "pem";
     34 
     35 }  // namespace
     36 
     37 class NetworkCertMigratorTest : public testing::Test {
     38  public:
     39   NetworkCertMigratorTest() {}
     40   virtual ~NetworkCertMigratorTest() {}
     41 
     42   virtual void SetUp() OVERRIDE {
     43     ASSERT_TRUE(test_nssdb_.is_open());
     44     slot_ = net::NSSCertDatabase::GetInstance()->GetPublicModule();
     45     ASSERT_TRUE(slot_->os_module_handle());
     46 
     47     LoginState::Initialize();
     48 
     49     DBusThreadManager::InitializeWithStub();
     50     service_test_ =
     51         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
     52     message_loop_.RunUntilIdle();
     53     service_test_->ClearServices();
     54     message_loop_.RunUntilIdle();
     55 
     56     CertLoader::Initialize();
     57     CertLoader::Get()->SetSlowTaskRunnerForTest(
     58         message_loop_.message_loop_proxy());
     59     CertLoader::Get()->SetCryptoTaskRunner(message_loop_.message_loop_proxy());
     60   }
     61 
     62   virtual void TearDown() OVERRIDE {
     63     network_cert_migrator_.reset();
     64     network_state_handler_.reset();
     65     CertLoader::Shutdown();
     66     DBusThreadManager::Shutdown();
     67     LoginState::Shutdown();
     68     CleanupTestCert();
     69   }
     70 
     71  protected:
     72   void SetupTestCACert() {
     73     scoped_refptr<net::X509Certificate> cert_wo_nickname =
     74         net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
     75                                            "eku-test-root.pem",
     76                                            net::X509Certificate::FORMAT_AUTO)
     77             .back();
     78     net::X509Certificate::GetPEMEncoded(cert_wo_nickname->os_cert_handle(),
     79                                         &test_ca_cert_pem_);
     80     std::string der_encoded;
     81     net::X509Certificate::GetDEREncoded(cert_wo_nickname->os_cert_handle(),
     82                                         &der_encoded);
     83     cert_wo_nickname = NULL;
     84 
     85     test_ca_cert_ = net::X509Certificate::CreateFromBytesWithNickname(
     86         der_encoded.data(), der_encoded.size(), kNSSNickname);
     87     net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance();
     88     net::CertificateList cert_list;
     89     cert_list.push_back(test_ca_cert_);
     90     net::NSSCertDatabase::ImportCertFailureList failures;
     91     EXPECT_TRUE(cert_database->ImportCACerts(
     92         cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures));
     93     ASSERT_TRUE(failures.empty()) << net::ErrorToString(failures[0].net_error);
     94   }
     95 
     96   void SetupNetworkHandlers() {
     97     network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
     98     network_cert_migrator_.reset(new NetworkCertMigrator);
     99     network_cert_migrator_->Init(network_state_handler_.get());
    100   }
    101 
    102   void SetupWifiWithNss() {
    103     const bool add_to_visible = true;
    104     const bool add_to_watchlist = true;
    105     service_test_->AddService(kWifiStub,
    106                               kWifiStub,
    107                               flimflam::kTypeWifi,
    108                               flimflam::kStateOnline,
    109                               add_to_visible,
    110                               add_to_watchlist);
    111     service_test_->SetServiceProperty(kWifiStub,
    112                                       flimflam::kEapCaCertNssProperty,
    113                                       base::StringValue(kNSSNickname));
    114   }
    115 
    116   void GetEapCACertProperties(std::string* nss_nickname, std::string* ca_pem) {
    117     nss_nickname->clear();
    118     ca_pem->clear();
    119     const base::DictionaryValue* properties =
    120         service_test_->GetServiceProperties(kWifiStub);
    121     properties->GetStringWithoutPathExpansion(flimflam::kEapCaCertNssProperty,
    122                                               nss_nickname);
    123     const base::ListValue* ca_pems = NULL;
    124     properties->GetListWithoutPathExpansion(shill::kEapCaCertPemProperty,
    125                                             &ca_pems);
    126     if (ca_pems && !ca_pems->empty())
    127       ca_pems->GetString(0, ca_pem);
    128   }
    129 
    130   void SetupVpnWithNss(bool open_vpn) {
    131     const bool add_to_visible = true;
    132     const bool add_to_watchlist = true;
    133     service_test_->AddService(kVPNStub,
    134                               kVPNStub,
    135                               flimflam::kTypeVPN,
    136                               flimflam::kStateIdle,
    137                               add_to_visible,
    138                               add_to_watchlist);
    139     base::DictionaryValue provider;
    140     const char* nss_property = open_vpn ? flimflam::kOpenVPNCaCertNSSProperty
    141                                         : flimflam::kL2tpIpsecCaCertNssProperty;
    142     provider.SetStringWithoutPathExpansion(nss_property, kNSSNickname);
    143     service_test_->SetServiceProperty(
    144         kVPNStub, flimflam::kProviderProperty, provider);
    145   }
    146 
    147   void GetVpnCACertProperties(bool open_vpn,
    148                               std::string* nss_nickname,
    149                               std::string* ca_pem) {
    150     nss_nickname->clear();
    151     ca_pem->clear();
    152     const base::DictionaryValue* properties =
    153         service_test_->GetServiceProperties(kVPNStub);
    154     const base::DictionaryValue* provider = NULL;
    155     properties->GetDictionaryWithoutPathExpansion(flimflam::kProviderProperty,
    156                                                   &provider);
    157     if (!provider)
    158       return;
    159     const char* nss_property = open_vpn ? flimflam::kOpenVPNCaCertNSSProperty
    160                                         : flimflam::kL2tpIpsecCaCertNssProperty;
    161     provider->GetStringWithoutPathExpansion(nss_property, nss_nickname);
    162     const base::ListValue* ca_pems = NULL;
    163     const char* pem_property = open_vpn ? shill::kOpenVPNCaCertPemProperty
    164                                         : shill::kL2tpIpsecCaCertPemProperty;
    165     provider->GetListWithoutPathExpansion(pem_property, &ca_pems);
    166     if (ca_pems && !ca_pems->empty())
    167       ca_pems->GetString(0, ca_pem);
    168   }
    169 
    170   ShillServiceClient::TestInterface* service_test_;
    171   scoped_refptr<net::X509Certificate> test_ca_cert_;
    172   std::string test_ca_cert_pem_;
    173   base::MessageLoop message_loop_;
    174 
    175  private:
    176   void CleanupTestCert() {
    177     ASSERT_TRUE(net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(
    178         test_ca_cert_.get()));
    179   }
    180 
    181   scoped_ptr<NetworkStateHandler> network_state_handler_;
    182   scoped_ptr<NetworkCertMigrator> network_cert_migrator_;
    183   scoped_refptr<net::CryptoModule> slot_;
    184   crypto::ScopedTestNSSDB test_nssdb_;
    185 
    186   DISALLOW_COPY_AND_ASSIGN(NetworkCertMigratorTest);
    187 };
    188 
    189 TEST_F(NetworkCertMigratorTest, MigrateNssOnInitialization) {
    190   // Add a new network for migration before the handlers are initialized.
    191   SetupWifiWithNss();
    192   SetupTestCACert();
    193   SetupNetworkHandlers();
    194 
    195   message_loop_.RunUntilIdle();
    196   std::string nss_nickname, ca_pem;
    197   GetEapCACertProperties(&nss_nickname, &ca_pem);
    198   EXPECT_TRUE(nss_nickname.empty());
    199   EXPECT_EQ(test_ca_cert_pem_, ca_pem);
    200 }
    201 
    202 TEST_F(NetworkCertMigratorTest, MigrateNssOnNetworkAppearance) {
    203   SetupTestCACert();
    204   SetupNetworkHandlers();
    205   message_loop_.RunUntilIdle();
    206 
    207   // Add a new network for migration after the handlers are initialized.
    208   SetupWifiWithNss();
    209 
    210   message_loop_.RunUntilIdle();
    211   std::string nss_nickname, ca_pem;
    212   GetEapCACertProperties(&nss_nickname, &ca_pem);
    213   EXPECT_TRUE(nss_nickname.empty());
    214   EXPECT_EQ(test_ca_cert_pem_, ca_pem);
    215 }
    216 
    217 TEST_F(NetworkCertMigratorTest, DoNotMigrateNssIfPemSet) {
    218   // Add a new network with an already set PEM property.
    219   SetupWifiWithNss();
    220   base::ListValue ca_pems;
    221   ca_pems.AppendString(kFakePEM);
    222   service_test_->SetServiceProperty(
    223       kWifiStub, shill::kEapCaCertPemProperty, ca_pems);
    224 
    225   SetupTestCACert();
    226   SetupNetworkHandlers();
    227   message_loop_.RunUntilIdle();
    228 
    229   std::string nss_nickname, ca_pem;
    230   GetEapCACertProperties(&nss_nickname, &ca_pem);
    231   EXPECT_TRUE(nss_nickname.empty());
    232   EXPECT_EQ(kFakePEM, ca_pem);
    233 }
    234 
    235 TEST_F(NetworkCertMigratorTest, MigrateOpenVpn) {
    236   // Add a new network for migration before the handlers are initialized.
    237   SetupVpnWithNss(true /* OpenVPN */);
    238 
    239   SetupTestCACert();
    240   SetupNetworkHandlers();
    241 
    242   message_loop_.RunUntilIdle();
    243   std::string nss_nickname, ca_pem;
    244   GetVpnCACertProperties(true /* OpenVPN */, &nss_nickname, &ca_pem);
    245   EXPECT_TRUE(nss_nickname.empty());
    246   EXPECT_EQ(test_ca_cert_pem_, ca_pem);
    247 }
    248 
    249 TEST_F(NetworkCertMigratorTest, MigrateIpsecVpn) {
    250   // Add a new network for migration before the handlers are initialized.
    251   SetupVpnWithNss(false /* not OpenVPN */);
    252 
    253   SetupTestCACert();
    254   SetupNetworkHandlers();
    255 
    256   message_loop_.RunUntilIdle();
    257   std::string nss_nickname, ca_pem;
    258   GetVpnCACertProperties(false /* not OpenVPN */, &nss_nickname, &ca_pem);
    259   EXPECT_TRUE(nss_nickname.empty());
    260   EXPECT_EQ(test_ca_cert_pem_, ca_pem);
    261 }
    262 
    263 
    264 }  // namespace chromeos
    265