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