Skip to content

Commit 8b61ef9

Browse files
committed
cmd/age-keylookup: check checkpoint freshness in monitor mode
1 parent e5b50fa commit 8b61ef9

3 files changed

Lines changed: 22 additions & 4 deletions

File tree

cmd/age-keylookup/main.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,26 @@ func monitorLog(serverURL string, policy torchwood.Policy, vrfKey *vrf.PublicKey
243243
if err != nil {
244244
return nil, fmt.Errorf("failed to read checkpoint: %w", err)
245245
}
246-
checkpoint, _, err := torchwood.VerifyCheckpoint(signedCheckpoint, policy)
246+
checkpoint, n, err := torchwood.VerifyCheckpoint(signedCheckpoint, policy)
247247
if err != nil {
248248
return nil, fmt.Errorf("failed to parse checkpoint: %w", err)
249249
}
250250

251+
// Check the checkpoint is fresh
252+
for _, sig := range n.Sigs {
253+
if sig.Name == checkpoint.Origin {
254+
// The log's signature doesn't include a timestamp, for legacy reasons.
255+
continue
256+
}
257+
t, err := torchwood.CosignatureTimestamp(sig)
258+
if err != nil {
259+
return nil, fmt.Errorf("failed to extract cosignature %q timestamp: %w", sig.Name, err)
260+
}
261+
if time.Since(time.Unix(t, 0)) > 6*time.Hour {
262+
return nil, fmt.Errorf("checkpoint cosignature %q is too old", sig.Name)
263+
}
264+
}
265+
251266
// Fetch all entries up to the checkpoint size
252267
var pubkeys []string
253268
for i, entry := range c.AllEntries(context.Background(), checkpoint.Tree, 0) {

cmd/age-keyserver/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func main() {
129129
// remove integration latency for the first request. Keep a 1s checkpoint
130130
// interval not to hit the witnesses too often; this will be observed only
131131
// if two requests come in quick succession. Finally, only publish a
132-
// checkpoint once a day if there are no new entries, making the average qps
132+
// checkpoint every hour if there are no new entries, making the average qps
133133
// on witnesses low. Poll for new checkpoints quickly since it should be
134134
// just a read from a hot filesystem cache.
135135
checkpointInterval := 1 * time.Second
@@ -140,7 +140,7 @@ func main() {
140140
WithCheckpointSigner(s).
141141
WithBatching(1, tessera.DefaultBatchMaxAge).
142142
WithCheckpointInterval(checkpointInterval).
143-
WithCheckpointRepublishInterval(24*time.Hour).
143+
WithCheckpointRepublishInterval(1*time.Hour).
144144
WithWitnesses(witnesses, nil))
145145
if err != nil {
146146
log.Fatalln("failed to create log appender:", err)

cosignature.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,10 @@ func keyHash(name string, key []byte) uint32 {
180180
}
181181

182182
// CosignatureTimestamp returns the timestamp of the cosignature, which is the
183-
// time at which the witness signed the checkpoint.
183+
// time at which the witness signed the checkpoint, in seconds since the Unix epoch.
184+
//
185+
// Witnesses can re-sign a checkpoint, but only if it's for the latest tree they
186+
// have seen. Thus, the timestamp can be used to determine if a checkpoint is fresh.
184187
func CosignatureTimestamp(sig note.Signature) (int64, error) {
185188
sigBytes, err := base64.StdEncoding.DecodeString(sig.Base64)
186189
if err != nil {

0 commit comments

Comments
 (0)