From e091186d830d575d17ede23099734ced524091a3 Mon Sep 17 00:00:00 2001 From: Andrew Ayer Date: Wed, 6 Apr 2016 08:10:06 -0700 Subject: [PATCH] Save consistency proof along with evidence of misbehavior Although the consistency proof is neither necessary nor sufficient to prove misbehavior by a log, this will help with debugging if a log returns a bogus consistency proof erroneously (which seems to be happening with the Rocketeer log lately...). --- cmd/common.go | 20 +++++++++++++------- helpers.go | 9 +++++++++ scanner.go | 8 ++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/cmd/common.go b/cmd/common.go index a8729d9..969ea50 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -84,20 +84,25 @@ func defangLogUri (logUri string) string { return strings.Replace(strings.Replace(logUri, "://", "_", 1), "/", "_", -1) } -func saveEvidence (logUri string, firstSTH *ct.SignedTreeHead, secondSTH *ct.SignedTreeHead) (string, string, error) { +func saveEvidence (logUri string, firstSTH *ct.SignedTreeHead, secondSTH *ct.SignedTreeHead, proof ct.ConsistencyProof) (string, string, string, error) { now := strconv.FormatInt(time.Now().Unix(), 10) firstFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri) + ".inconsistent." + now + ".first") if err := ctwatch.WriteSTHFile(firstFilename, firstSTH); err != nil { - return "", "", err + return "", "", "", err } secondFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri) + ".inconsistent." + now + ".second") if err := ctwatch.WriteSTHFile(secondFilename, secondSTH); err != nil { - return "", "", err + return "", "", "", err } - return firstFilename, secondFilename, nil + proofFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri) + ".inconsistent." + now + ".proof") + if err := ctwatch.WriteProofFile(proofFilename, proof); err != nil { + return "", "", "", err + } + + return firstFilename, secondFilename, proofFilename, nil } func Main (argStateDir string, processCallback ctwatch.ProcessCallback) { @@ -200,18 +205,19 @@ func Main (argStateDir string, processCallback ctwatch.ProcessCallback) { if prevSTH != nil { var valid bool var err error - valid, treeBuilder, err = scanner.CheckConsistency(prevSTH, latestSTH) + var proof ct.ConsistencyProof + valid, treeBuilder, proof, err = scanner.CheckConsistency(prevSTH, latestSTH) if err != nil { log.Printf("Error fetching consistency proof: %s\n", err) exitCode |= 4 continue } if !valid { - firstFilename, secondFilename, err := saveEvidence(logUri, prevSTH, latestSTH) + firstFilename, secondFilename, proofFilename, err := saveEvidence(logUri, prevSTH, latestSTH, proof) if err != nil { log.Printf("Consistency proof failed - the log has misbehaved! Saving evidence of misbehavior failed: %s\n", err) } else { - log.Printf("Consistency proof failed - the log has misbehaved! Evidence of misbehavior has been saved to '%s' and '%s'.\n", firstFilename, secondFilename) + log.Printf("Consistency proof failed - the log has misbehaved! Evidence of misbehavior has been saved to '%s' and '%s' (with proof in '%s').\n", firstFilename, secondFilename, proofFilename) } exitCode |= 8 continue diff --git a/helpers.go b/helpers.go index d8a6a73..c33f8f9 100644 --- a/helpers.go +++ b/helpers.go @@ -46,6 +46,15 @@ func WriteSTHFile (path string, sth *ct.SignedTreeHead) error { return ioutil.WriteFile(path, sthJson, 0666) } +func WriteProofFile (path string, proof ct.ConsistencyProof) error { + proofJson, err := json.MarshalIndent(proof, "", "\t") + if err != nil { + return err + } + proofJson = append(proofJson, byte('\n')) + return ioutil.WriteFile(path, proofJson, 0666) +} + func IsPrecert (entry *ct.LogEntry) bool { return entry.Leaf.TimestampedEntry.EntryType == ct.PrecertLogEntryType } diff --git a/scanner.go b/scanner.go index 1833954..fea6fd8 100644 --- a/scanner.go +++ b/scanner.go @@ -202,12 +202,12 @@ func (s *Scanner) GetSTH() (*ct.SignedTreeHead, error) { return latestSth, nil } -func (s *Scanner) CheckConsistency(first *ct.SignedTreeHead, second *ct.SignedTreeHead) (bool, *MerkleTreeBuilder, error) { +func (s *Scanner) CheckConsistency(first *ct.SignedTreeHead, second *ct.SignedTreeHead) (bool, *MerkleTreeBuilder, ct.ConsistencyProof, error) { var proof ct.ConsistencyProof if first.TreeSize > second.TreeSize { // No way this can be valid - return false, nil, nil + return false, nil, nil, nil } else if first.TreeSize == second.TreeSize { // The proof *should* be empty, so don't bother contacting the server. // This is necessary because the digicert server returns a 400 error if first==second. @@ -216,12 +216,12 @@ func (s *Scanner) CheckConsistency(first *ct.SignedTreeHead, second *ct.SignedTr var err error proof, err = s.logClient.GetConsistencyProof(int64(first.TreeSize), int64(second.TreeSize)) if err != nil { - return false, nil, err + return false, nil, nil, err } } valid, treeBuilder := VerifyConsistencyProof(proof, first, second) - return valid, treeBuilder, nil + return valid, treeBuilder, proof, nil } func (s *Scanner) Scan(startIndex int64, endIndex int64, processCert ProcessCallback, treeBuilder *MerkleTreeBuilder) error {