From 5847e78c1f679dca445663ae8802cfc49b3c874e Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 08:19:48 +0000 Subject: [PATCH 01/11] Remove ctutil/loginfo.go --- ctutil/loginfo.go | 172 ---------------------------------------------- 1 file changed, 172 deletions(-) delete mode 100644 ctutil/loginfo.go diff --git a/ctutil/loginfo.go b/ctutil/loginfo.go deleted file mode 100644 index 113eb240d6..0000000000 --- a/ctutil/loginfo.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ctutil - -import ( - "context" - "crypto/sha256" - "fmt" - "net/http" - "strings" - "sync" - "time" - - ct "github.com/google/certificate-transparency-go" - "github.com/google/certificate-transparency-go/client" - "github.com/google/certificate-transparency-go/jsonclient" - "github.com/google/certificate-transparency-go/loglist" - "github.com/google/certificate-transparency-go/x509" - "github.com/transparency-dev/merkle/proof" - "github.com/transparency-dev/merkle/rfc6962" -) - -// LogInfo holds the objects needed to perform per-log verification and -// validation of SCTs. -type LogInfo struct { - Description string - Client client.CheckLogClient - MMD time.Duration - Verifier *ct.SignatureVerifier - PublicKey []byte - - mu sync.RWMutex - lastSTH *ct.SignedTreeHead -} - -// NewLogInfo builds a LogInfo object based on a log list entry. -func NewLogInfo(log *loglist.Log, hc *http.Client) (*LogInfo, error) { - url := log.URL - if !strings.HasPrefix(url, "https://") { - url = "https://" + url - } - lc, err := client.New(url, hc, jsonclient.Options{PublicKeyDER: log.Key, UserAgent: "ct-go-logclient"}) - if err != nil { - return nil, fmt.Errorf("failed to create client for log %q: %v", log.Description, err) - } - return newLogInfo(log, lc) -} - -func newLogInfo(log *loglist.Log, lc client.CheckLogClient) (*LogInfo, error) { - logKey, err := x509.ParsePKIXPublicKey(log.Key) - if err != nil { - return nil, fmt.Errorf("failed to parse public key data for log %q: %v", log.Description, err) - } - verifier, err := ct.NewSignatureVerifier(logKey) - if err != nil { - return nil, fmt.Errorf("failed to build verifier log %q: %v", log.Description, err) - } - mmd := time.Duration(log.MaximumMergeDelay) * time.Second - return &LogInfo{ - Description: log.Description, - Client: lc, - MMD: mmd, - Verifier: verifier, - PublicKey: log.Key, - }, nil -} - -// LogInfoByHash holds LogInfo objects index by the SHA-256 hash of the log's public key. -type LogInfoByHash map[[sha256.Size]byte]*LogInfo - -// LogInfoByKeyHash builds a map of LogInfo objects indexed by their key hashes. -func LogInfoByKeyHash(ll *loglist.LogList, hc *http.Client) (LogInfoByHash, error) { - return logInfoByKeyHash(ll, hc, NewLogInfo) -} - -func logInfoByKeyHash(ll *loglist.LogList, hc *http.Client, infoFactory func(*loglist.Log, *http.Client) (*LogInfo, error)) (map[[sha256.Size]byte]*LogInfo, error) { - result := make(map[[sha256.Size]byte]*LogInfo) - for _, log := range ll.Logs { - h := sha256.Sum256(log.Key) - li, err := infoFactory(&log, hc) - if err != nil { - return nil, err - } - result[h] = li - } - return result, nil -} - -// LastSTH returns the last STH known for the log. -func (li *LogInfo) LastSTH() *ct.SignedTreeHead { - li.mu.RLock() - defer li.mu.RUnlock() - return li.lastSTH -} - -// SetSTH sets the last STH known for the log. -func (li *LogInfo) SetSTH(sth *ct.SignedTreeHead) { - li.mu.Lock() - defer li.mu.Unlock() - li.lastSTH = sth -} - -// VerifySCTSignature checks the signature in the SCT matches the given leaf (adjusted for the -// timestamp in the SCT) and log. -func (li *LogInfo) VerifySCTSignature(sct ct.SignedCertificateTimestamp, leaf ct.MerkleTreeLeaf) error { - leaf.TimestampedEntry.Timestamp = sct.Timestamp - if err := li.Verifier.VerifySCTSignature(sct, ct.LogEntry{Leaf: leaf}); err != nil { - return fmt.Errorf("failed to verify SCT signature from log %q: %v", li.Description, err) - } - return nil -} - -// VerifyInclusionLatest checks that the given Merkle tree leaf, adjusted for the provided timestamp, -// is present in the latest known tree size of the log. If no tree size for the log is known, it will -// be queried. On success, returns the index of the leaf in the log. -func (li *LogInfo) VerifyInclusionLatest(ctx context.Context, leaf ct.MerkleTreeLeaf, timestamp uint64) (int64, error) { - sth := li.LastSTH() - if sth == nil { - var err error - sth, err = li.Client.GetSTH(ctx) - if err != nil { - return -1, fmt.Errorf("failed to get current STH for %q log: %v", li.Description, err) - } - li.SetSTH(sth) - } - return li.VerifyInclusionAt(ctx, leaf, timestamp, sth.TreeSize, sth.SHA256RootHash[:]) -} - -// VerifyInclusion checks that the given Merkle tree leaf, adjusted for the provided timestamp, -// is present in the current tree size of the log. On success, returns the index of the leaf -// in the log. -func (li *LogInfo) VerifyInclusion(ctx context.Context, leaf ct.MerkleTreeLeaf, timestamp uint64) (int64, error) { - sth, err := li.Client.GetSTH(ctx) - if err != nil { - return -1, fmt.Errorf("failed to get current STH for %q log: %v", li.Description, err) - } - li.SetSTH(sth) - return li.VerifyInclusionAt(ctx, leaf, timestamp, sth.TreeSize, sth.SHA256RootHash[:]) -} - -// VerifyInclusionAt checks that the given Merkle tree leaf, adjusted for the provided timestamp, -// is present in the given tree size & root hash of the log. On success, returns the index of the -// leaf in the log. -func (li *LogInfo) VerifyInclusionAt(ctx context.Context, leaf ct.MerkleTreeLeaf, timestamp, treeSize uint64, rootHash []byte) (int64, error) { - leaf.TimestampedEntry.Timestamp = timestamp - leafHash, err := ct.LeafHashForLeaf(&leaf) - if err != nil { - return -1, fmt.Errorf("failed to create leaf hash: %v", err) - } - - rsp, err := li.Client.GetProofByHash(ctx, leafHash[:], treeSize) - if err != nil { - return -1, fmt.Errorf("failed to GetProofByHash(sct,size=%d): %v", treeSize, err) - } - - if err := proof.VerifyInclusion(rfc6962.DefaultHasher, uint64(rsp.LeafIndex), treeSize, leafHash[:], rsp.AuditPath, rootHash); err != nil { - return -1, fmt.Errorf("failed to verify inclusion proof at size %d: %v", treeSize, err) - } - return rsp.LeafIndex, nil -} From ec3a97aa08d2cacc60b19e4a1f66750483027a54 Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 08:38:13 +0000 Subject: [PATCH 02/11] Migrate loglist from v1 to v3 in ctclient cmd --- client/ctclient/cmd/root.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ctclient/cmd/root.go b/client/ctclient/cmd/root.go index 76d73e8962..dace0da748 100644 --- a/client/ctclient/cmd/root.go +++ b/client/ctclient/cmd/root.go @@ -29,7 +29,7 @@ import ( ct "github.com/google/certificate-transparency-go" "github.com/google/certificate-transparency-go/client" "github.com/google/certificate-transparency-go/jsonclient" - "github.com/google/certificate-transparency-go/loglist" + "github.com/google/certificate-transparency-go/loglist3" "github.com/google/certificate-transparency-go/x509util" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -53,7 +53,7 @@ func init() { flags := rootCmd.PersistentFlags() flags.BoolVar(&skipHTTPSVerify, "skip_https_verify", false, "Skip verification of HTTPS transport connection") flags.StringVar(&logName, "log_name", "", "Name of log to retrieve information from --log_list for") - flags.StringVar(&logList, "log_list", loglist.AllLogListURL, "Location of master log list (URL or filename)") + flags.StringVar(&logList, "log_list", loglist3.AllLogListURL, "Location of master log list (URL or filename)") flags.StringVar(&logURI, "log_uri", "https://ct.googleapis.com/rocketeer", "CT log base URI") flags.StringVar(&pubKey, "pub_key", "", "Name of file containing log's public key") } @@ -121,7 +121,7 @@ func connect(ctx context.Context) *client.LogClient { if err != nil { klog.Exitf("Failed to read log list: %v", err) } - ll, err := loglist.NewFromJSON(llData) + ll, err := loglist3.NewFromJSON(llData) if err != nil { klog.Exitf("Failed to build log list: %v", err) } From f2701dfa2f9a5a5d78dd8856020385a82dce6107 Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 08:53:33 +0000 Subject: [PATCH 03/11] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a8653e09..99b8fc7a24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,10 @@ ### Cleanup - * `WithBalancerName` is deprecated and removed, using the recommended way + * `WithBalancerName` is deprecated and removed, using the recommended way. * `ctfe.PEMCertPool` type has been moved to `x509util.PEMCertPool` to reduce dependencies (#903). + * Remove log list v1 package and its dependencies. ### Migrillian From ff3a5b5614cfd3e2ac0ba6333b30fdcc5cf1d1ae Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 08:55:37 +0000 Subject: [PATCH 04/11] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99b8fc7a24..deccf41a1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ * #800: Remove dependency from `ratelimit`. * #927: Add read-only mode to CTFE config. * Update Trillian to [0a389c4](https://github.com/google/trillian/commit/0a389c4bb8d97fb3be8f55d7e5b428cf4304986f) + * Migrate loglist from v1 to v3 in ctclient cmd. ## v1.1.2 From b65b71b0797f86981d812b3dadef346e12ff4b92 Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 08:56:38 +0000 Subject: [PATCH 05/11] Remove log list v1 package and its dependencies --- loglist/chrome-list-pubkey.pem | 14 -- loglist/diff_check.go | 114 ---------- loglist/diff_check_test.go | 257 --------------------- loglist/findlog/main.go | 121 ---------- loglist/logfilter.go | 77 ------- loglist/logfilter_test.go | 125 ----------- loglist/loglist.go | 245 --------------------- loglist/loglist_test.go | 392 --------------------------------- 8 files changed, 1345 deletions(-) delete mode 100644 loglist/chrome-list-pubkey.pem delete mode 100644 loglist/diff_check.go delete mode 100644 loglist/diff_check_test.go delete mode 100644 loglist/findlog/main.go delete mode 100644 loglist/logfilter.go delete mode 100644 loglist/logfilter_test.go delete mode 100644 loglist/loglist.go delete mode 100644 loglist/loglist_test.go diff --git a/loglist/chrome-list-pubkey.pem b/loglist/chrome-list-pubkey.pem deleted file mode 100644 index c90bfa535e..0000000000 --- a/loglist/chrome-list-pubkey.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsu0BHGnQ++W2CTdyZyxv -HHRALOZPlnu/VMVgo2m+JZ8MNbAOH2cgXb8mvOj8flsX/qPMuKIaauO+PwROMjiq -fUpcFm80Kl7i97ZQyBDYKm3MkEYYpGN+skAR2OebX9G2DfDqFY8+jUpOOWtBNr3L -rmVcwx+FcFdMjGDlrZ5JRmoJ/SeGKiORkbbu9eY1Wd0uVhz/xI5bQb0OgII7hEj+ -i/IPbJqOHgB8xQ5zWAJJ0DmG+FM6o7gk403v6W3S8qRYiR84c50KppGwe4YqSMkF -bLDleGQWLoaDSpEWtESisb4JiLaY4H+Kk0EyAhPSb+49JfUozYl+lf7iFN3qRq/S -IXXTh6z0S7Qa8EYDhKGCrpI03/+qprwy+my6fpWHi6aUIk4holUCmWvFxZDfixox -K0RlqbFDl2JXMBquwlQpm8u5wrsic1ksIv9z8x9zh4PJqNpCah0ciemI3YGRQqSe -/mRRXBiSn9YQBUPcaeqCYan+snGADFwHuXCd9xIAdFBolw9R9HTedHGUfVXPJDiF -4VusfX6BRR/qaadB+bqEArF/TzuDUr6FvOR4o8lUUxgLuZ/7HO+bHnaPFKYHHSm+ -+z1lVDhhYuSZ8ax3T0C3FZpb7HMjZtpEorSV5ElKJEJwrhrBCMOD8L01EoSPrGlS -1w22i9uGHMn/uGQKo28u7AsCAwEAAQ== ------END PUBLIC KEY----- \ No newline at end of file diff --git a/loglist/diff_check.go b/loglist/diff_check.go deleted file mode 100644 index d2a2b369bf..0000000000 --- a/loglist/diff_check.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package loglist - -import ( - "bytes" - "fmt" - "reflect" - "sort" - - ct "github.com/google/certificate-transparency-go" -) - -type warningList struct { - warnings []string -} - -func (wl *warningList) addWarning(w string) { - if w != "" { - wl.warnings = append(wl.warnings, w) - } -} - -// checkMasterOpsMatchBranch checks operator IDs set of branch is equal to or -// wider than master one. No restriction on description mismatches. -func checkMasterOpsMatchBranch(master *LogList, branch *LogList, wl *warningList) { - masterOps := master.OperatorIDSet() - branchOps := branch.OperatorIDSet() - for opID := range masterOps { - if branchOps[opID] == "" { - wl.addWarning(fmt.Sprintf( - "Operator %q id=%d present at master log list but missing at branch.", - masterOps[opID], opID)) - } - } -} - -// checkEquivalence: whether 2 logs are functionally identical. -func (l *Log) checkEquivalence(log2 *Log, wl *warningList) { - // Description and STH comparison are omitted. - if !bytes.Equal(l.Key, log2.Key) { - wl.addWarning(fmt.Sprintf( - "Log %q and log %q have different keys.", - l.Description, log2.Description)) - } - if l.MaximumMergeDelay != log2.MaximumMergeDelay { - wl.addWarning(fmt.Sprintf( - "Maximum merge delay mismatch for logs %q and %q: %d != %d.", - l.Description, log2.Description, l.MaximumMergeDelay, - log2.MaximumMergeDelay)) - } - // Strong assumption: operators IDs are semantically same across logs. - log1Ops := l.OperatedBy - log2Ops := log2.OperatedBy - sort.IntSlice(log1Ops).Sort() - sort.IntSlice(log2Ops).Sort() - if !reflect.DeepEqual(log1Ops, log2Ops) { - wl.addWarning(fmt.Sprintf( - "Operators mismatch for logs %q and %q.", - l.Description, log2.Description)) - } - if l.URL != log2.URL { - wl.addWarning(fmt.Sprintf( - "URL mismatch for logs %q and %q: %s != %s.", - l.Description, log2.Description, l.URL, log2.URL)) - } - if l.DisqualifiedAt != log2.DisqualifiedAt { - wl.addWarning(fmt.Sprintf( - "Disqualified-at-timing mismatch for logs %q and %q: %v != %v.", - l.Description, log2.Description, - ct.TimestampToTime(uint64(l.DisqualifiedAt)), - ct.TimestampToTime(uint64(log2.DisqualifiedAt)))) - } - if l.DNSAPIEndpoint != log2.DNSAPIEndpoint { - wl.addWarning(fmt.Sprintf( - "DNS API mismatch for logs %q and %q: %s != %s.", - l.Description, log2.Description, l.DNSAPIEndpoint, - log2.DNSAPIEndpoint)) - } -} - -// checkMasterLogsMatchBranch checks whether logs present at branched-list -// either have equivalent key matched entry at master-list or are absent from -// master. -func checkMasterLogsMatchBranch(master *LogList, branch *LogList, wl *warningList) { - for _, log := range branch.Logs { - if masterEntry := master.FindLogByKey(log.Key); masterEntry != nil { - masterEntry.checkEquivalence(&log, wl) - } - } -} - -// CheckBranch checks edited version of LogList against a master one for edit -// restrictions: consistency across operators, matching functionality of mutual -// logs. -// Returns slice of warnings if any. -func (ll *LogList) CheckBranch(branch *LogList) []string { - w := &warningList{warnings: []string{}} - checkMasterOpsMatchBranch(ll, branch, w) - checkMasterLogsMatchBranch(ll, branch, w) - return w.warnings -} diff --git a/loglist/diff_check_test.go b/loglist/diff_check_test.go deleted file mode 100644 index 8437062896..0000000000 --- a/loglist/diff_check_test.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package loglist - -import ( - "strings" - "testing" - - "github.com/mohae/deepcopy" -) - -func TestCheckOperatorsDiff(t *testing.T) { - tests := []struct { - name string - branch LogList - wantWarnings []string - }{ - { - name: "Equal", - branch: LogList{ - Operators: []Operator{ - {ID: 0, Name: "Google"}, - {ID: 1, Name: "Bob's CT Log Shop"}, - }, - Logs: []Log{}, - }, - wantWarnings: []string{}, - }, - { - name: "ShuffledRenamed", - branch: LogList{ - Operators: []Operator{ - {ID: 1, Name: "Bob's CT Log Shop+"}, - {ID: 0, Name: "Google"}, - }, - Logs: []Log{}, - }, - wantWarnings: []string{}, - }, - { - name: "Missing", - branch: LogList{ - Operators: []Operator{ - {ID: 1, Name: "Bob's CT Log Shop"}, - }, - Logs: []Log{}, - }, - wantWarnings: []string{"Operator \"Google\" id=0 present at master log list but missing at branch."}, - }, - { - name: "Added", - branch: LogList{ - Operators: []Operator{ - {ID: 0, Name: "Google"}, - {ID: 1, Name: "Bob's CT Log Shop"}, - {ID: 2, Name: "Alice's CT Log Shop"}, - }, - Logs: []Log{}, - }, - wantWarnings: []string{}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - wl := warningList{warnings: []string{}} - checkMasterOpsMatchBranch(&sampleLogList, &test.branch, &wl) - wMismatchIds := getMismatchIds(wl.warnings, test.wantWarnings) - if len(wMismatchIds) > 0 { - t.Errorf("checkOperators %s: got '%v', want warnings '%v'.\n %v-st/d/th warning mismatch.", test.name, wl.warnings, test.wantWarnings, wMismatchIds) - } - }) - } -} - -func generateKeyURLMismatch(ll *LogList) Log { - log := deepcopy.Copy(ll.Logs[0]).(Log) - log.Key = ll.Logs[1].Key - log.URL = ll.Logs[1].URL - return log -} - -func generateTimingsMismatch(ll *LogList) Log { - log := deepcopy.Copy(ll.Logs[0]).(Log) - log.MaximumMergeDelay = 86401 - log.DisqualifiedAt = 1460678400 - return log -} - -func generateOperatorsDNSMismatch(ll *LogList) Log { - log := deepcopy.Copy(ll.Logs[0]).(Log) - log.OperatedBy = append(log.OperatedBy, 1) - log.DNSAPIEndpoint = ll.Logs[1].DNSAPIEndpoint - return log -} - -func TestCheckLogPairEquivalence(t *testing.T) { - tests := []struct { - name string - log1 Log - log2 Log - wantWarnings []string - }{ - { - name: "Equal", - log1: deepcopy.Copy(sampleLogList.Logs[0]).(Log), - log2: deepcopy.Copy(sampleLogList.Logs[0]).(Log), - wantWarnings: []string{}, - }, - { - name: "KeyURLMismatch", - log1: deepcopy.Copy(sampleLogList.Logs[0]).(Log), - log2: generateKeyURLMismatch(&sampleLogList), - wantWarnings: []string{ - "Log \"Google 'Aviator' log\" and log \"Google 'Aviator' log\" have different keys.", - "URL mismatch for logs \"Google 'Aviator' log\" and \"Google 'Aviator' log\": ct.googleapis.com/aviator/ != ct.googleapis.com/icarus/.", - }, - }, - { - name: "TimingsMismatch", - log1: deepcopy.Copy(sampleLogList.Logs[0]).(Log), - log2: generateTimingsMismatch(&sampleLogList), - wantWarnings: []string{ - "Maximum merge delay mismatch for logs \"Google 'Aviator' log\" and \"Google 'Aviator' log\": 86400 != 86401.", - "Disqualified-at-timing mismatch for logs \"Google 'Aviator' log\" and \"Google 'Aviator' log\": ", - }, - }, - { - name: "OperatorsDNSMismatch", - log1: deepcopy.Copy(sampleLogList.Logs[0]).(Log), - log2: generateOperatorsDNSMismatch(&sampleLogList), - wantWarnings: []string{ - "Operators mismatch for logs \"Google 'Aviator' log\" and \"Google 'Aviator' log\".", - "DNS API mismatch for logs \"Google 'Aviator' log\" and \"Google 'Aviator' log\": aviator.ct.googleapis.com != icarus.ct.googleapis.com.", - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - wl := warningList{warnings: []string{}} - test.log1.checkEquivalence(&test.log2, &wl) - wMismatchIds := getMismatchIds(wl.warnings, test.wantWarnings) - if len(wMismatchIds) > 0 { - t.Errorf("checkLogs %s: got '%v', want warnings '%v'.\n %v-st/d/th warning mismatch.", test.name, wl.warnings, test.wantWarnings, wMismatchIds) - } - }) - } -} - -func leaveSingleLog() LogList { - ll := deepcopy.Copy(sampleLogList).(LogList) - ll.Logs = ll.Logs[0:1] - return ll -} - -func leaveSingleLogSingleOp() LogList { - ll := leaveSingleLog() - ll.Operators = ll.Operators[0:1] - return ll -} - -func messOperators() LogList { - ll := deepcopy.Copy(sampleLogList).(LogList) - ll.Logs[0].OperatedBy = []int{1} - ll.Operators = ll.Operators[0:1] - return ll -} - -func swapLogsSwapOps() LogList { - ll := deepcopy.Copy(sampleLogList).(LogList) - ll.Logs[0] = sampleLogList.Logs[3] - ll.Logs[3] = sampleLogList.Logs[0] - ll.Operators[0] = sampleLogList.Operators[1] - ll.Operators[1] = sampleLogList.Operators[0] - return ll -} - -func TestCheckBranch(t *testing.T) { - tests := []struct { - name string - branchList LogList - wantWarnings []string - wantError bool - }{ - { - name: "Copy", - branchList: deepcopy.Copy(sampleLogList).(LogList), - wantWarnings: []string{}, - wantError: false, - }, - { - name: "OneMatch", - branchList: leaveSingleLog(), - wantWarnings: []string{}, - wantError: false, - }, - { - name: "OneMatchOperatorMiss", // Operator exclusion is restricted. - branchList: leaveSingleLogSingleOp(), - wantWarnings: []string{ - "Operator \"Bob's CT Log Shop\" id=1 present at master log list but missing at branch.", - }, - wantError: true, - }, - { - name: "Shuffled", - branchList: swapLogsSwapOps(), - wantWarnings: []string{}, - wantError: false, - }, - { - name: "OperatorsMess", - branchList: messOperators(), - wantWarnings: []string{ - "Operator \"Bob's CT Log Shop\" id=1 present at master log list but missing at branch.", - "Operators mismatch for logs \"Google 'Aviator' log\" and \"Google 'Aviator' log\".", - }, - wantError: true, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - wl := sampleLogList.CheckBranch(&test.branchList) - if test.wantError != (len(wl) > 0) { - t.Errorf("CheckBranch %s: error status mismatch.", test.name) - } - wMismatchIds := getMismatchIds(wl, test.wantWarnings) - if len(wMismatchIds) > 0 { - t.Errorf("CheckBranch %s: got '%v', want warnings '%v'.\n %v-st/d/th warning mismatch.", test.name, wl, test.wantWarnings, wMismatchIds) - } - }) - } -} - -func getMismatchIds(got []string, want []string) []int { - wMismatchIds := make([]int, 0) - for i := 0; i < len(got) || i < len(want); i++ { - if i >= len(got) || i >= len(want) || !strings.Contains(got[i], want[i]) { - wMismatchIds = append(wMismatchIds, i) - } - } - return wMismatchIds -} diff --git a/loglist/findlog/main.go b/loglist/findlog/main.go deleted file mode 100644 index e1a42c48e2..0000000000 --- a/loglist/findlog/main.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// The findlog binary attempts to provide information about a log based on -// ID or name. -package main - -import ( - "crypto" - "crypto/sha256" - "encoding/base64" - "flag" - "fmt" - "net/http" - "os" - "time" - - ct "github.com/google/certificate-transparency-go" - "github.com/google/certificate-transparency-go/loglist" - "github.com/google/certificate-transparency-go/x509util" - "k8s.io/klog/v2" -) - -var ( - logList = flag.String("log_list", loglist.AllLogListURL, "Location of master log list (URL or filename)") - logListSig = flag.String("log_list_sig", "", "Location of log list signature (URL or filename)") - logListPubKeyFile = flag.String("log_list_pubkey", "", "File holding public key signing log list in PEM format") - verbose = flag.Bool("verbose", false, "Print more information") -) - -func main() { - flag.Parse() - client := &http.Client{Timeout: time.Second * 10} - - llData, err := x509util.ReadFileOrURL(*logList, client) - if err != nil { - klog.Exitf("Failed to read log list: %v", err) - } - - var pubKey crypto.PublicKey - if *logListPubKeyFile != "" { - data, err := os.ReadFile(*logListPubKeyFile) - if err != nil { - klog.Exitf("Failed to read public key: %v", err) - } - pubKey, _ /* keyhash */, _ /* rest */, err = ct.PublicKeyFromPEM(data) - if err != nil { - klog.Exitf("Failed to parse public key: %v", err) - } - } - - factory := func(d []byte) (*loglist.LogList, error) { - return loglist.NewFromJSON(d) - } - if pubKey != nil { - sig, err := x509util.ReadFileOrURL(*logListSig, client) - if err != nil { - klog.Exitf("Failed to read log list signature: %v", err) - } - factory = func(d []byte) (*loglist.LogList, error) { - return loglist.NewFromSignedJSON(d, sig, pubKey) - } - } - - ll, err := factory(llData) - if err != nil { - klog.Exitf("Failed to build log list: %v", err) - } - - args := flag.Args() - if len(args) == 0 { - klog.Exitf("No logs specified") - } - for _, arg := range args { - logs := ll.FuzzyFindLog(arg) - for _, log := range logs { - fmt.Printf("%s \t\t<%s>\n", log.Description, log.URL) - if *verbose { - fmt.Printf(" Key (hex): %x\n", log.Key) - fmt.Printf(" Key (base64): %s\n", base64.StdEncoding.EncodeToString(log.Key)) - keyhash := sha256.Sum256(log.Key) - fmt.Printf(" KeyHash (hex): %x\n", keyhash[:]) - fmt.Printf(" KeyHash (base64): %s\n", base64.StdEncoding.EncodeToString(keyhash[:])) - fmt.Printf(" MMD: %d seconds\n", log.MaximumMergeDelay) - for _, who := range log.OperatedBy { - for _, op := range ll.Operators { - if op.ID == who { - fmt.Printf(" Operator: %s\n", op.Name) - } - } - } - if log.FinalSTH != nil { - fmt.Printf(" FinalSTH:\n") - fmt.Printf(" TreeSize: %d\n", log.FinalSTH.TreeSize) - when := ct.TimestampToTime(uint64(log.FinalSTH.Timestamp)) - fmt.Printf(" Timestamp: %d (%v)\n", log.FinalSTH.Timestamp, when) - fmt.Printf(" SHA256RootHash: %x\n", log.FinalSTH.SHA256RootHash) - fmt.Printf(" TreeHeadSignature: %x\n", log.FinalSTH.TreeHeadSignature) - } - if log.DisqualifiedAt > 0 { - when := ct.TimestampToTime(uint64(log.DisqualifiedAt)) - fmt.Printf(" Disqualified at: %v (%d)\n", when, log.DisqualifiedAt) - } - if log.DNSAPIEndpoint != "" { - fmt.Printf(" DNS API endpoint: %s\n", log.DNSAPIEndpoint) - } - } - } - } -} diff --git a/loglist/logfilter.go b/loglist/logfilter.go deleted file mode 100644 index 867605864f..0000000000 --- a/loglist/logfilter.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package loglist - -import ( - "time" - - "github.com/google/certificate-transparency-go/x509" - "github.com/google/certificate-transparency-go/x509util" - "k8s.io/klog/v2" -) - -// LogRoots maps Log-URLs (stated at LogList) to the pools of their accepted -// root-certificates. -type LogRoots map[string]*x509util.PEMCertPool - -// ActiveLogs creates a new LogList containing only non-disqualified non-frozen -// logs from the original. -func (ll *LogList) ActiveLogs() LogList { - var active LogList - // Keep all the operators. - active.Operators = ll.Operators - for _, l := range ll.Logs { - if (l.DisqualifiedAt <= 0 && l.FinalSTH == nil) || time.Until(time.Unix(int64(l.DisqualifiedAt), 0)) > 0 { - active.Logs = append(active.Logs, l) - } - } - return active -} - -// Compatible creates a new LogList containing only the logs of original -// LogList that are compatible with the provided cert, according to -// the passed in collection of per-log roots. Logs that are missing from -// the collection are treated as always compatible and included, even if -// an empty cert root is passed in. -// Cert-root when provided is expected to be CA-cert. -func (ll *LogList) Compatible(cert *x509.Certificate, certRoot *x509.Certificate, roots LogRoots) LogList { - var compatible LogList - // Keep all the operators. - compatible.Operators = ll.Operators - - // Check whether chain is ending with CA-cert. - if certRoot != nil && !certRoot.IsCA { - klog.Warningf("Compatible method expects fully rooted chain, while last cert of the chain provided is not root") - return compatible - } - - for _, l := range ll.Logs { - // If root set is not defined, we treat Log as compatible assuming no - // knowledge of its roots. - if _, ok := roots[l.URL]; !ok { - compatible.Logs = append(compatible.Logs, l) - continue - } - if certRoot == nil { - continue - } - - // Check root is accepted. - if roots[l.URL].Included(certRoot) { - compatible.Logs = append(compatible.Logs, l) - } - } - return compatible -} diff --git a/loglist/logfilter_test.go b/loglist/logfilter_test.go deleted file mode 100644 index 7c0327b698..0000000000 --- a/loglist/logfilter_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package loglist - -import ( - "testing" - - "github.com/google/certificate-transparency-go/testdata" - "github.com/google/certificate-transparency-go/x509" - "github.com/google/certificate-transparency-go/x509util" - - "github.com/kylelemons/godebug/pretty" -) - -func subLogList(logURLs map[string]bool) LogList { - var ll LogList - ll.Operators = sampleLogList.Operators - for _, l := range sampleLogList.Logs { - if logURLs[l.URL] { - ll.Logs = append(ll.Logs, l) - } - } - return ll -} - -func TestActiveLogs(t *testing.T) { - tests := []struct { - name string - in LogList - want LogList - }{ - { - name: "Sample", - in: sampleLogList, - want: subLogList(map[string]bool{"ct.googleapis.com/icarus/": true, "ct.googleapis.com/rocketeer/": true, "ct.googleapis.com/racketeer/": true}), - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.in.ActiveLogs() - if diff := pretty.Compare(got, test.want); diff != "" { - t.Errorf("Extracting active logs out of %v diff: (-got + want)\n%s", test.in, diff) - } - }) - } -} - -func artificialRoots(source string) LogRoots { - roots := LogRoots{ - "log.bob.io": x509util.NewPEMCertPool(), - "ct.googleapis.com/racketeer/": x509util.NewPEMCertPool(), - "ct.googleapis.com/rocketeer/": x509util.NewPEMCertPool(), - "ct.googleapis.com/aviator/": x509util.NewPEMCertPool(), - } - roots["log.bob.io"].AppendCertsFromPEM([]byte(source)) - return roots -} - -func TestCompatible(t *testing.T) { - cert, _ := x509util.CertificateFromPEM([]byte(testdata.TestPreCertPEM)) - caCert, _ := x509util.CertificateFromPEM([]byte(testdata.CACertPEM)) - - tests := []struct { - name string - in LogList - cert *x509.Certificate - certRoot *x509.Certificate - roots LogRoots - want LogList - }{ - { - name: "RootedChain", - in: sampleLogList, - cert: cert, - certRoot: caCert, - roots: artificialRoots(testdata.CACertPEM), - want: subLogList(map[string]bool{"log.bob.io": true, "ct.googleapis.com/icarus/": true}), // icarus has no root info. - }, - { - name: "RootedChainNoRootAccepted", - in: sampleLogList, - cert: cert, - certRoot: caCert, - roots: artificialRoots(testdata.TestPreCertPEM), - want: subLogList(map[string]bool{"ct.googleapis.com/icarus/": true}), // icarus has no root info. - }, - { - name: "UnRootedChain", - in: sampleLogList, - cert: cert, - certRoot: cert, - roots: artificialRoots(testdata.CACertPEM), - want: subLogList(map[string]bool{}), - }, - { - name: "EmptyChain", - in: sampleLogList, - cert: nil, - certRoot: nil, - roots: artificialRoots(testdata.CACertPEM), - want: subLogList(map[string]bool{"ct.googleapis.com/icarus/": true}), // icarus has no root info. - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.in.Compatible(test.cert, test.certRoot, test.roots) - if diff := pretty.Compare(got, test.want); diff != "" { - t.Errorf("Getting compatible logs diff: (-got +want)\n%s", diff) - } - }) - } -} diff --git a/loglist/loglist.go b/loglist/loglist.go deleted file mode 100644 index f0959be438..0000000000 --- a/loglist/loglist.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package loglist allows parsing and searching of the master CT Log list. -package loglist - -import ( - "bytes" - "crypto" - "crypto/ecdsa" - "crypto/rsa" - "crypto/sha256" - "encoding/base64" - "encoding/hex" - "encoding/json" - "fmt" - "regexp" - "strings" - "unicode" - - "github.com/google/certificate-transparency-go/tls" -) - -const ( - // LogListURL has the master URL for Google Chrome's log list. - LogListURL = "https://www.gstatic.com/ct/log_list/log_list.json" - // LogListSignatureURL has the URL for the signature over Google Chrome's log list. - LogListSignatureURL = "https://www.gstatic.com/ct/log_list/log_list.sig" - // AllLogListURL has the URL for the list of all known logs (which isn't signed). - AllLogListURL = "https://www.gstatic.com/ct/log_list/all_logs_list.json" -) - -// Manually mapped from https://www.gstatic.com/ct/log_list/log_list_schema.json - -// LogList holds a collection of logs and their operators -type LogList struct { - Logs []Log `json:"logs"` - Operators []Operator `json:"operators"` -} - -// Operator describes a log operator -type Operator struct { - ID int `json:"id"` - Name string `json:"name"` -} - -// Log describes a log. -type Log struct { - Description string `json:"description"` - Key []byte `json:"key"` - MaximumMergeDelay int `json:"maximum_merge_delay"` // seconds - OperatedBy []int `json:"operated_by"` // List of log operators - URL string `json:"url"` - FinalSTH *STH `json:"final_sth,omitempty"` - DisqualifiedAt int `json:"disqualified_at,omitempty"` - DNSAPIEndpoint string `json:"dns_api_endpoint,omitempty"` // DNS API endpoint for the log -} - -// STH describes a signed tree head from a log. -type STH struct { - TreeSize int `json:"tree_size"` - Timestamp int `json:"timestamp"` - SHA256RootHash []byte `json:"sha256_root_hash"` - TreeHeadSignature []byte `json:"tree_head_signature"` -} - -// GoogleOperated returns whether Log is operated by Google. Rough logic. -func (l *Log) GoogleOperated() bool { - lowerDesc := strings.ToLower(l.Description) - return strings.Contains(lowerDesc, "google") -} - -// NewFromJSON creates a LogList from JSON encoded data. -func NewFromJSON(llData []byte) (*LogList, error) { - var ll LogList - if err := json.Unmarshal(llData, &ll); err != nil { - return nil, fmt.Errorf("failed to parse log list: %v", err) - } - return &ll, nil -} - -// NewFromSignedJSON creates a LogList from JSON encoded data, checking a -// signature along the way. The signature data should be provided as the -// raw signature data. -func NewFromSignedJSON(llData, rawSig []byte, pubKey crypto.PublicKey) (*LogList, error) { - var sigAlgo tls.SignatureAlgorithm - switch pkType := pubKey.(type) { - case *rsa.PublicKey: - sigAlgo = tls.RSA - case *ecdsa.PublicKey: - sigAlgo = tls.ECDSA - default: - return nil, fmt.Errorf("unsupported public key type %v", pkType) - } - tlsSig := tls.DigitallySigned{ - Algorithm: tls.SignatureAndHashAlgorithm{ - Hash: tls.SHA256, - Signature: sigAlgo, - }, - Signature: rawSig, - } - if err := tls.VerifySignature(pubKey, llData, tlsSig); err != nil { - return nil, fmt.Errorf("failed to verify signature: %v", err) - } - return NewFromJSON(llData) -} - -// OperatorIDSet is a helper op, creates set of operators for LogList. -func (ll *LogList) OperatorIDSet() map[int]string { - ops := make(map[int]string) - for _, op := range ll.Operators { - ops[op.ID] = op.Name - } - return ops -} - -// FindLogByName returns all logs whose names contain the given string. -func (ll *LogList) FindLogByName(name string) []*Log { - name = strings.ToLower(name) - var results []*Log - for _, log := range ll.Logs { - if strings.Contains(strings.ToLower(log.Description), name) { - log := log - results = append(results, &log) - } - } - return results -} - -// FindLogByURL finds the log with the given URL. -func (ll *LogList) FindLogByURL(url string) *Log { - for _, log := range ll.Logs { - // Don't count trailing slashes - if strings.TrimRight(log.URL, "/") == strings.TrimRight(url, "/") { - return &log - } - } - return nil -} - -// FindLogByKeyHash finds the log with the given key hash. -func (ll *LogList) FindLogByKeyHash(keyhash [sha256.Size]byte) *Log { - for _, log := range ll.Logs { - h := sha256.Sum256(log.Key) - if bytes.Equal(h[:], keyhash[:]) { - return &log - } - } - return nil -} - -// FindLogByKeyHashPrefix finds all logs whose key hash starts with the prefix. -func (ll *LogList) FindLogByKeyHashPrefix(prefix string) []*Log { - var results []*Log - for _, log := range ll.Logs { - h := sha256.Sum256(log.Key) - hh := hex.EncodeToString(h[:]) - if strings.HasPrefix(hh, prefix) { - log := log - results = append(results, &log) - } - } - return results -} - -// FindLogByKey finds the log with the given DER-encoded key. -func (ll *LogList) FindLogByKey(key []byte) *Log { - for _, log := range ll.Logs { - if bytes.Equal(log.Key[:], key) { - return &log - } - } - return nil -} - -var hexDigits = regexp.MustCompile("^[0-9a-fA-F]+$") - -// FuzzyFindLog tries to find logs that match the given unspecified input, -// whose format is unspecified. This generally returns a single log, but -// if text input that matches multiple log descriptions is provided, then -// multiple logs may be returned. -func (ll *LogList) FuzzyFindLog(input string) []*Log { - input = strings.Trim(input, " \t") - if logs := ll.FindLogByName(input); len(logs) > 0 { - return logs - } - if log := ll.FindLogByURL(input); log != nil { - return []*Log{log} - } - // Try assuming the input is binary data of some form. First base64: - if data, err := base64.StdEncoding.DecodeString(input); err == nil { - if len(data) == sha256.Size { - var hash [sha256.Size]byte - copy(hash[:], data) - if log := ll.FindLogByKeyHash(hash); log != nil { - return []*Log{log} - } - } - if log := ll.FindLogByKey(data); log != nil { - return []*Log{log} - } - } - // Now hex, but strip all internal whitespace first. - input = stripInternalSpace(input) - if data, err := hex.DecodeString(input); err == nil { - if len(data) == sha256.Size { - var hash [sha256.Size]byte - copy(hash[:], data) - if log := ll.FindLogByKeyHash(hash); log != nil { - return []*Log{log} - } - } - if log := ll.FindLogByKey(data); log != nil { - return []*Log{log} - } - } - // Finally, allow hex strings with an odd number of digits. - if hexDigits.MatchString(input) { - if logs := ll.FindLogByKeyHashPrefix(input); len(logs) > 0 { - return logs - } - } - - return nil -} - -func stripInternalSpace(input string) string { - return strings.Map(func(r rune) rune { - if !unicode.IsSpace(r) { - return r - } - return -1 - }, input) -} diff --git a/loglist/loglist_test.go b/loglist/loglist_test.go deleted file mode 100644 index 8477735920..0000000000 --- a/loglist/loglist_test.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package loglist - -import ( - "crypto/sha256" - "encoding/base64" - "encoding/json" - "fmt" - "reflect" - "strings" - "testing" - - "github.com/google/certificate-transparency-go/testdata" -) - -var sampleLogList = LogList{ - Operators: []Operator{ - {ID: 0, Name: "Google"}, - {ID: 1, Name: "Bob's CT Log Shop"}, - }, - Logs: []Log{ - { - Description: "Google 'Aviator' log", - Key: deb64("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q=="), - URL: "ct.googleapis.com/aviator/", - MaximumMergeDelay: 86400, - OperatedBy: []int{0}, - FinalSTH: &STH{ - TreeSize: 46466472, - Timestamp: 1480512258330, - SHA256RootHash: deb64("LcGcZRsm+LGYmrlyC5LXhV1T6OD8iH5dNlb0sEJl9bA="), - TreeHeadSignature: deb64("BAMASDBGAiEA/M0Nvt77aNe+9eYbKsv6rRpTzFTKa5CGqb56ea4hnt8CIQCJDE7pL6xgAewMd5i3G1lrBWgFooT2kd3+zliEz5Rw8w=="), - }, - DNSAPIEndpoint: "aviator.ct.googleapis.com", - }, - { - Description: "Google 'Icarus' log", - Key: deb64("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETtK8v7MICve56qTHHDhhBOuV4IlUaESxZryCfk9QbG9co/CqPvTsgPDbCpp6oFtyAHwlDhnvr7JijXRD9Cb2FA=="), - URL: "ct.googleapis.com/icarus/", - MaximumMergeDelay: 86400, - OperatedBy: []int{0}, - DNSAPIEndpoint: "icarus.ct.googleapis.com", - }, - { - Description: "Google 'Rocketeer' log", - Key: deb64("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg=="), - URL: "ct.googleapis.com/rocketeer/", - MaximumMergeDelay: 86400, - OperatedBy: []int{0}, - DNSAPIEndpoint: "rocketeer.ct.googleapis.com", - }, - { - Description: "Google 'Racketeer' log", - // Key value chosed to have a hash that starts ee4... (specifically ee412fe25948348961e2f3e08c682e813ec0ff770b6d75171763af3014ff9768) - Key: deb64("Hy2TPTZ2yq9ASMmMZiB9SZEUx5WNH5G0Ft5Tm9vKMcPXA+ic/Ap3gg6fXzBJR8zLkt5lQjvKMdbHYMGv7yrsZg=="), - URL: "ct.googleapis.com/racketeer/", - MaximumMergeDelay: 86400, - OperatedBy: []int{0}, - DNSAPIEndpoint: "racketeer.ct.googleapis.com", - }, - { - Description: "Bob's Dubious Log", - Key: deb64("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2MNvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA=="), - URL: "log.bob.io", - MaximumMergeDelay: 86400, - OperatedBy: []int{1}, - DisqualifiedAt: 1460678400, - DNSAPIEndpoint: "dubious-bob.ct.googleapis.com", - }, - }, -} - -func TestJSONMarshal(t *testing.T) { - var tests = []struct { - name string - in LogList - want, wantErr string - }{ - { - name: "MultiValid", - in: sampleLogList, - want: testdata.SampleLogList, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got, err := json.Marshal(&test.in) - if err != nil { - if test.wantErr == "" { - t.Errorf("json.Marshal()=nil,%v; want _,nil", err) - } else if !strings.Contains(err.Error(), test.wantErr) { - t.Errorf("json.Marshal()=nil,%v; want nil,err containing %q", err, test.wantErr) - } - return - } - if test.wantErr != "" { - t.Errorf("json.Marshal()=%q,nil; want nil,err containing %q", got, test.wantErr) - } - if string(got) != test.want { - t.Errorf("json.Marshal()=%q,nil; want %q", got, test.want) - } - }) - } -} - -func TestFindLogByName(t *testing.T) { - var tests = []struct { - name, in string - want int - }{ - {name: "Single", in: "Dubious", want: 1}, - {name: "SingleDifferentCase", in: "DUBious", want: 1}, - {name: "Multiple", in: "Google", want: 4}, - {name: "None", in: "Llamalog", want: 0}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := sampleLogList.FindLogByName(test.in) - if len(got) != test.want { - t.Errorf("len(FindLogByName(%q)=%d, want %d", test.in, len(got), test.want) - } - }) - } -} - -func TestFindLogByURL(t *testing.T) { - var tests = []struct { - name, in, want string - }{ - {name: "NotFound", in: "nowhere.com"}, - {name: "Found//", in: "ct.googleapis.com/icarus/", want: "Google 'Icarus' log"}, - {name: "Found./", in: "ct.googleapis.com/icarus", want: "Google 'Icarus' log"}, - {name: "Found/.", in: "log.bob.io/", want: "Bob's Dubious Log"}, - {name: "Found..", in: "log.bob.io", want: "Bob's Dubious Log"}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - log := sampleLogList.FindLogByURL(test.in) - got := "" - if log != nil { - got = log.Description - } - if got != test.want { - t.Errorf("FindLogByURL(%q)=%q, want %q", test.in, got, test.want) - } - }) - } -} - -func TestFindLogByKeyhash(t *testing.T) { - var tests = []struct { - name string - in []byte - want string - }{ - { - name: "NotFound", - in: []byte{0xaa, 0xbb, 0xcc}, - }, - { - name: "FoundRocketeer", - in: []byte{ - 0xee, 0x4b, 0xbd, 0xb7, 0x75, 0xce, 0x60, 0xba, 0xe1, 0x42, 0x69, 0x1f, 0xab, 0xe1, 0x9e, 0x66, - 0xa3, 0x0f, 0x7e, 0x5f, 0xb0, 0x72, 0xd8, 0x83, 0x00, 0xc4, 0x7b, 0x89, 0x7a, 0xa8, 0xfd, 0xcb, - }, - want: "Google 'Rocketeer' log", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - var hash [sha256.Size]byte - copy(hash[:], test.in) - log := sampleLogList.FindLogByKeyHash(hash) - got := "" - if log != nil { - got = log.Description - } - if got != test.want { - t.Errorf("FindLogByKeyHash(%x)=%q, want %q", test.in, got, test.want) - } - }) - } -} - -func TestFindLogByKeyhashPrefix(t *testing.T) { - var tests = []struct { - name, in string - want []string - }{ - { - name: "NotFound", - in: "aabbcc", - want: []string{}, - }, - { - name: "FoundRocketeer", - in: "ee4b", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundRocketeerOdd", - in: "ee4bb", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundMultiple", - in: "ee4", - want: []string{"Google 'Rocketeer' log", "Google 'Racketeer' log"}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - logs := sampleLogList.FindLogByKeyHashPrefix(test.in) - got := make([]string, len(logs)) - for i, log := range logs { - got[i] = log.Description - } - if !reflect.DeepEqual(got, test.want) { - t.Errorf("FindLogByKeyHash(%x)=%q, want %q", test.in, got, test.want) - } - }) - } -} - -func TestFindLogByKey(t *testing.T) { - var tests = []struct { - name string - in []byte - want string - }{ - { - name: "NotFound", - in: []byte{0xaa, 0xbb, 0xcc}, - }, - { - name: "FoundRocketeer", - in: deb64("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg=="), - want: "Google 'Rocketeer' log", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - log := sampleLogList.FindLogByKey(test.in) - got := "" - if log != nil { - got = log.Description - } - if got != test.want { - t.Errorf("FindLogByKey(%x)=%q, want %q", test.in, got, test.want) - } - }) - } -} - -func TestFuzzyFindLog(t *testing.T) { - var tests = []struct { - name, in string - want []string - }{ - { - name: "NotFound", - in: "aabbcc", - want: []string{}, - }, - { - name: "FoundByKey64", - in: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg==", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundByKeyHex", - in: "3059301306072a8648ce3d020106082a8648ce3d03010703420004205b18c83cc18bb3310800bfa090572bb7478c6fb568b08e9078e9a073ea4f28212e9cc0f4161baaf9d5d7a980c34e2f523c9801254624252823772d05c2407a", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundByKeyHashHex", - in: " ee 4b bd b7 75 ce 60 ba e1 42 69 1f ab e1 9e 66 a3 0f 7e 5f b0 72 d8 83 00 c4 7b 89 7a a8 fd cb", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundByKeyHashHexPrefix", - in: "ee4bbdb7", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundByKeyHash64", - in: "7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/cs=", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundByName", - in: "Rocketeer", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundByNameDifferentCase", - in: "rocketeer", - want: []string{"Google 'Rocketeer' log"}, - }, - { - name: "FoundByURL", - in: "ct.googleapis.com/rocketeer", - want: []string{"Google 'Rocketeer' log"}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - logs := sampleLogList.FuzzyFindLog(test.in) - got := make([]string, len(logs)) - for i, log := range logs { - got[i] = log.Description - } - if !reflect.DeepEqual(got, test.want) { - t.Errorf("FuzzyFindLog(%q)=%v, want %v", test.in, got, test.want) - } - }) - } -} - -func TestStripInternalSpace(t *testing.T) { - var tests = []struct { - in string - want string - }{ - {in: "xyz", want: "xyz"}, - {in: "x y z", want: "xyz"}, - {in: "x yz ", want: "xyz"}, - {in: " xyz ", want: "xyz"}, - {in: "xy\t\tz", want: "xyz"}, - } - - for _, test := range tests { - got := stripInternalSpace(test.in) - if got != test.want { - t.Errorf("stripInternalSpace(%q)=%q, want %q", test.in, got, test.want) - } - } -} - -func changeLogDesc(log Log, desc string) Log { - log.Description = desc - return log -} - -func TestGoogleOperated(t *testing.T) { - var tests = []struct { - in Log - out bool - }{ - {in: sampleLogList.Logs[0], out: true}, - {in: sampleLogList.Logs[1], out: true}, - {in: sampleLogList.Logs[2], out: true}, - {in: sampleLogList.Logs[3], out: true}, - {in: sampleLogList.Logs[4], out: false}, - {in: changeLogDesc(sampleLogList.Logs[1], "Gogle 'Aviator' log"), out: false}, - {in: changeLogDesc(sampleLogList.Logs[4], "Bob's Dubious Log is non-Google"), out: true}, - } - for _, test := range tests { - isGoog := test.in.GoogleOperated() - if isGoog != test.out { - t.Errorf("GoogleOperated status for %s is %t, want %t", test.in.Description, isGoog, test.out) - } - } -} - -func deb64(b string) []byte { - data, err := base64.StdEncoding.DecodeString(b) - if err != nil { - panic(fmt.Sprintf("hard-coded test data failed to decode: %v", err)) - } - return data -} From 471a43469f38f7f8ba33adce73d25efbfae9e334 Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 13:43:09 +0000 Subject: [PATCH 06/11] Migrate loglist dependency from v1 to v3 in ctutil/loginfo.go --- ctutil/loginfo.go | 174 ++++++++++++++++++++++++++++++++++++ ctutil/sctcheck/sctcheck.go | 16 ++-- 2 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 ctutil/loginfo.go diff --git a/ctutil/loginfo.go b/ctutil/loginfo.go new file mode 100644 index 0000000000..83d9739c7e --- /dev/null +++ b/ctutil/loginfo.go @@ -0,0 +1,174 @@ +// Copyright 2018 Google LLC. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctutil + +import ( + "context" + "crypto/sha256" + "fmt" + "net/http" + "strings" + "sync" + "time" + + ct "github.com/google/certificate-transparency-go" + "github.com/google/certificate-transparency-go/client" + "github.com/google/certificate-transparency-go/jsonclient" + "github.com/google/certificate-transparency-go/loglist3" + "github.com/google/certificate-transparency-go/x509" + "github.com/transparency-dev/merkle/proof" + "github.com/transparency-dev/merkle/rfc6962" +) + +// LogInfo holds the objects needed to perform per-log verification and +// validation of SCTs. +type LogInfo struct { + Description string + Client client.CheckLogClient + MMD time.Duration + Verifier *ct.SignatureVerifier + PublicKey []byte + + mu sync.RWMutex + lastSTH *ct.SignedTreeHead +} + +// NewLogInfo builds a LogInfo object based on a log list entry. +func NewLogInfo(log *loglist3.Log, hc *http.Client) (*LogInfo, error) { + url := log.URL + if !strings.HasPrefix(url, "https://") { + url = "https://" + url + } + lc, err := client.New(url, hc, jsonclient.Options{PublicKeyDER: log.Key, UserAgent: "ct-go-logclient"}) + if err != nil { + return nil, fmt.Errorf("failed to create client for log %q: %v", log.Description, err) + } + return newLogInfo(log, lc) +} + +func newLogInfo(log *loglist3.Log, lc client.CheckLogClient) (*LogInfo, error) { + logKey, err := x509.ParsePKIXPublicKey(log.Key) + if err != nil { + return nil, fmt.Errorf("failed to parse public key data for log %q: %v", log.Description, err) + } + verifier, err := ct.NewSignatureVerifier(logKey) + if err != nil { + return nil, fmt.Errorf("failed to build verifier log %q: %v", log.Description, err) + } + mmd := time.Duration(log.MMD) * time.Second + return &LogInfo{ + Description: log.Description, + Client: lc, + MMD: mmd, + Verifier: verifier, + PublicKey: log.Key, + }, nil +} + +// LogInfoByHash holds LogInfo objects index by the SHA-256 hash of the log's public key. +type LogInfoByHash map[[sha256.Size]byte]*LogInfo + +// LogInfoByKeyHash builds a map of LogInfo objects indexed by their key hashes. +func LogInfoByKeyHash(ll *loglist3.LogList, hc *http.Client) (LogInfoByHash, error) { + return logInfoByKeyHash(ll, hc, NewLogInfo) +} + +func logInfoByKeyHash(ll *loglist3.LogList, hc *http.Client, infoFactory func(*loglist3.Log, *http.Client) (*LogInfo, error)) (map[[sha256.Size]byte]*LogInfo, error) { + result := make(map[[sha256.Size]byte]*LogInfo) + for _, operator := range ll.Operators { + for _, log := range operator.Logs { + h := sha256.Sum256(log.Key) + li, err := infoFactory(log, hc) + if err != nil { + return nil, err + } + result[h] = li + } + } + return result, nil +} + +// LastSTH returns the last STH known for the log. +func (li *LogInfo) LastSTH() *ct.SignedTreeHead { + li.mu.RLock() + defer li.mu.RUnlock() + return li.lastSTH +} + +// SetSTH sets the last STH known for the log. +func (li *LogInfo) SetSTH(sth *ct.SignedTreeHead) { + li.mu.Lock() + defer li.mu.Unlock() + li.lastSTH = sth +} + +// VerifySCTSignature checks the signature in the SCT matches the given leaf (adjusted for the +// timestamp in the SCT) and log. +func (li *LogInfo) VerifySCTSignature(sct ct.SignedCertificateTimestamp, leaf ct.MerkleTreeLeaf) error { + leaf.TimestampedEntry.Timestamp = sct.Timestamp + if err := li.Verifier.VerifySCTSignature(sct, ct.LogEntry{Leaf: leaf}); err != nil { + return fmt.Errorf("failed to verify SCT signature from log %q: %v", li.Description, err) + } + return nil +} + +// VerifyInclusionLatest checks that the given Merkle tree leaf, adjusted for the provided timestamp, +// is present in the latest known tree size of the log. If no tree size for the log is known, it will +// be queried. On success, returns the index of the leaf in the log. +func (li *LogInfo) VerifyInclusionLatest(ctx context.Context, leaf ct.MerkleTreeLeaf, timestamp uint64) (int64, error) { + sth := li.LastSTH() + if sth == nil { + var err error + sth, err = li.Client.GetSTH(ctx) + if err != nil { + return -1, fmt.Errorf("failed to get current STH for %q log: %v", li.Description, err) + } + li.SetSTH(sth) + } + return li.VerifyInclusionAt(ctx, leaf, timestamp, sth.TreeSize, sth.SHA256RootHash[:]) +} + +// VerifyInclusion checks that the given Merkle tree leaf, adjusted for the provided timestamp, +// is present in the current tree size of the log. On success, returns the index of the leaf +// in the log. +func (li *LogInfo) VerifyInclusion(ctx context.Context, leaf ct.MerkleTreeLeaf, timestamp uint64) (int64, error) { + sth, err := li.Client.GetSTH(ctx) + if err != nil { + return -1, fmt.Errorf("failed to get current STH for %q log: %v", li.Description, err) + } + li.SetSTH(sth) + return li.VerifyInclusionAt(ctx, leaf, timestamp, sth.TreeSize, sth.SHA256RootHash[:]) +} + +// VerifyInclusionAt checks that the given Merkle tree leaf, adjusted for the provided timestamp, +// is present in the given tree size & root hash of the log. On success, returns the index of the +// leaf in the log. +func (li *LogInfo) VerifyInclusionAt(ctx context.Context, leaf ct.MerkleTreeLeaf, timestamp, treeSize uint64, rootHash []byte) (int64, error) { + leaf.TimestampedEntry.Timestamp = timestamp + leafHash, err := ct.LeafHashForLeaf(&leaf) + if err != nil { + return -1, fmt.Errorf("failed to create leaf hash: %v", err) + } + + rsp, err := li.Client.GetProofByHash(ctx, leafHash[:], treeSize) + if err != nil { + return -1, fmt.Errorf("failed to GetProofByHash(sct,size=%d): %v", treeSize, err) + } + + if err := proof.VerifyInclusion(rfc6962.DefaultHasher, uint64(rsp.LeafIndex), treeSize, leafHash[:], rsp.AuditPath, rootHash); err != nil { + return -1, fmt.Errorf("failed to verify inclusion proof at size %d: %v", treeSize, err) + } + return rsp.LeafIndex, nil +} diff --git a/ctutil/sctcheck/sctcheck.go b/ctutil/sctcheck/sctcheck.go index 6d74994276..05a56df32f 100644 --- a/ctutil/sctcheck/sctcheck.go +++ b/ctutil/sctcheck/sctcheck.go @@ -30,7 +30,7 @@ import ( "time" "github.com/google/certificate-transparency-go/ctutil" - "github.com/google/certificate-transparency-go/loglist" + "github.com/google/certificate-transparency-go/loglist3" "github.com/google/certificate-transparency-go/x509" "github.com/google/certificate-transparency-go/x509util" "k8s.io/klog/v2" @@ -39,12 +39,12 @@ import ( ) var ( - logList = flag.String("log_list", loglist.AllLogListURL, "Location of master CT log list (URL or filename)") + logList = flag.String("log_list", loglist3.AllLogListURL, "Location of master CT log list (URL or filename)") deadline = flag.Duration("deadline", 30*time.Second, "Timeout deadline for HTTP requests") checkInclusion = flag.Bool("check_inclusion", true, "Whether to check SCT inclusion in issuing CT log") ) -type logInfoFactory func(*loglist.Log, *http.Client) (*ctutil.LogInfo, error) +type logInfoFactory func(*loglist3.Log, *http.Client) (*ctutil.LogInfo, error) func main() { klog.InitFlags(nil) @@ -56,7 +56,7 @@ func main() { if err != nil { klog.Exitf("Failed to read log list: %v", err) } - ll, err := loglist.NewFromJSON(llData) + ll, err := loglist3.NewFromJSON(llData) if err != nil { klog.Exitf("Failed to parse log list: %v", err) } @@ -106,7 +106,7 @@ func main() { // checkChain iterates over any embedded SCTs in the leaf certificate of the chain // and checks those SCTs. Returns the counts of valid and invalid embedded SCTs found. -func checkChain(ctx context.Context, lf logInfoFactory, chain []*x509.Certificate, ll *loglist.LogList, hc *http.Client) (int, int) { +func checkChain(ctx context.Context, lf logInfoFactory, chain []*x509.Certificate, ll *loglist3.LogList, hc *http.Client) (int, int) { leaf := chain[0] if len(leaf.SCTList.SCTList) == 0 { return 0, 0 @@ -148,7 +148,7 @@ func checkChain(ctx context.Context, lf logInfoFactory, chain []*x509.Certificat // for an HTTPS site. Along the way it checks any external SCTs that are served // up on the connection alongside the chain. Returns the chain and counts of // valid and invalid external SCTs found. -func getAndCheckSiteChain(ctx context.Context, lf logInfoFactory, target string, ll *loglist.LogList, hc *http.Client) ([]*x509.Certificate, int, int, error) { +func getAndCheckSiteChain(ctx context.Context, lf logInfoFactory, target string, ll *loglist3.LogList, hc *http.Client) ([]*x509.Certificate, int, int, error) { u, err := url.Parse(target) if err != nil { return nil, 0, 0, fmt.Errorf("failed to parse URL: %v", err) @@ -212,7 +212,7 @@ func getAndCheckSiteChain(ctx context.Context, lf logInfoFactory, target string, // checkSCT performs checks on an SCT and Merkle tree leaf, performing both // signature validation and online log inclusion checking. Returns whether // the SCT is valid. -func checkSCT(ctx context.Context, liFactory logInfoFactory, subject string, merkleLeaf *ct.MerkleTreeLeaf, sctData *x509.SerializedSCT, ll *loglist.LogList, hc *http.Client) bool { +func checkSCT(ctx context.Context, liFactory logInfoFactory, subject string, merkleLeaf *ct.MerkleTreeLeaf, sctData *x509.SerializedSCT, ll *loglist3.LogList, hc *http.Client) bool { sct, err := x509util.ExtractSCT(sctData) if err != nil { klog.Errorf("Failed to deserialize %s data: %v", subject, err) @@ -246,7 +246,7 @@ func checkSCT(ctx context.Context, liFactory logInfoFactory, subject string, mer if err != nil { age := time.Since(ct.TimestampToTime(sct.Timestamp)) if age < logInfo.MMD { - klog.Warningf("Failed to verify inclusion proof (%v) but %s timestamp is only %v old, less than log's MMD of %d seconds", err, subject, age, log.MaximumMergeDelay) + klog.Warningf("Failed to verify inclusion proof (%v) but %s timestamp is only %v old, less than log's MMD of %d seconds", err, subject, age, log.MMD) } else { klog.Errorf("Failed to verify inclusion proof for %s: %v", subject, err) } From 0c4457795d89f0275ab2d6bdd3761ec7a5a2dd4e Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 13:43:33 +0000 Subject: [PATCH 07/11] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index deccf41a1c..ce41383638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,8 @@ * #800: Remove dependency from `ratelimit`. * #927: Add read-only mode to CTFE config. * Update Trillian to [0a389c4](https://github.com/google/trillian/commit/0a389c4bb8d97fb3be8f55d7e5b428cf4304986f) - * Migrate loglist from v1 to v3 in ctclient cmd. + * Migrate loglist dependency from v1 to v3 in ctclient cmd. + * Migrate loglist dependency from v1 to v3 in ctutil/loginfo.go ## v1.1.2 From e112e1b4acc2c83a5e04f59a4beb9904327b6820 Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 13:53:57 +0000 Subject: [PATCH 08/11] Migrate loglist dependency from v1 to v3 in ctutil/sctscan.go --- ctutil/sctscan/sctscan.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ctutil/sctscan/sctscan.go b/ctutil/sctscan/sctscan.go index 9980dd7196..b4988e2ee4 100644 --- a/ctutil/sctscan/sctscan.go +++ b/ctutil/sctscan/sctscan.go @@ -27,7 +27,7 @@ import ( "github.com/google/certificate-transparency-go/client" "github.com/google/certificate-transparency-go/ctutil" "github.com/google/certificate-transparency-go/jsonclient" - "github.com/google/certificate-transparency-go/loglist" + "github.com/google/certificate-transparency-go/loglist3" "github.com/google/certificate-transparency-go/scanner" "github.com/google/certificate-transparency-go/x509" "github.com/google/certificate-transparency-go/x509util" @@ -36,7 +36,7 @@ import ( var ( logURI = flag.String("log_uri", "https://ct.googleapis.com/pilot", "CT log base URI") - logList = flag.String("log_list", loglist.AllLogListURL, "Location of master CT log list (URL or filename)") + logList = flag.String("log_list", loglist3.AllLogListURL, "Location of master CT log list (URL or filename)") inclusion = flag.Bool("inclusion", false, "Whether to do inclusion checking") deadline = flag.Duration("deadline", 30*time.Second, "Timeout deadline for HTTP requests") batchSize = flag.Int("batch_size", 1000, "Max number of entries to request at per call to get-entries") @@ -71,7 +71,7 @@ func main() { if err != nil { klog.Exitf("Failed to read log list: %v", err) } - ll, err := loglist.NewFromJSON(llData) + ll, err := loglist3.NewFromJSON(llData) if err != nil { klog.Exitf("Failed to parse log list: %v", err) } From 69e391382f39ab097368e6db2942fe4afc71c52a Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 13:54:42 +0000 Subject: [PATCH 09/11] Migrate loglist dependency from v1 to v3 in trillian/integration/ct_hammer/main.go --- trillian/integration/ct_hammer/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trillian/integration/ct_hammer/main.go b/trillian/integration/ct_hammer/main.go index e182f77cff..71cfccc092 100644 --- a/trillian/integration/ct_hammer/main.go +++ b/trillian/integration/ct_hammer/main.go @@ -34,7 +34,7 @@ import ( "github.com/google/certificate-transparency-go/client" "github.com/google/certificate-transparency-go/fixchain/ratelimiter" "github.com/google/certificate-transparency-go/jsonclient" - "github.com/google/certificate-transparency-go/loglist" + "github.com/google/certificate-transparency-go/loglist3" "github.com/google/certificate-transparency-go/trillian/ctfe" "github.com/google/certificate-transparency-go/trillian/ctfe/configpb" "github.com/google/certificate-transparency-go/trillian/integration" @@ -56,7 +56,7 @@ var ( srcLogURI = flag.String("src_log_uri", "", "URI for source log to copy certificates from") srcPubKey = flag.String("src_pub_key", "", "Name of file containing source log's public key") srcLogName = flag.String("src_log_name", "", "Name of source log to copy certificate from (from --log_list)") - logList = flag.String("log_list", loglist.AllLogListURL, "Location of master log list (URL or filename)") + logList = flag.String("log_list", loglist3.AllLogListURL, "Location of master log list (URL or filename)") skipHTTPSVerify = flag.Bool("skip_https_verify", false, "Skip verification of HTTPS transport connection to source log") chainBufSize = flag.Int("buffered_chains", 100, "Number of buffered certificate chains to hold") startIndex = flag.Int64("start_index", 0, "Index of start point in source log to scan from (-1 for random start index)") @@ -133,7 +133,7 @@ func copierGeneratorFactory(ctx context.Context) integration.GeneratorFactory { if err != nil { klog.Exitf("Failed to read log list: %v", err) } - ll, err := loglist.NewFromJSON(llData) + ll, err := loglist3.NewFromJSON(llData) if err != nil { klog.Exitf("Failed to build log list: %v", err) } From a8615ba0ca4b3b5168e5f991925f2ce5248cd1e9 Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 13:55:03 +0000 Subject: [PATCH 10/11] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce41383638..813fc22214 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ * Update Trillian to [0a389c4](https://github.com/google/trillian/commit/0a389c4bb8d97fb3be8f55d7e5b428cf4304986f) * Migrate loglist dependency from v1 to v3 in ctclient cmd. * Migrate loglist dependency from v1 to v3 in ctutil/loginfo.go + * Migrate loglist dependency from v1 to v3 in ctutil/sctscan.go + * Migrate loglist dependency from v1 to v3 in trillian/integration/ct_hammer/main.go ## v1.1.2 From 9ba1f44ec0135ac20e1ad3ac97d4ca214a480a54 Mon Sep 17 00:00:00 2001 From: Roger Ng Date: Thu, 8 Sep 2022 14:05:28 +0000 Subject: [PATCH 11/11] go mod tidy --- go.mod | 1 - go.sum | 2 -- 2 files changed, 3 deletions(-) diff --git a/go.mod b/go.mod index bb6a3f74d6..3e0a6c153c 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/gorilla/mux v1.8.0 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-sqlite3 v1.14.15 - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/prometheus/client_golang v1.13.0 github.com/rs/cors v1.8.2 github.com/sergi/go-diff v1.2.0 diff --git a/go.sum b/go.sum index 99c4a19fe1..3b2dea3aec 100644 --- a/go.sum +++ b/go.sum @@ -452,8 +452,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo=