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 |