Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(674)

Side by Side Diff: chromeos/network/client_cert_resolver.cc

Issue 1717123002: Allow ${CERT_SAN_EMAIL} and ${CERT_SAN_UPN} in the ONC Identity field (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: change to use new GetSubjectAltNameByType() name Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 EAP-TLS Identity field, if it is configured through a policy
58 // substitution.
Ryan Sleevi 2016/02/29 23:51:51 What does this mean?
Kevin Cernekee 2016/03/02 21:38:03 Done.
59 std::string identity;
51 }; 60 };
52 61
53 typedef std::vector<ClientCertResolver::NetworkAndMatchingCert> 62 typedef std::vector<ClientCertResolver::NetworkAndMatchingCert>
54 NetworkCertMatches; 63 NetworkCertMatches;
55 64
56 namespace { 65 namespace {
57 66
58 // Returns true if |vector| contains |value|. 67 // Returns true if |vector| contains |value|.
59 template <class T> 68 template <class T>
60 bool ContainsValue(const std::vector<T>& vector, const T& value) { 69 bool ContainsValue(const std::vector<T>& vector, const T& value) {
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 !CertLoader::IsCertificateHardwareBacked(&cert)) { 180 !CertLoader::IsCertificateHardwareBacked(&cert)) {
172 continue; 181 continue;
173 } 182 }
174 client_certs.push_back(CertAndIssuer(*it, GetPEMEncodedIssuer(cert))); 183 client_certs.push_back(CertAndIssuer(*it, GetPEMEncodedIssuer(cert)));
175 } 184 }
176 185
177 std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration); 186 std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration);
178 return client_certs; 187 return client_certs;
179 } 188 }
180 189
190 // Looks up subjectAlternativeName fields in |cert| that match |type|,
191 // then searches for |var_name| in |identity| and replaces any occurrences
192 // with the SAN.
Ryan Sleevi 2016/02/29 23:51:51 Comment: This comment is somewhat grammatically co
Kevin Cernekee 2016/03/02 21:38:03 Done.
193 void ReplaceSAN(const std::string& var_name,
194 const net::X509Certificate& cert,
195 net::x509_util::SubjectAltNameType type,
196 std::string* identity) {
197 if (identity->find(var_name, 0) == std::string::npos)
198 return;
199 std::vector<std::string> names;
200 net::x509_util::GetSubjectAltNameByType(cert.os_cert_handle(), type, &names);
Ryan Sleevi 2016/02/29 23:51:51 API DESIGN: Why do you return all names, if you're
Kevin Cernekee 2016/03/02 21:38:03 Someday I might care about other names. The calle
Ryan Sleevi 2016/03/02 21:57:28 But today you don't.
201 if (!names.empty())
202 base::ReplaceSubstringsAfterOffset(identity, 0, var_name, names.at(0));
Ryan Sleevi 2016/02/29 23:51:51 DESIGN: Why do you use this method of substitution
Kevin Cernekee 2016/03/02 21:38:03 It mirrors what was done for ${LOGIN_ID} and ${LOG
203 }
204
181 // Searches for matches between |networks| and |certs| and writes matches to 205 // Searches for matches between |networks| and |certs| and writes matches to
182 // |matches|. Because this calls NSS functions and is potentially slow, it must 206 // |matches|. Because this calls NSS functions and is potentially slow, it must
183 // be run on a worker thread. 207 // be run on a worker thread.
184 void FindCertificateMatches(const net::CertificateList& certs, 208 void FindCertificateMatches(const net::CertificateList& certs,
185 std::vector<NetworkAndCertPattern>* networks, 209 std::vector<NetworkAndCertPattern>* networks,
186 base::Time now, 210 base::Time now,
187 NetworkCertMatches* matches) { 211 NetworkCertMatches* matches) {
188 std::vector<CertAndIssuer> client_certs( 212 std::vector<CertAndIssuer> client_certs(
189 CreateSortedCertAndIssuerList(certs, now)); 213 CreateSortedCertAndIssuerList(certs, now));
190 214
191 for (std::vector<NetworkAndCertPattern>::const_iterator it = 215 for (std::vector<NetworkAndCertPattern>::const_iterator it =
192 networks->begin(); 216 networks->begin();
193 it != networks->end(); ++it) { 217 it != networks->end(); ++it) {
194 std::vector<CertAndIssuer>::iterator cert_it = 218 std::vector<CertAndIssuer>::iterator cert_it =
195 std::find_if(client_certs.begin(), 219 std::find_if(client_certs.begin(),
196 client_certs.end(), 220 client_certs.end(),
197 MatchCertWithPattern(it->cert_config.pattern)); 221 MatchCertWithPattern(it->cert_config.pattern));
198 std::string pkcs11_id; 222 std::string pkcs11_id;
199 int slot_id = -1; 223 int slot_id = -1;
224 std::string identity;
225
200 if (cert_it == client_certs.end()) { 226 if (cert_it == client_certs.end()) {
201 VLOG(1) << "Couldn't find a matching client cert for network " 227 VLOG(1) << "Couldn't find a matching client cert for network "
202 << it->service_path; 228 << it->service_path;
203 // Leave |pkcs11_id| empty to indicate that no cert was found for this 229 // Leave |pkcs11_id| empty to indicate that no cert was found for this
204 // network. 230 // network.
205 } else { 231 } else {
206 pkcs11_id = 232 pkcs11_id =
207 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id); 233 CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id);
208 if (pkcs11_id.empty()) { 234 if (pkcs11_id.empty()) {
209 LOG(ERROR) << "Couldn't determine PKCS#11 ID."; 235 LOG(ERROR) << "Couldn't determine PKCS#11 ID.";
210 // So far this error is not expected to happen. We can just continue, in 236 // 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. 237 // the worst case the user can remove the problematic cert.
212 continue; 238 continue;
213 } 239 }
240
241 // If the policy specifies an identity containing ${CERT_SAN_xxx},
242 // see if the cert contains a suitable subjectAltName that we can
243 // stuff into the shill properties.
Ryan Sleevi 2016/02/29 23:51:51 Comment nit: Avoid "we" in comments; it's ambiguou
Kevin Cernekee 2016/03/02 21:38:03 Done.
244 identity = it->cert_config.policy_identity;
245 ReplaceSAN(::onc::substitutes::kCertSANEmail, *cert_it->cert,
246 net::x509_util::SAN_RFC822_NAME, &identity);
Ryan Sleevi 2016/02/29 23:51:51 API DESIGN: When the SAN is absent and it just con
Kevin Cernekee 2016/03/02 21:38:03 Documented this in the bug.
247 ReplaceSAN(::onc::substitutes::kCertSANUPN, *cert_it->cert,
248 net::x509_util::SAN_UPN, &identity);
Ryan Sleevi 2016/02/29 23:51:51 So when there's no match, you leave the |identity|
Kevin Cernekee 2016/03/02 21:38:03 I like it. If a user can't get on the network and
214 } 249 }
250
215 matches->push_back(ClientCertResolver::NetworkAndMatchingCert( 251 matches->push_back(ClientCertResolver::NetworkAndMatchingCert(
216 it->service_path, it->cert_config.location, pkcs11_id, slot_id)); 252 it->service_path, it->cert_config.location, pkcs11_id, slot_id,
253 identity));
217 } 254 }
218 } 255 }
219 256
220 void LogError(const std::string& service_path, 257 void LogError(const std::string& service_path,
221 const std::string& dbus_error_name, 258 const std::string& dbus_error_name,
222 const std::string& dbus_error_message) { 259 const std::string& dbus_error_message) {
223 network_handler::ShillErrorCallbackFunction( 260 network_handler::ShillErrorCallbackFunction(
224 "ClientCertResolver.SetProperties failed", 261 "ClientCertResolver.SetProperties failed",
225 service_path, 262 service_path,
226 network_handler::ErrorCallback(), 263 network_handler::ErrorCallback(),
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 VLOG(1) << "Configuring certificate of network " << it->service_path; 532 VLOG(1) << "Configuring certificate of network " << it->service_path;
496 base::DictionaryValue shill_properties; 533 base::DictionaryValue shill_properties;
497 if (it->pkcs11_id.empty()) { 534 if (it->pkcs11_id.empty()) {
498 client_cert::SetEmptyShillProperties(it->cert_config_type, 535 client_cert::SetEmptyShillProperties(it->cert_config_type,
499 &shill_properties); 536 &shill_properties);
500 } else { 537 } else {
501 client_cert::SetShillProperties(it->cert_config_type, 538 client_cert::SetShillProperties(it->cert_config_type,
502 it->key_slot_id, 539 it->key_slot_id,
503 it->pkcs11_id, 540 it->pkcs11_id,
504 &shill_properties); 541 &shill_properties);
542 if (!it->identity.empty()) {
543 shill_properties.SetStringWithoutPathExpansion(
544 shill::kEapIdentityProperty, it->identity);
545 }
505 } 546 }
506 network_properties_changed_ = true; 547 network_properties_changed_ = true;
507 DBusThreadManager::Get()->GetShillServiceClient()-> 548 DBusThreadManager::Get()->GetShillServiceClient()->
508 SetProperties(dbus::ObjectPath(it->service_path), 549 SetProperties(dbus::ObjectPath(it->service_path),
509 shill_properties, 550 shill_properties,
510 base::Bind(&base::DoNothing), 551 base::Bind(&base::DoNothing),
511 base::Bind(&LogError, it->service_path)); 552 base::Bind(&LogError, it->service_path));
512 network_state_handler_->RequestUpdateForNetwork(it->service_path); 553 network_state_handler_->RequestUpdateForNetwork(it->service_path);
513 } 554 }
514 if (queued_networks_to_resolve_.empty()) 555 if (queued_networks_to_resolve_.empty())
(...skipping 11 matching lines...) Expand all
526 FOR_EACH_OBSERVER(Observer, observers_, ResolveRequestCompleted(changed)); 567 FOR_EACH_OBSERVER(Observer, observers_, ResolveRequestCompleted(changed));
527 } 568 }
528 569
529 base::Time ClientCertResolver::Now() const { 570 base::Time ClientCertResolver::Now() const {
530 if (testing_clock_) 571 if (testing_clock_)
531 return testing_clock_->Now(); 572 return testing_clock_->Now();
532 return base::Time::Now(); 573 return base::Time::Now();
533 } 574 }
534 575
535 } // namespace chromeos 576 } // namespace chromeos
OLDNEW
« no previous file with comments | « no previous file | chromeos/network/client_cert_resolver_unittest.cc » ('j') | chromeos/network/client_cert_resolver_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698