From dc192e97ad2d04fffdf13ac9206de3b6027141ca Mon Sep 17 00:00:00 2001 From: Al Cutter Date: Thu, 11 Apr 2024 13:24:26 +0100 Subject: [PATCH] Add time extraction --- note/note_rfc6962.go | 15 +++++++++++++++ note/note_rfc6962_test.go | 11 ++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/note/note_rfc6962.go b/note/note_rfc6962.go index 8a2cd85..59c8aa3 100644 --- a/note/note_rfc6962.go +++ b/note/note_rfc6962.go @@ -27,6 +27,7 @@ import ( "fmt" "strconv" "strings" + "time" ct "github.com/google/certificate-transparency-go" "golang.org/x/mod/sumdb/note" @@ -112,6 +113,20 @@ func RFC6962STHToCheckpoint(j []byte, v note.Verifier) ([]byte, error) { return n, nil } +// RFC6962STHTimestamp extracts the embedded timestamp from a translated RFC6962 STH signature. +func RFC6962STHTimestamp(s note.Signature) (time.Time, error) { + r, err := base64.StdEncoding.DecodeString(s.Base64) + if err != nil { + return time.UnixMilli(0), errMalformedSig + } + if len(r) <= keyHashSize+timestampSize { + return time.UnixMilli(0), errVerifierAlg + } + r = r[keyHashSize:] // Skip the hash + // Next 8 bytes are the timestamp as Unix millis-since-epoch: + return time.Unix(0, int64(binary.BigEndian.Uint64(r)*1000)), nil +} + func rfc6962Keyhash(name string, logID [32]byte) uint32 { h := sha256.New() h.Write([]byte(name)) diff --git a/note/note_rfc6962_test.go b/note/note_rfc6962_test.go index f35976a..5877fc9 100644 --- a/note/note_rfc6962_test.go +++ b/note/note_rfc6962_test.go @@ -21,6 +21,7 @@ import ( "strconv" "strings" "testing" + "time" "golang.org/x/mod/sumdb/note" ) @@ -110,7 +111,6 @@ func TestVerify(t *testing.T) { if gotErr := err != nil; gotErr != test.wantErr { t.Fatalf("Got err %q, want err %t", err, test.wantErr) } - t.Logf("%v", n) }) } @@ -172,6 +172,15 @@ func TestRFC6962STHToCheckpoint(t *testing.T) { if got, want := lines[2], base64.StdEncoding.EncodeToString(sth.SHA256RootHash); got != want { t.Errorf("Got roothash %q, want %q", got, want) } + + ts, err := RFC6962STHTimestamp(n.Sigs[0]) + if err != nil { + t.Fatalf("RFC6962STHTimestamp: %v", err) + } + if got, want := ts, time.Unix(0, int64(sth.Timestamp*1000)); got != want { + t.Fatalf("Got %v, want %v", got, want) + } + }) } }