Only replace DNS label with placeholder if it's utterly unparsable

e.g. contains control characters, Punycode conversion fails

There are quite simply too many certs with bogus DNS labels out in the wild,
and it just doesn't make sense to bother every .com domain holder because
GoDaddy signed a cert with a DNS name like "www.        just4funpartyrentals.com"
It is highly unlikely any validator will ever match that DNS name.
This commit is contained in:
Andrew Ayer 2016-05-04 11:43:02 -07:00
parent 60636ba2d7
commit ea3db97486
2 changed files with 19 additions and 25 deletions

View File

@ -58,14 +58,15 @@ func setWatchDomains (domains []string) error {
// For example, if we're monitoring sub.example.com, also monitor: // For example, if we're monitoring sub.example.com, also monitor:
// *.example.com // *.example.com
// ?.example.com // ?.example.com
// <invalid>.example.com // <unparsable>.example.com
// TODO: support for wildcards that are not the entire label (e.g. ac-*.fr)
var parentDomain string var parentDomain string
if dot := strings.IndexRune(asciiDomain, '.'); dot != -1 { if dot := strings.IndexRune(asciiDomain, '.'); dot != -1 {
parentDomain = asciiDomain[dot:] parentDomain = asciiDomain[dot:]
} }
addWatchDomain("*" + parentDomain) addWatchDomain("*" + parentDomain)
addWatchDomain("?" + parentDomain) addWatchDomain("?" + parentDomain)
addWatchDomain(ctwatch.InvalidDNSLabelPlaceholder + parentDomain) addWatchDomain(ctwatch.UnparsableDNSLabelPlaceholder + parentDomain)
} }
} }
return nil return nil

View File

@ -8,7 +8,7 @@ import (
"golang.org/x/net/idna" "golang.org/x/net/idna"
) )
const InvalidDNSLabelPlaceholder = "<invalid>" const UnparsableDNSLabelPlaceholder = "<unparsable>"
/* /*
const ( const (
@ -61,25 +61,14 @@ func latin1ToUTF8 (value []byte) string {
return string(runes) return string(runes)
} }
// Validate a DNS label. We are less strict than we could be, // Make sure the DNS label doesn't have any weird characters that
// because the main purpose of this is to prevent nasty characters // could cause trouble during later processing.
// from getting through that could cause headaches later (e.g. NUL, func isSaneDNSLabelChar (ch rune) bool {
// control characters). In particular, we allow '_' (since it's return ch == '\t' || (ch >= 32 && ch <= 126)
// quite common in hostnames despite being prohibited), '*' (since
// it's used to represent wildcards), and '?' (since it's used
// in CT to represent redacted labels).
func isValidDNSLabelChar (ch rune) bool {
return (ch >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z') ||
(ch >= '0' && ch <= '9') ||
ch == '-' || ch == '_';
} }
func isValidDNSLabel (label string) bool { func isSaneDNSLabel (label string) bool {
if label == "*" || label == "?" {
return true
}
for _, ch := range label { for _, ch := range label {
if !isValidDNSLabelChar(ch) { if !isSaneDNSLabelChar(ch) {
return false return false
} }
} }
@ -114,13 +103,17 @@ func trimTrailingDots (value string) string {
return value[0:length] return value[0:length]
} }
// Convert the DNS name to lower case and replace invalid labels with a placeholder // Try to canonicalize/sanitize the DNS name:
// 1. Trim leading and trailing whitespace
// 2. Trim trailing dots
// 3. Convert to lower case
// 4. Replace totally nonsensical labels (e.g. having non-printable characters) with a placeholder
func sanitizeDNSName (value string) string { func sanitizeDNSName (value string) string {
value = strings.ToLower(trimTrailingDots(strings.TrimSpace(value))) value = strings.ToLower(trimTrailingDots(strings.TrimSpace(value)))
labels := strings.Split(value, ".") labels := strings.Split(value, ".")
for i, label := range labels { for i, label := range labels {
if !isValidDNSLabel(label) { if !isSaneDNSLabel(label) {
labels[i] = InvalidDNSLabelPlaceholder labels[i] = UnparsableDNSLabelPlaceholder
} }
} }
return strings.Join(labels, ".") return strings.Join(labels, ".")
@ -131,10 +124,10 @@ func sanitizeUnicodeDNSName (value string) string {
value = strings.ToLower(trimTrailingDots(strings.TrimSpace(value))) value = strings.ToLower(trimTrailingDots(strings.TrimSpace(value)))
labels := strings.Split(value, ".") labels := strings.Split(value, ".")
for i, label := range labels { for i, label := range labels {
if asciiLabel, err := idna.ToASCII(label); err == nil && isValidDNSLabel(asciiLabel) { if asciiLabel, err := idna.ToASCII(label); err == nil && isSaneDNSLabel(asciiLabel) {
labels[i] = asciiLabel labels[i] = asciiLabel
} else { } else {
labels[i] = InvalidDNSLabelPlaceholder labels[i] = UnparsableDNSLabelPlaceholder
} }
} }
return strings.Join(labels, ".") return strings.Join(labels, ".")