Index: chromeos/network/network_cert_migrator.cc |
diff --git a/chromeos/network/network_cert_migrator.cc b/chromeos/network/network_cert_migrator.cc |
index 29a34102af96e0dd95e59c27a6dbe3935abe6d8f..31f476aef6f85cb729173a54c0f4b3013363b550 100644 |
--- a/chromeos/network/network_cert_migrator.cc |
+++ b/chromeos/network/network_cert_migrator.cc |
@@ -12,6 +12,7 @@ |
#include "base/metrics/histogram.h" |
#include "chromeos/dbus/dbus_thread_manager.h" |
#include "chromeos/dbus/shill_service_client.h" |
+#include "chromeos/network/client_cert_util.h" |
#include "chromeos/network/network_handler_callbacks.h" |
#include "chromeos/network/network_state.h" |
#include "chromeos/network/network_state_handler.h" |
@@ -44,12 +45,23 @@ std::string GetNickname(const net::X509Certificate& cert) { |
} // namespace |
-// Checks which of the given |networks| has one of the deprecated |
-// CaCertNssProperties set. If such a network already has a CaCertPEM property, |
-// then the NssProperty is cleared. Otherwise, the NssProperty is compared with |
-// the nickname of each certificate of |certs|. If a match is found, then the |
-// CaCertPemProperty is set and the NssProperty is cleared. Otherwise, the |
-// network is not modified. |
+// Migrates each network of |networks| with a deprecated CaCertNss property to |
+// the respective CaCertPEM property and fixes an invalid or missing slot ID of |
+// a client certificate configuration. |
+// |
+// If a network already has a CaCertPEM property, then the NssProperty is |
+// cleared. Otherwise, the NssProperty is compared with |
+// the nickname of each certificate of |certs|. If a match is found, the |
+// CaCertPemProperty is set and the NssProperty is cleared. |
+// |
+// If a network with a client certificate configuration (i.e. a PKCS11 ID) is |
+// found, the configured client certificate is looked up. |
+// If the certificate is found, the currently configured slot ID (if any) is |
+// compared with the actual slot ID of the certificate and if required updated. |
+// If the certificate is not found, the client certificate configuration is |
+// removed. |
+// |
+// Only if necessary, a network will be notified. |
class NetworkCertMigrator::MigrationTask |
: public base::RefCounted<MigrationTask> { |
public: |
@@ -61,11 +73,15 @@ class NetworkCertMigrator::MigrationTask |
void Run(const NetworkStateHandler::NetworkStateList& networks) { |
// Request properties for each network that has a CaCertNssProperty set |
- // according to the NetworkStateHandler. |
+ // or which could be configured with a client certificate. |
for (NetworkStateHandler::NetworkStateList::const_iterator it = |
networks.begin(); it != networks.end(); ++it) { |
- if (!(*it)->HasCACertNSS()) |
+ if (!(*it)->HasCACertNSS() && |
+ (*it)->security() != shill::kSecurity8021x && |
+ (*it)->type() != shill::kTypeVPN && |
+ (*it)->type() != shill::kTypeEthernetEap) { |
continue; |
+ } |
const std::string& service_path = (*it)->path(); |
DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( |
dbus::ObjectPath(service_path), |
@@ -83,6 +99,59 @@ class NetworkCertMigrator::MigrationTask |
return; |
} |
+ base::DictionaryValue new_properties; |
+ MigrateClientCertProperties(service_path, properties, &new_properties); |
+ MigrateNssProperties(service_path, properties, &new_properties); |
+ |
+ if (new_properties.empty()) |
+ return; |
+ SendPropertiesToShill(service_path, new_properties); |
+ } |
+ |
+ void MigrateClientCertProperties(const std::string& service_path, |
+ const base::DictionaryValue& properties, |
+ base::DictionaryValue* new_properties) { |
+ int configured_slot_id = -1; |
+ std::string pkcs11_id; |
+ chromeos::client_cert::ConfigType config_type = |
+ chromeos::client_cert::CONFIG_TYPE_NONE; |
+ chromeos::client_cert::GetClientCertFromShillProperties( |
+ properties, &config_type, &configured_slot_id, &pkcs11_id); |
+ if (config_type == chromeos::client_cert::CONFIG_TYPE_NONE || |
+ pkcs11_id.empty()) { |
+ return; |
+ } |
+ |
+ // OpenVPN configuration doesn't have a slot id to migrate. |
+ if (config_type == chromeos::client_cert::CONFIG_TYPE_OPENVPN) |
+ return; |
+ |
+ int real_slot_id = -1; |
+ scoped_refptr<net::X509Certificate> cert = |
+ FindCertificateWithPkcs11Id(pkcs11_id, &real_slot_id); |
+ if (!cert) { |
+ LOG(WARNING) << "No matching cert found, removing the certificate " |
+ "configuration from network " << service_path; |
+ chromeos::client_cert::SetEmptyShillProperties(config_type, |
+ new_properties); |
+ return; |
+ } |
+ if (real_slot_id == -1) { |
+ LOG(WARNING) << "Found a certificate without slot id."; |
+ return; |
+ } |
+ |
+ if (cert && real_slot_id != configured_slot_id) { |
+ VLOG(1) << "Network " << service_path |
+ << " is configured with no or an incorrect slot id."; |
+ chromeos::client_cert::SetShillProperties( |
+ config_type, real_slot_id, pkcs11_id, new_properties); |
+ } |
+ } |
+ |
+ void MigrateNssProperties(const std::string& service_path, |
+ const base::DictionaryValue& properties, |
+ base::DictionaryValue* new_properties) { |
std::string nss_key, pem_key, nickname; |
const base::ListValue* pem_property = NULL; |
UMANetworkType uma_type = UMA_NETWORK_TYPE_SIZE; |
@@ -99,7 +168,7 @@ class NetworkCertMigrator::MigrationTask |
if (pem_property && !pem_property->empty()) { |
VLOG(2) << "PEM already exists, clearing NSS property."; |
- ClearNssProperty(service_path, nss_key); |
+ ClearNssProperty(nss_key, new_properties); |
return; |
} |
@@ -117,7 +186,8 @@ class NetworkCertMigrator::MigrationTask |
return; |
} |
- SetNssAndPemProperties(service_path, nss_key, pem_key, pem_encoded); |
+ ClearNssProperty(nss_key, new_properties); |
+ SetPemProperty(pem_key, pem_encoded, new_properties); |
} |
void GetNssAndPemProperties(const base::DictionaryValue& shill_properties, |
@@ -159,18 +229,25 @@ class NetworkCertMigrator::MigrationTask |
} |
} |
- void ClearNssProperty(const std::string& service_path, |
- const std::string& nss_key) { |
- DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( |
- dbus::ObjectPath(service_path), |
- nss_key, |
- base::StringValue(std::string()), |
- base::Bind( |
- &MigrationTask::NotifyNetworkStateHandler, this, service_path), |
- base::Bind(&network_handler::ShillErrorCallbackFunction, |
- "MigrationTask.SetProperty failed", |
- service_path, |
- network_handler::ErrorCallback())); |
+ void ClearNssProperty(const std::string& nss_key, |
+ base::DictionaryValue* new_properties) { |
+ new_properties->SetStringWithoutPathExpansion(nss_key, std::string()); |
+ } |
+ |
+ scoped_refptr<net::X509Certificate> FindCertificateWithPkcs11Id( |
+ const std::string& pkcs11_id, int* slot_id) { |
+ *slot_id = -1; |
+ for (net::CertificateList::iterator it = certs_.begin(); it != certs_.end(); |
+ ++it) { |
+ int current_slot_id = -1; |
+ std::string current_pkcs11_id = |
+ CertLoader::GetPkcs11IdAndSlotForCert(**it, ¤t_slot_id); |
+ if (current_pkcs11_id == pkcs11_id) { |
+ *slot_id = current_slot_id; |
+ return *it; |
+ } |
+ } |
+ return NULL; |
} |
scoped_refptr<net::X509Certificate> FindCertificateWithNickname( |
@@ -183,19 +260,19 @@ class NetworkCertMigrator::MigrationTask |
return NULL; |
} |
- void SetNssAndPemProperties(const std::string& service_path, |
- const std::string& nss_key, |
- const std::string& pem_key, |
- const std::string& pem_encoded_cert) { |
- base::DictionaryValue new_properties; |
- new_properties.SetStringWithoutPathExpansion(nss_key, std::string()); |
+ void SetPemProperty(const std::string& pem_key, |
+ const std::string& pem_encoded_cert, |
+ base::DictionaryValue* new_properties) { |
scoped_ptr<base::ListValue> ca_cert_pems(new base::ListValue); |
ca_cert_pems->AppendString(pem_encoded_cert); |
- new_properties.SetWithoutPathExpansion(pem_key, ca_cert_pems.release()); |
+ new_properties->SetWithoutPathExpansion(pem_key, ca_cert_pems.release()); |
+ } |
+ void SendPropertiesToShill(const std::string& service_path, |
+ const base::DictionaryValue& properties) { |
DBusThreadManager::Get()->GetShillServiceClient()->SetProperties( |
dbus::ObjectPath(service_path), |
- new_properties, |
+ properties, |
base::Bind( |
&MigrationTask::NotifyNetworkStateHandler, this, service_path), |
base::Bind(&MigrationTask::LogErrorAndNotifyNetworkStateHandler, |
@@ -258,20 +335,26 @@ void NetworkCertMigrator::NetworkListChanged() { |
VLOG(2) << "Certs not loaded yet."; |
return; |
} |
- // Run the migration process from deprecated CaCertNssProperties to CaCertPem. |
- VLOG(2) << "Start NSS nickname to PEM migration."; |
+ // Run the migration process from deprecated CaCertNssProperties to CaCertPem |
+ // and to fix missing or incorrect slot ids of client certificates. |
+ VLOG(2) << "Start certificate migration of network configurations."; |
scoped_refptr<MigrationTask> helper(new MigrationTask( |
CertLoader::Get()->cert_list(), weak_ptr_factory_.GetWeakPtr())); |
NetworkStateHandler::NetworkStateList networks; |
- network_state_handler_->GetVisibleNetworkList(&networks); |
+ network_state_handler_->GetNetworkListByType( |
+ NetworkTypePattern::Default(), |
+ true, // only configured networks |
+ false, // visible and not visible networks |
+ 0, // no count limit |
+ &networks); |
helper->Run(networks); |
} |
void NetworkCertMigrator::OnCertificatesLoaded( |
const net::CertificateList& cert_list, |
bool initial_load) { |
- // Maybe there are networks referring to certs (by NSS nickname) that were not |
- // loaded before but are now. |
+ // Maybe there are networks referring to certs that were not loaded before but |
+ // are now. |
NetworkListChanged(); |
} |