acme/autocert: support configurable CSR extensions

Package users can now provide extra CSR extensions
to serve certificates with desired properties.

Fixes golang/go#17801.
Change-Id: Iac1010f41391c865f6e318bad2e0dafc2ffef6b1
Reviewed-on: https://go-review.googlesource.com/42470
Reviewed-by: Adam Langley <agl@golang.org>
Run-TryBot: Adam Langley <agl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/acme/autocert/autocert.go b/acme/autocert/autocert.go
index 97281d8..95c3928 100644
--- a/acme/autocert/autocert.go
+++ b/acme/autocert/autocert.go
@@ -146,6 +146,15 @@
 	// is EC-based keys using the P-256 curve.
 	ForceRSA bool
 
+	// ExtraExtensions are used when generating a new CSR (Certificate Request),
+	// thus allowing customization of the resulting certificate.
+	// For instance, TLS Feature Extension (RFC 7633) can be used
+	// to prevent an OCSP downgrade attack.
+	//
+	// The field value is passed to crypto/x509.CreateCertificateRequest
+	// in the template's ExtraExtensions field as is.
+	ExtraExtensions []pkix.Extension
+
 	clientMu sync.Mutex
 	client   *acme.Client // initialized by acmeClient method
 
@@ -527,7 +536,7 @@
 	if err := m.verify(ctx, client, domain); err != nil {
 		return nil, nil, err
 	}
-	csr, err := certRequest(key, domain)
+	csr, err := certRequest(key, domain, m.ExtraExtensions)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -870,12 +879,12 @@
 	}, nil
 }
 
-// certRequest creates a certificate request for the given common name cn
-// and optional SANs.
-func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) {
+// certRequest generates a CSR for the given common name cn and optional SANs.
+func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) {
 	req := &x509.CertificateRequest{
-		Subject:  pkix.Name{CommonName: cn},
-		DNSNames: san,
+		Subject:         pkix.Name{CommonName: cn},
+		DNSNames:        san,
+		ExtraExtensions: ext,
 	}
 	return x509.CreateCertificateRequest(rand.Reader, req, key)
 }
diff --git a/acme/autocert/autocert_test.go b/acme/autocert/autocert_test.go
index 54d38e2..8549082 100644
--- a/acme/autocert/autocert_test.go
+++ b/acme/autocert/autocert_test.go
@@ -14,6 +14,7 @@
 	"crypto/tls"
 	"crypto/x509"
 	"crypto/x509/pkix"
+	"encoding/asn1"
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
@@ -854,3 +855,33 @@
 		}
 	}
 }
+
+func TestCertRequest(t *testing.T) {
+	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// An extension from RFC7633. Any will do.
+	ext := pkix.Extension{
+		Id:    asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1},
+		Value: []byte("dummy"),
+	}
+	b, err := certRequest(key, "example.org", []pkix.Extension{ext}, "san.example.org")
+	if err != nil {
+		t.Fatalf("certRequest: %v", err)
+	}
+	r, err := x509.ParseCertificateRequest(b)
+	if err != nil {
+		t.Fatalf("ParseCertificateRequest: %v", err)
+	}
+	var found bool
+	for _, v := range r.Extensions {
+		if v.Id.Equal(ext.Id) {
+			found = true
+			break
+		}
+	}
+	if !found {
+		t.Errorf("want %v in Extensions: %v", ext, r.Extensions)
+	}
+}