From e18d36ebae30536c77c61cd5da123991e0ca1629 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Sun, 31 Dec 2023 09:39:25 +0100 Subject: Add drafty prototype --- pkg/storage/index/inmem.go | 113 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 pkg/storage/index/inmem.go (limited to 'pkg/storage/index/inmem.go') diff --git a/pkg/storage/index/inmem.go b/pkg/storage/index/inmem.go new file mode 100644 index 0000000..0a084bf --- /dev/null +++ b/pkg/storage/index/inmem.go @@ -0,0 +1,113 @@ +package index + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/google/certificate-transparency-go/x509" + "rgdd.se/silent-ct/pkg/crtutil" +) + +type CertificateID string + +func (crtID *CertificateID) Set(crt x509.Certificate) { + *crtID = CertificateID(crtutil.UniqueID(crt)) +} + +type CertificateInfo struct { + ObservedAt time.Time `json:"observed_at"` + StoredAt string `json:"stored_at"` +} + +// index is an in-memory index of certificates +type index struct { + Alerting map[CertificateID][]CertificateInfo `json:"alerting"` // Certificates that were not marked as "good" on time + Legitimate map[CertificateID][]CertificateInfo `json:"legitimate"` // Certificates that are considered "good" + Pending map[CertificateID][]CertificateInfo `json:"pending"` // Certificates that have yet to be marked as "good" +} + +func newIndex() index { + return index{ + Alerting: make(map[CertificateID][]CertificateInfo), + Legitimate: make(map[CertificateID][]CertificateInfo), + Pending: make(map[CertificateID][]CertificateInfo), + } +} + +func (ix *index) JSONUnmarshal(b []byte) error { + type internal index + if err := json.Unmarshal(b, (*internal)(ix)); err != nil { + return err + } + for i, m := range []map[CertificateID][]CertificateInfo{ix.Alerting, ix.Legitimate, ix.Pending} { + if m == nil { + return fmt.Errorf("dictionary named %q is not in the index", []string{"alerting", "legitimate", "pending"}[i]) + } + } + return nil +} + +func (ix *index) triggerAlerts(delay time.Duration) []CertificateInfo { + var alerts []CertificateInfo + + for key, certInfos := range ix.Pending { + certInfo := certInfos[0] + if time.Since(certInfo.ObservedAt) < delay { + continue + } + + alerts = append(alerts, certInfo) + ix.Alerting[key] = certInfos + delete(ix.Pending, key) + } + + return alerts +} + +func (ix *index) addChain(crtID CertificateID, path string) bool { + if _, ok := ix.Legitimate[crtID]; ok { + return false // we already marked this certificate as "good" + } + + entry := CertificateInfo{ObservedAt: time.Now(), StoredAt: path} + crtInfos := []CertificateInfo{entry} + if v, ok := ix.Alerting[crtID]; ok { + crtInfos = append(crtInfos, v...) + delete(ix.Alerting, crtID) // no longer alerting + } else if v, ok := ix.Pending[crtID]; ok { + crtInfos = append(crtInfos, v...) + delete(ix.Pending, crtID) // no longer pending + } + + ix.Legitimate[crtID] = crtInfos + return true // index updated such that this certificate is marked as "good" +} + +func (ix *index) addEntry(crtID CertificateID, path string) bool { + crtInfo := CertificateInfo{ObservedAt: time.Now(), StoredAt: path} + if _, ok := ix.Legitimate[crtID]; ok { + return add(ix.Legitimate, crtID, crtInfo) + } else if _, ok := ix.Alerting[crtID]; ok { + return add(ix.Alerting, crtID, crtInfo) + } + return add(ix.Pending, crtID, crtInfo) +} + +func add(m map[CertificateID][]CertificateInfo, key CertificateID, value CertificateInfo) bool { + crtInfos, ok := m[key] + if !ok { + m[key] = []CertificateInfo{value} + return true + } + + for _, crtInfo := range crtInfos { + if value.StoredAt == crtInfo.StoredAt { + return false // duplicate + } + } + + crtInfos = append(crtInfos, value) + m[key] = crtInfos + return true +} -- cgit v1.2.3