[certificate-transparency] push by ekas...@google.com - Refactor tests and related code on 2012-10-11 17:56 GMT

21 views
Skip to first unread message

certificate-...@googlecode.com

unread,
Oct 11, 2012, 1:56:58 PM10/11/12
to certificate-...@googlegroups.com
Revision: 9208768c234a
Branch: default
Author: Emilia Kasper <eka...@google.com>
Date: Thu Oct 11 10:55:00 2012
Log: Refactor tests and related code
http://code.google.com/p/certificate-transparency/source/detail?r=9208768c234a

Added:
/src/include/frontend.h
/src/log/cert_submission_handler_test.cc
/src/log/database_large_test.cc
/src/log/frontend.cc
/src/log/frontend.h
/src/log/frontend_test.cc
/src/log/test_db.h
/src/log/test_signer.cc
/src/log/test_signer.h
Deleted:
/src/log/submission_handler.cc
/src/log/submission_handler.h
/src/log/submission_handler_test.cc
Modified:
/.hgignore
/src/README
/src/client/Makefile
/src/client/ssl_client.cc
/src/log/Makefile
/src/log/cert.cc
/src/log/cert.h
/src/log/cert_submission_handler.cc
/src/log/cert_submission_handler.h
/src/log/database.h
/src/log/database_test.cc
/src/log/file_storage_test.cc
/src/log/frontend_signer.cc
/src/log/frontend_signer.h
/src/log/frontend_signer_test.cc
/src/log/log_lookup_test.cc
/src/log/log_signer.cc
/src/log/log_signer.h
/src/log/log_signer_test.cc
/src/log/log_verifier.cc
/src/log/sqlite_db.cc
/src/log/sqlite_db.h
/src/log/tree_signer.cc
/src/log/tree_signer_test.cc
/src/merkletree/serial_hasher.cc
/src/merkletree/serial_hasher.h
/src/merkletree/serial_hasher_test.cc
/src/proto/ct.proto
/src/server/Makefile
/src/server/ct-server.cc

=======================================
--- /dev/null
+++ /src/include/frontend.h Thu Oct 11 10:55:00 2012
@@ -0,0 +1,1 @@
+../log/frontend.h
=======================================
--- /dev/null
+++ /src/log/cert_submission_handler_test.cc Thu Oct 11 10:55:00 2012
@@ -0,0 +1,173 @@
+#include <gtest/gtest.h>
+#include <openssl/ssl.h>
+#include <string>
+
+#include "cert_checker.h"
+#include "cert_submission_handler.h"
+#include "ct.pb.h"
+#include "util.h"
+
+static const char kCertDir[] = "../test/testdata";
+
+// Valid certificates.
+// Self-signed
+static const char kCaCert[] = "ca-cert.pem";
+// Issued by ca.pem
+static const char kLeafCert[] = "test-cert.pem";
+// Issued by ca.pem
+static const char kCaPreCert[] = "ca-pre-cert.pem";
+// Issued by ca-pre-cert.pem
+static const char kPreCert[] = "test-pre-cert.pem";
+// Issued by ca-cert.pem
+static const char kIntermediateCert[] = "intermediate-cert.pem";
+// Issued by intermediate-cert.pem
+static const char kChainLeafCert[] = "test2-cert.pem";
+
+namespace {
+
+using ct::CertificateEntry;
+using std::string;
+
+class CertSubmissionHandlerTest : public ::testing::Test {
+ protected:
+ string ca_;
+ string leaf_;
+ string ca_precert_;
+ string precert_;
+ string intermediate_;
+ string chain_leaf_;
+ string cert_dir_;
+ CertSubmissionHandler *handler_;
+ CertChecker *checker_;
+
+ CertSubmissionHandlerTest() : handler_(NULL) {}
+
+ void SetUp() {
+ cert_dir_ = string(kCertDir);
+ checker_ = new CertChecker();
+ checker_->LoadTrustedCertificate(cert_dir_ + "/" + kCaCert);
+ handler_ = new CertSubmissionHandler(checker_);
+ ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kCaCert, &ca_));
+ ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kLeafCert, &leaf_));
+ ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kCaPreCert,
+ &ca_precert_));
+ ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kPreCert,
+ &precert_));
+ ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kIntermediateCert,
+ &intermediate_));
+ ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kChainLeafCert,
+ &chain_leaf_));
+ }
+
+ ~CertSubmissionHandlerTest() {
+ delete checker_;
+ delete handler_;
+ }
+};
+
+TEST_F(CertSubmissionHandlerTest, SubmitCert) {
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::X509_ENTRY);
+ // Submit a leaf cert.
+ EXPECT_EQ(CertSubmissionHandler::OK,
+ handler_->ProcessSubmission(leaf_, &entry));
+ EXPECT_TRUE(entry.has_leaf_certificate());
+ EXPECT_EQ(0, entry.intermediates_size());
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitEmptyCert) {
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::X509_ENTRY);
+ EXPECT_EQ(CertSubmissionHandler::EMPTY_SUBMISSION,
+ handler_->ProcessSubmission("", &entry));
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitInvalidCert) {
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::X509_ENTRY);
+ EXPECT_EQ(CertSubmissionHandler::INVALID_PEM_ENCODED_CHAIN,
+ handler_->ProcessSubmission("-----BEGIN
CERTIFICATE-----\ninvalid"
+ "\n-----END CERTIFICATE-----",
&entry));
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitChain) {
+ // Submit a chain.
+ string submit = chain_leaf_ + intermediate_;
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::X509_ENTRY);
+ EXPECT_EQ(CertSubmissionHandler::OK,
+ handler_->ProcessSubmission(submit, &entry));
+ EXPECT_TRUE(entry.has_leaf_certificate());
+ EXPECT_EQ(1, entry.intermediates_size());
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitPartialChain) {
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::X509_ENTRY);
+ // Submit a leaf cert with a missing intermediate.
+ EXPECT_EQ(CertSubmissionHandler::UNKNOWN_ROOT,
+ handler_->ProcessSubmission(chain_leaf_, &entry));
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitInvalidChain) {
+ string invalid_submit = ca_;
+ invalid_submit.append(leaf_);
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::X509_ENTRY);
+ // An invalid chain with two certs in wrong order.
+ EXPECT_EQ(CertSubmissionHandler::INVALID_CERTIFICATE_CHAIN,
+ handler_->ProcessSubmission(invalid_submit, &entry));
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitCertAsPreCert) {
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::PRECERT_ENTRY);
+ // Various things are wrong here, so do not expect a specific error.
+ EXPECT_NE(CertSubmissionHandler::OK,
+ handler_->ProcessSubmission(leaf_, &entry));
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitCertChainAsPreCert) {
+ string submit = chain_leaf_ + intermediate_;
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::PRECERT_ENTRY);
+ EXPECT_NE(CertSubmissionHandler::OK,
+ handler_->ProcessSubmission(submit, &entry));
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitPreCertChain) {
+ string submit = precert_ + ca_precert_;
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::PRECERT_ENTRY);
+ EXPECT_EQ(CertSubmissionHandler::OK,
+ handler_->ProcessSubmission(submit, &entry));
+ EXPECT_TRUE(entry.has_leaf_certificate());
+ // |intermediates| is the entire precert chain (excluding root).
+ EXPECT_EQ(2, entry.intermediates_size());
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitInvalidPreCertChain) {
+ // In wrong order.
+ string submit = ca_precert_ + precert_;
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::PRECERT_ENTRY);
+ EXPECT_NE(CertSubmissionHandler::OK,
+ handler_->ProcessSubmission(submit, &entry));
+}
+
+TEST_F(CertSubmissionHandlerTest, SubmitPreCertChainAsCertChain) {
+ string submit = precert_ + ca_precert_;
+ CertificateEntry entry;
+ entry.set_type(CertificateEntry::X509_ENTRY);
+ // This should fail since ca_precert_ is not a CA cert (CA:false).
+ EXPECT_NE(CertSubmissionHandler::OK,
+ handler_->ProcessSubmission(submit, &entry));
+}
+
+} // namespace
+
+int main(int argc, char**argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ SSL_library_init();
+ return RUN_ALL_TESTS();
+}
=======================================
--- /dev/null
+++ /src/log/database_large_test.cc Thu Oct 11 10:55:00 2012
@@ -0,0 +1,135 @@
+/* -*- indent-tabs-mode: nil -*- */
+
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+#include <set>
+#include <stdlib.h>
+#include <string>
+#include <sys/resource.h>
+
+#include "database.h"
+#include "file_db.h"
+#include "file_storage.h"
+#include "sqlite_db.h"
+#include "test_db.h"
+#include "test_signer.h"
+#include "util.h"
+
+DEFINE_int32(database_size, 0, "Number of entries to put in the test
database. "
+ "Be careful choosing this, as the database will fill up your
disk "
+ "(entries are a few kB each). Maximum is limited to 1 000
000. "
+ "Also note that SQLite may be very slow with small batch
sizes.");
+DEFINE_int32(batch_size, 1, "Number of writes to batch together "
+ "in one transaction (no effect for FileDB).");
+
+namespace {
+
+using ct::LoggedCertificate;
+using std::string;
+
+template <class T> class LargeDBTest : public ::testing::Test {
+ protected:
+ LargeDBTest() :
+ test_db_(),
+ test_signer_() { }
+
+ ~LargeDBTest() {}
+
+ void FillDatabase(int entries) {
+ LoggedCertificate logged_cert;
+ for (int i = 0; i < entries; ++i) {
+ test_signer_.CreateUniqueFakeSignature(&logged_cert);
+ EXPECT_EQ(Database::OK,
+ db()->CreatePendingCertificateEntry(logged_cert));
+ }
+ }
+
+ int ReadAllPendingEntries() {
+ std::set<string> pending_hashes = db()->PendingHashes();
+ std::set<string>::const_iterator it;
+ LoggedCertificate lookup_cert;
+ for (it = pending_hashes.begin(); it != pending_hashes.end(); ++it) {
+ EXPECT_EQ(Database::LOOKUP_OK,
+ this->db()->LookupCertificateByHash(*it, &lookup_cert));
+ }
+ return pending_hashes.size();
+ }
+
+ T *db() const { return test_db_.db(); }
+
+ TestDB<T> test_db_;
+ TestSigner test_signer_;
+};
+
+typedef testing::Types<FileDB, SQLiteDB> Databases;
+
+TYPED_TEST_CASE(LargeDBTest, Databases);
+
+TYPED_TEST(LargeDBTest, Benchmark) {
+ int entries = FLAGS_database_size;
+ CHECK_GE(entries, 0);
+ int batch_size = FLAGS_batch_size;
+ int original_log_level = FLAGS_minloglevel;
+
+ struct rusage ru_before, ru_after;
+ getrusage(RUSAGE_SELF, &ru_before);
+ uint64_t realtime_before, realtime_after;
+ realtime_before = util::TimeInMilliseconds();
+ if (batch_size == 1 || !this->db()->Transactional()) {
+ this->FillDatabase(entries);
+ } else {
+ CHECK_GT(batch_size, 1);
+ while (entries >= batch_size) {
+ this->db()->BeginTransaction();
+ this->FillDatabase(batch_size);
+ this->db()->EndTransaction();
+ entries -= batch_size;
+ }
+ if (entries > 0) {
+ this->db()->BeginTransaction();
+ this->FillDatabase(entries);
+ this->db()->EndTransaction();
+ }
+ }
+ realtime_after = util::TimeInMilliseconds();
+ getrusage(RUSAGE_SELF, &ru_after);
+
+ FLAGS_minloglevel = 0;
+ LOG(INFO) << "Real time spent creating " << FLAGS_database_size
+ << " entries: " << realtime_after - realtime_before << " ms";
+ LOG(INFO) << "Peak RSS delta (as reported by getrusage()) was "
+ << ru_after.ru_maxrss - ru_before.ru_maxrss << " kB";
+ FLAGS_minloglevel = original_log_level;
+
+ getrusage(RUSAGE_SELF, &ru_before);
+ realtime_before = util::TimeInMilliseconds();
+ CHECK_EQ(FLAGS_database_size, this->ReadAllPendingEntries());
+ realtime_after = util::TimeInMilliseconds();
+ getrusage(RUSAGE_SELF, &ru_after);
+
+ FLAGS_minloglevel = 0;
+ LOG(INFO) << "Real time spent reading " << FLAGS_database_size
+ << " entries, sorted by key: "
+ << realtime_after - realtime_before << " ms";
+ LOG(INFO) << "Peak RSS delta (as reported by getrusage()) was "
+ << ru_after.ru_maxrss - ru_before.ru_maxrss << " kB";
+ FLAGS_minloglevel = original_log_level;
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ // Change the defaults. Can be overridden on command line.
+ // Log to stderr instead of log files.
+ FLAGS_logtostderr = true;
+ // Only log fatal messages by default.
+ FLAGS_minloglevel = 3;
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
+ ::testing::InitGoogleTest(&argc, argv);
+ CHECK_GT(FLAGS_database_size, 0) << "Please specify the test database
size";
+ CHECK_LE(FLAGS_database_size, 1000000)
+ << "Database size exceeds allowed maximum";
+ return RUN_ALL_TESTS();
+}
=======================================
--- /dev/null
+++ /src/log/frontend.cc Thu Oct 11 10:55:00 2012
@@ -0,0 +1,104 @@
+#include <glog/logging.h>
+
+#include "ct.pb.h"
+#include "frontend.h"
+#include "frontend_signer.h"
+#include "cert_submission_handler.h"
+
+using ct::CertificateEntry;
+using ct::SignedCertificateTimestamp;
+using std::string;
+
+Frontend::Frontend(CertSubmissionHandler *handler, FrontendSigner *signer)
+ : handler_(handler),
+ signer_(signer) {}
+
+Frontend::~Frontend() {
+ delete signer_;
+ delete handler_;
+}
+
+Frontend::SubmitResult Frontend::QueueEntry(CertificateEntry::Type type,
+ const string &data,
+ SignedCertificateTimestamp
*sct) {
+ // Step 1. Preprocessing: convert the submission into a CertificateEntry
+ // and verify the chain.
+ CertificateEntry entry;
+ entry.set_type(type);
+ CertSubmissionHandler::SubmitResult pre_result =
+ handler_->ProcessSubmission(data, &entry);
+ if (pre_result != CertSubmissionHandler::OK)
+ return GetSubmitError(pre_result);
+
+ // Step 2. Submit to database.
+ FrontendSigner::SubmitResult signer_result = signer_->QueueEntry(entry,
sct);
+
+ SubmitResult result;
+ switch (signer_result) {
+ case NEW:
+ result = NEW;
+ break;
+ case DUPLICATE:
+ result = DUPLICATE;
+ break;
+ default:
+ LOG(FATAL) << "Unknown FrontendSigner return code " << signer_result;
+ }
+
+ return result;
+}
+
+// static
+std::string Frontend::SubmitResultString(SubmitResult result) {
+ string result_string;
+ switch (result) {
+ case NEW:
+ result_string = "new submission accepted";
+ break;
+ case DUPLICATE:
+ result_string = "duplicate submission";
+ case BAD_PEM_FORMAT:
+ result_string = "not a valid PEM-encoded chain";
+ break;
+ // TODO(ekasper): the following two could/should be more precise.
+ case SUBMISSION_TOO_LONG:
+ result_string = "DER-encoded certificate chain length "
+ "exceeds allowed limit";
+ break;
+ case CERTIFICATE_VERIFY_ERROR:
+ result_string = "could not verify certificate chain";
+ break;
+ case PRECERT_CHAIN_NOT_WELL_FORMED:
+ result_string = "precert chain not well-formed";
+ break;
+ default:
+ LOG(FATAL) << "Unknown SubmissionHandler return code " << result;
+ }
+
+ return result_string;
+}
+
+// static
+Frontend::SubmitResult
+Frontend::GetSubmitError(CertSubmissionHandler::SubmitResult result) {
+ SubmitResult submit_result;
+ switch (result) {
+ case CertSubmissionHandler::EMPTY_SUBMISSION:
+ case CertSubmissionHandler::INVALID_PEM_ENCODED_CHAIN:
+ submit_result = BAD_PEM_FORMAT;
+ break;
+ case CertSubmissionHandler::SUBMISSION_TOO_LONG:
+ submit_result = SUBMISSION_TOO_LONG;
+ break;
+ case CertSubmissionHandler::INVALID_CERTIFICATE_CHAIN:
+ case CertSubmissionHandler::UNKNOWN_ROOT:
+ submit_result = CERTIFICATE_VERIFY_ERROR;
+ break;
+ case CertSubmissionHandler::PRECERT_CHAIN_NOT_WELL_FORMED:
+ submit_result = PRECERT_CHAIN_NOT_WELL_FORMED;
+ break;
+ default:
+ LOG(FATAL) << "Unknown CertSubmissionHandler return code " << result;
+ }
+ return submit_result;
+}
=======================================
--- /dev/null
+++ /src/log/frontend.h Thu Oct 11 10:55:00 2012
@@ -0,0 +1,38 @@
+#ifndef FRONTEND_H
+#define FRONTEND_H
+
+#include "ct.pb.h"
+#include "cert_submission_handler.h"
+
+class FrontendSigner;
+
+// Frontend for accepting new submissions.
+class Frontend {
+ public:
+ // Takes ownership of the handler and signer.
+ Frontend(CertSubmissionHandler *handler, FrontendSigner *signer);
+ ~Frontend();
+
+ enum SubmitResult {
+ NEW,
+ DUPLICATE,
+ BAD_PEM_FORMAT,
+ SUBMISSION_TOO_LONG,
+ CERTIFICATE_VERIFY_ERROR,
+ PRECERT_CHAIN_NOT_WELL_FORMED,
+ };
+
+ SubmitResult QueueEntry(ct::CertificateEntry::Type type,
+ const std::string &data,
+ ct::SignedCertificateTimestamp *sct);
+
+ static std::string SubmitResultString(SubmitResult result);
+
+ private:
+ CertSubmissionHandler *handler_;
+ FrontendSigner *signer_;
+
+ static SubmitResult
+ GetSubmitError(CertSubmissionHandler::SubmitResult result);
+};
+#endif
=======================================
--- /dev/null
+++ /src/log/frontend_test.cc Thu Oct 11 10:55:00 2012
@@ -0,0 +1,254 @@
+/* -*- indent-tabs-mode: nil -*- */
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+#include <openssl/ssl.h>
+#include <string>
+
+#include "cert_submission_handler.h"
+#include "ct.pb.h"
+#include "file_db.h"
+#include "frontend.h"
+#include "frontend_signer.h"
+#include "log_verifier.h"
+#include "merkle_verifier.h"
+#include "serial_hasher.h"
+#include "sqlite_db.h"
+#include "test_db.h"
+#include "test_signer.h"
+#include "util.h"
+
+static const char kCertDir[] = "../test/testdata";
+
+// Valid certificates.
+// Self-signed
+static const char kCaCert[] = "ca-cert.pem";
+// Issued by ca-cert.pem
+static const char kLeafCert[] = "test-cert.pem";
+// Issued by ca.pem
+static const char kCaPreCert[] = "ca-pre-cert.pem";
+// Issued by ca-pre-cert.pem
+static const char kPreCert[] = "test-pre-cert.pem";
+// The resulting embedded cert, issued by ca-cert.pem
+static const char kEmbeddedCert[] = "test-embedded-cert.pem";
+// Issued by ca-cert.pem
+static const char kIntermediateCert[] = "intermediate-cert.pem";
+// Issued by intermediate-cert.pem
+static const char kChainLeafCert[] = "test2-cert.pem";
+
+namespace {
+
+using ct::CertificateEntry;
+using ct::LoggedCertificate;
+using ct::SignedCertificateTimestamp;
+using std::string;
+
+// A slightly shorter notation for constructing hex strings from binary
blobs.
+string H(const string &byte_string) {
+ return util::HexString(byte_string);
+}
+
+template <class T> class FrontendTest : public ::testing::Test {
+ protected:
+ FrontendTest()
+ : test_db_(),
+ test_signer_(),
+ verifier_(new LogVerifier(TestSigner::DefaultVerifier(),
+ new MerkleVerifier(new Sha256Hasher()))),
+ checker_(),
+ frontend_(new Frontend(new CertSubmissionHandler(&checker_),
+ new FrontendSigner(
+ db(), TestSigner::DefaultSigner()))) {}
+
+ void SetUp() {
+ cert_dir_ = string(kCertDir);
+ ASSERT_TRUE(util::ReadTextFile(cert_dir_ + "/" + kLeafCert,
&leaf_pem_));
+ ASSERT_TRUE(util::ReadTextFile(cert_dir_ + "/" + kCaPreCert,
+ &ca_precert_pem_));
+ ASSERT_TRUE(util::ReadTextFile(cert_dir_ + "/" + kPreCert,
+ &precert_pem_));
+ ASSERT_TRUE(util::ReadTextFile(cert_dir_ + "/" + kIntermediateCert,
+ &intermediate_pem_));
+ ASSERT_TRUE(util::ReadTextFile(cert_dir_ + "/" + kChainLeafCert,
+ &chain_leaf_pem_));
+ ASSERT_TRUE(util::ReadTextFile(cert_dir_ + "/" + kCaCert, &ca_pem_));
+ ASSERT_TRUE(util::ReadTextFile(cert_dir_ + "/" + kEmbeddedCert,
+ &embedded_pem_));
+ ASSERT_TRUE(checker_.LoadTrustedCertificate(cert_dir_ + "/" +
kCaCert));
+ }
+
+ ~FrontendTest() {
+ delete verifier_;
+ delete frontend_;
+ }
+
+ T *db() const { return test_db_.db(); }
+
+ TestDB<T> test_db_;
+ TestSigner test_signer_;
+ LogVerifier *verifier_;
+ CertChecker checker_;
+ Frontend *frontend_;
+ string cert_dir_;
+ string leaf_pem_;
+ string ca_precert_pem_;
+ string precert_pem_;
+ string intermediate_pem_;
+ string chain_leaf_pem_;
+ string embedded_pem_;
+ string ca_pem_;
+};
+
+typedef testing::Types<FileDB, SQLiteDB> Databases;
+
+TYPED_TEST_CASE(FrontendTest, Databases);
+
+TYPED_TEST(FrontendTest, TestSubmitValid) {
+ SignedCertificateTimestamp sct;
+ EXPECT_EQ(Frontend::NEW,
+ this->frontend_->QueueEntry(CertificateEntry::X509_ENTRY,
+ this->leaf_pem_, &sct));
+
+ // Look it up and expect to get the right thing back.
+ LoggedCertificate logged_cert;
+ Cert cert(this->leaf_pem_);
+ EXPECT_EQ(Database::LOOKUP_OK,
+ this->db()->LookupCertificateByHash(cert.Sha256Digest(),
+ &logged_cert));
+
+ // Compare the leaf cert.
+ string der_string = cert.DerEncoding();
+ EXPECT_EQ(H(der_string),
+ H(logged_cert.sct().entry().leaf_certificate()));
+
+ // And verify the signature.
+ sct.mutable_entry()->set_leaf_certificate(der_string);
+ EXPECT_EQ(LogVerifier::VERIFY_OK,
+ this->verifier_->VerifySignedCertificateTimestamp(sct));
+}
+
+TYPED_TEST(FrontendTest, TestSubmitValidWithIntermediate) {
+ SignedCertificateTimestamp sct;
+ string submission = this->chain_leaf_pem_ + this->intermediate_pem_;
+ EXPECT_EQ(Frontend::NEW,
+ this->frontend_->QueueEntry(CertificateEntry::X509_ENTRY,
+ submission, &sct));
+
+ // Look it up and expect to get the right thing back.
+ LoggedCertificate logged_cert;
+ Cert cert(this->chain_leaf_pem_);
+ EXPECT_EQ(Database::LOOKUP_OK,
+ this->db()->LookupCertificateByHash(cert.Sha256Digest(),
+ &logged_cert));
+
+ // Compare the leaf cert.
+ string der_string = cert.DerEncoding();
+ EXPECT_EQ(H(der_string),
+ H(logged_cert.sct().entry().leaf_certificate()));
+
+ // And verify the signature.
+ sct.mutable_entry()->set_leaf_certificate(der_string);
+ EXPECT_EQ(LogVerifier::VERIFY_OK,
+ this->verifier_->VerifySignedCertificateTimestamp(sct));
+
+ // Compare the first intermediate.
+ ASSERT_GE(logged_cert.sct().entry().intermediates_size(), 1);
+ Cert cert2(this->intermediate_pem_);
+ EXPECT_EQ(H(cert2.DerEncoding()),
+ H(logged_cert.sct().entry().intermediates(0)));
+}
+
+TYPED_TEST(FrontendTest, TestSubmitDuplicate) {
+ SignedCertificateTimestamp sct;
+ EXPECT_EQ(Frontend::NEW,
+ this->frontend_->QueueEntry(CertificateEntry::X509_ENTRY,
+ this->leaf_pem_, NULL));
+ EXPECT_EQ(Frontend::DUPLICATE,
+ this->frontend_->QueueEntry(CertificateEntry::X509_ENTRY,
+ this->leaf_pem_, &sct));
+
+ // Look it up and expect to get the right thing back.
+ LoggedCertificate logged_cert;
+ Cert cert(this->leaf_pem_);
+ EXPECT_EQ(Database::LOOKUP_OK,
+ this->db()->LookupCertificateByHash(cert.Sha256Digest(),
+ &logged_cert));
+
+ // Compare the leaf cert.
+ string der_string = cert.DerEncoding();
+ EXPECT_EQ(H(der_string),
+ H(logged_cert.sct().entry().leaf_certificate()));
+
+ // And verify the signature.
+ sct.mutable_entry()->set_leaf_certificate(der_string);
+ EXPECT_EQ(LogVerifier::VERIFY_OK,
+ this->verifier_->VerifySignedCertificateTimestamp(sct));
+}
+
+TYPED_TEST(FrontendTest, TestSubmitInvalidChain) {
+ SignedCertificateTimestamp sct;
+ // Missing intermediate.
+ EXPECT_EQ(Frontend::CERTIFICATE_VERIFY_ERROR,
+ this->frontend_->QueueEntry(CertificateEntry::X509_ENTRY,
+ this->chain_leaf_pem_, &sct));
+ EXPECT_FALSE(sct.has_signature());
+}
+
+TYPED_TEST(FrontendTest, TestSubmitInvalidPem) {
+ SignedCertificateTimestamp sct;
+ string fake_cert("-----BEGIN CERTIFICATE-----\n"
+ "Iamnotavalidcert\n"
+ "-----END CERTIFICATE-----\n");
+ EXPECT_EQ(Frontend::BAD_PEM_FORMAT,
+ this->frontend_->QueueEntry(CertificateEntry::X509_ENTRY,
+ fake_cert, &sct));
+ EXPECT_FALSE(sct.has_signature());
+}
+
+TYPED_TEST(FrontendTest, TestSubmitPrecert) {
+ SignedCertificateTimestamp sct;
+ string submission = this->precert_pem_ + this->ca_precert_pem_;
+ EXPECT_EQ(Frontend::NEW,
+ this->frontend_->QueueEntry(CertificateEntry::PRECERT_ENTRY,
+ submission, &sct));
+
+ CertChain chain(this->embedded_pem_);
+ CertificateEntry entry;
+ CHECK_EQ(SubmissionHandler::OK,
+ CertSubmissionHandler::X509ChainToEntry(chain, &entry));
+
+ // Look it up.
+ string hash = Sha256Hasher::Sha256Digest(entry.leaf_certificate());
+ LoggedCertificate logged_cert;
+ EXPECT_EQ(Database::LOOKUP_OK,
+ this->db()->LookupCertificateByHash(hash, &logged_cert));
+ Cert pre(this->precert_pem_);
+ Cert ca_pre(this->ca_precert_pem_);
+
+ // Verify the signature.
+ sct.mutable_entry()->set_leaf_certificate(entry.leaf_certificate());
+ EXPECT_EQ(LogVerifier::VERIFY_OK,
+ this->verifier_->VerifySignedCertificateTimestamp(sct));
+
+ // Expect to have the original certs logged in the chain.
+ ASSERT_GE(logged_cert.sct().entry().intermediates_size(), 2);
+ EXPECT_EQ(H(pre.DerEncoding()),
+ H(logged_cert.sct().entry().intermediates(0)));
+ EXPECT_EQ(H(ca_pre.DerEncoding()),
+ H(logged_cert.sct().entry().intermediates(1)));
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ // Change the defaults. Can be overridden on command line.
+ // Log to stderr instead of log files.
+ FLAGS_logtostderr = true;
+ // Only log fatal messages by default.
+ FLAGS_minloglevel = 3;
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
+ ::testing::InitGoogleTest(&argc, argv);
+ SSL_library_init();
+ return RUN_ALL_TESTS();
+}
=======================================
--- /dev/null
+++ /src/log/test_db.h Thu Oct 11 10:55:00 2012
@@ -0,0 +1,108 @@
+#ifndef TEST_DB_H
+#define TEST_DB_H
+
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+#include <string>
+
+#include "database.h"
+#include "file_db.h"
+#include "file_storage.h"
+#include "sqlite_db.h"
+#include "util.h"
+
+DEFINE_string(database_test_dir, "/tmp",
+ "Test directory for databases that use the disk. We attempt
to "
+ "remove all created files and directories but data may be
left "
+ "behind if the program does not exit cleanly.");
+
+static const unsigned kCertStorageDepth = 3;
+static const unsigned kTreeStorageDepth = 8;
+
+class TmpStorage {
+ public:
+ TmpStorage()
+ : tmp_dir_(FLAGS_database_test_dir) {
+ file_base_ = util::CreateTemporaryDirectory(tmp_dir_ + "/ctlogXXXXXX");
+ CHECK_EQ(tmp_dir_ + "/ctlog", file_base_.substr(0, tmp_dir_.size() +
6));
+ CHECK_EQ(tmp_dir_.size() + 12, file_base_.length());
+ }
+
+ ~TmpStorage() {
+ // Check again that it is safe to empty file_base_.
+ CHECK_EQ(tmp_dir_ + "/ctlog", file_base_.substr(0, tmp_dir_.size() +
6));
+ CHECK_EQ(tmp_dir_.size() + 12, file_base_.length());
+
+ std::string command = "rm -r " + file_base_;
+ CHECK_ERR(system(command.c_str()))
+ << "Failed to delete temporary directory in " << file_base_;
+ }
+
+ std::string TmpStorageDir() const { return file_base_; }
+ private:
+ std::string tmp_dir_;
+ std::string file_base_;
+};
+
+// Helper for generating test instances of the databases for typed tests.
+template <class T>
+class TestDB {
+ public:
+ TestDB()
+ : tmp_() {
+ Setup();
+ }
+
+ ~TestDB() {
+ if (db_ != NULL)
+ delete db_;
+ }
+
+ void Setup();
+
+ T *db() const { return db_; }
+
+ // Build a second database from the current disk state. Caller owns
result.
+ // Meant to be used for testing resumes from disk.
+ // Concurrent behaviour is undefined (depends on the Database
implementation).
+ T *SecondDB() const;
+
+ private:
+ TmpStorage tmp_;
+ T *db_;
+};
+
+template <> void TestDB<FileDB>::Setup() {
+ std::string certs_dir = tmp_.TmpStorageDir() + "/certs";
+ std::string tree_dir = tmp_.TmpStorageDir() + "/tree";
+ CHECK_ERR(mkdir(certs_dir.c_str(), 0700));
+ CHECK_ERR(mkdir(tree_dir.c_str(), 0700));
+
+ db_ = new FileDB(new FileStorage(certs_dir, kCertStorageDepth),
+ new FileStorage(tree_dir, kTreeStorageDepth));
+}
+
+template <> FileDB *TestDB<FileDB>::SecondDB() const {
+ std::string certs_dir = this->tmp_.TmpStorageDir() + "/certs";
+ std::string tree_dir = this->tmp_.TmpStorageDir() + "/tree";
+ return new FileDB(new FileStorage(certs_dir, kCertStorageDepth),
+ new FileStorage(tree_dir, kTreeStorageDepth));
+}
+
+template <> void TestDB<SQLiteDB>::Setup() {
+ db_ = new SQLiteDB(tmp_.TmpStorageDir() + "/sqlite");
+}
+
+template <> SQLiteDB *TestDB<SQLiteDB>::SecondDB() const {
+ return new SQLiteDB(tmp_.TmpStorageDir() + "/sqlite");
+}
+
+// Not a Database; we just use the same template for setup.
+template <> void TestDB<FileStorage>::Setup() {
+ db_ = new FileStorage(tmp_.TmpStorageDir(), kCertStorageDepth);
+}
+
+template <> FileStorage *TestDB<FileStorage>::SecondDB() const {
+ return new FileStorage(tmp_.TmpStorageDir(), kCertStorageDepth);
+}
+#endif
=======================================
--- /dev/null
+++ /src/log/test_signer.cc Thu Oct 11 10:55:00 2012
@@ -0,0 +1,250 @@
+#include <glog/logging.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <stdlib.h>
+#include <string>
+
+#include "ct.pb.h"
+#include "log_signer.h"
+#include "serializer.h"
+#include "test_signer.h"
+#include "util.h"
+
+#include "serial_hasher.h"
+
+namespace {
+
+using ct::CertificateEntry;
+using ct::DigitallySigned;
+using ct::LoggedCertificate;
+using ct::SignedCertificateTimestamp;
+using ct::SignedTreeHead;
+using std::string;
+
+// A slightly shorter notation for constructing binary blobs from test
vectors.
+string B(const char *hexstring) {
+ return util::BinaryString(hexstring);
+}
+
+const char kDefaultDerCert[] =
+ "308202ca30820233a003020102020102300d06092a864886f70d01010505003055310b3009"
+ "06035504061302474231243022060355040a131b4365727469666963617465205472616e73"
+ "706172656e6379204341310e300c0603550408130557616c65733110300e06035504071307"
+ "4572772057656e301e170d3132303630313030303030305a170d3232303630313030303030"
+ "305a3052310b30090603550406130247423121301f060355040a1318436572746966696361"
+ "7465205472616e73706172656e6379310e300c0603550408130557616c65733110300e0603"
+ "55040713074572772057656e30819f300d06092a864886f70d010101050003818d00308189"
+ "02818100b8742267898b99ba6bfd6e6f7ada8e54337f58feb7227c46248437ba5f89b007cb"
+ "e1ecb4545b38ed23fddbf6b9742cafb638157f68184776a1b38ab39318ddd734489b4d7501"
+ "17cd83a220a7b52f295d1e18571469a581c23c68c57d973761d9787a091fb5864936b16653"
+ "5e21b427e3c6d690b2e91a87f36b7ec26f59ce53b50203010001a381ac3081a9301d060355"
+ "1d0e041604141184e1187c87956dffc31dd0521ff564efbeae8d307d0603551d2304763074"
+ "8014a3b8d89ba2690dfb48bbbf87c1039ddce56256c6a159a4573055310b30090603550406"
+ "1302474231243022060355040a131b4365727469666963617465205472616e73706172656e"
+ "6379204341310e300c0603550408130557616c65733110300e060355040713074572772057"
+ "656e82010030090603551d1304023000300d06092a864886f70d010105050003818100292e"
+ "cf6e46c7a0bcd69051739277710385363341c0a9049637279707ae23cc5128a4bdea0d480e"
+ "d0206b39e3a77a2b0c49b0271f4140ab75c1de57aba498e09459b479cf92a4d5d5dd5cbe3f"
+ "0a11e25f04078df88fc388b61b867a8de46216c0e17c31fc7d8003ecc37be22292f84242ab"
+ "87fb08bd4dfa3c1b9ce4d3ee6667da";
+
+const char kDefaultDerCertHash[] =
+ "50335d9cd3649871d0c95397648bf7814c297b3bad7020b2c13d2b0aef6e3b49";
+
+// Some time in September 2012.
+const uint64_t kDefaultSCTTimestamp = 1348589665525LL;
+
+const char kDefaultSCTSignature[] =
+ "3044022041dc1ec2dd47ad84bd1da5f88cf5bf0516476cd7822f1f5e8f59e624ee259a1d02"
+ "20522f61d5b0e6d00aa9fff2589e9918dfa8af3faa312ea037a20bc762f71c337c";
+
+// Some time in September 2012.
+const uint64_t kDefaultSTHTimestamp = 1348589667204LL;
+
+const uint64_t kDefaultTreeSize = 42;
+
+// *Some* hash that we pretend is a valid root hash.
+const char kDefaultRootHash[] =
+ "18041bd4665083001fba8c5411d2d748e8abbfdcdfd9218cb02b68a78e7d4c23";
+
+const char kDefaultSTHSignature[] =
+ "3045022066ab4e7eaad1961c34448ed5dd37959bed95476fc02476def57c63a91b52445c02"
+ "21009887b36a965e04e196753fac4a15cffbb86770bfacf74dfe6e259c967904fecc";
+
+const char kEcP256PrivateKey[] =
+ "-----BEGIN EC PRIVATE KEY-----\n"
+ "MHcCAQEEIG8QAquNnarN6Ik2cMIZtPBugh9wNRe0e309MCmDfBGuoAoGCCqGSM49\n"
+ "AwEHoUQDQgAES0AfBkjr7b8b19p5Gk8plSAN16wWXZyhYsH6FMCEUK60t7pem/ck\n"
+ "oPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
+ "-----END EC PRIVATE KEY-----\n";
+
+const char kEcP256PublicKey[] =
+ "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES0AfBkjr7b8b19p5Gk8plSAN16wW\n"
+ "XZyhYsH6FMCEUK60t7pem/ckoPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
+ "-----END PUBLIC KEY-----\n";
+
+EVP_PKEY* PrivateKeyFromPem(const string &pemkey) {
+ // BIO_new_mem_buf is read-only.
+ BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
+ EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+ assert(pkey != NULL);
+ BIO_free(bio);
+ return pkey;
+}
+
+EVP_PKEY* PublicKeyFromPem(const string &pemkey) {
+ BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
+ EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+ assert(pkey != NULL);
+ BIO_free(bio);
+ return pkey;
+}
+
+} // namespace
+
+TestSigner::TestSigner()
+ : default_signer_(NULL),
+ counter_(0),
+ default_cert_(B(kDefaultDerCert)) {
+ counter_ = util::TimeInMilliseconds();
+ srand(counter_);
+ EVP_PKEY *pkey = PrivateKeyFromPem(kEcP256PrivateKey);
+ CHECK_NOTNULL(pkey);
+ default_signer_ = new LogSigner(pkey);
+}
+
+TestSigner::~TestSigner() {
+ delete default_signer_;
+}
+
+// Caller owns result.
+// Call as many times as required to get a fresh copy every time.
+// static
+LogSigner *TestSigner::DefaultSigner() {
+ EVP_PKEY *pkey = PrivateKeyFromPem(kEcP256PrivateKey);
+ CHECK_NOTNULL(pkey);
+ return new LogSigner(pkey);
+}
+
+// Caller owns result.
+// Call as many times as required to get a fresh copy every time.
+//static
+LogSigVerifier *TestSigner::DefaultVerifier() {
+ EVP_PKEY *pubkey = PublicKeyFromPem(kEcP256PublicKey);
+ CHECK_NOTNULL(pubkey);
+ return new LogSigVerifier(pubkey);
+}
+
+// static
+void TestSigner::SetDefaults(SignedCertificateTimestamp *sct) {
+ sct->set_timestamp(kDefaultSCTTimestamp);
+ sct->mutable_entry()->set_type(CertificateEntry::X509_ENTRY);
+ sct->mutable_entry()->set_leaf_certificate(B(kDefaultDerCert));
+ sct->mutable_signature()->set_hash_algorithm(DigitallySigned::SHA256);
+ sct->mutable_signature()->set_sig_algorithm(DigitallySigned::ECDSA);
+ sct->mutable_signature()->set_signature(B(kDefaultSCTSignature));
+}
+
+// static
+void TestSigner::SetDefaults(LoggedCertificate *logged_cert) {
+ // Some time in September 2012.
+ SetDefaults(logged_cert->mutable_sct());
+ // FIXME(ekasper): don't assume SHA256 in test vectors
+ // (despite the field name).
+ logged_cert->set_certificate_sha256_hash(B(kDefaultDerCertHash));
+}
+
+// static
+void TestSigner::SetDefaults(SignedTreeHead *tree_head) {
+ tree_head->set_timestamp(kDefaultSTHTimestamp);
+ tree_head->set_tree_size(kDefaultTreeSize);
+ tree_head->set_root_hash(B(kDefaultRootHash));
+
tree_head->mutable_signature()->set_hash_algorithm(DigitallySigned::SHA256);
+
tree_head->mutable_signature()->set_sig_algorithm(DigitallySigned::ECDSA);
+ tree_head->mutable_signature()->set_signature(B(kDefaultSTHSignature));
+}
+
+string TestSigner::UniqueFakeCertBytestring() {
+ string counter_suffix = Serializer::SerializeUint(counter_++, 8);
+ int length = (rand() % 512) + 512 - counter_suffix.size();
+
+ string ret;
+ while (length >= 256) {
+ int offset = rand() & 0xff;
+ DCHECK_LE(offset + 256, default_cert_.size());
+ ret.append(default_cert_.substr(offset, 256));
+ length -=256;
+ }
+
+ if (length > 0) {
+ int offset = rand() & 0xff;
+ ret.append(default_cert_.substr(offset, length));
+ }
+
+ ret.append(counter_suffix);
+ return ret;
+}
+
+string TestSigner::UniqueHash() {
+ string counter = Serializer::SerializeUint(counter_++, 8);
+ return Sha256Hasher::Sha256Digest(counter);
+}
+
+void TestSigner::CreateUnique(CertificateEntry *entry) {
+ entry->set_leaf_certificate(UniqueFakeCertBytestring());
+ int random_bits = rand();
+ CertificateEntry::Type type = random_bits & 1 ?
+ CertificateEntry::X509_ENTRY : CertificateEntry::PRECERT_ENTRY;
+
+ entry->set_type(type);
+
+ entry->clear_intermediates();
+ if (random_bits & 2) {
+ entry->add_intermediates(UniqueFakeCertBytestring());
+
+ if (random_bits & 4) {
+ entry->add_intermediates(UniqueFakeCertBytestring());
+ }
+ }
+}
+
+void TestSigner::CreateUnique(LoggedCertificate *logged_cert) {
+ FillData(logged_cert);
+
+ CHECK_EQ(LogSigner::OK,
+ default_signer_->SignCertificateTimestamp(
+ logged_cert->mutable_sct()));
+}
+
+void TestSigner::CreateUniqueFakeSignature(LoggedCertificate *logged_cert)
{
+ FillData(logged_cert);
+
+ logged_cert->mutable_sct()->mutable_signature()->set_hash_algorithm(
+ DigitallySigned::SHA256);
+ logged_cert->mutable_sct()->mutable_signature()->set_sig_algorithm(
+ DigitallySigned::ECDSA);
+ logged_cert->mutable_sct()->mutable_signature()->set_signature(
+ B(kDefaultSCTSignature));
+}
+
+void TestSigner::CreateUnique(SignedTreeHead *sth) {
+ sth->set_timestamp(util::TimeInMilliseconds());
+ sth->set_tree_size(rand());
+ sth->set_root_hash(UniqueHash());
+ CHECK_EQ(LogSigner::OK,
+ default_signer_->SignTreeHead(sth));
+}
+
+void TestSigner::FillData(LoggedCertificate *logged_cert) {
+ logged_cert->mutable_sct()->set_timestamp(util::TimeInMilliseconds());
+
+ CreateUnique(logged_cert->mutable_sct()->mutable_entry());
+
+ logged_cert->set_certificate_sha256_hash(Sha256Hasher::Sha256Digest(
+ logged_cert->sct().entry().leaf_certificate()));
+
+ logged_cert->clear_sequence_number();
+}
=======================================
--- /dev/null
+++ /src/log/test_signer.h Thu Oct 11 10:55:00 2012
@@ -0,0 +1,74 @@
+#ifndef TEST_SIGNER_H
+#define TEST_SIGNER_H
+
+#include <stdint.h>
+#include <string>
+
+#include "ct.pb.h"
+#include "log_signer.h"
+
+// Helper class for database tests that generates test data
+// that roughly resembles real certificate data in shape and size.
+class TestSigner {
+ public:
+ TestSigner();
+ ~TestSigner();
+
+ static LogSigner *DefaultSigner();
+
+ static LogSigVerifier *DefaultVerifier();
+
+ // For KAT tests: an SCT with a valid signature.
+ static void SetDefaults( ct::SignedCertificateTimestamp *sct);
+
+ // For KAT tests: a logged cert with a valid hash and signature.
+ // TODO(ekasper): add an intermediate for better coverage.
+ static void SetDefaults(ct::LoggedCertificate *logged_cert);
+
+ // For KAT tests: a tree head with a valid signature.
+ // Uses SHA256 for the tree hash.
+ static void SetDefaults(ct::SignedTreeHead *tree_head);
+
+ // simulate a cert DER string - 512-1023 randomized (not random!) bytes.
+ // The bytes are obtained by (a) copying chunks of 256 bytes from
+ // offsets 0 - 255 of the default cert and (b) appending a counter value
+ // (derived from current time) to further guarantee no collisions.
+ // (Note that real DER certs always start with 0x30...)
+ std::string UniqueFakeCertBytestring();
+
+ // Sha256(counter).
+ std::string UniqueHash();
+
+ // Generates a randomized entry as follows:
+ // type - chosen randomly between all options
+ // leaf_certificate - 512-1023 randomized (not random!) bytes.
+ // intermediates - 50%, none; 25%, 1; 25%, 2.
+ void CreateUnique(ct::CertificateEntry *entry);
+
+ // timestamp - current
+ // signature - valid signature from the default signer
+ // hash - valid sha256 hash of the leaf certificate
+ // sequence number - cleared
+ void CreateUnique(ct::LoggedCertificate *logged_cert);
+
+ // Same as above but set the default signature to avoid overhead from
signing.
+ void CreateUniqueFakeSignature(ct::LoggedCertificate *logged_cert);
+
+ // Generates a randomized entry as follows:
+ // timestamp - current
+ // tree size - [0, RAND_MAX]
+ // root hash - random unique hash
+ // signature - valid on the above
+ void CreateUnique(ct::SignedTreeHead *sth);
+
+ private:
+ // Fill everything apart from the signature.
+ void FillData(ct::LoggedCertificate *logged_cert);
+ LogSigner *default_signer_;
+ // ct::SignedCertificateTimestamp default_sct_;
+ // ct::SignedTreeHead default_sth_;
+ uint64_t counter_;
+ // Binary blob.
+ std::string default_cert_;
+};
+#endif
=======================================
--- /src/log/submission_handler.cc Tue Oct 9 04:30:56 2012
+++ /dev/null
@@ -1,98 +0,0 @@
-#include "ct.pb.h"
-#include "serializer.h"
-#include "submission_handler.h"
-
-using ct::CertificateEntry;
-using std::string;
-
-SubmissionHandler::SubmitResult
-SubmissionHandler::ProcessSubmission(const string &submission,
- CertificateEntry *entry) {
- assert(entry != NULL);
- assert(entry->has_type());
-
- if (submission.empty())
- return EMPTY_SUBMISSION;
-
- SubmitResult submit_result = INVALID_TYPE;
- switch(entry->type()) {
- case CertificateEntry::X509_ENTRY:
- submit_result = ProcessX509Submission(submission, entry);
- break;
- case CertificateEntry::PRECERT_ENTRY:
- submit_result = ProcessPreCertSubmission(submission, entry);
- break;
- default:
- // We support all types, so we should currently never get here.
- assert(false);
- break;
- }
-
- if (submit_result != OK)
- return submit_result;
-
- Serializer::SerializeResult serialize_result =
- Serializer::CheckFormat(*entry);
- if (serialize_result != Serializer::OK)
- return GetFormatError(serialize_result);
-
- return OK;
-}
-
-// Default (for testing) - no verification,
-// just write the submission in the leaf cert field.
-SubmissionHandler::SubmitResult
-SubmissionHandler::ProcessX509Submission(const string &submission,
- CertificateEntry *entry) {
- entry->set_leaf_certificate(submission);
- return OK;
-}
-
-// Default (for testing) - no verification,
-// just write the submission in the leaf cert field.
-SubmissionHandler::SubmitResult
-SubmissionHandler::ProcessPreCertSubmission(const string &submission,
- CertificateEntry *entry) {
- entry->set_leaf_certificate(submission);
- return OK;
-}
-
-// static
-SubmissionHandler::SubmitResult
-SubmissionHandler::GetFormatError(Serializer::SerializeResult result) {
- SubmitResult submit_result = UNKNOWN_ERROR;
- switch (result) {
- // Since the submission handler checks that the submission is valid
- // for a given type, the only error we should be seeing here
- // is a chain whose canonical encoding is too long.
- // Anything else (invalid/empty certs) should be caught earlier.
- case Serializer::CERTIFICATE_TOO_LONG:
- case Serializer::CERTIFICATE_CHAIN_TOO_LONG:
- submit_result = SUBMISSION_TOO_LONG;
- break;
- default:
- assert(false);
- }
-
- return submit_result;
-}
-
-// static
-SubmissionHandler::SubmitResult
-SubmissionHandler::GetVerifyError(CertChecker::CertVerifyResult result) {
- SubmitResult submit_result = UNKNOWN_ERROR;
- switch (result) {
- case CertChecker::INVALID_CERTIFICATE_CHAIN:
- submit_result = INVALID_CERTIFICATE_CHAIN;
- break;
- case CertChecker::PRECERT_CHAIN_NOT_WELL_FORMED:
- submit_result = PRECERT_CHAIN_NOT_WELL_FORMED;
- break;
- case CertChecker::ROOT_NOT_IN_LOCAL_STORE:
- submit_result = UNKNOWN_ROOT;
- break;
- default:
- assert(false);
- }
- return submit_result;
-}
=======================================
--- /src/log/submission_handler.h Tue Oct 9 04:30:56 2012
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef SUBMISSION_HANDLER_H
-#define SUBMISSION_HANDLER_H
-
-#include "cert_checker.h"
-#include "ct.pb.h"
-#include "serializer.h"
-
-// The submission handler is responsible for parsing submissions and
-// deciding whether they are accepted for logging.
-class SubmissionHandler {
- public:
- SubmissionHandler() {}
- virtual ~SubmissionHandler() {}
-
- enum SubmitResult {
- OK,
- INVALID_TYPE,
- UNKNOWN_ERROR,
- EMPTY_SUBMISSION,
- SUBMISSION_TOO_LONG,
- CHAIN_NOT_LOADED,
- INVALID_PEM_ENCODED_CHAIN,
- INVALID_CERTIFICATE_CHAIN,
- PRECERT_CHAIN_NOT_WELL_FORMED,
- UNKNOWN_ROOT,
- };
-
- // entry should have the expected type set.
- SubmitResult ProcessSubmission(const std::string &submission,
- ct::CertificateEntry *entry);
-
- protected:
- virtual SubmitResult ProcessX509Submission(const std::string &submission,
- ct::CertificateEntry *entry);
- virtual SubmitResult ProcessPreCertSubmission(const std::string
&submission,
- ct::CertificateEntry
*entry);
-
- static SubmitResult GetFormatError(Serializer::SerializeResult result);
-
- static SubmitResult GetVerifyError(CertChecker::CertVerifyResult result);
-};
-#endif
=======================================
--- /src/log/submission_handler_test.cc Tue Oct 9 04:30:56 2012
+++ /dev/null
@@ -1,166 +0,0 @@
-#include <gtest/gtest.h>
-#include <openssl/ssl.h>
-#include <string>
-
-#include "cert_checker.h"
-#include "cert_submission_handler.h"
-#include "ct.pb.h"
-#include "util.h"
-
-static const char kCertDir[] = "../test/testdata";
-
-// Valid certificates.
-// Self-signed
-static const char kCaCert[] = "ca-cert.pem";
-// Issued by ca.pem
-static const char kLeafCert[] = "test-cert.pem";
-// Issued by ca.pem
-static const char kCaPreCert[] = "ca-pre-cert.pem";
-// Issued by ca-pre-cert.pem
-static const char kPreCert[] = "test-pre-cert.pem";
-// Issued by ca-cert.pem
-static const char kIntermediateCert[] = "intermediate-cert.pem";
-// Issued by intermediate-cert.pem
-static const char kChainLeafCert[] = "test2-cert.pem";
-
-namespace {
-
-using ct::CertificateEntry;
-using std::string;
-
-class CertSubmissionHandlerTest : public ::testing::Test {
- protected:
- string ca_;
- string leaf_;
- string ca_precert_;
- string precert_;
- string intermediate_;
- string chain_leaf_;
- string cert_dir_;
- CertSubmissionHandler *handler_;
- CertChecker *checker_;
-
- CertSubmissionHandlerTest() : handler_(NULL) {}
-
- void SetUp() {
- cert_dir_ = string(kCertDir);
- checker_ = new CertChecker();
- checker_->LoadTrustedCertificate(cert_dir_ + "/" + kCaCert);
- handler_ = new CertSubmissionHandler(checker_);
- ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kCaCert, &ca_));
- ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kLeafCert, &leaf_));
- ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kCaPreCert,
- &ca_precert_));
- ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kPreCert,
- &precert_));
- ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kIntermediateCert,
- &intermediate_));
- ASSERT_TRUE(util::ReadBinaryFile(cert_dir_ + "/" + kChainLeafCert,
- &chain_leaf_));
- }
-
- ~CertSubmissionHandlerTest() {
- delete checker_;
- delete handler_;
- }
-};
-
-TEST_F(CertSubmissionHandlerTest, SubmitCert) {
- CertificateEntry entry;
- entry.set_type(CertificateEntry::X509_ENTRY);
- // Submit a leaf cert.
- EXPECT_EQ(SubmissionHandler::OK, handler_->ProcessSubmission(leaf_,
&entry));
- EXPECT_TRUE(entry.has_leaf_certificate());
- EXPECT_EQ(0, entry.intermediates_size());
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitEmptyCert) {
- CertificateEntry entry;
- entry.set_type(CertificateEntry::X509_ENTRY);
- EXPECT_EQ(SubmissionHandler::EMPTY_SUBMISSION,
- handler_->ProcessSubmission("", &entry));
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitInvalidCert) {
- CertificateEntry entry;
- entry.set_type(CertificateEntry::X509_ENTRY);
- EXPECT_EQ(SubmissionHandler::INVALID_PEM_ENCODED_CHAIN,
- handler_->ProcessSubmission("-----BEGIN
CERTIFICATE-----\ninvalid"
- "\n-----END CERTIFICATE-----",
&entry));
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitChain) {
- // Submit a chain.
- string submit = chain_leaf_ + intermediate_;
- CertificateEntry entry;
- entry.set_type(CertificateEntry::X509_ENTRY);
- EXPECT_EQ(SubmissionHandler::OK, handler_->ProcessSubmission(submit,
&entry));
- EXPECT_TRUE(entry.has_leaf_certificate());
- EXPECT_EQ(1, entry.intermediates_size());
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitPartialChain) {
- CertificateEntry entry;
- entry.set_type(CertificateEntry::X509_ENTRY);
- // Submit a leaf cert with a missing intermediate.
- EXPECT_EQ(SubmissionHandler::UNKNOWN_ROOT,
- handler_->ProcessSubmission(chain_leaf_, &entry));
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitInvalidChain) {
- string invalid_submit = ca_;
- invalid_submit.append(leaf_);
- CertificateEntry entry;
- entry.set_type(CertificateEntry::X509_ENTRY);
- // An invalid chain with two certs in wrong order.
- EXPECT_EQ(SubmissionHandler::INVALID_CERTIFICATE_CHAIN,
- handler_->ProcessSubmission(invalid_submit, &entry));
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitCertAsPreCert) {
- CertificateEntry entry;
- entry.set_type(CertificateEntry::PRECERT_ENTRY);
- // Various things are wrong here, so do not expect a specific error.
- EXPECT_NE(SubmissionHandler::OK, handler_->ProcessSubmission(leaf_,
&entry));
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitCertChainAsPreCert) {
- string submit = chain_leaf_ + intermediate_;
- CertificateEntry entry;
- entry.set_type(CertificateEntry::PRECERT_ENTRY);
- EXPECT_NE(SubmissionHandler::OK, handler_->ProcessSubmission(submit,
&entry));
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitPreCertChain) {
- string submit = precert_ + ca_precert_;
- CertificateEntry entry;
- entry.set_type(CertificateEntry::PRECERT_ENTRY);
- EXPECT_EQ(SubmissionHandler::OK, handler_->ProcessSubmission(submit,
&entry));
- EXPECT_TRUE(entry.has_leaf_certificate());
- // |intermediates| is the entire precert chain (excluding root).
- EXPECT_EQ(2, entry.intermediates_size());
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitInvalidPreCertChain) {
- // In wrong order.
- string submit = ca_precert_ + precert_;
- CertificateEntry entry;
- entry.set_type(CertificateEntry::PRECERT_ENTRY);
- EXPECT_NE(SubmissionHandler::OK, handler_->ProcessSubmission(submit,
&entry));
-}
-
-TEST_F(CertSubmissionHandlerTest, SubmitPreCertChainAsCertChain) {
- string submit = precert_ + ca_precert_;
- CertificateEntry entry;
- entry.set_type(CertificateEntry::X509_ENTRY);
- // This should fail since ca_precert_ is not a CA cert (CA:false).
- EXPECT_NE(SubmissionHandler::OK, handler_->ProcessSubmission(submit,
&entry));
-}
-
-} // namespace
-
-int main(int argc, char**argv) {
- ::testing::InitGoogleTest(&argc, argv);
- SSL_library_init();
- return RUN_ALL_TESTS();
-}
=======================================
--- /.hgignore Mon Oct 8 02:51:26 2012
+++ /.hgignore Thu Oct 11 10:55:00 2012
@@ -20,10 +20,12 @@
^src/log/cert_checker_test$
^src/log/log_lookup_test$
^src/log/log_signer_test$
-^src/log/submission_handler_test$
+^src/log/cert_submission_handler_test$
^src/log/frontend_signer_test$
+^src/log/frontend_test$
^src/log/file_storage_test$
^src/log/database_test$
+^src/log/database_large_test$
^src/log/tree_signer_test$
.*\.pb.h$
.*\.pb.cc$
=======================================
--- /src/README Wed Oct 3 06:42:48 2012
+++ /src/README Thu Oct 11 10:55:00 2012
@@ -73,3 +73,21 @@

and run tests.

+-----TESTING AND LOGGING OPTIONS-----
+
+Note that several tests write files on disk. The default directory for
+storing temporary testdata is /tmp. You can change
+this by setting TMPDIR=<tmpdir> for make.
+
+End-to-end tests also create temporary certificate and server files in
+src/test/tmp
+All these files are cleaned up after a successful test run.
+
+For logging options, see
+http://google-glog.googlecode.com/svn/trunk/doc/glog.html
+
+By default, unit tests log to stderr, and log only messages with a FATAL
level
+(i.e., those that result in abnormal program termination).
+You can override the defaults with command-line flags.
+
+End-to-end tests log everything at INFO level and above.
=======================================
--- /src/client/Makefile Fri Oct 5 03:26:17 2012
+++ /src/client/Makefile Thu Oct 11 10:55:00 2012
@@ -13,8 +13,7 @@

OBJS= client.o log_client.o ssl_client.o ../merkletree/merkle_verifier.o \
../merkletree/serial_hasher.o ../merkletree/tree_hasher.o \
-../util/util.o ../log/cert.o \
-../log/log_signer.o ../log/log_verifier.o ../log/submission_handler.o \
+../util/util.o ../log/cert.o ../log/log_signer.o ../log/log_verifier.o \
../log/cert_submission_handler.o ../log/cert_checker.o \
../proto/ct.pb.o ../proto/serializer.o

=======================================
--- /src/client/ssl_client.cc Tue Oct 9 06:13:42 2012
+++ /src/client/ssl_client.cc Thu Oct 11 10:55:00 2012
@@ -78,7 +78,7 @@
LogVerifier *verifier, SignedCertificateTimestamp
*sct) {
CertificateEntry entry;
if (CertSubmissionHandler::X509ChainToEntry(chain, &entry) !=
- SubmissionHandler::OK)
+ CertSubmissionHandler::OK)
return LogVerifier::INVALID_FORMAT;

SignedCertificateTimestamp local_sct;
=======================================
--- /src/log/Makefile Mon Oct 8 02:51:26 2012
+++ /src/log/Makefile Thu Oct 11 10:55:00 2012
@@ -1,6 +1,6 @@
CXXFLAG= -Wall -Werror -O3 -g
INCLUDE= -I ../include -I $(GTESTDIR)/include -I $(PROTOBUFDIR)/src
-LIBS= $(GTESTDIR)/make/gtest.a -lpthread
$(PROTOBUFDIR)/src/.libs/libprotobuf.a -lglog -lssl -lcrypto -lsqlite3
+LIBS= $(GTESTDIR)/make/gtest.a -lpthread
$(PROTOBUFDIR)/src/.libs/libprotobuf.a -lgflags -lglog -lssl -lcrypto
-lsqlite3
# Need OpenSSL >= 1.0.0
ifneq ($(OPENSSLDIR),)
INCLUDE+= -I $(OPENSSLDIR)/include
@@ -11,9 +11,9 @@
LIBS+= -L /usr/local/lib
CXXFLAGS= $(INCLUDE) $(CXXFLAG)

-all: .depend cert_test cert_checker_test submission_handler_test \
+all: .depend cert_test cert_checker_test cert_submission_handler_test \
file_storage_test database_test frontend_signer_test tree_signer_test
\
- log_lookup_test
+ log_lookup_test database_large_test

# Preprocessing step for compiling .proto files.
../include/ct.pb.h: ../proto/ct.proto
@@ -27,18 +27,23 @@

include .depend

-test: cert_test cert_checker_test submission_handler_test log_signer_test \
+ifneq ($(TMPDIR),)
+ FLAGS= --database_test_dir=$(TMPDIR)
+endif
+
+test: cert_test cert_checker_test cert_submission_handler_test
log_signer_test \
file_storage_test database_test frontend_signer_test
tree_signer_test \
- log_lookup_test
+ log_lookup_test database_large_test
./cert_test
./cert_checker_test
- ./submission_handler_test
+ ./cert_submission_handler_test
./log_signer_test
- ./file_storage_test
- ./database_test
- ./frontend_signer_test
- ./tree_signer_test
- ./log_lookup_test
+ ./file_storage_test $(FLAGS)
+ ./database_test $(FLAGS)
+ ./frontend_signer_test $(FLAGS)
+ ./tree_signer_test $(FLAGS)
+ ./log_lookup_test $(FLAGS)
+# Do not run database large test by default

cert_test: cert_test.o cert.o ../util/util.o
$(CXX) -o cert_test cert_test.o cert.o ../util/util.o $(LIBS)
@@ -47,66 +52,98 @@
$(CXX) -o cert_checker_test cert_checker_test.o cert_checker.o cert.o \
../util/util.o $(LIBS)

-submission_handler_test: submission_handler_test.o submission_handler.o \
- cert_checker.o cert.o cert_submission_handler.o \
- ../util/util.o ../proto/ct.pb.o ../proto/serializer.o
- $(CXX) -o submission_handler_test submission_handler_test.o \
- submission_handler.o cert_checker.o cert.o ../util/util.o \
- ../proto/ct.pb.o ../proto/serializer.o \
- cert_submission_handler.o $(LIBS)
+cert_submission_handler_test: cert_submission_handler_test.o \
+ cert_checker.o cert.o cert_submission_handler.o \
+ ../util/util.o ../proto/ct.pb.o \
+ ../proto/serializer.o
+ $(CXX) -o cert_submission_handler_test cert_submission_handler_test.o \
+ cert_checker.o cert.o ../util/util.o ../proto/ct.pb.o \
+ ../proto/serializer.o cert_submission_handler.o $(LIBS)

log_signer_test: log_signer_test.o log_signer.o ../util/util.o \
- ../proto/ct.pb.o ../proto/serializer.o
+ ../proto/ct.pb.o ../proto/serializer.o test_signer.o \
+ ../merkletree/serial_hasher.o
$(CXX) -o log_signer_test log_signer_test.o log_signer.o \
- ../util/util.o ../proto/ct.pb.o ../proto/serializer.o $(LIBS)
+ ../util/util.o ../proto/ct.pb.o ../proto/serializer.o \
+ test_signer.o ../merkletree/serial_hasher.o $(LIBS)

file_storage_test: file_storage_test.o file_storage.o filesystem_op.o \
- ../util/util.o
+ ../util/util.o file_db.o sqlite_db.o ../proto/ct.pb.o \
+ ../proto/serializer.o
$(CXX) -o file_storage_test file_storage_test.o file_storage.o \
- filesystem_op.o ../util/util.o $(LIBS)
+ filesystem_op.o ../util/util.o file_db.o sqlite_db.o \
+ ../proto/ct.pb.o ../proto/serializer.o $(LIBS)

database_test: database_test.o file_db.o file_storage.o \
filesystem_op.o sqlite_db.o ../util/util.o ../proto/ct.pb.o \
- ../proto/serializer.o
+ ../proto/serializer.o test_signer.o log_signer.o \
+ ../merkletree/serial_hasher.o
$(CXX) -o database_test database_test.o file_db.o file_storage.o \
filesystem_op.o sqlite_db.o ../util/util.o ../proto/ct.pb.o \
- ../proto/serializer.o $(LIBS)
+ ../proto/serializer.o test_signer.o log_signer.o \
+ ../merkletree/serial_hasher.o $(LIBS)
+
+database_large_test: database_large_test.o file_db.o file_storage.o \
+ filesystem_op.o sqlite_db.o \
+ ../util/util.o ../proto/ct.pb.o \
+ ../proto/serializer.o test_signer.o log_signer.o \
+ ../merkletree/serial_hasher.o
+ $(CXX) -o database_large_test database_large_test.o file_db.o \
+ file_storage.o filesystem_op.o sqlite_db.o ../util/util.o \
+ ../proto/ct.pb.o ../proto/serializer.o test_signer.o \
+ log_signer.o ../merkletree/serial_hasher.o $(LIBS)

frontend_signer_test: frontend_signer_test.o frontend_signer.o \
- log_signer.o log_verifier.o submission_handler.o \
+ log_signer.o log_verifier.o test_signer.o \
../util/util.o ../proto/ct.pb.o ../proto/serializer.o \
- ../merkletree/serial_hasher.o ../merkletree/tree_hasher.o \
+ ../merkletree/serial_hasher.o \
+ ../merkletree/tree_hasher.o \
../merkletree/merkle_verifier.o file_db.o file_storage.o \
filesystem_op.o sqlite_db.o
$(CXX) -o frontend_signer_test frontend_signer_test.o \
- frontend_signer.o log_signer.o log_verifier.o \
- submission_handler.o ../util/util.o \
- ../proto/ct.pb.o ../proto/serializer.o \
+ frontend_signer.o log_signer.o log_verifier.o test_signer.o \
+ ../util/util.o ../proto/ct.pb.o ../proto/serializer.o \
../merkletree/serial_hasher.o ../merkletree/tree_hasher.o \
../merkletree/merkle_verifier.o file_db.o file_storage.o \
filesystem_op.o sqlite_db.o $(LIBS)

+frontend_test: frontend_test.o frontend_test.o frontend.o
frontend_signer.o \
+ log_signer.o log_verifier.o test_signer.o \
+ cert.o cert_checker.o cert_submission_handler.o \
+ ../util/util.o ../proto/ct.pb.o ../proto/serializer.o \
+ ../merkletree/serial_hasher.o ../merkletree/tree_hasher.o \
+ ../merkletree/merkle_verifier.o file_db.o file_storage.o \
+ filesystem_op.o sqlite_db.o
+ $(CXX) -o frontend_test frontend_test.o frontend.o frontend_signer.o \
+ log_signer.o log_verifier.o test_signer.o \
+ cert.o cert_checker.o cert_submission_handler.o \
+ ../util/util.o ../proto/ct.pb.o ../proto/serializer.o \
+ ../merkletree/serial_hasher.o ../merkletree/tree_hasher.o \
+ ../merkletree/merkle_verifier.o file_db.o file_storage.o \
+ filesystem_op.o sqlite_db.o $(LIBS)
+
tree_signer_test: tree_signer_test.o tree_signer.o log_signer.o
log_verifier.o \
../util/util.o ../proto/ct.pb.o ../proto/serializer.o \
../merkletree/serial_hasher.o ../merkletree/tree_hasher.o \
../merkletree/merkle_tree.o ../merkletree/merkle_verifier.o \
- file_db.o file_storage.o filesystem_op.o sqlite_db.o
+ file_db.o file_storage.o filesystem_op.o sqlite_db.o \
+ test_signer.o
$(CXX) -o tree_signer_test tree_signer_test.o tree_signer.o \
log_signer.o log_verifier.o ../util/util.o ../proto/ct.pb.o \
../proto/serializer.o ../merkletree/serial_hasher.o \
../merkletree/tree_hasher.o ../merkletree/merkle_tree.o \
../merkletree/merkle_verifier.o file_db.o file_storage.o \
- filesystem_op.o sqlite_db.o $(LIBS)
+ filesystem_op.o sqlite_db.o test_signer.o $(LIBS)

log_lookup_test: log_lookup_test.o log_lookup.o tree_signer.o log_signer.o
\
log_verifier.o ../util/util.o ../proto/ct.pb.o \
../proto/serializer.o ../merkletree/serial_hasher.o \
../merkletree/tree_hasher.o ../merkletree/merkle_tree.o \
../merkletree/merkle_verifier.o file_db.o file_storage.o \
- filesystem_op.o sqlite_db.o
+ filesystem_op.o sqlite_db.o test_signer.o
$(CXX) -o log_lookup_test log_lookup_test.o log_lookup.o tree_signer.o \
log_signer.o log_verifier.o ../util/util.o ../proto/ct.pb.o \
../proto/serializer.o ../merkletree/serial_hasher.o \
../merkletree/tree_hasher.o ../merkletree/merkle_tree.o \
../merkletree/merkle_verifier.o file_db.o file_storage.o \
- filesystem_op.o sqlite_db.o $(LIBS)
+ filesystem_op.o sqlite_db.o test_signer.o $(LIBS)
=======================================
--- /src/log/cert.cc Tue Oct 9 04:30:56 2012
+++ /src/log/cert.cc Thu Oct 11 10:55:00 2012
@@ -1,4 +1,5 @@
#include <assert.h>
+#include <glog/logging.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/err.h>
@@ -137,6 +138,14 @@
OPENSSL_free(der_buf);
return ret;
}
+
+string Cert::Sha256Digest() const {
+ assert(IsLoaded());
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int len;
+ CHECK_EQ(1, X509_digest(x509_, EVP_sha256(), digest, &len));
+ return string(reinterpret_cast<char*>(digest), len);
+}

// WARNING WARNING this method modifies the x509_ structure
// and thus invalidates the cert. Use with care.
=======================================
--- /src/log/cert.h Tue Oct 9 04:30:56 2012
+++ /src/log/cert.h Thu Oct 11 10:55:00 2012
@@ -57,6 +57,8 @@
// returns binary data
std::string DerEncoding() const;

+ std::string Sha256Digest() const;
+
// WARNING WARNING The following methods modify the x509_ structure
// and thus invalidate the cert.
// They are mostly needed for processing precerts. Use with care.
=======================================
--- /src/log/cert_submission_handler.cc Tue Oct 9 04:30:56 2012
+++ /src/log/cert_submission_handler.cc Thu Oct 11 10:55:00 2012
@@ -1,4 +1,4 @@
-#include <assert.h>
+#include <glog/logging.h>
#include <string>

#include "cert.h"
@@ -11,12 +11,44 @@
using std::string;

CertSubmissionHandler::CertSubmissionHandler(CertChecker *cert_checker)
- : cert_checker_(cert_checker) {
- assert(cert_checker_ != NULL);
+ : cert_checker_(cert_checker) {}
+
+CertSubmissionHandler::SubmitResult
+CertSubmissionHandler::ProcessSubmission(const string &submission,
+ CertificateEntry *entry) {
+ CHECK_NOTNULL(entry);
+ CHECK(entry->has_type());
+
+ if (submission.empty())
+ return EMPTY_SUBMISSION;
+
+ SubmitResult submit_result = INVALID_TYPE;
+ switch (entry->type()) {
+ case CertificateEntry::X509_ENTRY:
+ submit_result = ProcessX509Submission(submission, entry);
+ break;
+ case CertificateEntry::PRECERT_ENTRY:
+ submit_result = ProcessPreCertSubmission(submission, entry);
+ break;
+ default:
+ // We support all types, so we should currently never get here.
+ LOG(FATAL) << "Unknown entry type " << entry->type();
+ break;
+ }
+
+ if (submit_result != OK)
+ return submit_result;
+
+ Serializer::SerializeResult serialize_result =
+ Serializer::CheckFormat(*entry);
+ if (serialize_result != Serializer::OK)
+ return GetFormatError(serialize_result);
+
+ return OK;
}

// static
-SubmissionHandler::SubmitResult
+CertSubmissionHandler::SubmitResult
CertSubmissionHandler::X509ChainToEntry(const CertChain &chain,
CertificateEntry *entry) {
if (!chain.IsLoaded())
@@ -39,7 +71,7 @@

// Inputs must be concatenated PEM entries.
// Format checking is done in the parent class.
-SubmissionHandler::SubmitResult
+CertSubmissionHandler::SubmitResult
CertSubmissionHandler::ProcessX509Submission(const string &submission,
CertificateEntry *entry) {
string pem_string(reinterpret_cast<const char*>(submission.data()),
@@ -62,7 +94,7 @@
return OK;
}

-SubmissionHandler::SubmitResult
+CertSubmissionHandler::SubmitResult
CertSubmissionHandler::ProcessPreCertSubmission(const string &submission,
CertificateEntry *entry) {
string pem_string(reinterpret_cast<const char*>(submission.data()),
@@ -90,7 +122,8 @@
return string();

Cert *tbs = chain.PreCert()->Clone();
- assert(tbs != NULL && tbs->IsLoaded());
+ CHECK_NOTNULL(tbs);
+ CHECK(tbs->IsLoaded());

// Remove the poison extension and the signature.
tbs->DeleteExtension(Cert::kPoisonExtensionOID);
@@ -98,7 +131,8 @@

// Fix the issuer.
const Cert *ca_precert = chain.CaPreCert();
- assert(ca_precert != NULL && ca_precert->IsLoaded());
+ CHECK_NOTNULL(ca_precert);
+ CHECK(ca_precert->IsLoaded());
tbs->CopyIssuerFrom(*ca_precert);

string der_cert = tbs->DerEncoding();
@@ -111,7 +145,8 @@
return string();

const Cert *leaf = chain.LeafCert();
- assert(leaf != NULL && leaf->IsLoaded());
+ CHECK_NOTNULL(leaf);
+ CHECK(leaf->IsLoaded());

Cert *tbs = leaf->Clone();

@@ -123,3 +158,43 @@
delete tbs;
return der_cert;
}
+
+// static
+CertSubmissionHandler::SubmitResult
+CertSubmissionHandler::GetFormatError(Serializer::SerializeResult result) {
+ SubmitResult submit_result;
+ switch (result) {
+ // Since the submission handler checks that the submission is valid
+ // for a given type, the only error we should be seeing here
+ // is a chain whose canonical encoding is too long.
+ // Anything else (invalid/empty certs) should be caught earlier.
+ case Serializer::CERTIFICATE_TOO_LONG:
+ case Serializer::CERTIFICATE_CHAIN_TOO_LONG:
+ submit_result = SUBMISSION_TOO_LONG;
+ break;
+ default:
+ LOG(FATAL) << "Unknown Serializer error " << result;
+ }
+
+ return submit_result;
+}
+
+// static
+CertSubmissionHandler::SubmitResult
+CertSubmissionHandler::GetVerifyError(CertChecker::CertVerifyResult
result) {
+ SubmitResult submit_result;
+ switch (result) {
+ case CertChecker::INVALID_CERTIFICATE_CHAIN:
+ submit_result = INVALID_CERTIFICATE_CHAIN;
+ break;
+ case CertChecker::PRECERT_CHAIN_NOT_WELL_FORMED:
+ submit_result = PRECERT_CHAIN_NOT_WELL_FORMED;
+ break;
+ case CertChecker::ROOT_NOT_IN_LOCAL_STORE:
+ submit_result = UNKNOWN_ROOT;
+ break;
+ default:
+ LOG(FATAL) << "Unknown CertChecker error " << result;
+ }
+ return submit_result;
+}
=======================================
--- /src/log/cert_submission_handler.h Tue Oct 9 04:30:56 2012
+++ /src/log/cert_submission_handler.h Thu Oct 11 10:55:00 2012
@@ -5,25 +5,40 @@

#include "cert_checker.h"
#include "ct.pb.h"
-#include "submission_handler.h"
+#include "serializer.h"

// Parse incoming submissions, do preliminary sanity checks and pass them
// through cert checker.
// Prepare for signing by parsing the input into an appropriate
// log entry structure.
-class CertSubmissionHandler : public SubmissionHandler {
+class CertSubmissionHandler {
public:
// Does not take ownership of the cert_checker.
- CertSubmissionHandler(CertChecker *cert_checker);
+ explicit CertSubmissionHandler(CertChecker *cert_checker);
~CertSubmissionHandler() {}

+ enum SubmitResult {
+ OK,
+ INVALID_TYPE,
+ EMPTY_SUBMISSION,
+ SUBMISSION_TOO_LONG,
+ CHAIN_NOT_LOADED,
+ INVALID_PEM_ENCODED_CHAIN,
+ INVALID_CERTIFICATE_CHAIN,
+ PRECERT_CHAIN_NOT_WELL_FORMED,
+ UNKNOWN_ROOT,
+ };
+
+ // entry should have the expected type set.
+ SubmitResult ProcessSubmission(const std::string &submission,
+ ct::CertificateEntry *entry);

// For clients, to reconstruct the bytestring under the signature
// from the observed chain.
static SubmitResult X509ChainToEntry(const CertChain &chain,
ct::CertificateEntry *entry);

- protected:
+ private:
SubmitResult ProcessX509Submission(const std::string &submission,
ct::CertificateEntry *entry);

@@ -31,10 +46,13 @@
SubmitResult ProcessPreCertSubmission(const std::string &submission,
ct::CertificateEntry *entry);

- private:
static std::string TbsCertificate(const CertChain &chain);
static std::string TbsCertificate(const PreCertChain &chain);

CertChecker *cert_checker_;
+
+ static SubmitResult GetFormatError(Serializer::SerializeResult result);
+
+ static SubmitResult GetVerifyError(CertChecker::CertVerifyResult result);
};
#endif
=======================================
--- /src/log/database.h Tue Oct 9 06:20:07 2012
+++ /src/log/database.h Thu Oct 11 10:55:00 2012
@@ -3,6 +3,7 @@
#ifndef DATABASE_H
#define DATABASE_H

+#include <glog/logging.h>
#include <set>

#include "ct.pb.h"
@@ -34,6 +35,16 @@
};

virtual ~Database() {}
+
+ virtual bool Transactional() const { return false; }
+
+ virtual void BeginTransaction() {
+ DLOG(FATAL) << "Transactions not supported";
+ }
+
+ virtual void EndTransaction() {
+ DLOG(FATAL) << "Transactions not supported";
+ }

// Attempt to create a new entry. Fail if no certificate hash is given,
// or an entry with this hash already exists.
=======================================
--- /src/log/database_test.cc Tue Oct 9 04:30:56 2012
+++ /src/log/database_test.cc Thu Oct 11 10:55:00 2012
@@ -1,16 +1,17 @@
/* -*- indent-tabs-mode: nil -*- */

+#include <gflags/gflags.h>
+#include <glog/logging.h>
#include <gtest/gtest.h>
-#include <iostream>
#include <set>
-#include <stdint.h>
#include <string>
-#include <sys/stat.h>

#include "database.h"
#include "file_db.h"
#include "file_storage.h"
#include "sqlite_db.h"
+#include "test_db.h"
+#include "test_signer.h"
#include "util.h"

namespace {
@@ -21,178 +22,25 @@
using ct::SignedTreeHead;
using std::string;

-const unsigned kCertStorageDepth = 3;
-const unsigned kTreeStorageDepth = 8;
-
-// A slightly shorter notation for constructing binary blobs from test
vectors.
-string B(const char *hexstring) {
- return util::BinaryString(hexstring);
-}
-
-// The reverse.
+// A slightly shorter notation for constructing hex strings from binary
blobs.
string H(const string &byte_string) {
return util::HexString(byte_string);
}
-
-const char kDefaultHash[] =
- "18041bd4665083001fba8c5411d2d748e8abbfdcdfd9218cb02b68a78e7d4c23";
-
-const char kAlternativeHash[] =
- "3bfb960453ebaebf33727da7a1f4db38acc051d381b6da20d6d4e88f0eabfd7a";
-
-const char kDefaultSignature[] =
- "3046022100ee89fb556fd72264098e8c80da9141c2aa2a788587bcc73d235ff7fd42dd5a11"
- "022100a3df4dd9c6cc6374ec1a7ba06d3a3c791e542287819fe1a15ca134d9cbb8bb74";
-
-const char kDefaultDerCert[] =
- "308202ca30820233a003020102020102300d06092a864886f70d01010505003055310b3009"
- "06035504061302474231243022060355040a131b4365727469666963617465205472616e73"
- "706172656e6379204341310e300c0603550408130557616c65733110300e06035504071307"
- "4572772057656e301e170d3132303630313030303030305a170d3232303630313030303030"
- "305a3052310b30090603550406130247423121301f060355040a1318436572746966696361"
- "7465205472616e73706172656e6379310e300c0603550408130557616c65733110300e0603"
- "55040713074572772057656e30819f300d06092a864886f70d010101050003818d00308189"
- "02818100b8742267898b99ba6bfd6e6f7ada8e54337f58feb7227c46248437ba5f89b007cb"
- "e1ecb4545b38ed23fddbf6b9742cafb638157f68184776a1b38ab39318ddd734489b4d7501"
- "17cd83a220a7b52f295d1e18571469a581c23c68c57d973761d9787a091fb5864936b16653"
- "5e21b427e3c6d690b2e91a87f36b7ec26f59ce53b50203010001a381ac3081a9301d060355"
- "1d0e041604141184e1187c87956dffc31dd0521ff564efbeae8d307d0603551d2304763074"
- "8014a3b8d89ba2690dfb48bbbf87c1039ddce56256c6a159a4573055310b30090603550406"
- "1302474231243022060355040a131b4365727469666963617465205472616e73706172656e"
- "6379204341310e300c0603550408130557616c65733110300e060355040713074572772057"
- "656e82010030090603551d1304023000300d06092a864886f70d010105050003818100292e"
- "cf6e46c7a0bcd69051739277710385363341c0a9049637279707ae23cc5128a4bdea0d480e"
- "d0206b39e3a77a2b0c49b0271f4140ab75c1de57aba498e09459b479cf92a4d5d5dd5cbe3f"
- "0a11e25f04078df88fc388b61b867a8de46216c0e17c31fc7d8003ecc37be22292f84242ab"
- "87fb08bd4dfa3c1b9ce4d3ee6667da";

template <class T> class DBTest : public ::testing::Test {
protected:
DBTest() :
- db_(NULL),
- logged_cert_(),
- tree_head_() {
- // Some time in September 2012.
- logged_cert_.mutable_sct()->set_timestamp(1348589665525LL);
- logged_cert_.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert_.mutable_sct()->mutable_entry()->set_leaf_certificate(
- B(kDefaultDerCert));
- logged_cert_.mutable_sct()->mutable_signature()->set_hash_algorithm(
- DigitallySigned::SHA256);
- logged_cert_.mutable_sct()->mutable_signature()->set_sig_algorithm(
- DigitallySigned::ECDSA);
- logged_cert_.mutable_sct()->mutable_signature()->set_signature(
- B(kDefaultSignature));
- // FIXME(ekasper): don't assume SHA256 in test vectors
- // (despite the field name).
- logged_cert_.set_certificate_sha256_hash(B(kDefaultHash));
+ test_db_(),
+ test_signer_() { }

- tree_head_.set_timestamp(1348589665525LL);
- tree_head_.set_tree_size(42);
- tree_head_.set_root_hash(B(kDefaultHash));
- tree_head_.mutable_signature()->set_hash_algorithm(
- DigitallySigned::SHA256);
- tree_head_.mutable_signature()->set_sig_algorithm(
- DigitallySigned::ECDSA);
- tree_head_.mutable_signature()->set_signature(B(kDefaultSignature));
- }
+ ~DBTest() {}

- void SetUp();
- void TearDown();
- // provide a second reference to the same test database
- Database *SecondDB();
+ T *db() const { return test_db_.db(); }

- const LoggedCertificate &DefaultLoggedCert() const {
- return logged_cert_;
- }
-
- const SignedTreeHead &DefaultTreeHead() const {
- return tree_head_;
- }
-
- const uint64_t DefaultTimestamp() const {
- return logged_cert_.sct().timestamp();
- }
-
- const string DefaultHash() const {
- return logged_cert_.certificate_sha256_hash();
- }
-
- const string AlternativeHash() const {
- return B(kAlternativeHash);
- }
-
- const uint64_t DefaultTreeSize() const {
- return tree_head_.tree_size();
- }
-
- ~DBTest() {
- if (db_ != NULL)
- delete db_;
- }
-
- Database *db_;
- string file_base_;
- LoggedCertificate logged_cert_;
- SignedTreeHead tree_head_;
+ TestDB<T> test_db_;
+ TestSigner test_signer_;
};

-template <> void DBTest<FileDB>::SetUp() {
- file_base_ = util::CreateTemporaryDirectory("/tmp/ctlogXXXXXX");
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- string certs_dir = file_base_ + "/certs";
- string tree_dir = file_base_ + "/tree";
- int ret = mkdir(certs_dir.c_str(), 0700);
- ASSERT_EQ(ret, 0);
- ret = mkdir(tree_dir.c_str(), 0700);
- ASSERT_EQ(ret, 0);
-
- db_ = new FileDB(new FileStorage(certs_dir, kCertStorageDepth),
- new FileStorage(tree_dir, kTreeStorageDepth));
-}
-
-template <> void DBTest<FileDB>::TearDown() {
- // Check again that it is safe to empty file_base_.
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- string command = "rm -r " + file_base_;
- int ret = system(command.c_str());
- if (ret != 0)
- std::cout << "Failed to delete temporary directory in "
- << file_base_ << std::endl;
-}
-
-template <> Database *DBTest<FileDB>::SecondDB() {
- string certs_dir = this->file_base_ + "/certs";
- string tree_dir = this->file_base_ + "/tree";
- return new FileDB(new FileStorage(certs_dir, kCertStorageDepth),
- new FileStorage(tree_dir, kTreeStorageDepth));
-}
-
-template <> void DBTest<SQLiteDB>::SetUp() {
- file_base_ = util::CreateTemporaryDirectory("/tmp/ctlogXXXXXX");
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- db_ = new SQLiteDB(file_base_ + "/ct");
-}
-
-template <> void DBTest<SQLiteDB>::TearDown() {
- // Check again that it is safe to empty file_base_.
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- string command = "rm -r " + file_base_;
- int ret = system(command.c_str());
- if (ret != 0)
- std::cout << "Failed to delete temporary directory in "
- << file_base_ << std::endl;
-}
-
-template <> Database *DBTest<SQLiteDB>::SecondDB() {
- return new SQLiteDB(file_base_ + "/ct");
-}
-
typedef testing::Types<FileDB, SQLiteDB> Databases;

TYPED_TEST_CASE(DBTest, Databases);
@@ -228,238 +76,251 @@
}

TYPED_TEST(DBTest, CreatePending) {
- LoggedCertificate lookup_cert;
+ LoggedCertificate logged_cert, lookup_cert;
+ this->test_signer_.CreateUnique(&logged_cert);

EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(
- this->DefaultLoggedCert()));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

EXPECT_EQ(Database::LOOKUP_OK,
- this->db_->LookupCertificateByHash(this->DefaultHash(),
- &lookup_cert));
- CompareLoggedCerts(this->DefaultLoggedCert(), lookup_cert);
+ this->db()->LookupCertificateByHash(
+ logged_cert.certificate_sha256_hash(), &lookup_cert));
+ CompareLoggedCerts(logged_cert, lookup_cert);
+
+ string similar_hash = logged_cert.certificate_sha256_hash();
+ similar_hash[similar_hash.size() - 1] ^= 1;

EXPECT_EQ(Database::NOT_FOUND,
- this->db_->LookupCertificateByHash(this->AlternativeHash(),
- &lookup_cert));
+ this->db()->LookupCertificateByHash(similar_hash,
+ &lookup_cert));
+ EXPECT_EQ(Database::NOT_FOUND,
+
this->db()->LookupCertificateByHash(this->test_signer_.UniqueHash(),
+ &lookup_cert));
}

-TYPED_TEST(DBTest, GetPending) {
- LoggedCertificate logged_cert;
- logged_cert.CopyFrom(this->DefaultLoggedCert());
- logged_cert.set_certificate_sha256_hash(this->AlternativeHash());
+TYPED_TEST(DBTest, GetPendingHashes) {
+ LoggedCertificate logged_cert, logged_cert2;
+ this->test_signer_.CreateUnique(&logged_cert);
+ this->test_signer_.CreateUnique(&logged_cert2);

EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(
- this->DefaultLoggedCert()));
+ this->db()->CreatePendingCertificateEntry(logged_cert));
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert2));

std::set<string> hashes;
- hashes.insert(this->DefaultHash());
- hashes.insert(this->AlternativeHash());
+ hashes.insert(logged_cert.certificate_sha256_hash());
+ hashes.insert(logged_cert2.certificate_sha256_hash());

- std::set<string> pending_hashes = this->db_->PendingHashes();
+ std::set<string> pending_hashes = this->db()->PendingHashes();
EXPECT_EQ(hashes, pending_hashes);
}

TYPED_TEST(DBTest, CreatePendingDuplicate) {
- LoggedCertificate logged_cert, lookup_cert;
- logged_cert.CopyFrom(this->DefaultLoggedCert());
- // Change the timestamp.
- logged_cert.mutable_sct()->set_timestamp(this->DefaultTimestamp() +
1000);
+ LoggedCertificate logged_cert, duplicate_cert, lookup_cert;
+ this->test_signer_.CreateUnique(&logged_cert);
+
+ duplicate_cert.CopyFrom(logged_cert);
+ // Change the timestamp so that we can check that we get the right thing
back.
+ duplicate_cert.mutable_sct()->set_timestamp(
+ logged_cert.sct().timestamp() + 1000);

EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(
- this->DefaultLoggedCert()));
+ this->db()->CreatePendingCertificateEntry(logged_cert));
+
EXPECT_EQ(Database::DUPLICATE_CERTIFICATE_HASH,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(duplicate_cert));

EXPECT_EQ(Database::LOOKUP_OK,
- this->db_->LookupCertificateByHash(this->DefaultHash(),
- &lookup_cert));
- // Check that we get the original entry back.
- CompareLoggedCerts(this->DefaultLoggedCert(), lookup_cert);
+ this->db()->LookupCertificateByHash(
+ logged_cert.certificate_sha256_hash(), &lookup_cert));
+ // Check that we get the original entry back.
+ CompareLoggedCerts(logged_cert, lookup_cert);
}

TYPED_TEST(DBTest, AssignSequenceNumber) {
- LoggedCertificate lookup_cert;
+ LoggedCertificate logged_cert, lookup_cert;
+ this->test_signer_.CreateUnique(&logged_cert);

EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(
- this->DefaultLoggedCert()));
+ this->db()->CreatePendingCertificateEntry(logged_cert));
EXPECT_EQ(Database::OK,
- this->db_->AssignCertificateSequenceNumber(this->DefaultHash(),
- 42));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 42));

EXPECT_EQ(Database::LOOKUP_OK,
- this->db_->LookupCertificateByHash(this->DefaultHash(),
- &lookup_cert));
+ this->db()->LookupCertificateByHash(
+ logged_cert.certificate_sha256_hash(), &lookup_cert));
EXPECT_EQ(42U, lookup_cert.sequence_number());

lookup_cert.clear_sequence_number();
- CompareLoggedCerts(this->DefaultLoggedCert(), lookup_cert);
+ CompareLoggedCerts(logged_cert, lookup_cert);
}

TYPED_TEST(DBTest, AssignSequenceNumberNotPending) {
+ LoggedCertificate logged_cert;
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::ENTRY_NOT_FOUND,
-
this->db_->AssignCertificateSequenceNumber(this->DefaultHash(), 0));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 0));

EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(
- this->DefaultLoggedCert()));
+ this->db()->CreatePendingCertificateEntry(logged_cert));
EXPECT_EQ(Database::OK,
- this->db_->AssignCertificateSequenceNumber(this->DefaultHash(),
- 42));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 42));

EXPECT_EQ(Database::ENTRY_ALREADY_LOGGED,
- this->db_->AssignCertificateSequenceNumber(this->DefaultHash(),
- 42));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 42));
}

TYPED_TEST(DBTest, AssignSequenceNumberTwice) {
- LoggedCertificate logged_cert;
- logged_cert.CopyFrom(this->DefaultLoggedCert());
- logged_cert.set_certificate_sha256_hash(this->AlternativeHash());
+ LoggedCertificate logged_cert, logged_cert2;
+ this->test_signer_.CreateUnique(&logged_cert);
+ this->test_signer_.CreateUnique(&logged_cert2);

EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(
- this->DefaultLoggedCert()));
+ this->db()->CreatePendingCertificateEntry(logged_cert));
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert2));
EXPECT_EQ(Database::OK,
- this->db_->AssignCertificateSequenceNumber(
- this->DefaultHash(), 42));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 42));
EXPECT_EQ(Database::SEQUENCE_NUMBER_ALREADY_IN_USE,
-
this->db_->AssignCertificateSequenceNumber(this->AlternativeHash(),
- 42));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert2.certificate_sha256_hash(), 42));
}

TYPED_TEST(DBTest, LookupBySequenceNumber) {
- LoggedCertificate logged_cert, lookup_cert0, lookup_cert1;
- logged_cert.CopyFrom(this->DefaultLoggedCert());
- logged_cert.set_certificate_sha256_hash(this->AlternativeHash());
- logged_cert.mutable_sct()->set_timestamp(this->DefaultTimestamp() +
1000);
+ LoggedCertificate logged_cert, logged_cert2, lookup_cert, lookup_cert2;
+ this->test_signer_.CreateUnique(&logged_cert);
+ this->test_signer_.CreateUnique(&logged_cert2);

EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(
- this->DefaultLoggedCert()));
+ this->db()->CreatePendingCertificateEntry(logged_cert));
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert2));
EXPECT_EQ(Database::OK,
- this->db_->AssignCertificateSequenceNumber(
- this->DefaultHash(), 42));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 42));
EXPECT_EQ(Database::OK,
-
this->db_->AssignCertificateSequenceNumber(this->AlternativeHash(),
- 22));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert2.certificate_sha256_hash(), 22));

EXPECT_EQ(Database::NOT_FOUND,
- this->db_->LookupCertificateByIndex(23, &lookup_cert0));
+ this->db()->LookupCertificateByIndex(23, &lookup_cert));

EXPECT_EQ(Database::LOOKUP_OK,
- this->db_->LookupCertificateByIndex(42, &lookup_cert0));
- EXPECT_EQ(42U, lookup_cert0.sequence_number());
+ this->db()->LookupCertificateByIndex(42, &lookup_cert));
+ EXPECT_EQ(42U, lookup_cert.sequence_number());

- lookup_cert0.clear_sequence_number();
- CompareLoggedCerts(this->DefaultLoggedCert(), lookup_cert0);
+ lookup_cert.clear_sequence_number();
+ CompareLoggedCerts(logged_cert, lookup_cert);

EXPECT_EQ(Database::LOOKUP_OK,
- this->db_->LookupCertificateByIndex(22, &lookup_cert1));
- EXPECT_EQ(22U, lookup_cert1.sequence_number());
- EXPECT_EQ(this->DefaultTimestamp() + 1000,
lookup_cert1.sct().timestamp());
+ this->db()->LookupCertificateByIndex(22, &lookup_cert2));
+ EXPECT_EQ(22U, lookup_cert2.sequence_number());
+
+ lookup_cert2.clear_sequence_number();
+ CompareLoggedCerts(logged_cert2, lookup_cert2);
}

TYPED_TEST(DBTest, WriteTreeHead) {
- SignedTreeHead lookup_sth;
+ SignedTreeHead sth, lookup_sth;
+ this->test_signer_.CreateUnique(&sth);

- EXPECT_EQ(Database::NOT_FOUND, this->db_->LatestTreeHead(&lookup_sth));
+ EXPECT_EQ(Database::NOT_FOUND, this->db()->LatestTreeHead(&lookup_sth));

- EXPECT_EQ(Database::OK,
this->db_->WriteTreeHead(this->DefaultTreeHead()));
+ EXPECT_EQ(Database::OK, this->db()->WriteTreeHead(sth));

- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&lookup_sth));
- CompareTreeHeads(this->DefaultTreeHead(), lookup_sth);
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&lookup_sth));
+ CompareTreeHeads(sth, lookup_sth);
}

TYPED_TEST(DBTest, WriteTreeHeadDuplicateTimestamp) {
- SignedTreeHead sth, lookup_sth;
+ SignedTreeHead sth, sth2, lookup_sth;
+ this->test_signer_.CreateUnique(&sth);

- EXPECT_EQ(Database::OK,
this->db_->WriteTreeHead(this->DefaultTreeHead()));
+ EXPECT_EQ(Database::OK, this->db()->WriteTreeHead(sth));

- sth.CopyFrom(this->DefaultTreeHead());
- sth.set_tree_size(this->DefaultTreeSize() + 1);
+ sth2.CopyFrom(sth);
+ sth2.set_tree_size(sth.tree_size() + 1);
EXPECT_EQ(Database::DUPLICATE_TREE_HEAD_TIMESTAMP,
- this->db_->WriteTreeHead(sth));
+ this->db()->WriteTreeHead(sth2));

- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&lookup_sth));
- CompareTreeHeads(this->DefaultTreeHead(), lookup_sth);
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&lookup_sth));
+ CompareTreeHeads(sth, lookup_sth);
}

TYPED_TEST(DBTest, WriteTreeHeadNewerTimestamp) {
- SignedTreeHead sth, lookup_sth;
-
- EXPECT_EQ(Database::OK,
this->db_->WriteTreeHead(this->DefaultTreeHead()));
+ SignedTreeHead sth, sth2, lookup_sth;
+ this->test_signer_.CreateUnique(&sth);
+ this->test_signer_.CreateUnique(&sth2);
+ // Should be newer already but don't rely on this.
+ sth2.set_timestamp(sth.timestamp() + 1000);

- sth.CopyFrom(this->DefaultTreeHead());
- sth.set_timestamp(this->DefaultTimestamp() + 1000);
- EXPECT_EQ(Database::OK, this->db_->WriteTreeHead(sth));
+ EXPECT_EQ(Database::OK, this->db()->WriteTreeHead(sth));
+ EXPECT_EQ(Database::OK, this->db()->WriteTreeHead(sth2));

- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&lookup_sth));
- CompareTreeHeads(sth, lookup_sth);
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&lookup_sth));
+ CompareTreeHeads(sth2, lookup_sth);
}

TYPED_TEST(DBTest, WriteTreeHeadOlderTimestamp) {
- SignedTreeHead sth, lookup_sth;
-
- EXPECT_EQ(Database::OK,
this->db_->WriteTreeHead(this->DefaultTreeHead()));
+ SignedTreeHead sth, sth2, lookup_sth;
+ this->test_signer_.CreateUnique(&sth);
+ this->test_signer_.CreateUnique(&sth2);
+ // Should be newer already but don't rely on this.
+ sth2.set_timestamp(sth.timestamp() - 1000);

- sth.CopyFrom(this->DefaultTreeHead());
- sth.set_timestamp(this->DefaultTimestamp() - 1000);
- EXPECT_EQ(Database::OK, this->db_->WriteTreeHead(sth));
+ EXPECT_EQ(Database::OK, this->db()->WriteTreeHead(sth));
+ EXPECT_EQ(Database::OK, this->db()->WriteTreeHead(sth2));

- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&lookup_sth));
- CompareTreeHeads(this->DefaultTreeHead(), lookup_sth);
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&lookup_sth));
+ CompareTreeHeads(sth, lookup_sth);
}

TYPED_TEST(DBTest, Resume) {
- LoggedCertificate logged_cert, lookup_cert0, lookup_cert1;
- logged_cert.CopyFrom(this->DefaultLoggedCert());
- logged_cert.set_certificate_sha256_hash(this->AlternativeHash());
- logged_cert.mutable_sct()->set_timestamp(this->DefaultTimestamp() +
1000);
+ LoggedCertificate logged_cert, logged_cert2, lookup_cert, lookup_cert2;
+ this->test_signer_.CreateUnique(&logged_cert);
+ this->test_signer_.CreateUnique(&logged_cert2);

EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(
- this->DefaultLoggedCert()));
+ this->db()->CreatePendingCertificateEntry(logged_cert));
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert2));
EXPECT_EQ(Database::OK,
- this->db_->AssignCertificateSequenceNumber(
- this->DefaultHash(), 42));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 42));

- SignedTreeHead sth, lookup_sth;
- sth.CopyFrom(this->DefaultTreeHead());
- sth.set_timestamp(this->DefaultTimestamp() - 1000);
- EXPECT_EQ(Database::OK,
this->db_->WriteTreeHead(this->DefaultTreeHead()));
- EXPECT_EQ(Database::OK, this->db_->WriteTreeHead(sth));
+ SignedTreeHead sth, sth2, lookup_sth;
+ this->test_signer_.CreateUnique(&sth);
+ this->test_signer_.CreateUnique(&sth2);
+ sth2.set_timestamp(sth.timestamp() - 1000);
+ EXPECT_EQ(Database::OK, this->db()->WriteTreeHead(sth));
+ EXPECT_EQ(Database::OK, this->db()->WriteTreeHead(sth2));

- Database *db2 = this->SecondDB();
+ Database *db2 = this->test_db_.SecondDB();

EXPECT_EQ(Database::LOOKUP_OK,
- db2->LookupCertificateByHash(this->DefaultHash(),
&lookup_cert0));
- EXPECT_EQ(42U, lookup_cert0.sequence_number());
+ db2->LookupCertificateByHash(
+ logged_cert.certificate_sha256_hash(), &lookup_cert));
+ EXPECT_EQ(42U, lookup_cert.sequence_number());

- lookup_cert0.clear_sequence_number();
- CompareLoggedCerts(this->DefaultLoggedCert(), lookup_cert0);
+ lookup_cert.clear_sequence_number();
+ CompareLoggedCerts(logged_cert, lookup_cert);

EXPECT_EQ(Database::LOOKUP_OK,
- db2->LookupCertificateByHash(this->AlternativeHash(),
- &lookup_cert1));
- CompareLoggedCerts(logged_cert, lookup_cert1);
+ db2->LookupCertificateByHash(
+ logged_cert2.certificate_sha256_hash(), &lookup_cert2));
+ CompareLoggedCerts(logged_cert2, lookup_cert2);

EXPECT_EQ(Database::LOOKUP_OK, db2->LatestTreeHead(&lookup_sth));
- CompareTreeHeads(this->DefaultTreeHead(), lookup_sth);
+ CompareTreeHeads(sth, lookup_sth);

std::set<string> pending_hashes;
- pending_hashes.insert(this->AlternativeHash());
+ pending_hashes.insert(logged_cert2.certificate_sha256_hash());

EXPECT_EQ(pending_hashes, db2->PendingHashes());

@@ -467,7 +328,7 @@
}

TYPED_TEST(DBTest, ResumeEmpty) {
- Database *db2 = this->SecondDB();
+ Database *db2 = this->test_db_.SecondDB();

LoggedCertificate lookup_cert;
EXPECT_EQ(Database::NOT_FOUND,
@@ -483,7 +344,14 @@

} // namespace

-int main(int argc, char**argv) {
+int main(int argc, char **argv) {
+ // Change the defaults. Can be overridden on command line.
+ // Log to stderr instead of log files.
+ FLAGS_logtostderr = true;
+ // Only log fatal messages by default.
+ FLAGS_minloglevel = 3;
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
=======================================
--- /src/log/file_storage_test.cc Tue Oct 9 04:30:56 2012
+++ /src/log/file_storage_test.cc Thu Oct 11 10:55:00 2012
@@ -1,3 +1,5 @@
+#include <gflags/gflags.h>
+#include <glog/logging.h>
#include <gtest/gtest.h>
#include <errno.h>
#include <iostream>
@@ -9,6 +11,7 @@

#include "file_storage.h"
#include "filesystem_op.h"
+#include "test_db.h"
#include "util.h"

namespace {
@@ -20,33 +23,11 @@
class BasicFileStorageTest : public ::testing::Test {
protected:
BasicFileStorageTest() :
- file_db_(NULL) {}
+ test_db_() {}

- void SetUp() {
- file_base_ = util::CreateTemporaryDirectory("/tmp/ctlogXXXXXX");
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- file_db_ = new FileStorage(file_base_, kStorageDepth);
- }
+ FileStorage *fs() const { return test_db_.db(); }

- void TearDown() {
- // Check again that it is safe to empty file_base_.
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- string command = "rm -r " + file_base_;
- int ret = system(command.c_str());
- if (ret != 0)
- std::cout << "Failed to delete temporary directory in "
- << file_base_ << std::endl;
- }
-
- ~BasicFileStorageTest() {
- if (file_db_ != NULL)
- delete file_db_;
- }
-
- FileStorage *file_db_;
- string file_base_;
+ TestDB<FileStorage>test_db_;
};

TEST_F(BasicFileStorageTest, Create) {
@@ -56,16 +37,16 @@
string key1("1245abcd", 8);
string value1("Alice", 5);

- EXPECT_EQ(FileStorage::NOT_FOUND, file_db_->LookupEntry(key0, NULL));
- EXPECT_EQ(FileStorage::NOT_FOUND, file_db_->LookupEntry(key1, NULL));
+ EXPECT_EQ(FileStorage::NOT_FOUND, fs()->LookupEntry(key0, NULL));
+ EXPECT_EQ(FileStorage::NOT_FOUND, fs()->LookupEntry(key1, NULL));

- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key0, value0));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key0, value0));
string lookup_result;
- EXPECT_EQ(FileStorage::OK, file_db_->LookupEntry(key0, &lookup_result));
+ EXPECT_EQ(FileStorage::OK, fs()->LookupEntry(key0, &lookup_result));
EXPECT_EQ(value0, lookup_result);

- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key1, value1));
- EXPECT_EQ(FileStorage::OK, file_db_->LookupEntry(key1, &lookup_result));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key1, value1));
+ EXPECT_EQ(FileStorage::OK, fs()->LookupEntry(key1, &lookup_result));
EXPECT_EQ(value1, lookup_result);
}

@@ -76,14 +57,14 @@
string key1("1245abcd", 8);
string value1("Alice", 5);

- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key0, value0));
- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key1, value1));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key0, value0));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key1, value1));

std::set<string> keys;
keys.insert(key0);
keys.insert(key1);

- std::set<string> scan_keys = file_db_->Scan();
+ std::set<string> scan_keys = fs()->Scan();
EXPECT_EQ(keys, scan_keys);
}

@@ -91,18 +72,18 @@
string key("1234xyzw", 8);
string value("unicorn", 7);

- EXPECT_EQ(FileStorage::NOT_FOUND, file_db_->LookupEntry(key, NULL));
- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key, value));
+ EXPECT_EQ(FileStorage::NOT_FOUND, fs()->LookupEntry(key, NULL));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key, value));
string lookup_result;
- EXPECT_EQ(FileStorage::OK, file_db_->LookupEntry(key, &lookup_result));
+ EXPECT_EQ(FileStorage::OK, fs()->LookupEntry(key, &lookup_result));
EXPECT_EQ(value, lookup_result);

// Try to log another entry with the same key.
string new_value("alice", 5);
EXPECT_EQ(FileStorage::ENTRY_ALREADY_EXISTS,
- file_db_->CreateEntry(key, new_value));
+ fs()->CreateEntry(key, new_value));
lookup_result.clear();
- EXPECT_EQ(FileStorage::OK, file_db_->LookupEntry(key, &lookup_result));
+ EXPECT_EQ(FileStorage::OK, fs()->LookupEntry(key, &lookup_result));

// Expect to receive the original entry on lookup.
EXPECT_EQ(value, lookup_result);
@@ -112,16 +93,16 @@
string key("1234xyzw", 8);
string value("unicorn", 7);

- EXPECT_EQ(FileStorage::NOT_FOUND, file_db_->LookupEntry(key, NULL));
- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key, value));
+ EXPECT_EQ(FileStorage::NOT_FOUND, fs()->LookupEntry(key, NULL));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key, value));
string lookup_result;
- EXPECT_EQ(FileStorage::OK, file_db_->LookupEntry(key, &lookup_result));
+ EXPECT_EQ(FileStorage::OK, fs()->LookupEntry(key, &lookup_result));
EXPECT_EQ(value, lookup_result);

// Update.
string new_value("alice", 5);
- EXPECT_EQ(FileStorage::OK, file_db_->UpdateEntry(key, new_value));
- EXPECT_EQ(FileStorage::OK, file_db_->LookupEntry(key, &lookup_result));
+ EXPECT_EQ(FileStorage::OK, fs()->UpdateEntry(key, new_value));
+ EXPECT_EQ(FileStorage::OK, fs()->LookupEntry(key, &lookup_result));

// Expect to receive the new entry on lookup.
EXPECT_EQ(new_value, lookup_result);
@@ -137,12 +118,12 @@
string similar_key2("123", 3);
string empty_key;

- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key, value));
- EXPECT_EQ(FileStorage::OK, file_db_->LookupEntry(key, NULL));
- EXPECT_EQ(FileStorage::NOT_FOUND, file_db_->LookupEntry(similar_key0,
NULL));
- EXPECT_EQ(FileStorage::NOT_FOUND, file_db_->LookupEntry(similar_key1,
NULL));
- EXPECT_EQ(FileStorage::NOT_FOUND, file_db_->LookupEntry(similar_key2,
NULL));
- EXPECT_EQ(FileStorage::NOT_FOUND, file_db_->LookupEntry(empty_key,
NULL));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key, value));
+ EXPECT_EQ(FileStorage::OK, fs()->LookupEntry(key, NULL));
+ EXPECT_EQ(FileStorage::NOT_FOUND, fs()->LookupEntry(similar_key0, NULL));
+ EXPECT_EQ(FileStorage::NOT_FOUND, fs()->LookupEntry(similar_key1, NULL));
+ EXPECT_EQ(FileStorage::NOT_FOUND, fs()->LookupEntry(similar_key2, NULL));
+ EXPECT_EQ(FileStorage::NOT_FOUND, fs()->LookupEntry(empty_key, NULL));
}

TEST_F(BasicFileStorageTest, Resume) {
@@ -152,19 +133,21 @@
string key1("1245abcd", 8);
string value1("Alice", 5);

- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key0, value0));
- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key1, value1));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key0, value0));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key1, value1));

// A second database.
- FileStorage db2(file_base_, kStorageDepth);
+ FileStorage *db2 = test_db_.SecondDB();

// Look up and expect to find the entries.
string lookup_result;
- EXPECT_EQ(FileStorage::OK, db2.LookupEntry(key0, &lookup_result));
+ EXPECT_EQ(FileStorage::OK, db2->LookupEntry(key0, &lookup_result));
EXPECT_EQ(value0, lookup_result);

- EXPECT_EQ(FileStorage::OK, db2.LookupEntry(key1, &lookup_result));
+ EXPECT_EQ(FileStorage::OK, db2->LookupEntry(key1, &lookup_result));
EXPECT_EQ(value1, lookup_result);
+
+ delete db2;
};

TEST_F(BasicFileStorageTest, ScanOnResume) {
@@ -174,48 +157,28 @@
string key1("1245abcd", 8);
string value1("Alice", 5);

- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key0, value0));
- EXPECT_EQ(FileStorage::OK, file_db_->CreateEntry(key1, value1));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key0, value0));
+ EXPECT_EQ(FileStorage::OK, fs()->CreateEntry(key1, value1));

// A second database.
- FileStorage db2(file_base_, kStorageDepth);
+ FileStorage *db2 = test_db_.SecondDB();

std::set<string> keys;
keys.insert(key0);
keys.insert(key1);

- std::set<string> scan_keys = db2.Scan();
+ std::set<string> scan_keys = db2->Scan();
EXPECT_EQ(keys, scan_keys);
+ delete db2;
}

class FailingFileStorageDeathTest : public ::testing::Test {
protected:
- FailingFileStorageDeathTest() {}
-
- void SetUp() {
- file_base_ = util::CreateTemporaryDirectory("/tmp/ctlogXXXXXX");
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- }
-
string GetTemporaryDirectory() {
- return util::CreateTemporaryDirectory(file_base_ + "/ctlogXXXXXX");
- }
-
- void TearDown() {
- // Check again that it is safe to empty file_base_.
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- string command = "rm -r " + file_base_;
- int ret = system(command.c_str());
- if (ret != 0)
- std::cout << "Failed to delete temporary directory in "
- << file_base_ << std::endl;
+ return util::CreateTemporaryDirectory(
+ tmp_.TmpStorageDir() + "/ctlogXXXXXX");
}
-
- ~FailingFileStorageDeathTest() {}
-
- string file_base_;
+ TmpStorage tmp_;
};

TEST(DeathTest, SupportDeath) {
@@ -388,7 +351,14 @@

} // namespace

-int main(int argc, char**argv) {
+int main(int argc, char **argv) {
+ // Change the defaults. Can be overridden on command line.
+ // Log to stderr instead of log files.
+ FLAGS_logtostderr = true;
+ // Only log fatal messages by default.
+ FLAGS_minloglevel = 3;
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
=======================================
--- /src/log/frontend_signer.cc Tue Oct 9 04:30:56 2012
+++ /src/log/frontend_signer.cc Thu Oct 11 10:55:00 2012
@@ -1,12 +1,10 @@
-#include <assert.h>
-#include <stdint.h>
+#include <glog/logging.h>

-#include "database.h"
#include "ct.pb.h"
+#include "database.h"
#include "frontend_signer.h"
#include "log_signer.h"
#include "serial_hasher.h"
-#include "submission_handler.h"
#include "util.h"

using ct::CertificateEntry;
@@ -16,49 +14,15 @@

FrontendSigner::FrontendSigner(Database *db, LogSigner *signer)
: db_(db),
- hasher_(new Sha256Hasher()),
- signer_(signer),
- // Default handler.
- handler_(new SubmissionHandler()) {
- assert(signer_ != NULL);
- assert(db_ != NULL);
-}
-
-FrontendSigner::FrontendSigner(Database *db, LogSigner *signer,
- SubmissionHandler *handler)
- : db_(db),
- hasher_(new Sha256Hasher()),
- signer_(signer),
- handler_(handler) {
- assert(signer_ != NULL);
- assert(db_ != NULL);
- assert(handler_ != NULL);
-}
+ signer_(signer) {}

FrontendSigner::~FrontendSigner() {
- delete hasher_;
delete signer_;
- delete handler_;
}

FrontendSigner::SubmitResult
-FrontendSigner::QueueEntry(const string &data,
+FrontendSigner::QueueEntry(const CertificateEntry &entry,
SignedCertificateTimestamp *sct) {
- return QueueEntry(CertificateEntry::X509_ENTRY, data, sct);
-}
-
-FrontendSigner::SubmitResult
-FrontendSigner::QueueEntry(CertificateEntry::Type type,
- const string data,
- SignedCertificateTimestamp *sct) {
- // Verify the submission and compute signed and unsigned parts.
- CertificateEntry entry;
- entry.set_type(type);
- SubmissionHandler::SubmitResult result =
- handler_->ProcessSubmission(data, &entry);
- if (result != SubmissionHandler::OK)
- return GetSubmitError(result);
-
// Check if the entry already exists.
string sha256_hash = ComputeCertificateHash(entry);
assert(!sha256_hash.empty());
@@ -68,15 +32,13 @@
db_->LookupCertificateByHash(sha256_hash, &logged_cert);

if (db_result == Database::LOOKUP_OK) {
- if(sct != NULL)
+ if (sct != NULL)
sct->CopyFrom(logged_cert.sct());

- if (logged_cert.has_sequence_number())
- return LOGGED;
- return PENDING;
+ return DUPLICATE;
}

- assert(db_result == Database::NOT_FOUND);
+ CHECK_EQ(Database::NOT_FOUND, db_result);

LoggedCertificate new_cert;
new_cert.set_certificate_sha256_hash(sha256_hash);
@@ -88,86 +50,21 @@
db_->CreatePendingCertificateEntry(new_cert);

// Assume for now that nobody interfered while we were busy signing.
- assert(write_result == Database::OK);
+ CHECK_EQ(Database::OK, write_result);
if (sct != NULL)
sct->CopyFrom(new_cert.sct());
return NEW;
}
-
-// static
-string FrontendSigner::SubmitResultString(SubmitResult result) {
- string result_string;
- switch (result) {
- case LOGGED:
- result_string = "submission already logged";
- break;
- case PENDING:
- result_string = "submission already pending";
- break;
- case NEW:
- result_string = "new submission accepted";
- break;
- case BAD_PEM_FORMAT:
- result_string = "not a valid PEM-encoded chain";
- break;
- // TODO(ekasper): the following two could/should be more precise.
- case SUBMISSION_TOO_LONG:
- result_string = "DER-encoded certificate chain length "
- "exceeds allowed limit";
- break;
- case CERTIFICATE_VERIFY_ERROR:
- result_string = "could not verify certificate chain";
- break;
- case PRECERT_CHAIN_NOT_WELL_FORMED:
- result_string = "precert chain not well-formed";
- break;
- case UNKNOWN_ERROR:
- result_string = "unknown error";
- break;
- default:
- assert(false);
- }
-
- return result_string;
-}

string
FrontendSigner::ComputeCertificateHash(const CertificateEntry &entry)
const {
// Compute the SHA-256 hash of the leaf certificate.
- hasher_->Reset();
- hasher_->Update(entry.leaf_certificate());
- return hasher_->Final();
+ return Sha256Hasher::Sha256Digest(entry.leaf_certificate());
}

void FrontendSigner::TimestampAndSign(SignedCertificateTimestamp *sct)
const {
sct->set_timestamp(util::TimeInMilliseconds());
// The submission handler has already verified the format of this entry,
// so this should never fail.
- LogSigner::SignResult ret = signer_->SignCertificateTimestamp(sct);
- assert(ret == LogSigner::OK);
-}
-
-// static
-FrontendSigner::SubmitResult
-FrontendSigner::GetSubmitError(SubmissionHandler::SubmitResult result) {
- SubmitResult submit_result = UNKNOWN_ERROR;
- switch (result) {
- case SubmissionHandler::EMPTY_SUBMISSION:
- case SubmissionHandler::INVALID_PEM_ENCODED_CHAIN:
- submit_result = BAD_PEM_FORMAT;
- break;
- case SubmissionHandler::SUBMISSION_TOO_LONG:
- submit_result = SUBMISSION_TOO_LONG;
- break;
- case SubmissionHandler::INVALID_CERTIFICATE_CHAIN:
- case SubmissionHandler::UNKNOWN_ROOT:
- submit_result = CERTIFICATE_VERIFY_ERROR;
- break;
- case SubmissionHandler::PRECERT_CHAIN_NOT_WELL_FORMED:
- submit_result = PRECERT_CHAIN_NOT_WELL_FORMED;
- break;
- default:
- assert(false);
- }
- return submit_result;
+ CHECK_EQ(LogSigner::OK, signer_->SignCertificateTimestamp(sct));
}
=======================================
--- /src/log/frontend_signer.h Tue Oct 9 04:30:56 2012
+++ /src/log/frontend_signer.h Thu Oct 11 10:55:00 2012
@@ -5,52 +5,34 @@
#include <string>

#include "ct.pb.h"
-#include "submission_handler.h"

class Database;
class LogSigner;
-class SerialHasher;

class FrontendSigner {
public:
- // Takes ownership of |signer|.
- FrontendSigner(Database *db, LogSigner *signer);
-
- // Takes ownership of |signer| and |handler|.
- FrontendSigner(Database *db, LogSigner *signer, SubmissionHandler
*handler);
-
- ~FrontendSigner();
-
enum SubmitResult {
- LOGGED,
- PENDING,
NEW,
- BAD_PEM_FORMAT,
- SUBMISSION_TOO_LONG,
- CERTIFICATE_VERIFY_ERROR,
- PRECERT_CHAIN_NOT_WELL_FORMED,
- UNKNOWN_ERROR,
+ DUPLICATE,
};

- SubmitResult QueueEntry(const std::string &data,
- ct::SignedCertificateTimestamp *sct);
+ // Takes ownership of |signer|.
+ FrontendSigner(Database *db, LogSigner *signer);
+
+ ~FrontendSigner();

- SubmitResult QueueEntry(ct::CertificateEntry::Type type,
- const std::string data,
+ // Log the entry if it's not already in the database,
+ // and return either a new timestamp-signature pair,
+ // or a previously existing one. (Currently also copies the
+ // entry to the sct but you shouldn't rely on this.)
+ SubmitResult QueueEntry(const ct::CertificateEntry &entry,
ct::SignedCertificateTimestamp *sct);

- static std::string SubmitResultString(SubmitResult result);
-
private:
Database *db_;
- SerialHasher *hasher_;
LogSigner *signer_;
- SubmissionHandler *handler_;
-
std::string ComputeCertificateHash(const ct::CertificateEntry &entry)
const;

void TimestampAndSign(ct::SignedCertificateTimestamp *sct) const;
-
- static SubmitResult GetSubmitError(SubmissionHandler::SubmitResult
result);
};
#endif
=======================================
--- /src/log/frontend_signer_test.cc Tue Oct 9 04:30:56 2012
+++ /src/log/frontend_signer_test.cc Thu Oct 11 10:55:00 2012
@@ -1,244 +1,205 @@
/* -*- indent-tabs-mode: nil -*- */
-
+#include <gflags/gflags.h>
+#include <glog/logging.h>
#include <gtest/gtest.h>
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <stddef.h>
#include <string>

#include "ct.pb.h"
#include "file_db.h"
-#include "file_storage.h"
#include "frontend_signer.h"
-#include "log_signer.h"
#include "log_verifier.h"
#include "merkle_verifier.h"
+#include "serial_hasher.h"
#include "sqlite_db.h"
+#include "test_db.h"
+#include "test_signer.h"
#include "util.h"

namespace {

using ct::CertificateEntry;
+using ct::LoggedCertificate;
using ct::SignedCertificateTimestamp;
using std::string;

-const char *ecp256_private_key = {
- "-----BEGIN EC PRIVATE KEY-----\n"
- "MHcCAQEEIG8QAquNnarN6Ik2cMIZtPBugh9wNRe0e309MCmDfBGuoAoGCCqGSM49\n"
- "AwEHoUQDQgAES0AfBkjr7b8b19p5Gk8plSAN16wWXZyhYsH6FMCEUK60t7pem/ck\n"
- "oPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
- "-----END EC PRIVATE KEY-----\n"
-};
-
-const char *ecp256_public_key = {
- "-----BEGIN PUBLIC KEY-----\n"
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES0AfBkjr7b8b19p5Gk8plSAN16wW\n"
- "XZyhYsH6FMCEUK60t7pem/ckoPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
- "-----END PUBLIC KEY-----\n"
-};
-
-EVP_PKEY* PrivateKeyFromPem(const string &pemkey) {
- BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
- EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
- assert(pkey != NULL);
- BIO_free(bio);
- return pkey;
+// A slightly shorter notation for constructing hex strings from binary
blobs.
+string H(const string &byte_string) {
+ return util::HexString(byte_string);
}

-EVP_PKEY* PublicKeyFromPem(const string &pemkey) {
- BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
- EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
- assert(pkey != NULL);
- BIO_free(bio);
- return pkey;
-}
-
-const unsigned kCertStorageDepth = 3;
-const unsigned kTreeStorageDepth = 8;
-
template <class T> class FrontendSignerTest : public ::testing::Test {
protected:
FrontendSignerTest()
- : db_(NULL),
- verifier_(NULL),
- frontend_(NULL) {}
-
- void SetUp() {
- EVP_PKEY *pkey = PrivateKeyFromPem(ecp256_private_key);
- EVP_PKEY *pubkey = PublicKeyFromPem(ecp256_public_key);
- verifier_ = new LogVerifier(new LogSigVerifier(pubkey),
- new MerkleVerifier(new Sha256Hasher()));
- file_base_ = util::CreateTemporaryDirectory("/tmp/ctlogXXXXXX");
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
-
- NewDB();
-
- frontend_ = new FrontendSigner(db_, new LogSigner(pkey));
- ASSERT_TRUE(verifier_ != NULL);
- ASSERT_TRUE(frontend_ != NULL);
- }
-
- void NewDB();
-
- void TearDown() {
- // Check again that it is safe to empty file_base_.
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- string command = "rm -r " + file_base_;
- int ret = system(command.c_str());
- if (ret != 0)
- std::cout << "Failed to delete temporary directory in "
- << file_base_ << std::endl;
- }
+ : test_db_(),
+ test_signer_(),
+ verifier_(new LogVerifier(TestSigner::DefaultVerifier(),
+ new MerkleVerifier(new Sha256Hasher()))),
+ frontend_(new FrontendSigner(test_db_.db(),
+ TestSigner::DefaultSigner())) {}

~FrontendSignerTest() {
delete verifier_;
delete frontend_;
- delete db_;
}

- Database *db_;
+ T *db() const { return test_db_.db(); }
+
+ TestDB<T> test_db_;
+ TestSigner test_signer_;
LogVerifier *verifier_;
FrontendSigner *frontend_;
- string file_base_;
};

-template <> void FrontendSignerTest<FileDB>::NewDB() {
- string certs_dir = file_base_ + "/certs";
- string tree_dir = file_base_ + "/tree";
- int ret = mkdir(certs_dir.c_str(), 0700);
- ASSERT_EQ(ret, 0);
- ret = mkdir(tree_dir.c_str(), 0700);
- ASSERT_EQ(ret, 0);
-
- db_ = new FileDB(new FileStorage(certs_dir, kCertStorageDepth),
- new FileStorage(tree_dir, kTreeStorageDepth));
-}
-
-template <> void FrontendSignerTest<SQLiteDB>::NewDB() {
- db_ = new SQLiteDB(file_base_ + "/ct");
+void CompareEntries(const CertificateEntry &entry0,
+ const CertificateEntry &entry1) {
+ EXPECT_EQ(entry0.type(), entry1.type());
+ EXPECT_EQ(H(entry0.leaf_certificate()), H(entry1.leaf_certificate()));
+ EXPECT_EQ(entry0.intermediates_size(), entry1.intermediates_size());
+ for (int i = 0; i < entry0.intermediates_size(); ++i)
+ EXPECT_EQ(H(entry0.intermediates(i)), H(entry1.intermediates(i)));
}

typedef testing::Types<FileDB, SQLiteDB> Databases;

TYPED_TEST_CASE(FrontendSignerTest, Databases);

-const char unicorn[] = "Unicorn";
-const char alice[] = "Alice";
-
TYPED_TEST(FrontendSignerTest, Log) {
- const string kUnicorn(unicorn, 7);
- const string kAlice(alice, 5);
+ CertificateEntry entry0, entry1;
+ this->test_signer_.CreateUnique(&entry0);
+ this->test_signer_.CreateUnique(&entry1);

// Log and expect success.
- SignedCertificateTimestamp sct0, sct1;
- EXPECT_EQ(FrontendSigner::NEW,
- this->frontend_->QueueEntry(kUnicorn, &sct0));
- EXPECT_EQ(sct0.entry().type(), CertificateEntry::X509_ENTRY);
- EXPECT_EQ(sct0.entry().leaf_certificate(), kUnicorn);
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry0,
NULL));
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry1,
NULL));
+
+ // Look it up and expect to get the right thing back.
+ LoggedCertificate logged_cert0, logged_cert1;
+ string hash0 = Sha256Hasher::Sha256Digest(entry0.leaf_certificate());
+ string hash1 = Sha256Hasher::Sha256Digest(entry1.leaf_certificate());
+
+ EXPECT_EQ(Database::LOOKUP_OK,
+ this->db()->LookupCertificateByHash(hash0, &logged_cert0));
+ EXPECT_EQ(Database::LOOKUP_OK,
+ this->db()->LookupCertificateByHash(hash1, &logged_cert1));

- EXPECT_EQ(FrontendSigner::NEW,
- this->frontend_->QueueEntry(kAlice, &sct1));
- EXPECT_EQ(sct1.entry().type(), CertificateEntry::X509_ENTRY);
- EXPECT_EQ(sct1.entry().leaf_certificate(), kAlice);
+ CompareEntries(entry0, logged_cert0.sct().entry());
+ CompareEntries(entry1, logged_cert1.sct().entry());
}

TYPED_TEST(FrontendSignerTest, Time) {
- const string kUnicorn(unicorn, 7);
- const string kAlice(alice, 5);
+ CertificateEntry entry0, entry1;
+ this->test_signer_.CreateUnique(&entry0);
+ this->test_signer_.CreateUnique(&entry1);

// Log and expect success.
SignedCertificateTimestamp sct0, sct1;
- EXPECT_EQ(FrontendSigner::NEW,
- this->frontend_->QueueEntry(kUnicorn, &sct0));
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry0,
&sct0));
EXPECT_LE(sct0.timestamp(), util::TimeInMilliseconds());
EXPECT_GT(sct0.timestamp(), 0U);

- EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(kAlice,
&sct1));
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry1,
&sct1));
EXPECT_LE(sct0.timestamp(), sct1.timestamp());
EXPECT_LE(sct1.timestamp(), util::TimeInMilliseconds());
}

TYPED_TEST(FrontendSignerTest, LogDuplicates) {
- const string kUnicorn(unicorn, 7);
+ CertificateEntry entry;
+ this->test_signer_.CreateUnique(&entry);
+
+ SignedCertificateTimestamp sct0, sct1;
+ // Log and expect success.
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry,
&sct0));
+ // Wait for time to change.
+ usleep(2000);
+ // Try to log again.
+ EXPECT_EQ(FrontendSigner::DUPLICATE,
+ this->frontend_->QueueEntry(entry, &sct1));
+
+ // Expect to get the original timestamp.
+ EXPECT_EQ(sct0.timestamp(), sct1.timestamp());
+}
+
+TYPED_TEST(FrontendSignerTest, LogDuplicatesDifferentChain) {
+ CertificateEntry entry0, entry1;
+ this->test_signer_.CreateUnique(&entry0);
+ entry1.CopyFrom(entry0);
+ entry1.add_intermediates(this->test_signer_.UniqueFakeCertBytestring());

SignedCertificateTimestamp sct0, sct1;
// Log and expect success.
- EXPECT_EQ(FrontendSigner::NEW,
- this->frontend_->QueueEntry(kUnicorn, &sct0));
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry0,
&sct0));
// Wait for time to change.
usleep(2000);
// Try to log again.
- EXPECT_EQ(FrontendSigner::PENDING,
- this->frontend_->QueueEntry(kUnicorn, &sct1));
+ EXPECT_EQ(FrontendSigner::DUPLICATE,
+ this->frontend_->QueueEntry(entry1, &sct1));

- EXPECT_EQ(sct0.entry().type(), sct1.entry().type());
- EXPECT_EQ(sct0.entry().leaf_certificate(),
sct1.entry().leaf_certificate());
// Expect to get the original timestamp.
EXPECT_EQ(sct0.timestamp(), sct1.timestamp());
}

TYPED_TEST(FrontendSignerTest, Verify) {
- const string kUnicorn(unicorn, 7);
- const string kAlice(alice, 5);
+ CertificateEntry entry0, entry1;
+ this->test_signer_.CreateUnique(&entry0);
+ this->test_signer_.CreateUnique(&entry1);

// Log and expect success.
- SignedCertificateTimestamp sct, sct2;
- EXPECT_EQ(FrontendSigner::NEW,
- this->frontend_->QueueEntry(kUnicorn, &sct));
- EXPECT_EQ(FrontendSigner::NEW,
- this->frontend_->QueueEntry(CertificateEntry::PRECERT_ENTRY,
- kAlice, &sct2));
+ SignedCertificateTimestamp sct0, sct1;
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry0,
&sct0));
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry1,
&sct1));

// Verify results.
- EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(sct),
+ // Copy the submitted entry to the SCT.
+ sct0.mutable_entry()->CopyFrom(entry0);
+ sct1.mutable_entry()->CopyFrom(entry1);
+
+ EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(sct0),
LogVerifier::VERIFY_OK);
- EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(sct2),
+ EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(sct1),
LogVerifier::VERIFY_OK);

// Swap the data and expect failure.
- SignedCertificateTimestamp wrong_sct(sct);
- wrong_sct.mutable_entry()->CopyFrom(sct2.entry());
+ SignedCertificateTimestamp wrong_sct(sct0);
+ wrong_sct.mutable_entry()->CopyFrom(entry1);
EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(wrong_sct),
LogVerifier::INVALID_SIGNATURE);
}

TYPED_TEST(FrontendSignerTest, TimedVerify) {
- const string kUnicorn(unicorn, 7);
- const string kAlice(alice, 5);
+ CertificateEntry entry0, entry1;
+ this->test_signer_.CreateUnique(&entry0);
+ this->test_signer_.CreateUnique(&entry1);

uint64_t past_time = util::TimeInMilliseconds();
usleep(2000);

// Log and expect success.
- SignedCertificateTimestamp sct, sct2;
- EXPECT_EQ(FrontendSigner::NEW,
- this->frontend_->QueueEntry(kUnicorn, &sct));
+ SignedCertificateTimestamp sct0, sct1;
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry0,
&sct0));
// Make sure we get different timestamps.
usleep(2000);
- EXPECT_EQ(FrontendSigner::NEW,
- this->frontend_->QueueEntry(CertificateEntry::PRECERT_ENTRY,
- kAlice, &sct2));
+ EXPECT_EQ(FrontendSigner::NEW, this->frontend_->QueueEntry(entry1,
&sct1));

- EXPECT_GT(sct2.timestamp(), sct.timestamp());
+ EXPECT_GT(sct1.timestamp(), sct0.timestamp());

// Verify.
- EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(sct),
+ // Copy the submitted entry to the SCT.
+ sct0.mutable_entry()->CopyFrom(entry0);
+ sct1.mutable_entry()->CopyFrom(entry1);
+ EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(sct0),
LogVerifier::VERIFY_OK);
- EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(sct2),
+ EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(sct1),
LogVerifier::VERIFY_OK);

// Go back to the past and expect verification to fail (since the sct is
// from the future).
EXPECT_EQ(this->verifier_->
- VerifySignedCertificateTimestamp(sct, 0, past_time),
+ VerifySignedCertificateTimestamp(sct0, 0, past_time),
LogVerifier::INVALID_TIMESTAMP);

// Swap timestamps and expect failure.
- SignedCertificateTimestamp wrong_sct(sct);
- wrong_sct.set_timestamp(sct2.timestamp());
+ SignedCertificateTimestamp wrong_sct(sct0);
+ wrong_sct.set_timestamp(sct1.timestamp());
EXPECT_EQ(this->verifier_->VerifySignedCertificateTimestamp(wrong_sct),
LogVerifier::INVALID_SIGNATURE);
}
@@ -246,6 +207,13 @@
} // namespace

int main(int argc, char**argv) {
+ // Change the defaults. Can be overridden on command line.
+ // Log to stderr instead of log files.
+ FLAGS_logtostderr = true;
+ // Only log fatal messages by default.
+ FLAGS_minloglevel = 3;
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
=======================================
--- /src/log/log_lookup_test.cc Tue Oct 9 04:30:56 2012
+++ /src/log/log_lookup_test.cc Thu Oct 11 10:55:00 2012
@@ -1,9 +1,6 @@
+#include <gflags/gflags.h>
#include <glog/logging.h>
#include <gtest/gtest.h>
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <stddef.h>
#include <string>

#include "file_db.h"
@@ -14,6 +11,8 @@
#include "merkle_verifier.h"
#include "serial_hasher.h"
#include "sqlite_db.h"
+#include "test_db.h"
+#include "test_signer.h"
#include "tree_signer.h"
#include "util.h"

@@ -24,248 +23,162 @@
using ct::MerkleAuditProof;
using std::string;

-const char *ecp256_private_key = {
- "-----BEGIN EC PRIVATE KEY-----\n"
- "MHcCAQEEIG8QAquNnarN6Ik2cMIZtPBugh9wNRe0e309MCmDfBGuoAoGCCqGSM49\n"
- "AwEHoUQDQgAES0AfBkjr7b8b19p5Gk8plSAN16wWXZyhYsH6FMCEUK60t7pem/ck\n"
- "oPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
- "-----END EC PRIVATE KEY-----\n"
-};
-
-const char *ecp256_public_key = {
- "-----BEGIN PUBLIC KEY-----\n"
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES0AfBkjr7b8b19p5Gk8plSAN16wW\n"
- "XZyhYsH6FMCEUK60t7pem/ckoPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
- "-----END PUBLIC KEY-----\n"
-};
-
-EVP_PKEY* PrivateKeyFromPem(const string &pemkey) {
- BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
- EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
- assert(pkey != NULL);
- BIO_free(bio);
- return pkey;
-}
-
-EVP_PKEY* PublicKeyFromPem(const string &pemkey) {
- BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
- EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
- assert(pkey != NULL);
- BIO_free(bio);
- return pkey;
-}
-
-const unsigned kCertStorageDepth = 3;
-const unsigned kTreeStorageDepth = 8;
-
template <class T> class LogLookupTest : public ::testing::Test {
protected:
LogLookupTest()
- : db_(NULL),
+ : test_db_(),
+ test_signer_(),
tree_signer_(NULL),
verifier_(NULL) {}

void SetUp() {
- EVP_PKEY *pkey = PrivateKeyFromPem(ecp256_private_key);
- EVP_PKEY *pubkey = PublicKeyFromPem(ecp256_public_key);
- verifier_ = new LogVerifier(new LogSigVerifier(pubkey),
+ verifier_ = new LogVerifier(TestSigner::DefaultVerifier(),
new MerkleVerifier(new Sha256Hasher()));
- file_base_ = util::CreateTemporaryDirectory("/tmp/ctlogXXXXXX");
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
-
- NewDB();
-
- tree_signer_ = new TreeSigner(db_, new LogSigner(pkey));
+ tree_signer_ = new TreeSigner(db(), TestSigner::DefaultSigner());
ASSERT_TRUE(verifier_ != NULL);
ASSERT_TRUE(tree_signer_ != NULL);
}
-
- void NewDB();
-
- void TearDown() {
- // Check again that it is safe to empty file_base_.
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- string command = "rm -r " + file_base_;
- int ret = system(command.c_str());
- if (ret != 0)
- std::cout << "Failed to delete temporary directory in "
- << file_base_ << std::endl;
- }

~LogLookupTest() {
delete tree_signer_;
delete verifier_;
- delete db_;
}

- Database *db_;
+ T *db() const { return test_db_.db(); }
+ TestDB<T> test_db_;
+ TestSigner test_signer_;
TreeSigner *tree_signer_;
LogVerifier *verifier_;
- string file_base_;
};

-template <> void LogLookupTest<FileDB>::NewDB() {
- string certs_dir = file_base_ + "/certs";
- string tree_dir = file_base_ + "/tree";
- int ret = mkdir(certs_dir.c_str(), 0700);
- ASSERT_EQ(ret, 0);
- ret = mkdir(tree_dir.c_str(), 0700);
- ASSERT_EQ(ret, 0);
-
- db_ = new FileDB(new FileStorage(certs_dir, kCertStorageDepth),
- new FileStorage(tree_dir, kTreeStorageDepth));
-}
-
-template <> void LogLookupTest<SQLiteDB>::NewDB() {
- db_ = new SQLiteDB(file_base_ + "/ct");
-}
-
typedef testing::Types<FileDB, SQLiteDB> Databases;

TYPED_TEST_CASE(LogLookupTest, Databases);

-// TODO(ekasper): use real data.
TYPED_TEST(LogLookupTest, Lookup) {
- string hash("1234xyzw", 8);
- string wrong_hash("1234xyzq", 8);
-
LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

MerkleAuditProof proof;
EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());

- LogLookup lookup(this->db_);
+ LogLookup lookup(this->db());
// Look the new entry up.
- EXPECT_EQ(LogLookup::OK, lookup.CertificateAuditProof(1234, hash,
&proof));
+ EXPECT_EQ(LogLookup::OK,
+ lookup.CertificateAuditProof(logged_cert.sct().timestamp(),
+
logged_cert.certificate_sha256_hash(),
+ &proof));
}

TYPED_TEST(LogLookupTest, NotFound) {
- string hash("1234xyzw", 8);
- string wrong_hash("1234xyzq", 8);
-
LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

MerkleAuditProof proof;
EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());

- LogLookup lookup(this->db_);
+ LogLookup lookup(this->db());

- // Look up stuff that's not in the DB.
+ // Look up using a wrong hash.
+ string hash = this->test_signer_.UniqueHash();
EXPECT_EQ(LogLookup::NOT_FOUND,
- lookup.CertificateAuditProof(1234, wrong_hash, &proof));
+ lookup.CertificateAuditProof(logged_cert.sct().timestamp(),
+ hash,
+ &proof));
+
+ // Wrong timestamp
EXPECT_EQ(LogLookup::NOT_FOUND,
- lookup.CertificateAuditProof(1235, hash, &proof));
+ lookup.CertificateAuditProof(logged_cert.sct().timestamp() +
1,
+
logged_cert.certificate_sha256_hash(),
+ &proof));
}

TYPED_TEST(LogLookupTest, Update) {
- string hash("1234xyzw", 8);
-
- LogLookup lookup(this->db_);
-
+ LogLookup lookup(this->db());
LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

MerkleAuditProof proof;
EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());

// There is an entry but we don't know about it yet.
EXPECT_EQ(LogLookup::NOT_FOUND,
- lookup.CertificateAuditProof(1234, hash, &proof));
+ lookup.CertificateAuditProof(logged_cert.sct().timestamp(),
+
logged_cert.certificate_sha256_hash(),
+ &proof));
+
// Update
EXPECT_EQ(LogLookup::UPDATE_OK, lookup.Update());
// Look the new entry up.
- EXPECT_EQ(LogLookup::OK, lookup.CertificateAuditProof(1234, hash,
&proof));
+ EXPECT_EQ(LogLookup::OK,
+ lookup.CertificateAuditProof(logged_cert.sct().timestamp(),
+
logged_cert.certificate_sha256_hash(),
+ &proof));
}

// Verify that the audit proof constructed is correct (assuming the signer
// operates correctly). TODO(ekasper): KAT tests.
TYPED_TEST(LogLookupTest, Verify) {
- string hash("1234xyzw", 8);
- string wrong_hash("1234xyzq", 8);
-
LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

+ MerkleAuditProof proof;
EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());

- LogLookup lookup(this->db_);
- MerkleAuditProof proof;
+ LogLookup lookup(this->db());
// Look the new entry up.
- EXPECT_EQ(LogLookup::OK, lookup.CertificateAuditProof(1234, hash,
&proof));
+ EXPECT_EQ(LogLookup::OK,
+ lookup.CertificateAuditProof(logged_cert.sct().timestamp(),
+
logged_cert.certificate_sha256_hash(),
+ &proof));
EXPECT_EQ(LogVerifier::VERIFY_OK,
this->verifier_->VerifyMerkleAuditProof(logged_cert.sct(),
proof));
}

// Build a bigger tree so that we actually verify a non-empty path.
TYPED_TEST(LogLookupTest, VerifyWithPath) {
- string hash("1234xyzw", 8);
- string cert("certificate", 11);
-
LoggedCertificate logged_certs[13];

// Make the tree not balanced for extra fun.
for (int i = 0; i < 13; ++i) {
- logged_certs[i].set_certificate_sha256_hash(hash +
static_cast<char>(i));
- logged_certs[i].mutable_sct()->set_timestamp(1234 + i);
- logged_certs[i].mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_certs[i].mutable_sct()->mutable_entry()->
- set_leaf_certificate(cert + static_cast<char>(i));
-
+ this->test_signer_.CreateUnique(&logged_certs[i]);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_certs[i]));
+ this->db()->CreatePendingCertificateEntry(logged_certs[i]));
}

EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());

- LogLookup lookup(this->db_);
+ LogLookup lookup(this->db());
MerkleAuditProof proof;

- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 13; ++i) {
EXPECT_EQ(LogLookup::OK,
- lookup.CertificateAuditProof(1234 + i,
- hash + static_cast<char>(i),
- &proof));
+ lookup.CertificateAuditProof(
+ logged_certs[i].sct().timestamp(),
+ logged_certs[i].certificate_sha256_hash(), &proof));
EXPECT_EQ(LogVerifier::VERIFY_OK,
-
this->verifier_->VerifyMerkleAuditProof(logged_certs[i].sct(),
- proof));
+ this->verifier_->VerifyMerkleAuditProof(
+ logged_certs[i].sct(), proof));
}
}

} // namespace
int main(int argc, char**argv) {
+ // Change the defaults. Can be overridden on command line.
+ // Log to stderr instead of log files.
+ FLAGS_logtostderr = true;
+ // Only log fatal messages by default.
+ FLAGS_minloglevel = 3;
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
=======================================
--- /src/log/log_signer.cc Wed Oct 10 10:16:52 2012
+++ /src/log/log_signer.cc Thu Oct 11 10:55:00 2012
@@ -1,4 +1,4 @@
-#include <assert.h>
+#include <glog/logging.h>
#include <openssl/evp.h>
#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER < 0x10000000
@@ -27,7 +27,7 @@
sig_algo_ = DigitallySigned::ECDSA;
break;
default:
- assert(false);
+ LOG(FATAL) << "Unsupported key type";
}
}

@@ -50,8 +50,8 @@

DigitallySigned signature;
Sign(CERTIFICATE_TIMESTAMP, serialized_sct, &signature);
- res = Serializer::SerializeDigitallySigned(signature, result);
- assert(res == Serializer::OK);
+ CHECK_EQ(Serializer::OK,
+ Serializer::SerializeDigitallySigned(signature, result));
return OK;
}

@@ -79,8 +79,8 @@

DigitallySigned signature;
Sign(TREE_HEAD, serialized_sth, &signature);
- res = Serializer::SerializeDigitallySigned(signature, result);
- assert(res == Serializer::OK);
+ CHECK_EQ(Serializer::OK,
+ Serializer::SerializeDigitallySigned(signature, result));
return OK;
}

@@ -97,7 +97,7 @@
// static
LogSigner::SignResult
LogSigner::GetSerializeError(Serializer::SerializeResult result) {
- SignResult sign_result = UNKNOWN_ERROR;
+ SignResult sign_result;
switch (result) {
case Serializer::INVALID_TYPE:
sign_result = INVALID_ENTRY_TYPE;
@@ -112,7 +112,7 @@
sign_result = INVALID_HASH_LENGTH;
break;
default:
- assert(false);
+ LOG(FATAL) << "Unknown Serializer error code " << result;
}
return sign_result;
}
@@ -131,12 +131,12 @@
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
// NOTE: this syntax for setting the hash function requires OpenSSL >=
1.0.0.
- assert(EVP_SignInit(&ctx, EVP_sha256()) == 1);
- assert(EVP_SignUpdate(&ctx, data.data(), data.size()) == 1);
+ CHECK_EQ(1, EVP_SignInit(&ctx, EVP_sha256()));
+ CHECK_EQ(1, EVP_SignUpdate(&ctx, data.data(), data.size()));
unsigned int sig_size = EVP_PKEY_size(pkey_);
unsigned char *sig = new unsigned char[sig_size];

- assert(EVP_SignFinal(&ctx, sig, &sig_size, pkey_) == 1);
+ CHECK_EQ(1, EVP_SignFinal(&ctx, sig, &sig_size, pkey_));

EVP_MD_CTX_cleanup(&ctx);
string ret(reinterpret_cast<char*>(sig), sig_size);
@@ -154,7 +154,7 @@
sig_algo_ = DigitallySigned::ECDSA;
break;
default:
- assert(false);
+ LOG(FATAL) << "Unsupported key type";
}
}

@@ -226,7 +226,7 @@
// static
LogSigVerifier::VerifyResult
LogSigVerifier::GetSerializeError(Serializer::SerializeResult result) {
- VerifyResult verify_result = UNKNOWN_ERROR;
+ VerifyResult verify_result;
switch (result) {
case Serializer::INVALID_TYPE:
verify_result = INVALID_ENTRY_TYPE;
@@ -241,7 +241,7 @@
verify_result = INVALID_HASH_LENGTH;
break;
default:
- assert(false);
+ LOG(FATAL) << "Unknown Deserializer error code " << result;
}
return verify_result;
}
@@ -250,7 +250,7 @@
LogSigVerifier::VerifyResult
LogSigVerifier::GetDeserializeSignatureError(
Deserializer::DeserializeResult result) {
- VerifyResult verify_result = UNKNOWN_ERROR;
+ VerifyResult verify_result;
switch (result) {
case Deserializer::INPUT_TOO_SHORT:
verify_result = SIGNATURE_TOO_SHORT;
@@ -265,7 +265,7 @@
verify_result = SIGNATURE_TOO_LONG;
break;
default:
- assert(false);
+ LOG(FATAL) << "Unknown Deserializer error code " << result;
}
return verify_result;
}
@@ -289,8 +289,8 @@
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
// NOTE: this syntax for setting the hash function requires OpenSSL >=
1.0.0.
- assert(EVP_VerifyInit(&ctx, EVP_sha256()) == 1);
- assert(EVP_VerifyUpdate(&ctx, data.data(), data.size()) == 1);
+ CHECK_EQ(1, EVP_VerifyInit(&ctx, EVP_sha256()));
+ CHECK_EQ(1, EVP_VerifyUpdate(&ctx, data.data(), data.size()));
bool ret =
(EVP_VerifyFinal(&ctx,
reinterpret_cast<const unsigned
char*>(sig_string.data()),
=======================================
--- /src/log/log_signer.h Wed Oct 10 10:16:52 2012
+++ /src/log/log_signer.h Thu Oct 11 10:55:00 2012
@@ -26,7 +26,6 @@
EMPTY_CERTIFICATE,
CERTIFICATE_TOO_LONG,
INVALID_HASH_LENGTH,
- UNKNOWN_ERROR,
};

// The protobuf-agnostic library version:
@@ -81,7 +80,6 @@
SIGNATURE_ALGORITHM_MISMATCH,
INVALID_SIGNATURE,
INVALID_HASH_LENGTH,
- UNKNOWN_ERROR,
};

// The protobuf-agnostic library version.
=======================================
--- /src/log/log_signer_test.cc Wed Oct 10 10:16:52 2012
+++ /src/log/log_signer_test.cc Thu Oct 11 10:55:00 2012
@@ -1,13 +1,13 @@
+#include <gflags/gflags.h>
+#include <glog/logging.h>
#include <gtest/gtest.h>
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
#include <stdint.h>
#include <string>

#include "ct.pb.h"
#include "log_signer.h"
#include "serializer.h"
+#include "test_signer.h"
#include "util.h"

namespace {
@@ -19,174 +19,94 @@
using ct::SignedTreeHead;
using std::string;

-// A slightly shorter notation for constructing binary blobs from test
vectors.
-string S(const char *hexstring, size_t byte_length) {
- return string(hexstring, 2 * byte_length);
-}
-
-string B(const char *hexstring, size_t byte_length) {
- return util::BinaryString(S(hexstring, byte_length));
-}
-
-// The reverse.
+// A slightly shorter notation for constructing hex strings from binary
blobs.
string H(const string &byte_string) {
return util::HexString(byte_string);
}

-const char *ecp256_private_key = {
- "-----BEGIN EC PRIVATE KEY-----\n"
- "MHcCAQEEIG8QAquNnarN6Ik2cMIZtPBugh9wNRe0e309MCmDfBGuoAoGCCqGSM49\n"
- "AwEHoUQDQgAES0AfBkjr7b8b19p5Gk8plSAN16wWXZyhYsH6FMCEUK60t7pem/ck\n"
- "oPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
- "-----END EC PRIVATE KEY-----\n"
-};
-
-const char *ecp256_public_key = {
- "-----BEGIN PUBLIC KEY-----\n"
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES0AfBkjr7b8b19p5Gk8plSAN16wW\n"
- "XZyhYsH6FMCEUK60t7pem/ckoPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
- "-----END PUBLIC KEY-----\n"
-};
-
-EVP_PKEY* PrivateKeyFromPem(const string &pemkey) {
- BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
- EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
- assert(pkey != NULL);
- BIO_free(bio);
- return pkey;
-}
-
-EVP_PKEY* PublicKeyFromPem(const string &pemkey) {
- BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
- EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
- assert(pkey != NULL);
- BIO_free(bio);
- return pkey;
-}
-
-// A valid signature on the default SCT, using the private key above.
-const char kDefaultSCTSignature[] =
- "3046022100ee89fb556fd72264098e8c80da9141c2aa2a788587bcc73d235ff7fd42dd5a11"
- "022100a3df4dd9c6cc6374ec1a7ba06d3a3c791e542287819fe1a15ca134d9cbb8bb74";
-
-const size_t kDefaultSCTSignatureLength = 72;
-
-// A valid signature on the default STH, using the private key above.
-const char kDefaultSTHSignature[] =
- "3046022100b86d453a133102e7a83fb3c123b7080d5ed38231c0b4676614717c057133614a"
- "022100f11a6d22e266993242109d76465e5659c400a29464386697efd84f9a78f52d21";
-
-const size_t kDefaultSTHSignatureLength = 72;
-
class LogSignerTest : public ::testing::Test {
protected:
LogSignerTest() : signer_(NULL),
- verifier_(NULL),
- sct_(),
- sth_() {
- sct_.set_timestamp(1234);
- sct_.mutable_entry()->set_type(CertificateEntry::X509_ENTRY);
- sct_.mutable_entry()->set_leaf_certificate("certificate");
- sct_.mutable_signature()->set_hash_algorithm(DigitallySigned::SHA256);
- sct_.mutable_signature()->set_sig_algorithm(DigitallySigned::ECDSA);
- sct_.mutable_signature()->set_signature(B(kDefaultSCTSignature,
- kDefaultSCTSignatureLength));
- sth_.set_timestamp(2345);
- sth_.set_tree_size(6);
- sth_.set_root_hash("imustbeexactlythirtytwobyteslong");
- sth_.mutable_signature()->set_hash_algorithm(DigitallySigned::SHA256);
- sth_.mutable_signature()->set_sig_algorithm(DigitallySigned::ECDSA);
- sth_.mutable_signature()->set_signature(B(kDefaultSTHSignature,
- kDefaultSTHSignatureLength));
- }
+ verifier_(NULL) {}

- const SignedCertificateTimestamp &DefaultSCT() const { return sct_; }
-
- uint64_t DefaultSCTTimestamp() const { return sct_.timestamp(); }
-
- const string &DefaultCert() const {
- return sct_.entry().leaf_certificate();
+ void SetUp() {
+ signer_ = TestSigner::DefaultSigner();
+ verifier_ = TestSigner::DefaultVerifier();
}

- ct::CertificateEntryType DefaultType() const {
- return static_cast<ct::CertificateEntryType>(sct_.entry().type());
+ ~LogSignerTest() {
+ delete signer_;
+ delete verifier_;
}

- const DigitallySigned &DefaultSCTSignature() const { return
sct_.signature(); }
-
- string DefaultSerializedSCTSignature() const {
- string serialized_sig;
- Serializer::SerializeDigitallySigned(DefaultSCTSignature(),
&serialized_sig);
- return serialized_sig;
+ // For the protobuf-agnostic version. The enum values are required to
match,
+ // so we convert by name.
+ static ct::CertificateEntryType SignedType(
+ CertificateEntry::Type type) {
+ switch (type) {
+ case CertificateEntry::X509_ENTRY:
+ return ct::X509_ENTRY;
+ case CertificateEntry::PRECERT_ENTRY:
+ return ct::PRECERT_ENTRY;
+ default:
+ DLOG(FATAL) << "Unknown entry type " << type;
+ }
}

- const SignedTreeHead &DefaultSTH() const { return sth_; }
-
- uint64_t DefaultSTHTimestamp() const { return sth_.timestamp(); }
-
- uint64_t DefaultTreeSize() const { return sth_.tree_size(); }
-
- string DefaultRootHash() const { return sth_.root_hash(); }
-
- const DigitallySigned &DefaultSTHSignature() const { return
sth_.signature(); }
-
- string DefaultSerializedSTHSignature() const {
+ static string SerializedSignature(const DigitallySigned &signature) {
string serialized_sig;
- Serializer::SerializeDigitallySigned(DefaultSTHSignature(),
&serialized_sig);
+ CHECK_EQ(Serializer::OK,
+ Serializer::SerializeDigitallySigned(signature,
+ &serialized_sig));
return serialized_sig;
}
-
- void SetUp() {
- EVP_PKEY *pkey = PrivateKeyFromPem(ecp256_private_key);
- EVP_PKEY *pubkey = PublicKeyFromPem(ecp256_public_key);
- signer_ = new LogSigner(pkey);
- verifier_ = new LogSigVerifier(pubkey);
- ASSERT_TRUE(signer_ != NULL);
- ASSERT_TRUE(verifier_ != NULL);
- }
-
- ~LogSignerTest() {
- delete signer_;
- delete verifier_;
- }

LogSigner *signer_;
LogSigVerifier *verifier_;
- SignedCertificateTimestamp sct_;
- SignedTreeHead sth_;
+ TestSigner test_signer_;
};

TEST_F(LogSignerTest, VerifySCTKatTest) {
- EXPECT_EQ(LogSigVerifier::OK,
verifier_->VerifySCTSignature(DefaultSCT()));
+ SignedCertificateTimestamp default_sct;
+ TestSigner::SetDefaults(&default_sct);
+
+ EXPECT_EQ(LogSigVerifier::OK,
verifier_->VerifySCTSignature(default_sct));
+
EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(),
-
DefaultSerializedSCTSignature()));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(),
+ SerializedSignature(default_sct.signature())));
}

TEST_F(LogSignerTest, VerifySTHKatTest) {
- EXPECT_EQ(LogSigVerifier::OK,
verifier_->VerifySTHSignature(DefaultSTH()));
+ SignedTreeHead default_sth;
+ TestSigner::SetDefaults(&default_sth);
+
+ EXPECT_EQ(LogSigVerifier::OK,
verifier_->VerifySTHSignature(default_sth));
+
EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
-
DefaultSerializedSTHSignature()));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(),
+ SerializedSignature(default_sth.signature())));
}

TEST_F(LogSignerTest, SignAndVerifySCT) {
- SignedCertificateTimestamp sct;
- sct.CopyFrom(DefaultSCT());
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
+ sct.CopyFrom(default_sct);
sct.clear_signature();
ASSERT_FALSE(sct.has_signature());

EXPECT_EQ(LogSigner::OK, signer_->SignCertificateTimestamp(&sct));
EXPECT_TRUE(sct.has_signature());
- EXPECT_EQ(DefaultSCTSignature().hash_algorithm(),
+ EXPECT_EQ(default_sct.signature().hash_algorithm(),
sct.signature().hash_algorithm());
- EXPECT_EQ(DefaultSCTSignature().sig_algorithm(),
+ EXPECT_EQ(default_sct.signature().sig_algorithm(),
sct.signature().sig_algorithm());
// We should get a fresh signature.
- EXPECT_NE(H(DefaultSCTSignature().signature()),
+ EXPECT_NE(H(default_sct.signature().signature()),
H(sct.signature().signature()));
// But it should still be valid.
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));
@@ -194,29 +114,34 @@
// The second version.
string serialized_sig;
EXPECT_EQ(LogSigner::OK,
- signer_->SignCertificateTimestamp(DefaultSCTTimestamp(),
- DefaultType(), DefaultCert(),
- &serialized_sig));
- EXPECT_NE(H(DefaultSerializedSCTSignature()), H(serialized_sig));
+ signer_->SignCertificateTimestamp(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(), &serialized_sig));
+
+ string default_serialized_sig =
SerializedSignature(default_sct.signature());
+ EXPECT_NE(H(default_serialized_sig), H(serialized_sig));
EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(), serialized_sig));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(),
+ default_serialized_sig));
}

TEST_F(LogSignerTest, SignAndVerifySTH) {
- SignedTreeHead sth;
- sth.CopyFrom(DefaultSTH());
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
+ sth.CopyFrom(default_sth);
sth.clear_signature();
ASSERT_FALSE(sth.has_signature());

EXPECT_EQ(LogSigner::OK, signer_->SignTreeHead(&sth));
EXPECT_TRUE(sth.has_signature());
- EXPECT_EQ(DefaultSTHSignature().hash_algorithm(),
+ EXPECT_EQ(default_sth.signature().hash_algorithm(),
sth.signature().hash_algorithm());
- EXPECT_EQ(DefaultSTHSignature().sig_algorithm(),
+ EXPECT_EQ(default_sth.signature().sig_algorithm(),
sth.signature().sig_algorithm());
// We should get a fresh signature.
- EXPECT_NE(H(DefaultSTHSignature().signature()),
+ EXPECT_NE(H(default_sth.signature().signature()),
H(sth.signature().signature()));
// But it should still be valid.
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySTHSignature(sth));
@@ -224,18 +149,22 @@
// The second version.
string serialized_sig;
EXPECT_EQ(LogSigner::OK,
- signer_->SignTreeHead(DefaultSTHTimestamp(), DefaultTreeSize(),
- DefaultRootHash(), &serialized_sig));
- EXPECT_NE(H(DefaultSerializedSTHSignature()), H(serialized_sig));
+ signer_->SignTreeHead(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(), &serialized_sig));
+
+ string default_serialized_sig =
SerializedSignature(default_sth.signature());
+ EXPECT_NE(H(default_serialized_sig), H(serialized_sig));
EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
serialized_sig));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(), default_serialized_sig));
}

TEST_F(LogSignerTest, SignAndVerifySCTApiCrossCheck) {
- SignedCertificateTimestamp sct;
- sct.CopyFrom(DefaultSCT());
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
+ sct.CopyFrom(default_sct);
sct.clear_signature();

EXPECT_EQ(LogSigner::OK, signer_->SignCertificateTimestamp(&sct));
@@ -246,14 +175,16 @@
Serializer::SerializeDigitallySigned(sct.signature(),
&serialized_sig));
EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(), serialized_sig));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(), serialized_sig));

// The second version.
serialized_sig.clear();
EXPECT_EQ(LogSigner::OK,
- signer_->SignCertificateTimestamp(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(),
&serialized_sig));
+ signer_->SignCertificateTimestamp(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(), &serialized_sig));

// Deserialize and verify.
sct.clear_signature();
@@ -264,8 +195,9 @@
}

TEST_F(LogSignerTest, SignAndVerifySTHApiCrossCheck) {
- SignedTreeHead sth;
- sth.CopyFrom(DefaultSTH());
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
+ sth.CopyFrom(default_sth);
sth.clear_signature();

EXPECT_EQ(LogSigner::OK, signer_->SignTreeHead(&sth));
@@ -276,15 +208,16 @@
Serializer::SerializeDigitallySigned(sth.signature(),
&serialized_sig));
EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
serialized_sig));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(), serialized_sig));

// The second version.
serialized_sig.clear();
EXPECT_EQ(LogSigner::OK,
- signer_->SignTreeHead(DefaultSTHTimestamp(), DefaultTreeSize(),
- DefaultRootHash(), &serialized_sig));
+ signer_->SignTreeHead(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(), &serialized_sig));

// Deserialize and verify.
sth.clear_signature();
@@ -295,17 +228,20 @@
}

TEST_F(LogSignerTest, SignInvalidType) {
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
string serialized_sig;
EXPECT_EQ(LogSigner::INVALID_ENTRY_TYPE,
signer_->SignCertificateTimestamp(
- DefaultSCTTimestamp(),
+ default_sct.timestamp(),
static_cast<ct::CertificateEntryType>(-1),
- DefaultCert(),
+ default_sct.entry().leaf_certificate(),
&serialized_sig));
}

TEST_F(LogSignerTest, SignEmptyCert) {
- SignedCertificateTimestamp sct;
- sct.CopyFrom(DefaultSCT());
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
+ sct.CopyFrom(default_sct);
sct.clear_signature();
sct.mutable_entry()->clear_leaf_certificate();

@@ -315,14 +251,15 @@
string serialized_sig;
string empty_cert;
EXPECT_EQ(LogSigner::EMPTY_CERTIFICATE,
- signer_->SignCertificateTimestamp(DefaultSCTTimestamp(),
DefaultType(),
- empty_cert,
- &serialized_sig));
+ signer_->SignCertificateTimestamp(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ empty_cert, &serialized_sig));
}

TEST_F(LogSignerTest, SignBadRootHash) {
- SignedTreeHead sth;
- sth.CopyFrom(DefaultSTH());
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
+ sth.CopyFrom(default_sth);
sth.clear_signature();
sth.set_root_hash("bad");

@@ -330,158 +267,195 @@

string serialized_sig;
EXPECT_EQ(LogSigner::INVALID_HASH_LENGTH,
- signer_->SignTreeHead(DefaultSTHTimestamp(), DefaultTreeSize(),
- "bad", &serialized_sig));
+ signer_->SignTreeHead(default_sth.timestamp(),
+ default_sth.tree_size(), "bad",
+ &serialized_sig));
}

TEST_F(LogSignerTest, VerifyChangeSCTTimestamp) {
- SignedCertificateTimestamp sct;
- sct.CopyFrom(DefaultSCT());
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
+ sct.CopyFrom(default_sct);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));

- sct.set_timestamp(4321);
+ uint64_t new_timestamp = default_sct.timestamp() + 1000;
+
+ sct.set_timestamp(new_timestamp);
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
verifier_->VerifySCTSignature(sct));

EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(),
-
DefaultSerializedSCTSignature()));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(),
+ SerializedSignature(default_sct.signature())));

EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
- verifier_->VerifySCTSignature(4321, DefaultType(),
DefaultCert(),
-
DefaultSerializedSCTSignature()));
+ verifier_->VerifySCTSignature(
+ new_timestamp, SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(),
+ SerializedSignature(default_sct.signature())));
}

TEST_F(LogSignerTest, VerifyChangeSTHTimestamp) {
- SignedTreeHead sth;
- sth.CopyFrom(DefaultSTH());
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
+ sth.CopyFrom(default_sth);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySTHSignature(sth));

- sth.set_timestamp(4321);
+ uint64_t new_timestamp = default_sth.timestamp() + 1000;
+ sth.set_timestamp(new_timestamp);
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
verifier_->VerifySTHSignature(sth));

EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
-
DefaultSerializedSTHSignature()));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(),
+ SerializedSignature(default_sth.signature())));
+
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
- verifier_->VerifySTHSignature(4321, DefaultTreeSize(),
- DefaultRootHash(),
-
DefaultSerializedSTHSignature()));
+ verifier_->VerifySTHSignature(
+ new_timestamp, default_sth.tree_size(),
+ default_sth.root_hash(),
+ SerializedSignature(default_sth.signature())));
}

TEST_F(LogSignerTest, VerifyChangeType) {
- SignedCertificateTimestamp sct;
- sct.CopyFrom(DefaultSCT());
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
+ sct.CopyFrom(default_sct);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));

+ CHECK_NE(CertificateEntry::PRECERT_ENTRY, sct.entry().type());
sct.mutable_entry()->set_type(CertificateEntry::PRECERT_ENTRY);
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
verifier_->VerifySCTSignature(sct));

EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(),
-
DefaultSerializedSCTSignature()));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(),
+ SerializedSignature(default_sct.signature())));
+

EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
- ct::PRECERT_ENTRY,
- DefaultCert(),
-
DefaultSerializedSCTSignature()));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
+ SignedType(CertificateEntry::PRECERT_ENTRY),
+ default_sct.entry().leaf_certificate(),
+ SerializedSignature(default_sct.signature())));
}

TEST_F(LogSignerTest, VerifyChangeCert) {
- SignedCertificateTimestamp sct;
- sct.CopyFrom(DefaultSCT());
+ SignedCertificateTimestamp default_sct, sct, sct2;
+ TestSigner::SetDefaults(&default_sct);
+ sct.CopyFrom(default_sct);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));

- sct.mutable_entry()->set_leaf_certificate("bazinga");
+ string new_cert = test_signer_.UniqueFakeCertBytestring();
+ sct.mutable_entry()->set_leaf_certificate(new_cert);
+
+ // Check that we can successfully sign and verify the new sct.
+ sct2.CopyFrom(sct);
+ EXPECT_EQ(LogSigner::OK, signer_->SignCertificateTimestamp(&sct2));
+ EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct2));
+
+ // We should not be able to verify the new cert with the old signature.
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
verifier_->VerifySCTSignature(sct));

EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(),
-
DefaultSerializedSCTSignature()));
-
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(),
+ SerializedSignature(default_sct.signature())));
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- "bazinga",
-
DefaultSerializedSCTSignature()));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ new_cert, SerializedSignature(default_sct.signature())));
}

TEST_F(LogSignerTest, VerifyChangeTreeSize) {
- SignedTreeHead sth;
- sth.CopyFrom(DefaultSTH());
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
+ sth.CopyFrom(default_sth);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySTHSignature(sth));

- sth.set_tree_size(4321);
+ uint64_t new_tree_size = default_sth.tree_size() + 1;
+ sth.set_tree_size(new_tree_size);
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
verifier_->VerifySTHSignature(sth));

EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
-
DefaultSerializedSTHSignature()));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(),
+ SerializedSignature(default_sth.signature())));

EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(), 4321,
- DefaultRootHash(),
-
DefaultSerializedSTHSignature()));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), new_tree_size,
+ default_sth.root_hash(),
+ SerializedSignature(default_sth.signature())));
}

TEST_F(LogSignerTest, VerifySCTBadHashAlgorithm) {
- SignedCertificateTimestamp sct;
- sct.CopyFrom(DefaultSCT());
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
+ sct.CopyFrom(default_sct);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));

+ CHECK_NE(DigitallySigned::SHA224, sct.signature().hash_algorithm());
sct.mutable_signature()->set_hash_algorithm(DigitallySigned::SHA224);
EXPECT_EQ(LogSigVerifier::HASH_ALGORITHM_MISMATCH,
verifier_->VerifySCTSignature(sct));
}

TEST_F(LogSignerTest, VerifySTHBadHashAlgorithm) {
- SignedTreeHead sth;
- sth.CopyFrom(DefaultSTH());
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
+ sth.CopyFrom(default_sth);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySTHSignature(sth));

+ CHECK_NE(DigitallySigned::SHA224, sth.signature().hash_algorithm());
sth.mutable_signature()->set_hash_algorithm(DigitallySigned::SHA224);
EXPECT_EQ(LogSigVerifier::HASH_ALGORITHM_MISMATCH,
verifier_->VerifySTHSignature(sth));
}

TEST_F(LogSignerTest, VerifySCTBadSignatureAlgorithm) {
- SignedCertificateTimestamp sct;
- sct.CopyFrom(DefaultSCT());
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
+ sct.CopyFrom(default_sct);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));

+ CHECK_NE(DigitallySigned::DSA, sct.signature().sig_algorithm());
sct.mutable_signature()->set_sig_algorithm(DigitallySigned::DSA);
EXPECT_EQ(LogSigVerifier::SIGNATURE_ALGORITHM_MISMATCH,
verifier_->VerifySCTSignature(sct));
}

TEST_F(LogSignerTest, VerifySTHBadSignatureAlgorithm) {
- SignedTreeHead sth;
- sth.CopyFrom(DefaultSTH());
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
+ sth.CopyFrom(default_sth);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySTHSignature(sth));

+ CHECK_NE(DigitallySigned::DSA, sth.signature().sig_algorithm());
sth.mutable_signature()->set_sig_algorithm(DigitallySigned::DSA);
EXPECT_EQ(LogSigVerifier::SIGNATURE_ALGORITHM_MISMATCH,
verifier_->VerifySTHSignature(sth));
}

TEST_F(LogSignerTest, VerifyBadSCTSignature) {
- SignedCertificateTimestamp sct;
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
// Too short.
- sct.CopyFrom(DefaultSCT());
+ sct.CopyFrom(default_sct);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));

- string bad_signature = DefaultSCTSignature().signature();
+ string bad_signature = default_sct.signature().signature();
bad_signature.erase(bad_signature.end() - 1);
sct.mutable_signature()->set_signature(bad_signature);
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
@@ -491,10 +465,10 @@
// OpenSSL ECDSA Verify parses *up to* a given number of bytes,
// rather than exactly the given number of bytes, and hence appending
// garbage in the end still results in a valid signature.
- // sct.CopyFrom(DefaultSCT());
+ // sct.CopyFrom(default_sct);
// EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));

- // bad_signature = DefaultSCTSignature().signature();
+ // bad_signature = default_sct.signature().signature();
// bad_signature.push_back(0x42);

// sct.mutable_signature()->set_signature(bad_signature);
@@ -502,11 +476,11 @@
// verifier_->VerifySCTSignature(sct));

// Flip the lsb of each byte one by one.
- for (size_t i = 0; i < DefaultSCTSignature().signature().size(); ++i) {
- sct.CopyFrom(DefaultSCT());
+ for (size_t i = 0; i < default_sct.signature().signature().size(); ++i) {
+ sct.CopyFrom(default_sct);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySCTSignature(sct));

- bad_signature = DefaultSCTSignature().signature();
+ bad_signature = default_sct.signature().signature();
bad_signature[i] ^= 0x01;
sct.mutable_signature()->set_signature(bad_signature);
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
@@ -515,12 +489,13 @@
}

TEST_F(LogSignerTest, VerifyBadSTHSignature) {
- SignedTreeHead sth;
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
// Too short.
- sth.CopyFrom(DefaultSTH());
+ sth.CopyFrom(default_sth);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySTHSignature(sth));

- string bad_signature = DefaultSTHSignature().signature();
+ string bad_signature = default_sth.signature().signature();
bad_signature.erase(bad_signature.end() - 1);
sth.mutable_signature()->set_signature(bad_signature);
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
@@ -530,10 +505,10 @@
// OpenSSL ECDSA Verify parses *up to* a given number of bytes,
// rather than exactly the given number of bytes, and hence appending
// garbage in the end still results in a valid signature.
- // sth.CopyFrom(DefaultSTH());
+ // sth.CopyFrom(default_sth);
// EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySTHSignature(sth));

- // bad_signature = DefaultSTHSignature().signature();
+ // bad_signature = default_sth.signature().signature();
// bad_signature.push_back(0x42);

// sth.mutable_signature()->set_signature(bad_signature);
@@ -541,11 +516,11 @@
// verifier_->VerifySTHSignature(sth));

// Flip the lsb of each byte one by one.
- for (size_t i = 0; i < DefaultSTHSignature().signature().size(); ++i) {
- sth.CopyFrom(DefaultSTH());
+ for (size_t i = 0; i < default_sth.signature().signature().size(); ++i) {
+ sth.CopyFrom(default_sth);
EXPECT_EQ(LogSigVerifier::OK, verifier_->VerifySTHSignature(sth));

- bad_signature = DefaultSTHSignature().signature();
+ bad_signature = default_sth.signature().signature();
bad_signature[i] ^= 0x01;
sth.mutable_signature()->set_signature(bad_signature);
EXPECT_EQ(LogSigVerifier::INVALID_SIGNATURE,
@@ -554,21 +529,26 @@
}

TEST_F(LogSignerTest, VerifyBadSerializedSCTSignature) {
- string serialized_sig = DefaultSerializedSCTSignature();
+ SignedCertificateTimestamp default_sct, sct;
+ TestSigner::SetDefaults(&default_sct);
+ string serialized_sig = SerializedSignature(default_sct.signature());
EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(), serialized_sig));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(), serialized_sig));
// Too short.
string bad_signature = serialized_sig.substr(0, serialized_sig.size() -
1);
EXPECT_EQ(LogSigVerifier::SIGNATURE_TOO_SHORT,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(), bad_signature));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(), bad_signature));
// Too long.
bad_signature = serialized_sig;
bad_signature.push_back(0x42);
EXPECT_EQ(LogSigVerifier::SIGNATURE_TOO_LONG,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
DefaultType(),
- DefaultCert(), bad_signature));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(), bad_signature));

// Flip the lsb of each byte one by one.
for (size_t i = 0; i < serialized_sig.size(); ++i) {
@@ -576,31 +556,34 @@
bad_signature[i] ^= 0x01;
// Error codes vary, depending on which byte was flipped.
EXPECT_NE(LogSigVerifier::OK,
- verifier_->VerifySCTSignature(DefaultSCTTimestamp(),
- DefaultType(),
- DefaultCert(), bad_signature));
+ verifier_->VerifySCTSignature(
+ default_sct.timestamp(),
+ SignedType(default_sct.entry().type()),
+ default_sct.entry().leaf_certificate(), bad_signature));
}
}

TEST_F(LogSignerTest, VerifyBadSerializedSTHSignature) {
- string serialized_sig = DefaultSerializedSTHSignature();
+ SignedTreeHead default_sth, sth;
+ TestSigner::SetDefaults(&default_sth);
+ string serialized_sig = SerializedSignature(default_sth.signature());
EXPECT_EQ(LogSigVerifier::OK,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
serialized_sig));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(), serialized_sig));
// Too short.
string bad_signature = serialized_sig.substr(0, serialized_sig.size() -
1);
EXPECT_EQ(LogSigVerifier::SIGNATURE_TOO_SHORT,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
bad_signature));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(), bad_signature));
// Too long.
bad_signature = serialized_sig;
bad_signature.push_back(0x42);
EXPECT_EQ(LogSigVerifier::SIGNATURE_TOO_LONG,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
bad_signature));
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(), bad_signature));

// Flip the lsb of each byte one by one.
for (size_t i = 0; i < serialized_sig.size(); ++i) {
@@ -608,16 +591,22 @@
bad_signature[i] ^= 0x01;
// Error codes vary, depending on which byte was flipped.
EXPECT_NE(LogSigVerifier::OK,
- verifier_->VerifySTHSignature(DefaultSTHTimestamp(),
- DefaultTreeSize(),
- DefaultRootHash(),
bad_signature));
-
+ verifier_->VerifySTHSignature(
+ default_sth.timestamp(), default_sth.tree_size(),
+ default_sth.root_hash(), bad_signature));
}
}

} // namespace

int main(int argc, char **argv) {
+ // Change the defaults. Can be overridden on command line.
+ // Log to stderr instead of log files.
+ FLAGS_logtostderr = true;
+ // Only log fatal messages by default.
+ FLAGS_minloglevel = 3;
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
=======================================
--- /src/log/log_verifier.cc Tue Oct 9 04:30:56 2012
+++ /src/log/log_verifier.cc Thu Oct 11 10:55:00 2012
@@ -1,11 +1,11 @@
#include <stdint.h>

+#include "cert_submission_handler.h"
#include "ct.pb.h"
#include "log_signer.h"
#include "log_verifier.h"
#include "merkle_verifier.h"
#include "serializer.h"
-#include "submission_handler.h"
#include "util.h"

using ct::MerkleAuditProof;
=======================================
--- /src/log/sqlite_db.cc Tue Oct 9 06:20:07 2012
+++ /src/log/sqlite_db.cc Thu Oct 11 10:55:00 2012
@@ -36,6 +36,14 @@
SQLiteDB::~SQLiteDB() {
CHECK_EQ(SQLITE_OK, sqlite3_close(db_));
}
+
+void SQLiteDB::BeginTransaction() {
+ CHECK_EQ(SQLITE_OK, sqlite3_exec(db_, "BEGIN;", NULL, NULL, NULL));
+}
+
+void SQLiteDB::EndTransaction() {
+ CHECK_EQ(SQLITE_OK, sqlite3_exec(db_, "COMMIT;", NULL, NULL, NULL));
+}

// Reduce the ugliness of the sqlite3 API.
class Statement {
=======================================
--- /src/log/sqlite_db.h Tue Oct 9 06:20:07 2012
+++ /src/log/sqlite_db.h Thu Oct 11 10:55:00 2012
@@ -1,5 +1,7 @@
/* -*- mode: c++; indent-tabs-mode: nil -*- */

+#ifndef SQLITE_DB_H
+#define SQLITE_DB_H
#include <string>

#include "database.h"
@@ -12,6 +14,15 @@

~SQLiteDB();

+ // Temporary, for benchmarking. If we want to do this for real, then
+ // we need to implement rollbacks for errors that occur in the middle
+ // of a transaction.
+ virtual bool Transactional() const { return true; }
+
+ void BeginTransaction();
+
+ void EndTransaction();
+
virtual WriteResult
CreatePendingCertificateEntry_(const ct::LoggedCertificate &logged_cert);

@@ -36,3 +47,4 @@
private:
sqlite3 *db_;
};
+#endif
=======================================
--- /src/log/tree_signer.cc Tue Oct 9 04:30:56 2012
+++ /src/log/tree_signer.cc Thu Oct 11 10:55:00 2012
@@ -46,7 +46,7 @@
return DB_ERROR;
}
} else {
- CHECK_EQ(db_result, Database::OK) << "Latest STH lookup failed";
+ CHECK_EQ(db_result, Database::LOOKUP_OK) << "Latest STH lookup failed";
if (sth.timestamp() != latest_tree_head_.timestamp() ||
sth.tree_size() != latest_tree_head_.tree_size() ||
sth.root_hash() != latest_tree_head_.root_hash()) {
=======================================
--- /src/log/tree_signer_test.cc Tue Oct 9 04:30:56 2012
+++ /src/log/tree_signer_test.cc Thu Oct 11 10:55:00 2012
@@ -1,225 +1,123 @@
/* -*- indent-tabs-mode: nil -*- */

+#include <gflags/gflags.h>
+#include <glog/logging.h>
#include <gtest/gtest.h>
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
#include <stdint.h>
#include <string>

#include "ct.pb.h"
#include "file_db.h"
-#include "file_storage.h"
#include "log_signer.h"
#include "log_verifier.h"
#include "merkle_verifier.h"
#include "sqlite_db.h"
+#include "test_db.h"
+#include "test_signer.h"
#include "tree_signer.h"
#include "util.h"

namespace {

-using ct::CertificateEntry;
using ct::LoggedCertificate;
using ct::SignedTreeHead;
using std::string;

-const char *ecp256_private_key = {
- "-----BEGIN EC PRIVATE KEY-----\n"
- "MHcCAQEEIG8QAquNnarN6Ik2cMIZtPBugh9wNRe0e309MCmDfBGuoAoGCCqGSM49\n"
- "AwEHoUQDQgAES0AfBkjr7b8b19p5Gk8plSAN16wWXZyhYsH6FMCEUK60t7pem/ck\n"
- "oPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
- "-----END EC PRIVATE KEY-----\n"
-};
-
-const char *ecp256_public_key = {
- "-----BEGIN PUBLIC KEY-----\n"
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES0AfBkjr7b8b19p5Gk8plSAN16wW\n"
- "XZyhYsH6FMCEUK60t7pem/ckoPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n"
- "-----END PUBLIC KEY-----\n"
-};
-
-EVP_PKEY* PrivateKeyFromPem(const string &pemkey) {
- BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
- EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
- assert(pkey != NULL);
- BIO_free(bio);
- return pkey;
-}
-
-EVP_PKEY* PublicKeyFromPem(const string &pemkey) {
- BIO *bio = BIO_new_mem_buf(const_cast<char*>(pemkey.data()),
pemkey.size());
- EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
- assert(pkey != NULL);
- BIO_free(bio);
- return pkey;
-}
-
-const unsigned kCertStorageDepth = 3;
-const unsigned kTreeStorageDepth = 8;
-
template <class T> class TreeSignerTest : public ::testing::Test {
protected:
TreeSignerTest()
- : db_(NULL),
+ : test_db_(),
+ test_signer_(),
verifier_(NULL),
tree_signer_(NULL) {}

void SetUp() {
- EVP_PKEY *pkey = PrivateKeyFromPem(ecp256_private_key);
- EVP_PKEY *pubkey = PublicKeyFromPem(ecp256_public_key);
- verifier_ = new LogVerifier(new LogSigVerifier(pubkey),
+ verifier_ = new LogVerifier(TestSigner::DefaultVerifier(),
new MerkleVerifier(new Sha256Hasher()));
- file_base_ = util::CreateTemporaryDirectory("/tmp/ctlogXXXXXX");
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
-
- NewDB();
-
- tree_signer_ = new TreeSigner(db_, new LogSigner(pkey));
- ASSERT_TRUE(verifier_ != NULL);
- ASSERT_TRUE(tree_signer_ != NULL);
+ tree_signer_ = new TreeSigner(db(), TestSigner::DefaultSigner());
}
-
- void NewDB();

TreeSigner *GetSimilar() const {
- EVP_PKEY *pkey = PrivateKeyFromPem(ecp256_private_key);
- return new TreeSigner(db_, new LogSigner(pkey));
- }
-
- void TearDown() {
- // Check again that it is safe to empty file_base_.
- ASSERT_EQ("/tmp/ctlog", file_base_.substr(0, 10));
- ASSERT_EQ(16U, file_base_.length());
- string command = "rm -r " + file_base_;
- int ret = system(command.c_str());
- if (ret != 0)
- std::cout << "Failed to delete temporary directory in "
- << file_base_ << std::endl;
+ return new TreeSigner(db(), TestSigner::DefaultSigner());
}

~TreeSignerTest() {
delete verifier_;
delete tree_signer_;
- delete db_;
}

- Database *db_;
+ T *db() const { return test_db_.db(); }
+ TestDB<T> test_db_;
+ TestSigner test_signer_;
LogVerifier *verifier_;
TreeSigner *tree_signer_;
- string file_base_;
};

-template <> void TreeSignerTest<FileDB>::NewDB() {
- string certs_dir = file_base_ + "/certs";
- string tree_dir = file_base_ + "/tree";
- int ret = mkdir(certs_dir.c_str(), 0700);
- ASSERT_EQ(ret, 0);
- ret = mkdir(tree_dir.c_str(), 0700);
- ASSERT_EQ(ret, 0);
-
- db_ = new FileDB(new FileStorage(certs_dir, kCertStorageDepth),
- new FileStorage(tree_dir, kTreeStorageDepth));
-}
-
-template <> void TreeSignerTest<SQLiteDB>::NewDB() {
- db_ = new SQLiteDB(file_base_ + "/ct");
-}
-
typedef testing::Types<FileDB, SQLiteDB> Databases;

TYPED_TEST_CASE(TreeSignerTest, Databases);

// TODO(ekasper): KAT tests.
TYPED_TEST(TreeSignerTest, Sign) {
- string hash("1234xyzw", 8);
-
LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());

SignedTreeHead sth;
- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&sth));
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&sth));
EXPECT_EQ(1U, sth.tree_size());
EXPECT_EQ(sth.timestamp(), this->tree_signer_->LastUpdateTime());
}

TYPED_TEST(TreeSignerTest, Timestamp) {
- string hash("1234xyzw", 8);
-
LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());
uint64_t last_update = this->tree_signer_->LastUpdateTime();
- EXPECT_GE(last_update, 1234U);
+ EXPECT_GE(last_update, logged_cert.sct().timestamp());

// Now create a second entry with a timestamp some time in the future
// and verify that the signer's timestamp is greater than that.
uint64_t future = last_update + 10000;
- logged_cert.mutable_sct()->set_timestamp(future);
- string hash2("1234abcd", 8);
- logged_cert.set_certificate_sha256_hash(hash2);
+ LoggedCertificate logged_cert2;
+ this->test_signer_.CreateUnique(&logged_cert2);
+ logged_cert2.mutable_sct()->set_timestamp(future);
+ EXPECT_EQ(Database::OK,
+ this->db()->CreatePendingCertificateEntry(logged_cert2));

- EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());
EXPECT_GE(this->tree_signer_->LastUpdateTime(), future);
}

TYPED_TEST(TreeSignerTest, Verify) {
- string hash("1234xyzw", 8);
-
LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());

SignedTreeHead sth;
- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&sth));
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&sth));
EXPECT_EQ(LogVerifier::VERIFY_OK,
this->verifier_->VerifySignedTreeHead(sth));
}

TYPED_TEST(TreeSignerTest, ResumeClean) {
- string hash("1234xyzw", 8);
-
LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());
SignedTreeHead sth;

- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&sth));
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&sth));

TreeSigner *signer2 = this->GetSimilar();
EXPECT_EQ(signer2->LastUpdateTime(), sth.timestamp());
@@ -228,7 +126,7 @@
EXPECT_EQ(TreeSigner::OK, signer2->UpdateTree());
SignedTreeHead sth2;

- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&sth2));
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&sth2));
EXPECT_LT(sth.timestamp(), sth2.timestamp());
EXPECT_EQ(sth.root_hash(), sth2.root_hash());
EXPECT_EQ(sth.tree_size(), sth2.tree_size());
@@ -241,31 +139,23 @@
TYPED_TEST(TreeSignerTest, ResumePartialSign) {
EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());
SignedTreeHead sth;
- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&sth));
- EXPECT_EQ(0U, sth.tree_size());
-
- // Log a pending entry.
- string hash("1234xyzw", 8);
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&sth));

LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

// Simulate the case where we assign a sequence number but fail
// before signing.
EXPECT_EQ(Database::OK,
- this->db_->AssignCertificateSequenceNumber(hash, 0));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 0));

TreeSigner *signer2 = this->GetSimilar();
EXPECT_EQ(TreeSigner::OK, signer2->UpdateTree());
SignedTreeHead sth2;
- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&sth2));
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&sth2));
// The signer should have picked up the sequence number commit.
EXPECT_EQ(1U, sth2.tree_size());
EXPECT_LT(sth.timestamp(), sth2.timestamp());
@@ -278,7 +168,7 @@
EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());
SignedTreeHead sth;

- EXPECT_EQ(Database::LOOKUP_OK, this->db_->LatestTreeHead(&sth));
+ EXPECT_EQ(Database::LOOKUP_OK, this->db()->LatestTreeHead(&sth));
EXPECT_GT(sth.timestamp(), 0U);
EXPECT_EQ(sth.tree_size(), 0U);
}
@@ -296,27 +186,22 @@

TYPED_TEST(TreeSignerTest, FailInconsistentSequenceNumbers) {
EXPECT_EQ(TreeSigner::OK, this->tree_signer_->UpdateTree());
- string hash("1234xyzw", 8);

LoggedCertificate logged_cert;
- logged_cert.set_certificate_sha256_hash(hash);
- logged_cert.mutable_sct()->set_timestamp(1234);
- logged_cert.mutable_sct()->mutable_entry()->set_type(
- CertificateEntry::X509_ENTRY);
- logged_cert.mutable_sct()->mutable_entry()->set_leaf_certificate("cert");
-
+ this->test_signer_.CreateUnique(&logged_cert);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert));

// Assign a sequence number the signer does not know about.
EXPECT_EQ(Database::OK,
- this->db_->AssignCertificateSequenceNumber(hash, 0));
+ this->db()->AssignCertificateSequenceNumber(
+ logged_cert.certificate_sha256_hash(), 0));

// Create another pending entry.
- string hash2("1234abcd", 8);
- logged_cert.set_certificate_sha256_hash(hash2);
+ LoggedCertificate logged_cert2;
+ this->test_signer_.CreateUnique(&logged_cert2);
EXPECT_EQ(Database::OK,
- this->db_->CreatePendingCertificateEntry(logged_cert));
+ this->db()->CreatePendingCertificateEntry(logged_cert2));

// Update should fail because we cannot commit a sequence number.
EXPECT_EQ(TreeSigner::DB_ERROR, this->tree_signer_->UpdateTree());
@@ -324,7 +209,14 @@

} // namespace

-int main(int argc, char**argv) {
+int main(int argc, char **argv) {
+ // Change the defaults. Can be overridden on command line.
+ // Log to stderr instead of log files.
+ FLAGS_logtostderr = true;
+ // Only log fatal messages by default.
+ FLAGS_minloglevel = 3;
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
=======================================
--- /src/merkletree/serial_hasher.cc Tue Oct 9 04:30:56 2012
+++ /src/merkletree/serial_hasher.cc Thu Oct 11 10:55:00 2012
@@ -5,6 +5,8 @@
#include "serial_hasher.h"
#include "types.h"

+using std::string;
+
const size_t Sha256Hasher::kDigestSize = SHA256_DIGEST_LENGTH;

Sha256Hasher::Sha256Hasher() : initialized_(false) {}
@@ -21,12 +23,20 @@
SHA256_Update(&ctx_, data.data(), data.size());
}

-std::string Sha256Hasher::Final() {
+string Sha256Hasher::Final() {
if (!initialized_)
Reset();

unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_Final(hash, &ctx_);
- return std::string(reinterpret_cast<char*>(hash), SHA256_DIGEST_LENGTH);
+ return string(reinterpret_cast<char*>(hash), SHA256_DIGEST_LENGTH);
initialized_ = false;
}
+
+// static
+string Sha256Hasher::Sha256Digest(const string &data) {
+ Sha256Hasher hasher;
+ hasher.Reset();
+ hasher.Update(data);
+ return hasher.Final();
+}
=======================================
--- /src/merkletree/serial_hasher.h Tue Oct 9 04:30:56 2012
+++ /src/merkletree/serial_hasher.h Thu Oct 11 10:55:00 2012
@@ -1,19 +1,25 @@
-#ifndef SERIALHASHER_H
-#define SERIALHASHER_H
+#ifndef SERIAL_HASHER_H
+#define SERIAL_HASHER_H

#include <openssl/sha.h>
#include <stddef.h>
#include <string>

-
class SerialHasher {
public:
SerialHasher() {}
virtual ~SerialHasher() {}

virtual size_t DigestSize() const = 0;
+
+ // Reset the context. Must be called before the first
+ // Update() call (and again after each Final() call).
virtual void Reset() = 0;
+
+ // Update the hash context with (binary) data.
virtual void Update(const std::string &data) = 0;
+
+ // Finalize the hash context and return the binary digest blob.
virtual std::string Final() = 0;
};

@@ -27,6 +33,9 @@
void Update(const std::string &data);
std::string Final();

+ // Create a new hasher and call Reset(), Update(), and Final().
+ static std::string Sha256Digest(const std::string &data);
+
private:
SHA256_CTX ctx_;
bool initialized_;
=======================================
--- /src/merkletree/serial_hasher_test.cc Tue Oct 9 04:30:56 2012
+++ /src/merkletree/serial_hasher_test.cc Thu Oct 11 10:55:00 2012
@@ -92,6 +92,16 @@
output = this->hasher_->Final();
EXPECT_EQ(H(digest), H(output));
}
+
+TEST(Sha256Test, StaticDigest) {
+ string input, output, digest;
+
+ for (size_t i = 0; test_sha256[i].input != NULL; ++i) {
+ digest = Sha256Hasher::Sha256Digest(S(test_sha256[i].input,
+ test_sha256[i].input_length));
+ EXPECT_STREQ(H(digest).c_str(), test_sha256[i].output);
+ }
+}

#undef S
#undef H
=======================================
--- /src/proto/ct.proto Wed Oct 10 10:16:52 2012
+++ /src/proto/ct.proto Thu Oct 11 10:55:00 2012
@@ -46,6 +46,8 @@
repeated bytes intermediates = 3;
}

+// TODO(ekasper): Consider moving the CertificateEntry out of this
+// message to LoggedCertificate, to better match the I-D.
message SignedCertificateTimestamp {
// UTC time in milliseconds, since January 1, 1970, 00:00.
optional uint64 timestamp = 1;
=======================================
--- /src/server/Makefile Fri Oct 5 03:26:17 2012
+++ /src/server/Makefile Thu Oct 11 10:55:00 2012
@@ -13,8 +13,8 @@

OBJS= ../merkletree/serial_hasher.o \
../util/util.o ../log/cert_checker.o ../log/cert.o \
- ../log/submission_handler.o ../log/cert_submission_handler.o \
- ../log/log_signer.o ../log/frontend_signer.o \
+ ../log/cert_submission_handler.o \
+ ../log/log_signer.o ../log/frontend_signer.o ../log/frontend.o \
../log/file_db.o ../log/file_storage.o ../log/filesystem_op.o \
../log/sqlite_db.o ../proto/ct.pb.o ../proto/serializer.o

=======================================
--- /src/server/ct-server.cc Tue Oct 9 04:30:56 2012
+++ /src/server/ct-server.cc Thu Oct 11 10:55:00 2012
@@ -23,6 +23,7 @@
#include "file_db.h"
#include "file_storage.h"
#include "frontend_signer.h"
+#include "frontend.h"
#include "log_signer.h"
#include "serializer.h"
#include "sqlite_db.h"
@@ -401,10 +402,10 @@

class CTLogManager {
public:
- CTLogManager(FrontendSigner *signer)
- : signer_(signer) {}
+ CTLogManager(Frontend *frontend)
+ : frontend_(frontend) {}

- ~CTLogManager() { delete signer_; }
+ ~CTLogManager() { delete frontend_; }

enum LogReply {
SIGNED_CERTIFICATE_TIMESTAMP,
@@ -416,24 +417,23 @@
LogReply SubmitEntry(CertificateEntry::Type type, const string &data,
SignedCertificateTimestamp *sct, string *error) {
SignedCertificateTimestamp local_sct;
- FrontendSigner::SubmitResult submit_result =
- signer_->QueueEntry(type, data, &local_sct);
+ Frontend::SubmitResult submit_result =
+ frontend_->QueueEntry(type, data, &local_sct);

LogReply reply = REJECT;
switch (submit_result) {
- case FrontendSigner::LOGGED:
- case FrontendSigner::PENDING:
- case FrontendSigner::NEW:
+ case Frontend::NEW:
+ case Frontend::DUPLICATE:
sct->CopyFrom(local_sct);
reply = SIGNED_CERTIFICATE_TIMESTAMP;
break;
default:
- error->assign(FrontendSigner::SubmitResultString(submit_result));
+ error->assign(Frontend::SubmitResultString(submit_result));
}
return reply;
}
private:
- FrontendSigner *signer_;
+ Frontend *frontend_;
};

class CTServer : public Server {
@@ -669,10 +669,10 @@
new FileStorage(FLAGS_tree_dir,
FLAGS_tree_storage_depth));

- FrontendSigner signer(db, new LogSigner(pkey),
- new CertSubmissionHandler(&checker));
+ Frontend frontend(new CertSubmissionHandler(&checker),
+ new FrontendSigner(db, new LogSigner(pkey)));

- CTLogManager manager(&signer);
+ CTLogManager manager(&frontend);
CTServerListener l(&loop, fd, &manager);
LOG(INFO) << "Server listening on port " << FLAGS_port;
loop.Forever();
Reply all
Reply to author
Forward
0 new messages