OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 #include "chromeos/network/client_cert_resolver.h" | 4 #include "chromeos/network/client_cert_resolver.h" |
5 | 5 |
6 #include <cert.h> | 6 #include <cert.h> |
7 #include <pk11pub.h> | 7 #include <pk11pub.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 int slot_id = 0; | 101 int slot_id = 0; |
102 const std::string pkcs11_id = | 102 const std::string pkcs11_id = |
103 CertLoader::GetPkcs11IdAndSlotForCert(*test_client_cert_, &slot_id); | 103 CertLoader::GetPkcs11IdAndSlotForCert(*test_client_cert_, &slot_id); |
104 test_cert_id_ = base::StringPrintf("%i:%s", slot_id, pkcs11_id.c_str()); | 104 test_cert_id_ = base::StringPrintf("%i:%s", slot_id, pkcs11_id.c_str()); |
105 } | 105 } |
106 } | 106 } |
107 | 107 |
108 // Imports a client certificate. Its PKCS#11 ID is stored in |test_cert_id_|. | 108 // Imports a client certificate. Its PKCS#11 ID is stored in |test_cert_id_|. |
109 // If |import_issuer| is true, also imports the CA cert (stored as PEM in | 109 // If |import_issuer| is true, also imports the CA cert (stored as PEM in |
110 // test_ca_cert_pem_) that issued the client certificate. | 110 // test_ca_cert_pem_) that issued the client certificate. |
111 void SetupTestCerts(bool import_issuer) { | 111 void SetupTestCerts(const std::string& prefix, bool import_issuer) { |
112 // Load a CA cert. | 112 // Load a CA cert. |
113 net::CertificateList ca_cert_list = net::CreateCertificateListFromFile( | 113 net::CertificateList ca_cert_list = net::CreateCertificateListFromFile( |
114 net::GetTestCertsDirectory(), "client_1_ca.pem", | 114 net::GetTestCertsDirectory(), prefix + "_ca.pem", |
115 net::X509Certificate::FORMAT_AUTO); | 115 net::X509Certificate::FORMAT_AUTO); |
116 ASSERT_TRUE(!ca_cert_list.empty()); | 116 ASSERT_TRUE(!ca_cert_list.empty()); |
117 net::X509Certificate::GetPEMEncoded(ca_cert_list[0]->os_cert_handle(), | 117 net::X509Certificate::GetPEMEncoded(ca_cert_list[0]->os_cert_handle(), |
118 &test_ca_cert_pem_); | 118 &test_ca_cert_pem_); |
119 ASSERT_TRUE(!test_ca_cert_pem_.empty()); | 119 ASSERT_TRUE(!test_ca_cert_pem_.empty()); |
120 | 120 |
121 if (import_issuer) { | 121 if (import_issuer) { |
122 net::NSSCertDatabase::ImportCertFailureList failures; | 122 net::NSSCertDatabase::ImportCertFailureList failures; |
123 EXPECT_TRUE(test_nsscertdb_->ImportCACerts( | 123 EXPECT_TRUE(test_nsscertdb_->ImportCACerts( |
124 ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures)); | 124 ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures)); |
125 ASSERT_TRUE(failures.empty()) | 125 ASSERT_TRUE(failures.empty()) |
126 << net::ErrorToString(failures[0].net_error); | 126 << net::ErrorToString(failures[0].net_error); |
127 } | 127 } |
128 | 128 |
129 // Import a client cert signed by that CA. | 129 // Import a client cert signed by that CA. |
130 test_client_cert_ = | 130 test_client_cert_ = net::ImportClientCertAndKeyFromFile( |
131 net::ImportClientCertAndKeyFromFile(net::GetTestCertsDirectory(), | 131 net::GetTestCertsDirectory(), prefix + ".pem", prefix + ".pk8", |
132 "client_1.pem", | 132 test_nssdb_.slot()); |
133 "client_1.pk8", | |
134 test_nssdb_.slot()); | |
135 ASSERT_TRUE(test_client_cert_.get()); | 133 ASSERT_TRUE(test_client_cert_.get()); |
136 } | 134 } |
137 | 135 |
138 void SetupNetworkHandlers() { | 136 void SetupNetworkHandlers() { |
139 network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); | 137 network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); |
140 network_profile_handler_.reset(new NetworkProfileHandler()); | 138 network_profile_handler_.reset(new NetworkProfileHandler()); |
141 network_config_handler_.reset(new NetworkConfigurationHandler()); | 139 network_config_handler_.reset(new NetworkConfigurationHandler()); |
142 managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl()); | 140 managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl()); |
143 client_cert_resolver_.reset(new ClientCertResolver()); | 141 client_cert_resolver_.reset(new ClientCertResolver()); |
144 | 142 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 ASSERT_TRUE(policy_value->GetAsList(&policy)); | 211 ASSERT_TRUE(policy_value->GetAsList(&policy)); |
214 | 212 |
215 managed_config_handler_->SetPolicy( | 213 managed_config_handler_->SetPolicy( |
216 onc::ONC_SOURCE_USER_POLICY, kUserHash, *policy, | 214 onc::ONC_SOURCE_USER_POLICY, kUserHash, *policy, |
217 base::DictionaryValue() /* no global network config */); | 215 base::DictionaryValue() /* no global network config */); |
218 } | 216 } |
219 | 217 |
220 // Sets up a policy with a certificate pattern that matches any client cert | 218 // Sets up a policy with a certificate pattern that matches any client cert |
221 // that is signed by the test CA cert (stored in |test_ca_cert_pem_|). In | 219 // that is signed by the test CA cert (stored in |test_ca_cert_pem_|). In |
222 // particular it will match the test client cert. | 220 // particular it will match the test client cert. |
223 void SetupPolicyMatchingIssuerPEM() { | 221 void SetupPolicyMatchingIssuerPEM(const std::string& identity) { |
224 const char* kTestPolicyTemplate = | 222 const char* kTestPolicyTemplate = |
225 "[ { \"GUID\": \"wifi_stub\"," | 223 "[ { \"GUID\": \"wifi_stub\"," |
226 " \"Name\": \"wifi_stub\"," | 224 " \"Name\": \"wifi_stub\"," |
227 " \"Type\": \"WiFi\"," | 225 " \"Type\": \"WiFi\"," |
228 " \"WiFi\": {" | 226 " \"WiFi\": {" |
229 " \"Security\": \"WPA-EAP\"," | 227 " \"Security\": \"WPA-EAP\"," |
230 " \"SSID\": \"wifi_ssid\"," | 228 " \"SSID\": \"wifi_ssid\"," |
231 " \"EAP\": {" | 229 " \"EAP\": {" |
| 230 " \"Identity\": \"%s\"," |
232 " \"Outer\": \"EAP-TLS\"," | 231 " \"Outer\": \"EAP-TLS\"," |
233 " \"ClientCertType\": \"Pattern\"," | 232 " \"ClientCertType\": \"Pattern\"," |
234 " \"ClientCertPattern\": {" | 233 " \"ClientCertPattern\": {" |
235 " \"IssuerCAPEMs\": [ \"%s\" ]" | 234 " \"IssuerCAPEMs\": [ \"%s\" ]" |
236 " }" | 235 " }" |
237 " }" | 236 " }" |
238 " }" | 237 " }" |
239 "} ]"; | 238 "} ]"; |
240 std::string policy_json = | 239 std::string policy_json = base::StringPrintf( |
241 base::StringPrintf(kTestPolicyTemplate, test_ca_cert_pem_.c_str()); | 240 kTestPolicyTemplate, identity.c_str(), test_ca_cert_pem_.c_str()); |
242 | 241 |
243 std::string error; | 242 std::string error; |
244 scoped_ptr<base::Value> policy_value = base::JSONReader::ReadAndReturnError( | 243 scoped_ptr<base::Value> policy_value = base::JSONReader::ReadAndReturnError( |
245 policy_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error); | 244 policy_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error); |
246 ASSERT_TRUE(policy_value) << error; | 245 ASSERT_TRUE(policy_value) << error; |
247 | 246 |
248 base::ListValue* policy = nullptr; | 247 base::ListValue* policy = nullptr; |
249 ASSERT_TRUE(policy_value->GetAsList(&policy)); | 248 ASSERT_TRUE(policy_value->GetAsList(&policy)); |
250 | 249 |
251 managed_config_handler_->SetPolicy( | 250 managed_config_handler_->SetPolicy( |
252 onc::ONC_SOURCE_USER_POLICY, | 251 onc::ONC_SOURCE_USER_POLICY, |
253 kUserHash, | 252 kUserHash, |
254 *policy, | 253 *policy, |
255 base::DictionaryValue() /* no global network config */); | 254 base::DictionaryValue() /* no global network config */); |
256 } | 255 } |
257 | 256 |
258 void SetWifiState(const std::string& state) { | 257 void SetWifiState(const std::string& state) { |
259 ASSERT_TRUE(service_test_->SetServiceProperty( | 258 ASSERT_TRUE(service_test_->SetServiceProperty( |
260 kWifiStub, shill::kStateProperty, base::StringValue(state))); | 259 kWifiStub, shill::kStateProperty, base::StringValue(state))); |
261 } | 260 } |
262 | 261 |
263 void GetClientCertProperties(std::string* pkcs11_id) { | 262 void GetServiceProperty(const std::string& prop_name, |
264 pkcs11_id->clear(); | 263 std::string* prop_value) { |
| 264 prop_value->clear(); |
265 const base::DictionaryValue* properties = | 265 const base::DictionaryValue* properties = |
266 service_test_->GetServiceProperties(kWifiStub); | 266 service_test_->GetServiceProperties(kWifiStub); |
267 if (!properties) | 267 if (!properties) |
268 return; | 268 return; |
269 properties->GetStringWithoutPathExpansion(shill::kEapCertIdProperty, | 269 properties->GetStringWithoutPathExpansion(prop_name, prop_value); |
270 pkcs11_id); | |
271 } | 270 } |
272 | 271 |
273 int network_properties_changed_count_; | 272 int network_properties_changed_count_; |
274 std::string test_cert_id_; | 273 std::string test_cert_id_; |
275 scoped_ptr<base::SimpleTestClock> test_clock_; | 274 scoped_ptr<base::SimpleTestClock> test_clock_; |
276 scoped_ptr<ClientCertResolver> client_cert_resolver_; | 275 scoped_ptr<ClientCertResolver> client_cert_resolver_; |
277 | 276 |
278 private: | 277 private: |
279 // ClientCertResolver::Observer: | 278 // ClientCertResolver::Observer: |
280 void ResolveRequestCompleted(bool network_properties_changed) override { | 279 void ResolveRequestCompleted(bool network_properties_changed) override { |
(...skipping 11 matching lines...) Expand all Loading... |
292 base::MessageLoop message_loop_; | 291 base::MessageLoop message_loop_; |
293 scoped_refptr<net::X509Certificate> test_client_cert_; | 292 scoped_refptr<net::X509Certificate> test_client_cert_; |
294 std::string test_ca_cert_pem_; | 293 std::string test_ca_cert_pem_; |
295 crypto::ScopedTestNSSDB test_nssdb_; | 294 crypto::ScopedTestNSSDB test_nssdb_; |
296 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nsscertdb_; | 295 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nsscertdb_; |
297 | 296 |
298 DISALLOW_COPY_AND_ASSIGN(ClientCertResolverTest); | 297 DISALLOW_COPY_AND_ASSIGN(ClientCertResolverTest); |
299 }; | 298 }; |
300 | 299 |
301 TEST_F(ClientCertResolverTest, NoMatchingCertificates) { | 300 TEST_F(ClientCertResolverTest, NoMatchingCertificates) { |
302 SetupTestCerts(false /* do not import the issuer */); | 301 SetupTestCerts("client_1", false /* do not import the issuer */); |
303 StartCertLoader(); | 302 StartCertLoader(); |
304 SetupWifi(); | 303 SetupWifi(); |
305 base::RunLoop().RunUntilIdle(); | 304 base::RunLoop().RunUntilIdle(); |
306 network_properties_changed_count_ = 0; | 305 network_properties_changed_count_ = 0; |
307 SetupNetworkHandlers(); | 306 SetupNetworkHandlers(); |
308 SetupPolicyMatchingIssuerPEM(); | 307 SetupPolicyMatchingIssuerPEM(""); |
309 base::RunLoop().RunUntilIdle(); | 308 base::RunLoop().RunUntilIdle(); |
310 | 309 |
311 // Verify that no client certificate was configured. | 310 // Verify that no client certificate was configured. |
312 std::string pkcs11_id; | 311 std::string pkcs11_id; |
313 GetClientCertProperties(&pkcs11_id); | 312 GetServiceProperty(shill::kEapCertIdProperty, &pkcs11_id); |
314 EXPECT_EQ(std::string(), pkcs11_id); | 313 EXPECT_EQ(std::string(), pkcs11_id); |
315 EXPECT_EQ(1, network_properties_changed_count_); | 314 EXPECT_EQ(1, network_properties_changed_count_); |
316 EXPECT_FALSE(client_cert_resolver_->IsAnyResolveTaskRunning()); | 315 EXPECT_FALSE(client_cert_resolver_->IsAnyResolveTaskRunning()); |
317 } | 316 } |
318 | 317 |
319 TEST_F(ClientCertResolverTest, MatchIssuerCNWithoutIssuerInstalled) { | 318 TEST_F(ClientCertResolverTest, MatchIssuerCNWithoutIssuerInstalled) { |
320 SetupTestCerts(false /* do not import the issuer */); | 319 SetupTestCerts("client_1", false /* do not import the issuer */); |
321 SetupWifi(); | 320 SetupWifi(); |
322 base::RunLoop().RunUntilIdle(); | 321 base::RunLoop().RunUntilIdle(); |
323 | 322 |
324 SetupNetworkHandlers(); | 323 SetupNetworkHandlers(); |
325 SetupPolicyMatchingIssuerCN(); | 324 SetupPolicyMatchingIssuerCN(); |
326 base::RunLoop().RunUntilIdle(); | 325 base::RunLoop().RunUntilIdle(); |
327 | 326 |
328 network_properties_changed_count_ = 0; | 327 network_properties_changed_count_ = 0; |
329 StartCertLoader(); | 328 StartCertLoader(); |
330 base::RunLoop().RunUntilIdle(); | 329 base::RunLoop().RunUntilIdle(); |
331 | 330 |
332 // Verify that the resolver positively matched the pattern in the policy with | 331 // Verify that the resolver positively matched the pattern in the policy with |
333 // the test client cert and configured the network. | 332 // the test client cert and configured the network. |
334 std::string pkcs11_id; | 333 std::string pkcs11_id; |
335 GetClientCertProperties(&pkcs11_id); | 334 GetServiceProperty(shill::kEapCertIdProperty, &pkcs11_id); |
336 EXPECT_EQ(test_cert_id_, pkcs11_id); | 335 EXPECT_EQ(test_cert_id_, pkcs11_id); |
337 EXPECT_EQ(1, network_properties_changed_count_); | 336 EXPECT_EQ(1, network_properties_changed_count_); |
338 } | 337 } |
339 | 338 |
340 TEST_F(ClientCertResolverTest, ResolveOnCertificatesLoaded) { | 339 TEST_F(ClientCertResolverTest, ResolveOnCertificatesLoaded) { |
341 SetupTestCerts(true /* import issuer */); | 340 SetupTestCerts("client_1", true /* import issuer */); |
342 SetupWifi(); | 341 SetupWifi(); |
343 base::RunLoop().RunUntilIdle(); | 342 base::RunLoop().RunUntilIdle(); |
344 | 343 |
345 SetupNetworkHandlers(); | 344 SetupNetworkHandlers(); |
346 SetupPolicyMatchingIssuerPEM(); | 345 SetupPolicyMatchingIssuerPEM(""); |
347 base::RunLoop().RunUntilIdle(); | 346 base::RunLoop().RunUntilIdle(); |
348 | 347 |
349 network_properties_changed_count_ = 0; | 348 network_properties_changed_count_ = 0; |
350 StartCertLoader(); | 349 StartCertLoader(); |
351 base::RunLoop().RunUntilIdle(); | 350 base::RunLoop().RunUntilIdle(); |
352 | 351 |
353 // Verify that the resolver positively matched the pattern in the policy with | 352 // Verify that the resolver positively matched the pattern in the policy with |
354 // the test client cert and configured the network. | 353 // the test client cert and configured the network. |
355 std::string pkcs11_id; | 354 std::string pkcs11_id; |
356 GetClientCertProperties(&pkcs11_id); | 355 GetServiceProperty(shill::kEapCertIdProperty, &pkcs11_id); |
357 EXPECT_EQ(test_cert_id_, pkcs11_id); | 356 EXPECT_EQ(test_cert_id_, pkcs11_id); |
358 EXPECT_EQ(1, network_properties_changed_count_); | 357 EXPECT_EQ(1, network_properties_changed_count_); |
359 } | 358 } |
360 | 359 |
361 TEST_F(ClientCertResolverTest, ResolveAfterPolicyApplication) { | 360 TEST_F(ClientCertResolverTest, ResolveAfterPolicyApplication) { |
362 SetupTestCerts(true /* import issuer */); | 361 SetupTestCerts("client_1", true /* import issuer */); |
363 SetupWifi(); | 362 SetupWifi(); |
364 base::RunLoop().RunUntilIdle(); | 363 base::RunLoop().RunUntilIdle(); |
365 StartCertLoader(); | 364 StartCertLoader(); |
366 SetupNetworkHandlers(); | 365 SetupNetworkHandlers(); |
367 base::RunLoop().RunUntilIdle(); | 366 base::RunLoop().RunUntilIdle(); |
368 | 367 |
369 // Policy application will trigger the ClientCertResolver. | 368 // Policy application will trigger the ClientCertResolver. |
370 network_properties_changed_count_ = 0; | 369 network_properties_changed_count_ = 0; |
371 SetupPolicyMatchingIssuerPEM(); | 370 SetupPolicyMatchingIssuerPEM(""); |
372 base::RunLoop().RunUntilIdle(); | 371 base::RunLoop().RunUntilIdle(); |
373 | 372 |
374 // Verify that the resolver positively matched the pattern in the policy with | 373 // Verify that the resolver positively matched the pattern in the policy with |
375 // the test client cert and configured the network. | 374 // the test client cert and configured the network. |
376 std::string pkcs11_id; | 375 std::string pkcs11_id; |
377 GetClientCertProperties(&pkcs11_id); | 376 GetServiceProperty(shill::kEapCertIdProperty, &pkcs11_id); |
378 EXPECT_EQ(test_cert_id_, pkcs11_id); | 377 EXPECT_EQ(test_cert_id_, pkcs11_id); |
379 EXPECT_EQ(1, network_properties_changed_count_); | 378 EXPECT_EQ(1, network_properties_changed_count_); |
380 } | 379 } |
381 | 380 |
382 TEST_F(ClientCertResolverTest, ExpiringCertificate) { | 381 TEST_F(ClientCertResolverTest, ExpiringCertificate) { |
383 SetupTestCerts(true /* import issuer */); | 382 SetupTestCerts("client_1", true /* import issuer */); |
384 SetupWifi(); | 383 SetupWifi(); |
385 base::RunLoop().RunUntilIdle(); | 384 base::RunLoop().RunUntilIdle(); |
386 | 385 |
387 SetupNetworkHandlers(); | 386 SetupNetworkHandlers(); |
388 SetupPolicyMatchingIssuerPEM(); | 387 SetupPolicyMatchingIssuerPEM(""); |
389 base::RunLoop().RunUntilIdle(); | 388 base::RunLoop().RunUntilIdle(); |
390 | 389 |
391 StartCertLoader(); | 390 StartCertLoader(); |
392 base::RunLoop().RunUntilIdle(); | 391 base::RunLoop().RunUntilIdle(); |
393 | 392 |
394 SetWifiState(shill::kStateOnline); | 393 SetWifiState(shill::kStateOnline); |
395 base::RunLoop().RunUntilIdle(); | 394 base::RunLoop().RunUntilIdle(); |
396 | 395 |
397 // Verify that the resolver positively matched the pattern in the policy with | 396 // Verify that the resolver positively matched the pattern in the policy with |
398 // the test client cert and configured the network. | 397 // the test client cert and configured the network. |
399 std::string pkcs11_id; | 398 std::string pkcs11_id; |
400 GetClientCertProperties(&pkcs11_id); | 399 GetServiceProperty(shill::kEapCertIdProperty, &pkcs11_id); |
401 EXPECT_EQ(test_cert_id_, pkcs11_id); | 400 EXPECT_EQ(test_cert_id_, pkcs11_id); |
402 | 401 |
403 // Verify that, after the certificate expired and the network disconnection | 402 // Verify that, after the certificate expired and the network disconnection |
404 // happens, no client certificate was configured. | 403 // happens, no client certificate was configured. |
405 test_clock_->SetNow(base::Time::Max()); | 404 test_clock_->SetNow(base::Time::Max()); |
406 SetWifiState(shill::kStateOffline); | 405 SetWifiState(shill::kStateOffline); |
407 base::RunLoop().RunUntilIdle(); | 406 base::RunLoop().RunUntilIdle(); |
408 GetClientCertProperties(&pkcs11_id); | 407 GetServiceProperty(shill::kEapCertIdProperty, &pkcs11_id); |
409 EXPECT_EQ(std::string(), pkcs11_id); | 408 EXPECT_EQ(std::string(), pkcs11_id); |
410 } | 409 } |
411 | 410 |
| 411 TEST_F(ClientCertResolverTest, PopulateIdentityFromCert) { |
| 412 SetupTestCerts("client_3", true /* import issuer */); |
| 413 SetupWifi(); |
| 414 base::RunLoop().RunUntilIdle(); |
| 415 |
| 416 SetupNetworkHandlers(); |
| 417 SetupPolicyMatchingIssuerPEM("${CERT_SAN_EMAIL}"); |
| 418 base::RunLoop().RunUntilIdle(); |
| 419 |
| 420 network_properties_changed_count_ = 0; |
| 421 StartCertLoader(); |
| 422 base::RunLoop().RunUntilIdle(); |
| 423 |
| 424 // Verify that the resolver read the subjectAltName email field from the |
| 425 // cert, and wrote it into the shill service entry. |
| 426 std::string identity; |
| 427 GetServiceProperty(shill::kEapIdentityProperty, &identity); |
| 428 EXPECT_EQ("santest@example.com", identity); |
| 429 EXPECT_EQ(1, network_properties_changed_count_); |
| 430 |
| 431 // Verify that after changing the ONC policy to request a variant of the |
| 432 // Microsoft Universal Principal Name field instead, the correct value is |
| 433 // substituted into the shill service entry. |
| 434 SetupPolicyMatchingIssuerPEM("upn-${CERT_SAN_UPN}-suffix"); |
| 435 base::RunLoop().RunUntilIdle(); |
| 436 |
| 437 GetServiceProperty(shill::kEapIdentityProperty, &identity); |
| 438 EXPECT_EQ("upn-santest@ad.corp.example.com-suffix", identity); |
| 439 EXPECT_EQ(2, network_properties_changed_count_); |
| 440 } |
| 441 |
412 } // namespace chromeos | 442 } // namespace chromeos |
OLD | NEW |