From: Adam Langley Date: Tue, 31 Jan 2012 16:00:16 +0000 (-0500) Subject: crypto/x509: use case-insensitive hostname matching. X-Git-Tag: weekly.2012-02-07~179 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8efb304440474a4c168c30fc07f2787eaf16cfbf;p=gostls13.git crypto/x509: use case-insensitive hostname matching. Fixes #2792. R=golang-dev, r CC=golang-dev https://golang.org/cl/5590045 --- diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go index 50a3b66e55..87b1cb7bb1 100644 --- a/src/pkg/crypto/x509/verify.go +++ b/src/pkg/crypto/x509/verify.go @@ -7,6 +7,7 @@ package x509 import ( "strings" "time" + "unicode/utf8" ) type InvalidReason int @@ -225,17 +226,51 @@ func matchHostnames(pattern, host string) bool { return true } +// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use +// an explicitly ASCII function to avoid any sharp corners resulting from +// performing Unicode operations on DNS labels. +func toLowerCaseASCII(in string) string { + // If the string is already lower-case then there's nothing to do. + isAlreadyLowerCase := true + for _, c := range in { + if c == utf8.RuneError { + // If we get a UTF-8 error then there might be + // upper-case ASCII bytes in the invalid sequence. + isAlreadyLowerCase = false + break + } + if 'A' <= c && c <= 'Z' { + isAlreadyLowerCase = false + break + } + } + + if isAlreadyLowerCase { + return in + } + + out := []byte(in) + for i, c := range out { + if 'A' <= c && c <= 'Z' { + out[i] += 'a' - 'A' + } + } + return string(out) +} + // VerifyHostname returns nil if c is a valid certificate for the named host. // Otherwise it returns an error describing the mismatch. func (c *Certificate) VerifyHostname(h string) error { + lowered := toLowerCaseASCII(h) + if len(c.DNSNames) > 0 { for _, match := range c.DNSNames { - if matchHostnames(match, h) { + if matchHostnames(toLowerCaseASCII(match), lowered) { return nil } } // If Subject Alt Name is given, we ignore the common name. - } else if matchHostnames(c.Subject.CommonName, h) { + } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) { return nil } diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go index 2016858307..2cdd66a558 100644 --- a/src/pkg/crypto/x509/verify_test.go +++ b/src/pkg/crypto/x509/verify_test.go @@ -37,6 +37,17 @@ var verifyTests = []verifyTest{ {"Google", "Thawte", "VeriSign"}, }, }, + { + leaf: googleLeaf, + intermediates: []string{thawteIntermediate}, + roots: []string{verisignRoot}, + currentTime: 1302726541, + dnsName: "WwW.GooGLE.coM", + + expectedChains: [][]string{ + {"Google", "Thawte", "VeriSign"}, + }, + }, { leaf: googleLeaf, intermediates: []string{thawteIntermediate},