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

Side by Side Diff: net/cert/x509_certificate.cc

Issue 2000503002: Remove the fingerprint and ca_fingerprint from X509Certificate (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@move_cache
Patch Set: Created 4 years, 7 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
OLDNEW
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>
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
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);
eroman 2016/05/26 01:46:26 If we are able to get hash collisions on SHA-256 w
Ryan Sleevi 2016/05/26 07:48:38 This seems like an unrelated request, and I'm not
eroman 2016/05/26 20:28:55 My concern starts with the comment below: // Tw
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,
eroman 2016/05/26 01:46:26 Same here.
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.
183 183
184 if (--pos->second.ref_count == 0) { 184 if (--pos->second.ref_count == 0) {
185 // The last reference to |cert_handle| has been removed, so release the 185 // The last reference to |cert_handle| has been removed, so release the
186 // Entry's OS handle and remove the Entry. The caller still holds a 186 // Entry's OS handle and remove the Entry. The caller still holds a
187 // reference to |cert_handle| and is responsible for freeing it. 187 // reference to |cert_handle| and is responsible for freeing it.
188 X509Certificate::FreeOSCertHandle(pos->second.cert_handle); 188 X509Certificate::FreeOSCertHandle(pos->second.cert_handle);
189 cache_.erase(pos); 189 cache_.erase(pos);
(...skipping 28 matching lines...) Expand all
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()( 228 bool X509Certificate::LessThan::operator()(
Ryan Sleevi 2016/05/20 06:02:31 The thing that makes me unhappy is this ends up be
eroman 2016/05/26 01:46:26 Doing a codesearch didn't turn up references for t
Ryan Sleevi 2016/05/26 07:48:38 Yup, that's why I thought this was safer than it w
229 const scoped_refptr<X509Certificate>& lhs, 229 const scoped_refptr<X509Certificate>& lhs,
230 const scoped_refptr<X509Certificate>& rhs) const { 230 const scoped_refptr<X509Certificate>& rhs) const {
231 if (lhs.get() == rhs.get()) 231 if (lhs == rhs)
232 return false; 232 return false;
233 233
234 int rv = memcmp(lhs->fingerprint_.data, rhs->fingerprint_.data, 234 std::string lhs_der;
235 sizeof(lhs->fingerprint_.data)); 235 X509Certificate::GetDEREncoded(lhs->os_cert_handle(), &lhs_der);
236 if (rv != 0)
237 return rv < 0;
238 236
239 rv = memcmp(lhs->ca_fingerprint_.data, rhs->ca_fingerprint_.data, 237 std::string rhs_der;
240 sizeof(lhs->ca_fingerprint_.data)); 238 X509Certificate::GetDEREncoded(rhs->os_cert_handle(), &rhs_der);
eroman 2016/05/26 01:46:26 None of this code checks for failure from GetDEREn
Ryan Sleevi 2016/05/26 07:48:38 This is the correct answer, sorry for not document
241 return rv < 0; 239 if (lhs_der != rhs_der)
240 return lhs_der < rhs_der;
241
242 const X509Certificate::OSCertHandles& lhs_intermediates =
243 lhs->GetIntermediateCertificates();
244 const X509Certificate::OSCertHandles& rhs_intermediates =
245 rhs->GetIntermediateCertificates();
246 return std::lexicographical_compare(
eroman 2016/05/30 20:20:30 This is worth noting in the documentation for Less
247 lhs_intermediates.begin(), lhs_intermediates.end(),
248 rhs_intermediates.begin(), rhs_intermediates.end(),
249 [](const X509Certificate::OSCertHandle& left,
250 const X509Certificate::OSCertHandle& right) {
251 std::string left_encoded;
252 X509Certificate::GetDEREncoded(left, &left_encoded);
253 std::string right_encoded;
254 X509Certificate::GetDEREncoded(right, &right_encoded);
255 return left_encoded < right_encoded;
eroman 2016/05/30 20:20:30 To confirm: The ordering itself wasn't being relie
256 });
242 } 257 }
243 258
244 X509Certificate::X509Certificate(const std::string& subject, 259 X509Certificate::X509Certificate(const std::string& subject,
245 const std::string& issuer, 260 const std::string& issuer,
246 base::Time start_date, 261 base::Time start_date,
247 base::Time expiration_date) 262 base::Time expiration_date)
248 : subject_(subject), 263 : subject_(subject),
249 issuer_(issuer), 264 issuer_(issuer),
250 valid_start_(start_date), 265 valid_start_(start_date),
251 valid_expiry_(expiration_date), 266 valid_expiry_(expiration_date),
252 cert_handle_(NULL) { 267 cert_handle_(NULL) {
253 memset(fingerprint_.data, 0, sizeof(fingerprint_.data));
254 memset(ca_fingerprint_.data, 0, sizeof(ca_fingerprint_.data));
255 } 268 }
256 269
257 // static 270 // static
258 scoped_refptr<X509Certificate> X509Certificate::CreateFromHandle( 271 scoped_refptr<X509Certificate> X509Certificate::CreateFromHandle(
259 OSCertHandle cert_handle, 272 OSCertHandle cert_handle,
260 const OSCertHandles& intermediates) { 273 const OSCertHandles& intermediates) {
261 DCHECK(cert_handle); 274 DCHECK(cert_handle);
262 return new X509Certificate(cert_handle, intermediates); 275 return new X509Certificate(cert_handle, intermediates);
263 } 276 }
264 277
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { 716 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) {
704 if (!GetPEMEncoded(intermediate_ca_certs_[i], &pem_data)) 717 if (!GetPEMEncoded(intermediate_ca_certs_[i], &pem_data))
705 return false; 718 return false;
706 encoded_chain.push_back(pem_data); 719 encoded_chain.push_back(pem_data);
707 } 720 }
708 pem_encoded->swap(encoded_chain); 721 pem_encoded->swap(encoded_chain);
709 return true; 722 return true;
710 } 723 }
711 724
712 // static 725 // 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( 726 SHA256HashValue X509Certificate::CalculateChainFingerprint256(
734 OSCertHandle leaf, 727 OSCertHandle leaf,
735 const OSCertHandles& intermediates) { 728 const OSCertHandles& intermediates) {
736 OSCertHandles chain; 729 OSCertHandles chain;
737 chain.push_back(leaf); 730 chain.push_back(leaf);
738 chain.insert(chain.end(), intermediates.begin(), intermediates.end()); 731 chain.insert(chain.end(), intermediates.begin(), intermediates.end());
739 732
740 return CalculateCAFingerprint256(chain); 733 return CalculateCAFingerprint256(chain);
741 } 734 }
742 735
(...skipping 19 matching lines...) Expand all
762 RemoveFromCache(cert_handle_); 755 RemoveFromCache(cert_handle_);
763 FreeOSCertHandle(cert_handle_); 756 FreeOSCertHandle(cert_handle_);
764 } 757 }
765 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { 758 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) {
766 RemoveFromCache(intermediate_ca_certs_[i]); 759 RemoveFromCache(intermediate_ca_certs_[i]);
767 FreeOSCertHandle(intermediate_ca_certs_[i]); 760 FreeOSCertHandle(intermediate_ca_certs_[i]);
768 } 761 }
769 } 762 }
770 763
771 } // namespace net 764 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698