Index: net/cert/internal/trust_store_nss_unittest.cc |
diff --git a/net/cert/internal/trust_store_nss_unittest.cc b/net/cert/internal/trust_store_nss_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..65797192157ac07b30245d7d8772c7472a09ead2 |
--- /dev/null |
+++ b/net/cert/internal/trust_store_nss_unittest.cc |
@@ -0,0 +1,246 @@ |
+// Copyright 2016 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/cert/internal/trust_store_nss.h" |
+ |
+#include <cert.h> |
+#include <certdb.h> |
+ |
+#include "base/bind.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/run_loop.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "crypto/scoped_test_nss_db.h" |
+#include "net/cert/internal/test_helpers.h" |
+#include "net/cert/internal/trust_store_test_helpers.h" |
+#include "net/cert/scoped_nss_types.h" |
+#include "net/cert/x509_certificate.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace net { |
+ |
+namespace { |
+ |
+void NotCalled(TrustAnchors anchors) { |
+ ADD_FAILURE() << "NotCalled was called"; |
+} |
+ |
+class TrustStoreNSSTest : public testing::Test { |
+ public: |
+ void SetUp() override { |
+ ASSERT_TRUE(test_nssdb_.is_open()); |
+ |
+ ParsedCertificateList chain; |
+ bool unused_verify_result; |
+ der::GeneralizedTime unused_time; |
+ std::string unused_errors; |
+ |
+ ReadVerifyCertChainTestFromFile("key-rollover-oldchain.pem", &chain, |
+ &oldroot_, &unused_time, |
+ &unused_verify_result, &unused_errors); |
+ ASSERT_EQ(2U, chain.size()); |
+ target_ = chain[0]; |
+ oldintermediate_ = chain[1]; |
+ ASSERT_TRUE(target_); |
+ ASSERT_TRUE(oldintermediate_); |
+ ASSERT_TRUE(oldroot_); |
+ |
+ scoped_refptr<TrustAnchor> unused_root; |
+ ReadVerifyCertChainTestFromFile("key-rollover-longrolloverchain.pem", |
+ &chain, &unused_root, &unused_time, |
+ &unused_verify_result, &unused_errors); |
+ ASSERT_EQ(4U, chain.size()); |
+ newintermediate_ = chain[1]; |
+ newroot_ = TrustAnchor::CreateFromCertificateNoConstraints(chain[2]); |
+ newrootrollover_ = chain[3]; |
+ ASSERT_TRUE(newintermediate_); |
+ ASSERT_TRUE(newroot_); |
+ ASSERT_TRUE(newrootrollover_); |
+ |
+ trust_store_nss_.reset( |
+ new TrustStoreNSS(trustSSL, base::ThreadTaskRunnerHandle::Get())); |
+ } |
+ |
+ std::string GetUniqueNickname() { |
+ return "trust_store_nss_unittest" + base::UintToString(nickname_counter_++); |
+ } |
+ |
+ void AddCertToNSS(const ParsedCertificate* cert) { |
+ std::string nickname = GetUniqueNickname(); |
+ ScopedCERTCertificate nss_cert( |
+ X509Certificate::CreateOSCertHandleFromBytesWithNickname( |
+ cert->der_cert().AsStringPiece().data(), cert->der_cert().Length(), |
+ nickname.c_str())); |
+ ASSERT_TRUE(nss_cert); |
+ SECStatus srv = |
+ PK11_ImportCert(test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE, |
+ nickname.c_str(), PR_FALSE /* includeTrust (unused) */); |
+ ASSERT_EQ(SECSuccess, srv); |
+ } |
+ |
+ void AddCertsToNSS() { |
+ AddCertToNSS(target_.get()); |
+ AddCertToNSS(oldintermediate_.get()); |
+ AddCertToNSS(newintermediate_.get()); |
+ AddCertToNSS(oldroot_->cert().get()); |
+ AddCertToNSS(newroot_->cert().get()); |
+ AddCertToNSS(newrootrollover_.get()); |
+ } |
+ |
+ // Trusts |cert|. Assumes the cert was already imported into NSS. |
+ void TrustCert(const TrustAnchor* anchor) { TrustCert(anchor->cert().get()); } |
+ void TrustCert(const ParsedCertificate* cert) { |
+ SECItem der_cert; |
+ der_cert.data = const_cast<uint8_t*>(cert->der_cert().UnsafeData()); |
+ der_cert.len = base::checked_cast<unsigned>(cert->der_cert().Length()); |
+ der_cert.type = siDERCertBuffer; |
+ |
+ ScopedCERTCertificate nss_cert( |
+ CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), &der_cert)); |
+ ASSERT_TRUE(nss_cert); |
+ |
+ CERTCertTrust trust = {0}; |
+ trust.sslFlags = |
+ CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA; |
+ SECStatus srv = |
+ CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nss_cert.get(), &trust); |
+ ASSERT_EQ(SECSuccess, srv); |
+ } |
+ |
+ protected: |
+ void ExpectTrustStoreContains(tracked_objects::Location loc, |
+ scoped_refptr<ParsedCertificate> cert, |
+ TrustAnchors expected_async_matches) { |
+ SCOPED_TRACE(loc.ToString()); |
+ |
+ TrustAnchors sync_matches; |
+ TrustAnchorResultRecorder anchor_results; |
+ std::unique_ptr<TrustStore::Request> req; |
+ trust_store_nss_->FindTrustAnchorsForCert(cert, anchor_results.Callback(), |
+ &sync_matches, &req); |
+ ASSERT_TRUE(req); |
+ EXPECT_TRUE(sync_matches.empty()); |
+ |
+ anchor_results.Run(); |
+ std::vector<der::Input> der_result_matches; |
+ for (const auto& it : anchor_results.matches()) |
+ der_result_matches.push_back(it->cert()->der_cert()); |
+ std::sort(der_result_matches.begin(), der_result_matches.end()); |
+ |
+ std::vector<der::Input> der_expected_matches; |
+ for (const auto& it : expected_async_matches) |
+ der_expected_matches.push_back(it->cert()->der_cert()); |
+ std::sort(der_expected_matches.begin(), der_expected_matches.end()); |
+ |
+ EXPECT_EQ(der_expected_matches, der_result_matches); |
+ } |
+ |
+ scoped_refptr<TrustAnchor> oldroot_; |
+ scoped_refptr<TrustAnchor> newroot_; |
+ |
+ scoped_refptr<ParsedCertificate> target_; |
+ scoped_refptr<ParsedCertificate> oldintermediate_; |
+ scoped_refptr<ParsedCertificate> newintermediate_; |
+ scoped_refptr<ParsedCertificate> newrootrollover_; |
+ crypto::ScopedTestNSSDB test_nssdb_; |
+ std::unique_ptr<TrustStoreNSS> trust_store_nss_; |
+ unsigned nickname_counter_ = 0; |
+}; |
+ |
+// Without adding any certs to the NSS DB, should get no anchor results for any |
+// of the test certs. |
+TEST_F(TrustStoreNSSTest, CertsNotPresent) { |
+ ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors()); |
+} |
+ |
+// If certs are present in NSS DB but aren't marked as trusted, should get no |
+// anchor results for any of the test certs. |
+TEST_F(TrustStoreNSSTest, CertsPresentButNotTrusted) { |
+ AddCertsToNSS(); |
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors()); |
+} |
+ |
+// A self-signed CA certificate is trusted. FindTrustAnchorsForCert should |
+// return the cert on any intermediates with a matching issuer, and on any |
+// matching self-signed/self-issued CA certs. |
+TEST_F(TrustStoreNSSTest, TrustedCA) { |
+ AddCertsToNSS(); |
+ TrustCert(newroot_.get()); |
+ ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, {newroot_}); |
+ ExpectTrustStoreContains(FROM_HERE, oldintermediate_, {newroot_}); |
+ ExpectTrustStoreContains(FROM_HERE, newrootrollover_, {newroot_}); |
+ ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), {newroot_}); |
+ ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), {newroot_}); |
+} |
+ |
+// When an intermediate certificate is trusted, FindTrustAnchorsForCert should |
+// return that cert on any certs issued by the intermediate, but not for the |
+// intermediate itself (or the CAs). |
+TEST_F(TrustStoreNSSTest, TrustedIntermediate) { |
+ AddCertsToNSS(); |
+ TrustCert(newintermediate_.get()); |
+ ExpectTrustStoreContains( |
+ FROM_HERE, target_, |
+ {TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_)}); |
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, oldintermediate_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, newrootrollover_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors()); |
+} |
+ |
+// Multiple self-signed CA certificates with the same name are trusted. |
+// FindTrustAnchorsForCert should return all these certs on any intermediates |
+// with a matching issuer, and on any matching self-signed/self-issued CA certs. |
+TEST_F(TrustStoreNSSTest, MultipleTrustedCAWithSameSubject) { |
+ AddCertsToNSS(); |
+ TrustCert(oldroot_.get()); |
+ TrustCert(newroot_.get()); |
+ ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors()); |
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, {newroot_, oldroot_}); |
+ ExpectTrustStoreContains(FROM_HERE, oldintermediate_, {newroot_, oldroot_}); |
+ ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), {newroot_, oldroot_}); |
+} |
+ |
+// Cancel a FindTrustAnchorsForCert request before it has returned any results. |
+// Callback should not be called. |
+TEST_F(TrustStoreNSSTest, CancelRequest) { |
+ std::unique_ptr<TrustStore::Request> req; |
+ TrustAnchors sync_matches; |
+ trust_store_nss_->FindTrustAnchorsForCert(target_, base::Bind(&NotCalled), |
+ &sync_matches, &req); |
+ ASSERT_TRUE(req); |
+ req.reset(); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+// Cancel a FindTrustAnchorsForCert request during the callback. Should not |
+// crash. |
+TEST_F(TrustStoreNSSTest, CancelRequestDuringCallback) { |
+ AddCertsToNSS(); |
+ TrustCert(newroot_.get()); |
+ |
+ base::RunLoop run_loop; |
+ std::unique_ptr<TrustStore::Request> req; |
+ TrustAnchors sync_matches; |
+ trust_store_nss_->FindTrustAnchorsForCert( |
+ newintermediate_, |
+ base::Bind(&TrustStoreRequestDeleter, &req, run_loop.QuitClosure()), |
+ &sync_matches, &req); |
+ ASSERT_TRUE(req); |
+ run_loop.Run(); |
+ ASSERT_FALSE(req); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+} // namespace |
+ |
+} // namespace net |