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_util_openssl.h" | 5 #include "net/cert/x509_util_openssl.h" |
6 | 6 |
7 #include <limits.h> | 7 #include <limits.h> |
8 #include <openssl/asn1.h> | 8 #include <openssl/asn1.h> |
9 #include <openssl/digest.h> | 9 #include <openssl/digest.h> |
10 #include <openssl/mem.h> | 10 #include <openssl/mem.h> |
11 | 11 |
12 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <map> |
13 #include <memory> | 14 #include <memory> |
14 | 15 |
15 #include "base/lazy_instance.h" | 16 #include "base/lazy_instance.h" |
16 #include "base/logging.h" | 17 #include "base/logging.h" |
17 #include "base/macros.h" | 18 #include "base/macros.h" |
18 #include "base/strings/string_piece.h" | 19 #include "base/strings/string_piece.h" |
19 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 21 #include "base/synchronization/lock.h" |
20 #include "crypto/ec_private_key.h" | 22 #include "crypto/ec_private_key.h" |
21 #include "crypto/openssl_util.h" | 23 #include "crypto/openssl_util.h" |
22 #include "crypto/rsa_private_key.h" | 24 #include "crypto/rsa_private_key.h" |
23 #include "crypto/scoped_openssl_types.h" | 25 #include "crypto/scoped_openssl_types.h" |
24 #include "net/cert/internal/parse_certificate.h" | 26 #include "net/cert/internal/parse_certificate.h" |
25 #include "net/cert/internal/signature_algorithm.h" | 27 #include "net/cert/internal/signature_algorithm.h" |
26 #include "net/cert/x509_cert_types.h" | 28 #include "net/cert/x509_cert_types.h" |
27 #include "net/cert/x509_certificate.h" | 29 #include "net/cert/x509_certificate.h" |
28 #include "net/cert/x509_util.h" | 30 #include "net/cert/x509_util.h" |
29 #include "net/ssl/scoped_openssl_types.h" | 31 #include "net/ssl/scoped_openssl_types.h" |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 // Sign it with the private key. | 167 // Sign it with the private key. |
166 if (!X509_sign(cert, key, md)) { | 168 if (!X509_sign(cert, key, md)) { |
167 LOG(ERROR) << "Could not sign certificate with key."; | 169 LOG(ERROR) << "Could not sign certificate with key."; |
168 return false; | 170 return false; |
169 } | 171 } |
170 | 172 |
171 // Convert it into a DER-encoded string copied to |der_encoded|. | 173 // Convert it into a DER-encoded string copied to |der_encoded|. |
172 return DerEncodeCert(cert, der_encoded); | 174 return DerEncodeCert(cert, der_encoded); |
173 } | 175 } |
174 | 176 |
175 struct DERCache { | 177 // Re-encoding the DER data via i2d_X509 is an expensive operation, but |
176 std::string data; | 178 // it's necessary for comparing two certificates. Re-encode at most once |
177 }; | 179 // per certificate and cache the pointer to the data within the X509 cert |
178 | 180 // using X509_set_ex_data. For memory efficiency the DER data itself is |
179 void DERCache_free(void* parent, void* ptr, CRYPTO_EX_DATA* ad, int idx, | 181 // stored globally, shared between certificates and is deleted once all |
180 long argl, void* argp) { | 182 // certificates that reference it are deleted. |
181 DERCache* der_cache = static_cast<DERCache*>(ptr); | 183 class DerCache { |
182 delete der_cache; | |
183 } | |
184 | |
185 class DERCacheInitSingleton { | |
186 public: | 184 public: |
187 DERCacheInitSingleton() { | 185 // Returns nullptr only if DerEncodeCert() has failed. |
188 crypto::EnsureOpenSSLInit(); | 186 static const std::string* Get(X509* cert) { |
189 der_cache_ex_index_ = X509_get_ex_new_index(0, 0, 0, 0, DERCache_free); | 187 const std::string* cached_der = GetInstance().Retrieve(cert); |
190 DCHECK_NE(-1, der_cache_ex_index_); | 188 if (cached_der) { |
| 189 return cached_der; |
| 190 } |
| 191 std::string der; |
| 192 if (!DerEncodeCert(cert, &der)) { |
| 193 return nullptr; |
| 194 } |
| 195 return GetInstance().Put(cert, std::move(der)); |
191 } | 196 } |
192 | 197 |
193 int der_cache_ex_index() const { return der_cache_ex_index_; } | 198 private: |
| 199 friend struct base::DefaultLazyInstanceTraits<DerCache>; |
194 | 200 |
195 private: | 201 DerCache() { |
196 int der_cache_ex_index_; | 202 crypto::EnsureOpenSSLInit(); |
| 203 x509_value_index_ = |
| 204 X509_get_ex_new_index(0, nullptr, nullptr, nullptr, &free_x509_value); |
| 205 DCHECK_NE(-1, x509_value_index_); |
| 206 } |
197 | 207 |
198 DISALLOW_COPY_AND_ASSIGN(DERCacheInitSingleton); | 208 const std::string* Retrieve(X509* cert) const { |
| 209 return static_cast<const std::string*>( |
| 210 X509_get_ex_data(cert, x509_value_index_)); |
| 211 } |
| 212 |
| 213 const std::string* Put(X509* cert, std::string der) { |
| 214 base::AutoLock lock(lock_); |
| 215 auto der_iter = count_by_der_.emplace(std::move(der), 0).first; |
| 216 der_iter->second++; // add a reference |
| 217 const std::string* cached_der = &der_iter->first; |
| 218 X509_set_ex_data(cert, x509_value_index_, |
| 219 const_cast<std::string*>(cached_der)); |
| 220 return cached_der; |
| 221 } |
| 222 |
| 223 void Remove(const std::string& der) { |
| 224 base::AutoLock lock(lock_); |
| 225 auto der_iter = count_by_der_.find(der); |
| 226 DCHECK(count_by_der_.end() != der_iter); |
| 227 der_iter->second--; // remove a reference |
| 228 if (der_iter->second == 0) { |
| 229 count_by_der_.erase(der_iter); |
| 230 } |
| 231 } |
| 232 |
| 233 static DerCache& GetInstance() { |
| 234 static base::LazyInstance<DerCache>::Leaky instance = |
| 235 LAZY_INSTANCE_INITIALIZER; |
| 236 return instance.Get(); |
| 237 } |
| 238 |
| 239 static void free_x509_value(void* parent, |
| 240 void* value, |
| 241 CRYPTO_EX_DATA* ad, |
| 242 int idx, |
| 243 long argl, |
| 244 void* argp) { |
| 245 const std::string* cached_der = static_cast<const std::string*>(value); |
| 246 DCHECK(cached_der); |
| 247 GetInstance().Remove(*cached_der); |
| 248 } |
| 249 |
| 250 int x509_value_index_; |
| 251 std::map<std::string, size_t> count_by_der_; |
| 252 base::Lock lock_; |
199 }; | 253 }; |
200 | 254 |
201 base::LazyInstance<DERCacheInitSingleton>::Leaky g_der_cache_singleton = | |
202 LAZY_INSTANCE_INITIALIZER; | |
203 | |
204 } // namespace | 255 } // namespace |
205 | 256 |
206 bool CreateSelfSignedCert(crypto::RSAPrivateKey* key, | 257 bool CreateSelfSignedCert(crypto::RSAPrivateKey* key, |
207 DigestAlgorithm alg, | 258 DigestAlgorithm alg, |
208 const std::string& common_name, | 259 const std::string& common_name, |
209 uint32_t serial_number, | 260 uint32_t serial_number, |
210 base::Time not_valid_before, | 261 base::Time not_valid_before, |
211 base::Time not_valid_after, | 262 base::Time not_valid_after, |
212 std::string* der_encoded) { | 263 std::string* der_encoded) { |
213 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | 264 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 return false; | 328 return false; |
278 | 329 |
279 base::StringPiece str_date(reinterpret_cast<const char*>(x509_time->data), | 330 base::StringPiece str_date(reinterpret_cast<const char*>(x509_time->data), |
280 x509_time->length); | 331 x509_time->length); |
281 | 332 |
282 CertDateFormat format = x509_time->type == V_ASN1_UTCTIME ? | 333 CertDateFormat format = x509_time->type == V_ASN1_UTCTIME ? |
283 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; | 334 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; |
284 return ParseCertificateDate(str_date, format, time); | 335 return ParseCertificateDate(str_date, format, time); |
285 } | 336 } |
286 | 337 |
287 // Returns true if |der_cache| points to valid data, false otherwise. | 338 // Returns true if |out_der| points to valid data, false otherwise. |
288 // (note: the DER-encoded data in |der_cache| is owned by |cert|, callers should | 339 // (note: the DER-encoded data in |out_der| is owned by |cert|, callers should |
289 // not free it). | 340 // not free it). |
290 bool GetDER(X509* x509, base::StringPiece* der_cache) { | 341 bool GetDER(X509* x509, base::StringPiece* out_der) { |
291 int x509_der_cache_index = | 342 const std::string* cached_der = DerCache::Get(x509); |
292 g_der_cache_singleton.Get().der_cache_ex_index(); | 343 if (!cached_der) { |
293 | 344 return false; |
294 // Re-encoding the DER data via i2d_X509 is an expensive operation, | |
295 // but it's necessary for comparing two certificates. Re-encode at | |
296 // most once per certificate and cache the data within the X509 cert | |
297 // using X509_set_ex_data. | |
298 DERCache* internal_cache = static_cast<DERCache*>( | |
299 X509_get_ex_data(x509, x509_der_cache_index)); | |
300 if (!internal_cache) { | |
301 std::unique_ptr<DERCache> new_cache(new DERCache); | |
302 if (!DerEncodeCert(x509, &new_cache->data)) | |
303 return false; | |
304 internal_cache = new_cache.get(); | |
305 X509_set_ex_data(x509, x509_der_cache_index, new_cache.release()); | |
306 } | 345 } |
307 *der_cache = base::StringPiece(internal_cache->data); | 346 *out_der = base::StringPiece(*cached_der); |
308 return true; | 347 return true; |
309 } | 348 } |
310 | 349 |
311 bool GetTLSServerEndPointChannelBinding(const X509Certificate& certificate, | 350 bool GetTLSServerEndPointChannelBinding(const X509Certificate& certificate, |
312 std::string* token) { | 351 std::string* token) { |
313 static const char kChannelBindingPrefix[] = "tls-server-end-point:"; | 352 static const char kChannelBindingPrefix[] = "tls-server-end-point:"; |
314 | 353 |
315 std::string der_encoded_certificate; | 354 std::string der_encoded_certificate; |
316 if (!X509Certificate::GetDEREncoded(certificate.os_cert_handle(), | 355 if (!X509Certificate::GetDEREncoded(certificate.os_cert_handle(), |
317 &der_encoded_certificate)) | 356 &der_encoded_certificate)) |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 | 396 |
358 digest.resize(out_size); | 397 digest.resize(out_size); |
359 token->assign(kChannelBindingPrefix); | 398 token->assign(kChannelBindingPrefix); |
360 token->append(digest.begin(), digest.end()); | 399 token->append(digest.begin(), digest.end()); |
361 return true; | 400 return true; |
362 } | 401 } |
363 | 402 |
364 } // namespace x509_util | 403 } // namespace x509_util |
365 | 404 |
366 } // namespace net | 405 } // namespace net |
OLD | NEW |