summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authorrsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-06 18:22:09 +0000
committerrsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-06 18:22:09 +0000
commit130686ac6398e7d53a238f2588f44dd926f90933 (patch)
treeec7d482c645e36174c20bfb2a0cdde0a26a93f6d /net/base
parent1fa3a98a1eb48c7f96e5a1d710a9b4ca296b6ad1 (diff)
downloadchromium_src-130686ac6398e7d53a238f2588f44dd926f90933.zip
chromium_src-130686ac6398e7d53a238f2588f44dd926f90933.tar.gz
chromium_src-130686ac6398e7d53a238f2588f44dd926f90933.tar.bz2
Sort client certificates by preference before prompting the user
When determining the list of available client certificates, order the returned client certificates based on heuristics to determine preference. Certificates are sorted based on validity, including that they're still valid, that certificates with longer expirations are preferred, and that, barring those, certificates that are newer are preferred. BUG=89267 TEST=net_unittests --gtest_filter=X509UtilTest* Review URL: https://chromiumcodereview.appspot.com/11275167 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166231 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r--net/base/x509_util.cc48
-rw-r--r--net/base/x509_util.h19
-rw-r--r--net/base/x509_util_unittest.cc54
3 files changed, 121 insertions, 0 deletions
diff --git a/net/base/x509_util.cc b/net/base/x509_util.cc
new file mode 100644
index 0000000..246c173
--- /dev/null
+++ b/net/base/x509_util.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/x509_util.h"
+
+#include "base/time.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+namespace x509_util {
+
+bool ClientCertSorter::operator()(
+ const scoped_refptr<X509Certificate>& a,
+ const scoped_refptr<X509Certificate>& b) const {
+ // Certificates that are null are sorted last.
+ if (!a.get() || !b.get())
+ return a.get() && !b.get();
+
+ // Certificates that are expired/not-yet-valid are sorted last.
+ base::Time now = base::Time::Now();
+ bool a_is_valid = now >= a->valid_start() && now <= a->valid_expiry();
+ bool b_is_valid = now >= b->valid_start() && now <= b->valid_expiry();
+ if (a_is_valid && !b_is_valid)
+ return true;
+
+ // Certificates with longer expirations appear as higher priority (less
+ // than) certificates with shorter expirations.
+ if (a->valid_expiry() != b->valid_expiry())
+ return a->valid_expiry() > b->valid_expiry();
+
+ // If the expiration dates are equivalent, certificates that were issued
+ // more recently should be prioritized over older certificates.
+ if (a->valid_start() != b->valid_start())
+ return a->valid_start() > b->valid_start();
+
+ // Otherwise, prefer client certificates with shorter chains.
+ const X509Certificate::OSCertHandles& a_intermediates =
+ a->GetIntermediateCertificates();
+ const X509Certificate::OSCertHandles& b_intermediates =
+ b->GetIntermediateCertificates();
+ return a_intermediates.size() < b_intermediates.size();
+}
+
+} // namespace x509_util
+
+} // namespace net
diff --git a/net/base/x509_util.h b/net/base/x509_util.h
index 1257d46..a800fdf 100644
--- a/net/base/x509_util.h
+++ b/net/base/x509_util.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/memory/ref_counted.h"
#include "base/time.h"
#include "net/base/net_export.h"
@@ -16,6 +17,8 @@ class ECPrivateKey;
namespace net {
+class X509Certificate;
+
namespace x509_util {
// Returns true if the times can be used to create an X.509 certificate.
@@ -41,6 +44,22 @@ bool NET_EXPORT_PRIVATE CreateDomainBoundCertEC(
base::Time not_valid_after,
std::string* der_cert);
+// Comparator for use in STL algorithms that will sort client certificates by
+// order of preference.
+// Returns true if |a| is more preferable than |b|, allowing it to be used
+// with any algorithm that compares according to strict weak ordering.
+//
+// Criteria include:
+// - Prefer certificates that have a longer validity period (later
+// expiration dates)
+// - If equal, prefer certificates that were issued more recently
+// - If equal, prefer shorter chains (if available)
+struct NET_EXPORT_PRIVATE ClientCertSorter {
+ bool operator()(
+ const scoped_refptr<X509Certificate>& a,
+ const scoped_refptr<X509Certificate>& b) const;
+};
+
} // namespace x509_util
} // namespace net
diff --git a/net/base/x509_util_unittest.cc b/net/base/x509_util_unittest.cc
new file mode 100644
index 0000000..34c1781
--- /dev/null
+++ b/net/base/x509_util_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/x509_util.h"
+
+#include <algorithm>
+
+#include "base/time.h"
+#include "net/base/x509_certificate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace x509_util {
+
+TEST(X509UtilTest, SortClientCertificates) {
+ CertificateList certs;
+
+ const base::Time now = base::Time::Now();
+ const base::TimeDelta five_days = base::TimeDelta::FromDays(5);
+
+ certs.push_back(scoped_refptr<X509Certificate>(NULL));
+ certs.push_back(new X509Certificate(
+ "expired", "expired",
+ base::Time::UnixEpoch(), base::Time::UnixEpoch()));
+ certs.push_back(new X509Certificate(
+ "not yet valid", "not yet valid",
+ base::Time::Max(), base::Time::Max()));
+ certs.push_back(new X509Certificate(
+ "older cert", "older cert",
+ now - five_days, now + five_days));
+ certs.push_back(scoped_refptr<X509Certificate>(NULL));
+ certs.push_back(new X509Certificate(
+ "newer cert", "newer cert",
+ now - base::TimeDelta::FromDays(3), now + five_days));
+
+ std::sort(certs.begin(), certs.end(), ClientCertSorter());
+
+ ASSERT_TRUE(certs[0].get());
+ EXPECT_EQ("newer cert", certs[0]->subject().common_name);
+ ASSERT_TRUE(certs[1].get());
+ EXPECT_EQ("older cert", certs[1]->subject().common_name);
+ ASSERT_TRUE(certs[2].get());
+ EXPECT_EQ("not yet valid", certs[2]->subject().common_name);
+ ASSERT_TRUE(certs[3].get());
+ EXPECT_EQ("expired", certs[3]->subject().common_name);
+ ASSERT_FALSE(certs[4].get());
+ ASSERT_FALSE(certs[5].get());
+}
+
+} // namespace x509_util
+
+} // namespace net