From 0ba0a1fef06b0b484434a94c1da79f889b6687a5 Mon Sep 17 00:00:00 2001 From: Andrew Ayer Date: Wed, 16 Oct 2024 08:23:22 -0400 Subject: [PATCH 1/2] merkletree: replace IsComplete with more useful ContainsFirstN --- merkletree/fragment.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/merkletree/fragment.go b/merkletree/fragment.go index 4d82502..a679c72 100644 --- a/merkletree/fragment.go +++ b/merkletree/fragment.go @@ -90,8 +90,9 @@ func (tree FragmentedCollapsedTree) Subtrees() []CollapsedTree { } } -func (tree FragmentedCollapsedTree) IsComplete(size uint64) bool { - return len(tree.subtrees) == 1 && tree.subtrees[0].offset == 0 && tree.subtrees[0].size == size +// Return true iff the tree contains at least the first n nodes (without any gaps) +func (tree FragmentedCollapsedTree) ContainsFirstN(n uint64) bool { + return len(tree.subtrees) >= 1 && tree.subtrees[0].offset == 0 && tree.subtrees[0].size >= n } func (tree *FragmentedCollapsedTree) Init(subtrees []CollapsedTree) error { From 8472e14d4c72c4c8e64b3442a3e216c52f7d7217 Mon Sep 17 00:00:00 2001 From: Andrew Ayer Date: Mon, 25 Nov 2024 08:09:57 -0500 Subject: [PATCH 2/2] Add log list support for static-ct-api logs --- cmd/submitct/main.go | 11 ++++++----- loglist/helpers.go | 4 ++++ loglist/schema.go | 34 ++++++++++++++++++++++++++++++---- loglist/validate.go | 14 +++++++++++++- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/cmd/submitct/main.go b/cmd/submitct/main.go index a5e8e0c..986da32 100644 --- a/cmd/submitct/main.go +++ b/cmd/submitct/main.go @@ -158,18 +158,19 @@ func main() { var logs []Log for _, ctlog := range list.AllLogs() { + submissionURL := ctlog.GetSubmissionURL() pubkey, err := x509.ParsePKIXPublicKey(ctlog.Key) if err != nil { - log.Fatalf("%s: Failed to parse log public key: %s", ctlog.URL, err) + log.Fatalf("%s: Failed to parse log public key: %s", submissionURL, err) } verifier, err := ct.NewSignatureVerifier(pubkey) if err != nil { - log.Fatalf("%s: Failed to create signature verifier for log: %s", ctlog.URL, err) + log.Fatalf("%s: Failed to create signature verifier for log: %s", submissionURL, err) } logs = append(logs, Log{ Log: ctlog, SignatureVerifier: verifier, - LogClient: client.New(strings.TrimRight(ctlog.URL, "/")), + LogClient: client.New(strings.TrimRight(submissionURL, "/")), }) } @@ -212,11 +213,11 @@ func main() { go func(fingerprint [32]byte, ctlog Log) { sct, err := ctlog.SubmitChain(chain) if err != nil { - log.Printf("%x (%s): %s: Submission Error: %s", fingerprint, cn, ctlog.URL, err) + log.Printf("%x (%s): %s: Submission Error: %s", fingerprint, cn, ctlog.GetSubmissionURL(), err) atomic.AddUint32(&submitErrors, 1) } else if *verbose { timestamp := time.Unix(int64(sct.Timestamp)/1000, int64(sct.Timestamp%1000)*1000000) - log.Printf("%x (%s): %s: Submitted at %s", fingerprint, cn, ctlog.URL, timestamp) + log.Printf("%x (%s): %s: Submitted at %s", fingerprint, cn, ctlog.GetSubmissionURL(), timestamp) } wg.Done() }(fingerprint, ctlog) diff --git a/loglist/helpers.go b/loglist/helpers.go index d236322..ab1586b 100644 --- a/loglist/helpers.go +++ b/loglist/helpers.go @@ -13,12 +13,16 @@ import ( "time" ) +// Return all tiled and non-tiled logs from all operators func (list *List) AllLogs() []*Log { logs := []*Log{} for operator := range list.Operators { for log := range list.Operators[operator].Logs { logs = append(logs, &list.Operators[operator].Logs[log]) } + for log := range list.Operators[operator].TiledLogs { + logs = append(logs, &list.Operators[operator].TiledLogs[log]) + } } return logs } diff --git a/loglist/schema.go b/loglist/schema.go index eb56c7d..7d070aa 100644 --- a/loglist/schema.go +++ b/loglist/schema.go @@ -22,16 +22,19 @@ type List struct { } type Operator struct { - Name string `json:"name"` - Email []string `json:"email"` - Logs []Log `json:"logs"` + Name string `json:"name"` + Email []string `json:"email"` + Logs []Log `json:"logs"` + TiledLogs []Log `json:"tiled_logs"` } type Log struct { Key []byte `json:"key"` LogID ct.SHA256Hash `json:"log_id"` MMD int `json:"mmd"` - URL string `json:"url"` + URL string `json:"url,omitempty"` // only for rfc6962 logs + SubmissionURL string `json:"submission_url,omitempty"` // only for static-ct-api logs + MonitoringURL string `json:"monitoring_url,omitempty"` // only for static-ct-api logs Description string `json:"description"` State State `json:"state"` DNS string `json:"dns"` @@ -44,6 +47,29 @@ type Log struct { // TODO: add previous_operators } +func (log *Log) IsRFC6962() bool { return log.URL != "" } +func (log *Log) IsStaticCTAPI() bool { return log.SubmissionURL != "" && log.MonitoringURL != "" } + +// Return URL prefix for submission using the RFC6962 protocol +func (log *Log) GetSubmissionURL() string { + if log.SubmissionURL != "" { + return log.SubmissionURL + } else { + return log.URL + } +} + +// Return URL prefix for monitoring. +// Since the protocol understood by the URL might be either RFC6962 or static-ct-api, this URL is +// only useful for informational purposes. +func (log *Log) GetMonitoringURL() string { + if log.MonitoringURL != "" { + return log.MonitoringURL + } else { + return log.URL + } +} + type State struct { Pending *struct { Timestamp time.Time `json:"timestamp"` diff --git a/loglist/validate.go b/loglist/validate.go index 65da8e4..8cc2750 100644 --- a/loglist/validate.go +++ b/loglist/validate.go @@ -26,7 +26,12 @@ func (list *List) Validate() error { func (operator *Operator) Validate() error { for i := range operator.Logs { if err := operator.Logs[i].Validate(); err != nil { - return fmt.Errorf("problem with %dth log (%s): %w", i, operator.Logs[i].LogIDString(), err) + return fmt.Errorf("problem with %dth non-tiled log (%s): %w", i, operator.Logs[i].LogIDString(), err) + } + } + for i := range operator.TiledLogs { + if err := operator.TiledLogs[i].Validate(); err != nil { + return fmt.Errorf("problem with %dth tiled log (%s): %w", i, operator.TiledLogs[i].LogIDString(), err) } } return nil @@ -37,5 +42,12 @@ func (log *Log) Validate() error { if log.LogID != realLogID { return fmt.Errorf("log ID does not match log key") } + + if !log.IsRFC6962() && !log.IsStaticCTAPI() { + return fmt.Errorf("URL(s) not provided") + } else if log.IsRFC6962() && log.IsStaticCTAPI() { + return fmt.Errorf("inconsistent URLs provided") + } + return nil }