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 |