| OLD | NEW |
| 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> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/lazy_instance.h" |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 10 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 11 #include "base/singleton.h" | |
| 12 #include "base/string_piece.h" | 12 #include "base/string_piece.h" |
| 13 #include "base/time.h" | 13 #include "base/time.h" |
| 14 #include "net/base/pem_tokenizer.h" | 14 #include "net/base/pem_tokenizer.h" |
| 15 | 15 |
| 16 namespace net { | 16 namespace net { |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 // Returns true if this cert fingerprint is the null (all zero) fingerprint. | 20 // Returns true if this cert fingerprint is the null (all zero) fingerprint. |
| 21 // We use this as a bogus fingerprint value. | 21 // We use this as a bogus fingerprint value. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 32 const X509Certificate::Format kFormatDecodePriority[] = { | 32 const X509Certificate::Format kFormatDecodePriority[] = { |
| 33 X509Certificate::FORMAT_SINGLE_CERTIFICATE, | 33 X509Certificate::FORMAT_SINGLE_CERTIFICATE, |
| 34 X509Certificate::FORMAT_PKCS7 | 34 X509Certificate::FORMAT_PKCS7 |
| 35 }; | 35 }; |
| 36 | 36 |
| 37 // The PEM block header used for DER certificates | 37 // The PEM block header used for DER certificates |
| 38 const char kCertificateHeader[] = "CERTIFICATE"; | 38 const char kCertificateHeader[] = "CERTIFICATE"; |
| 39 // The PEM block header used for PKCS#7 data | 39 // The PEM block header used for PKCS#7 data |
| 40 const char kPKCS7Header[] = "PKCS7"; | 40 const char kPKCS7Header[] = "PKCS7"; |
| 41 | 41 |
| 42 } // namespace | |
| 43 | |
| 44 bool X509Certificate::LessThan::operator()(X509Certificate* lhs, | |
| 45 X509Certificate* rhs) const { | |
| 46 if (lhs == rhs) | |
| 47 return false; | |
| 48 | |
| 49 SHA1FingerprintLessThan fingerprint_functor; | |
| 50 return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_); | |
| 51 } | |
| 52 | |
| 53 // A thread-safe cache for X509Certificate objects. | 42 // A thread-safe cache for X509Certificate objects. |
| 54 // | 43 // |
| 55 // The cache does not hold a reference to the certificate objects. The objects | 44 // The cache does not hold a reference to the certificate objects. The objects |
| 56 // must |Remove| themselves from the cache upon destruction (or else the cache | 45 // must |Remove| themselves from the cache upon destruction (or else the cache |
| 57 // will be holding dead pointers to the objects). | 46 // will be holding dead pointers to the objects). |
| 58 // TODO(rsleevi): There exists a chance of a use-after-free, due to a race | 47 // TODO(rsleevi): There exists a chance of a use-after-free, due to a race |
| 59 // between Find() and Remove(). See http://crbug.com/49377 | 48 // between Find() and Remove(). See http://crbug.com/49377 |
| 60 class X509Certificate::Cache { | 49 class X509CertificateCache { |
| 61 public: | 50 public: |
| 62 static Cache* GetInstance(); | |
| 63 void Insert(X509Certificate* cert); | 51 void Insert(X509Certificate* cert); |
| 64 void Remove(X509Certificate* cert); | 52 void Remove(X509Certificate* cert); |
| 65 X509Certificate* Find(const SHA1Fingerprint& fingerprint); | 53 X509Certificate* Find(const SHA1Fingerprint& fingerprint); |
| 66 | 54 |
| 67 private: | 55 private: |
| 68 typedef std::map<SHA1Fingerprint, X509Certificate*, SHA1FingerprintLessThan> | 56 typedef std::map<SHA1Fingerprint, X509Certificate*, SHA1FingerprintLessThan> |
| 69 CertMap; | 57 CertMap; |
| 70 | 58 |
| 71 // Obtain an instance of X509Certificate::Cache via GetInstance(). | 59 // Obtain an instance of X509CertificateCache via a LazyInstance. |
| 72 Cache() {} | 60 X509CertificateCache() {} |
| 73 friend struct DefaultSingletonTraits<Cache>; | 61 ~X509CertificateCache() {} |
| 62 friend struct base::DefaultLazyInstanceTraits<X509CertificateCache>; |
| 74 | 63 |
| 75 // You must acquire this lock before using any private data of this object. | 64 // You must acquire this lock before using any private data of this object. |
| 76 // You must not block while holding this lock. | 65 // You must not block while holding this lock. |
| 77 Lock lock_; | 66 Lock lock_; |
| 78 | 67 |
| 79 // The certificate cache. You must acquire |lock_| before using |cache_|. | 68 // The certificate cache. You must acquire |lock_| before using |cache_|. |
| 80 CertMap cache_; | 69 CertMap cache_; |
| 81 | 70 |
| 82 DISALLOW_COPY_AND_ASSIGN(Cache); | 71 DISALLOW_COPY_AND_ASSIGN(X509CertificateCache); |
| 83 }; | 72 }; |
| 84 | 73 |
| 85 // Get the singleton object for the cache. | 74 base::LazyInstance<X509CertificateCache, |
| 86 // static | 75 base::LeakyLazyInstanceTraits<X509CertificateCache> > |
| 87 X509Certificate::Cache* X509Certificate::Cache::GetInstance() { | 76 g_x509_certificate_cache(base::LINKER_INITIALIZED); |
| 88 return Singleton<X509Certificate::Cache>::get(); | |
| 89 } | |
| 90 | 77 |
| 91 // Insert |cert| into the cache. The cache does NOT AddRef |cert|. | 78 // Insert |cert| into the cache. The cache does NOT AddRef |cert|. |
| 92 // Any existing certificate with the same fingerprint will be replaced. | 79 // Any existing certificate with the same fingerprint will be replaced. |
| 93 void X509Certificate::Cache::Insert(X509Certificate* cert) { | 80 void X509CertificateCache::Insert(X509Certificate* cert) { |
| 94 AutoLock lock(lock_); | 81 AutoLock lock(lock_); |
| 95 | 82 |
| 96 DCHECK(!IsNullFingerprint(cert->fingerprint())) << | 83 DCHECK(!IsNullFingerprint(cert->fingerprint())) << |
| 97 "Only insert certs with real fingerprints."; | 84 "Only insert certs with real fingerprints."; |
| 98 cache_[cert->fingerprint()] = cert; | 85 cache_[cert->fingerprint()] = cert; |
| 99 }; | 86 }; |
| 100 | 87 |
| 101 // Remove |cert| from the cache. The cache does not assume that |cert| is | 88 // Remove |cert| from the cache. The cache does not assume that |cert| is |
| 102 // already in the cache. | 89 // already in the cache. |
| 103 void X509Certificate::Cache::Remove(X509Certificate* cert) { | 90 void X509CertificateCache::Remove(X509Certificate* cert) { |
| 104 AutoLock lock(lock_); | 91 AutoLock lock(lock_); |
| 105 | 92 |
| 106 CertMap::iterator pos(cache_.find(cert->fingerprint())); | 93 CertMap::iterator pos(cache_.find(cert->fingerprint())); |
| 107 if (pos == cache_.end()) | 94 if (pos == cache_.end()) |
| 108 return; // It is not an error to remove a cert that is not in the cache. | 95 return; // It is not an error to remove a cert that is not in the cache. |
| 109 cache_.erase(pos); | 96 cache_.erase(pos); |
| 110 }; | 97 }; |
| 111 | 98 |
| 112 // Find a certificate in the cache with the given fingerprint. If one does | 99 // Find a certificate in the cache with the given fingerprint. If one does |
| 113 // not exist, this method returns NULL. | 100 // not exist, this method returns NULL. |
| 114 X509Certificate* X509Certificate::Cache::Find( | 101 X509Certificate* X509CertificateCache::Find( |
| 115 const SHA1Fingerprint& fingerprint) { | 102 const SHA1Fingerprint& fingerprint) { |
| 116 AutoLock lock(lock_); | 103 AutoLock lock(lock_); |
| 117 | 104 |
| 118 CertMap::iterator pos(cache_.find(fingerprint)); | 105 CertMap::iterator pos(cache_.find(fingerprint)); |
| 119 if (pos == cache_.end()) | 106 if (pos == cache_.end()) |
| 120 return NULL; | 107 return NULL; |
| 121 | 108 |
| 122 return pos->second; | 109 return pos->second; |
| 123 }; | 110 }; |
| 124 | 111 |
| 112 } // namespace |
| 113 |
| 114 bool X509Certificate::LessThan::operator()(X509Certificate* lhs, |
| 115 X509Certificate* rhs) const { |
| 116 if (lhs == rhs) |
| 117 return false; |
| 118 |
| 119 SHA1FingerprintLessThan fingerprint_functor; |
| 120 return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_); |
| 121 } |
| 122 |
| 125 // static | 123 // static |
| 126 X509Certificate* X509Certificate::CreateFromHandle( | 124 X509Certificate* X509Certificate::CreateFromHandle( |
| 127 OSCertHandle cert_handle, | 125 OSCertHandle cert_handle, |
| 128 Source source, | 126 Source source, |
| 129 const OSCertHandles& intermediates) { | 127 const OSCertHandles& intermediates) { |
| 130 DCHECK(cert_handle); | 128 DCHECK(cert_handle); |
| 131 DCHECK(source != SOURCE_UNUSED); | 129 DCHECK(source != SOURCE_UNUSED); |
| 132 | 130 |
| 133 // Check if we already have this certificate in memory. | 131 // Check if we already have this certificate in memory. |
| 134 X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); | 132 X509CertificateCache* cache = g_x509_certificate_cache.Pointer(); |
| 135 X509Certificate* cached_cert = | 133 X509Certificate* cached_cert = |
| 136 cache->Find(CalculateFingerprint(cert_handle)); | 134 cache->Find(CalculateFingerprint(cert_handle)); |
| 137 if (cached_cert) { | 135 if (cached_cert) { |
| 138 DCHECK(cached_cert->source_ != SOURCE_UNUSED); | 136 DCHECK(cached_cert->source_ != SOURCE_UNUSED); |
| 139 if (cached_cert->source_ > source || | 137 if (cached_cert->source_ > source || |
| 140 (cached_cert->source_ == source && | 138 (cached_cert->source_ == source && |
| 141 cached_cert->HasIntermediateCertificates(intermediates))) { | 139 cached_cert->HasIntermediateCertificates(intermediates))) { |
| 142 // Return the certificate with the same fingerprint from our cache. | 140 // Return the certificate with the same fingerprint from our cache. |
| 143 DHISTOGRAM_COUNTS("X509CertificateReuseCount", 1); | 141 DHISTOGRAM_COUNTS("X509CertificateReuseCount", 1); |
| 144 return cached_cert; | 142 return cached_cert; |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 issuer_(issuer), | 302 issuer_(issuer), |
| 305 valid_start_(start_date), | 303 valid_start_(start_date), |
| 306 valid_expiry_(expiration_date), | 304 valid_expiry_(expiration_date), |
| 307 cert_handle_(NULL), | 305 cert_handle_(NULL), |
| 308 source_(SOURCE_UNUSED) { | 306 source_(SOURCE_UNUSED) { |
| 309 memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); | 307 memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); |
| 310 } | 308 } |
| 311 | 309 |
| 312 X509Certificate::~X509Certificate() { | 310 X509Certificate::~X509Certificate() { |
| 313 // We might not be in the cache, but it is safe to remove ourselves anyway. | 311 // We might not be in the cache, but it is safe to remove ourselves anyway. |
| 314 X509Certificate::Cache::GetInstance()->Remove(this); | 312 g_x509_certificate_cache.Get().Remove(this); |
| 315 if (cert_handle_) | 313 if (cert_handle_) |
| 316 FreeOSCertHandle(cert_handle_); | 314 FreeOSCertHandle(cert_handle_); |
| 317 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) | 315 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) |
| 318 FreeOSCertHandle(intermediate_ca_certs_[i]); | 316 FreeOSCertHandle(intermediate_ca_certs_[i]); |
| 319 } | 317 } |
| 320 | 318 |
| 321 bool X509Certificate::HasExpired() const { | 319 bool X509Certificate::HasExpired() const { |
| 322 return base::Time::Now() > valid_expiry(); | 320 return base::Time::Now() > valid_expiry(); |
| 323 } | 321 } |
| 324 | 322 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 340 | 338 |
| 341 bool X509Certificate::HasIntermediateCertificates(const OSCertHandles& certs) { | 339 bool X509Certificate::HasIntermediateCertificates(const OSCertHandles& certs) { |
| 342 for (size_t i = 0; i < certs.size(); ++i) { | 340 for (size_t i = 0; i < certs.size(); ++i) { |
| 343 if (!HasIntermediateCertificate(certs[i])) | 341 if (!HasIntermediateCertificate(certs[i])) |
| 344 return false; | 342 return false; |
| 345 } | 343 } |
| 346 return true; | 344 return true; |
| 347 } | 345 } |
| 348 | 346 |
| 349 } // namespace net | 347 } // namespace net |
| OLD | NEW |