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

Side by Side Diff: net/base/x509_certificate_win.cc

Issue 4040: Refactoring out common code in the X.509 cert handling (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 3 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
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 "net/base/x509_certificate.h" 5 #include "net/base/x509_certificate.h"
6 6
7 #include <map>
8
9 #include "base/histogram.h" 7 #include "base/histogram.h"
10 #include "base/lock.h" 8 #include "base/logging.h"
11 #include "base/pickle.h" 9 #include "base/pickle.h"
12 #include "base/singleton.h"
13 #include "base/string_tokenizer.h" 10 #include "base/string_tokenizer.h"
14 #include "base/string_util.h" 11 #include "base/string_util.h"
15 #include "net/base/cert_status_flags.h" 12 #include "net/base/cert_status_flags.h"
16 #include "net/base/ev_root_ca_metadata.h" 13 #include "net/base/ev_root_ca_metadata.h"
17 14
18 #pragma comment(lib, "crypt32.lib") 15 #pragma comment(lib, "crypt32.lib")
19 16
20 namespace net { 17 namespace net {
21 18
22 namespace { 19 namespace {
23 20
24 // Returns true if this cert fingerprint is the null (all zero) fingerprint.
25 // We use this as a bogus fingerprint value.
26 bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) {
27 for (size_t i = 0; i < arraysize(fingerprint.data); ++i) {
28 if (fingerprint.data[i] != 0)
29 return false;
30 }
31 return true;
32 }
33
34 // Calculates the SHA-1 fingerprint of the certificate. Returns an empty 21 // Calculates the SHA-1 fingerprint of the certificate. Returns an empty
35 // (all zero) fingerprint on failure. 22 // (all zero) fingerprint on failure.
36 X509Certificate::Fingerprint CalculateFingerprint(PCCERT_CONTEXT cert) { 23 X509Certificate::Fingerprint CalculateFingerprint(PCCERT_CONTEXT cert) {
37 DCHECK(NULL != cert->pbCertEncoded); 24 DCHECK(NULL != cert->pbCertEncoded);
38 DCHECK(0 != cert->cbCertEncoded); 25 DCHECK(0 != cert->cbCertEncoded);
39 26
40 BOOL rv; 27 BOOL rv;
41 X509Certificate::Fingerprint sha1; 28 X509Certificate::Fingerprint sha1;
42 DWORD sha1_size = sizeof(sha1.data); 29 DWORD sha1_size = sizeof(sha1.data);
43 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, 30 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded,
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 class ScopedPtrMallocFreeCertChain { 162 class ScopedPtrMallocFreeCertChain {
176 public: 163 public:
177 void operator()(const CERT_CHAIN_CONTEXT* x) const { 164 void operator()(const CERT_CHAIN_CONTEXT* x) const {
178 CertFreeCertificateChain(x); 165 CertFreeCertificateChain(x);
179 } 166 }
180 }; 167 };
181 168
182 typedef scoped_ptr_malloc<const CERT_CHAIN_CONTEXT, 169 typedef scoped_ptr_malloc<const CERT_CHAIN_CONTEXT,
183 ScopedPtrMallocFreeCertChain> ScopedCertChainContext; 170 ScopedPtrMallocFreeCertChain> ScopedCertChainContext;
184 171
185 } // namespace 172 // Helper function to parse a principal from a WinInet description of that
173 // principal.
174 void ParsePrincipal(const std::string& description,
175 X509Certificate::Principal* principal) {
176 // The description of the principal is a string with each LDAP value on
177 // a separate line.
178 const std::string kDelimiters("\r\n");
186 179
187 bool X509Certificate::FingerprintLessThan::operator()( 180 std::vector<std::string> common_names, locality_names, state_names,
188 const Fingerprint& lhs, 181 country_names;
189 const Fingerprint& rhs) const { 182
190 for (size_t i = 0; i < sizeof(lhs.data); ++i) { 183 // TODO(jcampan): add business_category and serial_number.
191 if (lhs.data[i] < rhs.data[i]) 184 const std::string kPrefixes[] = { std::string("CN="),
192 return true; 185 std::string("L="),
193 if (lhs.data[i] > rhs.data[i]) 186 std::string("S="),
194 return false; 187 std::string("C="),
188 std::string("STREET="),
189 std::string("O="),
190 std::string("OU="),
191 std::string("DC=") };
192
193 std::vector<std::string>* values[] = {
194 &common_names, &locality_names,
195 &state_names, &country_names,
196 &(principal->street_addresses),
197 &(principal->organization_names),
198 &(principal->organization_unit_names),
199 &(principal->domain_components) };
200 DCHECK(arraysize(kPrefixes) == arraysize(values));
201
202 StringTokenizer str_tok(description, kDelimiters);
203 while (str_tok.GetNext()) {
204 std::string entry = str_tok.token();
205 for (int i = 0; i < arraysize(kPrefixes); i++) {
206 if (!entry.compare(0, kPrefixes[i].length(), kPrefixes[i])) {
207 std::string value = entry.substr(kPrefixes[i].length());
208 // Remove enclosing double-quotes if any.
209 if (value.size() >= 2 &&
210 value[0] == '"' && value[value.size() - 1] == '"')
211 value = value.substr(1, value.size() - 2);
212 values[i]->push_back(value);
213 break;
214 }
215 }
195 } 216 }
196 return false; 217
218 // We don't expect to have more than one CN, L, S, and C.
219 std::vector<std::string>* single_value_lists[4] = {
220 &common_names, &locality_names, &state_names, &country_names };
221 std::string* single_values[4] = {
222 &principal->common_name, &principal->locality_name,
223 &principal->state_or_province_name, &principal->country_name };
224 for (int i = 0; i < arraysize(single_value_lists); ++i) {
225 int length = static_cast<int>(single_value_lists[i]->size());
226 DCHECK(single_value_lists[i]->size() <= 1);
227 if (single_value_lists[i]->size() > 0)
228 *(single_values[i]) = (*(single_value_lists[i]))[0];
229 }
197 } 230 }
198 231
199 bool X509Certificate::LessThan::operator()(X509Certificate* lhs, 232 } // namespace
200 X509Certificate* rhs) const {
201 if (lhs == rhs)
202 return false;
203
204 X509Certificate::FingerprintLessThan fingerprint_functor;
205 return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_);
206 }
207
208 // A thread-safe cache for X509Certificate objects.
209 //
210 // The cache does not hold a reference to the certificate objects. The objects
211 // must |Remove| themselves from the cache upon destruction (or else the cache
212 // will be holding dead pointers to the objects).
213 class X509Certificate::Cache {
214 public:
215 // Get the singleton object for the cache.
216 static X509Certificate::Cache* GetInstance() {
217 return Singleton<X509Certificate::Cache>::get();
218 }
219
220 // Insert |cert| into the cache. The cache does NOT AddRef |cert|. The cache
221 // must not already contain a certificate with the same fingerprint.
222 void Insert(X509Certificate* cert) {
223 AutoLock lock(lock_);
224
225 DCHECK(!IsNullFingerprint(cert->fingerprint())) <<
226 "Only insert certs with real fingerprints.";
227 DCHECK(cache_.find(cert->fingerprint()) == cache_.end());
228 cache_[cert->fingerprint()] = cert;
229 };
230
231 // Remove |cert| from the cache. The cache does not assume that |cert| is
232 // already in the cache.
233 void Remove(X509Certificate* cert) {
234 AutoLock lock(lock_);
235
236 CertMap::iterator pos(cache_.find(cert->fingerprint()));
237 if (pos == cache_.end())
238 return; // It is not an error to remove a cert that is not in the cache.
239 cache_.erase(pos);
240 };
241
242 // Find a certificate in the cache with the given fingerprint. If one does
243 // not exist, this method returns NULL.
244 X509Certificate* Find(const Fingerprint& fingerprint) {
245 AutoLock lock(lock_);
246
247 CertMap::iterator pos(cache_.find(fingerprint));
248 if (pos == cache_.end())
249 return NULL;
250
251 return pos->second;
252 };
253
254 private:
255 typedef std::map<Fingerprint, X509Certificate*, FingerprintLessThan> CertMap;
256
257 // Obtain an instance of X509Certificate::Cache via GetInstance().
258 Cache() { }
259 friend struct DefaultSingletonTraits<X509Certificate::Cache>;
260
261 // You must acquire this lock before using any private data of this object.
262 // You must not block while holding this lock.
263 Lock lock_;
264
265 // The certificate cache. You must acquire |lock_| before using |cache_|.
266 CertMap cache_;
267
268 DISALLOW_COPY_AND_ASSIGN(X509Certificate::Cache);
269 };
270 233
271 void X509Certificate::Initialize() { 234 void X509Certificate::Initialize() {
272 std::wstring subject_info; 235 std::wstring subject_info;
273 std::wstring issuer_info; 236 std::wstring issuer_info;
274 DWORD name_size; 237 DWORD name_size;
275 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, 238 name_size = CertNameToStr(cert_handle_->dwCertEncodingType,
276 &cert_handle_->pCertInfo->Subject, 239 &cert_handle_->pCertInfo->Subject,
277 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, 240 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
278 NULL, 0); 241 NULL, 0);
279 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, 242 name_size = CertNameToStr(cert_handle_->dwCertEncodingType,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 // the |cert_handle|, which makes it our job to free it. 275 // the |cert_handle|, which makes it our job to free it.
313 CertFreeCertificateContext(cert_handle); 276 CertFreeCertificateContext(cert_handle);
314 DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); 277 DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1);
315 return cert; 278 return cert;
316 } 279 }
317 // Otherwise, allocate a new object. 280 // Otherwise, allocate a new object.
318 return new X509Certificate(cert_handle); 281 return new X509Certificate(cert_handle);
319 } 282 }
320 283
321 // static 284 // static
322 X509Certificate* X509Certificate::CreateFromBytes(const char* data, int length) { 285 X509Certificate* X509Certificate::CreateFromBytes(const char* data,
286 int length) {
323 OSCertHandle cert_handle = NULL; 287 OSCertHandle cert_handle = NULL;
324 if (!CertAddEncodedCertificateToStore( 288 if (!CertAddEncodedCertificateToStore(
325 NULL, // the cert won't be persisted in any cert store 289 NULL, // the cert won't be persisted in any cert store
326 X509_ASN_ENCODING, 290 X509_ASN_ENCODING,
327 reinterpret_cast<const BYTE*>(data), length, 291 reinterpret_cast<const BYTE*>(data), length,
328 CERT_STORE_ADD_USE_EXISTING, 292 CERT_STORE_ADD_USE_EXISTING,
329 &cert_handle)) 293 &cert_handle))
330 return NULL; 294 return NULL;
331 295
332 return CreateFromHandle(cert_handle); 296 return CreateFromHandle(cert_handle);
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 // Get the certificatePolicies extension of the end certificate. 424 // Get the certificatePolicies extension of the end certificate.
461 PCCERT_CONTEXT end_cert = element[0]->pCertContext; 425 PCCERT_CONTEXT end_cert = element[0]->pCertContext;
462 scoped_ptr_malloc<CERT_POLICIES_INFO> policies_info; 426 scoped_ptr_malloc<CERT_POLICIES_INFO> policies_info;
463 GetCertPoliciesInfo(end_cert, &policies_info); 427 GetCertPoliciesInfo(end_cert, &policies_info);
464 if (!policies_info.get()) 428 if (!policies_info.get())
465 return false; 429 return false;
466 430
467 return ContainsPolicy(policies_info.get(), ev_policy_oid.c_str()); 431 return ContainsPolicy(policies_info.get(), ev_policy_oid.c_str());
468 } 432 }
469 433
470 // static
471 void X509Certificate::ParsePrincipal(const std::string& description,
472 Principal* principal) {
473 // The description of the principal is a string with each LDAP value on
474 // a separate line.
475 const std::string kDelimiters("\r\n");
476
477 std::vector<std::string> common_names, locality_names, state_names,
478 country_names;
479
480 // TODO(jcampan): add business_category and serial_number.
481 const std::string kPrefixes[] = { std::string("CN="),
482 std::string("L="),
483 std::string("S="),
484 std::string("C="),
485 std::string("STREET="),
486 std::string("O="),
487 std::string("OU="),
488 std::string("DC=") };
489
490 std::vector<std::string>* values[] = {
491 &common_names, &locality_names,
492 &state_names, &country_names,
493 &(principal->street_addresses),
494 &(principal->organization_names),
495 &(principal->organization_unit_names),
496 &(principal->domain_components) };
497 DCHECK(arraysize(kPrefixes) == arraysize(values));
498
499 StringTokenizer str_tok(description, kDelimiters);
500 while (str_tok.GetNext()) {
501 std::string entry = str_tok.token();
502 for (int i = 0; i < arraysize(kPrefixes); i++) {
503 if (!entry.compare(0, kPrefixes[i].length(), kPrefixes[i])) {
504 std::string value = entry.substr(kPrefixes[i].length());
505 // Remove enclosing double-quotes if any.
506 if (value.size() >= 2 &&
507 value[0] == '"' && value[value.size() - 1] == '"')
508 value = value.substr(1, value.size() - 2);
509 values[i]->push_back(value);
510 break;
511 }
512 }
513 }
514
515 // We don't expect to have more than one CN, L, S, and C.
516 std::vector<std::string>* single_value_lists[4] = {
517 &common_names, &locality_names, &state_names, &country_names };
518 std::string* single_values[4] = {
519 &principal->common_name, &principal->locality_name,
520 &principal->state_or_province_name, &principal->country_name };
521 for (int i = 0; i < arraysize(single_value_lists); ++i) {
522 int length = static_cast<int>(single_value_lists[i]->size());
523 DCHECK(single_value_lists[i]->size() <= 1);
524 if (single_value_lists[i]->size() > 0)
525 *(single_values[i]) = (*(single_value_lists[i]))[0];
526 }
527 }
528
529 X509Certificate::Policy::Judgment X509Certificate::Policy::Check(
530 X509Certificate* cert) const {
531 // It shouldn't matter which set we check first, but we check denied first
532 // in case something strange has happened.
533
534 if (denied_.find(cert->fingerprint()) != denied_.end()) {
535 // DCHECK that the order didn't matter.
536 DCHECK(allowed_.find(cert->fingerprint()) == allowed_.end());
537 return DENIED;
538 }
539
540 if (allowed_.find(cert->fingerprint()) != allowed_.end()) {
541 // DCHECK that the order didn't matter.
542 DCHECK(denied_.find(cert->fingerprint()) == denied_.end());
543 return ALLOWED;
544 }
545
546 // We don't have a policy for this cert.
547 return UNKNOWN;
548 }
549
550 void X509Certificate::Policy::Allow(X509Certificate* cert) {
551 // Put the cert in the allowed set and (maybe) remove it from the denied set.
552 denied_.erase(cert->fingerprint());
553 allowed_.insert(cert->fingerprint());
554 }
555
556 void X509Certificate::Policy::Deny(X509Certificate* cert) {
557 // Put the cert in the denied set and (maybe) remove it from the allowed set.
558 allowed_.erase(cert->fingerprint());
559 denied_.insert(cert->fingerprint());
560 }
561
562 } // namespace net 434 } // namespace net
563 435
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698