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 }