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> |
(...skipping 65 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); |
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 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()( | 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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |