Index: chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc |
diff --git a/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc b/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0c485a51f9b2299f5ec1840ac10f95d7c54405ce |
--- /dev/null |
+++ b/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc |
@@ -0,0 +1,373 @@ |
+// Copyright 2014 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 "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h" |
+ |
+#include "crypto/nss_util.h" |
+#include "crypto/nss_util_internal.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/test_data_directory.h" |
+#include "net/cert/cert_verify_proc.h" |
+#include "net/cert/cert_verify_result.h" |
+#include "net/cert/nss_cert_database_chromeos.h" |
+#include "net/test/cert_test_util.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace chromeos { |
+ |
+class CertVerifyProcChromeOSTest : public testing::Test { |
+ public: |
+ CertVerifyProcChromeOSTest() : user_1_("user1"), user_2_("user2") {} |
+ |
+ virtual void SetUp() OVERRIDE { |
+ // Initialize nss_util slots. |
+ ASSERT_TRUE(user_1_.constructed_successfully()); |
+ ASSERT_TRUE(user_2_.constructed_successfully()); |
+ user_1_.FinishInit(); |
+ user_2_.FinishInit(); |
+ |
+ // Create NSSCertDatabaseChromeOS for each user. |
+ db_1_.reset(new net::NSSCertDatabaseChromeOS( |
+ crypto::GetPublicSlotForChromeOSUser(user_1_.username_hash()), |
+ crypto::GetPrivateSlotForChromeOSUser( |
+ user_1_.username_hash(), |
+ base::Callback<void(crypto::ScopedPK11Slot)>()))); |
+ db_2_.reset(new net::NSSCertDatabaseChromeOS( |
+ crypto::GetPublicSlotForChromeOSUser(user_2_.username_hash()), |
+ crypto::GetPrivateSlotForChromeOSUser( |
+ user_2_.username_hash(), |
+ base::Callback<void(crypto::ScopedPK11Slot)>()))); |
+ |
+ // Create default verifier and for each user. |
+ verify_proc_default_ = new CertVerifyProcChromeOS(); |
+ verify_proc_1_ = new CertVerifyProcChromeOS(db_1_->GetPublicSlot()); |
+ verify_proc_2_ = new CertVerifyProcChromeOS(db_2_->GetPublicSlot()); |
+ |
+ // Load test cert chains from disk. |
+ certs_1_ = |
+ net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), |
+ "multi-root-chain1.pem", |
+ net::X509Certificate::FORMAT_AUTO); |
+ ASSERT_EQ(4U, certs_1_.size()); |
+ |
+ certs_2_ = |
+ net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), |
+ "multi-root-chain2.pem", |
+ net::X509Certificate::FORMAT_AUTO); |
+ ASSERT_EQ(4U, certs_2_.size()); |
+ |
+ // The chains: |
+ // 1. A (end-entity) -> B -> C -> D (self-signed root) |
+ // 2. A (end-entity) -> B -> C2 -> E (self-signed root) |
+ ASSERT_TRUE(certs_1_[0]->Equals(certs_2_[0])); |
+ ASSERT_TRUE(certs_1_[1]->Equals(certs_2_[1])); |
+ ASSERT_FALSE(certs_1_[2]->Equals(certs_2_[2])); |
+ ASSERT_EQ("C CA", certs_1_[2]->subject().common_name); |
+ ASSERT_EQ("C CA", certs_2_[2]->subject().common_name); |
+ |
+ root_1_.push_back(certs_1_.back()); |
+ root_2_.push_back(certs_2_.back()); |
+ |
+ ASSERT_EQ("D Root CA", root_1_[0]->subject().common_name); |
+ ASSERT_EQ("E Root CA", root_2_[0]->subject().common_name); |
+ } |
+ |
+ int VerifyWithAdditionalTrustAnchors( |
+ net::CertVerifyProc* verify_proc, |
+ const net::CertificateList& additional_trust_anchors, |
+ net::X509Certificate* cert, |
+ std::string* root_subject_name) { |
+ int flags = 0; |
+ net::CertVerifyResult verify_result; |
+ int error = verify_proc->Verify(cert, |
+ "127.0.0.1", |
+ flags, |
+ NULL, |
+ additional_trust_anchors, |
+ &verify_result); |
+ if (verify_result.verified_cert.get() && |
+ !verify_result.verified_cert->GetIntermediateCertificates().empty()) { |
+ net::X509Certificate::OSCertHandle root = |
+ verify_result.verified_cert->GetIntermediateCertificates().back(); |
+ root_subject_name->assign(root->subjectName); |
+ } else { |
+ root_subject_name->clear(); |
+ } |
+ return error; |
+ } |
+ |
+ int Verify(net::CertVerifyProc* verify_proc, |
+ net::X509Certificate* cert, |
+ std::string* root_subject_name) { |
+ net::CertificateList additional_trust_anchors; |
+ return VerifyWithAdditionalTrustAnchors( |
+ verify_proc, additional_trust_anchors, cert, root_subject_name); |
+ } |
+ |
+ protected: |
+ crypto::ScopedTestNSSChromeOSUser user_1_; |
+ crypto::ScopedTestNSSChromeOSUser user_2_; |
+ scoped_ptr<net::NSSCertDatabaseChromeOS> db_1_; |
+ scoped_ptr<net::NSSCertDatabaseChromeOS> db_2_; |
+ scoped_refptr<net::CertVerifyProc> verify_proc_default_; |
+ scoped_refptr<net::CertVerifyProc> verify_proc_1_; |
+ scoped_refptr<net::CertVerifyProc> verify_proc_2_; |
+ net::CertificateList certs_1_; |
+ net::CertificateList certs_2_; |
+ net::CertificateList root_1_; |
+ net::CertificateList root_2_; |
+}; |
+ |
+// Test that the CertVerifyProcChromeOS doesn't trusts roots that are in other |
+// user's slots or that have been deleted, and that verifying done by one user |
+// doesn't affect verifications done by others. |
+TEST_F(CertVerifyProcChromeOSTest, TestChainVerify) { |
+ scoped_refptr<net::X509Certificate> server = certs_1_[0]; |
+ std::string verify_root; |
+ // Before either of the root certs have been trusted, all verifications should |
+ // fail with CERT_AUTHORITY_INVALID. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_default_.get(), server.get(), &verify_root)); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_1_.get(), server.get(), &verify_root)); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_2_.get(), server.get(), &verify_root)); |
+ |
+ // Import and trust the D root for user 1. |
+ net::NSSCertDatabase::ImportCertFailureList failed; |
+ EXPECT_TRUE(db_1_->ImportCACerts( |
+ root_1_, net::NSSCertDatabase::TRUSTED_SSL, &failed)); |
+ EXPECT_EQ(0U, failed.size()); |
+ |
+ // Imported CA certs are not trusted by default verifier. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_default_.get(), server.get(), &verify_root)); |
+ // User 1 should now verify successfully through the D root. |
+ EXPECT_EQ(net::OK, Verify(verify_proc_1_.get(), server.get(), &verify_root)); |
+ EXPECT_EQ("CN=D Root CA", verify_root); |
+ // User 2 should still fail. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_2_.get(), server.get(), &verify_root)); |
+ |
+ // Import and trust the E root for user 2. |
+ failed.clear(); |
+ EXPECT_TRUE(db_2_->ImportCACerts( |
+ root_2_, net::NSSCertDatabase::TRUSTED_SSL, &failed)); |
+ EXPECT_EQ(0U, failed.size()); |
+ |
+ // Imported CA certs are not trusted by default verifier. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_default_.get(), server.get(), &verify_root)); |
+ // User 1 should still verify successfully through the D root. |
+ EXPECT_EQ(net::OK, Verify(verify_proc_1_.get(), server.get(), &verify_root)); |
+ EXPECT_EQ("CN=D Root CA", verify_root); |
+ // User 2 should now verify successfully through the E root. |
+ EXPECT_EQ(net::OK, Verify(verify_proc_2_.get(), server.get(), &verify_root)); |
+ EXPECT_EQ("CN=E Root CA", verify_root); |
+ |
+ // Delete D root. |
+ EXPECT_TRUE(db_1_->DeleteCertAndKey(root_1_[0])); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_default_.get(), server.get(), &verify_root)); |
+ // User 1 should now fail to verify. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_1_.get(), server.get(), &verify_root)); |
+ // User 2 should still verify successfully through the E root. |
+ EXPECT_EQ(net::OK, Verify(verify_proc_2_.get(), server.get(), &verify_root)); |
+ EXPECT_EQ("CN=E Root CA", verify_root); |
+ |
+ // Delete E root. |
+ EXPECT_TRUE(db_2_->DeleteCertAndKey(root_2_[0])); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_default_.get(), server.get(), &verify_root)); |
+ // User 1 should still fail to verify. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_1_.get(), server.get(), &verify_root)); |
+ // User 2 should now fail to verify. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_2_.get(), server.get(), &verify_root)); |
+} |
+ |
+// Test that roots specified through additional_trust_anchors are trusted for |
+// that verification, and that there is not any caching that affects later |
+// verifications. |
+TEST_F(CertVerifyProcChromeOSTest, TestAdditionalTrustAnchors) { |
+ EXPECT_TRUE(verify_proc_default_->SupportsAdditionalTrustAnchors()); |
+ EXPECT_TRUE(verify_proc_1_->SupportsAdditionalTrustAnchors()); |
+ |
+ scoped_refptr<net::X509Certificate> server = certs_1_[0]; |
+ std::string verify_root; |
+ net::CertificateList additional_trust_anchors; |
+ |
+ // Before either of the root certs have been trusted, all verifications should |
+ // fail with CERT_AUTHORITY_INVALID. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ |
+ // Use D Root CA as additional trust anchor. Verifications should succeed now. |
+ additional_trust_anchors.push_back(root_1_[0]); |
+ EXPECT_EQ(net::OK, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ EXPECT_EQ("CN=D Root CA", verify_root); |
+ EXPECT_EQ(net::OK, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ EXPECT_EQ("CN=D Root CA", verify_root); |
+ // User 2 should still fail. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_2_.get(), |
+ net::CertificateList(), |
+ server.get(), |
+ &verify_root)); |
+ |
+ // Without additional trust anchors, verification should fail again. |
+ additional_trust_anchors.clear(); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ |
+ // Import and trust the D Root CA for user 2. |
+ net::CertificateList roots; |
+ roots.push_back(root_1_[0]); |
+ net::NSSCertDatabase::ImportCertFailureList failed; |
+ EXPECT_TRUE( |
+ db_2_->ImportCACerts(roots, net::NSSCertDatabase::TRUSTED_SSL, &failed)); |
+ EXPECT_EQ(0U, failed.size()); |
+ |
+ // Use D Root CA as additional trust anchor. Verifications should still |
+ // succeed even if the cert is trusted by a different profile. |
+ additional_trust_anchors.push_back(root_1_[0]); |
+ EXPECT_EQ(net::OK, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ EXPECT_EQ("CN=D Root CA", verify_root); |
+ EXPECT_EQ(net::OK, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ EXPECT_EQ("CN=D Root CA", verify_root); |
+ EXPECT_EQ(net::OK, |
+ VerifyWithAdditionalTrustAnchors(verify_proc_2_.get(), |
+ additional_trust_anchors, |
+ server.get(), |
+ &verify_root)); |
+ EXPECT_EQ("CN=D Root CA", verify_root); |
+} |
+ |
+class CertVerifyProcChromeOSOrderingTest |
+ : public CertVerifyProcChromeOSTest, |
+ public ::testing::WithParamInterface< |
+ std::tr1::tuple<bool, int, std::string> > {}; |
+ |
+// Test a variety of different combinations of (maybe) verifying / (maybe) |
+// importing / verifying again, to try to find any cases where caching might |
+// affect the results. |
+TEST_P(CertVerifyProcChromeOSOrderingTest, TrustThenVerify) { |
+ const ParamType& param = GetParam(); |
+ const bool verify_first = std::tr1::get<0>(param); |
+ const int trust_bitmask = std::tr1::get<1>(param); |
+ const std::string test_order = std::tr1::get<2>(param); |
+ DVLOG(1) << "verify_first: " << verify_first |
+ << " trust_bitmask: " << trust_bitmask |
+ << " test_order: " << test_order; |
+ |
+ scoped_refptr<net::X509Certificate> server = certs_1_[0]; |
+ std::string verify_root; |
+ |
+ if (verify_first) { |
+ // Before either of the root certs have been trusted, all verifications |
+ // should fail with CERT_AUTHORITY_INVALID. |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_default_.get(), server.get(), &verify_root)); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_1_.get(), server.get(), &verify_root)); |
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_2_.get(), server.get(), &verify_root)); |
+ } |
+ |
+ int expected_user1_result = net::ERR_CERT_AUTHORITY_INVALID; |
+ int expected_user2_result = net::ERR_CERT_AUTHORITY_INVALID; |
+ |
+ if (trust_bitmask & 1) { |
+ expected_user1_result = net::OK; |
+ // Import and trust the D root for user 1. |
+ net::NSSCertDatabase::ImportCertFailureList failed; |
+ EXPECT_TRUE(db_1_->ImportCACerts( |
+ root_1_, net::NSSCertDatabase::TRUSTED_SSL, &failed)); |
+ EXPECT_EQ(0U, failed.size()); |
+ } |
+ |
+ if (trust_bitmask & 2) { |
+ expected_user2_result = net::OK; |
+ // Import and trust the E root for user 2. |
+ net::NSSCertDatabase::ImportCertFailureList failed; |
+ EXPECT_TRUE(db_2_->ImportCACerts( |
+ root_2_, net::NSSCertDatabase::TRUSTED_SSL, &failed)); |
+ EXPECT_EQ(0U, failed.size()); |
+ } |
+ |
+ // Repeat the tests twice, they should return the same each time. |
+ for (int i = 0; i < 2; ++i) { |
+ SCOPED_TRACE(i); |
+ for (std::string::const_iterator j = test_order.begin(); |
+ j != test_order.end(); |
+ ++j) { |
+ switch (*j) { |
+ case 'd': |
+ // Default verifier should always fail. |
+ EXPECT_EQ( |
+ net::ERR_CERT_AUTHORITY_INVALID, |
+ Verify(verify_proc_default_.get(), server.get(), &verify_root)); |
+ break; |
+ case '1': |
+ EXPECT_EQ(expected_user1_result, |
+ Verify(verify_proc_1_.get(), server.get(), &verify_root)); |
+ if (expected_user1_result == net::OK) |
+ EXPECT_EQ("CN=D Root CA", verify_root); |
+ break; |
+ case '2': |
+ EXPECT_EQ(expected_user2_result, |
+ Verify(verify_proc_2_.get(), server.get(), &verify_root)); |
+ if (expected_user2_result == net::OK) |
+ EXPECT_EQ("CN=E Root CA", verify_root); |
+ break; |
+ default: |
+ FAIL(); |
+ } |
+ } |
+ } |
+} |
+ |
+INSTANTIATE_TEST_CASE_P( |
+ Variations, |
+ CertVerifyProcChromeOSOrderingTest, |
+ ::testing::Combine( |
+ ::testing::Bool(), |
+ ::testing::Range(0, 1 << 2), |
+ ::testing::Values("d12", "d21", "1d2", "12d", "2d1", "21d"))); |
+ |
+} // namespace chromeos |