Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chromeos / network / network_cert_migrator.cc
blob9bc90db544ceda1ffccf0d0a14fb67e24962a0c3
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
3 // found in the LICENSE file.
5 #include "chromeos/network/network_cert_migrator.h"
7 #include <cert.h>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/metrics/histogram.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_service_client.h"
15 #include "chromeos/network/client_cert_util.h"
16 #include "chromeos/network/network_handler_callbacks.h"
17 #include "chromeos/network/network_state.h"
18 #include "chromeos/network/network_state_handler.h"
19 #include "dbus/object_path.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
22 namespace chromeos {
24 // Migrates each network of |networks| with an invalid or missing slot ID in
25 // their client certificate configuration.
27 // If a network with a client certificate configuration (i.e. a PKCS11 ID) is
28 // found, the configured client certificate is looked up.
29 // If the certificate is found, the currently configured slot ID (if any) is
30 // compared with the actual slot ID of the certificate and if required updated.
31 // If the certificate is not found, the client certificate configuration is
32 // removed.
34 // Only if necessary, a network will be notified.
35 class NetworkCertMigrator::MigrationTask
36 : public base::RefCounted<MigrationTask> {
37 public:
38 MigrationTask(const net::CertificateList& certs,
39 const base::WeakPtr<NetworkCertMigrator>& cert_migrator)
40 : certs_(certs),
41 cert_migrator_(cert_migrator) {
44 void Run(const NetworkStateHandler::NetworkStateList& networks) {
45 // Request properties for each network that could be configured with a
46 // client certificate.
47 for (const NetworkState* network : networks) {
48 if (network->security_class() != shill::kSecurity8021x &&
49 network->type() != shill::kTypeVPN &&
50 network->type() != shill::kTypeEthernetEap) {
51 continue;
53 const std::string& service_path = network->path();
54 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
55 dbus::ObjectPath(service_path),
56 base::Bind(&network_handler::GetPropertiesCallback,
57 base::Bind(&MigrationTask::MigrateNetwork, this),
58 network_handler::ErrorCallback(),
59 service_path));
63 void MigrateNetwork(const std::string& service_path,
64 const base::DictionaryValue& properties) {
65 if (!cert_migrator_) {
66 VLOG(2) << "NetworkCertMigrator already destroyed. Aborting migration.";
67 return;
70 base::DictionaryValue new_properties;
71 MigrateClientCertProperties(service_path, properties, &new_properties);
73 if (new_properties.empty())
74 return;
75 SendPropertiesToShill(service_path, new_properties);
78 void MigrateClientCertProperties(const std::string& service_path,
79 const base::DictionaryValue& properties,
80 base::DictionaryValue* new_properties) {
81 int configured_slot_id = -1;
82 std::string pkcs11_id;
83 chromeos::client_cert::ConfigType config_type =
84 chromeos::client_cert::CONFIG_TYPE_NONE;
85 chromeos::client_cert::GetClientCertFromShillProperties(
86 properties, &config_type, &configured_slot_id, &pkcs11_id);
87 if (config_type == chromeos::client_cert::CONFIG_TYPE_NONE ||
88 pkcs11_id.empty()) {
89 return;
92 // OpenVPN configuration doesn't have a slot id to migrate.
93 if (config_type == chromeos::client_cert::CONFIG_TYPE_OPENVPN)
94 return;
96 int real_slot_id = -1;
97 scoped_refptr<net::X509Certificate> cert =
98 FindCertificateWithPkcs11Id(pkcs11_id, &real_slot_id);
99 if (!cert.get()) {
100 LOG(WARNING) << "No matching cert found, removing the certificate "
101 "configuration from network " << service_path;
102 chromeos::client_cert::SetEmptyShillProperties(config_type,
103 new_properties);
104 return;
106 if (real_slot_id == -1) {
107 LOG(WARNING) << "Found a certificate without slot id.";
108 return;
111 if (cert.get() && real_slot_id != configured_slot_id) {
112 VLOG(1) << "Network " << service_path
113 << " is configured with no or an incorrect slot id.";
114 chromeos::client_cert::SetShillProperties(
115 config_type, real_slot_id, pkcs11_id, new_properties);
119 scoped_refptr<net::X509Certificate> FindCertificateWithPkcs11Id(
120 const std::string& pkcs11_id, int* slot_id) {
121 *slot_id = -1;
122 for (scoped_refptr<net::X509Certificate> cert : certs_) {
123 int current_slot_id = -1;
124 std::string current_pkcs11_id =
125 CertLoader::GetPkcs11IdAndSlotForCert(*cert, &current_slot_id);
126 if (current_pkcs11_id == pkcs11_id) {
127 *slot_id = current_slot_id;
128 return cert;
131 return nullptr;
134 void SendPropertiesToShill(const std::string& service_path,
135 const base::DictionaryValue& properties) {
136 DBusThreadManager::Get()->GetShillServiceClient()->SetProperties(
137 dbus::ObjectPath(service_path), properties,
138 base::Bind(&base::DoNothing), base::Bind(&LogError, service_path));
141 static void LogError(const std::string& service_path,
142 const std::string& error_name,
143 const std::string& error_message) {
144 network_handler::ShillErrorCallbackFunction(
145 "MigrationTask.SetProperties failed",
146 service_path,
147 network_handler::ErrorCallback(),
148 error_name,
149 error_message);
152 private:
153 friend class base::RefCounted<MigrationTask>;
154 virtual ~MigrationTask() {
157 net::CertificateList certs_;
158 base::WeakPtr<NetworkCertMigrator> cert_migrator_;
161 NetworkCertMigrator::NetworkCertMigrator()
162 : network_state_handler_(nullptr),
163 weak_ptr_factory_(this) {
166 NetworkCertMigrator::~NetworkCertMigrator() {
167 network_state_handler_->RemoveObserver(this, FROM_HERE);
168 if (CertLoader::IsInitialized())
169 CertLoader::Get()->RemoveObserver(this);
172 void NetworkCertMigrator::Init(NetworkStateHandler* network_state_handler) {
173 DCHECK(network_state_handler);
174 network_state_handler_ = network_state_handler;
175 network_state_handler_->AddObserver(this, FROM_HERE);
177 DCHECK(CertLoader::IsInitialized());
178 CertLoader::Get()->AddObserver(this);
181 void NetworkCertMigrator::NetworkListChanged() {
182 if (!CertLoader::Get()->certificates_loaded()) {
183 VLOG(2) << "Certs not loaded yet.";
184 return;
186 // Run the migration process to fix missing or incorrect slot ids of client
187 // certificates.
188 VLOG(2) << "Start certificate migration of network configurations.";
189 scoped_refptr<MigrationTask> helper(new MigrationTask(
190 CertLoader::Get()->cert_list(), weak_ptr_factory_.GetWeakPtr()));
191 NetworkStateHandler::NetworkStateList networks;
192 network_state_handler_->GetNetworkListByType(
193 NetworkTypePattern::Default(),
194 true, // only configured networks
195 false, // visible and not visible networks
196 0, // no count limit
197 &networks);
198 helper->Run(networks);
201 void NetworkCertMigrator::OnCertificatesLoaded(
202 const net::CertificateList& cert_list,
203 bool initial_load) {
204 if (initial_load)
205 NetworkListChanged();
208 } // namespace chromeos