Beispiel #1
0
func Fuzz(data []byte) int {
	for _, v := range data {
		if v <= 0x20 || v >= 0x80 {
			return 0
		}
	}
	dec, err := idna.ToUnicode(string(data))
	if err != nil {
		return 0
	}
	enc, err := idna.ToASCII(dec)
	if err != nil {
		fmt.Printf("data: %q\n", data)
		fmt.Printf("dec : %q\n", dec)
		panic(err)
	}
	dec1, err := idna.ToUnicode(enc)
	if err != nil {
		fmt.Printf("data: %q\n", data)
		fmt.Printf("dec : %q\n", dec)
		fmt.Printf("enc : %q\n", enc)
		panic(err)
	}
	if dec != dec1 {
		fmt.Printf("data: %q\n", data)
		fmt.Printf("dec : %q\n", dec)
		fmt.Printf("enc : %q\n", enc)
		fmt.Printf("dec1: %q\n", dec1)
		panic("not equal")
	}
	return 1
}
Beispiel #2
0
// Match returns the length of the ETLD matched, if no match, then 0 is returned.
func Match(s string) int {
	s, err := idna.ToUnicode(strings.ToLower(s))
	if err != nil {
		return 0
	}

	return etldlen(s)
}
Beispiel #3
0
// ReadMetadata reads JSON files for each zone in the metadata directory.
func ReadMetadata(zones map[string]*Zone) (errs []error) {
	dir := filepath.Join(BaseDir, "metadata")
	paths, _ := filepath.Glob(filepath.Join(dir, "*.json"))
	var read int
	for _, path := range paths {
		// Ensure filename equals ASCII/punycode domain name
		base := filepath.Base(path)
		ext := filepath.Ext(base)
		di := strings.TrimSuffix(base, ext)
		d, err := idna.ToUnicode(di)
		if err != nil {
			errs = append(errs, err)
			LogError(err)
			continue
		}

		// Ensure the domain exists in zones.txt
		z, ok := zones[d]
		if !ok {
			err = fmt.Errorf("domain not found in zones.txt: %s", base)
			errs = append(errs, err)
			LogWarning(err)
			continue
		}

		// Parse the JSON metadata
		f, err := os.Open(path)
		if err != nil {
			err = fmt.Errorf("cannot load %s: %s", base, err)
			errs = append(errs, err)
			LogError(err)
			continue
		}
		dec := json.NewDecoder(f)
		err = dec.Decode(z)
		f.Close()
		if err != nil && err != io.EOF {
			err = fmt.Errorf("unable to parse %s: %s", base, err)
			errs = append(errs, err)
			LogError(err)
			continue
		}
		read++

		// Ensure domain name matches
		if z.Domain != d {
			err = fmt.Errorf("domain %s doesn’t match filename (expected %s): %s", z.Domain, z.ASCII(), base)
			errs = append(errs, err)
			LogError(err)
			continue
		}
	}
	color.Fprintf(os.Stderr, "@{.}Read %d metadata files\n", read)
	return
}
Beispiel #4
0
// parseDomain parses the domain part of a jid according to RFC7622
func parseDomain(domain string) string {
	ip := net.ParseIP(domain)
	if ip != nil {
		return ip.String()
	}

	domain, err := idna.ToUnicode(domain)
	if err != nil {
		return ""
	}
	return domain
}
Beispiel #5
0
// decodes IDN names to Unicode and adds it to value
func decodeIDN(field mapper.Field) mapper.Field {
	for _, item := range field.Value {
		idnItem, err := idna.ToUnicode(item)
		if err == nil && idnItem != item {
			field.Value = append(
				field.Value,
				strings.Replace(field.Format, "{idn}", idnItem, 1),
			)
		}
	}
	field.Format = ""
	return field
}
Beispiel #6
0
// Normalize returns normalized URL string.
// Behavior:
// 1. Remove unnecessary host dots.
// 2. Remove default port (http://localhost:80 becomes http://localhost).
// 3. Remove duplicate slashes.
// 4. Remove unnecessary dots from path.
// 5. Sort query parameters.
// 6. Decode host IP into decimal numbers.
// 7. Handle escape values.
// 8. Decode Punycode domains into UTF8 representation.
func Normalize(u *url.URL) (string, error) {
	host, port, err := SplitHostPort(u)
	if err != nil {
		return "", err
	}
	if err := checkHost(host); err != nil {
		return "", err
	}

	// Decode Punycode.
	host, err = idna.ToUnicode(host)
	if err != nil {
		return "", err
	}

	u.Host = strings.ToLower(host)
	if port != "" {
		u.Host += ":" + port
	}
	u.Scheme = strings.ToLower(u.Scheme)

	return purell.NormalizeURL(u, normalizeFlags), nil
}
Beispiel #7
0
// MatchingRules returns a list of the rules that u matches.
// For consistency with phrase matching, it is a map with rules for keys
// and with all values equal to 1.
func (m *URLMatcher) MatchingRules(u *url.URL) map[rule]int {
	result := make(map[rule]int)

	host := strings.ToLower(u.Host)

	// strip off the port number, if present
	colon := strings.LastIndex(host, ":")
	// IPv6 addresses contain colons inside brackets, so be careful.
	if colon != -1 && !strings.Contains(host[colon:], "]") {
		host = host[:colon]
	}

	// Find the main domain name (e.g. "google" in "www.google.com").
	suffix := publicsuffix.List.PublicSuffix(host)
	if suffix != "" && suffix != host {
		domain := host[:len(host)-len(suffix)-1]
		dot := strings.LastIndex(domain, ".")
		if dot != -1 {
			domain = domain[dot+1:]
		}
		if idn, err := idna.ToUnicode(domain); err == nil {
			domain = idn
		}
		m.domainRegexes.findMatches(domain, result)
	}

	if idn, err := idna.ToUnicode(host); err == nil {
		host = idn
	}

	urlString := ""
	if u.Scheme != "" {
		urlString += strings.ToLower(u.Scheme) + ":"
	}
	if host != "" {
		urlString += "//" + host
		m.hostRegexes.findMatches(host, result)
	}

	path := strings.ToLower(u.Path)
	m.pathRegexes.findMatches(path, result)
	urlString += path

	query := strings.ToLower(u.RawQuery)
	if query != "" {
		q, err := url.QueryUnescape(query)
		if err == nil {
			// Change ' ' back to '+'.
			query = strings.Replace(q, " ", "+", -1)
		}
		m.queryRegexes.findMatches(query, result)
		urlString += "?" + query
	}

	m.regexes.findMatches(urlString, result)

	// Test for matches of the host and of the domains it belongs to.
	s := host
	for {
		// Test for matches with the path.
		s2 := s + path
		for {
			if r, ok := m.fragments[s2]; ok {
				result[r] = 1
			}
			slash := strings.LastIndex(s2, "/")
			if slash < 1 {
				// It's either not found, or at the first character.
				break
			}
			s2 = s2[:slash]
		}

		if r, ok := m.fragments[s]; ok {
			result[r] = 1
		}
		dot := strings.Index(s, ".")
		if dot == -1 {
			break
		}
		s = s[dot+1:]
	}

	return result
}
Beispiel #8
0
func (z *Zone) unicodeLabels(domain string) []string {
	prefix, _ := idna.ToUnicode(domain[:len(domain)-len(z.Domain)-1])
	return strings.Split(prefix, ".")
}
Beispiel #9
0
// WillingToIssue determines whether the CA is willing to issue for the provided
// identifier. It expects domains in id to be lowercase to prevent mismatched
// cases breaking queries.
//
// We place several criteria on identifiers we are willing to issue for:
//
//  * MUST self-identify as DNS identifiers
//  * MUST contain only bytes in the DNS hostname character set
//  * MUST NOT have more than maxLabels labels
//  * MUST follow the DNS hostname syntax rules in RFC 1035 and RFC 2181
//    In particular:
//    * MUST NOT contain underscores
//  * MUST NOT contain IDN labels (xn--)
//  * MUST NOT match the syntax of an IP address
//  * MUST end in a public suffix
//  * MUST have at least one label in addition to the public suffix
//  * MUST NOT be a label-wise suffix match for a name on the black list,
//    where comparison is case-independent (normalized to lower case)
//
// If WillingToIssue returns an error, it will be of type MalformedRequestError.
func (pa *AuthorityImpl) WillingToIssue(id core.AcmeIdentifier) error {
	if id.Type != core.IdentifierDNS {
		return errInvalidIdentifier
	}
	domain := id.Value

	if domain == "" {
		return errEmptyName
	}

	for _, ch := range []byte(domain) {
		if !isDNSCharacter(ch) {
			return errInvalidDNSCharacter
		}
	}

	if len(domain) > maxDNSIdentifierLength {
		return errNameTooLong
	}

	if ip := net.ParseIP(domain); ip != nil {
		return errIPAddress
	}

	if strings.HasSuffix(domain, ".") {
		return errNameEndsInDot
	}

	labels := strings.Split(domain, ".")
	if len(labels) > maxLabels {
		return errTooManyLabels
	}
	if len(labels) < 2 {
		return errTooFewLabels
	}
	for _, label := range labels {
		if len(label) < 1 {
			return errLabelTooShort
		}
		if len(label) > maxLabelLength {
			return errLabelTooLong
		}

		if !dnsLabelRegexp.MatchString(label) {
			return errInvalidDNSCharacter
		}

		if label[len(label)-1] == '-' {
			return errInvalidDNSCharacter
		}

		if punycodeRegexp.MatchString(label) {
			if features.Enabled(features.IDNASupport) {
				// We don't care about script usage, if a name is resolvable it was
				// registered with a higher power and they should be enforcing their
				// own policy. As long as it was properly encoded that is enough
				// for us.
				_, err := idna.ToUnicode(label)
				if err != nil {
					return errMalformedIDN
				}
			} else {
				return errIDNNotSupported
			}
		}
	}

	// Names must end in an ICANN TLD, but they must not be equal to an ICANN TLD.
	icannTLD, err := extractDomainIANASuffix(domain)
	if err != nil {
		return errNonPublic
	}
	if icannTLD == domain {
		return errICANNTLD
	}

	// Require no match against blacklist
	if err := pa.checkHostLists(domain); err != nil {
		return err
	}

	return nil
}