| 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 <memory> | 13 #include <memory> |
| 14 #include <map> |
| 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" |
| 20 #include "crypto/ec_private_key.h" | 21 #include "crypto/ec_private_key.h" |
| 21 #include "crypto/openssl_util.h" | 22 #include "crypto/openssl_util.h" |
| 22 #include "crypto/rsa_private_key.h" | 23 #include "crypto/rsa_private_key.h" |
| 23 #include "crypto/scoped_openssl_types.h" | 24 #include "crypto/scoped_openssl_types.h" |
| 24 #include "net/cert/internal/parse_certificate.h" | 25 #include "net/cert/internal/parse_certificate.h" |
| 25 #include "net/cert/internal/signature_algorithm.h" | 26 #include "net/cert/internal/signature_algorithm.h" |
| 26 #include "net/cert/x509_cert_types.h" | 27 #include "net/cert/x509_cert_types.h" |
| 27 #include "net/cert/x509_certificate.h" | 28 #include "net/cert/x509_certificate.h" |
| 28 #include "net/cert/x509_util.h" | 29 #include "net/cert/x509_util.h" |
| 29 #include "net/ssl/scoped_openssl_types.h" | 30 #include "net/ssl/scoped_openssl_types.h" |
| 30 | 31 |
| 32 #if defined(OS_ANDROID) |
| 33 #include <android/log.h> |
| 34 #define PRINTF(format, arguments...) \ |
| 35 __android_log_print(ANDROID_LOG_WARN, "PRINTF", format, ##arguments) |
| 36 #else |
| 37 #define PRINTF printf |
| 38 #endif |
| 39 |
| 31 namespace net { | 40 namespace net { |
| 32 | 41 |
| 33 namespace { | 42 namespace { |
| 34 | 43 |
| 35 using ScopedASN1_INTEGER = | 44 using ScopedASN1_INTEGER = |
| 36 crypto::ScopedOpenSSL<ASN1_INTEGER, ASN1_INTEGER_free>; | 45 crypto::ScopedOpenSSL<ASN1_INTEGER, ASN1_INTEGER_free>; |
| 37 using ScopedASN1_OCTET_STRING = | 46 using ScopedASN1_OCTET_STRING = |
| 38 crypto::ScopedOpenSSL<ASN1_OCTET_STRING, ASN1_OCTET_STRING_free>; | 47 crypto::ScopedOpenSSL<ASN1_OCTET_STRING, ASN1_OCTET_STRING_free>; |
| 39 using ScopedASN1_STRING = crypto::ScopedOpenSSL<ASN1_STRING, ASN1_STRING_free>; | 48 using ScopedASN1_STRING = crypto::ScopedOpenSSL<ASN1_STRING, ASN1_STRING_free>; |
| 40 using ScopedASN1_TIME = crypto::ScopedOpenSSL<ASN1_TIME, ASN1_TIME_free>; | 49 using ScopedASN1_TIME = crypto::ScopedOpenSSL<ASN1_TIME, ASN1_TIME_free>; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 // Sign it with the private key. | 174 // Sign it with the private key. |
| 166 if (!X509_sign(cert, key, md)) { | 175 if (!X509_sign(cert, key, md)) { |
| 167 LOG(ERROR) << "Could not sign certificate with key."; | 176 LOG(ERROR) << "Could not sign certificate with key."; |
| 168 return false; | 177 return false; |
| 169 } | 178 } |
| 170 | 179 |
| 171 // Convert it into a DER-encoded string copied to |der_encoded|. | 180 // Convert it into a DER-encoded string copied to |der_encoded|. |
| 172 return DerEncodeCert(cert, der_encoded); | 181 return DerEncodeCert(cert, der_encoded); |
| 173 } | 182 } |
| 174 | 183 |
| 184 struct { |
| 185 pthread_mutex_t lock; |
| 186 size_t hits; |
| 187 size_t misses; |
| 188 size_t count; |
| 189 size_t total_size; |
| 190 size_t total_unique_size; |
| 191 std::map<std::string, size_t>* uniques; |
| 192 } g_der_cache_stats = {PTHREAD_MUTEX_INITIALIZER}; |
| 193 |
| 194 enum DERCacheAction { |
| 195 DER_HIT, |
| 196 DER_MISS, |
| 197 DER_REMOVE |
| 198 }; |
| 199 |
| 200 void UpdateDERCacheStats(DERCacheAction action, const std::string* data) { |
| 201 auto& stats = g_der_cache_stats; |
| 202 pthread_mutex_lock(&stats.lock); |
| 203 switch (action) { |
| 204 case DER_HIT: { |
| 205 stats.hits++; |
| 206 break; |
| 207 } |
| 208 case DER_MISS: { |
| 209 stats.misses++; |
| 210 stats.count++; |
| 211 stats.total_size += data->capacity(); |
| 212 if (!stats.uniques) { |
| 213 stats.uniques = new std::map<std::string, size_t>(); |
| 214 } |
| 215 auto insert_result = stats.uniques->emplace(*data, 0); |
| 216 auto unique_iter = insert_result.first; |
| 217 bool inserted = insert_result.second; |
| 218 if (inserted) { |
| 219 stats.total_unique_size += unique_iter->first.capacity(); |
| 220 } |
| 221 unique_iter->second++; |
| 222 break; |
| 223 } |
| 224 case DER_REMOVE: { |
| 225 stats.count -= 1; |
| 226 stats.total_size -= data->capacity(); |
| 227 auto unique_iter = stats.uniques->find(*data); |
| 228 CHECK(unique_iter != stats.uniques->end()); |
| 229 unique_iter->second--; |
| 230 if (unique_iter->second == 0) { |
| 231 stats.total_unique_size -= unique_iter->first.capacity(); |
| 232 stats.uniques->erase(unique_iter); |
| 233 } |
| 234 break; |
| 235 } |
| 236 } |
| 237 if (action != DER_HIT) { |
| 238 PRINTF("DERCache: %zu KiB @ %zu instances (%zu KiB @ %zu unique), " |
| 239 "hit rate: %.1f%% (%zu/%zu)\n", |
| 240 stats.total_size / 1024, stats.count, |
| 241 stats.total_unique_size / 1024, stats.uniques->size(), |
| 242 stats.hits * 100.0 / (stats.hits + stats.misses), |
| 243 stats.hits, stats.misses); |
| 244 } |
| 245 pthread_mutex_unlock(&stats.lock); |
| 246 } |
| 247 |
| 175 struct DERCache { | 248 struct DERCache { |
| 176 std::string data; | 249 std::string data; |
| 250 |
| 251 ~DERCache() { |
| 252 UpdateDERCacheStats(DER_REMOVE, &data); |
| 253 } |
| 177 }; | 254 }; |
| 178 | 255 |
| 179 void DERCache_free(void* parent, void* ptr, CRYPTO_EX_DATA* ad, int idx, | 256 void DERCache_free(void* parent, void* ptr, CRYPTO_EX_DATA* ad, int idx, |
| 180 long argl, void* argp) { | 257 long argl, void* argp) { |
| 181 DERCache* der_cache = static_cast<DERCache*>(ptr); | 258 DERCache* der_cache = static_cast<DERCache*>(ptr); |
| 182 delete der_cache; | 259 delete der_cache; |
| 183 } | 260 } |
| 184 | 261 |
| 185 class DERCacheInitSingleton { | 262 class DERCacheInitSingleton { |
| 186 public: | 263 public: |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 // Re-encoding the DER data via i2d_X509 is an expensive operation, | 371 // Re-encoding the DER data via i2d_X509 is an expensive operation, |
| 295 // but it's necessary for comparing two certificates. Re-encode at | 372 // but it's necessary for comparing two certificates. Re-encode at |
| 296 // most once per certificate and cache the data within the X509 cert | 373 // most once per certificate and cache the data within the X509 cert |
| 297 // using X509_set_ex_data. | 374 // using X509_set_ex_data. |
| 298 DERCache* internal_cache = static_cast<DERCache*>( | 375 DERCache* internal_cache = static_cast<DERCache*>( |
| 299 X509_get_ex_data(x509, x509_der_cache_index)); | 376 X509_get_ex_data(x509, x509_der_cache_index)); |
| 300 if (!internal_cache) { | 377 if (!internal_cache) { |
| 301 std::unique_ptr<DERCache> new_cache(new DERCache); | 378 std::unique_ptr<DERCache> new_cache(new DERCache); |
| 302 if (!DerEncodeCert(x509, &new_cache->data)) | 379 if (!DerEncodeCert(x509, &new_cache->data)) |
| 303 return false; | 380 return false; |
| 381 UpdateDERCacheStats(DER_MISS, &new_cache->data); |
| 304 internal_cache = new_cache.get(); | 382 internal_cache = new_cache.get(); |
| 305 X509_set_ex_data(x509, x509_der_cache_index, new_cache.release()); | 383 X509_set_ex_data(x509, x509_der_cache_index, new_cache.release()); |
| 384 } else { |
| 385 UpdateDERCacheStats(DER_HIT, nullptr); |
| 306 } | 386 } |
| 307 *der_cache = base::StringPiece(internal_cache->data); | 387 *der_cache = base::StringPiece(internal_cache->data); |
| 308 return true; | 388 return true; |
| 309 } | 389 } |
| 310 | 390 |
| 311 bool GetTLSServerEndPointChannelBinding(const X509Certificate& certificate, | 391 bool GetTLSServerEndPointChannelBinding(const X509Certificate& certificate, |
| 312 std::string* token) { | 392 std::string* token) { |
| 313 static const char kChannelBindingPrefix[] = "tls-server-end-point:"; | 393 static const char kChannelBindingPrefix[] = "tls-server-end-point:"; |
| 314 | 394 |
| 315 std::string der_encoded_certificate; | 395 std::string der_encoded_certificate; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 | 437 |
| 358 digest.resize(out_size); | 438 digest.resize(out_size); |
| 359 token->assign(kChannelBindingPrefix); | 439 token->assign(kChannelBindingPrefix); |
| 360 token->append(digest.begin(), digest.end()); | 440 token->append(digest.begin(), digest.end()); |
| 361 return true; | 441 return true; |
| 362 } | 442 } |
| 363 | 443 |
| 364 } // namespace x509_util | 444 } // namespace x509_util |
| 365 | 445 |
| 366 } // namespace net | 446 } // namespace net |
| OLD | NEW |