From 895d5fea41177e444c18f4fdc820fffa5f67d5bf Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Sat, 9 Dec 2023 17:08:45 +0100 Subject: Add drafty skeleton --- pkg/monitor/matcher.go | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 pkg/monitor/matcher.go (limited to 'pkg/monitor/matcher.go') diff --git a/pkg/monitor/matcher.go b/pkg/monitor/matcher.go new file mode 100644 index 0000000..fa3a894 --- /dev/null +++ b/pkg/monitor/matcher.go @@ -0,0 +1,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 `.*\.`, but will +// otherwise match on any `.*\.` as well as SANs equal to . +// +// For example, let 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 +} -- cgit v1.2.3