| 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 26 matching lines...) Expand all Loading... |
| 55 namespace { | 56 namespace { |
| 56 | 57 |
| 57 // Returns true if |vector| contains |value|. | 58 // Returns true if |vector| contains |value|. |
| 58 template <class T> | 59 template <class T> |
| 59 bool ContainsValue(const std::vector<T>& vector, const T& value) { | 60 bool ContainsValue(const std::vector<T>& vector, const T& value) { |
| 60 return find(vector.begin(), vector.end(), value) != vector.end(); | 61 return find(vector.begin(), vector.end(), value) != vector.end(); |
| 61 } | 62 } |
| 62 | 63 |
| 63 // Returns true if a private key for certificate |cert| is installed. | 64 // Returns true if a private key for certificate |cert| is installed. |
| 64 bool HasPrivateKey(const net::X509Certificate& cert) { | 65 bool HasPrivateKey(const net::X509Certificate& cert) { |
| 65 PK11SlotInfo* slot = PK11_KeyForCertExists(cert.os_cert_handle(), NULL, NULL); | 66 PK11SlotInfo* slot = |
| 67 PK11_KeyForCertExists(cert.os_cert_handle(), nullptr, nullptr); |
| 66 if (!slot) | 68 if (!slot) |
| 67 return false; | 69 return false; |
| 68 | 70 |
| 69 PK11_FreeSlot(slot); | 71 PK11_FreeSlot(slot); |
| 70 return true; | 72 return true; |
| 71 } | 73 } |
| 72 | 74 |
| 73 // Describes a certificate which is issued by |issuer| (encoded as PEM). | 75 // Describes a certificate which is issued by |issuer| (encoded as PEM). |
| 74 // |issuer| can be empty if no issuer certificate is found in the database. | 76 // |issuer| can be empty if no issuer certificate is found in the database. |
| 75 struct CertAndIssuer { | 77 struct CertAndIssuer { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 std::string pem_encoded_issuer; | 151 std::string pem_encoded_issuer; |
| 150 if (!net::X509Certificate::GetPEMEncoded(issuer->os_cert_handle(), | 152 if (!net::X509Certificate::GetPEMEncoded(issuer->os_cert_handle(), |
| 151 &pem_encoded_issuer)) { | 153 &pem_encoded_issuer)) { |
| 152 LOG(ERROR) << "Couldn't PEM-encode certificate."; | 154 LOG(ERROR) << "Couldn't PEM-encode certificate."; |
| 153 return std::string(); | 155 return std::string(); |
| 154 } | 156 } |
| 155 return pem_encoded_issuer; | 157 return pem_encoded_issuer; |
| 156 } | 158 } |
| 157 | 159 |
| 158 std::vector<CertAndIssuer> CreateSortedCertAndIssuerList( | 160 std::vector<CertAndIssuer> CreateSortedCertAndIssuerList( |
| 159 const net::CertificateList& certs) { | 161 const net::CertificateList& certs, |
| 162 base::Time now) { |
| 160 // Filter all client certs and determines each certificate's issuer, which is | 163 // Filter all client certs and determines each certificate's issuer, which is |
| 161 // required for the pattern matching. | 164 // required for the pattern matching. |
| 162 std::vector<CertAndIssuer> client_certs; | 165 std::vector<CertAndIssuer> client_certs; |
| 163 for (net::CertificateList::const_iterator it = certs.begin(); | 166 for (net::CertificateList::const_iterator it = certs.begin(); |
| 164 it != certs.end(); ++it) { | 167 it != certs.end(); ++it) { |
| 165 const net::X509Certificate& cert = **it; | 168 const net::X509Certificate& cert = **it; |
| 166 if (cert.valid_expiry().is_null() || cert.HasExpired() || | 169 if (cert.valid_expiry().is_null() || now > cert.valid_expiry() || |
| 167 !HasPrivateKey(cert) || | 170 !HasPrivateKey(cert) || |
| 168 !CertLoader::IsCertificateHardwareBacked(&cert)) { | 171 !CertLoader::IsCertificateHardwareBacked(&cert)) { |
| 169 continue; | 172 continue; |
| 170 } | 173 } |
| 171 client_certs.push_back(CertAndIssuer(*it, GetPEMEncodedIssuer(cert))); | 174 client_certs.push_back(CertAndIssuer(*it, GetPEMEncodedIssuer(cert))); |
| 172 } | 175 } |
| 173 | 176 |
| 174 std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration); | 177 std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration); |
| 175 return client_certs; | 178 return client_certs; |
| 176 } | 179 } |
| 177 | 180 |
| 178 // Searches for matches between |networks| and |certs| and writes matches to | 181 // Searches for matches between |networks| and |certs| and writes matches to |
| 179 // |matches|. Because this calls NSS functions and is potentially slow, it must | 182 // |matches|. Because this calls NSS functions and is potentially slow, it must |
| 180 // be run on a worker thread. | 183 // be run on a worker thread. |
| 181 void FindCertificateMatches(const net::CertificateList& certs, | 184 void FindCertificateMatches(const net::CertificateList& certs, |
| 182 std::vector<NetworkAndCertPattern>* networks, | 185 std::vector<NetworkAndCertPattern>* networks, |
| 186 base::Time now, |
| 183 NetworkCertMatches* matches) { | 187 NetworkCertMatches* matches) { |
| 184 std::vector<CertAndIssuer> client_certs(CreateSortedCertAndIssuerList(certs)); | 188 std::vector<CertAndIssuer> client_certs( |
| 189 CreateSortedCertAndIssuerList(certs, now)); |
| 185 | 190 |
| 186 for (std::vector<NetworkAndCertPattern>::const_iterator it = | 191 for (std::vector<NetworkAndCertPattern>::const_iterator it = |
| 187 networks->begin(); | 192 networks->begin(); |
| 188 it != networks->end(); ++it) { | 193 it != networks->end(); ++it) { |
| 189 std::vector<CertAndIssuer>::iterator cert_it = | 194 std::vector<CertAndIssuer>::iterator cert_it = |
| 190 std::find_if(client_certs.begin(), | 195 std::find_if(client_certs.begin(), |
| 191 client_certs.end(), | 196 client_certs.end(), |
| 192 MatchCertWithPattern(it->cert_config.pattern)); | 197 MatchCertWithPattern(it->cert_config.pattern)); |
| 193 std::string pkcs11_id; | 198 std::string pkcs11_id; |
| 194 int slot_id = -1; | 199 int slot_id = -1; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 return false; | 234 return false; |
| 230 } | 235 } |
| 231 return true; | 236 return true; |
| 232 } | 237 } |
| 233 | 238 |
| 234 } // namespace | 239 } // namespace |
| 235 | 240 |
| 236 ClientCertResolver::ClientCertResolver() | 241 ClientCertResolver::ClientCertResolver() |
| 237 : resolve_task_running_(false), | 242 : resolve_task_running_(false), |
| 238 network_properties_changed_(false), | 243 network_properties_changed_(false), |
| 239 network_state_handler_(NULL), | 244 network_state_handler_(nullptr), |
| 240 managed_network_config_handler_(NULL), | 245 managed_network_config_handler_(nullptr), |
| 241 weak_ptr_factory_(this) { | 246 testing_clock_(nullptr), |
| 242 } | 247 weak_ptr_factory_(this) {} |
| 243 | 248 |
| 244 ClientCertResolver::~ClientCertResolver() { | 249 ClientCertResolver::~ClientCertResolver() { |
| 245 if (network_state_handler_) | 250 if (network_state_handler_) |
| 246 network_state_handler_->RemoveObserver(this, FROM_HERE); | 251 network_state_handler_->RemoveObserver(this, FROM_HERE); |
| 247 if (CertLoader::IsInitialized()) | 252 if (CertLoader::IsInitialized()) |
| 248 CertLoader::Get()->RemoveObserver(this); | 253 CertLoader::Get()->RemoveObserver(this); |
| 249 if (managed_network_config_handler_) | 254 if (managed_network_config_handler_) |
| 250 managed_network_config_handler_->RemoveObserver(this); | 255 managed_network_config_handler_->RemoveObserver(this); |
| 251 } | 256 } |
| 252 | 257 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 280 bool ClientCertResolver::IsAnyResolveTaskRunning() const { | 285 bool ClientCertResolver::IsAnyResolveTaskRunning() const { |
| 281 return resolve_task_running_; | 286 return resolve_task_running_; |
| 282 } | 287 } |
| 283 | 288 |
| 284 // static | 289 // static |
| 285 bool ClientCertResolver::ResolveCertificatePatternSync( | 290 bool ClientCertResolver::ResolveCertificatePatternSync( |
| 286 const client_cert::ConfigType client_cert_type, | 291 const client_cert::ConfigType client_cert_type, |
| 287 const CertificatePattern& pattern, | 292 const CertificatePattern& pattern, |
| 288 base::DictionaryValue* shill_properties) { | 293 base::DictionaryValue* shill_properties) { |
| 289 // Prepare and sort the list of known client certs. | 294 // Prepare and sort the list of known client certs. |
| 290 std::vector<CertAndIssuer> client_certs( | 295 std::vector<CertAndIssuer> client_certs(CreateSortedCertAndIssuerList( |
| 291 CreateSortedCertAndIssuerList(CertLoader::Get()->cert_list())); | 296 CertLoader::Get()->cert_list(), base::Time::Now())); |
| 292 | 297 |
| 293 // Search for a certificate matching the pattern. | 298 // Search for a certificate matching the pattern. |
| 294 std::vector<CertAndIssuer>::iterator cert_it = std::find_if( | 299 std::vector<CertAndIssuer>::iterator cert_it = std::find_if( |
| 295 client_certs.begin(), client_certs.end(), MatchCertWithPattern(pattern)); | 300 client_certs.begin(), client_certs.end(), MatchCertWithPattern(pattern)); |
| 296 | 301 |
| 297 if (cert_it == client_certs.end()) { | 302 if (cert_it == client_certs.end()) { |
| 298 VLOG(1) << "Couldn't find a matching client cert"; | 303 VLOG(1) << "Couldn't find a matching client cert"; |
| 299 client_cert::SetEmptyShillProperties(client_cert_type, shill_properties); | 304 client_cert::SetEmptyShillProperties(client_cert_type, shill_properties); |
| 300 return false; | 305 return false; |
| 301 } | 306 } |
| 302 | 307 |
| 303 int slot_id = -1; | 308 int slot_id = -1; |
| 304 std::string pkcs11_id = | 309 std::string pkcs11_id = |
| 305 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); | 310 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); |
| 306 if (pkcs11_id.empty()) { | 311 if (pkcs11_id.empty()) { |
| 307 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; | 312 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; |
| 308 // So far this error is not expected to happen. We can just continue, in | 313 // 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. | 314 // the worst case the user can remove the problematic cert. |
| 310 return false; | 315 return false; |
| 311 } | 316 } |
| 312 client_cert::SetShillProperties( | 317 client_cert::SetShillProperties( |
| 313 client_cert_type, slot_id, pkcs11_id, shill_properties); | 318 client_cert_type, slot_id, pkcs11_id, shill_properties); |
| 314 return true; | 319 return true; |
| 315 } | 320 } |
| 316 | 321 |
| 322 void ClientCertResolver::SetClockForTesting(base::Clock* clock) { |
| 323 testing_clock_ = clock; |
| 324 } |
| 325 |
| 317 void ClientCertResolver::NetworkListChanged() { | 326 void ClientCertResolver::NetworkListChanged() { |
| 318 VLOG(2) << "NetworkListChanged."; | 327 VLOG(2) << "NetworkListChanged."; |
| 319 if (!ClientCertificatesLoaded()) | 328 if (!ClientCertificatesLoaded()) |
| 320 return; | 329 return; |
| 321 // Configure only networks that were not configured before. | 330 // Configure only networks that were not configured before. |
| 322 | 331 |
| 323 // We'll drop networks from |resolved_networks_|, which are not known anymore. | 332 // We'll drop networks from |resolved_networks_|, which are not known anymore. |
| 324 std::set<std::string> old_resolved_networks; | 333 std::set<std::string> old_resolved_networks; |
| 325 old_resolved_networks.swap(resolved_networks_); | 334 old_resolved_networks.swap(resolved_networks_); |
| 326 | 335 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 339 if (ContainsKey(old_resolved_networks, service_path)) { | 348 if (ContainsKey(old_resolved_networks, service_path)) { |
| 340 resolved_networks_.insert(service_path); | 349 resolved_networks_.insert(service_path); |
| 341 continue; | 350 continue; |
| 342 } | 351 } |
| 343 networks_to_check.push_back(*it); | 352 networks_to_check.push_back(*it); |
| 344 } | 353 } |
| 345 | 354 |
| 346 ResolveNetworks(networks_to_check); | 355 ResolveNetworks(networks_to_check); |
| 347 } | 356 } |
| 348 | 357 |
| 358 void ClientCertResolver::NetworkConnectionStateChanged( |
| 359 const NetworkState* network) { |
| 360 if (!ClientCertificatesLoaded()) |
| 361 return; |
| 362 if (!network->IsConnectedState() && !network->IsConnectingState()) |
| 363 ResolveNetworks(NetworkStateHandler::NetworkStateList(1, network)); |
| 364 } |
| 365 |
| 349 void ClientCertResolver::OnCertificatesLoaded( | 366 void ClientCertResolver::OnCertificatesLoaded( |
| 350 const net::CertificateList& cert_list, | 367 const net::CertificateList& cert_list, |
| 351 bool initial_load) { | 368 bool initial_load) { |
| 352 VLOG(2) << "OnCertificatesLoaded."; | 369 VLOG(2) << "OnCertificatesLoaded."; |
| 353 if (!ClientCertificatesLoaded()) | 370 if (!ClientCertificatesLoaded()) |
| 354 return; | 371 return; |
| 355 // Compare all networks with all certificates. | 372 // Compare all networks with all certificates. |
| 356 NetworkStateHandler::NetworkStateList networks; | 373 NetworkStateHandler::NetworkStateList networks; |
| 357 network_state_handler_->GetNetworkListByType( | 374 network_state_handler_->GetNetworkListByType( |
| 358 NetworkTypePattern::Default(), | 375 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."; | 458 VLOG(2) << "Start task for resolving client cert patterns."; |
| 442 base::TaskRunner* task_runner = slow_task_runner_for_test_.get(); | 459 base::TaskRunner* task_runner = slow_task_runner_for_test_.get(); |
| 443 if (!task_runner) | 460 if (!task_runner) |
| 444 task_runner = | 461 task_runner = |
| 445 base::WorkerPool::GetTaskRunner(true /* task is slow */).get(); | 462 base::WorkerPool::GetTaskRunner(true /* task is slow */).get(); |
| 446 | 463 |
| 447 resolve_task_running_ = true; | 464 resolve_task_running_ = true; |
| 448 NetworkCertMatches* matches = new NetworkCertMatches; | 465 NetworkCertMatches* matches = new NetworkCertMatches; |
| 449 task_runner->PostTaskAndReply( | 466 task_runner->PostTaskAndReply( |
| 450 FROM_HERE, | 467 FROM_HERE, |
| 451 base::Bind(&FindCertificateMatches, | 468 base::Bind(&FindCertificateMatches, CertLoader::Get()->cert_list(), |
| 452 CertLoader::Get()->cert_list(), | 469 base::Owned(networks_to_resolve.release()), Now(), matches), |
| 453 base::Owned(networks_to_resolve.release()), | |
| 454 matches), | |
| 455 base::Bind(&ClientCertResolver::ConfigureCertificates, | 470 base::Bind(&ClientCertResolver::ConfigureCertificates, |
| 456 weak_ptr_factory_.GetWeakPtr(), | 471 weak_ptr_factory_.GetWeakPtr(), base::Owned(matches))); |
| 457 base::Owned(matches))); | |
| 458 } | 472 } |
| 459 | 473 |
| 460 void ClientCertResolver::ResolvePendingNetworks() { | 474 void ClientCertResolver::ResolvePendingNetworks() { |
| 461 NetworkStateHandler::NetworkStateList networks; | 475 NetworkStateHandler::NetworkStateList networks; |
| 462 network_state_handler_->GetNetworkListByType(NetworkTypePattern::Default(), | 476 network_state_handler_->GetNetworkListByType(NetworkTypePattern::Default(), |
| 463 true /* configured_only */, | 477 true /* configured_only */, |
| 464 false /* visible_only */, | 478 false /* visible_only */, |
| 465 0 /* no limit */, | 479 0 /* no limit */, |
| 466 &networks); | 480 &networks); |
| 467 | 481 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 | 519 |
| 506 void ClientCertResolver::NotifyResolveRequestCompleted() { | 520 void ClientCertResolver::NotifyResolveRequestCompleted() { |
| 507 VLOG(2) << "Notify observers: " << (network_properties_changed_ ? "" : "no ") | 521 VLOG(2) << "Notify observers: " << (network_properties_changed_ ? "" : "no ") |
| 508 << "networks changed."; | 522 << "networks changed."; |
| 509 resolve_task_running_ = false; | 523 resolve_task_running_ = false; |
| 510 const bool changed = network_properties_changed_; | 524 const bool changed = network_properties_changed_; |
| 511 network_properties_changed_ = false; | 525 network_properties_changed_ = false; |
| 512 FOR_EACH_OBSERVER(Observer, observers_, ResolveRequestCompleted(changed)); | 526 FOR_EACH_OBSERVER(Observer, observers_, ResolveRequestCompleted(changed)); |
| 513 } | 527 } |
| 514 | 528 |
| 529 base::Time ClientCertResolver::Now() const { |
| 530 if (testing_clock_) |
| 531 return testing_clock_->Now(); |
| 532 return base::Time::Now(); |
| 533 } |
| 534 |
| 515 } // namespace chromeos | 535 } // namespace chromeos |
| OLD | NEW |