]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: use case-insensitive hostname matching.
authorAdam Langley <agl@golang.org>
Tue, 31 Jan 2012 16:00:16 +0000 (11:00 -0500)
committerAdam Langley <agl@golang.org>
Tue, 31 Jan 2012 16:00:16 +0000 (11:00 -0500)
Fixes #2792.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5590045

src/pkg/crypto/x509/verify.go
src/pkg/crypto/x509/verify_test.go

index 50a3b66e55506a66ab9bea45f07eee93235b3918..87b1cb7bb1c35ecad92703a3ace72c3bba19ab05 100644 (file)
@@ -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
        }
 
index 2016858307e275e8ec3f81d6d7be1d9dfd07545b..2cdd66a5589d689531f9e2b2f0f9739867a91dfe 100644 (file)
@@ -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},