summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-29 03:49:49 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-29 03:49:49 +0000
commit931945aa9d1a72f61eb37d3f75eb13a542d4fc2e (patch)
treef0ff0f2bb66f1dadff926ae7bb3dd270692ae146
parentc5addfbb9cb0518d8346cc9b827c2a5e8c32957d (diff)
downloadchromium_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.cc3
-rw-r--r--net/base/ssl_client_socket_win.cc3
-rw-r--r--net/base/x509_certificate.cc62
-rw-r--r--net/base/x509_certificate.h41
-rw-r--r--net/base/x509_certificate_mac.cc121
-rw-r--r--net/base/x509_certificate_nss.cc108
-rw-r--r--net/base/x509_certificate_unittest.cc103
-rw-r--r--net/base/x509_certificate_win.cc114
-rw-r--r--net/http/http_cache.cc2
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_);