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

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

Issue 22588002: Refactor the client certificate code in chromeos/network/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Corrections after rebase. Created 7 years, 4 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 | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chromeos/network/certificate_pattern_matcher.h"
6
7 #include <cert.h>
8 #include <pk11pub.h>
9
10 #include <list>
11 #include <string>
12 #include <vector>
13
14 #include "chromeos/network/certificate_pattern.h"
15 #include "net/base/net_errors.h"
16 #include "net/cert/cert_database.h"
17 #include "net/cert/nss_cert_database.h"
18 #include "net/cert/x509_cert_types.h"
19 #include "net/cert/x509_certificate.h"
20
21 namespace chromeos {
22
23 namespace {
24
25 // Returns true only if any fields set in this pattern match exactly with
26 // similar fields in the principal. If organization_ or organizational_unit_
27 // are set, then at least one of the organizations or units in the principal
28 // must match.
29 bool CertPrincipalMatches(const IssuerSubjectPattern& pattern,
30 const net::CertPrincipal& principal) {
31 if (!pattern.common_name().empty() &&
32 pattern.common_name() != principal.common_name) {
33 return false;
34 }
35
36 if (!pattern.locality().empty() &&
37 pattern.locality() != principal.locality_name) {
38 return false;
39 }
40
41 if (!pattern.organization().empty()) {
42 if (std::find(principal.organization_names.begin(),
43 principal.organization_names.end(),
44 pattern.organization()) ==
45 principal.organization_names.end()) {
46 return false;
47 }
48 }
49
50 if (!pattern.organizational_unit().empty()) {
51 if (std::find(principal.organization_unit_names.begin(),
52 principal.organization_unit_names.end(),
53 pattern.organizational_unit()) ==
54 principal.organization_unit_names.end()) {
55 return false;
56 }
57 }
58
59 return true;
60 }
61
62 // Functor to filter out non-matching issuers.
63 class IssuerFilter {
64 public:
65 explicit IssuerFilter(const IssuerSubjectPattern& issuer)
66 : issuer_(issuer) {}
67 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
68 return !CertPrincipalMatches(issuer_, cert.get()->issuer());
69 }
70 private:
71 const IssuerSubjectPattern& issuer_;
72 };
73
74 // Functor to filter out non-matching subjects.
75 class SubjectFilter {
76 public:
77 explicit SubjectFilter(const IssuerSubjectPattern& subject)
78 : subject_(subject) {}
79 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
80 return !CertPrincipalMatches(subject_, cert.get()->subject());
81 }
82 private:
83 const IssuerSubjectPattern& subject_;
84 };
85
86 // Functor to filter out certs that don't have private keys, or are invalid.
87 class PrivateKeyFilter {
88 public:
89 explicit PrivateKeyFilter(net::CertDatabase* cert_db) : cert_db_(cert_db) {}
90 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
91 return cert_db_->CheckUserCert(cert.get()) != net::OK;
92 }
93 private:
94 net::CertDatabase* cert_db_;
95 };
96
97 // Functor to filter out certs that don't have an issuer in the associated
98 // IssuerCAPEMs list.
99 class IssuerCaFilter {
100 public:
101 explicit IssuerCaFilter(const std::vector<std::string>& issuer_ca_pems)
102 : issuer_ca_pems_(issuer_ca_pems) {}
103 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const {
104 // Find the certificate issuer for each certificate.
105 // TODO(gspencer): this functionality should be available from
106 // X509Certificate or NSSCertDatabase.
107 CERTCertificate* issuer_cert = CERT_FindCertIssuer(
108 cert.get()->os_cert_handle(), PR_Now(), certUsageAnyCA);
109
110 if (!issuer_cert)
111 return true;
112
113 std::string pem_encoded;
114 if (!net::X509Certificate::GetPEMEncoded(issuer_cert, &pem_encoded)) {
115 LOG(ERROR) << "Couldn't PEM-encode certificate.";
116 return true;
117 }
118
119 return (std::find(issuer_ca_pems_.begin(), issuer_ca_pems_.end(),
120 pem_encoded) ==
121 issuer_ca_pems_.end());
122 }
123 private:
124 const std::vector<std::string>& issuer_ca_pems_;
125 };
126
127 } // namespace
128
129 namespace certificate_pattern {
130
131 scoped_refptr<net::X509Certificate> GetCertificateMatch(
132 const CertificatePattern& pattern) {
133 typedef std::list<scoped_refptr<net::X509Certificate> > CertificateStlList;
134
135 // Start with all the certs, and narrow it down from there.
136 net::CertificateList all_certs;
137 CertificateStlList matching_certs;
138 net::NSSCertDatabase::GetInstance()->ListCerts(&all_certs);
139
140 if (all_certs.empty())
141 return NULL;
142
143 for (net::CertificateList::iterator iter = all_certs.begin();
144 iter != all_certs.end(); ++iter) {
145 matching_certs.push_back(*iter);
146 }
147
148 // Strip off any certs that don't have the right issuer and/or subject.
149 if (!pattern.issuer().Empty()) {
150 matching_certs.remove_if(IssuerFilter(pattern.issuer()));
151 if (matching_certs.empty())
152 return NULL;
153 }
154
155 if (!pattern.subject().Empty()) {
156 matching_certs.remove_if(SubjectFilter(pattern.subject()));
157 if (matching_certs.empty())
158 return NULL;
159 }
160
161 if (!pattern.issuer_ca_pems().empty()) {
162 matching_certs.remove_if(IssuerCaFilter(pattern.issuer_ca_pems()));
163 if (matching_certs.empty())
164 return NULL;
165 }
166
167 // Eliminate any certs that don't have private keys associated with
168 // them. The CheckUserCert call in the filter is a little slow (because of
169 // underlying PKCS11 calls), so we do this last to reduce the number of times
170 // we have to call it.
171 PrivateKeyFilter private_filter(net::CertDatabase::GetInstance());
172 matching_certs.remove_if(private_filter);
173
174 if (matching_certs.empty())
175 return NULL;
176
177 // We now have a list of certificates that match the pattern we're
178 // looking for. Now we find the one with the latest start date.
179 scoped_refptr<net::X509Certificate> latest(NULL);
180
181 // Iterate over the rest looking for the one that was issued latest.
182 for (CertificateStlList::iterator iter = matching_certs.begin();
183 iter != matching_certs.end(); ++iter) {
184 if (!latest.get() || (*iter)->valid_start() > latest->valid_start())
185 latest = *iter;
186 }
187
188 return latest;
189 }
190
191 } // namespace certificate_pattern
192
193 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698