Chromium Code Reviews| 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 "net/cert/x509_certificate.h" | 5 #include "net/cert/x509_certificate.h" |
| 6 | 6 |
| 7 #include <limits.h> | 7 #include <limits.h> |
| 8 #include <stdlib.h> | 8 #include <stdlib.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 #include <map> | 11 #include <map> |
| 12 #include <memory> | 12 #include <memory> |
| 13 #include <string> | 13 #include <string> |
| 14 #include <vector> | 14 #include <vector> |
| 15 | 15 |
| 16 #include "base/base64.h" | 16 #include "base/base64.h" |
| 17 #include "base/lazy_instance.h" | 17 #include "base/lazy_instance.h" |
| 18 #include "base/logging.h" | 18 #include "base/logging.h" |
| 19 #include "base/macros.h" | 19 #include "base/macros.h" |
| 20 #include "base/memory/singleton.h" | 20 #include "base/memory/singleton.h" |
| 21 #include "base/metrics/histogram_macros.h" | 21 #include "base/metrics/histogram_macros.h" |
| 22 #include "base/pickle.h" | 22 #include "base/pickle.h" |
| 23 #include "base/profiler/scoped_tracker.h" | 23 #include "base/profiler/scoped_tracker.h" |
| 24 #include "base/sha1.h" | 24 #include "base/sha1.h" |
|
eroman
2016/06/09 22:18:25
Can this be deleted?
Ryan Sleevi
2016/06/09 22:59:36
Thanks. Done.
| |
| 25 #include "base/strings/string_piece.h" | 25 #include "base/strings/string_piece.h" |
| 26 #include "base/strings/string_util.h" | 26 #include "base/strings/string_util.h" |
| 27 #include "base/synchronization/lock.h" | 27 #include "base/synchronization/lock.h" |
| 28 #include "base/time/time.h" | 28 #include "base/time/time.h" |
| 29 #include "crypto/secure_hash.h" | 29 #include "crypto/secure_hash.h" |
| 30 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 30 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 31 #include "net/base/url_util.h" | 31 #include "net/base/url_util.h" |
| 32 #include "net/cert/pem_tokenizer.h" | 32 #include "net/cert/pem_tokenizer.h" |
| 33 #include "url/url_canon.h" | 33 #include "url/url_canon.h" |
| 34 | 34 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 void InsertOrUpdate(X509Certificate::OSCertHandle* cert_handle); | 76 void InsertOrUpdate(X509Certificate::OSCertHandle* cert_handle); |
| 77 | 77 |
| 78 // Decrements the cache reference count for |cert_handle|, a handle that was | 78 // Decrements the cache reference count for |cert_handle|, a handle that was |
| 79 // previously obtained by calling InsertOrUpdate(). If this is the last | 79 // previously obtained by calling InsertOrUpdate(). If this is the last |
| 80 // cached reference held, this will remove the handle from the cache. The | 80 // cached reference held, this will remove the handle from the cache. The |
| 81 // caller retains ownership of |cert_handle| and remains responsible for | 81 // caller retains ownership of |cert_handle| and remains responsible for |
| 82 // calling FreeOSCertHandle() to release the underlying OS certificate | 82 // calling FreeOSCertHandle() to release the underlying OS certificate |
| 83 void Remove(X509Certificate::OSCertHandle cert_handle); | 83 void Remove(X509Certificate::OSCertHandle cert_handle); |
| 84 | 84 |
| 85 private: | 85 private: |
| 86 // A single entry in the cache. Certificates will be keyed by their SHA1 | 86 // A single entry in the cache. Certificates will be keyed by their SHA-256 |
| 87 // fingerprints, but will not be considered equivalent unless the entire | 87 // fingerprints, but will not be considered equivalent unless the entire |
| 88 // certificate data matches. | 88 // certificate data matches. |
| 89 struct Entry { | 89 struct Entry { |
| 90 Entry() : cert_handle(NULL), ref_count(0) {} | 90 Entry() : cert_handle(NULL), ref_count(0) {} |
| 91 | 91 |
| 92 X509Certificate::OSCertHandle cert_handle; | 92 X509Certificate::OSCertHandle cert_handle; |
| 93 | 93 |
| 94 // Increased by each call to InsertOrUpdate(), and balanced by each call | 94 // Increased by each call to InsertOrUpdate(), and balanced by each call |
| 95 // to Remove(). When it equals 0, all references created by | 95 // to Remove(). When it equals 0, all references created by |
| 96 // InsertOrUpdate() have been released, so the cache entry will be removed | 96 // InsertOrUpdate() have been released, so the cache entry will be removed |
| 97 // the cached OS certificate handle will be freed. | 97 // the cached OS certificate handle will be freed. |
| 98 int ref_count; | 98 int ref_count; |
| 99 }; | 99 }; |
| 100 typedef std::map<SHA1HashValue, Entry, SHA1HashValueLessThan> CertMap; | 100 typedef std::map<SHA256HashValue, Entry, SHA256HashValueLessThan> CertMap; |
| 101 | 101 |
| 102 // Obtain an instance of X509CertificateCache via a LazyInstance. | 102 // Obtain an instance of X509CertificateCache via a LazyInstance. |
| 103 X509CertificateCache() {} | 103 X509CertificateCache() {} |
| 104 ~X509CertificateCache() {} | 104 ~X509CertificateCache() {} |
| 105 friend struct base::DefaultLazyInstanceTraits<X509CertificateCache>; | 105 friend struct base::DefaultLazyInstanceTraits<X509CertificateCache>; |
| 106 | 106 |
| 107 // You must acquire this lock before using any private data of this object | 107 // You must acquire this lock before using any private data of this object |
| 108 // You must not block while holding this lock. | 108 // You must not block while holding this lock. |
| 109 base::Lock lock_; | 109 base::Lock lock_; |
| 110 | 110 |
| 111 // The certificate cache. You must acquire |lock_| before using |cache_|. | 111 // The certificate cache. You must acquire |lock_| before using |cache_|. |
| 112 CertMap cache_; | 112 CertMap cache_; |
| 113 | 113 |
| 114 DISALLOW_COPY_AND_ASSIGN(X509CertificateCache); | 114 DISALLOW_COPY_AND_ASSIGN(X509CertificateCache); |
| 115 }; | 115 }; |
| 116 | 116 |
| 117 base::LazyInstance<X509CertificateCache>::Leaky | 117 base::LazyInstance<X509CertificateCache>::Leaky |
| 118 g_x509_certificate_cache = LAZY_INSTANCE_INITIALIZER; | 118 g_x509_certificate_cache = LAZY_INSTANCE_INITIALIZER; |
| 119 | 119 |
| 120 void X509CertificateCache::InsertOrUpdate( | 120 void X509CertificateCache::InsertOrUpdate( |
| 121 X509Certificate::OSCertHandle* cert_handle) { | 121 X509Certificate::OSCertHandle* cert_handle) { |
| 122 DCHECK(cert_handle); | 122 DCHECK(cert_handle); |
| 123 SHA1HashValue fingerprint = | 123 SHA256HashValue fingerprint = |
| 124 X509Certificate::CalculateFingerprint(*cert_handle); | 124 X509Certificate::CalculateFingerprint256(*cert_handle); |
| 125 | 125 |
| 126 X509Certificate::OSCertHandle old_handle = NULL; | 126 X509Certificate::OSCertHandle old_handle = NULL; |
| 127 { | 127 { |
| 128 base::AutoLock lock(lock_); | 128 base::AutoLock lock(lock_); |
| 129 CertMap::iterator pos = cache_.find(fingerprint); | 129 CertMap::iterator pos = cache_.find(fingerprint); |
| 130 if (pos == cache_.end()) { | 130 if (pos == cache_.end()) { |
| 131 // A cached entry was not found, so initialize a new entry. The entry | 131 // A cached entry was not found, so initialize a new entry. The entry |
| 132 // assumes ownership of the current |*cert_handle|. | 132 // assumes ownership of the current |*cert_handle|. |
| 133 Entry cache_entry; | 133 Entry cache_entry; |
| 134 cache_entry.cert_handle = *cert_handle; | 134 cache_entry.cert_handle = *cert_handle; |
| 135 cache_entry.ref_count = 0; | 135 cache_entry.ref_count = 0; |
| 136 CertMap::value_type cache_value(fingerprint, cache_entry); | 136 CertMap::value_type cache_value(fingerprint, cache_entry); |
| 137 pos = cache_.insert(cache_value).first; | 137 pos = cache_.insert(cache_value).first; |
| 138 } else { | 138 } else { |
| 139 bool is_same_cert = | 139 bool is_same_cert = |
| 140 X509Certificate::IsSameOSCert(*cert_handle, pos->second.cert_handle); | 140 X509Certificate::IsSameOSCert(*cert_handle, pos->second.cert_handle); |
| 141 if (!is_same_cert) { | 141 if (!is_same_cert) { |
| 142 // Two certificates don't match, due to a SHA1 hash collision. Given | 142 // Two certificates don't match, due to a SHA-256 hash collision. Given |
| 143 // the low probability, the simplest solution is to not cache the | 143 // the low probability, the simplest solution is to not cache the |
| 144 // certificate, which should not affect performance too negatively. | 144 // certificate, which should not affect performance too negatively. |
| 145 return; | 145 return; |
| 146 } | 146 } |
| 147 // A cached entry was found and will be used instead of the caller's | 147 // A cached entry was found and will be used instead of the caller's |
| 148 // handle. Ensure the caller's original handle will be freed, since | 148 // handle. Ensure the caller's original handle will be freed, since |
| 149 // ownership is assumed. | 149 // ownership is assumed. |
| 150 old_handle = *cert_handle; | 150 old_handle = *cert_handle; |
| 151 } | 151 } |
| 152 // Whether an existing cached handle or a new handle, increment the | 152 // Whether an existing cached handle or a new handle, increment the |
| 153 // cache's reference count and return a handle that the caller can own. | 153 // cache's reference count and return a handle that the caller can own. |
| 154 ++pos->second.ref_count; | 154 ++pos->second.ref_count; |
| 155 *cert_handle = X509Certificate::DupOSCertHandle(pos->second.cert_handle); | 155 *cert_handle = X509Certificate::DupOSCertHandle(pos->second.cert_handle); |
| 156 } | 156 } |
| 157 // If the caller's handle was replaced with a cached handle, free the | 157 // If the caller's handle was replaced with a cached handle, free the |
| 158 // original handle now. This is done outside of the lock because | 158 // original handle now. This is done outside of the lock because |
| 159 // |old_handle| may be the only handle for this particular certificate, so | 159 // |old_handle| may be the only handle for this particular certificate, so |
| 160 // freeing it may be complex or resource-intensive and does not need to | 160 // freeing it may be complex or resource-intensive and does not need to |
| 161 // be guarded by the lock. | 161 // be guarded by the lock. |
| 162 if (old_handle) { | 162 if (old_handle) { |
| 163 X509Certificate::FreeOSCertHandle(old_handle); | 163 X509Certificate::FreeOSCertHandle(old_handle); |
| 164 #ifndef NDEBUG | 164 #ifndef NDEBUG |
| 165 LOCAL_HISTOGRAM_BOOLEAN("X509CertificateReuseCount", true); | 165 LOCAL_HISTOGRAM_BOOLEAN("X509CertificateReuseCount", true); |
| 166 #endif | 166 #endif |
| 167 } | 167 } |
| 168 } | 168 } |
| 169 | 169 |
| 170 void X509CertificateCache::Remove(X509Certificate::OSCertHandle cert_handle) { | 170 void X509CertificateCache::Remove(X509Certificate::OSCertHandle cert_handle) { |
| 171 SHA1HashValue fingerprint = | 171 SHA256HashValue fingerprint = |
| 172 X509Certificate::CalculateFingerprint(cert_handle); | 172 X509Certificate::CalculateFingerprint256(cert_handle); |
| 173 base::AutoLock lock(lock_); | 173 base::AutoLock lock(lock_); |
| 174 | 174 |
| 175 CertMap::iterator pos = cache_.find(fingerprint); | 175 CertMap::iterator pos = cache_.find(fingerprint); |
| 176 if (pos == cache_.end()) | 176 if (pos == cache_.end()) |
| 177 return; // A hash collision where the winning cert was already freed. | 177 return; // A hash collision where the winning cert was already freed. |
| 178 | 178 |
| 179 bool is_same_cert = X509Certificate::IsSameOSCert(cert_handle, | 179 bool is_same_cert = X509Certificate::IsSameOSCert(cert_handle, |
| 180 pos->second.cert_handle); | 180 pos->second.cert_handle); |
| 181 if (!is_same_cert) | 181 if (!is_same_cert) |
| 182 return; // A hash collision where the winning cert is still around. | 182 return; // A hash collision where the winning cert is still around. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 *left = src; | 218 *left = src; |
| 219 right->clear(); | 219 right->clear(); |
| 220 } else { | 220 } else { |
| 221 *left = src.substr(0, pos); | 221 *left = src.substr(0, pos); |
| 222 *right = src.substr(pos); | 222 *right = src.substr(pos); |
| 223 } | 223 } |
| 224 } | 224 } |
| 225 | 225 |
| 226 } // namespace | 226 } // namespace |
| 227 | 227 |
| 228 bool X509Certificate::LessThan::operator()( | |
| 229 const scoped_refptr<X509Certificate>& lhs, | |
| 230 const scoped_refptr<X509Certificate>& rhs) const { | |
| 231 if (lhs.get() == rhs.get()) | |
| 232 return false; | |
| 233 | |
| 234 int rv = memcmp(lhs->fingerprint_.data, rhs->fingerprint_.data, | |
| 235 sizeof(lhs->fingerprint_.data)); | |
| 236 if (rv != 0) | |
| 237 return rv < 0; | |
| 238 | |
| 239 rv = memcmp(lhs->ca_fingerprint_.data, rhs->ca_fingerprint_.data, | |
| 240 sizeof(lhs->ca_fingerprint_.data)); | |
| 241 return rv < 0; | |
| 242 } | |
| 243 | |
| 244 X509Certificate::X509Certificate(const std::string& subject, | 228 X509Certificate::X509Certificate(const std::string& subject, |
| 245 const std::string& issuer, | 229 const std::string& issuer, |
| 246 base::Time start_date, | 230 base::Time start_date, |
| 247 base::Time expiration_date) | 231 base::Time expiration_date) |
| 248 : subject_(subject), | 232 : subject_(subject), |
| 249 issuer_(issuer), | 233 issuer_(issuer), |
| 250 valid_start_(start_date), | 234 valid_start_(start_date), |
| 251 valid_expiry_(expiration_date), | 235 valid_expiry_(expiration_date), |
| 252 cert_handle_(NULL) { | 236 cert_handle_(NULL) { |
| 253 memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); | |
| 254 memset(ca_fingerprint_.data, 0, sizeof(ca_fingerprint_.data)); | |
| 255 } | 237 } |
| 256 | 238 |
| 257 // static | 239 // static |
| 258 scoped_refptr<X509Certificate> X509Certificate::CreateFromHandle( | 240 scoped_refptr<X509Certificate> X509Certificate::CreateFromHandle( |
| 259 OSCertHandle cert_handle, | 241 OSCertHandle cert_handle, |
| 260 const OSCertHandles& intermediates) { | 242 const OSCertHandles& intermediates) { |
| 261 DCHECK(cert_handle); | 243 DCHECK(cert_handle); |
| 262 return new X509Certificate(cert_handle, intermediates); | 244 return new X509Certificate(cert_handle, intermediates); |
| 263 } | 245 } |
| 264 | 246 |
| (...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 703 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { | 685 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { |
| 704 if (!GetPEMEncoded(intermediate_ca_certs_[i], &pem_data)) | 686 if (!GetPEMEncoded(intermediate_ca_certs_[i], &pem_data)) |
| 705 return false; | 687 return false; |
| 706 encoded_chain.push_back(pem_data); | 688 encoded_chain.push_back(pem_data); |
| 707 } | 689 } |
| 708 pem_encoded->swap(encoded_chain); | 690 pem_encoded->swap(encoded_chain); |
| 709 return true; | 691 return true; |
| 710 } | 692 } |
| 711 | 693 |
| 712 // static | 694 // static |
| 713 SHA256HashValue X509Certificate::CalculateCAFingerprint256( | |
| 714 const OSCertHandles& intermediates) { | |
| 715 SHA256HashValue sha256; | |
| 716 memset(sha256.data, 0, sizeof(sha256.data)); | |
| 717 | |
| 718 std::unique_ptr<crypto::SecureHash> hash( | |
| 719 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | |
| 720 | |
| 721 for (size_t i = 0; i < intermediates.size(); ++i) { | |
| 722 std::string der_encoded; | |
| 723 if (!GetDEREncoded(intermediates[i], &der_encoded)) | |
| 724 return sha256; | |
| 725 hash->Update(der_encoded.data(), der_encoded.length()); | |
| 726 } | |
| 727 hash->Finish(sha256.data, sizeof(sha256.data)); | |
| 728 | |
| 729 return sha256; | |
| 730 } | |
| 731 | |
| 732 // static | |
| 733 SHA256HashValue X509Certificate::CalculateChainFingerprint256( | 695 SHA256HashValue X509Certificate::CalculateChainFingerprint256( |
| 734 OSCertHandle leaf, | 696 OSCertHandle leaf, |
| 735 const OSCertHandles& intermediates) { | 697 const OSCertHandles& intermediates) { |
| 736 OSCertHandles chain; | 698 OSCertHandles chain; |
| 737 chain.push_back(leaf); | 699 chain.push_back(leaf); |
| 738 chain.insert(chain.end(), intermediates.begin(), intermediates.end()); | 700 chain.insert(chain.end(), intermediates.begin(), intermediates.end()); |
| 739 | 701 |
| 740 return CalculateCAFingerprint256(chain); | 702 return CalculateCAFingerprint256(chain); |
| 741 } | 703 } |
| 742 | 704 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 762 RemoveFromCache(cert_handle_); | 724 RemoveFromCache(cert_handle_); |
| 763 FreeOSCertHandle(cert_handle_); | 725 FreeOSCertHandle(cert_handle_); |
| 764 } | 726 } |
| 765 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { | 727 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { |
| 766 RemoveFromCache(intermediate_ca_certs_[i]); | 728 RemoveFromCache(intermediate_ca_certs_[i]); |
| 767 FreeOSCertHandle(intermediate_ca_certs_[i]); | 729 FreeOSCertHandle(intermediate_ca_certs_[i]); |
| 768 } | 730 } |
| 769 } | 731 } |
| 770 | 732 |
| 771 } // namespace net | 733 } // namespace net |
| OLD | NEW |