Revert 248827 "android: Migrate old content readback to use asyn..."
[chromium-blink-merge.git] / chromeos / network / client_cert_util.cc
blobc62c9ab17aace9c6b295ed85c423f7f3e2eaa4a6
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/scoped_nss_types.h"
20 #include "net/cert/x509_cert_types.h"
21 #include "net/cert/x509_certificate.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 namespace chromeos {
26 namespace client_cert {
28 namespace {
30 // Functor to filter out non-matching issuers.
31 class IssuerFilter {
32 public:
33 explicit IssuerFilter(const IssuerSubjectPattern& issuer)
34 : issuer_(issuer) {}
35 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
36 return !CertPrincipalMatches(issuer_, cert.get()->issuer());
38 private:
39 const IssuerSubjectPattern& issuer_;
42 // Functor to filter out non-matching subjects.
43 class SubjectFilter {
44 public:
45 explicit SubjectFilter(const IssuerSubjectPattern& subject)
46 : subject_(subject) {}
47 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
48 return !CertPrincipalMatches(subject_, cert.get()->subject());
50 private:
51 const IssuerSubjectPattern& subject_;
54 // Functor to filter out certs that don't have private keys, or are invalid.
55 class PrivateKeyFilter {
56 public:
57 explicit PrivateKeyFilter(net::CertDatabase* cert_db) : cert_db_(cert_db) {}
58 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
59 return cert_db_->CheckUserCert(cert.get()) != net::OK;
61 private:
62 net::CertDatabase* cert_db_;
65 // Functor to filter out certs that don't have an issuer in the associated
66 // IssuerCAPEMs list.
67 class IssuerCaFilter {
68 public:
69 explicit IssuerCaFilter(const std::vector<std::string>& issuer_ca_pems)
70 : issuer_ca_pems_(issuer_ca_pems) {}
71 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
72 // Find the certificate issuer for each certificate.
73 // TODO(gspencer): this functionality should be available from
74 // X509Certificate or NSSCertDatabase.
75 net::ScopedCERTCertificate issuer_cert(CERT_FindCertIssuer(
76 cert.get()->os_cert_handle(), PR_Now(), certUsageAnyCA));
78 if (!issuer_cert)
79 return true;
81 std::string pem_encoded;
82 if (!net::X509Certificate::GetPEMEncoded(issuer_cert.get(),
83 &pem_encoded)) {
84 LOG(ERROR) << "Couldn't PEM-encode certificate.";
85 return true;
88 return (std::find(issuer_ca_pems_.begin(), issuer_ca_pems_.end(),
89 pem_encoded) ==
90 issuer_ca_pems_.end());
92 private:
93 const std::vector<std::string>& issuer_ca_pems_;
96 std::string GetStringFromDictionary(const base::DictionaryValue& dict,
97 const std::string& key) {
98 std::string s;
99 dict.GetStringWithoutPathExpansion(key, &s);
100 return s;
103 } // namespace
105 // Returns true only if any fields set in this pattern match exactly with
106 // similar fields in the principal. If organization_ or organizational_unit_
107 // are set, then at least one of the organizations or units in the principal
108 // must match.
109 bool CertPrincipalMatches(const IssuerSubjectPattern& pattern,
110 const net::CertPrincipal& principal) {
111 if (!pattern.common_name().empty() &&
112 pattern.common_name() != principal.common_name) {
113 return false;
116 if (!pattern.locality().empty() &&
117 pattern.locality() != principal.locality_name) {
118 return false;
121 if (!pattern.organization().empty()) {
122 if (std::find(principal.organization_names.begin(),
123 principal.organization_names.end(),
124 pattern.organization()) ==
125 principal.organization_names.end()) {
126 return false;
130 if (!pattern.organizational_unit().empty()) {
131 if (std::find(principal.organization_unit_names.begin(),
132 principal.organization_unit_names.end(),
133 pattern.organizational_unit()) ==
134 principal.organization_unit_names.end()) {
135 return false;
139 return true;
142 scoped_refptr<net::X509Certificate> GetCertificateMatch(
143 const CertificatePattern& pattern,
144 const net::CertificateList& all_certs) {
145 typedef std::list<scoped_refptr<net::X509Certificate> > CertificateStlList;
147 // Start with all the certs, and narrow it down from there.
148 CertificateStlList matching_certs;
150 if (all_certs.empty())
151 return NULL;
153 for (net::CertificateList::const_iterator iter = all_certs.begin();
154 iter != all_certs.end(); ++iter) {
155 matching_certs.push_back(*iter);
158 // Strip off any certs that don't have the right issuer and/or subject.
159 if (!pattern.issuer().Empty()) {
160 matching_certs.remove_if(IssuerFilter(pattern.issuer()));
161 if (matching_certs.empty())
162 return NULL;
165 if (!pattern.subject().Empty()) {
166 matching_certs.remove_if(SubjectFilter(pattern.subject()));
167 if (matching_certs.empty())
168 return NULL;
171 if (!pattern.issuer_ca_pems().empty()) {
172 matching_certs.remove_if(IssuerCaFilter(pattern.issuer_ca_pems()));
173 if (matching_certs.empty())
174 return NULL;
177 // Eliminate any certs that don't have private keys associated with
178 // them. The CheckUserCert call in the filter is a little slow (because of
179 // underlying PKCS11 calls), so we do this last to reduce the number of times
180 // we have to call it.
181 PrivateKeyFilter private_filter(net::CertDatabase::GetInstance());
182 matching_certs.remove_if(private_filter);
184 if (matching_certs.empty())
185 return NULL;
187 // We now have a list of certificates that match the pattern we're
188 // looking for. Now we find the one with the latest start date.
189 scoped_refptr<net::X509Certificate> latest(NULL);
191 // Iterate over the rest looking for the one that was issued latest.
192 for (CertificateStlList::iterator iter = matching_certs.begin();
193 iter != matching_certs.end(); ++iter) {
194 if (!latest.get() || (*iter)->valid_start() > latest->valid_start())
195 latest = *iter;
198 return latest;
201 void SetShillProperties(const client_cert::ConfigType cert_config_type,
202 const std::string& tpm_slot,
203 const std::string& tpm_pin,
204 const std::string* pkcs11_id,
205 base::DictionaryValue* properties) {
206 const char* tpm_pin_property = NULL;
207 switch (cert_config_type) {
208 case CONFIG_TYPE_NONE: {
209 return;
211 case CONFIG_TYPE_OPENVPN: {
212 tpm_pin_property = shill::kOpenVPNPinProperty;
213 if (pkcs11_id) {
214 properties->SetStringWithoutPathExpansion(
215 shill::kOpenVPNClientCertIdProperty, *pkcs11_id);
217 break;
219 case CONFIG_TYPE_IPSEC: {
220 tpm_pin_property = shill::kL2tpIpsecPinProperty;
221 if (!tpm_slot.empty()) {
222 properties->SetStringWithoutPathExpansion(
223 shill::kL2tpIpsecClientCertSlotProperty, tpm_slot);
225 if (pkcs11_id) {
226 properties->SetStringWithoutPathExpansion(
227 shill::kL2tpIpsecClientCertIdProperty, *pkcs11_id);
229 break;
231 case CONFIG_TYPE_EAP: {
232 tpm_pin_property = shill::kEapPinProperty;
233 if (pkcs11_id) {
234 // Shill requires both CertID and KeyID for TLS connections, despite the
235 // fact that by convention they are the same ID.
236 properties->SetStringWithoutPathExpansion(shill::kEapCertIdProperty,
237 *pkcs11_id);
238 properties->SetStringWithoutPathExpansion(shill::kEapKeyIdProperty,
239 *pkcs11_id);
241 break;
244 DCHECK(tpm_pin_property);
245 if (!tpm_pin.empty())
246 properties->SetStringWithoutPathExpansion(tpm_pin_property, tpm_pin);
249 bool IsCertificateConfigured(const client_cert::ConfigType cert_config_type,
250 const base::DictionaryValue& service_properties) {
251 // VPN certificate properties are read from the Provider dictionary.
252 const base::DictionaryValue* provider_properties = NULL;
253 service_properties.GetDictionaryWithoutPathExpansion(
254 shill::kProviderProperty, &provider_properties);
255 switch (cert_config_type) {
256 case CONFIG_TYPE_NONE:
257 return true;
258 case CONFIG_TYPE_OPENVPN:
259 // OpenVPN generally requires a passphrase and we don't know whether or
260 // not one is required, so always return false here.
261 return false;
262 case CONFIG_TYPE_IPSEC:
263 // IPSec may require a passphrase, so return false here also.
264 return false;
265 case CONFIG_TYPE_EAP: {
266 std::string cert_id = GetStringFromDictionary(
267 service_properties, shill::kEapCertIdProperty);
268 std::string key_id = GetStringFromDictionary(
269 service_properties, shill::kEapKeyIdProperty);
270 std::string identity = GetStringFromDictionary(
271 service_properties, shill::kEapIdentityProperty);
272 return !cert_id.empty() && !key_id.empty() && !identity.empty();
275 NOTREACHED();
276 return false;
279 } // namespace client_cert
281 } // namespace chromeos