acme/autocert: remove trailing dot from domain before requesting cert

Browsers can send an SNI name of "example.com." for
https://example.com./ but LetsEncrypt rejects the trailing dot.

Fixes golang/go#18114

Change-Id: Ie38e355e5b5566a7eb18f77a2449660e22e21b4c
Reviewed-on: https://go-review.googlesource.com/33711
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/acme/autocert/autocert.go b/acme/autocert/autocert.go
index 12c9010..877bfba 100644
--- a/acme/autocert/autocert.go
+++ b/acme/autocert/autocert.go
@@ -187,6 +187,7 @@
 	}
 
 	// regular domain
+	name = strings.TrimSuffix(name, ".") // golang.org/issue/18114
 	cert, err := m.cert(name)
 	if err == nil {
 		return cert, nil
diff --git a/acme/autocert/autocert_test.go b/acme/autocert/autocert_test.go
index 3a9daa1..295f702 100644
--- a/acme/autocert/autocert_test.go
+++ b/acme/autocert/autocert_test.go
@@ -108,6 +108,14 @@
 }
 
 func TestGetCertificate(t *testing.T) {
+	testGetCertificate(t, false)
+}
+
+func TestGetCertificate_trailingDot(t *testing.T) {
+	testGetCertificate(t, true)
+}
+
+func testGetCertificate(t *testing.T, trailingDot bool) {
 	const domain = "example.org"
 	man := &Manager{Prompt: AcceptTOS}
 	defer man.stopRenew()
@@ -167,6 +175,9 @@
 			if err != nil {
 				t.Fatalf("new-cert: CSR: %v", err)
 			}
+			if csr.Subject.CommonName != domain {
+				t.Errorf("CommonName in CSR = %q; want %q", csr.Subject.CommonName, domain)
+			}
 			der, err := dummyCert(csr.PublicKey, domain)
 			if err != nil {
 				t.Fatalf("new-cert: dummyCert: %v", err)
@@ -201,11 +212,14 @@
 	// simulate tls.Config.GetCertificate
 	var tlscert *tls.Certificate
 	done := make(chan struct{})
-	go func() {
-		hello := &tls.ClientHelloInfo{ServerName: domain}
+	go func(serverName string) {
+		if trailingDot {
+			serverName += "."
+		}
+		hello := &tls.ClientHelloInfo{ServerName: serverName}
 		tlscert, err = man.GetCertificate(hello)
 		close(done)
-	}()
+	}(domain)
 	select {
 	case <-time.After(time.Minute):
 		t.Fatal("man.GetCertificate took too long to return")