summaryrefslogtreecommitdiffstats
path: root/net/base/x509_certificate.cc
diff options
context:
space:
mode:
authorsnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-05 16:59:54 +0000
committersnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-05 16:59:54 +0000
commit76964955a0fc995d7a0c95feaeaa17891eab2205 (patch)
tree26aca3f0ef8c93d5330f24f6136bfb6136df0bbe /net/base/x509_certificate.cc
parent357d16ba35c2f43322af5242d36bdf220b8f6455 (diff)
downloadchromium_src-76964955a0fc995d7a0c95feaeaa17891eab2205.zip
chromium_src-76964955a0fc995d7a0c95feaeaa17891eab2205.tar.gz
chromium_src-76964955a0fc995d7a0c95feaeaa17891eab2205.tar.bz2
Thread-safety for X509Certificate's intermediate-certs list.
BUG=32553,30001 TEST=none Review URL: http://codereview.chromium.org/661223 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40742 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base/x509_certificate.cc')
-rw-r--r--net/base/x509_certificate.cc92
1 files changed, 79 insertions, 13 deletions
diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc
index 24388d8..700b254 100644
--- a/net/base/x509_certificate.cc
+++ b/net/base/x509_certificate.cc
@@ -4,6 +4,10 @@
#include "net/base/x509_certificate.h"
+#if defined(USE_NSS)
+#include <cert.h>
+#endif
+
#include "base/histogram.h"
#include "base/logging.h"
#include "base/time.h"
@@ -24,6 +28,33 @@ bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) {
} // namespace
+// static
+bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
+ X509Certificate::OSCertHandle b) {
+ DCHECK(a && b);
+ if (a == b)
+ return true;
+#if defined(OS_WIN)
+ return a->cbCertEncoded == b->cbCertEncoded &&
+ memcmp(a->pbCertEncoded, b->pbCertEncoded, a->cbCertEncoded) == 0;
+#elif defined(OS_MACOSX)
+ if (CFEqual(a, b))
+ return true;
+ CSSM_DATA a_data, b_data;
+ return SecCertificateGetData(a, &a_data) == noErr &&
+ SecCertificateGetData(b, &b_data) == noErr &&
+ a_data.Length == b_data.Length &&
+ memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
+#elif defined(USE_NSS)
+ return a->derCert.len == b->derCert.len &&
+ memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0;
+#else
+ // TODO(snej): not implemented
+ UNREACHED();
+ return false;
+#endif
+}
+
bool X509Certificate::FingerprintLessThan::operator()(
const Fingerprint& lhs,
const Fingerprint& rhs) const {
@@ -57,14 +88,13 @@ X509Certificate::Cache* X509Certificate::Cache::GetInstance() {
return Singleton<X509Certificate::Cache>::get();
}
-// Insert |cert| into the cache. The cache does NOT AddRef |cert|. The cache
-// must not already contain a certificate with the same fingerprint.
+// Insert |cert| into the cache. The cache does NOT AddRef |cert|.
+// Any existing certificate with the same fingerprint will be replaced.
void X509Certificate::Cache::Insert(X509Certificate* cert) {
AutoLock lock(lock_);
DCHECK(!IsNullFingerprint(cert->fingerprint())) <<
"Only insert certs with real fingerprints.";
- DCHECK(cache_.find(cert->fingerprint()) == cache_.end());
cache_[cert->fingerprint()] = cert;
};
@@ -133,8 +163,10 @@ bool X509Certificate::Policy::HasDeniedCert() const {
}
// static
-X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle,
- Source source) {
+X509Certificate* X509Certificate::CreateFromHandle(
+ OSCertHandle cert_handle,
+ Source source,
+ const OSCertHandles& intermediates) {
DCHECK(cert_handle);
DCHECK(source != SOURCE_UNUSED);
@@ -144,18 +176,20 @@ X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle,
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.
+ if (cached_cert->source_ > source ||
+ (cached_cert->source_ == source &&
+ cached_cert->HasIntermediateCertificates(intermediates))) {
+ // Return the certificate with the same fingerprint from our cache.
+ // But we own the input OSCertHandle, which makes it our job to free it.
FreeOSCertHandle(cert_handle);
DHISTOGRAM_COUNTS("X509CertificateReuseCount", 1);
return cached_cert;
}
- // Kick out the old certificate from our cache. The new one is better.
- cache->Remove(cached_cert);
+ // Else the new cert is better and will replace the old one in the cache.
}
+
// Otherwise, allocate a new object.
- return new X509Certificate(cert_handle, source);
+ return new X509Certificate(cert_handle, source, intermediates);
}
// static
@@ -165,13 +199,25 @@ X509Certificate* X509Certificate::CreateFromBytes(const char* data,
if (!cert_handle)
return NULL;
- return CreateFromHandle(cert_handle, SOURCE_LONE_CERT_IMPORT);
+ return CreateFromHandle(cert_handle,
+ SOURCE_LONE_CERT_IMPORT,
+ OSCertHandles());
}
-X509Certificate::X509Certificate(OSCertHandle cert_handle, Source source)
+X509Certificate::X509Certificate(OSCertHandle cert_handle,
+ Source source,
+ const OSCertHandles& intermediates)
: cert_handle_(cert_handle),
source_(source) {
+#if defined(OS_MACOSX) || defined(OS_WIN)
+ // Copy/retain the intermediate cert handles.
+ for (size_t i = 0; i < intermediates.size(); ++i)
+ intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i]));
+#endif
+ // Platform-specific initialization.
Initialize();
+ // Store the certificate in the cache in case we need it later.
+ X509Certificate::Cache::GetInstance()->Insert(this);
}
X509Certificate::X509Certificate(const std::string& subject,
@@ -202,4 +248,24 @@ bool X509Certificate::HasExpired() const {
return base::Time::Now() > valid_expiry();
}
+bool X509Certificate::HasIntermediateCertificate(OSCertHandle cert) {
+#if defined(OS_MACOSX) || defined(OS_WIN)
+ for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) {
+ if (IsSameOSCert(cert, intermediate_ca_certs_[i]))
+ return true;
+ }
+ return false;
+#else
+ return true;
+#endif
+}
+
+bool X509Certificate::HasIntermediateCertificates(const OSCertHandles& certs) {
+ for (size_t i = 0; i < certs.size(); ++i) {
+ if (!HasIntermediateCertificate(certs[i]))
+ return false;
+ }
+ return true;
+}
+
} // namespace net