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