blob: 0be01503631bbb6ecb0c20b4532d99e58dc77da8 [file] [log] [blame]
// 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 "components/certificate_transparency/tree_state_tracker.h"
#include <memory>
#include <string>
#include <utility>
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "components/certificate_transparency/features.h"
#include "net/base/net_errors.h"
#include "net/cert/ct_log_verifier.h"
#include "net/cert/ct_serialization.h"
#include "net/cert/merkle_tree_leaf.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/signed_tree_head.h"
#include "net/cert/x509_certificate.h"
#include "net/dns/mock_host_resolver.h"
#include "net/log/net_log.h"
#include "net/log/test_net_log.h"
#include "net/test/ct_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using net::ct::SignedCertificateTimestamp;
using net::ct::SignedTreeHead;
using net::ct::GetSampleSignedTreeHead;
using net::ct::GetTestPublicKeyId;
using net::ct::GetTestPublicKey;
using net::ct::kSthRootHashLength;
using net::ct::GetX509CertSCT;
constexpr char kHostname[] = "example.test";
constexpr base::TimeDelta kZeroTTL;
namespace certificate_transparency {
class TreeStateTrackerTest : public ::testing::Test {
void SetUp() override {
log_ = net::CTLogVerifier::Create(GetTestPublicKey(), "testlog",
"unresolvable.invalid");
ASSERT_TRUE(log_);
ASSERT_EQ(log_->key_id(), GetTestPublicKeyId());
const std::string der_test_cert(net::ct::GetDerEncodedX509Cert());
chain_ = net::X509Certificate::CreateFromBytes(der_test_cert.data(),
der_test_cert.length());
ASSERT_TRUE(chain_.get());
GetX509CertSCT(&cert_sct_);
cert_sct_->origin = SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE;
}
protected:
base::test::ScopedTaskEnvironment task_environment_{
base::test::ScopedTaskEnvironment::MainThreadType::IO};
scoped_refptr<const net::CTLogVerifier> log_;
net::MockCachingHostResolver host_resolver_;
std::unique_ptr<TreeStateTracker> tree_tracker_;
scoped_refptr<net::X509Certificate> chain_;
scoped_refptr<SignedCertificateTimestamp> cert_sct_;
net::TestNetLog net_log_;
};
// Test that a new STH & SCT are delegated correctly to a
// SingleTreeTracker instance created by the TreeStateTracker.
// This is verified by looking for a single event on the net_log_
// passed into the TreeStateTracker c'tor.
TEST_F(TreeStateTrackerTest, TestDelegatesCorrectly) {
std::vector<scoped_refptr<const net::CTLogVerifier>> verifiers;
verifiers.push_back(log_);
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kCTLogAuditing);
tree_tracker_ =
std::make_unique<TreeStateTracker>(verifiers, &host_resolver_, &net_log_);
// Add a cache entry for kHostname that indicates it was looked up over DNS.
// SingleTreeTracker requires this before it will request an inclusion proof,
// as otherwise it would reveal to the DNS resolver which server a user
// visited. If the server was already looked up via DNS though, that that
// information is already known to the DNS resolver so there is then no harm.
host_resolver_.GetHostCache()->Set(
net::HostCache::Key(kHostname, net::ADDRESS_FAMILY_UNSPECIFIED, 0),
net::HostCache::Entry(net::OK, net::AddressList(),
net::HostCache::Entry::SOURCE_DNS),
base::TimeTicks::Now(), kZeroTTL);
SignedTreeHead sth;
GetSampleSignedTreeHead(&sth);
ASSERT_EQ(log_->key_id(), sth.log_id);
tree_tracker_->NewSTHObserved(sth);
ASSERT_EQ(log_->key_id(), cert_sct_->log_id);
tree_tracker_->OnSCTVerified(kHostname, chain_.get(), cert_sct_.get());
base::RunLoop().RunUntilIdle();
net::ct::MerkleTreeLeaf leaf;
ASSERT_TRUE(GetMerkleTreeLeaf(chain_.get(), cert_sct_.get(), &leaf));
std::string leaf_hash;
ASSERT_TRUE(HashMerkleTreeLeaf(leaf, &leaf_hash));
// There should be one NetLog event.
EXPECT_EQ(1u, net_log_.GetSize());
}
} // namespace certificate_transparency