diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-29 03:49:49 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-29 03:49:49 +0000 |
commit | 931945aa9d1a72f61eb37d3f75eb13a542d4fc2e (patch) | |
tree | f0ff0f2bb66f1dadff926ae7bb3dd270692ae146 | |
parent | c5addfbb9cb0518d8346cc9b827c2a5e8c32957d (diff) | |
download | chromium_src-931945aa9d1a72f61eb37d3f75eb13a542d4fc2e.zip chromium_src-931945aa9d1a72f61eb37d3f75eb13a542d4fc2e.tar.gz chromium_src-931945aa9d1a72f61eb37d3f75eb13a542d4fc2e.tar.bz2 |
Reverting 8864.
Revert r8864. It broke the build url_request_intercept_job.cc.
Review URL: http://codereview.chromium.org/19462
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8868 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/base/ssl_client_socket_mac.cc | 3 | ||||
-rw-r--r-- | net/base/ssl_client_socket_win.cc | 3 | ||||
-rw-r--r-- | net/base/x509_certificate.cc | 62 | ||||
-rw-r--r-- | net/base/x509_certificate.h | 41 | ||||
-rw-r--r-- | net/base/x509_certificate_mac.cc | 121 | ||||
-rw-r--r-- | net/base/x509_certificate_nss.cc | 108 | ||||
-rw-r--r-- | net/base/x509_certificate_unittest.cc | 103 | ||||
-rw-r--r-- | net/base/x509_certificate_win.cc | 114 | ||||
-rw-r--r-- | net/http/http_cache.cc | 2 |
9 files changed, 256 insertions, 301 deletions
diff --git a/net/base/ssl_client_socket_mac.cc b/net/base/ssl_client_socket_mac.cc index 24d33e5..f4b636e 100644 --- a/net/base/ssl_client_socket_mac.cc +++ b/net/base/ssl_client_socket_mac.cc @@ -380,8 +380,7 @@ void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) { static_cast<SecCertificateRef>( const_cast<void*>(CFArrayGetValueAtIndex(certs, 0))); CFRetain(client_cert); - ssl_info->cert = X509Certificate::CreateFromHandle( - client_cert, X509Certificate::SOURCE_FROM_NETWORK); + ssl_info->cert = X509Certificate::CreateFromHandle(client_cert); CFRelease(certs); } diff --git a/net/base/ssl_client_socket_win.cc b/net/base/ssl_client_socket_win.cc index 1f4c314..beeaba9 100644 --- a/net/base/ssl_client_socket_win.cc +++ b/net/base/ssl_client_socket_win.cc @@ -359,8 +359,7 @@ void SSLClientSocketWin::GetSSLInfo(SSLInfo* ssl_info) { if (status == SEC_E_OK) { DCHECK(server_cert_); PCCERT_CONTEXT dup_cert = CertDuplicateCertificateContext(server_cert_); - ssl_info->cert = X509Certificate::CreateFromHandle( - dup_cert, X509Certificate::SOURCE_FROM_NETWORK); + ssl_info->cert = X509Certificate::CreateFromHandle(dup_cert); } SecPkgContext_ConnectionInfo connection_info; status = QueryContextAttributes(&ctxt_, diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc index 443ef81..d62f963 100644 --- a/net/base/x509_certificate.cc +++ b/net/base/x509_certificate.cc @@ -4,7 +4,6 @@ #include "net/base/x509_certificate.h" -#include "base/histogram.h" #include "base/logging.h" namespace net { @@ -123,66 +122,5 @@ void X509Certificate::Policy::Deny(X509Certificate* cert) { denied_.insert(cert->fingerprint()); } -// static -X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle, - Source source) { - DCHECK(cert_handle); - DCHECK(source != SOURCE_UNUSED); - - // Check if we already have this certificate in memory. - X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); - X509Certificate* cached_cert = - cache->Find(CalculateFingerprint(cert_handle)); - if (cached_cert) { - DCHECK(cached_cert->source_ != SOURCE_UNUSED); - if (cached_cert->source_ >= source) { - // We've found a certificate with the same fingerprint in our cache. We - // own the |cert_handle|, which makes it our job to free it. - FreeOSCertHandle(cert_handle); - DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); - return cached_cert; - } - // Kick out the old certificate from our cache. The new one is better. - cache->Remove(cached_cert); - } - // Otherwise, allocate a new object. - return new X509Certificate(cert_handle, source); -} - -// static -X509Certificate* X509Certificate::CreateFromBytes(const char* data, - int length) { - OSCertHandle cert_handle = CreateOSCertHandleFromBytes(data, length); - if (!cert_handle) - return NULL; - - return CreateFromHandle(cert_handle, SOURCE_LONE_CERT_IMPORT); -} - -X509Certificate::X509Certificate(OSCertHandle cert_handle, Source source) - : cert_handle_(cert_handle), source_(source) { - Initialize(); -} - -X509Certificate::X509Certificate(const std::string& subject, - const std::string& issuer, - base::Time start_date, - base::Time expiration_date) - : subject_(subject), - issuer_(issuer), - valid_start_(start_date), - valid_expiry_(expiration_date), - cert_handle_(NULL), - source_(SOURCE_UNUSED) { - memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); -} - -X509Certificate::~X509Certificate() { - // We might not be in the cache, but it is safe to remove ourselves anyway. - X509Certificate::Cache::GetInstance()->Remove(this); - if (cert_handle_) - FreeOSCertHandle(cert_handle_); -} - } // namespace net diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 9127cc6..4e41570 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -13,7 +13,6 @@ #include "base/ref_counted.h" #include "base/singleton.h" #include "base/time.h" -#include "testing/gtest/include/gtest/gtest_prod.h" #if defined(OS_WIN) #include <windows.h> @@ -113,25 +112,10 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { std::set<Fingerprint, FingerprintLessThan> denied_; }; - // Where the certificate comes from. The enumeration constants are - // listed in increasing order of preference. - enum Source { - SOURCE_UNUSED = 0, // The source_ member is not used. - SOURCE_LONE_CERT_IMPORT = 1, // From importing a certificate without - // its intermediate CA certificates. - SOURCE_FROM_NETWORK = 2, // From the network. - }; - // Create an X509Certificate from a handle to the certificate object // in the underlying crypto library. This is a transfer of ownership; // X509Certificate will properly dispose of |cert_handle| for you. - // |source| specifies where |cert_handle| comes from. Given two - // certificate handles for the same certificate, our certificate cache - // prefers the handle from the network because our HTTP cache isn't - // caching the corresponding intermediate CA certificates yet - // (http://crbug.com/7065). - static X509Certificate* CreateFromHandle(OSCertHandle cert_handle, - Source source); + static X509Certificate* CreateFromHandle(OSCertHandle cert_handle); // Create an X509Certificate from the BER-encoded representation. // Returns NULL on failure. @@ -146,7 +130,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // Creates a X509Certificate from the ground up. Used by tests that simulate // SSL connections. - X509Certificate(const std::string& subject, const std::string& issuer, + X509Certificate(std::string subject, std::string issuer, base::Time start_date, base::Time expiration_date); // Appends a representation of this object to the given pickle. @@ -188,9 +172,6 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { OSCertHandle os_cert_handle() const { return cert_handle_; } private: - friend class base::RefCountedThreadSafe<X509Certificate>; - FRIEND_TEST(X509CertificateTest, Cache); - // A cache of X509Certificate objects. class Cache { public: @@ -219,25 +200,14 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // Construct an X509Certificate from a handle to the certificate object // in the underlying crypto library. - X509Certificate(OSCertHandle cert_handle, Source source); + explicit X509Certificate(OSCertHandle cert_handle); + friend class base::RefCountedThreadSafe<X509Certificate>; ~X509Certificate(); // Common object initialization code. Called by the constructors only. void Initialize(); - // Creates an OS certificate handle from the BER-encoded representation. - // Returns NULL on failure. - static OSCertHandle CreateOSCertHandleFromBytes(const char* data, - int length); - - // Frees an OS certificate handle. - static void FreeOSCertHandle(OSCertHandle cert_handle); - - // Calculates the SHA-1 fingerprint of the certificate. Returns an empty - // (all zero) fingerprint on failure. - static Fingerprint CalculateFingerprint(OSCertHandle cert_handle); - // The subject of the certificate. Principal subject_; @@ -256,9 +226,6 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // A handle to the certificate object in the underlying crypto library. OSCertHandle cert_handle_; - // Where the certificate comes from. - Source source_; - DISALLOW_COPY_AND_ASSIGN(X509Certificate); }; diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc index ac60645..11191bd 100644 --- a/net/base/x509_certificate_mac.cc +++ b/net/base/x509_certificate_mac.cc @@ -7,6 +7,7 @@ #include <CommonCrypto/CommonDigest.h> #include <time.h> +#include "base/histogram.h" #include "base/logging.h" #include "base/pickle.h" #include "net/base/cert_status_flags.h" @@ -18,6 +19,26 @@ namespace net { namespace { +// Calculates the SHA-1 fingerprint of the certificate. Returns an empty +// (all zero) fingerprint on failure. +X509Certificate::Fingerprint CalculateFingerprint( + X509Certificate::OSCertHandle cert) { + X509Certificate::Fingerprint sha1; + memset(sha1.data, 0, sizeof(sha1.data)); + + CSSM_DATA cert_data; + OSStatus status = SecCertificateGetData(cert, &cert_data); + if (status) + return sha1; + + DCHECK(NULL != cert_data.Data); + DCHECK(0 != cert_data.Length); + + CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); + + return sha1; +} + inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) { return oid1->Length == oid2->Length && (memcmp(oid1->Data, oid2->Data, oid1->Length) == 0); @@ -221,6 +242,42 @@ void X509Certificate::Initialize() { } // static +X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) { + DCHECK(cert_handle); + + // Check if we already have this certificate in memory. + X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); + X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle)); + if (cert) { + // We've found a certificate with the same fingerprint in our cache. We own + // the |cert_handle|, which makes it our job to free it. + CFRelease(cert_handle); + DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); + return cert; + } + // Otherwise, allocate a new object. + return new X509Certificate(cert_handle); +} + +// static +X509Certificate* X509Certificate::CreateFromBytes(const char* data, + int length) { + CSSM_DATA cert_data; + cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); + cert_data.Length = length; + + OSCertHandle cert_handle = NULL; + OSStatus status = SecCertificateCreateFromData(&cert_data, + CSSM_CERT_X_509v3, + CSSM_CERT_ENCODING_BER, + &cert_handle); + if (status) + return NULL; + + return CreateFromHandle(cert_handle); +} + +// static X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, void** pickle_iter) { const char* data; @@ -231,6 +288,21 @@ X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, return CreateFromBytes(data, length); } +X509Certificate::X509Certificate(OSCertHandle cert_handle) + : cert_handle_(cert_handle) { + Initialize(); +} + +X509Certificate::X509Certificate(std::string subject, std::string issuer, + Time start_date, Time expiration_date) + : subject_(subject), + issuer_(issuer), + valid_start_(start_date), + valid_expiry_(expiration_date), + cert_handle_(NULL) { + memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); +} + void X509Certificate::Persist(Pickle* pickle) { CSSM_DATA cert_data; OSStatus status = SecCertificateGetData(cert_handle_, &cert_data); @@ -242,6 +314,13 @@ void X509Certificate::Persist(Pickle* pickle) { pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), cert_data.Length); } +X509Certificate::~X509Certificate() { + // We might not be in the cache, but it is safe to remove ourselves anyway. + X509Certificate::Cache::GetInstance()->Remove(this); + if (cert_handle_) + CFRelease(cert_handle_); +} + void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { dns_names->clear(); @@ -266,46 +345,4 @@ bool X509Certificate::IsEV(int cert_status) const { return false; } -// static -X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( - const char* data, int length) { - CSSM_DATA cert_data; - cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); - cert_data.Length = length; - - OSCertHandle cert_handle = NULL; - OSStatus status = SecCertificateCreateFromData(&cert_data, - CSSM_CERT_X_509v3, - CSSM_CERT_ENCODING_BER, - &cert_handle); - if (status) - return NULL; - - return cert_handle; -} - -// static -void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { - CFRelease(cert_handle); -} - -// static -X509Certificate::Fingerprint X509Certificate::CalculateFingerprint( - OSCertHandle cert) { - Fingerprint sha1; - memset(sha1.data, 0, sizeof(sha1.data)); - - CSSM_DATA cert_data; - OSStatus status = SecCertificateGetData(cert, &cert_data); - if (status) - return sha1; - - DCHECK(NULL != cert_data.Data); - DCHECK(0 != cert_data.Length); - - CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); - - return sha1; -} - } // namespace net diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc index 2ca1255..ef4b8cd 100644 --- a/net/base/x509_certificate_nss.cc +++ b/net/base/x509_certificate_nss.cc @@ -13,12 +13,30 @@ #include <sechash.h> #undef Lock +#include "base/histogram.h" #include "base/logging.h" #include "base/time.h" #include "base/nss_init.h" namespace net { +// Calculates the SHA-1 fingerprint of the certificate. Returns an empty +// (all zero) fingerprint on failure. +X509Certificate::Fingerprint CalculateFingerprint( + X509Certificate::OSCertHandle cert) { + X509Certificate::Fingerprint sha1; + memset(sha1.data, 0, sizeof(sha1.data)); + + DCHECK(NULL != cert->derCert.data); + DCHECK(0 != cert->derCert.len); + + SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, + cert->derCert.data, cert->derCert.len); + DCHECK(rv == SECSuccess); + + return sha1; +} + namespace { // TODO(port): Implement this more simply, and put it in the right place @@ -39,11 +57,11 @@ base::Time PRTimeToBaseTime(PRTime prtime) { return base::Time::FromUTCExploded(exploded); } -void ParsePrincipal(SECItem* der_name, +void ParsePrincipal(SECItem *der_name, X509Certificate::Principal* principal) { CERTName name; - PRArenaPool* arena = NULL; + PRArenaPool *arena = NULL; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); DCHECK(arena != NULL); @@ -92,7 +110,7 @@ void ParsePrincipal(SECItem* der_name, SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); if (!decode_item) break; - std::string value(reinterpret_cast<char*>(decode_item->data), + std::string value(reinterpret_cast<char *>(decode_item->data), decode_item->len); values[oid]->push_back(value); SECITEM_FreeItem(decode_item, PR_TRUE); @@ -147,9 +165,9 @@ void GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle, name->type == certDNSName || name->type == certURI); if (name->type == name_type) { - unsigned char* p = name->name.other.data; + unsigned char *p = name->name.other.data; int len = name->name.other.len; - std::string value = std::string(reinterpret_cast<char*>(p), len); + std::string value = std::string(reinterpret_cast<char *>(p), len); result->push_back(value); } name = CERT_GetNextGeneralName(name); @@ -175,16 +193,63 @@ void X509Certificate::Initialize() { } // static +X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) { + DCHECK(cert_handle); + + // Check if we already have this certificate in memory. + X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); + X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle)); + if (cert) { + // We've found a certificate with the same fingerprint in our cache. We own + // the |cert_handle|, which makes it our job to free it. + CERT_DestroyCertificate(cert_handle); + DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); + return cert; + } + // Otherwise, allocate a new object. + return new X509Certificate(cert_handle); +} + +// static +X509Certificate* X509Certificate::CreateFromBytes(const char* data, + int length) { + base::EnsureNSSInit(); + + SECItem der_cert; + der_cert.data = reinterpret_cast<unsigned char *>(const_cast<char *>(data)); + der_cert.len = length; + OSCertHandle cert_handle = + CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, + NULL, PR_FALSE, PR_TRUE); + if (!cert_handle) + return NULL; + + return CreateFromHandle(cert_handle); +} + +// static X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, void** pickle_iter) { NOTIMPLEMENTED(); return NULL; } +X509Certificate::X509Certificate(OSCertHandle cert_handle) + : cert_handle_(cert_handle) { + Initialize(); +} + void X509Certificate::Persist(Pickle* pickle) { NOTIMPLEMENTED(); } +X509Certificate::~X509Certificate() { + // We might not be in the cache, but it is safe to remove ourselves anyway. + X509Certificate::Cache::GetInstance()->Remove(this); + if (cert_handle_) + CERT_DestroyCertificate(cert_handle_); +} + void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { dns_names->clear(); @@ -198,39 +263,6 @@ void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { if (dns_names->empty()) dns_names->push_back(subject_.common_name); } - -// static -X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( - const char* data, int length) { - base::EnsureNSSInit(); - - SECItem der_cert; - der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data)); - der_cert.len = length; - return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, - NULL, PR_FALSE, PR_TRUE); -} - -// static -void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { - CERT_DestroyCertificate(cert_handle); -} - -// static -X509Certificate::Fingerprint X509Certificate::CalculateFingerprint( - OSCertHandle cert) { - Fingerprint sha1; - memset(sha1.data, 0, sizeof(sha1.data)); - - DCHECK(NULL != cert->derCert.data); - DCHECK(0 != cert->derCert.len); - - SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, - cert->derCert.data, cert->derCert.len); - DCHECK(rv == SECSuccess); - - return sha1; -} } // namespace net diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc index bf98b5c..499b914 100644 --- a/net/base/x509_certificate_unittest.cc +++ b/net/base/x509_certificate_unittest.cc @@ -18,8 +18,11 @@ using base::Time; namespace { +class X509CertificateTest : public testing::Test { +}; + // Certificates for test data. They're obtained with: -// +// // $ openssl s_client -connect [host]:443 -showcerts // $ openssl x509 -inform PEM -outform DER > /tmp/host.der // $ xxd -i /tmp/host.der @@ -329,13 +332,13 @@ unsigned char thawte_fingerprint[] = { } // namespace -namespace net { +using net::X509Certificate; TEST(X509CertificateTest, GoogleCertParsing) { scoped_refptr<X509Certificate> google_cert = X509Certificate::CreateFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - - ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert); + + ASSERT_NE(static_cast<X509Certificate *>(NULL), google_cert); const X509Certificate::Principal& subject = google_cert->subject(); EXPECT_EQ("www.google.com", subject.common_name); @@ -347,7 +350,7 @@ TEST(X509CertificateTest, GoogleCertParsing) { EXPECT_EQ("Google Inc", subject.organization_names[0]); EXPECT_EQ(0U, subject.organization_unit_names.size()); EXPECT_EQ(0U, subject.domain_components.size()); - + const X509Certificate::Principal& issuer = google_cert->issuer(); EXPECT_EQ("Thawte SGC CA", issuer.common_name); EXPECT_EQ("", issuer.locality_name); @@ -358,14 +361,14 @@ TEST(X509CertificateTest, GoogleCertParsing) { EXPECT_EQ("Thawte Consulting (Pty) Ltd.", issuer.organization_names[0]); EXPECT_EQ(0U, issuer.organization_unit_names.size()); EXPECT_EQ(0U, issuer.domain_components.size()); - + // Use DoubleT because its epoch is the same on all platforms const Time& valid_start = google_cert->valid_start(); EXPECT_EQ(1209747775, valid_start.ToDoubleT()); - + const Time& valid_expiry = google_cert->valid_expiry(); EXPECT_EQ(1241283775, valid_expiry.ToDoubleT()); - + const X509Certificate::Fingerprint& fingerprint = google_cert->fingerprint(); for (size_t i = 0; i < 20; ++i) EXPECT_EQ(google_fingerprint[i], fingerprint.data[i]); @@ -374,7 +377,7 @@ TEST(X509CertificateTest, GoogleCertParsing) { google_cert->GetDNSNames(&dns_names); EXPECT_EQ(1U, dns_names.size()); EXPECT_EQ("www.google.com", dns_names[0]); - + #if ALLOW_EXTERNAL_ACCESS && defined(OS_WIN) // TODO(avi): turn this on for the Mac once EV checking is implemented. EXPECT_EQ(false, google_cert->IsEV(net::CERT_STATUS_REV_CHECKING_ENABLED)); @@ -384,8 +387,8 @@ TEST(X509CertificateTest, GoogleCertParsing) { TEST(X509CertificateTest, WebkitCertParsing) { scoped_refptr<X509Certificate> webkit_cert = X509Certificate::CreateFromBytes( reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der)); - - ASSERT_NE(static_cast<X509Certificate*>(NULL), webkit_cert); + + ASSERT_NE(static_cast<X509Certificate *>(NULL), webkit_cert); const X509Certificate::Principal& subject = webkit_cert->subject(); EXPECT_EQ("Cupertino", subject.locality_name); @@ -397,7 +400,7 @@ TEST(X509CertificateTest, WebkitCertParsing) { EXPECT_EQ(1U, subject.organization_unit_names.size()); EXPECT_EQ("Mac OS Forge", subject.organization_unit_names[0]); EXPECT_EQ(0U, subject.domain_components.size()); - + const X509Certificate::Principal& issuer = webkit_cert->issuer(); EXPECT_EQ("Go Daddy Secure Certification Authority", issuer.common_name); EXPECT_EQ("Scottsdale", issuer.locality_name); @@ -410,14 +413,14 @@ TEST(X509CertificateTest, WebkitCertParsing) { EXPECT_EQ("http://certificates.godaddy.com/repository", issuer.organization_unit_names[0]); EXPECT_EQ(0U, issuer.domain_components.size()); - + // Use DoubleT because its epoch is the same on all platforms const Time& valid_start = webkit_cert->valid_start(); EXPECT_EQ(1205883319, valid_start.ToDoubleT()); - + const Time& valid_expiry = webkit_cert->valid_expiry(); EXPECT_EQ(1300491319, valid_expiry.ToDoubleT()); - + const X509Certificate::Fingerprint& fingerprint = webkit_cert->fingerprint(); for (size_t i = 0; i < 20; ++i) EXPECT_EQ(webkit_fingerprint[i], fingerprint.data[i]); @@ -427,7 +430,7 @@ TEST(X509CertificateTest, WebkitCertParsing) { EXPECT_EQ(2U, dns_names.size()); EXPECT_EQ("*.webkit.org", dns_names[0]); EXPECT_EQ("webkit.org", dns_names[1]); - + #if ALLOW_EXTERNAL_ACCESS && defined(OS_WIN) EXPECT_EQ(false, webkit_cert->IsEV(net::CERT_STATUS_REV_CHECKING_ENABLED)); #endif @@ -436,8 +439,8 @@ TEST(X509CertificateTest, WebkitCertParsing) { TEST(X509CertificateTest, ThawteCertParsing) { scoped_refptr<X509Certificate> thawte_cert = X509Certificate::CreateFromBytes( reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der)); - - ASSERT_NE(static_cast<X509Certificate*>(NULL), thawte_cert); + + ASSERT_NE(static_cast<X509Certificate *>(NULL), thawte_cert); const X509Certificate::Principal& subject = thawte_cert->subject(); EXPECT_EQ("www.thawte.com", subject.common_name); @@ -449,7 +452,7 @@ TEST(X509CertificateTest, ThawteCertParsing) { EXPECT_EQ("Thawte Inc", subject.organization_names[0]); EXPECT_EQ(0U, subject.organization_unit_names.size()); EXPECT_EQ(0U, subject.domain_components.size()); - + const X509Certificate::Principal& issuer = thawte_cert->issuer(); EXPECT_EQ("thawte Extended Validation SSL CA", issuer.common_name); EXPECT_EQ("", issuer.locality_name); @@ -462,14 +465,14 @@ TEST(X509CertificateTest, ThawteCertParsing) { EXPECT_EQ("Terms of use at https://www.thawte.com/cps (c)06", issuer.organization_unit_names[0]); EXPECT_EQ(0U, issuer.domain_components.size()); - + // Use DoubleT because its epoch is the same on all platforms const Time& valid_start = thawte_cert->valid_start(); EXPECT_EQ(1169078400, valid_start.ToDoubleT()); - + const Time& valid_expiry = thawte_cert->valid_expiry(); EXPECT_EQ(1232236799, valid_expiry.ToDoubleT()); - + const X509Certificate::Fingerprint& fingerprint = thawte_cert->fingerprint(); for (size_t i = 0; i < 20; ++i) EXPECT_EQ(thawte_fingerprint[i], fingerprint.data[i]); @@ -478,7 +481,7 @@ TEST(X509CertificateTest, ThawteCertParsing) { thawte_cert->GetDNSNames(&dns_names); EXPECT_EQ(1U, dns_names.size()); EXPECT_EQ("www.thawte.com", dns_names[0]); - + #if ALLOW_EXTERNAL_ACCESS && defined(OS_WIN) // EV cert verification requires revocation checking. EXPECT_EQ(true, thawte_cert->IsEV(net::CERT_STATUS_REV_CHECKING_ENABLED)); @@ -487,57 +490,3 @@ TEST(X509CertificateTest, ThawteCertParsing) { EXPECT_EQ(false, thawte_cert->IsEV(0)); #endif } - -// Tests X509Certificate::Cache via X509Certificate::CreateFromHandle. We -// call X509Certificate::CreateFromHandle several times and observe whether -// it returns a cached or new X509Certificate object. -// -// All the OS certificate handles in this test are actually from the same -// source (the bytes of a lone certificate), but we pretend that some of them -// come from the network. -TEST(X509CertificateTest, Cache) { - X509Certificate::OSCertHandle google_cert_handle; - - // Add a certificate from the source SOURCE_LONE_CERT_IMPORT to our - // certificate cache. - google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert1 = X509Certificate::CreateFromHandle( - google_cert_handle, X509Certificate::SOURCE_LONE_CERT_IMPORT); - - // Add a certificate from the same source (SOURCE_LONE_CERT_IMPORT). This - // should return the cached certificate (cert1). - google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert2 = X509Certificate::CreateFromHandle( - google_cert_handle, X509Certificate::SOURCE_LONE_CERT_IMPORT); - - EXPECT_EQ(cert1, cert2); - - // Add a certificate from the network. This should kick out the original - // cached certificate (cert1) and return a new certificate. - google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert3 = X509Certificate::CreateFromHandle( - google_cert_handle, X509Certificate::SOURCE_FROM_NETWORK); - - EXPECT_NE(cert1, cert3); - - // Add one certificate from each source. Both should return the new cached - // certificate (cert3). - google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert4 = X509Certificate::CreateFromHandle( - google_cert_handle, X509Certificate::SOURCE_FROM_NETWORK); - - EXPECT_EQ(cert3, cert4); - - google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert5 = X509Certificate::CreateFromHandle( - google_cert_handle, X509Certificate::SOURCE_FROM_NETWORK); - - EXPECT_EQ(cert3, cert5); -} - -} // namespace net diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc index 57ce947..4e7c4ba 100644 --- a/net/base/x509_certificate_win.cc +++ b/net/base/x509_certificate_win.cc @@ -4,6 +4,7 @@ #include "net/base/x509_certificate.h" +#include "base/histogram.h" #include "base/logging.h" #include "base/pickle.h" #include "base/string_tokenizer.h" @@ -20,6 +21,23 @@ namespace net { namespace { +// Calculates the SHA-1 fingerprint of the certificate. Returns an empty +// (all zero) fingerprint on failure. +X509Certificate::Fingerprint CalculateFingerprint(PCCERT_CONTEXT cert) { + DCHECK(NULL != cert->pbCertEncoded); + DCHECK(0 != cert->cbCertEncoded); + + BOOL rv; + X509Certificate::Fingerprint sha1; + DWORD sha1_size = sizeof(sha1.data); + rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, + cert->cbCertEncoded, sha1.data, &sha1_size); + DCHECK(rv && sha1_size == sizeof(sha1.data)); + if (!rv) + memset(sha1.data, 0, sizeof(sha1.data)); + return sha1; +} + // Wrappers of malloc and free for CRYPT_DECODE_PARA, which requires the // WINAPI calling convention. void* WINAPI MyCryptAlloc(size_t size) { @@ -237,6 +255,39 @@ void X509Certificate::Initialize() { } // static +X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) { + DCHECK(cert_handle); + + // Check if we already have this certificate in memory. + X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); + X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle)); + if (cert) { + // We've found a certificate with the same fingerprint in our cache. We own + // the |cert_handle|, which makes it our job to free it. + CertFreeCertificateContext(cert_handle); + DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); + return cert; + } + // Otherwise, allocate a new object. + return new X509Certificate(cert_handle); +} + +// static +X509Certificate* X509Certificate::CreateFromBytes(const char* data, + int length) { + OSCertHandle cert_handle = NULL; + if (!CertAddEncodedCertificateToStore( + NULL, // the cert won't be persisted in any cert store + X509_ASN_ENCODING, + reinterpret_cast<const BYTE*>(data), length, + CERT_STORE_ADD_USE_EXISTING, + &cert_handle)) + return NULL; + + return CreateFromHandle(cert_handle); +} + +// static X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, void** pickle_iter) { const char* data; @@ -252,7 +303,22 @@ X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, NULL, reinterpret_cast<const void **>(&cert_handle))) return NULL; - return CreateFromHandle(cert_handle, SOURCE_LONE_CERT_IMPORT); + return CreateFromHandle(cert_handle); +} + +X509Certificate::X509Certificate(OSCertHandle cert_handle) + : cert_handle_(cert_handle) { + Initialize(); +} + +X509Certificate::X509Certificate(std::string subject, std::string issuer, + Time start_date, Time expiration_date) + : subject_(subject), + issuer_(issuer), + valid_start_(start_date), + valid_expiry_(expiration_date), + cert_handle_(NULL) { + memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); } void X509Certificate::Persist(Pickle* pickle) { @@ -271,6 +337,13 @@ void X509Certificate::Persist(Pickle* pickle) { pickle->TrimWriteData(length); } +X509Certificate::~X509Certificate() { + // We might not be in the cache, but it is safe to remove ourselves anyway. + X509Certificate::Cache::GetInstance()->Remove(this); + if (cert_handle_) + CertFreeCertificateContext(cert_handle_); +} + void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { dns_names->clear(); scoped_ptr_malloc<CERT_ALT_NAME_INFO> alt_name_info; @@ -333,7 +406,7 @@ bool X509Certificate::IsEV(int cert_status) const { // Look up the EV policy OID of the root CA. PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext; - Fingerprint fingerprint = CalculateFingerprint(root_cert); + X509Certificate::Fingerprint fingerprint = CalculateFingerprint(root_cert); std::string ev_policy_oid; if (!metadata->GetPolicyOID(fingerprint, &ev_policy_oid)) return false; @@ -349,42 +422,5 @@ bool X509Certificate::IsEV(int cert_status) const { return ContainsPolicy(policies_info.get(), ev_policy_oid.c_str()); } -// static -X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( - const char* data, int length) { - OSCertHandle cert_handle = NULL; - if (!CertAddEncodedCertificateToStore( - NULL, // the cert won't be persisted in any cert store - X509_ASN_ENCODING, - reinterpret_cast<const BYTE*>(data), length, - CERT_STORE_ADD_USE_EXISTING, - &cert_handle)) - return NULL; - - return cert_handle; -} - -// static -void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { - CertFreeCertificateContext(cert_handle); -} - -// static -X509Certificate::Fingerprint X509Certificate::CalculateFingerprint( - OSCertHandle cert) { - DCHECK(NULL != cert->pbCertEncoded); - DCHECK(0 != cert->cbCertEncoded); - - BOOL rv; - Fingerprint sha1; - DWORD sha1_size = sizeof(sha1.data); - rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, - cert->cbCertEncoded, sha1.data, &sha1_size); - DCHECK(rv && sha1_size == sizeof(sha1.data)); - if (!rv) - memset(sha1.data, 0, sizeof(sha1.data)); - return sha1; -} - } // namespace net diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index accd7da..fe0a130 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -855,8 +855,6 @@ void HttpCache::Transaction::OnNetworkInfoAvailable(int result) { if (mode_ == READ_WRITE) { if (new_response->headers->response_code() == 304) { // Update cached response based on headers in new_response - // TODO(wtc): should we update cached certificate - // (response_.ssl_info), too? response_.headers->Update(*new_response->headers); if (response_.headers->HasHeaderValue("cache-control", "no-store")) { cache_->DoomEntry(cache_key_); |