mirror of
				https://github.com/SSLMate/certspotter.git
				synced 2025-07-03 10:47:17 +02:00 
			
		
		
		
	Support crazy wildcards (not just in the left-most label)
This commit is contained in:
		
							parent
							
								
									e99ee481a4
								
							
						
					
					
						commit
						92fbdcb947
					
				@ -40,19 +40,12 @@ func trimTrailingDots (value string) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var stateDir = flag.String("state_dir", DefaultStateDir(), "Directory for storing state")
 | 
			
		||||
var watchDomains []string
 | 
			
		||||
var watchDomainSuffixes []string
 | 
			
		||||
 | 
			
		||||
func addWatchDomain (asciiDomain string) {
 | 
			
		||||
	watchDomains = append(watchDomains, asciiDomain)
 | 
			
		||||
	watchDomainSuffixes = append(watchDomainSuffixes, "." + asciiDomain)
 | 
			
		||||
}
 | 
			
		||||
var watchDomains [][]string
 | 
			
		||||
 | 
			
		||||
func setWatchDomains (domains []string) error {
 | 
			
		||||
	for _, domain := range domains {
 | 
			
		||||
		if domain == "." { // "." as in root zone (matches everything)
 | 
			
		||||
			watchDomains = []string{}
 | 
			
		||||
			watchDomainSuffixes = []string{""}
 | 
			
		||||
			watchDomains = [][]string{[]string{}}
 | 
			
		||||
			break
 | 
			
		||||
		} else {
 | 
			
		||||
			asciiDomain, err := idna.ToASCII(strings.ToLower(trimTrailingDots(domain)))
 | 
			
		||||
@ -60,44 +53,52 @@ func setWatchDomains (domains []string) error {
 | 
			
		||||
				return fmt.Errorf("Invalid domain `%s': %s", domain, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			addWatchDomain(asciiDomain)
 | 
			
		||||
 | 
			
		||||
			// Also monitor DNS names that _might_ match this domain (wildcards,
 | 
			
		||||
			// label redactions, and unparseable labels).
 | 
			
		||||
			// For example, if we're monitoring sub.example.com, also monitor:
 | 
			
		||||
			//   *.example.com
 | 
			
		||||
			//   ?.example.com
 | 
			
		||||
			//   <unparsable>.example.com
 | 
			
		||||
			// TODO: support for wildcards that are not the entire label (e.g. ac-*.fr)
 | 
			
		||||
			var parentDomain string
 | 
			
		||||
			if dot := strings.IndexRune(asciiDomain, '.'); dot != -1 {
 | 
			
		||||
				parentDomain = asciiDomain[dot:]
 | 
			
		||||
			}
 | 
			
		||||
			addWatchDomain("*" + parentDomain)
 | 
			
		||||
			addWatchDomain("?" + parentDomain)
 | 
			
		||||
			addWatchDomain(certspotter.UnparsableDNSLabelPlaceholder + parentDomain)
 | 
			
		||||
			watchDomains = append(watchDomains, strings.Split(asciiDomain, "."))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dnsNameMatches (dnsName string) bool {
 | 
			
		||||
	for _, domain := range watchDomains {
 | 
			
		||||
		if dnsName == domain {
 | 
			
		||||
			return true
 | 
			
		||||
func dnsLabelMatches (certLabel string, watchLabel string) bool {
 | 
			
		||||
	// For fail-safe behavior, if a label was unparsable, it matches everything.
 | 
			
		||||
	// Similarly, redacted labels match everything, since the label _might_ be
 | 
			
		||||
	// for a name we're interested in.
 | 
			
		||||
 | 
			
		||||
	return certLabel == "*" ||
 | 
			
		||||
	       certLabel == "?" ||
 | 
			
		||||
	       certLabel == certspotter.UnparsableDNSLabelPlaceholder ||
 | 
			
		||||
	       certspotter.MatchWildcard(certLabel, watchLabel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dnsNameMatches (dnsName []string, watchDomain []string) bool {
 | 
			
		||||
	for len(dnsName) > 0 && len(watchDomain) > 0 {
 | 
			
		||||
		certLabel := dnsName[len(dnsName)-1]
 | 
			
		||||
		watchLabel := watchDomain[len(watchDomain)-1]
 | 
			
		||||
 | 
			
		||||
		if !dnsLabelMatches(certLabel, watchLabel) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dnsName = dnsName[:len(dnsName)-1]
 | 
			
		||||
		watchDomain = watchDomain[:len(watchDomain)-1]
 | 
			
		||||
	}
 | 
			
		||||
	for _, domainSuffix := range watchDomainSuffixes {
 | 
			
		||||
		if strings.HasSuffix(dnsName, domainSuffix) {
 | 
			
		||||
 | 
			
		||||
	return len(watchDomain) == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dnsNameIsWatched (dnsName string) bool {
 | 
			
		||||
	labels := strings.Split(dnsName, ".")
 | 
			
		||||
	for _, watchDomain := range watchDomains {
 | 
			
		||||
		if dnsNameMatches(labels, watchDomain) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func anyDnsNameMatches (dnsNames []string) bool {
 | 
			
		||||
func anyDnsNameIsWatched (dnsNames []string) bool {
 | 
			
		||||
	for _, dnsName := range dnsNames {
 | 
			
		||||
		if dnsNameMatches(dnsName) {
 | 
			
		||||
		if dnsNameIsWatched(dnsName) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -122,7 +123,7 @@ func processEntry (scanner *certspotter.Scanner, entry *ct.LogEntry) {
 | 
			
		||||
	// parse error), report the certificate because we can't say for sure it
 | 
			
		||||
	// doesn't match a domain we care about.  We try very hard to make sure
 | 
			
		||||
	// parsing identifiers always succeeds, so false alarms should be rare.
 | 
			
		||||
	if info.Identifiers == nil || anyDnsNameMatches(info.Identifiers.DNSNames) {
 | 
			
		||||
	if info.Identifiers == nil || anyDnsNameIsWatched(info.Identifiers.DNSNames) {
 | 
			
		||||
		cmd.LogEntry(&info)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								helpers.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								helpers.go
									
									
									
									
									
								
							@ -399,3 +399,21 @@ func WriteCertRepository (repoPath string, isPrecert bool, certs [][]byte) (bool
 | 
			
		||||
 | 
			
		||||
	return false, path, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func MatchWildcard (pattern string, dnsName string) bool {
 | 
			
		||||
	for len(pattern) > 0 {
 | 
			
		||||
		if pattern[0] == '*' {
 | 
			
		||||
			if len(dnsName) > 0 && dnsName[0] != '.' && MatchWildcard(pattern, dnsName[1:]) {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
			pattern = pattern[1:]
 | 
			
		||||
		} else {
 | 
			
		||||
			if len(dnsName) == 0 || pattern[0] != dnsName[0] {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
			pattern = pattern[1:]
 | 
			
		||||
			dnsName = dnsName[1:]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return len(dnsName) == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user