cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / chromeos / network / client_cert_util.cc
blobad2bc457b3037ecf7178609cd3084bdde9db99b1
1 // Copyright (c) 2012 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/client_cert_util.h"
7 #include <cert.h>
8 #include <pk11pub.h>
10 #include <list>
11 #include <string>
12 #include <vector>
14 #include "base/values.h"
15 #include "chromeos/network/certificate_pattern.h"
16 #include "net/base/net_errors.h"
17 #include "net/cert/cert_database.h"
18 #include "net/cert/nss_cert_database.h"
19 #include "net/cert/x509_cert_types.h"
20 #include "net/cert/x509_certificate.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
23 namespace chromeos {
25 namespace client_cert {
27 namespace {
29 // Functor to filter out non-matching issuers.
30 class IssuerFilter {
31 public:
32 explicit IssuerFilter(const IssuerSubjectPattern& issuer)
33 : issuer_(issuer) {}
34 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
35 return !CertPrincipalMatches(issuer_, cert.get()->issuer());
37 private:
38 const IssuerSubjectPattern& issuer_;
41 // Functor to filter out non-matching subjects.
42 class SubjectFilter {
43 public:
44 explicit SubjectFilter(const IssuerSubjectPattern& subject)
45 : subject_(subject) {}
46 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
47 return !CertPrincipalMatches(subject_, cert.get()->subject());
49 private:
50 const IssuerSubjectPattern& subject_;
53 // Functor to filter out certs that don't have private keys, or are invalid.
54 class PrivateKeyFilter {
55 public:
56 explicit PrivateKeyFilter(net::CertDatabase* cert_db) : cert_db_(cert_db) {}
57 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
58 return cert_db_->CheckUserCert(cert.get()) != net::OK;
60 private:
61 net::CertDatabase* cert_db_;
64 // Functor to filter out certs that don't have an issuer in the associated
65 // IssuerCAPEMs list.
66 class IssuerCaFilter {
67 public:
68 explicit IssuerCaFilter(const std::vector<std::string>& issuer_ca_pems)
69 : issuer_ca_pems_(issuer_ca_pems) {}
70 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
71 // Find the certificate issuer for each certificate.
72 // TODO(gspencer): this functionality should be available from
73 // X509Certificate or NSSCertDatabase.
74 CERTCertificate* issuer_cert = CERT_FindCertIssuer(
75 cert.get()->os_cert_handle(), PR_Now(), certUsageAnyCA);
77 if (!issuer_cert)
78 return true;
80 std::string pem_encoded;
81 if (!net::X509Certificate::GetPEMEncoded(issuer_cert, &pem_encoded)) {
82 LOG(ERROR) << "Couldn't PEM-encode certificate.";
83 return true;
86 return (std::find(issuer_ca_pems_.begin(), issuer_ca_pems_.end(),
87 pem_encoded) ==
88 issuer_ca_pems_.end());
90 private:
91 const std::vector<std::string>& issuer_ca_pems_;
94 } // namespace
96 // Returns true only if any fields set in this pattern match exactly with
97 // similar fields in the principal. If organization_ or organizational_unit_
98 // are set, then at least one of the organizations or units in the principal
99 // must match.
100 bool CertPrincipalMatches(const IssuerSubjectPattern& pattern,
101 const net::CertPrincipal& principal) {
102 if (!pattern.common_name().empty() &&
103 pattern.common_name() != principal.common_name) {
104 return false;
107 if (!pattern.locality().empty() &&
108 pattern.locality() != principal.locality_name) {
109 return false;
112 if (!pattern.organization().empty()) {
113 if (std::find(principal.organization_names.begin(),
114 principal.organization_names.end(),
115 pattern.organization()) ==
116 principal.organization_names.end()) {
117 return false;
121 if (!pattern.organizational_unit().empty()) {
122 if (std::find(principal.organization_unit_names.begin(),
123 principal.organization_unit_names.end(),
124 pattern.organizational_unit()) ==
125 principal.organization_unit_names.end()) {
126 return false;
130 return true;
133 scoped_refptr<net::X509Certificate> GetCertificateMatch(
134 const CertificatePattern& pattern) {
135 typedef std::list<scoped_refptr<net::X509Certificate> > CertificateStlList;
137 // Start with all the certs, and narrow it down from there.
138 net::CertificateList all_certs;
139 CertificateStlList matching_certs;
140 net::NSSCertDatabase::GetInstance()->ListCerts(&all_certs);
142 if (all_certs.empty())
143 return NULL;
145 for (net::CertificateList::iterator iter = all_certs.begin();
146 iter != all_certs.end(); ++iter) {
147 matching_certs.push_back(*iter);
150 // Strip off any certs that don't have the right issuer and/or subject.
151 if (!pattern.issuer().Empty()) {
152 matching_certs.remove_if(IssuerFilter(pattern.issuer()));
153 if (matching_certs.empty())
154 return NULL;
157 if (!pattern.subject().Empty()) {
158 matching_certs.remove_if(SubjectFilter(pattern.subject()));
159 if (matching_certs.empty())
160 return NULL;
163 if (!pattern.issuer_ca_pems().empty()) {
164 matching_certs.remove_if(IssuerCaFilter(pattern.issuer_ca_pems()));
165 if (matching_certs.empty())
166 return NULL;
169 // Eliminate any certs that don't have private keys associated with
170 // them. The CheckUserCert call in the filter is a little slow (because of
171 // underlying PKCS11 calls), so we do this last to reduce the number of times
172 // we have to call it.
173 PrivateKeyFilter private_filter(net::CertDatabase::GetInstance());
174 matching_certs.remove_if(private_filter);
176 if (matching_certs.empty())
177 return NULL;
179 // We now have a list of certificates that match the pattern we're
180 // looking for. Now we find the one with the latest start date.
181 scoped_refptr<net::X509Certificate> latest(NULL);
183 // Iterate over the rest looking for the one that was issued latest.
184 for (CertificateStlList::iterator iter = matching_certs.begin();
185 iter != matching_certs.end(); ++iter) {
186 if (!latest.get() || (*iter)->valid_start() > latest->valid_start())
187 latest = *iter;
190 return latest;
193 void SetShillProperties(const client_cert::ConfigType cert_config_type,
194 const std::string& tpm_slot,
195 const std::string& tpm_pin,
196 const std::string* pkcs11_id,
197 base::DictionaryValue* properties) {
198 const char* tpm_pin_property = NULL;
199 switch (cert_config_type) {
200 case CONFIG_TYPE_NONE: {
201 return;
203 case CONFIG_TYPE_OPENVPN: {
204 tpm_pin_property = flimflam::kOpenVPNPinProperty;
205 if (pkcs11_id) {
206 properties->SetStringWithoutPathExpansion(
207 flimflam::kOpenVPNClientCertIdProperty, *pkcs11_id);
209 break;
211 case CONFIG_TYPE_IPSEC: {
212 tpm_pin_property = flimflam::kL2tpIpsecPinProperty;
213 if (!tpm_slot.empty()) {
214 properties->SetStringWithoutPathExpansion(
215 flimflam::kL2tpIpsecClientCertSlotProperty, tpm_slot);
217 if (pkcs11_id) {
218 properties->SetStringWithoutPathExpansion(
219 flimflam::kL2tpIpsecClientCertIdProperty, *pkcs11_id);
221 break;
223 case CONFIG_TYPE_EAP: {
224 tpm_pin_property = flimflam::kEapPinProperty;
225 if (pkcs11_id) {
226 // Shill requires both CertID and KeyID for TLS connections, despite the
227 // fact that by convention they are the same ID.
228 properties->SetStringWithoutPathExpansion(flimflam::kEapCertIdProperty,
229 *pkcs11_id);
230 properties->SetStringWithoutPathExpansion(flimflam::kEapKeyIdProperty,
231 *pkcs11_id);
233 break;
236 DCHECK(tpm_pin_property);
237 if (!tpm_pin.empty())
238 properties->SetStringWithoutPathExpansion(tpm_pin_property, tpm_pin);
241 } // namespace client_cert
243 } // namespace chromeos