13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chromeos/network/client_cert_resolver.h"
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <cert.h>
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <certt.h>  // for (SECCertUsageEnum) certUsageAnyCA
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <pk11pub.h>
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <algorithm>
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <string>
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/location.h"
163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/stl_util.h"
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/task_runner.h"
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/threading/worker_pool.h"
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/time/time.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chromeos/cert_loader.h"
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chromeos/dbus/shill_service_client.h"
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chromeos/network/managed_network_configuration_handler.h"
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chromeos/network/network_state.h"
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "components/onc/onc_constants.h"
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "dbus/object_path.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/cert/scoped_nss_types.h"
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "net/cert/x509_certificate.h"
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace chromeos {
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Describes a network |network_path| for which a matching certificate |cert_id|
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// was found or for which no certificate was found (|cert_id| will be empty).
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct ClientCertResolver::NetworkAndMatchingCert {
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NetworkAndMatchingCert(const std::string& network_path,
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                         client_cert::ConfigType config_type,
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         const std::string& cert_id,
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         int slot_id)
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : service_path(network_path),
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        cert_config_type(config_type),
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        pkcs11_id(cert_id),
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        key_slot_id(slot_id) {}
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string service_path;
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  client_cert::ConfigType cert_config_type;
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // The id of the matching certificate or empty if no certificate was found.
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string pkcs11_id;
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The id of the slot containing the certificate and the private key.
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int key_slot_id;
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)typedef std::vector<ClientCertResolver::NetworkAndMatchingCert>
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NetworkCertMatches;
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace {
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Returns true if |vector| contains |value|.
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)template <class T>
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ContainsValue(const std::vector<T>& vector, const T& value) {
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return find(vector.begin(), vector.end(), value) != vector.end();
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Returns true if a private key for certificate |cert| is installed.
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool HasPrivateKey(const net::X509Certificate& cert) {
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  PK11SlotInfo* slot = PK11_KeyForCertExists(cert.os_cert_handle(), NULL, NULL);
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!slot)
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  PK11_FreeSlot(slot);
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Describes a certificate which is issued by |issuer| (encoded as PEM).
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct CertAndIssuer {
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CertAndIssuer(const scoped_refptr<net::X509Certificate>& certificate,
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                const std::string& issuer)
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : cert(certificate),
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        pem_encoded_issuer(issuer) {}
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_refptr<net::X509Certificate> cert;
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string pem_encoded_issuer;
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool CompareCertExpiration(const CertAndIssuer& a,
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           const CertAndIssuer& b) {
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (a.cert->valid_expiry() > b.cert->valid_expiry());
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Describes a network that is configured with the certificate pattern
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// |client_cert_pattern|.
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct NetworkAndCertPattern {
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NetworkAndCertPattern(const std::string& network_path,
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        const client_cert::ClientCertConfig& client_cert_config)
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : service_path(network_path),
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        cert_config(client_cert_config) {}
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string service_path;
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  client_cert::ClientCertConfig cert_config;
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// A unary predicate that returns true if the given CertAndIssuer matches the
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// given certificate pattern.
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct MatchCertWithPattern {
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  explicit MatchCertWithPattern(const CertificatePattern& cert_pattern)
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      : pattern(cert_pattern) {}
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool operator()(const CertAndIssuer& cert_and_issuer) {
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!pattern.issuer().Empty() &&
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        !client_cert::CertPrincipalMatches(pattern.issuer(),
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                           cert_and_issuer.cert->issuer())) {
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return false;
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!pattern.subject().Empty() &&
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        !client_cert::CertPrincipalMatches(pattern.subject(),
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                           cert_and_issuer.cert->subject())) {
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return false;
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::vector<std::string>& issuer_ca_pems = pattern.issuer_ca_pems();
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!issuer_ca_pems.empty() &&
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        !ContainsValue(issuer_ca_pems, cert_and_issuer.pem_encoded_issuer)) {
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return false;
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return true;
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const CertificatePattern pattern;
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::vector<CertAndIssuer> CreateSortedCertAndIssuerList(
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const net::CertificateList& certs) {
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Filter all client certs and determines each certificate's issuer, which is
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // required for the pattern matching.
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<CertAndIssuer> client_certs;
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (net::CertificateList::const_iterator it = certs.begin();
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       it != certs.end(); ++it) {
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const net::X509Certificate& cert = **it;
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (cert.valid_expiry().is_null() || cert.HasExpired() ||
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        !HasPrivateKey(cert)) {
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    net::ScopedCERTCertificate issuer_handle(
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        CERT_FindCertIssuer(cert.os_cert_handle(), PR_Now(), certUsageAnyCA));
146d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!issuer_handle) {
147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      LOG(ERROR) << "Couldn't find an issuer.";
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      continue;
149d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    scoped_refptr<net::X509Certificate> issuer =
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        net::X509Certificate::CreateFromHandle(
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            issuer_handle.get(),
153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            net::X509Certificate::OSCertHandles() /* no intermediate certs */);
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!issuer.get()) {
155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      LOG(ERROR) << "Couldn't create issuer cert.";
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string pem_encoded_issuer;
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!net::X509Certificate::GetPEMEncoded(issuer->os_cert_handle(),
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                             &pem_encoded_issuer)) {
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      LOG(ERROR) << "Couldn't PEM-encode certificate.";
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    client_certs.push_back(CertAndIssuer(*it, pem_encoded_issuer));
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration);
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return client_certs;
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Searches for matches between |networks| and |certs| and writes matches to
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// |matches|. Because this calls NSS functions and is potentially slow, it must
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// be run on a worker thread.
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FindCertificateMatches(const net::CertificateList& certs,
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            std::vector<NetworkAndCertPattern>* networks,
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            NetworkCertMatches* matches) {
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<CertAndIssuer> client_certs(CreateSortedCertAndIssuerList(certs));
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<NetworkAndCertPattern>::const_iterator it =
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           networks->begin();
1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       it != networks->end(); ++it) {
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    std::vector<CertAndIssuer>::iterator cert_it =
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        std::find_if(client_certs.begin(),
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     client_certs.end(),
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     MatchCertWithPattern(it->cert_config.pattern));
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    std::string pkcs11_id;
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int slot_id = -1;
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (cert_it == client_certs.end()) {
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      VLOG(1) << "Couldn't find a matching client cert for network "
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              << it->service_path;
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Leave |pkcs11_id| empty to indicate that no cert was found for this
192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // network.
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      pkcs11_id =
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id);
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (pkcs11_id.empty()) {
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        LOG(ERROR) << "Couldn't determine PKCS#11 ID.";
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        // So far this error is not expected to happen. We can just continue, in
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        // the worst case the user can remove the problematic cert.
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        continue;
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
2023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    matches->push_back(ClientCertResolver::NetworkAndMatchingCert(
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        it->service_path, it->cert_config.location, pkcs11_id, slot_id));
2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void LogError(const std::string& service_path,
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              const std::string& dbus_error_name,
2103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              const std::string& dbus_error_message) {
2113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  network_handler::ShillErrorCallbackFunction(
2123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      "ClientCertResolver.SetProperties failed",
2133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      service_path,
2143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      network_handler::ErrorCallback(),
2153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      dbus_error_name,
2163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      dbus_error_message);
2173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ClientCertificatesLoaded() {
2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!CertLoader::Get()->certificates_loaded()) {
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    VLOG(1) << "Certificates not loaded yet.";
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!CertLoader::Get()->IsHardwareBacked()) {
2253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    VLOG(1) << "TPM is not available.";
2263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // namespace
2323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)ClientCertResolver::ClientCertResolver()
2343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    : network_state_handler_(NULL),
2353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      managed_network_config_handler_(NULL),
2363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      weak_ptr_factory_(this) {
2373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)ClientCertResolver::~ClientCertResolver() {
2403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (network_state_handler_)
2413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    network_state_handler_->RemoveObserver(this, FROM_HERE);
2423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (CertLoader::IsInitialized())
2433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CertLoader::Get()->RemoveObserver(this);
2443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (managed_network_config_handler_)
2453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    managed_network_config_handler_->RemoveObserver(this);
2463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientCertResolver::Init(
2493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NetworkStateHandler* network_state_handler,
2503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ManagedNetworkConfigurationHandler* managed_network_config_handler) {
2513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(network_state_handler);
2523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  network_state_handler_ = network_state_handler;
2533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  network_state_handler_->AddObserver(this, FROM_HERE);
2543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(managed_network_config_handler);
2563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  managed_network_config_handler_ = managed_network_config_handler;
2573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  managed_network_config_handler_->AddObserver(this);
2583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CertLoader::Get()->AddObserver(this);
2603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientCertResolver::SetSlowTaskRunnerForTest(
2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const scoped_refptr<base::TaskRunner>& task_runner) {
2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  slow_task_runner_for_test_ = task_runner;
2653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// static
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ClientCertResolver::ResolveCertificatePatternSync(
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const client_cert::ConfigType client_cert_type,
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const CertificatePattern& pattern,
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::DictionaryValue* shill_properties) {
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Prepare and sort the list of known client certs.
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<CertAndIssuer> client_certs(
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CreateSortedCertAndIssuerList(CertLoader::Get()->cert_list()));
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Search for a certificate matching the pattern.
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<CertAndIssuer>::iterator cert_it = std::find_if(
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      client_certs.begin(), client_certs.end(), MatchCertWithPattern(pattern));
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (cert_it == client_certs.end()) {
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    VLOG(1) << "Couldn't find a matching client cert";
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    client_cert::SetEmptyShillProperties(client_cert_type, shill_properties);
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int slot_id = -1;
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string pkcs11_id =
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CertLoader::GetPkcs11IdAndSlotForCert(*cert_it->cert, &slot_id);
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (pkcs11_id.empty()) {
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Couldn't determine PKCS#11 ID.";
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // So far this error is not expected to happen. We can just continue, in
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // the worst case the user can remove the problematic cert.
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  client_cert::SetShillProperties(
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      client_cert_type, slot_id, pkcs11_id, shill_properties);
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientCertResolver::NetworkListChanged() {
3013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  VLOG(2) << "NetworkListChanged.";
3023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClientCertificatesLoaded())
3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Configure only networks that were not configured before.
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // We'll drop networks from |resolved_networks_|, which are not known anymore.
3073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::set<std::string> old_resolved_networks;
3083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  old_resolved_networks.swap(resolved_networks_);
3093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  NetworkStateHandler::NetworkStateList networks;
311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  network_state_handler_->GetNetworkListByType(
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      NetworkTypePattern::Default(),
313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      true /* configured_only */,
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      false /* visible_only */,
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      0 /* no limit */,
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      &networks);
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  NetworkStateHandler::NetworkStateList networks_to_check;
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (NetworkStateHandler::NetworkStateList::const_iterator it =
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           networks.begin(); it != networks.end(); ++it) {
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& service_path = (*it)->path();
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (ContainsKey(old_resolved_networks, service_path)) {
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      resolved_networks_.insert(service_path);
3243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    networks_to_check.push_back(*it);
3273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ResolveNetworks(networks_to_check);
3303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientCertResolver::OnCertificatesLoaded(
3333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const net::CertificateList& cert_list,
3343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    bool initial_load) {
3353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  VLOG(2) << "OnCertificatesLoaded.";
3363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClientCertificatesLoaded())
3373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
3383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Compare all networks with all certificates.
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  NetworkStateHandler::NetworkStateList networks;
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  network_state_handler_->GetNetworkListByType(
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      NetworkTypePattern::Default(),
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      true /* configured_only */,
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      false /* visible_only */,
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      0 /* no limit */,
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      &networks);
3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ResolveNetworks(networks);
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientCertResolver::PolicyApplied(const std::string& service_path) {
3503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  VLOG(2) << "PolicyApplied " << service_path;
3513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ClientCertificatesLoaded())
3523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
3533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Compare this network with all certificates.
354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const NetworkState* network =
355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      network_state_handler_->GetNetworkStateFromServicePath(
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          service_path, true /* configured_only */);
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!network) {
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "service path '" << service_path << "' unknown.";
3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
3603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  NetworkStateHandler::NetworkStateList networks;
3623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  networks.push_back(network);
3633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ResolveNetworks(networks);
3643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ClientCertResolver::ResolveNetworks(
367f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const NetworkStateHandler::NetworkStateList& networks) {
3683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_ptr<std::vector<NetworkAndCertPattern> > networks_with_pattern(
3693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      new std::vector<NetworkAndCertPattern>);
3703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Filter networks with ClientCertPattern. As ClientCertPatterns can only be
3723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // set by policy, we check there.
373f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (NetworkStateHandler::NetworkStateList::const_iterator it =
374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           networks.begin(); it != networks.end(); ++it) {
375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const NetworkState* network = *it;
3763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // In any case, don't check this network again in NetworkListChanged.
3783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    resolved_networks_.insert(network->path());
3793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // If this network is not configured, it cannot have a ClientCertPattern.
381116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (network->profile_path().empty())
3823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
3833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::DictionaryValue* policy =
3853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        managed_network_config_handler_->FindPolicyByGuidAndProfile(
3863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            network->guid(), network->profile_path());
3873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!policy) {
3893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      VLOG(1) << "The policy for network " << network->path() << " with GUID "
3903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              << network->guid() << " is not available yet.";
3913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // Skip this network for now. Once the policy is loaded, PolicyApplied()
3923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // will retry.
3933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
3943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
3953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    VLOG(2) << "Inspecting network " << network->path();
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    client_cert::ClientCertConfig cert_config;
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    OncToClientCertConfig(*policy, &cert_config);
3993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Skip networks that don't have a ClientCertPattern.
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (cert_config.client_cert_type != ::onc::client_cert::kPattern)
4023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
4033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    networks_with_pattern->push_back(
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        NetworkAndCertPattern(network->path(), cert_config));
4063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (networks_with_pattern->empty())
4083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
4093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  VLOG(2) << "Start task for resolving client cert patterns.";
4113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::TaskRunner* task_runner = slow_task_runner_for_test_.get();
4123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!task_runner)
4131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    task_runner =
4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::WorkerPool::GetTaskRunner(true /* task is slow */).get();
4153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NetworkCertMatches* matches = new NetworkCertMatches;
4173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  task_runner->PostTaskAndReply(
4183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      FROM_HERE,
4193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&FindCertificateMatches,
4203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 CertLoader::Get()->cert_list(),
4213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 base::Owned(networks_with_pattern.release()),
4223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 matches),
4233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&ClientCertResolver::ConfigureCertificates,
4243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
4253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 base::Owned(matches)));
4263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientCertResolver::ConfigureCertificates(NetworkCertMatches* matches) {
4293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (NetworkCertMatches::const_iterator it = matches->begin();
4303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       it != matches->end(); ++it) {
4313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    VLOG(1) << "Configuring certificate of network " << it->service_path;
4323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::DictionaryValue shill_properties;
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (it->pkcs11_id.empty()) {
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      client_cert::SetEmptyShillProperties(it->cert_config_type,
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                           &shill_properties);
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      client_cert::SetShillProperties(it->cert_config_type,
4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                      it->key_slot_id,
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                      it->pkcs11_id,
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                      &shill_properties);
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DBusThreadManager::Get()->GetShillServiceClient()->
4433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        SetProperties(dbus::ObjectPath(it->service_path),
4443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        shill_properties,
4453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        base::Bind(&base::DoNothing),
4463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        base::Bind(&LogError, it->service_path));
4473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    network_state_handler_->RequestUpdateForNetwork(it->service_path);
4483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // namespace chromeos
452