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"
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"
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
34 // Only if necessary, a network will be notified.
35 class NetworkCertMigrator::MigrationTask
36 : public base::RefCounted
<MigrationTask
> {
38 MigrationTask(const net::CertificateList
& certs
,
39 const base::WeakPtr
<NetworkCertMigrator
>& cert_migrator
)
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
) {
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(),
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.";
70 base::DictionaryValue new_properties
;
71 MigrateClientCertProperties(service_path
, properties
, &new_properties
);
73 if (new_properties
.empty())
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
||
92 // OpenVPN configuration doesn't have a slot id to migrate.
93 if (config_type
== chromeos::client_cert::CONFIG_TYPE_OPENVPN
)
96 int real_slot_id
= -1;
97 scoped_refptr
<net::X509Certificate
> cert
=
98 FindCertificateWithPkcs11Id(pkcs11_id
, &real_slot_id
);
100 LOG(WARNING
) << "No matching cert found, removing the certificate "
101 "configuration from network " << service_path
;
102 chromeos::client_cert::SetEmptyShillProperties(config_type
,
106 if (real_slot_id
== -1) {
107 LOG(WARNING
) << "Found a certificate without slot id.";
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
) {
122 for (scoped_refptr
<net::X509Certificate
> cert
: certs_
) {
123 int current_slot_id
= -1;
124 std::string current_pkcs11_id
=
125 CertLoader::GetPkcs11IdAndSlotForCert(*cert
, ¤t_slot_id
);
126 if (current_pkcs11_id
== pkcs11_id
) {
127 *slot_id
= current_slot_id
;
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",
147 network_handler::ErrorCallback(),
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.";
186 // Run the migration process to fix missing or incorrect slot ids of client
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
198 helper
->Run(networks
);
201 void NetworkCertMigrator::OnCertificatesLoaded(
202 const net::CertificateList
& cert_list
,
205 NetworkListChanged();
208 } // namespace chromeos