1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
package index
import (
"encoding/json"
"fmt"
"time"
"github.com/google/certificate-transparency-go/x509"
"rgdd.se/silentct/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
}
|