network_cert_migrator_unittest.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
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
26namespace chromeos {
27
28namespace {
29
30const char* kWifiStub = "wifi_stub";
31const char* kVPNStub = "vpn_stub";
32const char* kNSSNickname = "nss_nickname";
33const char* kFakePEM = "pem";
34
35}  // namespace
36
37class 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
189TEST_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
202TEST_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
217TEST_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
235TEST_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
249TEST_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