Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 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. | |
| 4 | |
| 5 #include "chromeos/network/network_cert_handler.h" | |
| 6 | |
| 7 #include <cert.h> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/location.h" | |
| 11 #include "base/metrics/histogram.h" | |
| 12 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 13 #include "chromeos/dbus/shill_service_client.h" | |
| 14 #include "chromeos/network/network_handler_callbacks.h" | |
| 15 #include "chromeos/network/network_state.h" | |
| 16 #include "chromeos/network/network_state_handler.h" | |
| 17 #include "dbus/object_path.h" | |
| 18 #include "third_party/cros_system_api/dbus/service_constants.h" | |
| 19 | |
| 20 namespace chromeos { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 typedef std::vector<std::string> Nicknames; | |
|
pneubeck (no reviews)
2013/07/29 08:41:39
Not used, to be removed.
pneubeck (no reviews)
2013/07/29 13:15:08
Done.
| |
| 25 | |
| 26 enum UMANetworkType { | |
| 27 UMA_NETWORK_TYPE_EAP, | |
| 28 UMA_NETWORK_TYPE_OPENVPN, | |
| 29 UMA_NETWORK_TYPE_IPSEC, | |
| 30 UMA_NETWORK_TYPE_SIZE, | |
| 31 }; | |
| 32 | |
| 33 // Copied from x509_certificate_model_nss.cc | |
| 34 std::string GetNickname(const net::X509Certificate::OSCertHandle& cert_handle) { | |
| 35 if (!cert_handle->nickname) | |
| 36 return std::string(); | |
| 37 std::string name = cert_handle->nickname; | |
| 38 // Hack copied from mozilla: Cut off text before first :, which seems to | |
| 39 // just be the token name. | |
| 40 size_t colon_pos = name.find(':'); | |
| 41 if (colon_pos != std::string::npos) | |
| 42 name = name.substr(colon_pos + 1); | |
| 43 return name; | |
| 44 } | |
| 45 | |
| 46 } // namespace | |
| 47 | |
| 48 // Checks which of the given |networks| has one of the deprecated | |
| 49 // CaCertNssProperties set. If such a network already has a CaCertPEM property, | |
| 50 // then the NssProperty is cleared. Otherwise, the NssProperty is compared with | |
| 51 // the nickname of each certificate of |certs|. If a match is found, then the | |
| 52 // CaCertPemProperty is set and the NssProperty is cleared. Otherwise, the | |
| 53 // network is not modified. | |
| 54 class NetworkCertHandler::MigrationHelper | |
| 55 : public base::RefCounted<MigrationHelper> { | |
| 56 public: | |
| 57 MigrationHelper(const net::CertificateList& certs, | |
| 58 const base::WeakPtr<NetworkCertHandler>& cert_handler) | |
| 59 : certs_(certs), | |
| 60 cert_handler_(cert_handler) { | |
| 61 } | |
| 62 | |
| 63 void Run(const NetworkStateHandler::NetworkStateList& networks) { | |
| 64 // Request properties for each network that has a CaCertNssProperty set | |
| 65 // according to the NetworkStateHandler. | |
| 66 for (NetworkStateHandler::NetworkStateList::const_iterator it = | |
| 67 networks.begin(); | |
| 68 it != networks.end(); | |
| 69 ++it) { | |
| 70 if (!(*it)->HasCACertNSS()) | |
| 71 continue; | |
| 72 const std::string& service_path = (*it)->path(); | |
| 73 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( | |
| 74 dbus::ObjectPath(service_path), | |
| 75 base::Bind( | |
| 76 &MigrationHelper::GetPropertiesCallback, this, service_path)); | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 void GetPropertiesCallback(const std::string& service_path, | |
|
Mattias Nissler (ping if slow)
2013/07/29 10:08:15
This does too damn much given the unsuspecting nam
pneubeck (no reviews)
2013/07/29 13:15:08
Done.
| |
| 81 DBusMethodCallStatus call_status, | |
| 82 const base::DictionaryValue& properties) { | |
| 83 if (!cert_handler_) { | |
| 84 VLOG(2) << "NetworkCertHandler already destroyed. Aborting migration."; | |
| 85 return; // The CertHandler is destroyed, stop. | |
|
Mattias Nissler (ping if slow)
2013/07/29 10:08:15
Comment is redundant here, remove.
pneubeck (no reviews)
2013/07/29 13:15:08
Done.
| |
| 86 } | |
| 87 | |
| 88 if (call_status == DBUS_METHOD_CALL_FAILURE) | |
|
Mattias Nissler (ping if slow)
2013/07/29 10:08:15
Should this have a VLOG as well?
pneubeck (no reviews)
2013/07/29 13:15:08
Good point. Handling this error case like typical
| |
| 89 return; | |
| 90 | |
| 91 struct NssPem { | |
|
Mattias Nissler (ping if slow)
2013/07/29 10:08:15
static
pneubeck (no reviews)
2013/07/29 13:15:08
No, doesn't add anything:
https://groups.google.co
| |
| 92 const char* read_prefix; | |
| 93 const char* nss_key; | |
| 94 const char* pem_key; | |
| 95 UMANetworkType uma_type; | |
| 96 } const kNssPemMap[] = { | |
| 97 {NULL, flimflam::kEapCaCertNssProperty, shill::kEapCaCertPemProperty, | |
|
Mattias Nissler (ping if slow)
2013/07/29 10:08:15
I'm not entirely sure, but I think style guide / c
pneubeck (no reviews)
2013/07/29 13:15:08
optional, so I'd like to keep the automatic format
| |
| 98 UMA_NETWORK_TYPE_EAP}, | |
| 99 {flimflam::kProviderProperty, flimflam::kL2tpIpsecCaCertNssProperty, | |
| 100 shill::kL2tpIpsecCaCertPemProperty, UMA_NETWORK_TYPE_IPSEC}, | |
| 101 {flimflam::kProviderProperty, flimflam::kOpenVPNCaCertNSSProperty, | |
| 102 shill::kOpenVPNCaCertPemProperty, UMA_NETWORK_TYPE_OPENVPN}, | |
| 103 }; | |
| 104 | |
| 105 std::string nickname; | |
| 106 const base::ListValue* pem_property = NULL; | |
| 107 const NssPem* found_nss_pem = NULL; | |
| 108 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kNssPemMap); ++i) { | |
| 109 const base::DictionaryValue* dict = &properties; | |
| 110 if (kNssPemMap[i].read_prefix) { | |
| 111 properties.GetDictionaryWithoutPathExpansion(kNssPemMap[i].read_prefix, | |
| 112 &dict); | |
| 113 if (!dict) | |
| 114 continue; | |
| 115 } | |
| 116 dict->GetStringWithoutPathExpansion(kNssPemMap[i].nss_key, &nickname); | |
| 117 if (!nickname.empty()) { | |
| 118 found_nss_pem = &kNssPemMap[i]; | |
| 119 dict->GetListWithoutPathExpansion(kNssPemMap[i].pem_key, &pem_property); | |
| 120 break; | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 if (nickname.empty()) | |
| 125 return; // Didn't find any nickname. | |
| 126 | |
| 127 VLOG(2) << "Found NSS nickname to migrate. Property: " | |
| 128 << found_nss_pem->nss_key << ", network: " << service_path; | |
| 129 UMA_HISTOGRAM_ENUMERATION("Network.MigrationNssToPem", | |
| 130 found_nss_pem->uma_type, | |
| 131 UMA_NETWORK_TYPE_SIZE); | |
| 132 | |
| 133 if (pem_property && !pem_property->empty()) { | |
| 134 // The PEM property exists already. We only have to clear the NSS | |
| 135 // property. | |
| 136 VLOG(2) << "PEM already exists, clear NSS property."; | |
|
Mattias Nissler (ping if slow)
2013/07/29 10:08:15
nit: s/clear/clearing/
pneubeck (no reviews)
2013/07/29 13:15:08
Done.
| |
| 137 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( | |
| 138 dbus::ObjectPath(service_path), | |
| 139 found_nss_pem->nss_key, | |
| 140 base::StringValue(std::string()), | |
| 141 base::Bind(&base::DoNothing), | |
| 142 base::Bind(&network_handler::ShillErrorCallbackFunction, | |
| 143 "MigrationHelper.ClearProperty failed", | |
| 144 service_path, | |
| 145 network_handler::ErrorCallback())); | |
| 146 CHECK(cert_handler_); | |
| 147 CHECK(cert_handler_->network_state_handler_); | |
| 148 cert_handler_->network_state_handler_ | |
| 149 ->RequestUpdateForNetwork(service_path); | |
| 150 return; | |
| 151 } | |
| 152 | |
| 153 scoped_refptr<net::X509Certificate> cert; | |
| 154 for (net::CertificateList::iterator it = certs_.begin(); it != certs_.end(); | |
| 155 ++it) { | |
| 156 if (nickname == GetNickname((*it)->os_cert_handle())) { | |
| 157 cert = *it; | |
| 158 break; | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 if (!cert) { | |
| 163 VLOG(2) << "No matching cert found."; | |
| 164 return; // Didn't find a matching certificate. | |
|
Mattias Nissler (ping if slow)
2013/07/29 10:08:15
nit: remove redundant comment
pneubeck (no reviews)
2013/07/29 13:15:08
Done.
| |
| 165 } | |
| 166 | |
| 167 std::string pem_encoded; | |
| 168 if (!net::X509Certificate::GetPEMEncoded(cert->os_cert_handle(), | |
| 169 &pem_encoded)) { | |
| 170 LOG(ERROR) << "PEM encoding failed."; | |
| 171 return; // PEM encoding failed. | |
|
Mattias Nissler (ping if slow)
2013/07/29 10:08:15
nit: remove redundant comment
pneubeck (no reviews)
2013/07/29 13:15:08
Done.
| |
| 172 } | |
| 173 | |
| 174 base::DictionaryValue new_properties; | |
| 175 new_properties.SetStringWithoutPathExpansion(found_nss_pem->nss_key, | |
| 176 std::string()); | |
| 177 scoped_ptr<base::ListValue> ca_cert_pems(new base::ListValue); | |
| 178 ca_cert_pems->AppendString(pem_encoded); | |
| 179 new_properties.SetWithoutPathExpansion(found_nss_pem->pem_key, | |
| 180 ca_cert_pems.release()); | |
| 181 | |
| 182 DBusThreadManager::Get()->GetShillServiceClient() | |
| 183 ->SetProperties(dbus::ObjectPath(service_path), | |
| 184 new_properties, | |
| 185 base::Bind(&base::DoNothing), | |
| 186 base::Bind(&network_handler::ShillErrorCallbackFunction, | |
| 187 "MigrationHelper.SetProperties failed", | |
| 188 service_path, | |
| 189 network_handler::ErrorCallback())); | |
| 190 cert_handler_->network_state_handler_ | |
| 191 ->RequestUpdateForNetwork(service_path); | |
| 192 } | |
| 193 | |
| 194 private: | |
| 195 friend class base::RefCounted<MigrationHelper>; | |
| 196 virtual ~MigrationHelper() { | |
| 197 } | |
| 198 | |
| 199 net::CertificateList certs_; | |
| 200 base::WeakPtr<NetworkCertHandler> cert_handler_; | |
| 201 }; | |
| 202 | |
| 203 NetworkCertHandler::NetworkCertHandler() | |
| 204 : network_state_handler_(NULL), weak_ptr_factory_(this) {} | |
| 205 | |
| 206 NetworkCertHandler::~NetworkCertHandler() { | |
| 207 if (network_state_handler_) | |
| 208 network_state_handler_->RemoveObserver(this, FROM_HERE); | |
| 209 if (CertLoader::IsInitialized()) | |
| 210 CertLoader::Get()->RemoveObserver(this); | |
| 211 } | |
| 212 | |
| 213 void NetworkCertHandler::Init(NetworkStateHandler* network_state_handler) { | |
| 214 DCHECK(network_state_handler); | |
| 215 network_state_handler_ = network_state_handler; | |
| 216 network_state_handler_->AddObserver(this, FROM_HERE); | |
| 217 | |
| 218 DCHECK(CertLoader::IsInitialized()); | |
| 219 CertLoader::Get()->AddObserver(this); | |
| 220 } | |
| 221 | |
| 222 void NetworkCertHandler::NetworkListChanged() { | |
| 223 if (!CertLoader::Get()->certificates_loaded()) { | |
| 224 VLOG(2) << "Certs not loaded yet."; | |
| 225 return; | |
| 226 } | |
| 227 // Run the migration process from deprecated CaCertNssProperties to CaCertPem. | |
| 228 VLOG(2) << "Start NSS nickname to PEM migration."; | |
| 229 scoped_refptr<MigrationHelper> helper(new MigrationHelper( | |
| 230 CertLoader::Get()->cert_list(), weak_ptr_factory_.GetWeakPtr())); | |
| 231 NetworkStateHandler::NetworkStateList networks; | |
| 232 network_state_handler_->GetNetworkList(&networks); | |
| 233 helper->Run(networks); | |
| 234 } | |
| 235 | |
| 236 void NetworkCertHandler::OnCertificatesLoaded( | |
| 237 const net::CertificateList& cert_list, | |
| 238 bool initial_load) { | |
| 239 // Maybe there are networks referring to certs (by NSS nickname) that were not | |
| 240 // loaded before but are now. | |
| 241 NetworkListChanged(); | |
| 242 } | |
| 243 | |
| 244 } // namespace chromeos | |
| OLD | NEW |