@@ -20,6 +20,7 @@ import (
2020 "crypto/sha256"
2121 "crypto/x509"
2222 "encoding/base64"
23+ "errors"
2324 "flag"
2425 "fmt"
2526 "net/http"
@@ -71,68 +72,94 @@ func main() {
7172 src .SetAuthorizationHeader (fmt .Sprintf ("Bearer %s" , * bearerToken ))
7273 }
7374 v := verifierFromFlags ()
74- lsc := & logStateCollector {}
75- if err := fsck .Check (ctx , * origin , v , src , * N , lsc .merkleLeafHasher ()); err != nil {
76- klog .Exitf ("fsck failed: %v" , err )
77- }
75+ lsc := newLogStateCollector ()
76+ eg := errgroup.Group {}
77+ eg .Go (func () error {
78+ defer lsc .Close ()
79+ return fsck .Check (ctx , * origin , v , src , * N , lsc .merkleLeafHasher ())
80+
81+ })
82+ eg .Go (func () error {
83+ return lsc .checkIssuersTask (ctx , src .ReadIssuer , * N )
84+ })
7885
79- if err := checkIntermediates ( ctx , lsc , src . ReadIssuer , * N ); err != nil {
80- klog .Exitf ("Failed to verify presence intermediates: %v" , err )
86+ if err := eg . Wait ( ); err != nil {
87+ klog .Exitf ("FAILED: \n %v" , err )
8188 }
8289
8390 klog .Info ("OK" )
8491}
8592
86- func checkIntermediates (ctx context.Context , lsc * logStateCollector , readIssuer func (context.Context , []byte ) ([]byte , error ), N uint ) error {
87- klog .Infof ("Checking intermediates CAS" )
88- n := 0
89- work := make (chan []byte , N )
90- eg := errgroup.Group {}
93+ // logStateCollector tracks state of the target log which needs to be later checked.
94+ //
95+ // Currently, this is centred around the discovery and checking of issuers during entry bundle parsing.
96+ type logStateCollector struct {
97+ // issuersSeen contains the set of issuer fingerprints issuersSeen in the log so far.
98+ issuersSeen sync.Map
99+ // issuersToCheck is a channel of issuer fingerprints to look up in the target log's issuer CAS.
100+ issuersToCheck chan []byte
101+ }
102+
103+ // newLogStateCollector creates a new logStateCollector instance.
104+ func newLogStateCollector () * logStateCollector {
105+ return & logStateCollector {
106+ issuersToCheck : make (chan []byte ),
107+ }
108+ }
109+
110+ // Close should be called once no further issuers will be added.
111+ func (l * logStateCollector ) Close () {
112+ close (l .issuersToCheck )
113+ }
114+
115+ // checkIssuersTask reads looks up discovered issuer fingerprints in the target log's issuer CAS.
116+ //
117+ // This is a long-running function, it will only exit once Close has been called, and all remaining fingerprints in the
118+ // issuersToCheck channel have been checked.
119+ func (l * logStateCollector ) checkIssuersTask (ctx context.Context , readIssuer func (context.Context , []byte ) ([]byte , error ), N uint ) error {
120+ klog .Infof ("Checking issuers CAS" )
121+ errC := make (chan error )
122+ wg := sync.WaitGroup {}
91123 for range N {
92- eg .Go (func () error {
93- for fp := range work {
124+ wg .Add (1 )
125+ go func () {
126+ defer wg .Done ()
127+ for fp := range l .issuersToCheck {
94128 if _ , err := readIssuer (ctx , fp ); err != nil {
95- return fmt .Errorf ("couldn't fetch issuer for %x: %v" , fp , err )
129+ klog .Warningf ("Couldn't fetch issuer FP %x: %v" , fp , err )
130+ errC <- fmt .Errorf ("couldn't fetch issuer for %x: %v" , fp , err )
131+ continue
96132 }
133+ klog .V (2 ).Infof ("Issuer FP %x is present" , fp )
97134 }
98- return nil
99- })
135+ }()
100136 }
137+ wg .Wait ()
138+ close (errC )
101139
102- lsc .intermediates .Range (func (k any , v any ) bool {
103- fp := k .(string )
104- work <- []byte (fp )
105- n ++
106- return true
107- })
108- close (work )
109-
110- if err := eg .Wait (); err != nil {
111- return fmt .Errorf ("failed to fetch one or more issuers: %v" , err )
140+ errs := []error {}
141+ for e := range errC {
142+ errs = append (errs , e )
112143 }
113-
114- klog .Infof ("Checked %d intermediate issuers" , n )
115- return nil
116- }
117-
118- type logStateCollector struct {
119- intermediates sync.Map
144+ return errors .Join (errs ... )
120145}
121146
122- func (l * logStateCollector ) addIntermediates (fpRaw cryptobyte.String ) {
147+ // addIssuers adds the issuers in the provided byte string to the set of issuer to be checked.
148+ func (l * logStateCollector ) addIssuers (fpRaw cryptobyte.String ) {
123149 var fp []byte
124150 for len (fpRaw ) > 0 {
125151 fp , fpRaw = fpRaw [:32 ], fpRaw [32 :]
126- _ , existed := l .intermediates .LoadOrStore (string (fp ), true )
152+ _ , existed := l .issuersSeen .LoadOrStore (string (fp ), true )
127153 if ! existed {
128- klog .V (2 ).Infof ("Found intermediate FP %x" , fp )
154+ klog .V (2 ).Infof ("Found issuer FP %x" , fp )
155+ l .issuersToCheck <- fp
129156 }
130157 }
131158}
132159
133160// merkleLeafHasher returns a function which knows how to:
134161// - calculate RFC6962 Merkle leaf hashes for entries in a Static-CT formatted entry bundle,
135- // - keep track of the set of intermediate cert fingerprints seen while parsing entry bundles.
162+ // - keep track of the set of issuer cert fingerprints seen while parsing entry bundles.
136163func (l * logStateCollector ) merkleLeafHasher () func (bundle []byte ) ([][]byte , error ) {
137164 return func (bundle []byte ) ([][]byte , error ) {
138165 r := make ([][]byte , 0 , layout .EntryBundleWidth )
@@ -187,7 +214,7 @@ func (l *logStateCollector) merkleLeafHasher() func(bundle []byte) ([][]byte, er
187214 if ! b .ReadUint16LengthPrefixed (& fpRaw ) {
188215 return nil , fmt .Errorf ("failed to read chain fingerprints at entry index %d of bundle" , i )
189216 }
190- l .addIntermediates (fpRaw )
217+ l .addIssuers (fpRaw )
191218
192219 h := rfc6962 .DefaultHasher .HashLeaf (preimage .BytesOrPanic ())
193220 r = append (r , h )
0 commit comments