- add sources.
[platform/framework/web/crosswalk.git] / src / chromeos / network / client_cert_resolver_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 #include "chromeos/network/client_cert_resolver.h"
5
6 #include <cert.h>
7 #include <pk11pub.h>
8
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/json/json_reader.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16 #include "chromeos/dbus/shill_profile_client.h"
17 #include "chromeos/dbus/shill_service_client.h"
18 #include "chromeos/login/login_state.h"
19 #include "chromeos/network/managed_network_configuration_handler_impl.h"
20 #include "chromeos/network/network_configuration_handler.h"
21 #include "chromeos/network/network_profile_handler.h"
22 #include "chromeos/network/network_state_handler.h"
23 #include "crypto/nss_util.h"
24 #include "net/base/crypto_module.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/test_data_directory.h"
27 #include "net/cert/nss_cert_database.h"
28 #include "net/cert/x509_certificate.h"
29 #include "net/test/cert_test_util.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "third_party/cros_system_api/dbus/service_constants.h"
32
33 namespace chromeos {
34
35 namespace {
36
37 const char* kWifiStub = "wifi_stub";
38 const char* kWifiSSID = "wifi_ssid";
39 const char* kUserProfilePath = "user_profile";
40 const char* kUserHash = "user_hash";
41
42 }  // namespace
43
44 class ClientCertResolverTest : public testing::Test {
45  public:
46   ClientCertResolverTest() {}
47   virtual ~ClientCertResolverTest() {}
48
49   virtual void SetUp() OVERRIDE {
50     ASSERT_TRUE(test_nssdb_.is_open());
51     slot_ = net::NSSCertDatabase::GetInstance()->GetPublicModule();
52     ASSERT_TRUE(slot_->os_module_handle());
53
54     LoginState::Initialize();
55
56     DBusThreadManager::InitializeWithStub();
57     service_test_ =
58         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
59     profile_test_ =
60         DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
61     message_loop_.RunUntilIdle();
62     service_test_->ClearServices();
63     message_loop_.RunUntilIdle();
64
65     CertLoader::Initialize();
66     CertLoader* cert_loader = CertLoader::Get();
67     cert_loader->InitializeTPMForTest();
68     cert_loader->SetSlowTaskRunnerForTest(message_loop_.message_loop_proxy());
69     cert_loader->SetCryptoTaskRunner(message_loop_.message_loop_proxy());
70   }
71
72   virtual void TearDown() OVERRIDE {
73     client_cert_resolver_.reset();
74     managed_config_handler_.reset();
75     network_config_handler_.reset();
76     network_profile_handler_.reset();
77     network_state_handler_.reset();
78     CertLoader::Shutdown();
79     DBusThreadManager::Shutdown();
80     LoginState::Shutdown();
81     CleanupSlotContents();
82   }
83
84  protected:
85   // Imports a CA cert (stored as PEM in test_ca_cert_pem_) and a client
86   // certificate signed by that CA. Its PKCS#11 ID is stored in
87   // |test_pkcs11_id_|.
88   void SetupTestCerts() {
89     // Import a CA cert.
90     net::NSSCertDatabase* cert_db = net::NSSCertDatabase::GetInstance();
91     net::CertificateList ca_cert_list =
92         net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
93                                            "websocket_cacert.pem",
94                                            net::X509Certificate::FORMAT_AUTO);
95     ASSERT_TRUE(!ca_cert_list.empty());
96     net::NSSCertDatabase::ImportCertFailureList failures;
97     EXPECT_TRUE(cert_db->ImportCACerts(
98         ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures));
99     ASSERT_TRUE(failures.empty()) << net::ErrorToString(failures[0].net_error);
100
101     net::X509Certificate::GetPEMEncoded(ca_cert_list[0]->os_cert_handle(),
102                                         &test_ca_cert_pem_);
103     ASSERT_TRUE(!test_ca_cert_pem_.empty());
104
105     // Import a client cert signed by that CA.
106     scoped_refptr<net::CryptoModule> crypt_module = cert_db->GetPrivateModule();
107     std::string pkcs12_data;
108     ASSERT_TRUE(base::ReadFileToString(
109         net::GetTestCertsDirectory().Append("websocket_client_cert.p12"),
110         &pkcs12_data));
111
112     net::CertificateList client_cert_list;
113     ASSERT_EQ(net::OK,
114               cert_db->ImportFromPKCS12(crypt_module.get(),
115                                         pkcs12_data,
116                                         string16(),
117                                         false,
118                                         &client_cert_list));
119     ASSERT_TRUE(!client_cert_list.empty());
120     test_pkcs11_id_ = CertLoader::GetPkcs11IdForCert(*client_cert_list[0]);
121     ASSERT_TRUE(!test_pkcs11_id_.empty());
122   }
123
124   void SetupNetworkHandlers() {
125     network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
126     network_profile_handler_.reset(new NetworkProfileHandler());
127     network_config_handler_.reset(new NetworkConfigurationHandler());
128     managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
129     client_cert_resolver_.reset(new ClientCertResolver());
130
131     network_profile_handler_->Init(network_state_handler_.get());
132     network_config_handler_->Init(network_state_handler_.get());
133     managed_config_handler_->Init(network_state_handler_.get(),
134                                   network_profile_handler_.get(),
135                                   network_config_handler_.get());
136     client_cert_resolver_->Init(network_state_handler_.get(),
137                                 managed_config_handler_.get());
138     client_cert_resolver_->SetSlowTaskRunnerForTest(
139         message_loop_.message_loop_proxy());
140
141     profile_test_->AddProfile(kUserProfilePath, kUserHash);
142   }
143
144   void SetupWifi() {
145     const bool add_to_visible = true;
146     const bool add_to_watchlist = true;
147     service_test_->AddService(kWifiStub,
148                               kWifiSSID,
149                               shill::kTypeWifi,
150                               shill::kStateOnline,
151                               add_to_visible,
152                               add_to_watchlist);
153     service_test_->SetServiceProperty(
154         kWifiStub, shill::kGuidProperty, base::StringValue(kWifiStub));
155
156     profile_test_->AddService(kUserProfilePath, kWifiStub);
157   }
158
159   // Setup a policy with a certificate pattern that matches any client cert that
160   // is signed by the test CA cert (stored in |test_ca_cert_pem_|). In
161   // particular it will match the test client cert.
162   void SetupPolicy() {
163     const char* kTestPolicyTemplate =
164         "[ { \"GUID\": \"wifi_stub\","
165         "    \"Name\": \"wifi_stub\","
166         "    \"Type\": \"WiFi\","
167         "    \"WiFi\": {"
168         "      \"Security\": \"WPA-EAP\","
169         "      \"SSID\": \"wifi_ssid\","
170         "      \"EAP\": {"
171         "        \"Outer\": \"EAP-TLS\","
172         "        \"ClientCertType\": \"Pattern\","
173         "        \"ClientCertPattern\": {"
174         "          \"IssuerCAPEMs\": [ \"%s\" ]"
175         "        }"
176         "      }"
177         "    }"
178         "} ]";
179     std::string policy_json =
180         base::StringPrintf(kTestPolicyTemplate, test_ca_cert_pem_.c_str());
181
182     std::string error;
183     scoped_ptr<base::Value> policy_value(base::JSONReader::ReadAndReturnError(
184         policy_json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error));
185     ASSERT_TRUE(policy_value) << error;
186
187     base::ListValue* policy = NULL;
188     ASSERT_TRUE(policy_value->GetAsList(&policy));
189
190     managed_config_handler_->SetPolicy(
191         onc::ONC_SOURCE_USER_POLICY,
192         kUserHash,
193         *policy,
194         base::DictionaryValue() /* no global network config */);
195   }
196
197   void GetClientCertProperties(std::string* pkcs11_id) {
198     pkcs11_id->clear();
199     const base::DictionaryValue* properties =
200         service_test_->GetServiceProperties(kWifiStub);
201     if (!properties)
202       return;
203     properties->GetStringWithoutPathExpansion(shill::kEapCertIdProperty,
204                                               pkcs11_id);
205   }
206
207   ShillServiceClient::TestInterface* service_test_;
208   ShillProfileClient::TestInterface* profile_test_;
209   std::string test_pkcs11_id_;
210   scoped_refptr<net::X509Certificate> test_ca_cert_;
211   std::string test_ca_cert_pem_;
212   base::MessageLoop message_loop_;
213
214  private:
215   void CleanupSlotContents() {
216     CERTCertList* cert_list = PK11_ListCertsInSlot(slot_->os_module_handle());
217     for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
218          !CERT_LIST_END(node, cert_list);
219          node = CERT_LIST_NEXT(node)) {
220       scoped_refptr<net::X509Certificate> cert(
221           net::X509Certificate::CreateFromHandle(
222               node->cert, net::X509Certificate::OSCertHandles()));
223       net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(cert.get());
224     }
225     CERT_DestroyCertList(cert_list);
226   }
227
228   scoped_ptr<NetworkStateHandler> network_state_handler_;
229   scoped_ptr<NetworkProfileHandler> network_profile_handler_;
230   scoped_ptr<NetworkConfigurationHandler> network_config_handler_;
231   scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_;
232   scoped_ptr<ClientCertResolver> client_cert_resolver_;
233   scoped_refptr<net::CryptoModule> slot_;
234   crypto::ScopedTestNSSDB test_nssdb_;
235
236   DISALLOW_COPY_AND_ASSIGN(ClientCertResolverTest);
237 };
238
239 TEST_F(ClientCertResolverTest, NoMatchingCertificates) {
240   SetupNetworkHandlers();
241   SetupPolicy();
242   message_loop_.RunUntilIdle();
243
244   SetupWifi();
245   message_loop_.RunUntilIdle();
246
247   // Verify that no client certificate was configured.
248   std::string pkcs11_id;
249   GetClientCertProperties(&pkcs11_id);
250   EXPECT_TRUE(pkcs11_id.empty());
251 }
252
253 TEST_F(ClientCertResolverTest, ResolveOnInitialization) {
254   SetupTestCerts();
255   SetupNetworkHandlers();
256   SetupPolicy();
257   message_loop_.RunUntilIdle();
258
259   SetupWifi();
260   message_loop_.RunUntilIdle();
261
262   // Verify that the resolver positively matched the pattern in the policy with
263   // the test client cert and configured the network.
264   std::string pkcs11_id;
265   GetClientCertProperties(&pkcs11_id);
266   EXPECT_EQ(test_pkcs11_id_, pkcs11_id);
267 }
268
269 TEST_F(ClientCertResolverTest, ResolveAfterPolicyApplication) {
270   SetupTestCerts();
271   SetupNetworkHandlers();
272   message_loop_.RunUntilIdle();
273
274   // The policy will trigger the creation of a new wifi service.
275   SetupPolicy();
276   message_loop_.RunUntilIdle();
277
278   // Verify that the resolver positively matched the pattern in the policy with
279   // the test client cert and configured the network.
280   std::string pkcs11_id;
281   GetClientCertProperties(&pkcs11_id);
282   EXPECT_EQ(test_pkcs11_id_, pkcs11_id);
283 }
284
285 }  // namespace chromeos