| 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/network_cert_migrator.h" | 5 #include "chromeos/network/network_cert_migrator.h" |
| 6 | 6 |
| 7 #include <cert.h> | 7 #include <cert.h> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "chromeos/dbus/dbus_thread_manager.h" | 13 #include "chromeos/dbus/dbus_thread_manager.h" |
| 14 #include "chromeos/dbus/shill_service_client.h" | 14 #include "chromeos/dbus/shill_service_client.h" |
| 15 #include "chromeos/network/client_cert_util.h" |
| 15 #include "chromeos/network/network_handler_callbacks.h" | 16 #include "chromeos/network/network_handler_callbacks.h" |
| 16 #include "chromeos/network/network_state.h" | 17 #include "chromeos/network/network_state.h" |
| 17 #include "chromeos/network/network_state_handler.h" | 18 #include "chromeos/network/network_state_handler.h" |
| 18 #include "dbus/object_path.h" | 19 #include "dbus/object_path.h" |
| 19 #include "third_party/cros_system_api/dbus/service_constants.h" | 20 #include "third_party/cros_system_api/dbus/service_constants.h" |
| 20 | 21 |
| 21 namespace chromeos { | 22 namespace chromeos { |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 37 // Hack copied from mozilla: Cut off text before first :, which seems to | 38 // Hack copied from mozilla: Cut off text before first :, which seems to |
| 38 // just be the token name. | 39 // just be the token name. |
| 39 size_t colon_pos = name.find(':'); | 40 size_t colon_pos = name.find(':'); |
| 40 if (colon_pos != std::string::npos) | 41 if (colon_pos != std::string::npos) |
| 41 name = name.substr(colon_pos + 1); | 42 name = name.substr(colon_pos + 1); |
| 42 return name; | 43 return name; |
| 43 } | 44 } |
| 44 | 45 |
| 45 } // namespace | 46 } // namespace |
| 46 | 47 |
| 47 // Checks which of the given |networks| has one of the deprecated | 48 // Migrates each network of |networks| with a deprecated CaCertNss property to |
| 48 // CaCertNssProperties set. If such a network already has a CaCertPEM property, | 49 // the respective CaCertPEM property and fixes an invalid or missing slot ID of |
| 49 // then the NssProperty is cleared. Otherwise, the NssProperty is compared with | 50 // a client certificate configuration. |
| 50 // the nickname of each certificate of |certs|. If a match is found, then the | 51 // |
| 51 // CaCertPemProperty is set and the NssProperty is cleared. Otherwise, the | 52 // If a network already has a CaCertPEM property, then the NssProperty is |
| 52 // network is not modified. | 53 // cleared. Otherwise, the NssProperty is compared with |
| 54 // the nickname of each certificate of |certs|. If a match is found, the |
| 55 // CaCertPemProperty is set and the NssProperty is cleared. |
| 56 // |
| 57 // If a network with a client certificate configuration (i.e. a PKCS11 ID) is |
| 58 // found, the configured client certificate is looked up. |
| 59 // If the certificate is found, the currently configured slot ID (if any) is |
| 60 // compared with the actual slot ID of the certificate and if required updated. |
| 61 // If the certificate is not found, the client certificate configuration is |
| 62 // removed. |
| 63 // |
| 64 // Only if necessary, a network will be notified. |
| 53 class NetworkCertMigrator::MigrationTask | 65 class NetworkCertMigrator::MigrationTask |
| 54 : public base::RefCounted<MigrationTask> { | 66 : public base::RefCounted<MigrationTask> { |
| 55 public: | 67 public: |
| 56 MigrationTask(const net::CertificateList& certs, | 68 MigrationTask(const net::CertificateList& certs, |
| 57 const base::WeakPtr<NetworkCertMigrator>& cert_migrator) | 69 const base::WeakPtr<NetworkCertMigrator>& cert_migrator) |
| 58 : certs_(certs), | 70 : certs_(certs), |
| 59 cert_migrator_(cert_migrator) { | 71 cert_migrator_(cert_migrator) { |
| 60 } | 72 } |
| 61 | 73 |
| 62 void Run(const NetworkStateHandler::NetworkStateList& networks) { | 74 void Run(const NetworkStateHandler::NetworkStateList& networks) { |
| 63 // Request properties for each network that has a CaCertNssProperty set | 75 // Request properties for each network that has a CaCertNssProperty set |
| 64 // according to the NetworkStateHandler. | 76 // or which could be configured with a client certificate. |
| 65 for (NetworkStateHandler::NetworkStateList::const_iterator it = | 77 for (NetworkStateHandler::NetworkStateList::const_iterator it = |
| 66 networks.begin(); it != networks.end(); ++it) { | 78 networks.begin(); it != networks.end(); ++it) { |
| 67 if (!(*it)->HasCACertNSS()) | 79 if (!(*it)->HasCACertNSS() && |
| 80 (*it)->security() != shill::kSecurity8021x && |
| 81 (*it)->type() != shill::kTypeVPN && |
| 82 (*it)->type() != shill::kTypeEthernetEap) { |
| 68 continue; | 83 continue; |
| 84 } |
| 69 const std::string& service_path = (*it)->path(); | 85 const std::string& service_path = (*it)->path(); |
| 70 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( | 86 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( |
| 71 dbus::ObjectPath(service_path), | 87 dbus::ObjectPath(service_path), |
| 72 base::Bind(&network_handler::GetPropertiesCallback, | 88 base::Bind(&network_handler::GetPropertiesCallback, |
| 73 base::Bind(&MigrationTask::MigrateNetwork, this), | 89 base::Bind(&MigrationTask::MigrateNetwork, this), |
| 74 network_handler::ErrorCallback(), | 90 network_handler::ErrorCallback(), |
| 75 service_path)); | 91 service_path)); |
| 76 } | 92 } |
| 77 } | 93 } |
| 78 | 94 |
| 79 void MigrateNetwork(const std::string& service_path, | 95 void MigrateNetwork(const std::string& service_path, |
| 80 const base::DictionaryValue& properties) { | 96 const base::DictionaryValue& properties) { |
| 81 if (!cert_migrator_) { | 97 if (!cert_migrator_) { |
| 82 VLOG(2) << "NetworkCertMigrator already destroyed. Aborting migration."; | 98 VLOG(2) << "NetworkCertMigrator already destroyed. Aborting migration."; |
| 83 return; | 99 return; |
| 84 } | 100 } |
| 85 | 101 |
| 102 base::DictionaryValue new_properties; |
| 103 MigrateClientCertProperties(service_path, properties, &new_properties); |
| 104 MigrateNssProperties(service_path, properties, &new_properties); |
| 105 |
| 106 if (new_properties.empty()) |
| 107 return; |
| 108 SendPropertiesToShill(service_path, new_properties); |
| 109 } |
| 110 |
| 111 void MigrateClientCertProperties(const std::string& service_path, |
| 112 const base::DictionaryValue& properties, |
| 113 base::DictionaryValue* new_properties) { |
| 114 int configured_slot_id = -1; |
| 115 std::string pkcs11_id; |
| 116 chromeos::client_cert::ConfigType config_type = |
| 117 chromeos::client_cert::CONFIG_TYPE_NONE; |
| 118 chromeos::client_cert::GetClientCertFromShillProperties( |
| 119 properties, &config_type, &configured_slot_id, &pkcs11_id); |
| 120 if (config_type == chromeos::client_cert::CONFIG_TYPE_NONE || |
| 121 pkcs11_id.empty()) { |
| 122 return; |
| 123 } |
| 124 |
| 125 // OpenVPN configuration doesn't have a slot id to migrate. |
| 126 if (config_type == chromeos::client_cert::CONFIG_TYPE_OPENVPN) |
| 127 return; |
| 128 |
| 129 int real_slot_id = -1; |
| 130 scoped_refptr<net::X509Certificate> cert = |
| 131 FindCertificateWithPkcs11Id(pkcs11_id, &real_slot_id); |
| 132 if (!cert) { |
| 133 LOG(WARNING) << "No matching cert found, removing the certificate " |
| 134 "configuration from network " << service_path; |
| 135 chromeos::client_cert::SetEmptyShillProperties(config_type, |
| 136 new_properties); |
| 137 return; |
| 138 } |
| 139 if (real_slot_id == -1) { |
| 140 LOG(WARNING) << "Found a certificate without slot id."; |
| 141 return; |
| 142 } |
| 143 |
| 144 if (cert && real_slot_id != configured_slot_id) { |
| 145 VLOG(1) << "Network " << service_path |
| 146 << " is configured with no or an incorrect slot id."; |
| 147 chromeos::client_cert::SetShillProperties( |
| 148 config_type, real_slot_id, pkcs11_id, new_properties); |
| 149 } |
| 150 } |
| 151 |
| 152 void MigrateNssProperties(const std::string& service_path, |
| 153 const base::DictionaryValue& properties, |
| 154 base::DictionaryValue* new_properties) { |
| 86 std::string nss_key, pem_key, nickname; | 155 std::string nss_key, pem_key, nickname; |
| 87 const base::ListValue* pem_property = NULL; | 156 const base::ListValue* pem_property = NULL; |
| 88 UMANetworkType uma_type = UMA_NETWORK_TYPE_SIZE; | 157 UMANetworkType uma_type = UMA_NETWORK_TYPE_SIZE; |
| 89 | 158 |
| 90 GetNssAndPemProperties( | 159 GetNssAndPemProperties( |
| 91 properties, &nss_key, &pem_key, &pem_property, &nickname, &uma_type); | 160 properties, &nss_key, &pem_key, &pem_property, &nickname, &uma_type); |
| 92 if (nickname.empty()) | 161 if (nickname.empty()) |
| 93 return; // Didn't find any nickname. | 162 return; // Didn't find any nickname. |
| 94 | 163 |
| 95 VLOG(2) << "Found NSS nickname to migrate. Property: " << nss_key | 164 VLOG(2) << "Found NSS nickname to migrate. Property: " << nss_key |
| 96 << ", network: " << service_path; | 165 << ", network: " << service_path; |
| 97 UMA_HISTOGRAM_ENUMERATION( | 166 UMA_HISTOGRAM_ENUMERATION( |
| 98 "Network.MigrationNssToPem", uma_type, UMA_NETWORK_TYPE_SIZE); | 167 "Network.MigrationNssToPem", uma_type, UMA_NETWORK_TYPE_SIZE); |
| 99 | 168 |
| 100 if (pem_property && !pem_property->empty()) { | 169 if (pem_property && !pem_property->empty()) { |
| 101 VLOG(2) << "PEM already exists, clearing NSS property."; | 170 VLOG(2) << "PEM already exists, clearing NSS property."; |
| 102 ClearNssProperty(service_path, nss_key); | 171 ClearNssProperty(nss_key, new_properties); |
| 103 return; | 172 return; |
| 104 } | 173 } |
| 105 | 174 |
| 106 scoped_refptr<net::X509Certificate> cert = | 175 scoped_refptr<net::X509Certificate> cert = |
| 107 FindCertificateWithNickname(nickname); | 176 FindCertificateWithNickname(nickname); |
| 108 if (!cert) { | 177 if (!cert) { |
| 109 VLOG(2) << "No matching cert found."; | 178 VLOG(2) << "No matching cert found."; |
| 110 return; | 179 return; |
| 111 } | 180 } |
| 112 | 181 |
| 113 std::string pem_encoded; | 182 std::string pem_encoded; |
| 114 if (!net::X509Certificate::GetPEMEncoded(cert->os_cert_handle(), | 183 if (!net::X509Certificate::GetPEMEncoded(cert->os_cert_handle(), |
| 115 &pem_encoded)) { | 184 &pem_encoded)) { |
| 116 LOG(ERROR) << "PEM encoding failed."; | 185 LOG(ERROR) << "PEM encoding failed."; |
| 117 return; | 186 return; |
| 118 } | 187 } |
| 119 | 188 |
| 120 SetNssAndPemProperties(service_path, nss_key, pem_key, pem_encoded); | 189 ClearNssProperty(nss_key, new_properties); |
| 190 SetPemProperty(pem_key, pem_encoded, new_properties); |
| 121 } | 191 } |
| 122 | 192 |
| 123 void GetNssAndPemProperties(const base::DictionaryValue& shill_properties, | 193 void GetNssAndPemProperties(const base::DictionaryValue& shill_properties, |
| 124 std::string* nss_key, | 194 std::string* nss_key, |
| 125 std::string* pem_key, | 195 std::string* pem_key, |
| 126 const base::ListValue** pem_property, | 196 const base::ListValue** pem_property, |
| 127 std::string* nickname, | 197 std::string* nickname, |
| 128 UMANetworkType* uma_type) { | 198 UMANetworkType* uma_type) { |
| 129 struct NssPem { | 199 struct NssPem { |
| 130 const char* read_prefix; | 200 const char* read_prefix; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 152 if (!nickname->empty()) { | 222 if (!nickname->empty()) { |
| 153 *nss_key = kNssPemMap[i].nss_key; | 223 *nss_key = kNssPemMap[i].nss_key; |
| 154 *pem_key = kNssPemMap[i].pem_key; | 224 *pem_key = kNssPemMap[i].pem_key; |
| 155 *uma_type = kNssPemMap[i].uma_type; | 225 *uma_type = kNssPemMap[i].uma_type; |
| 156 dict->GetListWithoutPathExpansion(kNssPemMap[i].pem_key, pem_property); | 226 dict->GetListWithoutPathExpansion(kNssPemMap[i].pem_key, pem_property); |
| 157 return; | 227 return; |
| 158 } | 228 } |
| 159 } | 229 } |
| 160 } | 230 } |
| 161 | 231 |
| 162 void ClearNssProperty(const std::string& service_path, | 232 void ClearNssProperty(const std::string& nss_key, |
| 163 const std::string& nss_key) { | 233 base::DictionaryValue* new_properties) { |
| 164 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( | 234 new_properties->SetStringWithoutPathExpansion(nss_key, std::string()); |
| 165 dbus::ObjectPath(service_path), | 235 } |
| 166 nss_key, | 236 |
| 167 base::StringValue(std::string()), | 237 scoped_refptr<net::X509Certificate> FindCertificateWithPkcs11Id( |
| 168 base::Bind( | 238 const std::string& pkcs11_id, int* slot_id) { |
| 169 &MigrationTask::NotifyNetworkStateHandler, this, service_path), | 239 *slot_id = -1; |
| 170 base::Bind(&network_handler::ShillErrorCallbackFunction, | 240 for (net::CertificateList::iterator it = certs_.begin(); it != certs_.end(); |
| 171 "MigrationTask.SetProperty failed", | 241 ++it) { |
| 172 service_path, | 242 int current_slot_id = -1; |
| 173 network_handler::ErrorCallback())); | 243 std::string current_pkcs11_id = |
| 244 CertLoader::GetPkcs11IdAndSlotForCert(**it, ¤t_slot_id); |
| 245 if (current_pkcs11_id == pkcs11_id) { |
| 246 *slot_id = current_slot_id; |
| 247 return *it; |
| 248 } |
| 249 } |
| 250 return NULL; |
| 174 } | 251 } |
| 175 | 252 |
| 176 scoped_refptr<net::X509Certificate> FindCertificateWithNickname( | 253 scoped_refptr<net::X509Certificate> FindCertificateWithNickname( |
| 177 const std::string& nickname) { | 254 const std::string& nickname) { |
| 178 for (net::CertificateList::iterator it = certs_.begin(); it != certs_.end(); | 255 for (net::CertificateList::iterator it = certs_.begin(); it != certs_.end(); |
| 179 ++it) { | 256 ++it) { |
| 180 if (nickname == GetNickname(**it)) | 257 if (nickname == GetNickname(**it)) |
| 181 return *it; | 258 return *it; |
| 182 } | 259 } |
| 183 return NULL; | 260 return NULL; |
| 184 } | 261 } |
| 185 | 262 |
| 186 void SetNssAndPemProperties(const std::string& service_path, | 263 void SetPemProperty(const std::string& pem_key, |
| 187 const std::string& nss_key, | 264 const std::string& pem_encoded_cert, |
| 188 const std::string& pem_key, | 265 base::DictionaryValue* new_properties) { |
| 189 const std::string& pem_encoded_cert) { | |
| 190 base::DictionaryValue new_properties; | |
| 191 new_properties.SetStringWithoutPathExpansion(nss_key, std::string()); | |
| 192 scoped_ptr<base::ListValue> ca_cert_pems(new base::ListValue); | 266 scoped_ptr<base::ListValue> ca_cert_pems(new base::ListValue); |
| 193 ca_cert_pems->AppendString(pem_encoded_cert); | 267 ca_cert_pems->AppendString(pem_encoded_cert); |
| 194 new_properties.SetWithoutPathExpansion(pem_key, ca_cert_pems.release()); | 268 new_properties->SetWithoutPathExpansion(pem_key, ca_cert_pems.release()); |
| 269 } |
| 195 | 270 |
| 271 void SendPropertiesToShill(const std::string& service_path, |
| 272 const base::DictionaryValue& properties) { |
| 196 DBusThreadManager::Get()->GetShillServiceClient()->SetProperties( | 273 DBusThreadManager::Get()->GetShillServiceClient()->SetProperties( |
| 197 dbus::ObjectPath(service_path), | 274 dbus::ObjectPath(service_path), |
| 198 new_properties, | 275 properties, |
| 199 base::Bind( | 276 base::Bind( |
| 200 &MigrationTask::NotifyNetworkStateHandler, this, service_path), | 277 &MigrationTask::NotifyNetworkStateHandler, this, service_path), |
| 201 base::Bind(&MigrationTask::LogErrorAndNotifyNetworkStateHandler, | 278 base::Bind(&MigrationTask::LogErrorAndNotifyNetworkStateHandler, |
| 202 this, | 279 this, |
| 203 service_path)); | 280 service_path)); |
| 204 } | 281 } |
| 205 | 282 |
| 206 void LogErrorAndNotifyNetworkStateHandler(const std::string& service_path, | 283 void LogErrorAndNotifyNetworkStateHandler(const std::string& service_path, |
| 207 const std::string& error_name, | 284 const std::string& error_name, |
| 208 const std::string& error_message) { | 285 const std::string& error_message) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 | 328 |
| 252 DCHECK(CertLoader::IsInitialized()); | 329 DCHECK(CertLoader::IsInitialized()); |
| 253 CertLoader::Get()->AddObserver(this); | 330 CertLoader::Get()->AddObserver(this); |
| 254 } | 331 } |
| 255 | 332 |
| 256 void NetworkCertMigrator::NetworkListChanged() { | 333 void NetworkCertMigrator::NetworkListChanged() { |
| 257 if (!CertLoader::Get()->certificates_loaded()) { | 334 if (!CertLoader::Get()->certificates_loaded()) { |
| 258 VLOG(2) << "Certs not loaded yet."; | 335 VLOG(2) << "Certs not loaded yet."; |
| 259 return; | 336 return; |
| 260 } | 337 } |
| 261 // Run the migration process from deprecated CaCertNssProperties to CaCertPem. | 338 // Run the migration process from deprecated CaCertNssProperties to CaCertPem |
| 262 VLOG(2) << "Start NSS nickname to PEM migration."; | 339 // and to fix missing or incorrect slot ids of client certificates. |
| 340 VLOG(2) << "Start certificate migration of network configurations."; |
| 263 scoped_refptr<MigrationTask> helper(new MigrationTask( | 341 scoped_refptr<MigrationTask> helper(new MigrationTask( |
| 264 CertLoader::Get()->cert_list(), weak_ptr_factory_.GetWeakPtr())); | 342 CertLoader::Get()->cert_list(), weak_ptr_factory_.GetWeakPtr())); |
| 265 NetworkStateHandler::NetworkStateList networks; | 343 NetworkStateHandler::NetworkStateList networks; |
| 266 network_state_handler_->GetVisibleNetworkList(&networks); | 344 network_state_handler_->GetNetworkListByType( |
| 345 NetworkTypePattern::Default(), |
| 346 true, // only configured networks |
| 347 false, // visible and not visible networks |
| 348 0, // no count limit |
| 349 &networks); |
| 267 helper->Run(networks); | 350 helper->Run(networks); |
| 268 } | 351 } |
| 269 | 352 |
| 270 void NetworkCertMigrator::OnCertificatesLoaded( | 353 void NetworkCertMigrator::OnCertificatesLoaded( |
| 271 const net::CertificateList& cert_list, | 354 const net::CertificateList& cert_list, |
| 272 bool initial_load) { | 355 bool initial_load) { |
| 273 // Maybe there are networks referring to certs (by NSS nickname) that were not | 356 // Maybe there are networks referring to certs that were not loaded before but |
| 274 // loaded before but are now. | 357 // are now. |
| 275 NetworkListChanged(); | 358 NetworkListChanged(); |
| 276 } | 359 } |
| 277 | 360 |
| 278 } // namespace chromeos | 361 } // namespace chromeos |
| OLD | NEW |