Cache issuer certificates retrieved from static-ct-api logs

This commit is contained in:
Andrew Ayer 2025-05-06 14:19:25 -04:00
parent 958e7a9efb
commit 6151cb26da
4 changed files with 48 additions and 10 deletions

View File

@ -93,6 +93,23 @@ func (s *FilesystemState) RemoveSTH(ctx context.Context, logID LogID, sth *cttyp
return removeSTHFromDir(sthsDirPath, sth)
}
func (s *FilesystemState) StoreIssuer(ctx context.Context, fingerprint *[32]byte, issuer []byte) error {
filePath := filepath.Join(s.StateDir, "issuers", hex.EncodeToString(fingerprint[:]))
return writeFile(filePath, issuer, 0666)
}
func (s *FilesystemState) LoadIssuer(ctx context.Context, fingerprint *[32]byte) ([]byte, error) {
filePath := filepath.Join(s.StateDir, "issuers", hex.EncodeToString(fingerprint[:]))
issuer, err := os.ReadFile(filePath)
if errors.Is(err, fs.ErrNotExist) {
return nil, nil
} else if err != nil {
return nil, err
} else {
return issuer, err
}
}
func (s *FilesystemState) NotifyCert(ctx context.Context, cert *DiscoveredCert) error {
var notifiedPath string
var paths *certPaths

View File

@ -142,22 +142,34 @@ func (client *logClient) ReconstructTree(ctx context.Context, sth *cttypes.Signe
}
type issuerGetter struct {
state StateProvider
logGetter ctclient.IssuerGetter
}
func (ig *issuerGetter) GetIssuer(ctx context.Context, fingerprint *[32]byte) (issuer []byte, err error) {
// TODO-2 check cache
err = withRetry(ctx, 7, func() error {
issuer, err = ig.logGetter.GetIssuer(ctx, fingerprint)
return err
})
if err == nil {
// TODO-2 insert into cache
}
return
func (ig *issuerGetter) GetIssuer(ctx context.Context, fingerprint *[32]byte) ([]byte, error) {
if issuer, err := ig.state.LoadIssuer(ctx, fingerprint); err != nil {
log.Printf("error loading cached issuer %x (issuer will be retrieved from log instead): %s", *fingerprint, err)
} else if issuer != nil {
return issuer, nil
}
func newLogClient(ctlog *loglist.Log) (ctclient.Log, ctclient.IssuerGetter, error) {
var issuer []byte
if err := withRetry(ctx, 7, func() error {
var err error
issuer, err = ig.logGetter.GetIssuer(ctx, fingerprint)
return err
}); err != nil {
return nil, err
}
if err := ig.state.StoreIssuer(ctx, fingerprint, issuer); err != nil {
log.Printf("error caching issuer %x (issuer will be re-retrieved from log in the future): %s", *fingerprint, err)
}
return issuer, nil
}
func newLogClient(config *Config, ctlog *loglist.Log) (ctclient.Log, ctclient.IssuerGetter, error) {
switch {
case ctlog.IsRFC6962():
logURL, err := url.Parse(ctlog.URL)
@ -186,6 +198,7 @@ func newLogClient(ctlog *loglist.Log) (ctclient.Log, ctclient.IssuerGetter, erro
log: ctlog,
client: client,
}, &issuerGetter{
state: config.State,
logGetter: client,
}, nil
default:
@ -194,7 +207,7 @@ func newLogClient(ctlog *loglist.Log) (ctclient.Log, ctclient.IssuerGetter, erro
}
func monitorLogContinously(ctx context.Context, config *Config, ctlog *loglist.Log) (returnedErr error) {
client, issuerGetter, err := newLogClient(ctlog)
client, issuerGetter, err := newLogClient(config, ctlog)
if err != nil {
return err
}

View File

@ -63,6 +63,14 @@ type StateProvider interface {
// Remove an STH so it is no longer returned by LoadSTHs.
RemoveSTH(context.Context, LogID, *cttypes.SignedTreeHead) error
// Store a DER-encoded issuer certificate with the given fingerprint for
// retrieval by LoadIssuer. Returns nil if the issuer has already been stored.
StoreIssuer(context.Context, *[32]byte, []byte) error
// Retrieve a DER-encoded issuer certificate previously stored with StoreIssuer.
// Returns nil, nil if this issuer certificate has not been stored.
LoadIssuer(context.Context, *[32]byte) ([]byte, error)
// Called when a certificate matching the watch list is discovered.
NotifyCert(context.Context, *DiscoveredCert) error

View File

@ -145,7 +145,7 @@ func prepareStateDir(stateDir string) error {
return fmt.Errorf("%s was created by a newer version of certspotter; upgrade to the latest version of certspotter or remove this directory to start from scratch", stateDir)
}
for _, subdir := range []string{"certs", "logs", "healthchecks"} {
for _, subdir := range []string{"certs", "logs", "healthchecks", "issuers"} {
if err := os.Mkdir(filepath.Join(stateDir, subdir), 0777); err != nil && !errors.Is(err, fs.ErrExist) {
return err
}