OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/browser/chromeos/cros/certificate_pattern.h" | 5 #include "chromeos/network/certificate_pattern.h" |
6 | |
7 #include <algorithm> | |
8 #include <list> | |
9 #include <string> | |
10 #include <vector> | |
11 | |
12 #include <cert.h> | |
13 #include <pk11pub.h> | |
14 | 6 |
15 #include "base/logging.h" | 7 #include "base/logging.h" |
16 #include "base/values.h" | 8 #include "base/values.h" |
17 #include "net/base/net_errors.h" | |
18 #include "net/cert/cert_database.h" | |
19 #include "net/cert/nss_cert_database.h" | |
20 #include "net/cert/x509_cert_types.h" | |
21 #include "net/cert/x509_certificate.h" | |
22 | |
23 // To shorten some of those long lines below. | |
24 using base::DictionaryValue; | |
25 using base::ListValue; | |
26 using std::find; | |
27 using std::list; | |
28 using std::string; | |
29 using std::vector; | |
30 | 9 |
31 namespace chromeos { | 10 namespace chromeos { |
32 | 11 |
33 namespace { | 12 namespace { |
34 | 13 |
35 // Keys for converting classes below to/from dictionaries. | 14 // Keys for converting classes below to/from dictionaries. |
36 const char kCommonNameKey[] = "CommonName"; | 15 const char kCommonNameKey[] = "CommonName"; |
37 const char kLocalityKey[] = "Locality"; | 16 const char kLocalityKey[] = "Locality"; |
38 const char kOrganizationKey[] = "Organization"; | 17 const char kOrganizationKey[] = "Organization"; |
39 const char kOrganizationalUnitKey[] = "OrganizationalUnit"; | 18 const char kOrganizationalUnitKey[] = "OrganizationalUnit"; |
(...skipping 11 matching lines...) Expand all Loading... |
51 result->reserve(list->GetSize()); | 30 result->reserve(list->GetSize()); |
52 for (size_t i = 0; i < list->GetSize(); i++) { | 31 for (size_t i = 0; i < list->GetSize(); i++) { |
53 std::string item; | 32 std::string item; |
54 if (!list->GetString(i, &item)) | 33 if (!list->GetString(i, &item)) |
55 return false; | 34 return false; |
56 result->push_back(item); | 35 result->push_back(item); |
57 } | 36 } |
58 return true; | 37 return true; |
59 } | 38 } |
60 | 39 |
61 ListValue* CreateListFromStrings(const vector<string>& strings) { | 40 base::ListValue* CreateListFromStrings( |
62 ListValue* new_list = new ListValue; | 41 const std::vector<std::string>& strings) { |
63 for (vector<string>::const_iterator iter = strings.begin(); | 42 base::ListValue* new_list = new base::ListValue; |
| 43 for (std::vector<std::string>::const_iterator iter = strings.begin(); |
64 iter != strings.end(); ++iter) { | 44 iter != strings.end(); ++iter) { |
65 new_list->Append(new StringValue(*iter)); | 45 new_list->Append(new StringValue(*iter)); |
66 } | 46 } |
67 return new_list; | 47 return new_list; |
68 } | 48 } |
69 | 49 |
70 // Functor to filter out non-matching issuers. | |
71 class IssuerFilter { | |
72 public: | |
73 explicit IssuerFilter(const IssuerSubjectPattern& issuer) | |
74 : issuer_(issuer) {} | |
75 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const { | |
76 return !issuer_.Matches(cert.get()->issuer()); | |
77 } | |
78 private: | |
79 const IssuerSubjectPattern& issuer_; | |
80 }; | |
81 | |
82 // Functor to filter out non-matching subjects. | |
83 class SubjectFilter { | |
84 public: | |
85 explicit SubjectFilter(const IssuerSubjectPattern& subject) | |
86 : subject_(subject) {} | |
87 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const { | |
88 return !subject_.Matches(cert.get()->subject()); | |
89 } | |
90 private: | |
91 const IssuerSubjectPattern& subject_; | |
92 }; | |
93 | |
94 // Functor to filter out certs that don't have private keys, or are invalid. | |
95 class PrivateKeyFilter { | |
96 public: | |
97 explicit PrivateKeyFilter(net::CertDatabase* cert_db) : cert_db_(cert_db) {} | |
98 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const { | |
99 return cert_db_->CheckUserCert(cert.get()) != net::OK; | |
100 } | |
101 private: | |
102 net::CertDatabase* cert_db_; | |
103 }; | |
104 | |
105 // Functor to filter out certs that don't have an issuer in the associated | |
106 // IssuerCARef list. | |
107 class IssuerCaRefFilter { | |
108 public: | |
109 explicit IssuerCaRefFilter(const vector<string>& issuer_ca_ref_list) | |
110 : issuer_ca_ref_list_(issuer_ca_ref_list) {} | |
111 bool operator()(const scoped_refptr<net::X509Certificate>& cert) const { | |
112 // Find the certificate issuer for each certificate. | |
113 // TODO(gspencer): this functionality should be available from | |
114 // X509Certificate or NSSCertDatabase. | |
115 CERTCertificate* issuer_cert = CERT_FindCertIssuer( | |
116 cert.get()->os_cert_handle(), PR_Now(), certUsageAnyCA); | |
117 | |
118 if (issuer_cert && issuer_cert->nickname) { | |
119 // Separate the nickname stored in the certificate at the colon, since | |
120 // NSS likes to store it as token:nickname. | |
121 const char* delimiter = ::strchr(issuer_cert->nickname, ':'); | |
122 if (delimiter) { | |
123 delimiter++; // move past the colon. | |
124 vector<string>::const_iterator pat_iter = issuer_ca_ref_list_.begin(); | |
125 while (pat_iter != issuer_ca_ref_list_.end()) { | |
126 if (::strcmp(delimiter, pat_iter->c_str()) == 0) | |
127 return false; | |
128 ++pat_iter; | |
129 } | |
130 } | |
131 } | |
132 return true; | |
133 } | |
134 private: | |
135 const vector<string>& issuer_ca_ref_list_; | |
136 }; | |
137 | |
138 } // namespace | 50 } // namespace |
139 | 51 |
140 //////////////////////////////////////////////////////////////////////////////// | 52 //////////////////////////////////////////////////////////////////////////////// |
141 // IssuerSubjectPattern | 53 // IssuerSubjectPattern |
142 IssuerSubjectPattern::IssuerSubjectPattern(const std::string& common_name, | 54 IssuerSubjectPattern::IssuerSubjectPattern(const std::string& common_name, |
143 const std::string& locality, | 55 const std::string& locality, |
144 const std::string& organization, | 56 const std::string& organization, |
145 const std::string& organizational_unit) | 57 const std::string& organizational_unit) |
146 : common_name_(common_name), | 58 : common_name_(common_name), |
147 locality_(locality), | 59 locality_(locality), |
148 organization_(organization), | 60 organization_(organization), |
149 organizational_unit_(organizational_unit) { } | 61 organizational_unit_(organizational_unit) { } |
150 | 62 |
151 IssuerSubjectPattern::IssuerSubjectPattern() {} | 63 IssuerSubjectPattern::IssuerSubjectPattern() {} |
152 | 64 |
153 IssuerSubjectPattern::~IssuerSubjectPattern() {} | 65 IssuerSubjectPattern::~IssuerSubjectPattern() {} |
154 | 66 |
155 bool IssuerSubjectPattern::Matches(const net::CertPrincipal& principal) const { | |
156 if (!common_name_.empty() && common_name_ != principal.common_name) | |
157 return false; | |
158 | |
159 if (!locality_.empty() && locality_ != principal.locality_name) | |
160 return false; | |
161 | |
162 if (!organization_.empty()) { | |
163 if (find(principal.organization_names.begin(), | |
164 principal.organization_names.end(), organization_) == | |
165 principal.organization_names.end()) { | |
166 return false; | |
167 } | |
168 } | |
169 | |
170 if (!organizational_unit_.empty()) { | |
171 if (find(principal.organization_unit_names.begin(), | |
172 principal.organization_unit_names.end(), | |
173 organizational_unit_) == principal.organization_unit_names.end()) { | |
174 return false; | |
175 } | |
176 } | |
177 | |
178 return true; | |
179 } | |
180 | |
181 bool IssuerSubjectPattern::Empty() const { | 67 bool IssuerSubjectPattern::Empty() const { |
182 return common_name_.empty() && | 68 return common_name_.empty() && |
183 locality_.empty() && | 69 locality_.empty() && |
184 organization_.empty() && | 70 organization_.empty() && |
185 organizational_unit_.empty(); | 71 organizational_unit_.empty(); |
186 } | 72 } |
187 | 73 |
188 void IssuerSubjectPattern::Clear() { | 74 void IssuerSubjectPattern::Clear() { |
189 common_name_.clear(); | 75 common_name_.clear(); |
190 locality_.clear(); | 76 locality_.clear(); |
191 organization_.clear(); | 77 organization_.clear(); |
192 organizational_unit_.clear(); | 78 organizational_unit_.clear(); |
193 } | 79 } |
194 | 80 |
195 DictionaryValue* IssuerSubjectPattern::CreateAsDictionary() const { | 81 base::DictionaryValue* IssuerSubjectPattern::CreateAsDictionary() const { |
196 DictionaryValue* dict = new DictionaryValue; | 82 base::DictionaryValue* dict = new base::DictionaryValue; |
197 if (!common_name_.empty()) | 83 if (!common_name_.empty()) |
198 dict->SetString(kCommonNameKey, common_name_); | 84 dict->SetString(kCommonNameKey, common_name_); |
199 if (!locality_.empty()) | 85 if (!locality_.empty()) |
200 dict->SetString(kLocalityKey, locality_); | 86 dict->SetString(kLocalityKey, locality_); |
201 if (!organization_.empty()) | 87 if (!organization_.empty()) |
202 dict->SetString(kOrganizationKey, organization_); | 88 dict->SetString(kOrganizationKey, organization_); |
203 if (!organizational_unit_.empty()) | 89 if (!organizational_unit_.empty()) |
204 dict->SetString(kOrganizationalUnitKey, organizational_unit_); | 90 dict->SetString(kOrganizationalUnitKey, organizational_unit_); |
205 return dict; | 91 return dict; |
206 } | 92 } |
207 | 93 |
208 bool IssuerSubjectPattern::CopyFromDictionary(const DictionaryValue& dict) { | 94 bool IssuerSubjectPattern::CopyFromDictionary( |
| 95 const base::DictionaryValue& dict) { |
209 Clear(); | 96 Clear(); |
210 dict.GetString(kCommonNameKey, &common_name_); | 97 dict.GetString(kCommonNameKey, &common_name_); |
211 dict.GetString(kLocalityKey, &locality_); | 98 dict.GetString(kLocalityKey, &locality_); |
212 dict.GetString(kOrganizationKey, &organization_); | 99 dict.GetString(kOrganizationKey, &organization_); |
213 dict.GetString(kOrganizationalUnitKey, &organizational_unit_); | 100 dict.GetString(kOrganizationalUnitKey, &organizational_unit_); |
214 // If the dictionary wasn't empty, but we are, or vice versa, then something | 101 // If the dictionary wasn't empty, but we are, or vice versa, then something |
215 // went wrong. | 102 // went wrong. |
216 DCHECK(dict.empty() == Empty()); | 103 DCHECK(dict.empty() == Empty()); |
217 if (dict.empty() != Empty()) | 104 if (dict.empty() != Empty()) |
218 return false; | 105 return false; |
(...skipping 13 matching lines...) Expand all Loading... |
232 subject_.Empty(); | 119 subject_.Empty(); |
233 } | 120 } |
234 | 121 |
235 void CertificatePattern::Clear() { | 122 void CertificatePattern::Clear() { |
236 issuer_ca_ref_list_.clear(); | 123 issuer_ca_ref_list_.clear(); |
237 issuer_.Clear(); | 124 issuer_.Clear(); |
238 subject_.Clear(); | 125 subject_.Clear(); |
239 enrollment_uri_list_.clear(); | 126 enrollment_uri_list_.clear(); |
240 } | 127 } |
241 | 128 |
242 scoped_refptr<net::X509Certificate> CertificatePattern::GetMatch() const { | 129 base::DictionaryValue* CertificatePattern::CreateAsDictionary() const { |
243 typedef list<scoped_refptr<net::X509Certificate> > CertificateStlList; | 130 base::DictionaryValue* dict = new base::DictionaryValue; |
244 | |
245 // Start with all the certs, and narrow it down from there. | |
246 net::CertificateList all_certs; | |
247 CertificateStlList matching_certs; | |
248 net::NSSCertDatabase::GetInstance()->ListCerts(&all_certs); | |
249 | |
250 if (all_certs.empty()) | |
251 return NULL; | |
252 | |
253 for (net::CertificateList::iterator iter = all_certs.begin(); | |
254 iter != all_certs.end(); ++iter) { | |
255 matching_certs.push_back(*iter); | |
256 } | |
257 | |
258 // Strip off any certs that don't have the right issuer and/or subject. | |
259 if (!issuer_.Empty()) { | |
260 matching_certs.remove_if(IssuerFilter(issuer_)); | |
261 if (matching_certs.empty()) | |
262 return NULL; | |
263 } | |
264 | |
265 if (!subject_.Empty()) { | |
266 matching_certs.remove_if(SubjectFilter(subject_)); | |
267 if (matching_certs.empty()) | |
268 return NULL; | |
269 } | |
270 | |
271 if (!issuer_ca_ref_list_.empty()) { | |
272 matching_certs.remove_if(IssuerCaRefFilter(issuer_ca_ref_list_)); | |
273 if (matching_certs.empty()) | |
274 return NULL; | |
275 } | |
276 | |
277 // Eliminate any certs that don't have private keys associated with | |
278 // them. The CheckUserCert call in the filter is a little slow (because of | |
279 // underlying PKCS11 calls), so we do this last to reduce the number of times | |
280 // we have to call it. | |
281 PrivateKeyFilter private_filter(net::CertDatabase::GetInstance()); | |
282 matching_certs.remove_if(private_filter); | |
283 | |
284 if (matching_certs.empty()) | |
285 return NULL; | |
286 | |
287 // We now have a list of certificates that match the pattern we're | |
288 // looking for. Now we find the one with the latest start date. | |
289 scoped_refptr<net::X509Certificate> latest(NULL); | |
290 | |
291 // Iterate over the rest looking for the one that was issued latest. | |
292 for (CertificateStlList::iterator iter = matching_certs.begin(); | |
293 iter != matching_certs.end(); ++iter) { | |
294 if (!latest.get() || (*iter)->valid_start() > latest->valid_start()) | |
295 latest = *iter; | |
296 } | |
297 | |
298 return latest; | |
299 } | |
300 | |
301 DictionaryValue* CertificatePattern::CreateAsDictionary() const { | |
302 DictionaryValue* dict = new base::DictionaryValue; | |
303 | 131 |
304 if (!issuer_ca_ref_list_.empty()) | 132 if (!issuer_ca_ref_list_.empty()) |
305 dict->Set(kIssuerCaRefKey, CreateListFromStrings(issuer_ca_ref_list_)); | 133 dict->Set(kIssuerCaRefKey, CreateListFromStrings(issuer_ca_ref_list_)); |
306 | 134 |
307 if (!issuer_.Empty()) | 135 if (!issuer_.Empty()) |
308 dict->Set(kIssuerKey, issuer_.CreateAsDictionary()); | 136 dict->Set(kIssuerKey, issuer_.CreateAsDictionary()); |
309 | 137 |
310 if (!subject_.Empty()) | 138 if (!subject_.Empty()) |
311 dict->Set(kSubjectKey, subject_.CreateAsDictionary()); | 139 dict->Set(kSubjectKey, subject_.CreateAsDictionary()); |
312 | 140 |
313 if (!enrollment_uri_list_.empty()) | 141 if (!enrollment_uri_list_.empty()) |
314 dict->Set(kEnrollmentUriKey, CreateListFromStrings(enrollment_uri_list_)); | 142 dict->Set(kEnrollmentUriKey, CreateListFromStrings(enrollment_uri_list_)); |
315 return dict; | 143 return dict; |
316 } | 144 } |
317 | 145 |
318 bool CertificatePattern::CopyFromDictionary(const DictionaryValue &dict) { | 146 bool CertificatePattern::CopyFromDictionary(const base::DictionaryValue &dict) { |
319 const DictionaryValue* child_dict = NULL; | 147 const base::DictionaryValue* child_dict = NULL; |
320 const ListValue* child_list = NULL; | 148 const base::ListValue* child_list = NULL; |
321 Clear(); | 149 Clear(); |
322 | 150 |
323 // All of these are optional. | 151 // All of these are optional. |
324 if (dict.GetList(kIssuerCaRefKey, &child_list) && child_list) { | 152 if (dict.GetList(kIssuerCaRefKey, &child_list) && child_list) { |
325 if (!GetAsListOfStrings(*child_list, &issuer_ca_ref_list_)) | 153 if (!GetAsListOfStrings(*child_list, &issuer_ca_ref_list_)) |
326 return false; | 154 return false; |
327 } | 155 } |
328 if (dict.GetDictionary(kIssuerKey, &child_dict) && child_dict) { | 156 if (dict.GetDictionary(kIssuerKey, &child_dict) && child_dict) { |
329 if (!issuer_.CopyFromDictionary(*child_dict)) | 157 if (!issuer_.CopyFromDictionary(*child_dict)) |
330 return false; | 158 return false; |
(...skipping 12 matching lines...) Expand all Loading... |
343 // If we didn't copy anything from the dictionary, then it had better be | 171 // If we didn't copy anything from the dictionary, then it had better be |
344 // empty. | 172 // empty. |
345 DCHECK(dict.empty() == Empty()); | 173 DCHECK(dict.empty() == Empty()); |
346 if (dict.empty() != Empty()) | 174 if (dict.empty() != Empty()) |
347 return false; | 175 return false; |
348 | 176 |
349 return true; | 177 return true; |
350 } | 178 } |
351 | 179 |
352 } // namespace chromeos | 180 } // namespace chromeos |
OLD | NEW |