summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/cert_database_nss_unittest.cc13
-rw-r--r--net/base/cert_verify_proc.cc47
-rw-r--r--net/base/cert_verify_proc.h74
-rw-r--r--net/base/cert_verify_proc_unittest.cc944
-rw-r--r--net/base/multi_threaded_cert_verifier.cc23
-rw-r--r--net/base/multi_threaded_cert_verifier.h8
-rw-r--r--net/base/multi_threaded_cert_verifier_unittest.cc143
-rw-r--r--net/base/single_request_cert_verifier.cc4
-rw-r--r--net/base/test_certificate_data.h7
-rw-r--r--net/base/transport_security_state_unittest.cc13
-rw-r--r--net/base/x509_certificate.h61
-rw-r--r--net/base/x509_certificate_unittest.cc903
-rw-r--r--net/net.gyp2
13 files changed, 1235 insertions, 1007 deletions
diff --git a/net/base/cert_database_nss_unittest.cc b/net/base/cert_database_nss_unittest.cc
index 8119dae..8ed8251b 100644
--- a/net/base/cert_database_nss_unittest.cc
+++ b/net/base/cert_database_nss_unittest.cc
@@ -20,6 +20,7 @@
#include "crypto/scoped_nss_types.h"
#include "net/base/cert_database.h"
#include "net/base/cert_status_flags.h"
+#include "net/base/cert_verify_proc.h"
#include "net/base/cert_verify_result.h"
#include "net/base/crypto_module.h"
#include "net/base/net_errors.h"
@@ -550,9 +551,11 @@ TEST_F(CertDatabaseNSSTest, DISABLED_ImportServerCert) {
psm::nsNSSCertTrust goog_trust(goog_cert->os_cert_handle()->trust);
EXPECT_TRUE(goog_trust.HasPeer(PR_TRUE, PR_TRUE, PR_TRUE));
+ scoped_refptr<CertVerifyProc> verify_proc(CertVerifyProc::CreateDefault());
int flags = 0;
CertVerifyResult verify_result;
- int error = goog_cert->Verify("www.google.com", flags, NULL, &verify_result);
+ int error = verify_proc->Verify(goog_cert, "www.google.com", flags,
+ NULL, &verify_result);
EXPECT_EQ(OK, error);
EXPECT_EQ(0U, verify_result.cert_status);
}
@@ -575,10 +578,11 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned) {
psm::nsNSSCertTrust puny_trust(puny_cert->os_cert_handle()->trust);
EXPECT_TRUE(puny_trust.HasPeer(PR_TRUE, PR_TRUE, PR_TRUE));
+ scoped_refptr<CertVerifyProc> verify_proc(CertVerifyProc::CreateDefault());
int flags = 0;
CertVerifyResult verify_result;
- int error = puny_cert->Verify("xn--wgv71a119e.com", flags, NULL,
- &verify_result);
+ int error = verify_proc->Verify(puny_cert, "xn--wgv71a119e.com", flags,
+ NULL, &verify_result);
EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status);
@@ -589,7 +593,8 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned) {
CertDatabase::TRUSTED_SSL | CertDatabase::TRUSTED_EMAIL));
verify_result.Reset();
- error = puny_cert->Verify("xn--wgv71a119e.com", flags, NULL, &verify_result);
+ error = verify_proc->Verify(puny_cert, "xn--wgv71a119e.com", flags,
+ NULL, &verify_result);
EXPECT_EQ(OK, error);
EXPECT_EQ(0U, verify_result.cert_status);
}
diff --git a/net/base/cert_verify_proc.cc b/net/base/cert_verify_proc.cc
new file mode 100644
index 0000000..0b98199
--- /dev/null
+++ b/net/base/cert_verify_proc.cc
@@ -0,0 +1,47 @@
+// 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/cert_verify_proc.h"
+
+#include "build/build_config.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+// TODO(rsleevi): Temporary refactoring - http://crbug.com/114343
+class CertVerifyProcStub : public CertVerifyProc {
+ public:
+ CertVerifyProcStub() {}
+
+ private:
+ virtual ~CertVerifyProcStub() {}
+
+ // CertVerifyProc implementation
+ virtual int VerifyInternal(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result) OVERRIDE {
+ return cert->Verify(hostname, flags, crl_set, verify_result);
+ }
+};
+
+// static
+CertVerifyProc* CertVerifyProc::CreateDefault() {
+ return new CertVerifyProcStub();
+}
+
+CertVerifyProc::CertVerifyProc() {}
+
+CertVerifyProc::~CertVerifyProc() {}
+
+int CertVerifyProc::Verify(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result) {
+ return VerifyInternal(cert, hostname, flags, crl_set, verify_result);
+}
+
+} // namespace net
diff --git a/net/base/cert_verify_proc.h b/net/base/cert_verify_proc.h
new file mode 100644
index 0000000..ee737e1
--- /dev/null
+++ b/net/base/cert_verify_proc.h
@@ -0,0 +1,74 @@
+// 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.
+
+#ifndef NET_BASE_CERT_VERIFY_PROC_H_
+#define NET_BASE_CERT_VERIFY_PROC_H_
+#pragma once
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class CertVerifyResult;
+class CRLSet;
+class X509Certificate;
+
+// Class to perform certificate path building and verification for various
+// certificate uses. All methods of this class must be thread-safe, as they
+// may be called from various non-joinable worker threads.
+class NET_EXPORT CertVerifyProc
+ : public base::RefCountedThreadSafe<CertVerifyProc> {
+ public:
+ // Creates and returns the default CertVerifyProc.
+ static CertVerifyProc* CreateDefault();
+
+ // Verifies the certificate against the given hostname as an SSL server
+ // certificate. Returns OK if successful or an error code upon failure.
+ //
+ // The |*verify_result| structure, including the |verify_result->cert_status|
+ // bitmask, is always filled out regardless of the return value. If the
+ // certificate has multiple errors, the corresponding status flags are set in
+ // |verify_result->cert_status|, and the error code for the most serious
+ // error is returned.
+ //
+ // |flags| is bitwise OR'd of VerifyFlags:
+ //
+ // If VERIFY_REV_CHECKING_ENABLED is set in |flags|, online certificate
+ // revocation checking is performed (i.e. OCSP and downloading CRLs). CRLSet
+ // based revocation checking is always enabled, regardless of this flag, if
+ // |crl_set| is given.
+ //
+ // If VERIFY_EV_CERT is set in |flags| too, EV certificate verification is
+ // performed.
+ //
+ // |crl_set| points to an optional CRLSet structure which can be used to
+ // avoid revocation checks over the network.
+ int Verify(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result);
+
+ protected:
+ friend class base::RefCountedThreadSafe<CertVerifyProc>;
+
+ CertVerifyProc();
+ virtual ~CertVerifyProc();
+
+ private:
+ // Performs the actual verification using the desired underlying
+ // cryptographic library.
+ virtual int VerifyInternal(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result) = 0;
+};
+
+} // namespace net
+
+#endif // NET_BASE_CERT_VERIFY_PROC_H_
diff --git a/net/base/cert_verify_proc_unittest.cc b/net/base/cert_verify_proc_unittest.cc
new file mode 100644
index 0000000..3c6de2b7
--- /dev/null
+++ b/net/base/cert_verify_proc_unittest.cc
@@ -0,0 +1,944 @@
+// 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/cert_verify_proc.h"
+
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/string_number_conversions.h"
+#include "base/sha1.h"
+#include "net/base/cert_status_flags.h"
+#include "net/base/cert_test_util.h"
+#include "net/base/cert_verify_result.h"
+#include "net/base/crl_set.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_certificate_data.h"
+#include "net/base/test_root_certs.h"
+#include "net/base/x509_certificate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#elif defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
+#endif
+
+using base::HexEncode;
+
+namespace net {
+
+namespace {
+
+// A certificate for www.paypal.com with a NULL byte in the common name.
+// From http://www.gossamer-threads.com/lists/fulldisc/full-disclosure/70363
+unsigned char paypal_null_fingerprint[] = {
+ 0x4c, 0x88, 0x9e, 0x28, 0xd7, 0x7a, 0x44, 0x1e, 0x13, 0xf2, 0x6a, 0xba,
+ 0x1f, 0xe8, 0x1b, 0xd6, 0xab, 0x7b, 0xe8, 0xd7
+};
+
+} // namespace
+
+class CertVerifyProcTest : public testing::Test {
+ public:
+ CertVerifyProcTest()
+ : verify_proc_(CertVerifyProc::CreateDefault()) {
+ }
+ virtual ~CertVerifyProcTest() {}
+
+ protected:
+ int Verify(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result) {
+ return verify_proc_->Verify(cert, hostname, flags, crl_set,
+ verify_result);
+ }
+
+ private:
+ scoped_refptr<CertVerifyProc> verify_proc_;
+};
+
+TEST_F(CertVerifyProcTest, WithoutRevocationChecking) {
+ // Check that verification without revocation checking works.
+ CertificateList certs = CreateCertificateListFromFile(
+ GetTestCertsDirectory(),
+ "googlenew.chain.pem",
+ X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(certs[1]->os_cert_handle());
+
+ scoped_refptr<X509Certificate> google_full_chain =
+ X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
+ intermediates);
+
+ CertVerifyResult verify_result;
+ EXPECT_EQ(OK, Verify(google_full_chain, "www.google.com", 0 /* flags */,
+ NULL, &verify_result));
+}
+
+#if defined(OS_ANDROID) || defined(USE_OPENSSL)
+// TODO(jnd): http://crbug.com/117478 - EV verification is not yet supported.
+#define MAYBE_EVVerification DISABLED_EVVerification
+#else
+#define MAYBE_EVVerification EVVerification
+#endif
+TEST_F(CertVerifyProcTest, MAYBE_EVVerification) {
+ // This certificate will expire Jun 21, 2013.
+ CertificateList certs = CreateCertificateListFromFile(
+ GetTestCertsDirectory(),
+ "comodo.chain.pem",
+ X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+ ASSERT_EQ(3U, certs.size());
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(certs[1]->os_cert_handle());
+ intermediates.push_back(certs[2]->os_cert_handle());
+
+ scoped_refptr<X509Certificate> comodo_chain =
+ X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
+ intermediates);
+
+ scoped_refptr<CRLSet> crl_set(CRLSet::EmptyCRLSetForTesting());
+ CertVerifyResult verify_result;
+ int flags = X509Certificate::VERIFY_EV_CERT;
+ int error = Verify(comodo_chain, "comodo.com", flags, crl_set.get(),
+ &verify_result);
+ EXPECT_EQ(OK, error);
+ EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV);
+}
+
+TEST_F(CertVerifyProcTest, PaypalNullCertParsing) {
+ scoped_refptr<X509Certificate> paypal_null_cert(
+ X509Certificate::CreateFromBytes(
+ reinterpret_cast<const char*>(paypal_null_der),
+ sizeof(paypal_null_der)));
+
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), paypal_null_cert);
+
+ const SHA1Fingerprint& fingerprint =
+ paypal_null_cert->fingerprint();
+ for (size_t i = 0; i < 20; ++i)
+ EXPECT_EQ(paypal_null_fingerprint[i], fingerprint.data[i]);
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ int error = Verify(paypal_null_cert, "www.paypal.com", flags, NULL,
+ &verify_result);
+#if defined(USE_OPENSSL) || defined(OS_MACOSX) || defined(OS_WIN)
+ // TOOD(bulach): investigate why macosx and win aren't returning
+ // ERR_CERT_INVALID or ERR_CERT_COMMON_NAME_INVALID.
+ EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+#else
+ EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
+#endif
+ // Either the system crypto library should correctly report a certificate
+ // name mismatch, or our certificate blacklist should cause us to report an
+ // invalid certificate.
+#if !defined(OS_MACOSX) && !defined(USE_OPENSSL)
+ EXPECT_TRUE(verify_result.cert_status &
+ (CERT_STATUS_COMMON_NAME_INVALID | CERT_STATUS_INVALID));
+#endif
+}
+
+// A regression test for http://crbug.com/31497.
+// This certificate will expire on 2012-04-08. The test will still
+// pass if error == ERR_CERT_DATE_INVALID. TODO(wtc): generate test
+// certificates for this unit test. http://crbug.com/111742
+TEST_F(CertVerifyProcTest, IntermediateCARequireExplicitPolicy) {
+ FilePath certs_dir = GetTestCertsDirectory();
+
+ scoped_refptr<X509Certificate> server_cert =
+ ImportCertFromFile(certs_dir, "www_us_army_mil_cert.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
+
+ // The intermediate CA certificate's policyConstraints extension has a
+ // requireExplicitPolicy field with SkipCerts=0.
+ scoped_refptr<X509Certificate> intermediate_cert =
+ ImportCertFromFile(certs_dir, "dod_ca_17_cert.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
+
+ scoped_refptr<X509Certificate> root_cert =
+ ImportCertFromFile(certs_dir, "dod_root_ca_2_cert.der");
+ ScopedTestRoot scoped_root(root_cert);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate_cert->os_cert_handle());
+ scoped_refptr<X509Certificate> cert_chain =
+ X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
+ intermediates);
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ int error = Verify(cert_chain, "www.us.army.mil", flags, NULL,
+ &verify_result);
+ if (error == OK) {
+ EXPECT_EQ(0U, verify_result.cert_status);
+ } else {
+ EXPECT_EQ(ERR_CERT_DATE_INVALID, error);
+ EXPECT_EQ(CERT_STATUS_DATE_INVALID, verify_result.cert_status);
+ }
+}
+
+
+// Test for bug 58437.
+// This certificate will expire on 2011-12-21. The test will still
+// pass if error == ERR_CERT_DATE_INVALID.
+// This test is DISABLED because it appears that we cannot do
+// certificate revocation checking when running all of the net unit tests.
+// This test passes when run individually, but when run with all of the net
+// unit tests, the call to PKIXVerifyCert returns the NSS error -8180, which is
+// SEC_ERROR_REVOKED_CERTIFICATE. This indicates a lack of revocation
+// status, i.e. that the revocation check is failing for some reason.
+TEST_F(CertVerifyProcTest, DISABLED_GlobalSignR3EVTest) {
+ FilePath certs_dir = GetTestCertsDirectory();
+
+ scoped_refptr<X509Certificate> server_cert =
+ ImportCertFromFile(certs_dir, "2029_globalsign_com_cert.pem");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
+
+ scoped_refptr<X509Certificate> intermediate_cert =
+ ImportCertFromFile(certs_dir, "globalsign_ev_sha256_ca_cert.pem");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate_cert->os_cert_handle());
+ scoped_refptr<X509Certificate> cert_chain =
+ X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
+ intermediates);
+
+ CertVerifyResult verify_result;
+ int flags = X509Certificate::VERIFY_REV_CHECKING_ENABLED |
+ X509Certificate::VERIFY_EV_CERT;
+ int error = Verify(cert_chain, "2029.globalsign.com", flags, NULL,
+ &verify_result);
+ if (error == OK)
+ EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV);
+ else
+ EXPECT_EQ(ERR_CERT_DATE_INVALID, error);
+}
+
+// Currently, only RSA and DSA keys are checked for weakness, and our example
+// weak size is 768. These could change in the future.
+//
+// Note that this means there may be false negatives: keys for other
+// algorithms and which are weak will pass this test.
+static bool IsWeakKeyType(const std::string& key_type) {
+ size_t pos = key_type.find("-");
+ std::string size = key_type.substr(0, pos);
+ std::string type = key_type.substr(pos + 1);
+
+ if (type == "rsa" || type == "dsa")
+ return size == "768";
+
+ return false;
+}
+
+TEST_F(CertVerifyProcTest, RejectWeakKeys) {
+ FilePath certs_dir = GetTestCertsDirectory();
+ typedef std::vector<std::string> Strings;
+ Strings key_types;
+
+ // generate-weak-test-chains.sh currently has:
+ // key_types="768-rsa 1024-rsa 2048-rsa prime256v1-ecdsa"
+ // We must use the same key types here. The filenames generated look like:
+ // 2048-rsa-ee-by-768-rsa-intermediate.pem
+ key_types.push_back("768-rsa");
+ key_types.push_back("1024-rsa");
+ key_types.push_back("2048-rsa");
+
+ bool use_ecdsa = true;
+#if defined(OS_WIN)
+ use_ecdsa = base::win::GetVersion() > base::win::VERSION_XP;
+#elif defined(OS_MACOSX)
+ use_ecdsa = base::mac::IsOSSnowLeopardOrLater();
+#endif
+
+ if (use_ecdsa)
+ key_types.push_back("prime256v1-ecdsa");
+
+ // Add the root that signed the intermediates for this test.
+ scoped_refptr<X509Certificate> root_cert =
+ ImportCertFromFile(certs_dir, "2048-rsa-root.pem");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
+ ScopedTestRoot scoped_root(root_cert);
+
+ // Now test each chain.
+ for (Strings::const_iterator ee_type = key_types.begin();
+ ee_type != key_types.end(); ++ee_type) {
+ for (Strings::const_iterator signer_type = key_types.begin();
+ signer_type != key_types.end(); ++signer_type) {
+ std::string basename = *ee_type + "-ee-by-" + *signer_type +
+ "-intermediate.pem";
+ SCOPED_TRACE(basename);
+ scoped_refptr<X509Certificate> ee_cert =
+ ImportCertFromFile(certs_dir, basename);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert);
+
+ basename = *signer_type + "-intermediate.pem";
+ scoped_refptr<X509Certificate> intermediate =
+ ImportCertFromFile(certs_dir, basename);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate->os_cert_handle());
+ scoped_refptr<X509Certificate> cert_chain =
+ X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(),
+ intermediates);
+
+ CertVerifyResult verify_result;
+ int error = Verify(cert_chain, "127.0.0.1", 0, NULL, &verify_result);
+
+ if (IsWeakKeyType(*ee_type) || IsWeakKeyType(*signer_type)) {
+ EXPECT_NE(OK, error);
+ EXPECT_EQ(CERT_STATUS_WEAK_KEY,
+ verify_result.cert_status & CERT_STATUS_WEAK_KEY);
+ } else {
+ EXPECT_EQ(OK, error);
+ EXPECT_EQ(0U, verify_result.cert_status & CERT_STATUS_WEAK_KEY);
+ }
+ }
+ }
+}
+
+// Test for bug 108514.
+// The certificate will expire on 2012-07-20. The test will still
+// pass if error == ERR_CERT_DATE_INVALID. TODO(rsleevi): generate test
+// certificates for this unit test. http://crbug.com/111730
+TEST_F(CertVerifyProcTest, ExtraneousMD5RootCert) {
+ FilePath certs_dir = GetTestCertsDirectory();
+
+ scoped_refptr<X509Certificate> server_cert =
+ ImportCertFromFile(certs_dir, "images_etrade_wallst_com.pem");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
+
+ scoped_refptr<X509Certificate> intermediate_cert =
+ ImportCertFromFile(certs_dir, "globalsign_orgv1_ca.pem");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
+
+ scoped_refptr<X509Certificate> md5_root_cert =
+ ImportCertFromFile(certs_dir, "globalsign_root_ca_md5.pem");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), md5_root_cert);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate_cert->os_cert_handle());
+ intermediates.push_back(md5_root_cert->os_cert_handle());
+ scoped_refptr<X509Certificate> cert_chain =
+ X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
+ intermediates);
+
+ CertVerifyResult verify_result;
+ int flags = 0;
+ int error = Verify(cert_chain, "images.etrade.wallst.com", flags, NULL,
+ &verify_result);
+ if (error != OK)
+ EXPECT_EQ(ERR_CERT_DATE_INVALID, error);
+
+ EXPECT_FALSE(verify_result.has_md5);
+ EXPECT_FALSE(verify_result.has_md5_ca);
+}
+
+// Test for bug 94673.
+TEST_F(CertVerifyProcTest, GoogleDigiNotarTest) {
+ FilePath certs_dir = GetTestCertsDirectory();
+
+ scoped_refptr<X509Certificate> server_cert =
+ ImportCertFromFile(certs_dir, "google_diginotar.pem");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
+
+ scoped_refptr<X509Certificate> intermediate_cert =
+ ImportCertFromFile(certs_dir, "diginotar_public_ca_2025.pem");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate_cert->os_cert_handle());
+ scoped_refptr<X509Certificate> cert_chain =
+ X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
+ intermediates);
+
+ CertVerifyResult verify_result;
+ int flags = X509Certificate::VERIFY_REV_CHECKING_ENABLED;
+ int error = Verify(cert_chain, "mail.google.com", flags, NULL,
+ &verify_result);
+ EXPECT_NE(OK, error);
+
+ // Now turn off revocation checking. Certificate verification should still
+ // fail.
+ flags = 0;
+ error = Verify(cert_chain, "mail.google.com", flags, NULL, &verify_result);
+ EXPECT_NE(OK, error);
+}
+
+// Bug 111893: This test needs a new certificate.
+TEST_F(CertVerifyProcTest, DISABLED_TestKnownRoot) {
+ FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> cert =
+ ImportCertFromFile(certs_dir, "nist.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), cert);
+
+ // This intermediate is only needed for old Linux machines. Modern NSS
+ // includes it as a root already.
+ scoped_refptr<X509Certificate> intermediate_cert =
+ ImportCertFromFile(certs_dir, "nist_intermediate.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate_cert->os_cert_handle());
+ scoped_refptr<X509Certificate> cert_chain =
+ X509Certificate::CreateFromHandle(cert->os_cert_handle(),
+ intermediates);
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ // This is going to blow up in Feb 2012. Sorry! Disable and file a bug
+ // against agl. Also see PublicKeyHashes in this file.
+ int error = Verify(cert_chain, "www.nist.gov", flags, NULL, &verify_result);
+ EXPECT_EQ(OK, error);
+ EXPECT_EQ(0U, verify_result.cert_status);
+ EXPECT_TRUE(verify_result.is_issued_by_known_root);
+}
+
+// Bug 111893: This test needs a new certificate.
+TEST_F(CertVerifyProcTest, DISABLED_PublicKeyHashes) {
+ FilePath certs_dir = GetTestCertsDirectory();
+ // This is going to blow up in Feb 2012. Sorry! Disable and file a bug
+ // against agl. Also see TestKnownRoot in this file.
+ scoped_refptr<X509Certificate> cert =
+ ImportCertFromFile(certs_dir, "nist.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), cert);
+
+ // This intermediate is only needed for old Linux machines. Modern NSS
+ // includes it as a root already.
+ scoped_refptr<X509Certificate> intermediate_cert =
+ ImportCertFromFile(certs_dir, "nist_intermediate.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
+
+ ScopedTestRoot scoped_intermediate(intermediate_cert);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate_cert->os_cert_handle());
+ scoped_refptr<X509Certificate> cert_chain =
+ X509Certificate::CreateFromHandle(cert->os_cert_handle(),
+ intermediates);
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+
+ int error = Verify(cert_chain, "www.nist.gov", flags, NULL, &verify_result);
+ EXPECT_EQ(OK, error);
+ EXPECT_EQ(0U, verify_result.cert_status);
+ ASSERT_LE(2u, verify_result.public_key_hashes.size());
+ EXPECT_EQ(HexEncode(nistSPKIHash, base::kSHA1Length),
+ HexEncode(verify_result.public_key_hashes[0].data, base::kSHA1Length));
+ EXPECT_EQ("83244223D6CBF0A26FC7DE27CEBCA4BDA32612AD",
+ HexEncode(verify_result.public_key_hashes[1].data, base::kSHA1Length));
+}
+
+// A regression test for http://crbug.com/70293.
+// The Key Usage extension in this RSA SSL server certificate does not have
+// the keyEncipherment bit.
+TEST_F(CertVerifyProcTest, InvalidKeyUsage) {
+ FilePath certs_dir = GetTestCertsDirectory();
+
+ scoped_refptr<X509Certificate> server_cert =
+ ImportCertFromFile(certs_dir, "invalid_key_usage_cert.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ int error = Verify(server_cert, "jira.aquameta.com", flags, NULL,
+ &verify_result);
+#if defined(USE_OPENSSL)
+ // This certificate has two errors: "invalid key usage" and "untrusted CA".
+ // However, OpenSSL returns only one (the latter), and we can't detect
+ // the other errors.
+ EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+#else
+ EXPECT_EQ(ERR_CERT_INVALID, error);
+ EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID);
+#endif
+ // TODO(wtc): fix http://crbug.com/75520 to get all the certificate errors
+ // from NSS.
+#if !defined(USE_NSS)
+ // The certificate is issued by an unknown CA.
+ EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_AUTHORITY_INVALID);
+#endif
+}
+
+// Basic test for returning the chain in CertVerifyResult. Note that the
+// returned chain may just be a reflection of the originally supplied chain;
+// that is, if any errors occur, the default chain returned is an exact copy
+// of the certificate to be verified. The remaining VerifyReturn* tests are
+// used to ensure that the actual, verified chain is being returned by
+// Verify().
+TEST_F(CertVerifyProcTest, VerifyReturnChainBasic) {
+ FilePath certs_dir = GetTestCertsDirectory();
+ CertificateList certs = CreateCertificateListFromFile(
+ certs_dir, "x509_verify_results.chain.pem",
+ X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(3U, certs.size());
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(certs[1]->os_cert_handle());
+ intermediates.push_back(certs[2]->os_cert_handle());
+
+ ScopedTestRoot scoped_root(certs[2]);
+
+ scoped_refptr<X509Certificate> google_full_chain =
+ X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
+ intermediates);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain);
+ ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size());
+
+ CertVerifyResult verify_result;
+ EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
+ int error = Verify(google_full_chain, "127.0.0.1", 0, NULL, &verify_result);
+ EXPECT_EQ(OK, error);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
+
+ EXPECT_NE(google_full_chain, verify_result.verified_cert);
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(
+ google_full_chain->os_cert_handle(),
+ verify_result.verified_cert->os_cert_handle()));
+ const X509Certificate::OSCertHandles& return_intermediates =
+ verify_result.verified_cert->GetIntermediateCertificates();
+ ASSERT_EQ(2U, return_intermediates.size());
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
+ certs[1]->os_cert_handle()));
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
+ certs[2]->os_cert_handle()));
+}
+
+// Test that the certificate returned in CertVerifyResult is able to reorder
+// certificates that are not ordered from end-entity to root. While this is
+// a protocol violation if sent during a TLS handshake, if multiple sources
+// of intermediate certificates are combined, it's possible that order may
+// not be maintained.
+TEST_F(CertVerifyProcTest, VerifyReturnChainProperlyOrdered) {
+ FilePath certs_dir = GetTestCertsDirectory();
+ CertificateList certs = CreateCertificateListFromFile(
+ certs_dir, "x509_verify_results.chain.pem",
+ X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(3U, certs.size());
+
+ // Construct the chain out of order.
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(certs[2]->os_cert_handle());
+ intermediates.push_back(certs[1]->os_cert_handle());
+
+ ScopedTestRoot scoped_root(certs[2]);
+
+ scoped_refptr<X509Certificate> google_full_chain =
+ X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
+ intermediates);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain);
+ ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size());
+
+ CertVerifyResult verify_result;
+ EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
+ int error = Verify(google_full_chain, "127.0.0.1", 0, NULL, &verify_result);
+ EXPECT_EQ(OK, error);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
+
+ EXPECT_NE(google_full_chain, verify_result.verified_cert);
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(
+ google_full_chain->os_cert_handle(),
+ verify_result.verified_cert->os_cert_handle()));
+ const X509Certificate::OSCertHandles& return_intermediates =
+ verify_result.verified_cert->GetIntermediateCertificates();
+ ASSERT_EQ(2U, return_intermediates.size());
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
+ certs[1]->os_cert_handle()));
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
+ certs[2]->os_cert_handle()));
+}
+
+// Test that Verify() filters out certificates which are not related to
+// or part of the certificate chain being verified.
+TEST_F(CertVerifyProcTest, VerifyReturnChainFiltersUnrelatedCerts) {
+ FilePath certs_dir = GetTestCertsDirectory();
+ CertificateList certs = CreateCertificateListFromFile(
+ certs_dir, "x509_verify_results.chain.pem",
+ X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(3U, certs.size());
+ ScopedTestRoot scoped_root(certs[2]);
+
+ scoped_refptr<X509Certificate> unrelated_dod_certificate =
+ ImportCertFromFile(certs_dir, "dod_ca_17_cert.der");
+ scoped_refptr<X509Certificate> unrelated_dod_certificate2 =
+ ImportCertFromFile(certs_dir, "dod_root_ca_2_cert.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), unrelated_dod_certificate);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), unrelated_dod_certificate2);
+
+ // Interject unrelated certificates into the list of intermediates.
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(unrelated_dod_certificate->os_cert_handle());
+ intermediates.push_back(certs[1]->os_cert_handle());
+ intermediates.push_back(unrelated_dod_certificate2->os_cert_handle());
+ intermediates.push_back(certs[2]->os_cert_handle());
+
+ scoped_refptr<X509Certificate> google_full_chain =
+ X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
+ intermediates);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain);
+ ASSERT_EQ(4U, google_full_chain->GetIntermediateCertificates().size());
+
+ CertVerifyResult verify_result;
+ EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
+ int error = Verify(google_full_chain, "127.0.0.1", 0, NULL, &verify_result);
+ EXPECT_EQ(OK, error);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
+
+ EXPECT_NE(google_full_chain, verify_result.verified_cert);
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(
+ google_full_chain->os_cert_handle(),
+ verify_result.verified_cert->os_cert_handle()));
+ const X509Certificate::OSCertHandles& return_intermediates =
+ verify_result.verified_cert->GetIntermediateCertificates();
+ ASSERT_EQ(2U, return_intermediates.size());
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
+ certs[1]->os_cert_handle()));
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
+ certs[2]->os_cert_handle()));
+}
+
+#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
+static const uint8 kCRLSetThawteSPKIBlocked[] = {
+ 0x8e, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
+ 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
+ 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
+ 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
+ 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
+ 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
+ 0x30, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
+ 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x36, 0x58, 0x36, 0x4d, 0x78, 0x52, 0x37,
+ 0x58, 0x70, 0x4d, 0x51, 0x4b, 0x78, 0x49, 0x41, 0x39, 0x50, 0x6a, 0x36, 0x37,
+ 0x36, 0x38, 0x76, 0x74, 0x55, 0x6b, 0x6b, 0x7a, 0x48, 0x79, 0x7a, 0x41, 0x6f,
+ 0x6d, 0x6f, 0x4f, 0x68, 0x4b, 0x55, 0x6e, 0x7a, 0x73, 0x55, 0x3d, 0x22, 0x5d,
+ 0x7d,
+};
+
+static const uint8 kCRLSetThawteSerialBlocked[] = {
+ 0x60, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
+ 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
+ 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
+ 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
+ 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
+ 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
+ 0x31, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
+ 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0xb1, 0x12, 0x41, 0x42, 0xa5, 0xa1,
+ 0xa5, 0xa2, 0x88, 0x19, 0xc7, 0x35, 0x34, 0x0e, 0xff, 0x8c, 0x9e, 0x2f, 0x81,
+ 0x68, 0xfe, 0xe3, 0xba, 0x18, 0x7f, 0x25, 0x3b, 0xc1, 0xa3, 0x92, 0xd7, 0xe2,
+ // Note that this is actually blocking two serial numbers because on XP and
+ // Vista, CryptoAPI finds a different Thawte certificate.
+ 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x30, 0x00, 0x00, 0x02,
+ 0x04, 0x30, 0x00, 0x00, 0x06,
+};
+
+static const uint8 kCRLSetGoogleSerialBlocked[] = {
+ 0x60, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
+ 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
+ 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
+ 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
+ 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
+ 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
+ 0x31, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
+ 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0xe9, 0x7e, 0x8c, 0xc5, 0x1e, 0xd7,
+ 0xa4, 0xc4, 0x0a, 0xc4, 0x80, 0x3d, 0x3e, 0x3e, 0xbb, 0xeb, 0xcb, 0xed, 0x52,
+ 0x49, 0x33, 0x1f, 0x2c, 0xc0, 0xa2, 0x6a, 0x0e, 0x84, 0xa5, 0x27, 0xce, 0xc5,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x4f, 0x9d, 0x96, 0xd9, 0x66, 0xb0, 0x99, 0x2b,
+ 0x54, 0xc2, 0x95, 0x7c, 0xb4, 0x15, 0x7d, 0x4d,
+};
+
+// Test that CRLSets are effective in making a certificate appear to be
+// revoked.
+TEST_F(CertVerifyProcTest, CRLSet) {
+ CertificateList certs = CreateCertificateListFromFile(
+ GetTestCertsDirectory(),
+ "googlenew.chain.pem",
+ X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(certs[1]->os_cert_handle());
+
+ scoped_refptr<X509Certificate> google_full_chain =
+ X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
+ intermediates);
+
+ CertVerifyResult verify_result;
+ int error = Verify(google_full_chain, "www.google.com", 0, NULL,
+ &verify_result);
+ EXPECT_EQ(OK, error);
+
+ // First test blocking by SPKI.
+ base::StringPiece crl_set_bytes(
+ reinterpret_cast<const char*>(kCRLSetThawteSPKIBlocked),
+ sizeof(kCRLSetThawteSPKIBlocked));
+ scoped_refptr<CRLSet> crl_set;
+ ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
+
+ error = Verify(google_full_chain, "www.google.com", 0, crl_set.get(),
+ &verify_result);
+ EXPECT_EQ(ERR_CERT_REVOKED, error);
+
+ // Second, test revocation by serial number of a cert directly under the
+ // root.
+ crl_set_bytes = base::StringPiece(
+ reinterpret_cast<const char*>(kCRLSetThawteSerialBlocked),
+ sizeof(kCRLSetThawteSerialBlocked));
+ ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
+
+ error = Verify(google_full_chain, "www.google.com", 0, crl_set.get(),
+ &verify_result);
+ EXPECT_EQ(ERR_CERT_REVOKED, error);
+
+ // Lastly, test revocation by serial number of a certificate not under the
+ // root.
+ crl_set_bytes = base::StringPiece(
+ reinterpret_cast<const char*>(kCRLSetGoogleSerialBlocked),
+ sizeof(kCRLSetGoogleSerialBlocked));
+ ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
+
+ error = Verify(google_full_chain, "www.google.com", 0, crl_set.get(),
+ &verify_result);
+ EXPECT_EQ(ERR_CERT_REVOKED, error);
+}
+#endif
+
+struct WeakDigestTestData {
+ const char* root_cert_filename;
+ const char* intermediate_cert_filename;
+ const char* ee_cert_filename;
+ bool expected_has_md5;
+ bool expected_has_md4;
+ bool expected_has_md2;
+ bool expected_has_md5_ca;
+ bool expected_has_md2_ca;
+};
+
+// GTest 'magic' pretty-printer, so that if/when a test fails, it knows how
+// to output the parameter that was passed. Without this, it will simply
+// attempt to print out the first twenty bytes of the object, which depending
+// on platform and alignment, may result in an invalid read.
+void PrintTo(const WeakDigestTestData& data, std::ostream* os) {
+ *os << "root: "
+ << (data.root_cert_filename ? data.root_cert_filename : "none")
+ << "; intermediate: " << data.intermediate_cert_filename
+ << "; end-entity: " << data.ee_cert_filename;
+}
+
+class CertVerifyProcWeakDigestTest
+ : public CertVerifyProcTest,
+ public testing::WithParamInterface<WeakDigestTestData> {
+ public:
+ CertVerifyProcWeakDigestTest() {}
+ virtual ~CertVerifyProcWeakDigestTest() {}
+};
+
+TEST_P(CertVerifyProcWeakDigestTest, Verify) {
+ WeakDigestTestData data = GetParam();
+ FilePath certs_dir = GetTestCertsDirectory();
+
+ ScopedTestRoot test_root;
+ if (data.root_cert_filename) {
+ scoped_refptr<X509Certificate> root_cert =
+ ImportCertFromFile(certs_dir, data.root_cert_filename);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
+ test_root.Reset(root_cert);
+ }
+
+ scoped_refptr<X509Certificate> intermediate_cert =
+ ImportCertFromFile(certs_dir, data.intermediate_cert_filename);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
+ scoped_refptr<X509Certificate> ee_cert =
+ ImportCertFromFile(certs_dir, data.ee_cert_filename);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert);
+
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate_cert->os_cert_handle());
+
+ scoped_refptr<X509Certificate> ee_chain =
+ X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(),
+ intermediates);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_chain);
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ int rv = Verify(ee_chain, "127.0.0.1", flags, NULL, &verify_result);
+ EXPECT_EQ(data.expected_has_md5, verify_result.has_md5);
+ EXPECT_EQ(data.expected_has_md4, verify_result.has_md4);
+ EXPECT_EQ(data.expected_has_md2, verify_result.has_md2);
+ EXPECT_EQ(data.expected_has_md5_ca, verify_result.has_md5_ca);
+ EXPECT_EQ(data.expected_has_md2_ca, verify_result.has_md2_ca);
+
+ // Ensure that MD4 and MD2 are tagged as invalid.
+ if (data.expected_has_md4 || data.expected_has_md2) {
+ EXPECT_EQ(CERT_STATUS_INVALID,
+ verify_result.cert_status & CERT_STATUS_INVALID);
+ }
+
+ // Ensure that MD5 is flagged as weak.
+ if (data.expected_has_md5) {
+ EXPECT_EQ(
+ CERT_STATUS_WEAK_SIGNATURE_ALGORITHM,
+ verify_result.cert_status & CERT_STATUS_WEAK_SIGNATURE_ALGORITHM);
+ }
+
+ // If a root cert is present, then check that the chain was rejected if any
+ // weak algorithms are present. This is only checked when a root cert is
+ // present because the error reported for incomplete chains with weak
+ // algorithms depends on which implementation was used to validate (NSS,
+ // OpenSSL, CryptoAPI, Security.framework) and upon which weak algorithm
+ // present (MD2, MD4, MD5).
+ if (data.root_cert_filename) {
+ if (data.expected_has_md4 || data.expected_has_md2) {
+ EXPECT_EQ(ERR_CERT_INVALID, rv);
+ } else if (data.expected_has_md5) {
+ EXPECT_EQ(ERR_CERT_WEAK_SIGNATURE_ALGORITHM, rv);
+ } else {
+ EXPECT_EQ(OK, rv);
+ }
+ }
+}
+
+// Unlike TEST/TEST_F, which are macros that expand to further macros,
+// INSTANTIATE_TEST_CASE_P is a macro that expands directly to code that
+// stringizes the arguments. As a result, macros passed as parameters (such as
+// prefix or test_case_name) will not be expanded by the preprocessor. To work
+// around this, indirect the macro for INSTANTIATE_TEST_CASE_P, so that the
+// pre-processor will expand macros such as MAYBE_test_name before
+// instantiating the test.
+#define WRAPPED_INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+ INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator)
+
+// The signature algorithm of the root CA should not matter.
+const WeakDigestTestData kVerifyRootCATestData[] = {
+ { "weak_digest_md5_root.pem", "weak_digest_sha1_intermediate.pem",
+ "weak_digest_sha1_ee.pem", false, false, false, false, false },
+#if !defined(OS_MACOSX) // MD4 is not supported.
+ { "weak_digest_md4_root.pem", "weak_digest_sha1_intermediate.pem",
+ "weak_digest_sha1_ee.pem", false, false, false, false, false },
+#endif
+ { "weak_digest_md2_root.pem", "weak_digest_sha1_intermediate.pem",
+ "weak_digest_sha1_ee.pem", false, false, false, false, false },
+};
+INSTANTIATE_TEST_CASE_P(VerifyRoot, CertVerifyProcWeakDigestTest,
+ testing::ValuesIn(kVerifyRootCATestData));
+
+// The signature algorithm of intermediates should be properly detected.
+const WeakDigestTestData kVerifyIntermediateCATestData[] = {
+ { "weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem",
+ "weak_digest_sha1_ee.pem", true, false, false, true, false },
+#if !defined(USE_NSS) && !defined(OS_MACOSX) // MD4 is not supported.
+ { "weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem",
+ "weak_digest_sha1_ee.pem", false, true, false, false, false },
+#endif
+#if !defined(USE_NSS) // MD2 is disabled by default.
+ { "weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem",
+ "weak_digest_sha1_ee.pem", false, false, true, false, true },
+#endif
+};
+INSTANTIATE_TEST_CASE_P(VerifyIntermediate, CertVerifyProcWeakDigestTest,
+ testing::ValuesIn(kVerifyIntermediateCATestData));
+
+// The signature algorithm of end-entity should be properly detected.
+const WeakDigestTestData kVerifyEndEntityTestData[] = {
+ { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem",
+ "weak_digest_md5_ee.pem", true, false, false, false, false },
+#if !defined(USE_NSS) && !defined(OS_MACOSX) // MD4 is not supported.
+ { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem",
+ "weak_digest_md4_ee.pem", false, true, false, false, false },
+#endif
+#if !defined(USE_NSS) // MD2 is disabled by default.
+ { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem",
+ "weak_digest_md2_ee.pem", false, false, true, false, false },
+#endif
+};
+// Disabled on NSS - NSS caches chains/signatures in such a way that cannot
+// be cleared until NSS is cleanly shutdown, which is not presently supported
+// in Chromium.
+#if defined(USE_NSS)
+#define MAYBE_VerifyEndEntity DISABLED_VerifyEndEntity
+#else
+#define MAYBE_VerifyEndEntity VerifyEndEntity
+#endif
+WRAPPED_INSTANTIATE_TEST_CASE_P(MAYBE_VerifyEndEntity,
+ CertVerifyProcWeakDigestTest,
+ testing::ValuesIn(kVerifyEndEntityTestData));
+
+// Incomplete chains should still report the status of the intermediate.
+const WeakDigestTestData kVerifyIncompleteIntermediateTestData[] = {
+ { NULL, "weak_digest_md5_intermediate.pem", "weak_digest_sha1_ee.pem",
+ true, false, false, true, false },
+#if !defined(OS_MACOSX) // MD4 is not supported.
+ { NULL, "weak_digest_md4_intermediate.pem", "weak_digest_sha1_ee.pem",
+ false, true, false, false, false },
+#endif
+ { NULL, "weak_digest_md2_intermediate.pem", "weak_digest_sha1_ee.pem",
+ false, false, true, false, true },
+};
+// Disabled on NSS - libpkix does not return constructed chains on error,
+// preventing us from detecting/inspecting the verified chain.
+#if defined(USE_NSS)
+#define MAYBE_VerifyIncompleteIntermediate \
+ DISABLED_VerifyIncompleteIntermediate
+#else
+#define MAYBE_VerifyIncompleteIntermediate VerifyIncompleteIntermediate
+#endif
+WRAPPED_INSTANTIATE_TEST_CASE_P(
+ MAYBE_VerifyIncompleteIntermediate,
+ CertVerifyProcWeakDigestTest,
+ testing::ValuesIn(kVerifyIncompleteIntermediateTestData));
+
+// Incomplete chains should still report the status of the end-entity.
+const WeakDigestTestData kVerifyIncompleteEETestData[] = {
+ { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md5_ee.pem",
+ true, false, false, false, false },
+#if !defined(OS_MACOSX) // MD4 is not supported.
+ { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md4_ee.pem",
+ false, true, false, false, false },
+#endif
+ { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md2_ee.pem",
+ false, false, true, false, false },
+};
+// Disabled on NSS - libpkix does not return constructed chains on error,
+// preventing us from detecting/inspecting the verified chain.
+#if defined(USE_NSS)
+#define MAYBE_VerifyIncompleteEndEntity DISABLED_VerifyIncompleteEndEntity
+#else
+#define MAYBE_VerifyIncompleteEndEntity VerifyIncompleteEndEntity
+#endif
+WRAPPED_INSTANTIATE_TEST_CASE_P(
+ MAYBE_VerifyIncompleteEndEntity,
+ CertVerifyProcWeakDigestTest,
+ testing::ValuesIn(kVerifyIncompleteEETestData));
+
+// Differing algorithms between the intermediate and the EE should still be
+// reported.
+const WeakDigestTestData kVerifyMixedTestData[] = {
+ { "weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem",
+ "weak_digest_md2_ee.pem", true, false, true, true, false },
+ { "weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem",
+ "weak_digest_md5_ee.pem", true, false, true, false, true },
+#if !defined(OS_MACOSX) // MD4 is not supported.
+ { "weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem",
+ "weak_digest_md2_ee.pem", false, true, true, false, false },
+#endif
+};
+// NSS does not support MD4 and does not enable MD2 by default, making all
+// permutations invalid.
+#if defined(USE_NSS)
+#define MAYBE_VerifyMixed DISABLED_VerifyMixed
+#else
+#define MAYBE_VerifyMixed VerifyMixed
+#endif
+WRAPPED_INSTANTIATE_TEST_CASE_P(
+ MAYBE_VerifyMixed,
+ CertVerifyProcWeakDigestTest,
+ testing::ValuesIn(kVerifyMixedTestData));
+
+} // namespace net
diff --git a/net/base/multi_threaded_cert_verifier.cc b/net/base/multi_threaded_cert_verifier.cc
index 6a3037b..d614590 100644
--- a/net/base/multi_threaded_cert_verifier.cc
+++ b/net/base/multi_threaded_cert_verifier.cc
@@ -4,6 +4,8 @@
#include "net/base/multi_threaded_cert_verifier.h"
+#include <vector>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
@@ -13,6 +15,7 @@
#include "base/synchronization/lock.h"
#include "base/time.h"
#include "base/threading/worker_pool.h"
+#include "net/base/cert_verify_proc.h"
#include "net/base/crl_set.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
@@ -130,12 +133,14 @@ class CertVerifierRequest {
// eventually if Start() succeeds.
class CertVerifierWorker {
public:
- CertVerifierWorker(X509Certificate* cert,
+ CertVerifierWorker(CertVerifyProc* verify_proc,
+ X509Certificate* cert,
const std::string& hostname,
int flags,
CRLSet* crl_set,
MultiThreadedCertVerifier* cert_verifier)
- : cert_(cert),
+ : verify_proc_(verify_proc),
+ cert_(cert),
hostname_(hostname),
flags_(flags),
crl_set_(crl_set),
@@ -168,7 +173,8 @@ class CertVerifierWorker {
private:
void Run() {
// Runs on a worker thread.
- error_ = cert_->Verify(hostname_, flags_, crl_set_, &verify_result_);
+ error_ = verify_proc_->Verify(cert_, hostname_, flags_, crl_set_,
+ &verify_result_);
#if defined(USE_NSS)
// Detach the thread from NSPR.
// Calling NSS functions attaches the thread to NSPR, which stores
@@ -226,6 +232,7 @@ class CertVerifierWorker {
delete this;
}
+ scoped_refptr<CertVerifyProc> verify_proc_;
scoped_refptr<X509Certificate> cert_;
const std::string hostname_;
const int flags_;
@@ -324,7 +331,8 @@ MultiThreadedCertVerifier::MultiThreadedCertVerifier()
: cache_(kMaxCacheEntries),
requests_(0),
cache_hits_(0),
- inflight_joins_(0) {
+ inflight_joins_(0),
+ verify_proc_(CertVerifyProc::CreateDefault()) {
CertDatabase::AddObserver(this);
}
@@ -373,7 +381,8 @@ int MultiThreadedCertVerifier::Verify(X509Certificate* cert,
job = j->second;
} else {
// Need to make a new request.
- CertVerifierWorker* worker = new CertVerifierWorker(cert, hostname, flags,
+ CertVerifierWorker* worker = new CertVerifierWorker(verify_proc_, cert,
+ hostname, flags,
crl_set, this);
job = new CertVerifierJob(
worker,
@@ -441,4 +450,8 @@ void MultiThreadedCertVerifier::OnCertTrustChanged(
ClearCache();
}
+void MultiThreadedCertVerifier::SetCertVerifyProc(CertVerifyProc* verify_proc) {
+ verify_proc_ = verify_proc;
+}
+
} // namespace net
diff --git a/net/base/multi_threaded_cert_verifier.h b/net/base/multi_threaded_cert_verifier.h
index c8eca2e..10c9421 100644
--- a/net/base/multi_threaded_cert_verifier.h
+++ b/net/base/multi_threaded_cert_verifier.h
@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "net/base/cert_database.h"
@@ -26,10 +27,11 @@ namespace net {
class CertVerifierJob;
class CertVerifierRequest;
class CertVerifierWorker;
+class CertVerifyProc;
// MultiThreadedCertVerifier is a CertVerifier implementation that runs
// synchronous CertVerifier implementations on worker threads.
-class NET_EXPORT MultiThreadedCertVerifier :
+class NET_EXPORT_PRIVATE MultiThreadedCertVerifier :
public CertVerifier,
NON_EXPORTED_BASE(public base::NonThreadSafe),
public CertDatabase::Observer {
@@ -56,6 +58,7 @@ class NET_EXPORT MultiThreadedCertVerifier :
friend class CertVerifierWorker; // Calls HandleResult.
friend class CertVerifierRequest;
friend class CertVerifierJob;
+ friend class MultiThreadedCertVerifierTest;
FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest, CacheHit);
FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest, DifferentCACerts);
FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest, InflightJoin);
@@ -121,6 +124,7 @@ class NET_EXPORT MultiThreadedCertVerifier :
uint64 cache_hits() const { return cache_hits_; }
uint64 requests() const { return requests_; }
uint64 inflight_joins() const { return inflight_joins_; }
+ void SetCertVerifyProc(CertVerifyProc* verify_proc);
// cache_ maps from a request to a cached result.
typedef ExpiringCache<RequestParams, CachedResult> CertVerifierCache;
@@ -134,6 +138,8 @@ class NET_EXPORT MultiThreadedCertVerifier :
uint64 cache_hits_;
uint64 inflight_joins_;
+ scoped_refptr<CertVerifyProc> verify_proc_;
+
DISALLOW_COPY_AND_ASSIGN(MultiThreadedCertVerifier);
};
diff --git a/net/base/multi_threaded_cert_verifier_unittest.cc b/net/base/multi_threaded_cert_verifier_unittest.cc
index 17eed99..ae7d684 100644
--- a/net/base/multi_threaded_cert_verifier_unittest.cc
+++ b/net/base/multi_threaded_cert_verifier_unittest.cc
@@ -9,6 +9,8 @@
#include "base/format_macros.h"
#include "base/stringprintf.h"
#include "net/base/cert_test_util.h"
+#include "net/base/cert_verify_proc.h"
+#include "net/base/cert_verify_result.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/test_completion_callback.h"
@@ -23,7 +25,38 @@ void FailTest(int /* result */) {
FAIL();
}
-} // namespace;
+class MockCertVerifyProc : public CertVerifyProc {
+ public:
+ MockCertVerifyProc() {}
+
+ private:
+ virtual ~MockCertVerifyProc() {}
+
+ // CertVerifyProc implementation
+ virtual int VerifyInternal(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result) OVERRIDE {
+ verify_result->Reset();
+ verify_result->verified_cert = cert;
+ verify_result->cert_status = CERT_STATUS_COMMON_NAME_INVALID;
+ return ERR_CERT_COMMON_NAME_INVALID;
+ }
+};
+
+} // namespace
+
+class MultiThreadedCertVerifierTest : public ::testing::Test {
+ public:
+ MultiThreadedCertVerifierTest() {
+ verifier_.SetCertVerifyProc(new MockCertVerifyProc());
+ }
+ virtual ~MultiThreadedCertVerifierTest() {}
+
+ protected:
+ MultiThreadedCertVerifier verifier_;
+};
// Tests a cache hit, which should result in synchronous completion.
#if defined(OS_MACOSX)
@@ -32,9 +65,7 @@ void FailTest(int /* result */) {
#else
#define MAYBE_CacheHit CacheHit
#endif // defined(OS_MACOSX)
-TEST(MultiThreadedCertVerifierTest, MAYBE_CacheHit) {
- MultiThreadedCertVerifier verifier;
-
+TEST_F(MultiThreadedCertVerifierTest, MAYBE_CacheHit) {
FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(certs_dir, "ok_cert.pem"));
@@ -45,35 +76,35 @@ TEST(MultiThreadedCertVerifierTest, MAYBE_CacheHit) {
TestCompletionCallback callback;
CertVerifier::RequestHandle request_handle;
- error = verifier.Verify(test_cert, "www.example.com", 0, NULL, &verify_result,
- callback.callback(), &request_handle, BoundNetLog());
+ error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
+ &verify_result, callback.callback(),
+ &request_handle, BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, error);
ASSERT_TRUE(request_handle != NULL);
error = callback.WaitForResult();
ASSERT_TRUE(IsCertificateError(error));
- ASSERT_EQ(1u, verifier.requests());
- ASSERT_EQ(0u, verifier.cache_hits());
- ASSERT_EQ(0u, verifier.inflight_joins());
- ASSERT_EQ(1u, verifier.GetCacheSize());
-
- error = verifier.Verify(test_cert, "www.example.com", 0, NULL, &verify_result,
- callback.callback(), &request_handle, BoundNetLog());
+ ASSERT_EQ(1u, verifier_.requests());
+ ASSERT_EQ(0u, verifier_.cache_hits());
+ ASSERT_EQ(0u, verifier_.inflight_joins());
+ ASSERT_EQ(1u, verifier_.GetCacheSize());
+
+ error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
+ &verify_result, callback.callback(),
+ &request_handle, BoundNetLog());
// Synchronous completion.
ASSERT_NE(ERR_IO_PENDING, error);
ASSERT_TRUE(IsCertificateError(error));
ASSERT_TRUE(request_handle == NULL);
- ASSERT_EQ(2u, verifier.requests());
- ASSERT_EQ(1u, verifier.cache_hits());
- ASSERT_EQ(0u, verifier.inflight_joins());
- ASSERT_EQ(1u, verifier.GetCacheSize());
+ ASSERT_EQ(2u, verifier_.requests());
+ ASSERT_EQ(1u, verifier_.cache_hits());
+ ASSERT_EQ(0u, verifier_.inflight_joins());
+ ASSERT_EQ(1u, verifier_.GetCacheSize());
}
// Tests the same server certificate with different intermediate CA
// certificates. These should be treated as different certificate chains even
// though the two X509Certificate objects contain the same server certificate.
-TEST(MultiThreadedCertVerifierTest, DifferentCACerts) {
- MultiThreadedCertVerifier verifier;
-
+TEST_F(MultiThreadedCertVerifierTest, DifferentCACerts) {
FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> server_cert =
@@ -105,35 +136,33 @@ TEST(MultiThreadedCertVerifierTest, DifferentCACerts) {
TestCompletionCallback callback;
CertVerifier::RequestHandle request_handle;
- error = verifier.Verify(cert_chain1, "www.example.com", 0, NULL,
- &verify_result, callback.callback(),
- &request_handle, BoundNetLog());
+ error = verifier_.Verify(cert_chain1, "www.example.com", 0, NULL,
+ &verify_result, callback.callback(),
+ &request_handle, BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, error);
ASSERT_TRUE(request_handle != NULL);
error = callback.WaitForResult();
ASSERT_TRUE(IsCertificateError(error));
- ASSERT_EQ(1u, verifier.requests());
- ASSERT_EQ(0u, verifier.cache_hits());
- ASSERT_EQ(0u, verifier.inflight_joins());
- ASSERT_EQ(1u, verifier.GetCacheSize());
-
- error = verifier.Verify(cert_chain2, "www.example.com", 0, NULL,
- &verify_result, callback.callback(),
- &request_handle, BoundNetLog());
+ ASSERT_EQ(1u, verifier_.requests());
+ ASSERT_EQ(0u, verifier_.cache_hits());
+ ASSERT_EQ(0u, verifier_.inflight_joins());
+ ASSERT_EQ(1u, verifier_.GetCacheSize());
+
+ error = verifier_.Verify(cert_chain2, "www.example.com", 0, NULL,
+ &verify_result, callback.callback(),
+ &request_handle, BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, error);
ASSERT_TRUE(request_handle != NULL);
error = callback.WaitForResult();
ASSERT_TRUE(IsCertificateError(error));
- ASSERT_EQ(2u, verifier.requests());
- ASSERT_EQ(0u, verifier.cache_hits());
- ASSERT_EQ(0u, verifier.inflight_joins());
- ASSERT_EQ(2u, verifier.GetCacheSize());
+ ASSERT_EQ(2u, verifier_.requests());
+ ASSERT_EQ(0u, verifier_.cache_hits());
+ ASSERT_EQ(0u, verifier_.inflight_joins());
+ ASSERT_EQ(2u, verifier_.GetCacheSize());
}
// Tests an inflight join.
-TEST(MultiThreadedCertVerifierTest, InflightJoin) {
- MultiThreadedCertVerifier verifier;
-
+TEST_F(MultiThreadedCertVerifierTest, InflightJoin) {
FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(certs_dir, "ok_cert.pem"));
@@ -147,11 +176,12 @@ TEST(MultiThreadedCertVerifierTest, InflightJoin) {
TestCompletionCallback callback2;
CertVerifier::RequestHandle request_handle2;
- error = verifier.Verify(test_cert, "www.example.com", 0, NULL, &verify_result,
- callback.callback(), &request_handle, BoundNetLog());
+ error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
+ &verify_result, callback.callback(),
+ &request_handle, BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, error);
ASSERT_TRUE(request_handle != NULL);
- error = verifier.Verify(
+ error = verifier_.Verify(
test_cert, "www.example.com", 0, NULL, &verify_result2,
callback2.callback(), &request_handle2, BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, error);
@@ -160,15 +190,13 @@ TEST(MultiThreadedCertVerifierTest, InflightJoin) {
ASSERT_TRUE(IsCertificateError(error));
error = callback2.WaitForResult();
ASSERT_TRUE(IsCertificateError(error));
- ASSERT_EQ(2u, verifier.requests());
- ASSERT_EQ(0u, verifier.cache_hits());
- ASSERT_EQ(1u, verifier.inflight_joins());
+ ASSERT_EQ(2u, verifier_.requests());
+ ASSERT_EQ(0u, verifier_.cache_hits());
+ ASSERT_EQ(1u, verifier_.inflight_joins());
}
// Tests that the callback of a canceled request is never made.
-TEST(MultiThreadedCertVerifierTest, CancelRequest) {
- MultiThreadedCertVerifier verifier;
-
+TEST_F(MultiThreadedCertVerifierTest, CancelRequest) {
FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(certs_dir, "ok_cert.pem"));
@@ -178,32 +206,30 @@ TEST(MultiThreadedCertVerifierTest, CancelRequest) {
CertVerifyResult verify_result;
CertVerifier::RequestHandle request_handle;
- error = verifier.Verify(
+ error = verifier_.Verify(
test_cert, "www.example.com", 0, NULL, &verify_result,
base::Bind(&FailTest), &request_handle, BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, error);
ASSERT_TRUE(request_handle != NULL);
- verifier.CancelRequest(request_handle);
+ verifier_.CancelRequest(request_handle);
// Issue a few more requests to the worker pool and wait for their
// completion, so that the task of the canceled request (which runs on a
// worker thread) is likely to complete by the end of this test.
TestCompletionCallback callback;
for (int i = 0; i < 5; ++i) {
- error = verifier.Verify(
+ error = verifier_.Verify(
test_cert, "www2.example.com", 0, NULL, &verify_result,
callback.callback(), &request_handle, BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, error);
ASSERT_TRUE(request_handle != NULL);
error = callback.WaitForResult();
- verifier.ClearCache();
+ verifier_.ClearCache();
}
}
// Tests that a canceled request is not leaked.
-TEST(MultiThreadedCertVerifierTest, CancelRequestThenQuit) {
- MultiThreadedCertVerifier verifier;
-
+TEST_F(MultiThreadedCertVerifierTest, CancelRequestThenQuit) {
FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(certs_dir, "ok_cert.pem"));
@@ -214,15 +240,16 @@ TEST(MultiThreadedCertVerifierTest, CancelRequestThenQuit) {
TestCompletionCallback callback;
CertVerifier::RequestHandle request_handle;
- error = verifier.Verify(test_cert, "www.example.com", 0, NULL, &verify_result,
- callback.callback(), &request_handle, BoundNetLog());
+ error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
+ &verify_result, callback.callback(),
+ &request_handle, BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, error);
ASSERT_TRUE(request_handle != NULL);
- verifier.CancelRequest(request_handle);
+ verifier_.CancelRequest(request_handle);
// Destroy |verifier| by going out of scope.
}
-TEST(MultiThreadedCertVerifierTest, RequestParamsComparators) {
+TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) {
SHA1Fingerprint a_key;
memset(a_key.data, 'a', sizeof(a_key.data));
diff --git a/net/base/single_request_cert_verifier.cc b/net/base/single_request_cert_verifier.cc
index 3370600..1777945 100644
--- a/net/base/single_request_cert_verifier.cc
+++ b/net/base/single_request_cert_verifier.cc
@@ -35,10 +35,6 @@ int SingleRequestCertVerifier::Verify(X509Certificate* cert,
// Should not be already in use.
DCHECK(!cur_request_ && cur_request_callback_.is_null());
- // Do a synchronous verification.
- if (callback.is_null())
- return cert->Verify(hostname, flags, crl_set, verify_result);
-
CertVerifier::RequestHandle request = NULL;
// We need to be notified of completion before |callback| is called, so that
diff --git a/net/base/test_certificate_data.h b/net/base/test_certificate_data.h
index ffb2eba..0b5edf3 100644
--- a/net/base/test_certificate_data.h
+++ b/net/base/test_certificate_data.h
@@ -1,9 +1,14 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
namespace {
+// This is the SHA1 hash of the SubjectPublicKeyInfo of nist.der.
+static const char nistSPKIHash[] =
+ "\x15\x60\xde\x65\x4e\x03\x9f\xd0\x08\x82"
+ "\xa9\x6a\xc4\x65\x8e\x6f\x92\x06\x84\x35";
+
// Certificates for test data. They're obtained with:
//
// $ openssl s_client -connect [host]:443 -showcerts > /tmp/host.pem < /dev/null
diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc
index cc681dd..ae31848 100644
--- a/net/base/transport_security_state_unittest.cc
+++ b/net/base/transport_security_state_unittest.cc
@@ -15,7 +15,10 @@
#include "net/base/cert_test_util.h"
#include "net/base/cert_verifier.h"
#include "net/base/cert_verify_result.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
#include "net/base/ssl_info.h"
+#include "net/base/test_completion_callback.h"
#include "net/base/test_root_certs.h"
#include "net/base/x509_certificate.h"
#include "net/http/http_util.h"
@@ -287,9 +290,15 @@ TEST_F(TransportSecurityStateTest, ValidPinsHeaders) {
// Verify has the side-effect of populating public_key_hashes, which
// ParsePinsHeader needs. (It wants to check pins against the validated
// chain, not just the presented chain.)
+ int rv = ERR_FAILED;
CertVerifyResult result;
- int rv = ssl_info.cert->Verify("127.0.0.1", 0, NULL, &result);
- ASSERT_EQ(0, rv);
+ scoped_ptr<CertVerifier> verifier(CertVerifier::CreateDefault());
+ TestCompletionCallback callback;
+ CertVerifier::RequestHandle handle = NULL;
+ rv = verifier->Verify(ssl_info.cert, "127.0.0.1", 0, NULL, &result,
+ callback.callback(), &handle, BoundNetLog());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(OK, rv);
// Normally, ssl_client_socket_nss would do this, but for a unit test we
// fake it.
ssl_info.public_key_hashes = result.public_key_hashes;
diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h
index c22e940..4dc4f68 100644
--- a/net/base/x509_certificate.h
+++ b/net/base/x509_certificate.h
@@ -375,32 +375,6 @@ class NET_EXPORT X509Certificate
static X509_STORE* cert_store();
#endif
- // Verifies the certificate against the given hostname. Returns OK if
- // successful or an error code upon failure.
- //
- // The |*verify_result| structure, including the |verify_result->cert_status|
- // bitmask, is always filled out regardless of the return value. If the
- // certificate has multiple errors, the corresponding status flags are set in
- // |verify_result->cert_status|, and the error code for the most serious
- // error is returned.
- //
- // |flags| is bitwise OR'd of VerifyFlags:
- //
- // If VERIFY_REV_CHECKING_ENABLED is set in |flags|, online certificate
- // revocation checking is performed (i.e. OCSP and downloading CRLs). CRLSet
- // based revocation checking is always enabled, regardless of this flag, if
- // |crl_set| is given.
- //
- // If VERIFY_EV_CERT is set in |flags| too, EV certificate verification is
- // performed.
- //
- // |crl_set| points to an optional CRLSet structure which can be used to
- // avoid revocation checks over the network.
- int Verify(const std::string& hostname,
- int flags,
- CRLSet* crl_set,
- CertVerifyResult* verify_result) const;
-
// Verifies that |hostname| matches this certificate.
// Does not verify that the certificate is valid, only that the certificate
// matches this host.
@@ -481,11 +455,12 @@ class NET_EXPORT X509Certificate
private:
friend class base::RefCountedThreadSafe<X509Certificate>;
friend class TestRootCerts; // For unit tests
- FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, Cache);
- FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, IntermediateCertificates);
- FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, SerialNumbers);
- FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, DigiNotarCerts);
+ // TODO(rsleevi): Temporary refactoring - http://crbug.com/114343
+ friend class CertVerifyProcStub;
+
FRIEND_TEST_ALL_PREFIXES(X509CertificateNameVerifyTest, VerifyHostname);
+ FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, DigiNotarCerts);
+ FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, SerialNumbers);
// Construct an X509Certificate from a handle to the certificate object
// in the underlying crypto library.
@@ -497,6 +472,32 @@ class NET_EXPORT X509Certificate
// Common object initialization code. Called by the constructors only.
void Initialize();
+ // Verifies the certificate against the given hostname. Returns OK if
+ // successful or an error code upon failure.
+ //
+ // The |*verify_result| structure, including the |verify_result->cert_status|
+ // bitmask, is always filled out regardless of the return value. If the
+ // certificate has multiple errors, the corresponding status flags are set in
+ // |verify_result->cert_status|, and the error code for the most serious
+ // error is returned.
+ //
+ // |flags| is bitwise OR'd of VerifyFlags:
+ //
+ // If VERIFY_REV_CHECKING_ENABLED is set in |flags|, online certificate
+ // revocation checking is performed (i.e. OCSP and downloading CRLs). CRLSet
+ // based revocation checking is always enabled, regardless of this flag, if
+ // |crl_set| is given.
+ //
+ // If VERIFY_EV_CERT is set in |flags| too, EV certificate verification is
+ // performed.
+ //
+ // |crl_set| points to an optional CRLSet structure which can be used to
+ // avoid revocation checks over the network.
+ int Verify(const std::string& hostname,
+ int flags,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result) const;
+
#if defined(OS_WIN)
bool CheckEV(PCCERT_CHAIN_CONTEXT chain_context,
bool rev_checking_enabled,
diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc
index 7ba1e9d..228679d 100644
--- a/net/base/x509_certificate_unittest.cc
+++ b/net/base/x509_certificate_unittest.cc
@@ -3,21 +3,16 @@
// found in the LICENSE file.
#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
+#include "base/memory/scoped_ptr.h"
#include "base/pickle.h"
#include "base/sha1.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
#include "crypto/rsa_private_key.h"
#include "net/base/asn1_util.h"
-#include "net/base/cert_status_flags.h"
#include "net/base/cert_test_util.h"
-#include "net/base/cert_verify_result.h"
-#include "net/base/crl_set.h"
#include "net/base/net_errors.h"
#include "net/base/test_certificate_data.h"
-#include "net/base/test_root_certs.h"
#include "net/base/x509_certificate.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,12 +20,6 @@
#include <cert.h>
#endif
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#elif defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#endif
-
using base::HexEncode;
using base::Time;
@@ -67,13 +56,6 @@ unsigned char thawte_fingerprint[] = {
0xa1, 0x3a, 0x64, 0x04, 0x27, 0x90, 0x97, 0x37
};
-// A certificate for www.paypal.com with a NULL byte in the common name.
-// From http://www.gossamer-threads.com/lists/fulldisc/full-disclosure/70363
-unsigned char paypal_null_fingerprint[] = {
- 0x4c, 0x88, 0x9e, 0x28, 0xd7, 0x7a, 0x44, 0x1e, 0x13, 0xf2, 0x6a, 0xba,
- 0x1f, 0xe8, 0x1b, 0xd6, 0xab, 0x7b, 0xe8, 0xd7
-};
-
// A certificate for https://www.unosoft.hu/, whose AIA extension contains
// an LDAP URL without a host name.
unsigned char unosoft_hu_fingerprint[] = {
@@ -277,25 +259,6 @@ TEST(X509CertificateTest, WebkitCertParsing) {
EXPECT_FALSE(webkit_cert->VerifyNameMatch("www.foo.webkit.com"));
}
-TEST(X509CertificateTest, WithoutRevocationChecking) {
- // Check that verification without revocation checking works.
- CertificateList certs = CreateCertificateListFromFile(
- GetTestCertsDirectory(),
- "googlenew.chain.pem",
- X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(certs[1]->os_cert_handle());
-
- scoped_refptr<X509Certificate> google_full_chain =
- X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
- intermediates);
-
- CertVerifyResult verify_result;
- EXPECT_EQ(OK, google_full_chain->Verify("www.google.com", 0 /* flags */, NULL,
- &verify_result));
-}
-
TEST(X509CertificateTest, ThawteCertParsing) {
scoped_refptr<X509Certificate> thawte_cert(X509Certificate::CreateFromBytes(
reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der)));
@@ -343,37 +306,6 @@ TEST(X509CertificateTest, ThawteCertParsing) {
EXPECT_EQ("www.thawte.com", dns_names[0]);
}
-#if defined(OS_ANDROID) || defined(USE_OPENSSL)
-// TODO(jnd): http://crbug.com/117478 - EV verification is not yet supported.
-#define MAYBE_EVVerification DISABLED_EVVerification
-#else
-#define MAYBE_EVVerification EVVerification
-#endif
-TEST(X509CertificateTest, MAYBE_EVVerification) {
- // This certificate will expire Jun 21, 2013.
- CertificateList certs = CreateCertificateListFromFile(
- GetTestCertsDirectory(),
- "comodo.chain.pem",
- X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
- ASSERT_EQ(3U, certs.size());
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(certs[1]->os_cert_handle());
- intermediates.push_back(certs[2]->os_cert_handle());
-
- scoped_refptr<X509Certificate> comodo_chain =
- X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
- intermediates);
-
- scoped_refptr<CRLSet> crl_set(CRLSet::EmptyCRLSetForTesting());
- CertVerifyResult verify_result;
- int flags = X509Certificate::VERIFY_EV_CERT;
- int error = comodo_chain->Verify(
- "comodo.com", flags, crl_set.get(), &verify_result);
- EXPECT_EQ(OK, error);
- EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV);
-}
-
// Test that all desired AttributeAndValue pairs can be extracted when only
// a single RelativeDistinguishedName is present. "Normally" there is only
// one AVA per RDN, but some CAs place all AVAs within a single RDN.
@@ -424,39 +356,6 @@ TEST(X509CertificateTest, UnescapedSpecialCharacters) {
EXPECT_EQ(0U, subject.domain_components.size());
}
-TEST(X509CertificateTest, PaypalNullCertParsing) {
- scoped_refptr<X509Certificate> paypal_null_cert(
- X509Certificate::CreateFromBytes(
- reinterpret_cast<const char*>(paypal_null_der),
- sizeof(paypal_null_der)));
-
- ASSERT_NE(static_cast<X509Certificate*>(NULL), paypal_null_cert);
-
- const SHA1Fingerprint& fingerprint =
- paypal_null_cert->fingerprint();
- for (size_t i = 0; i < 20; ++i)
- EXPECT_EQ(paypal_null_fingerprint[i], fingerprint.data[i]);
-
- int flags = 0;
- CertVerifyResult verify_result;
- int error = paypal_null_cert->Verify("www.paypal.com", flags, NULL,
- &verify_result);
-#if defined(USE_OPENSSL) || defined(OS_MACOSX) || defined(OS_WIN)
- // TOOD(bulach): investigate why macosx and win aren't returning
- // ERR_CERT_INVALID or ERR_CERT_COMMON_NAME_INVALID.
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
-#else
- EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
-#endif
- // Either the system crypto library should correctly report a certificate
- // name mismatch, or our certificate blacklist should cause us to report an
- // invalid certificate.
-#if !defined(OS_MACOSX) && !defined(USE_OPENSSL)
- EXPECT_TRUE(verify_result.cert_status &
- (CERT_STATUS_COMMON_NAME_INVALID | CERT_STATUS_INVALID));
-#endif
-}
-
TEST(X509CertificateTest, SerialNumbers) {
scoped_refptr<X509Certificate> google_cert(
X509Certificate::CreateFromBytes(
@@ -539,233 +438,6 @@ TEST(X509CertificateTest, CAFingerprints) {
cert_chain3_ca_fingerprint, 20) == 0);
}
-// A regression test for http://crbug.com/31497.
-// This certificate will expire on 2012-04-08. The test will still
-// pass if error == ERR_CERT_DATE_INVALID. TODO(wtc): generate test
-// certificates for this unit test. http://crbug.com/111742
-TEST(X509CertificateTest, IntermediateCARequireExplicitPolicy) {
- FilePath certs_dir = GetTestCertsDirectory();
-
- scoped_refptr<X509Certificate> server_cert =
- ImportCertFromFile(certs_dir, "www_us_army_mil_cert.der");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
-
- // The intermediate CA certificate's policyConstraints extension has a
- // requireExplicitPolicy field with SkipCerts=0.
- scoped_refptr<X509Certificate> intermediate_cert =
- ImportCertFromFile(certs_dir, "dod_ca_17_cert.der");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
-
- scoped_refptr<X509Certificate> root_cert =
- ImportCertFromFile(certs_dir, "dod_root_ca_2_cert.der");
- ScopedTestRoot scoped_root(root_cert);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(intermediate_cert->os_cert_handle());
- scoped_refptr<X509Certificate> cert_chain =
- X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
- intermediates);
-
- int flags = 0;
- CertVerifyResult verify_result;
- int error = cert_chain->Verify("www.us.army.mil", flags, NULL,
- &verify_result);
- if (error == OK) {
- EXPECT_EQ(0U, verify_result.cert_status);
- } else {
- EXPECT_EQ(ERR_CERT_DATE_INVALID, error);
- EXPECT_EQ(CERT_STATUS_DATE_INVALID, verify_result.cert_status);
- }
-}
-
-// Test for bug 58437.
-// This certificate will expire on 2011-12-21. The test will still
-// pass if error == ERR_CERT_DATE_INVALID.
-// This test is DISABLED because it appears that we cannot do
-// certificate revocation checking when running all of the net unit tests.
-// This test passes when run individually, but when run with all of the net
-// unit tests, the call to PKIXVerifyCert returns the NSS error -8180, which is
-// SEC_ERROR_REVOKED_CERTIFICATE. This indicates a lack of revocation
-// status, i.e. that the revocation check is failing for some reason.
-TEST(X509CertificateTest, DISABLED_GlobalSignR3EVTest) {
- FilePath certs_dir = GetTestCertsDirectory();
-
- scoped_refptr<X509Certificate> server_cert =
- ImportCertFromFile(certs_dir, "2029_globalsign_com_cert.pem");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
-
- scoped_refptr<X509Certificate> intermediate_cert =
- ImportCertFromFile(certs_dir, "globalsign_ev_sha256_ca_cert.pem");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(intermediate_cert->os_cert_handle());
- scoped_refptr<X509Certificate> cert_chain =
- X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
- intermediates);
-
- CertVerifyResult verify_result;
- int flags = X509Certificate::VERIFY_REV_CHECKING_ENABLED |
- X509Certificate::VERIFY_EV_CERT;
- int error = cert_chain->Verify("2029.globalsign.com", flags, NULL,
- &verify_result);
- if (error == OK)
- EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV);
- else
- EXPECT_EQ(ERR_CERT_DATE_INVALID, error);
-}
-
-// Currently, only RSA and DSA keys are checked for weakness, and our example
-// weak size is 768. These could change in the future.
-//
-// Note that this means there may be false negatives: keys for other
-// algorithms and which are weak will pass this test.
-static bool IsWeakKeyType(const std::string& key_type) {
- size_t pos = key_type.find("-");
- std::string size = key_type.substr(0, pos);
- std::string type = key_type.substr(pos + 1);
-
- if (type == "rsa" || type == "dsa")
- return size == "768";
-
- return false;
-}
-
-TEST(X509CertificateTest, RejectWeakKeys) {
- FilePath certs_dir = GetTestCertsDirectory();
- typedef std::vector<std::string> Strings;
- Strings key_types;
-
- // generate-weak-test-chains.sh currently has:
- // key_types="768-rsa 1024-rsa 2048-rsa prime256v1-ecdsa"
- // We must use the same key types here. The filenames generated look like:
- // 2048-rsa-ee-by-768-rsa-intermediate.pem
- key_types.push_back("768-rsa");
- key_types.push_back("1024-rsa");
- key_types.push_back("2048-rsa");
-
- bool use_ecdsa = true;
-#if defined(OS_WIN)
- use_ecdsa = base::win::GetVersion() > base::win::VERSION_XP;
-#elif defined(OS_MACOSX)
- use_ecdsa = base::mac::IsOSSnowLeopardOrLater();
-#endif
-
- if (use_ecdsa)
- key_types.push_back("prime256v1-ecdsa");
-
- // Add the root that signed the intermediates for this test.
- scoped_refptr<X509Certificate> root_cert =
- ImportCertFromFile(certs_dir, "2048-rsa-root.pem");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
- ScopedTestRoot scoped_root(root_cert);
-
- // Now test each chain.
- for (Strings::const_iterator ee_type = key_types.begin();
- ee_type != key_types.end(); ++ee_type) {
- for (Strings::const_iterator signer_type = key_types.begin();
- signer_type != key_types.end(); ++signer_type) {
- std::string basename = *ee_type + "-ee-by-" + *signer_type +
- "-intermediate.pem";
- SCOPED_TRACE(basename);
- scoped_refptr<X509Certificate> ee_cert =
- ImportCertFromFile(certs_dir, basename);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert);
-
- basename = *signer_type + "-intermediate.pem";
- scoped_refptr<X509Certificate> intermediate =
- ImportCertFromFile(certs_dir, basename);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(intermediate->os_cert_handle());
- scoped_refptr<X509Certificate> cert_chain =
- X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(),
- intermediates);
-
- CertVerifyResult verify_result;
- int error = cert_chain->Verify("127.0.0.1", 0, NULL, &verify_result);
-
- if (IsWeakKeyType(*ee_type) || IsWeakKeyType(*signer_type)) {
- EXPECT_NE(OK, error);
- EXPECT_EQ(CERT_STATUS_WEAK_KEY,
- verify_result.cert_status & CERT_STATUS_WEAK_KEY);
- } else {
- EXPECT_EQ(OK, error);
- EXPECT_EQ(0U, verify_result.cert_status & CERT_STATUS_WEAK_KEY);
- }
- }
- }
-}
-
-// Test for bug 108514.
-// The certificate will expire on 2012-07-20. The test will still
-// pass if error == ERR_CERT_DATE_INVALID. TODO(rsleevi): generate test
-// certificates for this unit test. http://crbug.com/111730
-TEST(X509CertificateTest, ExtraneousMD5RootCert) {
- FilePath certs_dir = GetTestCertsDirectory();
-
- scoped_refptr<X509Certificate> server_cert =
- ImportCertFromFile(certs_dir, "images_etrade_wallst_com.pem");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
-
- scoped_refptr<X509Certificate> intermediate_cert =
- ImportCertFromFile(certs_dir, "globalsign_orgv1_ca.pem");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
-
- scoped_refptr<X509Certificate> md5_root_cert =
- ImportCertFromFile(certs_dir, "globalsign_root_ca_md5.pem");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), md5_root_cert);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(intermediate_cert->os_cert_handle());
- intermediates.push_back(md5_root_cert->os_cert_handle());
- scoped_refptr<X509Certificate> cert_chain =
- X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
- intermediates);
-
- CertVerifyResult verify_result;
- int flags = 0;
- int error = cert_chain->Verify("images.etrade.wallst.com", flags, NULL,
- &verify_result);
- if (error != OK)
- EXPECT_EQ(ERR_CERT_DATE_INVALID, error);
-
- EXPECT_FALSE(verify_result.has_md5);
- EXPECT_FALSE(verify_result.has_md5_ca);
-}
-
-// Test for bug 94673.
-TEST(X509CertificateTest, GoogleDigiNotarTest) {
- FilePath certs_dir = GetTestCertsDirectory();
-
- scoped_refptr<X509Certificate> server_cert =
- ImportCertFromFile(certs_dir, "google_diginotar.pem");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
-
- scoped_refptr<X509Certificate> intermediate_cert =
- ImportCertFromFile(certs_dir, "diginotar_public_ca_2025.pem");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(intermediate_cert->os_cert_handle());
- scoped_refptr<X509Certificate> cert_chain =
- X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
- intermediates);
-
- CertVerifyResult verify_result;
- int flags = X509Certificate::VERIFY_REV_CHECKING_ENABLED;
- int error = cert_chain->Verify("mail.google.com", flags, NULL,
- &verify_result);
- EXPECT_NE(OK, error);
-
- // Now turn off revocation checking. Certificate verification should still
- // fail.
- flags = 0;
- error = cert_chain->Verify("mail.google.com", flags, NULL, &verify_result);
- EXPECT_NE(OK, error);
-}
-
TEST(X509CertificateTest, DigiNotarCerts) {
static const char* const kDigiNotarFilenames[] = {
"diginotar_root_ca.pem",
@@ -801,40 +473,6 @@ TEST(X509CertificateTest, DigiNotarCerts) {
}
}
-// Bug 111893: This test needs a new certificate.
-TEST(X509CertificateTest, DISABLED_TestKnownRoot) {
- FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> cert =
- ImportCertFromFile(certs_dir, "nist.der");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), cert);
-
- // This intermediate is only needed for old Linux machines. Modern NSS
- // includes it as a root already.
- scoped_refptr<X509Certificate> intermediate_cert =
- ImportCertFromFile(certs_dir, "nist_intermediate.der");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(intermediate_cert->os_cert_handle());
- scoped_refptr<X509Certificate> cert_chain =
- X509Certificate::CreateFromHandle(cert->os_cert_handle(),
- intermediates);
-
- int flags = 0;
- CertVerifyResult verify_result;
- // This is going to blow up in Feb 2012. Sorry! Disable and file a bug
- // against agl. Also see PublicKeyHashes in this file.
- int error = cert_chain->Verify("www.nist.gov", flags, NULL, &verify_result);
- EXPECT_EQ(OK, error);
- EXPECT_EQ(0U, verify_result.cert_status);
- EXPECT_TRUE(verify_result.is_issued_by_known_root);
-}
-
-// This is the SHA1 hash of the SubjectPublicKeyInfo of nist.der.
-static const char nistSPKIHash[] =
- "\x15\x60\xde\x65\x4e\x03\x9f\xd0\x08\x82"
- "\xa9\x6a\xc4\x65\x8e\x6f\x92\x06\x84\x35";
-
TEST(X509CertificateTest, ExtractSPKIFromDERCert) {
FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> cert =
@@ -875,73 +513,6 @@ TEST(X509CertificateTest, ExtractCRLURLsFromDERCert) {
}
}
-// Bug 111893: This test needs a new certificate.
-TEST(X509CertificateTest, DISABLED_PublicKeyHashes) {
- FilePath certs_dir = GetTestCertsDirectory();
- // This is going to blow up in Feb 2012. Sorry! Disable and file a bug
- // against agl. Also see TestKnownRoot in this file.
- scoped_refptr<X509Certificate> cert =
- ImportCertFromFile(certs_dir, "nist.der");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), cert);
-
- // This intermediate is only needed for old Linux machines. Modern NSS
- // includes it as a root already.
- scoped_refptr<X509Certificate> intermediate_cert =
- ImportCertFromFile(certs_dir, "nist_intermediate.der");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
-
- ScopedTestRoot scoped_intermediate(intermediate_cert);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(intermediate_cert->os_cert_handle());
- scoped_refptr<X509Certificate> cert_chain =
- X509Certificate::CreateFromHandle(cert->os_cert_handle(),
- intermediates);
-
- int flags = 0;
- CertVerifyResult verify_result;
-
- int error = cert_chain->Verify("www.nist.gov", flags, NULL, &verify_result);
- EXPECT_EQ(OK, error);
- EXPECT_EQ(0U, verify_result.cert_status);
- ASSERT_LE(2u, verify_result.public_key_hashes.size());
- EXPECT_EQ(HexEncode(nistSPKIHash, base::kSHA1Length),
- HexEncode(verify_result.public_key_hashes[0].data, base::kSHA1Length));
- EXPECT_EQ("83244223D6CBF0A26FC7DE27CEBCA4BDA32612AD",
- HexEncode(verify_result.public_key_hashes[1].data, base::kSHA1Length));
-}
-
-// A regression test for http://crbug.com/70293.
-// The Key Usage extension in this RSA SSL server certificate does not have
-// the keyEncipherment bit.
-TEST(X509CertificateTest, InvalidKeyUsage) {
- FilePath certs_dir = GetTestCertsDirectory();
-
- scoped_refptr<X509Certificate> server_cert =
- ImportCertFromFile(certs_dir, "invalid_key_usage_cert.der");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
-
- int flags = 0;
- CertVerifyResult verify_result;
- int error = server_cert->Verify("jira.aquameta.com", flags, NULL,
- &verify_result);
-#if defined(USE_OPENSSL)
- // This certificate has two errors: "invalid key usage" and "untrusted CA".
- // However, OpenSSL returns only one (the latter), and we can't detect
- // the other errors.
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
-#else
- EXPECT_EQ(ERR_CERT_INVALID, error);
- EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID);
-#endif
- // TODO(wtc): fix http://crbug.com/75520 to get all the certificate errors
- // from NSS.
-#if !defined(USE_NSS)
- // The certificate is issued by an unknown CA.
- EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_AUTHORITY_INVALID);
-#endif
-}
-
// Tests X509CertificateCache via X509Certificate::CreateFromHandle. We
// call X509Certificate::CreateFromHandle several times and observe whether
// it returns a cached or new OSCertHandle.
@@ -1104,143 +675,6 @@ TEST(X509CertificateTest, IntermediateCertificates) {
X509Certificate::FreeOSCertHandle(google_handle);
}
-// Basic test for returning the chain in CertVerifyResult. Note that the
-// returned chain may just be a reflection of the originally supplied chain;
-// that is, if any errors occur, the default chain returned is an exact copy
-// of the certificate to be verified. The remaining VerifyReturn* tests are
-// used to ensure that the actual, verified chain is being returned by
-// Verify().
-TEST(X509CertificateTest, VerifyReturnChainBasic) {
- FilePath certs_dir = GetTestCertsDirectory();
- CertificateList certs = CreateCertificateListFromFile(
- certs_dir, "x509_verify_results.chain.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(3U, certs.size());
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(certs[1]->os_cert_handle());
- intermediates.push_back(certs[2]->os_cert_handle());
-
- ScopedTestRoot scoped_root(certs[2]);
-
- scoped_refptr<X509Certificate> google_full_chain =
- X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
- intermediates);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain);
- ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size());
-
- CertVerifyResult verify_result;
- EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
- int error = google_full_chain->Verify("127.0.0.1", 0, NULL, &verify_result);
- EXPECT_EQ(OK, error);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
-
- EXPECT_NE(google_full_chain, verify_result.verified_cert);
- EXPECT_TRUE(X509Certificate::IsSameOSCert(
- google_full_chain->os_cert_handle(),
- verify_result.verified_cert->os_cert_handle()));
- const X509Certificate::OSCertHandles& return_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(2U, return_intermediates.size());
- EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
- certs[1]->os_cert_handle()));
- EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
- certs[2]->os_cert_handle()));
-}
-
-// Test that the certificate returned in CertVerifyResult is able to reorder
-// certificates that are not ordered from end-entity to root. While this is
-// a protocol violation if sent during a TLS handshake, if multiple sources
-// of intermediate certificates are combined, it's possible that order may
-// not be maintained.
-TEST(X509CertificateTest, VerifyReturnChainProperlyOrdered) {
- FilePath certs_dir = GetTestCertsDirectory();
- CertificateList certs = CreateCertificateListFromFile(
- certs_dir, "x509_verify_results.chain.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(3U, certs.size());
-
- // Construct the chain out of order.
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(certs[2]->os_cert_handle());
- intermediates.push_back(certs[1]->os_cert_handle());
-
- ScopedTestRoot scoped_root(certs[2]);
-
- scoped_refptr<X509Certificate> google_full_chain =
- X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
- intermediates);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain);
- ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size());
-
- CertVerifyResult verify_result;
- EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
- int error = google_full_chain->Verify("127.0.0.1", 0, NULL, &verify_result);
- EXPECT_EQ(OK, error);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
-
- EXPECT_NE(google_full_chain, verify_result.verified_cert);
- EXPECT_TRUE(X509Certificate::IsSameOSCert(
- google_full_chain->os_cert_handle(),
- verify_result.verified_cert->os_cert_handle()));
- const X509Certificate::OSCertHandles& return_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(2U, return_intermediates.size());
- EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
- certs[1]->os_cert_handle()));
- EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
- certs[2]->os_cert_handle()));
-}
-
-// Test that Verify() filters out certificates which are not related to
-// or part of the certificate chain being verified.
-TEST(X509CertificateTest, VerifyReturnChainFiltersUnrelatedCerts) {
- FilePath certs_dir = GetTestCertsDirectory();
- CertificateList certs = CreateCertificateListFromFile(
- certs_dir, "x509_verify_results.chain.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(3U, certs.size());
- ScopedTestRoot scoped_root(certs[2]);
-
- scoped_refptr<X509Certificate> unrelated_dod_certificate =
- ImportCertFromFile(certs_dir, "dod_ca_17_cert.der");
- scoped_refptr<X509Certificate> unrelated_dod_certificate2 =
- ImportCertFromFile(certs_dir, "dod_root_ca_2_cert.der");
- ASSERT_NE(static_cast<X509Certificate*>(NULL), unrelated_dod_certificate);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), unrelated_dod_certificate2);
-
- // Interject unrelated certificates into the list of intermediates.
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(unrelated_dod_certificate->os_cert_handle());
- intermediates.push_back(certs[1]->os_cert_handle());
- intermediates.push_back(unrelated_dod_certificate2->os_cert_handle());
- intermediates.push_back(certs[2]->os_cert_handle());
-
- scoped_refptr<X509Certificate> google_full_chain =
- X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
- intermediates);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain);
- ASSERT_EQ(4U, google_full_chain->GetIntermediateCertificates().size());
-
- CertVerifyResult verify_result;
- EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
- int error = google_full_chain->Verify("127.0.0.1", 0, NULL, &verify_result);
- EXPECT_EQ(OK, error);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert);
-
- EXPECT_NE(google_full_chain, verify_result.verified_cert);
- EXPECT_TRUE(X509Certificate::IsSameOSCert(
- google_full_chain->os_cert_handle(),
- verify_result.verified_cert->os_cert_handle()));
- const X509Certificate::OSCertHandles& return_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(2U, return_intermediates.size());
- EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
- certs[1]->os_cert_handle()));
- EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
- certs[2]->os_cert_handle()));
-}
-
#if defined(OS_MACOSX)
TEST(X509CertificateTest, IsIssuedBy) {
FilePath certs_dir = GetTestCertsDirectory();
@@ -1412,110 +846,6 @@ TEST(X509CertificateTest, GetDEREncoded) {
}
#endif
-#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
-static const uint8 kCRLSetThawteSPKIBlocked[] = {
- 0x8e, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
- 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
- 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
- 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
- 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
- 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
- 0x30, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
- 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x36, 0x58, 0x36, 0x4d, 0x78, 0x52, 0x37,
- 0x58, 0x70, 0x4d, 0x51, 0x4b, 0x78, 0x49, 0x41, 0x39, 0x50, 0x6a, 0x36, 0x37,
- 0x36, 0x38, 0x76, 0x74, 0x55, 0x6b, 0x6b, 0x7a, 0x48, 0x79, 0x7a, 0x41, 0x6f,
- 0x6d, 0x6f, 0x4f, 0x68, 0x4b, 0x55, 0x6e, 0x7a, 0x73, 0x55, 0x3d, 0x22, 0x5d,
- 0x7d,
-};
-
-static const uint8 kCRLSetThawteSerialBlocked[] = {
- 0x60, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
- 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
- 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
- 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
- 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
- 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
- 0x31, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
- 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0xb1, 0x12, 0x41, 0x42, 0xa5, 0xa1,
- 0xa5, 0xa2, 0x88, 0x19, 0xc7, 0x35, 0x34, 0x0e, 0xff, 0x8c, 0x9e, 0x2f, 0x81,
- 0x68, 0xfe, 0xe3, 0xba, 0x18, 0x7f, 0x25, 0x3b, 0xc1, 0xa3, 0x92, 0xd7, 0xe2,
- // Note that this is actually blocking two serial numbers because on XP and
- // Vista, CryptoAPI finds a different Thawte certificate.
- 0x02, 0x00, 0x00, 0x00,
- 0x04, 0x30, 0x00, 0x00, 0x02,
- 0x04, 0x30, 0x00, 0x00, 0x06,
-};
-
-static const uint8 kCRLSetGoogleSerialBlocked[] = {
- 0x60, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
- 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
- 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
- 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
- 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
- 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
- 0x31, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
- 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0xe9, 0x7e, 0x8c, 0xc5, 0x1e, 0xd7,
- 0xa4, 0xc4, 0x0a, 0xc4, 0x80, 0x3d, 0x3e, 0x3e, 0xbb, 0xeb, 0xcb, 0xed, 0x52,
- 0x49, 0x33, 0x1f, 0x2c, 0xc0, 0xa2, 0x6a, 0x0e, 0x84, 0xa5, 0x27, 0xce, 0xc5,
- 0x01, 0x00, 0x00, 0x00, 0x10, 0x4f, 0x9d, 0x96, 0xd9, 0x66, 0xb0, 0x99, 0x2b,
- 0x54, 0xc2, 0x95, 0x7c, 0xb4, 0x15, 0x7d, 0x4d,
-};
-
-// Test that CRLSets are effective in making a certificate appear to be
-// revoked.
-TEST(X509CertificateTest, CRLSet) {
- CertificateList certs = CreateCertificateListFromFile(
- GetTestCertsDirectory(),
- "googlenew.chain.pem",
- X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(certs[1]->os_cert_handle());
-
- scoped_refptr<X509Certificate> google_full_chain =
- X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
- intermediates);
-
- CertVerifyResult verify_result;
- int error = google_full_chain->Verify(
- "www.google.com", 0, NULL, &verify_result);
- EXPECT_EQ(OK, error);
-
- // First test blocking by SPKI.
- base::StringPiece crl_set_bytes(
- reinterpret_cast<const char*>(kCRLSetThawteSPKIBlocked),
- sizeof(kCRLSetThawteSPKIBlocked));
- scoped_refptr<CRLSet> crl_set;
- ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
-
- error = google_full_chain->Verify(
- "www.google.com", 0, crl_set.get(), &verify_result);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
-
- // Second, test revocation by serial number of a cert directly under the
- // root.
- crl_set_bytes = base::StringPiece(
- reinterpret_cast<const char*>(kCRLSetThawteSerialBlocked),
- sizeof(kCRLSetThawteSerialBlocked));
- ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
-
- error = google_full_chain->Verify(
- "www.google.com", 0, crl_set.get(), &verify_result);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
-
- // Lastly, test revocation by serial number of a certificate not under the
- // root.
- crl_set_bytes = base::StringPiece(
- reinterpret_cast<const char*>(kCRLSetGoogleSerialBlocked),
- sizeof(kCRLSetGoogleSerialBlocked));
- ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
-
- error = google_full_chain->Verify(
- "www.google.com", 0, crl_set.get(), &verify_result);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
-}
-#endif
-
class X509CertificateParseTest
: public testing::TestWithParam<CertificateFormatTestData> {
public:
@@ -1776,235 +1106,4 @@ TEST_P(X509CertificateNameVerifyTest, VerifyHostname) {
INSTANTIATE_TEST_CASE_P(, X509CertificateNameVerifyTest,
testing::ValuesIn(kNameVerifyTestData));
-struct WeakDigestTestData {
- const char* root_cert_filename;
- const char* intermediate_cert_filename;
- const char* ee_cert_filename;
- bool expected_has_md5;
- bool expected_has_md4;
- bool expected_has_md2;
- bool expected_has_md5_ca;
- bool expected_has_md2_ca;
-};
-
-// GTest 'magic' pretty-printer, so that if/when a test fails, it knows how
-// to output the parameter that was passed. Without this, it will simply
-// attempt to print out the first twenty bytes of the object, which depending
-// on platform and alignment, may result in an invalid read.
-void PrintTo(const WeakDigestTestData& data, std::ostream* os) {
- *os << "root: "
- << (data.root_cert_filename ? data.root_cert_filename : "none")
- << "; intermediate: " << data.intermediate_cert_filename
- << "; end-entity: " << data.ee_cert_filename;
-}
-
-class X509CertificateWeakDigestTest
- : public testing::TestWithParam<WeakDigestTestData> {
- public:
- X509CertificateWeakDigestTest() {}
- virtual ~X509CertificateWeakDigestTest() {}
-};
-
-TEST_P(X509CertificateWeakDigestTest, Verify) {
- WeakDigestTestData data = GetParam();
- FilePath certs_dir = GetTestCertsDirectory();
-
- ScopedTestRoot test_root;
- if (data.root_cert_filename) {
- scoped_refptr<X509Certificate> root_cert =
- ImportCertFromFile(certs_dir, data.root_cert_filename);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
- test_root.Reset(root_cert);
- }
-
- scoped_refptr<X509Certificate> intermediate_cert =
- ImportCertFromFile(certs_dir, data.intermediate_cert_filename);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
- scoped_refptr<X509Certificate> ee_cert =
- ImportCertFromFile(certs_dir, data.ee_cert_filename);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert);
-
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(intermediate_cert->os_cert_handle());
-
- scoped_refptr<X509Certificate> ee_chain =
- X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(),
- intermediates);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_chain);
-
- int flags = 0;
- CertVerifyResult verify_result;
- int rv = ee_chain->Verify("127.0.0.1", flags, NULL, &verify_result);
- EXPECT_EQ(data.expected_has_md5, verify_result.has_md5);
- EXPECT_EQ(data.expected_has_md4, verify_result.has_md4);
- EXPECT_EQ(data.expected_has_md2, verify_result.has_md2);
- EXPECT_EQ(data.expected_has_md5_ca, verify_result.has_md5_ca);
- EXPECT_EQ(data.expected_has_md2_ca, verify_result.has_md2_ca);
-
- // Ensure that MD4 and MD2 are tagged as invalid.
- if (data.expected_has_md4 || data.expected_has_md2) {
- EXPECT_EQ(CERT_STATUS_INVALID,
- verify_result.cert_status & CERT_STATUS_INVALID);
- }
-
- // Ensure that MD5 is flagged as weak.
- if (data.expected_has_md5) {
- EXPECT_EQ(
- CERT_STATUS_WEAK_SIGNATURE_ALGORITHM,
- verify_result.cert_status & CERT_STATUS_WEAK_SIGNATURE_ALGORITHM);
- }
-
- // If a root cert is present, then check that the chain was rejected if any
- // weak algorithms are present. This is only checked when a root cert is
- // present because the error reported for incomplete chains with weak
- // algorithms depends on which implementation was used to validate (NSS,
- // OpenSSL, CryptoAPI, Security.framework) and upon which weak algorithm
- // present (MD2, MD4, MD5).
- if (data.root_cert_filename) {
- if (data.expected_has_md4 || data.expected_has_md2) {
- EXPECT_EQ(ERR_CERT_INVALID, rv);
- } else if (data.expected_has_md5) {
- EXPECT_EQ(ERR_CERT_WEAK_SIGNATURE_ALGORITHM, rv);
- } else {
- EXPECT_EQ(OK, rv);
- }
- }
-}
-
-// Unlike TEST/TEST_F, which are macros that expand to further macros,
-// INSTANTIATE_TEST_CASE_P is a macro that expands directly to code that
-// stringizes the arguments. As a result, macros passed as parameters (such as
-// prefix or test_case_name) will not be expanded by the preprocessor. To work
-// around this, indirect the macro for INSTANTIATE_TEST_CASE_P, so that the
-// pre-processor will expand macros such as MAYBE_test_name before
-// instantiating the test.
-#define WRAPPED_INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
- INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator)
-
-// The signature algorithm of the root CA should not matter.
-const WeakDigestTestData kVerifyRootCATestData[] = {
- { "weak_digest_md5_root.pem", "weak_digest_sha1_intermediate.pem",
- "weak_digest_sha1_ee.pem", false, false, false, false, false },
-#if !defined(OS_MACOSX) // MD4 is not supported.
- { "weak_digest_md4_root.pem", "weak_digest_sha1_intermediate.pem",
- "weak_digest_sha1_ee.pem", false, false, false, false, false },
-#endif
- { "weak_digest_md2_root.pem", "weak_digest_sha1_intermediate.pem",
- "weak_digest_sha1_ee.pem", false, false, false, false, false },
-};
-INSTANTIATE_TEST_CASE_P(VerifyRoot, X509CertificateWeakDigestTest,
- testing::ValuesIn(kVerifyRootCATestData));
-
-// The signature algorithm of intermediates should be properly detected.
-const WeakDigestTestData kVerifyIntermediateCATestData[] = {
- { "weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem",
- "weak_digest_sha1_ee.pem", true, false, false, true, false },
-#if !defined(USE_NSS) && !defined(OS_MACOSX) // MD4 is not supported.
- { "weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem",
- "weak_digest_sha1_ee.pem", false, true, false, false, false },
-#endif
-#if !defined(USE_NSS) // MD2 is disabled by default.
- { "weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem",
- "weak_digest_sha1_ee.pem", false, false, true, false, true },
-#endif
-};
-INSTANTIATE_TEST_CASE_P(VerifyIntermediate, X509CertificateWeakDigestTest,
- testing::ValuesIn(kVerifyIntermediateCATestData));
-
-// The signature algorithm of end-entity should be properly detected.
-const WeakDigestTestData kVerifyEndEntityTestData[] = {
- { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem",
- "weak_digest_md5_ee.pem", true, false, false, false, false },
-#if !defined(USE_NSS) && !defined(OS_MACOSX) // MD4 is not supported.
- { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem",
- "weak_digest_md4_ee.pem", false, true, false, false, false },
-#endif
-#if !defined(USE_NSS) // MD2 is disabled by default.
- { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem",
- "weak_digest_md2_ee.pem", false, false, true, false, false },
-#endif
-};
-// Disabled on NSS - NSS caches chains/signatures in such a way that cannot
-// be cleared until NSS is cleanly shutdown, which is not presently supported
-// in Chromium.
-#if defined(USE_NSS)
-#define MAYBE_VerifyEndEntity DISABLED_VerifyEndEntity
-#else
-#define MAYBE_VerifyEndEntity VerifyEndEntity
-#endif
-WRAPPED_INSTANTIATE_TEST_CASE_P(MAYBE_VerifyEndEntity,
- X509CertificateWeakDigestTest,
- testing::ValuesIn(kVerifyEndEntityTestData));
-
-// Incomplete chains should still report the status of the intermediate.
-const WeakDigestTestData kVerifyIncompleteIntermediateTestData[] = {
- { NULL, "weak_digest_md5_intermediate.pem", "weak_digest_sha1_ee.pem",
- true, false, false, true, false },
-#if !defined(OS_MACOSX) // MD4 is not supported.
- { NULL, "weak_digest_md4_intermediate.pem", "weak_digest_sha1_ee.pem",
- false, true, false, false, false },
-#endif
- { NULL, "weak_digest_md2_intermediate.pem", "weak_digest_sha1_ee.pem",
- false, false, true, false, true },
-};
-// Disabled on NSS - libpkix does not return constructed chains on error,
-// preventing us from detecting/inspecting the verified chain.
-#if defined(USE_NSS)
-#define MAYBE_VerifyIncompleteIntermediate \
- DISABLED_VerifyIncompleteIntermediate
-#else
-#define MAYBE_VerifyIncompleteIntermediate VerifyIncompleteIntermediate
-#endif
-WRAPPED_INSTANTIATE_TEST_CASE_P(
- MAYBE_VerifyIncompleteIntermediate,
- X509CertificateWeakDigestTest,
- testing::ValuesIn(kVerifyIncompleteIntermediateTestData));
-
-// Incomplete chains should still report the status of the end-entity.
-const WeakDigestTestData kVerifyIncompleteEETestData[] = {
- { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md5_ee.pem",
- true, false, false, false, false },
-#if !defined(OS_MACOSX) // MD4 is not supported.
- { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md4_ee.pem",
- false, true, false, false, false },
-#endif
- { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md2_ee.pem",
- false, false, true, false, false },
-};
-// Disabled on NSS - libpkix does not return constructed chains on error,
-// preventing us from detecting/inspecting the verified chain.
-#if defined(USE_NSS)
-#define MAYBE_VerifyIncompleteEndEntity DISABLED_VerifyIncompleteEndEntity
-#else
-#define MAYBE_VerifyIncompleteEndEntity VerifyIncompleteEndEntity
-#endif
-WRAPPED_INSTANTIATE_TEST_CASE_P(
- MAYBE_VerifyIncompleteEndEntity,
- X509CertificateWeakDigestTest,
- testing::ValuesIn(kVerifyIncompleteEETestData));
-
-// Differing algorithms between the intermediate and the EE should still be
-// reported.
-const WeakDigestTestData kVerifyMixedTestData[] = {
- { "weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem",
- "weak_digest_md2_ee.pem", true, false, true, true, false },
- { "weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem",
- "weak_digest_md5_ee.pem", true, false, true, false, true },
-#if !defined(OS_MACOSX) // MD4 is not supported.
- { "weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem",
- "weak_digest_md2_ee.pem", false, true, true, false, false },
-#endif
-};
-// NSS does not support MD4 and does not enable MD2 by default, making all
-// permutations invalid.
-#if defined(USE_NSS)
-#define MAYBE_VerifyMixed DISABLED_VerifyMixed
-#else
-#define MAYBE_VerifyMixed VerifyMixed
-#endif
-WRAPPED_INSTANTIATE_TEST_CASE_P(
- MAYBE_VerifyMixed,
- X509CertificateWeakDigestTest,
- testing::ValuesIn(kVerifyMixedTestData));
-
} // namespace net
diff --git a/net/net.gyp b/net/net.gyp
index 5c70b88a..d6229a35 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -70,6 +70,8 @@
'base/cert_status_flags.h',
'base/cert_verifier.cc',
'base/cert_verifier.h',
+ 'base/cert_verify_proc.cc',
+ 'base/cert_verify_proc.h',
'base/cert_verify_result.cc',
'base/cert_verify_result.h',
'base/completion_callback.h',