| 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/stl_util.h" | 16 #include "base/stl_util.h" |
| 17 #include "base/task_runner.h" | 17 #include "base/task_runner.h" |
| 18 #include "base/threading/worker_pool.h" | 18 #include "base/threading/worker_pool.h" |
| 19 #include "base/time/clock.h" |
| 19 #include "chromeos/dbus/dbus_thread_manager.h" | 20 #include "chromeos/dbus/dbus_thread_manager.h" |
| 20 #include "chromeos/dbus/shill_service_client.h" | 21 #include "chromeos/dbus/shill_service_client.h" |
| 21 #include "chromeos/network/managed_network_configuration_handler.h" | 22 #include "chromeos/network/managed_network_configuration_handler.h" |
| 22 #include "chromeos/network/network_state.h" | 23 #include "chromeos/network/network_state.h" |
| 23 #include "components/onc/onc_constants.h" | 24 #include "components/onc/onc_constants.h" |
| 24 #include "dbus/object_path.h" | 25 #include "dbus/object_path.h" |
| 25 #include "net/cert/scoped_nss_types.h" | 26 #include "net/cert/scoped_nss_types.h" |
| 26 #include "net/cert/x509_certificate.h" | 27 #include "net/cert/x509_certificate.h" |
| 27 | 28 |
| 28 namespace chromeos { | 29 namespace chromeos { |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 std::string pem_encoded_issuer; | 150 std::string pem_encoded_issuer; |
| 150 if (!net::X509Certificate::GetPEMEncoded(issuer->os_cert_handle(), | 151 if (!net::X509Certificate::GetPEMEncoded(issuer->os_cert_handle(), |
| 151 &pem_encoded_issuer)) { | 152 &pem_encoded_issuer)) { |
| 152 LOG(ERROR) << "Couldn't PEM-encode certificate."; | 153 LOG(ERROR) << "Couldn't PEM-encode certificate."; |
| 153 return std::string(); | 154 return std::string(); |
| 154 } | 155 } |
| 155 return pem_encoded_issuer; | 156 return pem_encoded_issuer; |
| 156 } | 157 } |
| 157 | 158 |
| 158 std::vector<CertAndIssuer> CreateSortedCertAndIssuerList( | 159 std::vector<CertAndIssuer> CreateSortedCertAndIssuerList( |
| 159 const net::CertificateList& certs) { | 160 const net::CertificateList& certs, |
| 161 base::Time now) { |
| 160 // Filter all client certs and determines each certificate's issuer, which is | 162 // Filter all client certs and determines each certificate's issuer, which is |
| 161 // required for the pattern matching. | 163 // required for the pattern matching. |
| 162 std::vector<CertAndIssuer> client_certs; | 164 std::vector<CertAndIssuer> client_certs; |
| 163 for (net::CertificateList::const_iterator it = certs.begin(); | 165 for (net::CertificateList::const_iterator it = certs.begin(); |
| 164 it != certs.end(); ++it) { | 166 it != certs.end(); ++it) { |
| 165 const net::X509Certificate& cert = **it; | 167 const net::X509Certificate& cert = **it; |
| 166 if (cert.valid_expiry().is_null() || cert.HasExpired() || | 168 if (cert.valid_expiry().is_null() || now > cert.valid_expiry() || |
| 167 !HasPrivateKey(cert) || | 169 !HasPrivateKey(cert) || |
| 168 !CertLoader::IsCertificateHardwareBacked(&cert)) { | 170 !CertLoader::IsCertificateHardwareBacked(&cert)) { |
| 169 continue; | 171 continue; |
| 170 } | 172 } |
| 171 client_certs.push_back(CertAndIssuer(*it, GetPEMEncodedIssuer(cert))); | 173 client_certs.push_back(CertAndIssuer(*it, GetPEMEncodedIssuer(cert))); |
| 172 } | 174 } |
| 173 | 175 |
| 174 std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration); | 176 std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration); |
| 175 return client_certs; | 177 return client_certs; |
| 176 } | 178 } |
| 177 | 179 |
| 178 // Searches for matches between |networks| and |certs| and writes matches to | 180 // Searches for matches between |networks| and |certs| and writes matches to |
| 179 // |matches|. Because this calls NSS functions and is potentially slow, it must | 181 // |matches|. Because this calls NSS functions and is potentially slow, it must |
| 180 // be run on a worker thread. | 182 // be run on a worker thread. |
| 181 void FindCertificateMatches(const net::CertificateList& certs, | 183 void FindCertificateMatches(const net::CertificateList& certs, |
| 182 std::vector<NetworkAndCertPattern>* networks, | 184 std::vector<NetworkAndCertPattern>* networks, |
| 185 base::Time now, |
| 183 NetworkCertMatches* matches) { | 186 NetworkCertMatches* matches) { |
| 184 std::vector<CertAndIssuer> client_certs(CreateSortedCertAndIssuerList(certs)); | 187 std::vector<CertAndIssuer> client_certs( |
| 188 CreateSortedCertAndIssuerList(certs, now)); |
| 185 | 189 |
| 186 for (std::vector<NetworkAndCertPattern>::const_iterator it = | 190 for (std::vector<NetworkAndCertPattern>::const_iterator it = |
| 187 networks->begin(); | 191 networks->begin(); |
| 188 it != networks->end(); ++it) { | 192 it != networks->end(); ++it) { |
| 189 std::vector<CertAndIssuer>::iterator cert_it = | 193 std::vector<CertAndIssuer>::iterator cert_it = |
| 190 std::find_if(client_certs.begin(), | 194 std::find_if(client_certs.begin(), |
| 191 client_certs.end(), | 195 client_certs.end(), |
| 192 MatchCertWithPattern(it->cert_config.pattern)); | 196 MatchCertWithPattern(it->cert_config.pattern)); |
| 193 std::string pkcs11_id; | 197 std::string pkcs11_id; |
| 194 int slot_id = -1; | 198 int slot_id = -1; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 bool ClientCertResolver::IsAnyResolveTaskRunning() const { | 284 bool ClientCertResolver::IsAnyResolveTaskRunning() const { |
| 281 return resolve_task_running_; | 285 return resolve_task_running_; |
| 282 } | 286 } |
| 283 | 287 |
| 284 // static | 288 // static |
| 285 bool ClientCertResolver::ResolveCertificatePatternSync( | 289 bool ClientCertResolver::ResolveCertificatePatternSync( |
| 286 const client_cert::ConfigType client_cert_type, | 290 const client_cert::ConfigType client_cert_type, |
| 287 const CertificatePattern& pattern, | 291 const CertificatePattern& pattern, |
| 288 base::DictionaryValue* shill_properties) { | 292 base::DictionaryValue* shill_properties) { |
| 289 // Prepare and sort the list of known client certs. | 293 // Prepare and sort the list of known client certs. |
| 290 std::vector<CertAndIssuer> client_certs( | 294 std::vector<CertAndIssuer> client_certs(CreateSortedCertAndIssuerList( |
| 291 CreateSortedCertAndIssuerList(CertLoader::Get()->cert_list())); | 295 CertLoader::Get()->cert_list(), base::Time::Now())); |
| 292 | 296 |
| 293 // Search for a certificate matching the pattern. | 297 // Search for a certificate matching the pattern. |
| 294 std::vector<CertAndIssuer>::iterator cert_it = std::find_if( | 298 std::vector<CertAndIssuer>::iterator cert_it = std::find_if( |
| 295 client_certs.begin(), client_certs.end(), MatchCertWithPattern(pattern)); | 299 client_certs.begin(), client_certs.end(), MatchCertWithPattern(pattern)); |
| 296 | 300 |
| 297 if (cert_it == client_certs.end()) { | 301 if (cert_it == client_certs.end()) { |
| 298 VLOG(1) << "Couldn't find a matching client cert"; | 302 VLOG(1) << "Couldn't find a matching client cert"; |
| 299 client_cert::SetEmptyShillProperties(client_cert_type, shill_properties); | 303 client_cert::SetEmptyShillProperties(client_cert_type, shill_properties); |
| 300 return false; | 304 return false; |
| 301 } | 305 } |
| 302 | 306 |
| 303 int slot_id = -1; | 307 int slot_id = -1; |
| 304 std::string pkcs11_id = | 308 std::string pkcs11_id = |
| 305 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); | 309 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); |
| 306 if (pkcs11_id.empty()) { | 310 if (pkcs11_id.empty()) { |
| 307 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; | 311 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; |
| 308 // So far this error is not expected to happen. We can just continue, in | 312 // So far this error is not expected to happen. We can just continue, in |
| 309 // the worst case the user can remove the problematic cert. | 313 // the worst case the user can remove the problematic cert. |
| 310 return false; | 314 return false; |
| 311 } | 315 } |
| 312 client_cert::SetShillProperties( | 316 client_cert::SetShillProperties( |
| 313 client_cert_type, slot_id, pkcs11_id, shill_properties); | 317 client_cert_type, slot_id, pkcs11_id, shill_properties); |
| 314 return true; | 318 return true; |
| 315 } | 319 } |
| 316 | 320 |
| 321 void ClientCertResolver::SetClockForTesting(scoped_ptr<base::Clock> clock) { |
| 322 testing_clock_ = clock.Pass(); |
| 323 } |
| 324 |
| 317 void ClientCertResolver::NetworkListChanged() { | 325 void ClientCertResolver::NetworkListChanged() { |
| 318 VLOG(2) << "NetworkListChanged."; | 326 VLOG(2) << "NetworkListChanged."; |
| 319 if (!ClientCertificatesLoaded()) | 327 if (!ClientCertificatesLoaded()) |
| 320 return; | 328 return; |
| 321 // Configure only networks that were not configured before. | 329 // Configure only networks that were not configured before. |
| 322 | 330 |
| 323 // We'll drop networks from |resolved_networks_|, which are not known anymore. | 331 // We'll drop networks from |resolved_networks_|, which are not known anymore. |
| 324 std::set<std::string> old_resolved_networks; | 332 std::set<std::string> old_resolved_networks; |
| 325 old_resolved_networks.swap(resolved_networks_); | 333 old_resolved_networks.swap(resolved_networks_); |
| 326 | 334 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 339 if (ContainsKey(old_resolved_networks, service_path)) { | 347 if (ContainsKey(old_resolved_networks, service_path)) { |
| 340 resolved_networks_.insert(service_path); | 348 resolved_networks_.insert(service_path); |
| 341 continue; | 349 continue; |
| 342 } | 350 } |
| 343 networks_to_check.push_back(*it); | 351 networks_to_check.push_back(*it); |
| 344 } | 352 } |
| 345 | 353 |
| 346 ResolveNetworks(networks_to_check); | 354 ResolveNetworks(networks_to_check); |
| 347 } | 355 } |
| 348 | 356 |
| 357 void ClientCertResolver::NetworkConnectionStateChanged( |
| 358 const NetworkState* network) { |
| 359 if (!ClientCertificatesLoaded()) |
| 360 return; |
| 361 if (!network->IsConnectedState() && !network->IsConnectingState()) |
| 362 ResolveNetworks(NetworkStateHandler::NetworkStateList(1, network)); |
| 363 } |
| 364 |
| 349 void ClientCertResolver::OnCertificatesLoaded( | 365 void ClientCertResolver::OnCertificatesLoaded( |
| 350 const net::CertificateList& cert_list, | 366 const net::CertificateList& cert_list, |
| 351 bool initial_load) { | 367 bool initial_load) { |
| 352 VLOG(2) << "OnCertificatesLoaded."; | 368 VLOG(2) << "OnCertificatesLoaded."; |
| 353 if (!ClientCertificatesLoaded()) | 369 if (!ClientCertificatesLoaded()) |
| 354 return; | 370 return; |
| 355 // Compare all networks with all certificates. | 371 // Compare all networks with all certificates. |
| 356 NetworkStateHandler::NetworkStateList networks; | 372 NetworkStateHandler::NetworkStateList networks; |
| 357 network_state_handler_->GetNetworkListByType( | 373 network_state_handler_->GetNetworkListByType( |
| 358 NetworkTypePattern::Default(), | 374 NetworkTypePattern::Default(), |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 VLOG(2) << "Start task for resolving client cert patterns."; | 457 VLOG(2) << "Start task for resolving client cert patterns."; |
| 442 base::TaskRunner* task_runner = slow_task_runner_for_test_.get(); | 458 base::TaskRunner* task_runner = slow_task_runner_for_test_.get(); |
| 443 if (!task_runner) | 459 if (!task_runner) |
| 444 task_runner = | 460 task_runner = |
| 445 base::WorkerPool::GetTaskRunner(true /* task is slow */).get(); | 461 base::WorkerPool::GetTaskRunner(true /* task is slow */).get(); |
| 446 | 462 |
| 447 resolve_task_running_ = true; | 463 resolve_task_running_ = true; |
| 448 NetworkCertMatches* matches = new NetworkCertMatches; | 464 NetworkCertMatches* matches = new NetworkCertMatches; |
| 449 task_runner->PostTaskAndReply( | 465 task_runner->PostTaskAndReply( |
| 450 FROM_HERE, | 466 FROM_HERE, |
| 451 base::Bind(&FindCertificateMatches, | 467 base::Bind(&FindCertificateMatches, CertLoader::Get()->cert_list(), |
| 452 CertLoader::Get()->cert_list(), | 468 base::Owned(networks_to_resolve.release()), Now(), matches), |
| 453 base::Owned(networks_to_resolve.release()), | |
| 454 matches), | |
| 455 base::Bind(&ClientCertResolver::ConfigureCertificates, | 469 base::Bind(&ClientCertResolver::ConfigureCertificates, |
| 456 weak_ptr_factory_.GetWeakPtr(), | 470 weak_ptr_factory_.GetWeakPtr(), base::Owned(matches))); |
| 457 base::Owned(matches))); | |
| 458 } | 471 } |
| 459 | 472 |
| 460 void ClientCertResolver::ResolvePendingNetworks() { | 473 void ClientCertResolver::ResolvePendingNetworks() { |
| 461 NetworkStateHandler::NetworkStateList networks; | 474 NetworkStateHandler::NetworkStateList networks; |
| 462 network_state_handler_->GetNetworkListByType(NetworkTypePattern::Default(), | 475 network_state_handler_->GetNetworkListByType(NetworkTypePattern::Default(), |
| 463 true /* configured_only */, | 476 true /* configured_only */, |
| 464 false /* visible_only */, | 477 false /* visible_only */, |
| 465 0 /* no limit */, | 478 0 /* no limit */, |
| 466 &networks); | 479 &networks); |
| 467 | 480 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 | 518 |
| 506 void ClientCertResolver::NotifyResolveRequestCompleted() { | 519 void ClientCertResolver::NotifyResolveRequestCompleted() { |
| 507 VLOG(2) << "Notify observers: " << (network_properties_changed_ ? "" : "no ") | 520 VLOG(2) << "Notify observers: " << (network_properties_changed_ ? "" : "no ") |
| 508 << "networks changed."; | 521 << "networks changed."; |
| 509 resolve_task_running_ = false; | 522 resolve_task_running_ = false; |
| 510 const bool changed = network_properties_changed_; | 523 const bool changed = network_properties_changed_; |
| 511 network_properties_changed_ = false; | 524 network_properties_changed_ = false; |
| 512 FOR_EACH_OBSERVER(Observer, observers_, ResolveRequestCompleted(changed)); | 525 FOR_EACH_OBSERVER(Observer, observers_, ResolveRequestCompleted(changed)); |
| 513 } | 526 } |
| 514 | 527 |
| 528 base::Time ClientCertResolver::Now() const { |
| 529 if (testing_clock_) |
| 530 return testing_clock_->Now(); |
| 531 return base::Time::Now(); |
| 532 } |
| 533 |
| 515 } // namespace chromeos | 534 } // namespace chromeos |
| OLD | NEW |