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/client_cert_resolver.h" | 5 #include "chromeos/network/client_cert_resolver.h" |
6 | 6 |
7 #include <cert.h> | 7 #include <cert.h> |
8 #include <certt.h> // for (SECCertUsageEnum) certUsageAnyCA | 8 #include <certt.h> // for (SECCertUsageEnum) certUsageAnyCA |
9 #include <pk11pub.h> | 9 #include <pk11pub.h> |
10 | 10 |
11 #include <algorithm> | 11 #include <algorithm> |
12 | 12 |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
14 #include "base/location.h" | 14 #include "base/location.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
17 #include "base/strings/string_util.h" | |
17 #include "base/task_runner.h" | 18 #include "base/task_runner.h" |
18 #include "base/threading/worker_pool.h" | 19 #include "base/threading/worker_pool.h" |
19 #include "base/time/clock.h" | 20 #include "base/time/clock.h" |
20 #include "chromeos/dbus/dbus_thread_manager.h" | 21 #include "chromeos/dbus/dbus_thread_manager.h" |
21 #include "chromeos/dbus/shill_service_client.h" | 22 #include "chromeos/dbus/shill_service_client.h" |
22 #include "chromeos/network/managed_network_configuration_handler.h" | 23 #include "chromeos/network/managed_network_configuration_handler.h" |
23 #include "chromeos/network/network_state.h" | 24 #include "chromeos/network/network_state.h" |
24 #include "components/onc/onc_constants.h" | 25 #include "components/onc/onc_constants.h" |
25 #include "dbus/object_path.h" | 26 #include "dbus/object_path.h" |
26 #include "net/cert/scoped_nss_types.h" | 27 #include "net/cert/scoped_nss_types.h" |
27 #include "net/cert/x509_certificate.h" | 28 #include "net/cert/x509_certificate.h" |
29 #include "net/cert/x509_util_nss.h" | |
30 #include "third_party/cros_system_api/dbus/service_constants.h" | |
28 | 31 |
29 namespace chromeos { | 32 namespace chromeos { |
30 | 33 |
31 // Describes a network |network_path| for which a matching certificate |cert_id| | 34 // Describes a network |network_path| for which a matching certificate |cert_id| |
32 // was found or for which no certificate was found (|cert_id| will be empty). | 35 // was found or for which no certificate was found (|cert_id| will be empty). |
33 struct ClientCertResolver::NetworkAndMatchingCert { | 36 struct ClientCertResolver::NetworkAndMatchingCert { |
34 NetworkAndMatchingCert(const std::string& network_path, | 37 NetworkAndMatchingCert(const std::string& network_path, |
35 client_cert::ConfigType config_type, | 38 client_cert::ConfigType config_type, |
36 const std::string& cert_id, | 39 const std::string& cert_id, |
37 int slot_id) | 40 int slot_id, |
41 const std::string& configured_identity) | |
38 : service_path(network_path), | 42 : service_path(network_path), |
39 cert_config_type(config_type), | 43 cert_config_type(config_type), |
40 pkcs11_id(cert_id), | 44 pkcs11_id(cert_id), |
41 key_slot_id(slot_id) {} | 45 key_slot_id(slot_id), |
46 identity(configured_identity) {} | |
42 | 47 |
43 std::string service_path; | 48 std::string service_path; |
44 client_cert::ConfigType cert_config_type; | 49 client_cert::ConfigType cert_config_type; |
45 | 50 |
46 // The id of the matching certificate or empty if no certificate was found. | 51 // The id of the matching certificate or empty if no certificate was found. |
47 std::string pkcs11_id; | 52 std::string pkcs11_id; |
48 | 53 |
49 // The id of the slot containing the certificate and the private key. | 54 // The id of the slot containing the certificate and the private key. |
50 int key_slot_id; | 55 int key_slot_id; |
56 | |
57 // The ONC WiFi.EAP.Identity field can contain variables like | |
58 // ${CERT_SAN_EMAIL} which are expanded by ClientCertResolver. | |
59 // |identity| stores a copy of this string after the substitution | |
stevenjb
2016/03/02 22:34:59
s/string/property/? (I assume 'string' refers to W
| |
60 // has been done. | |
61 std::string identity; | |
51 }; | 62 }; |
52 | 63 |
53 typedef std::vector<ClientCertResolver::NetworkAndMatchingCert> | 64 typedef std::vector<ClientCertResolver::NetworkAndMatchingCert> |
54 NetworkCertMatches; | 65 NetworkCertMatches; |
55 | 66 |
56 namespace { | 67 namespace { |
57 | 68 |
58 // Returns true if |vector| contains |value|. | 69 // Returns true if |vector| contains |value|. |
59 template <class T> | 70 template <class T> |
60 bool ContainsValue(const std::vector<T>& vector, const T& value) { | 71 bool ContainsValue(const std::vector<T>& vector, const T& value) { |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
190 | 201 |
191 for (std::vector<NetworkAndCertPattern>::const_iterator it = | 202 for (std::vector<NetworkAndCertPattern>::const_iterator it = |
192 networks->begin(); | 203 networks->begin(); |
193 it != networks->end(); ++it) { | 204 it != networks->end(); ++it) { |
194 std::vector<CertAndIssuer>::iterator cert_it = | 205 std::vector<CertAndIssuer>::iterator cert_it = |
195 std::find_if(client_certs.begin(), | 206 std::find_if(client_certs.begin(), |
196 client_certs.end(), | 207 client_certs.end(), |
197 MatchCertWithPattern(it->cert_config.pattern)); | 208 MatchCertWithPattern(it->cert_config.pattern)); |
198 std::string pkcs11_id; | 209 std::string pkcs11_id; |
199 int slot_id = -1; | 210 int slot_id = -1; |
211 std::string identity; | |
212 | |
200 if (cert_it == client_certs.end()) { | 213 if (cert_it == client_certs.end()) { |
201 VLOG(1) << "Couldn't find a matching client cert for network " | 214 VLOG(1) << "Couldn't find a matching client cert for network " |
202 << it->service_path; | 215 << it->service_path; |
203 // Leave |pkcs11_id| empty to indicate that no cert was found for this | 216 // Leave |pkcs11_id| empty to indicate that no cert was found for this |
204 // network. | 217 // network. |
205 } else { | 218 } else { |
206 pkcs11_id = | 219 pkcs11_id = |
207 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); | 220 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); |
208 if (pkcs11_id.empty()) { | 221 if (pkcs11_id.empty()) { |
209 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; | 222 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; |
210 // So far this error is not expected to happen. We can just continue, in | 223 // So far this error is not expected to happen. We can just continue, in |
211 // the worst case the user can remove the problematic cert. | 224 // the worst case the user can remove the problematic cert. |
212 continue; | 225 continue; |
213 } | 226 } |
227 | |
228 // If the policy specifies an identity containing ${CERT_SAN_xxx}, | |
229 // see if the cert contains a suitable subjectAltName that can be | |
230 // stuffed into the shill properties. | |
231 identity = it->cert_config.policy_identity; | |
232 std::vector<std::string> names; | |
233 | |
234 net::x509_util::GetRFC822SubjectAltNames( | |
235 (*cert_it->cert).os_cert_handle(), &names); | |
Ryan Sleevi
2016/03/02 21:57:29
cert_it->cert->os_cert_handle
Kevin Cernekee
2016/03/02 22:57:43
Done.
| |
236 if (!names.empty()) { | |
237 if (identity.find(::onc::substitutes::kCertSANEmail, 0) != | |
238 std::string::npos) { | |
Ryan Sleevi
2016/03/02 21:57:29
This is still quite inefficient.
size_t email_off
stevenjb
2016/03/02 22:34:59
+1 to suggested optimization. I am less concerned
Kevin Cernekee
2016/03/02 22:57:43
Done.
| |
239 base::ReplaceSubstringsAfterOffset( | |
240 &identity, 0, ::onc::substitutes::kCertSANEmail, names.at(0)); | |
Ryan Sleevi
2016/03/02 21:57:28
We strongly discourage .at() [it throws] and stron
stevenjb
2016/03/02 22:34:59
+1
Kevin Cernekee
2016/03/02 22:57:43
Done.
| |
241 } | |
242 } | |
243 net::x509_util::GetUPNSubjectAltNames((*cert_it->cert).os_cert_handle(), | |
244 &names); | |
245 if (!names.empty()) { | |
246 if (identity.find(::onc::substitutes::kCertSANUPN, 0) != | |
247 std::string::npos) { | |
248 base::ReplaceSubstringsAfterOffset( | |
249 &identity, 0, ::onc::substitutes::kCertSANUPN, names.at(0)); | |
250 } | |
251 } | |
214 } | 252 } |
253 | |
215 matches->push_back(ClientCertResolver::NetworkAndMatchingCert( | 254 matches->push_back(ClientCertResolver::NetworkAndMatchingCert( |
216 it->service_path, it->cert_config.location, pkcs11_id, slot_id)); | 255 it->service_path, it->cert_config.location, pkcs11_id, slot_id, |
256 identity)); | |
217 } | 257 } |
218 } | 258 } |
219 | 259 |
220 void LogError(const std::string& service_path, | 260 void LogError(const std::string& service_path, |
221 const std::string& dbus_error_name, | 261 const std::string& dbus_error_name, |
222 const std::string& dbus_error_message) { | 262 const std::string& dbus_error_message) { |
223 network_handler::ShillErrorCallbackFunction( | 263 network_handler::ShillErrorCallbackFunction( |
224 "ClientCertResolver.SetProperties failed", | 264 "ClientCertResolver.SetProperties failed", |
225 service_path, | 265 service_path, |
226 network_handler::ErrorCallback(), | 266 network_handler::ErrorCallback(), |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 VLOG(1) << "Configuring certificate of network " << it->service_path; | 535 VLOG(1) << "Configuring certificate of network " << it->service_path; |
496 base::DictionaryValue shill_properties; | 536 base::DictionaryValue shill_properties; |
497 if (it->pkcs11_id.empty()) { | 537 if (it->pkcs11_id.empty()) { |
498 client_cert::SetEmptyShillProperties(it->cert_config_type, | 538 client_cert::SetEmptyShillProperties(it->cert_config_type, |
499 &shill_properties); | 539 &shill_properties); |
500 } else { | 540 } else { |
501 client_cert::SetShillProperties(it->cert_config_type, | 541 client_cert::SetShillProperties(it->cert_config_type, |
502 it->key_slot_id, | 542 it->key_slot_id, |
503 it->pkcs11_id, | 543 it->pkcs11_id, |
504 &shill_properties); | 544 &shill_properties); |
545 if (!it->identity.empty()) { | |
546 shill_properties.SetStringWithoutPathExpansion( | |
547 shill::kEapIdentityProperty, it->identity); | |
548 } | |
Ryan Sleevi
2016/03/02 21:57:28
So, I tried to highlight it to you with the sugges
stevenjb
2016/03/02 22:34:59
That sounds to me like a security issue we should
Ryan Sleevi
2016/03/02 22:46:17
Mostly, I don't know to what extent the identity i
Kevin Cernekee
2016/03/02 22:57:43
Is there a standard way to truncate or detect stri
| |
505 } | 549 } |
506 network_properties_changed_ = true; | 550 network_properties_changed_ = true; |
507 DBusThreadManager::Get()->GetShillServiceClient()-> | 551 DBusThreadManager::Get()->GetShillServiceClient()-> |
508 SetProperties(dbus::ObjectPath(it->service_path), | 552 SetProperties(dbus::ObjectPath(it->service_path), |
509 shill_properties, | 553 shill_properties, |
510 base::Bind(&base::DoNothing), | 554 base::Bind(&base::DoNothing), |
511 base::Bind(&LogError, it->service_path)); | 555 base::Bind(&LogError, it->service_path)); |
512 network_state_handler_->RequestUpdateForNetwork(it->service_path); | 556 network_state_handler_->RequestUpdateForNetwork(it->service_path); |
513 } | 557 } |
514 if (queued_networks_to_resolve_.empty()) | 558 if (queued_networks_to_resolve_.empty()) |
(...skipping 11 matching lines...) Expand all Loading... | |
526 FOR_EACH_OBSERVER(Observer, observers_, ResolveRequestCompleted(changed)); | 570 FOR_EACH_OBSERVER(Observer, observers_, ResolveRequestCompleted(changed)); |
527 } | 571 } |
528 | 572 |
529 base::Time ClientCertResolver::Now() const { | 573 base::Time ClientCertResolver::Now() const { |
530 if (testing_clock_) | 574 if (testing_clock_) |
531 return testing_clock_->Now(); | 575 return testing_clock_->Now(); |
532 return base::Time::Now(); | 576 return base::Time::Now(); |
533 } | 577 } |
534 | 578 |
535 } // namespace chromeos | 579 } // namespace chromeos |
OLD | NEW |