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 | 4 |
5 #include "chromeos/network/client_cert_resolver.h" | 5 #include "chromeos/network/client_cert_resolver.h" |
6 | 6 |
7 #include <cert.h> | 7 #include <cert.h> |
8 #include <certt.h> // for (SECCertUsageEnum) certUsageAnyCA | 8 #include <certt.h> // for (SECCertUsageEnum) certUsageAnyCA |
9 #include <pk11pub.h> | 9 #include <pk11pub.h> |
10 | 10 |
11 #include <algorithm> | 11 #include <algorithm> |
12 | 12 |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
14 #include "base/location.h" | 14 #include "base/location.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/memory/ptr_util.h" |
16 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
17 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
18 #include "base/task_scheduler/post_task.h" | 19 #include "base/task_scheduler/post_task.h" |
19 #include "base/time/clock.h" | 20 #include "base/time/clock.h" |
20 #include "chromeos/dbus/dbus_thread_manager.h" | 21 #include "chromeos/dbus/dbus_thread_manager.h" |
21 #include "chromeos/dbus/shill_service_client.h" | 22 #include "chromeos/dbus/shill_service_client.h" |
22 #include "chromeos/network/managed_network_configuration_handler.h" | 23 #include "chromeos/network/managed_network_configuration_handler.h" |
23 #include "chromeos/network/network_state.h" | 24 #include "chromeos/network/network_state.h" |
24 #include "components/onc/onc_constants.h" | 25 #include "components/onc/onc_constants.h" |
25 #include "dbus/object_path.h" | 26 #include "dbus/object_path.h" |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 client_certs.push_back(CertAndIssuer(*it, GetPEMEncodedIssuer(cert))); | 185 client_certs.push_back(CertAndIssuer(*it, GetPEMEncodedIssuer(cert))); |
185 } | 186 } |
186 | 187 |
187 std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration); | 188 std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration); |
188 return client_certs; | 189 return client_certs; |
189 } | 190 } |
190 | 191 |
191 // Searches for matches between |networks| and |certs| and writes matches to | 192 // Searches for matches between |networks| and |certs| and writes matches to |
192 // |matches|. Because this calls NSS functions and is potentially slow, it must | 193 // |matches|. Because this calls NSS functions and is potentially slow, it must |
193 // be run on a worker thread. | 194 // be run on a worker thread. |
194 void FindCertificateMatches(const net::CertificateList& certs, | 195 std::unique_ptr<NetworkCertMatches> FindCertificateMatches( |
195 std::vector<NetworkAndCertPattern>* networks, | 196 const net::CertificateList& all_certs, |
196 base::Time now, | 197 const net::CertificateList& system_certs, |
197 NetworkCertMatches* matches) { | 198 std::vector<NetworkAndCertPattern>* networks, |
198 std::vector<CertAndIssuer> client_certs( | 199 base::Time now) { |
199 CreateSortedCertAndIssuerList(certs, now)); | 200 std::unique_ptr<NetworkCertMatches> matches = |
| 201 base::MakeUnique<NetworkCertMatches>(); |
| 202 |
| 203 std::vector<CertAndIssuer> all_client_certs( |
| 204 CreateSortedCertAndIssuerList(all_certs, now)); |
| 205 std::vector<CertAndIssuer> system_client_certs( |
| 206 CreateSortedCertAndIssuerList(system_certs, now)); |
200 | 207 |
201 for (std::vector<NetworkAndCertPattern>::const_iterator it = | 208 for (std::vector<NetworkAndCertPattern>::const_iterator it = |
202 networks->begin(); | 209 networks->begin(); |
203 it != networks->end(); ++it) { | 210 it != networks->end(); ++it) { |
204 std::vector<CertAndIssuer>::iterator cert_it = | 211 // Use only certs from the system token if the source of the client cert |
205 std::find_if(client_certs.begin(), | 212 // pattern is device policy. |
206 client_certs.end(), | 213 std::vector<CertAndIssuer>* client_certs = |
207 MatchCertWithPattern(it->cert_config.pattern)); | 214 it->cert_config.onc_source == ::onc::ONC_SOURCE_DEVICE_POLICY |
| 215 ? &system_client_certs |
| 216 : &all_client_certs; |
| 217 auto cert_it = std::find_if(client_certs->begin(), client_certs->end(), |
| 218 MatchCertWithPattern(it->cert_config.pattern)); |
208 std::string pkcs11_id; | 219 std::string pkcs11_id; |
209 int slot_id = -1; | 220 int slot_id = -1; |
210 std::string identity; | 221 std::string identity; |
211 | 222 |
212 if (cert_it == client_certs.end()) { | 223 if (cert_it == client_certs->end()) { |
213 VLOG(1) << "Couldn't find a matching client cert for network " | 224 VLOG(1) << "Couldn't find a matching client cert for network " |
214 << it->service_path; | 225 << it->service_path; |
215 // Leave |pkcs11_id| empty to indicate that no cert was found for this | 226 // Leave |pkcs11_id| empty to indicate that no cert was found for this |
216 // network. | 227 // network. |
217 } else { | 228 } else { |
218 pkcs11_id = | 229 pkcs11_id = |
219 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); | 230 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); |
220 if (pkcs11_id.empty()) { | 231 if (pkcs11_id.empty()) { |
221 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; | 232 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; |
222 // So far this error is not expected to happen. We can just continue, in | 233 // So far this error is not expected to happen. We can just continue, in |
(...skipping 26 matching lines...) Expand all Loading... |
249 if (!names.empty()) { | 260 if (!names.empty()) { |
250 base::ReplaceSubstringsAfterOffset( | 261 base::ReplaceSubstringsAfterOffset( |
251 &identity, offset, onc::substitutes::kCertSANUPN, names[0]); | 262 &identity, offset, onc::substitutes::kCertSANUPN, names[0]); |
252 } | 263 } |
253 } | 264 } |
254 } | 265 } |
255 matches->push_back(ClientCertResolver::NetworkAndMatchingCert( | 266 matches->push_back(ClientCertResolver::NetworkAndMatchingCert( |
256 it->service_path, it->cert_config.location, pkcs11_id, slot_id, | 267 it->service_path, it->cert_config.location, pkcs11_id, slot_id, |
257 identity)); | 268 identity)); |
258 } | 269 } |
| 270 return matches; |
259 } | 271 } |
260 | 272 |
261 void LogError(const std::string& service_path, | 273 void LogError(const std::string& service_path, |
262 const std::string& dbus_error_name, | 274 const std::string& dbus_error_name, |
263 const std::string& dbus_error_message) { | 275 const std::string& dbus_error_message) { |
264 network_handler::ShillErrorCallbackFunction( | 276 network_handler::ShillErrorCallbackFunction( |
265 "ClientCertResolver.SetProperties failed", | 277 "ClientCertResolver.SetProperties failed", |
266 service_path, | 278 service_path, |
267 network_handler::ErrorCallback(), | 279 network_handler::ErrorCallback(), |
268 dbus_error_name, | 280 dbus_error_name, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 observers_.RemoveObserver(observer); | 330 observers_.RemoveObserver(observer); |
319 } | 331 } |
320 | 332 |
321 bool ClientCertResolver::IsAnyResolveTaskRunning() const { | 333 bool ClientCertResolver::IsAnyResolveTaskRunning() const { |
322 return resolve_task_running_; | 334 return resolve_task_running_; |
323 } | 335 } |
324 | 336 |
325 // static | 337 // static |
326 bool ClientCertResolver::ResolveCertificatePatternSync( | 338 bool ClientCertResolver::ResolveCertificatePatternSync( |
327 const client_cert::ConfigType client_cert_type, | 339 const client_cert::ConfigType client_cert_type, |
328 const CertificatePattern& pattern, | 340 const client_cert::ClientCertConfig& client_cert_config, |
329 base::DictionaryValue* shill_properties) { | 341 base::DictionaryValue* shill_properties) { |
330 // Prepare and sort the list of known client certs. | 342 // Prepare and sort the list of known client certs. Use only certs from the |
331 std::vector<CertAndIssuer> client_certs(CreateSortedCertAndIssuerList( | 343 // system token if the source of the client cert pattern is device policy. |
332 CertLoader::Get()->cert_list(), base::Time::Now())); | 344 std::vector<CertAndIssuer> client_certs; |
| 345 if (client_cert_config.onc_source == ::onc::ONC_SOURCE_DEVICE_POLICY) { |
| 346 client_certs = CreateSortedCertAndIssuerList( |
| 347 CertLoader::Get()->system_certs(), base::Time::Now()); |
| 348 } else { |
| 349 client_certs = CreateSortedCertAndIssuerList(CertLoader::Get()->all_certs(), |
| 350 base::Time::Now()); |
| 351 } |
333 | 352 |
334 // Search for a certificate matching the pattern. | 353 // Search for a certificate matching the pattern. |
335 std::vector<CertAndIssuer>::iterator cert_it = std::find_if( | 354 std::vector<CertAndIssuer>::iterator cert_it = |
336 client_certs.begin(), client_certs.end(), MatchCertWithPattern(pattern)); | 355 std::find_if(client_certs.begin(), client_certs.end(), |
| 356 MatchCertWithPattern(client_cert_config.pattern)); |
337 | 357 |
338 if (cert_it == client_certs.end()) { | 358 if (cert_it == client_certs.end()) { |
339 VLOG(1) << "Couldn't find a matching client cert"; | 359 VLOG(1) << "Couldn't find a matching client cert"; |
340 client_cert::SetEmptyShillProperties(client_cert_type, shill_properties); | 360 client_cert::SetEmptyShillProperties(client_cert_type, shill_properties); |
341 return false; | 361 return false; |
342 } | 362 } |
343 | 363 |
344 int slot_id = -1; | 364 int slot_id = -1; |
345 std::string pkcs11_id = | 365 std::string pkcs11_id = |
346 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); | 366 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
445 networks.begin(); it != networks.end(); ++it) { | 465 networks.begin(); it != networks.end(); ++it) { |
446 const NetworkState* network = *it; | 466 const NetworkState* network = *it; |
447 | 467 |
448 // In any case, don't check this network again in NetworkListChanged. | 468 // In any case, don't check this network again in NetworkListChanged. |
449 resolved_networks_.insert(network->path()); | 469 resolved_networks_.insert(network->path()); |
450 | 470 |
451 // If this network is not configured, it cannot have a ClientCertPattern. | 471 // If this network is not configured, it cannot have a ClientCertPattern. |
452 if (network->profile_path().empty()) | 472 if (network->profile_path().empty()) |
453 continue; | 473 continue; |
454 | 474 |
| 475 onc::ONCSource onc_source = onc::ONC_SOURCE_NONE; |
455 const base::DictionaryValue* policy = | 476 const base::DictionaryValue* policy = |
456 managed_network_config_handler_->FindPolicyByGuidAndProfile( | 477 managed_network_config_handler_->FindPolicyByGuidAndProfile( |
457 network->guid(), network->profile_path()); | 478 network->guid(), network->profile_path(), &onc_source); |
458 | 479 |
459 if (!policy) { | 480 if (!policy) { |
460 VLOG(1) << "The policy for network " << network->path() << " with GUID " | 481 VLOG(1) << "The policy for network " << network->path() << " with GUID " |
461 << network->guid() << " is not available yet."; | 482 << network->guid() << " is not available yet."; |
462 // Skip this network for now. Once the policy is loaded, PolicyApplied() | 483 // Skip this network for now. Once the policy is loaded, PolicyApplied() |
463 // will retry. | 484 // will retry. |
464 continue; | 485 continue; |
465 } | 486 } |
466 | 487 |
467 VLOG(2) << "Inspecting network " << network->path(); | 488 VLOG(2) << "Inspecting network " << network->path(); |
468 client_cert::ClientCertConfig cert_config; | 489 client_cert::ClientCertConfig cert_config; |
469 OncToClientCertConfig(*policy, &cert_config); | 490 OncToClientCertConfig(onc_source, *policy, &cert_config); |
470 | 491 |
471 // Skip networks that don't have a ClientCertPattern. | 492 // Skip networks that don't have a ClientCertPattern. |
472 if (cert_config.client_cert_type != ::onc::client_cert::kPattern) | 493 if (cert_config.client_cert_type != ::onc::client_cert::kPattern) |
473 continue; | 494 continue; |
474 | 495 |
475 networks_to_resolve->push_back( | 496 networks_to_resolve->push_back( |
476 NetworkAndCertPattern(network->path(), cert_config)); | 497 NetworkAndCertPattern(network->path(), cert_config)); |
477 } | 498 } |
478 | 499 |
479 if (networks_to_resolve->empty()) { | 500 if (networks_to_resolve->empty()) { |
480 VLOG(1) << "No networks to resolve."; | 501 VLOG(1) << "No networks to resolve."; |
481 NotifyResolveRequestCompleted(); | 502 NotifyResolveRequestCompleted(); |
482 return; | 503 return; |
483 } | 504 } |
484 | 505 |
485 if (resolve_task_running_) { | 506 if (resolve_task_running_) { |
486 VLOG(1) << "A resolve task is already running. Queue this request."; | 507 VLOG(1) << "A resolve task is already running. Queue this request."; |
487 for (const NetworkAndCertPattern& network_and_pattern : | 508 for (const NetworkAndCertPattern& network_and_pattern : |
488 *networks_to_resolve) { | 509 *networks_to_resolve) { |
489 queued_networks_to_resolve_.insert(network_and_pattern.service_path); | 510 queued_networks_to_resolve_.insert(network_and_pattern.service_path); |
490 } | 511 } |
491 return; | 512 return; |
492 } | 513 } |
493 | 514 |
494 VLOG(2) << "Start task for resolving client cert patterns."; | 515 VLOG(2) << "Start task for resolving client cert patterns."; |
495 resolve_task_running_ = true; | 516 resolve_task_running_ = true; |
496 NetworkCertMatches* matches = new NetworkCertMatches; | 517 base::PostTaskWithTraitsAndReplyWithResult( |
497 base::PostTaskWithTraitsAndReply( | 518 FROM_HERE, |
498 FROM_HERE, base::TaskTraits() | 519 base::TaskTraits() |
499 .WithShutdownBehavior( | 520 .WithShutdownBehavior( |
500 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) | 521 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) |
501 .MayBlock(), | 522 .MayBlock(), |
502 base::Bind(&FindCertificateMatches, CertLoader::Get()->cert_list(), | 523 base::Bind(&FindCertificateMatches, CertLoader::Get()->all_certs(), |
503 base::Owned(networks_to_resolve.release()), Now(), matches), | 524 CertLoader::Get()->system_certs(), |
| 525 base::Owned(networks_to_resolve.release()), Now()), |
504 base::Bind(&ClientCertResolver::ConfigureCertificates, | 526 base::Bind(&ClientCertResolver::ConfigureCertificates, |
505 weak_ptr_factory_.GetWeakPtr(), base::Owned(matches))); | 527 weak_ptr_factory_.GetWeakPtr())); |
506 } | 528 } |
507 | 529 |
508 void ClientCertResolver::ResolvePendingNetworks() { | 530 void ClientCertResolver::ResolvePendingNetworks() { |
509 NetworkStateHandler::NetworkStateList networks; | 531 NetworkStateHandler::NetworkStateList networks; |
510 network_state_handler_->GetNetworkListByType(NetworkTypePattern::Default(), | 532 network_state_handler_->GetNetworkListByType(NetworkTypePattern::Default(), |
511 true /* configured_only */, | 533 true /* configured_only */, |
512 false /* visible_only */, | 534 false /* visible_only */, |
513 0 /* no limit */, | 535 0 /* no limit */, |
514 &networks); | 536 &networks); |
515 | 537 |
516 NetworkStateHandler::NetworkStateList networks_to_resolve; | 538 NetworkStateHandler::NetworkStateList networks_to_resolve; |
517 for (const NetworkState* network : networks) { | 539 for (const NetworkState* network : networks) { |
518 if (queued_networks_to_resolve_.count(network->path()) > 0) | 540 if (queued_networks_to_resolve_.count(network->path()) > 0) |
519 networks_to_resolve.push_back(network); | 541 networks_to_resolve.push_back(network); |
520 } | 542 } |
521 VLOG(1) << "Resolve pending " << networks_to_resolve.size() << " networks."; | 543 VLOG(1) << "Resolve pending " << networks_to_resolve.size() << " networks."; |
522 queued_networks_to_resolve_.clear(); | 544 queued_networks_to_resolve_.clear(); |
523 ResolveNetworks(networks_to_resolve); | 545 ResolveNetworks(networks_to_resolve); |
524 } | 546 } |
525 | 547 |
526 void ClientCertResolver::ConfigureCertificates(NetworkCertMatches* matches) { | 548 void ClientCertResolver::ConfigureCertificates( |
| 549 std::unique_ptr<NetworkCertMatches> matches) { |
527 for (NetworkCertMatches::const_iterator it = matches->begin(); | 550 for (NetworkCertMatches::const_iterator it = matches->begin(); |
528 it != matches->end(); ++it) { | 551 it != matches->end(); ++it) { |
529 VLOG(1) << "Configuring certificate of network " << it->service_path; | 552 VLOG(1) << "Configuring certificate of network " << it->service_path; |
530 base::DictionaryValue shill_properties; | 553 base::DictionaryValue shill_properties; |
531 if (it->pkcs11_id.empty()) { | 554 if (it->pkcs11_id.empty()) { |
532 client_cert::SetEmptyShillProperties(it->cert_config_type, | 555 client_cert::SetEmptyShillProperties(it->cert_config_type, |
533 &shill_properties); | 556 &shill_properties); |
534 } else { | 557 } else { |
535 client_cert::SetShillProperties(it->cert_config_type, | 558 client_cert::SetShillProperties(it->cert_config_type, |
536 it->key_slot_id, | 559 it->key_slot_id, |
(...skipping 28 matching lines...) Expand all Loading... |
565 observer.ResolveRequestCompleted(changed); | 588 observer.ResolveRequestCompleted(changed); |
566 } | 589 } |
567 | 590 |
568 base::Time ClientCertResolver::Now() const { | 591 base::Time ClientCertResolver::Now() const { |
569 if (testing_clock_) | 592 if (testing_clock_) |
570 return testing_clock_->Now(); | 593 return testing_clock_->Now(); |
571 return base::Time::Now(); | 594 return base::Time::Now(); |
572 } | 595 } |
573 | 596 |
574 } // namespace chromeos | 597 } // namespace chromeos |
OLD | NEW |