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
|
package monitor
import (
"fmt"
"strings"
ct "github.com/google/certificate-transparency-go"
)
type Matcher interface {
Match(leafInput, extraData []byte) (bool, error)
}
// MatchAll matches all certificates
type MatchAll struct{}
func (m *MatchAll) Match(leafInput, extraData []byte) (bool, error) {
return true, nil
}
// MatchWildcards matches a list of wildcards, see the MatchWildcard type
type MatchWildcards []MatchWildcard
func (m *MatchWildcards) Match(leafInput, extraData []byte) (bool, error) {
sans, err := getSANs(ct.LeafEntry{LeafInput: leafInput, ExtraData: extraData})
if err != nil {
return false, err
}
return m.match(sans), nil
}
func (m *MatchWildcards) match(sans []string) bool {
for _, mw := range (*m)[:] {
if mw.match(sans) {
return true
}
}
return false
}
// MatchWildcard exclude matches for `.*<Exclude>\.<Wildcard>`, but will
// otherwise match on any `.*\.<Wildcard>` as well as SANs equal to <Wildcard>.
//
// For example, let <Wildcard> be example.org and Exclude be [foo, bar]. Then
// example.org and www.example.org would match, whereas foo.example.org,
// sub.foo.example.org, and bar.example.org. would not match.
type MatchWildcard struct {
Wildcard string `json:"wildcard"`
Excludes []string `json:"excludes"`
}
func (m *MatchWildcard) match(sans []string) bool {
for _, san := range sans {
if san == m.Wildcard {
return true
}
if strings.HasSuffix(san, "."+m.Wildcard) && !m.exclude(san) {
return true
}
}
return false
}
func (m *MatchWildcard) exclude(san string) bool {
for _, exclude := range m.Excludes {
suffix := exclude + "." + m.Wildcard
if strings.HasSuffix(san, suffix) {
return true
}
}
return false
}
func getSANs(entry ct.LeafEntry) ([]string, error) {
// Warning: here be dragons, parsing of DNS names in certificates...
e, err := ct.LogEntryFromLeaf(0, &entry)
if err != nil {
return nil, fmt.Errorf("parse leaf: %v", err)
}
if e.Precert == nil && e.X509Cert == nil {
return nil, fmt.Errorf("neither precertificate nor certificate in leaf")
}
if e.Precert != nil && e.X509Cert != nil {
return nil, fmt.Errorf("both certificate and precertificate in leaf")
}
if e.Precert != nil {
return e.Precert.TBSCertificate.DNSNames, nil
}
return e.X509Cert.DNSNames, nil
}
|