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>
This commit is contained in:
Alex Vaghin
2018-05-25 16:01:59 +00:00
parent 159ae71589
commit a3beeb7486
2 changed files with 46 additions and 6 deletions
+15 -6
View File
@@ -146,6 +146,15 @@ type Manager struct {
// 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 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain
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 @@ func (s *certState) tlscert() (*tls.Certificate, error) {
}, 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)
}
+31
View File
@@ -14,6 +14,7 @@ import (
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/base64"
"encoding/json"
"fmt"
@@ -854,3 +855,33 @@ func TestManagerGetCertificateBogusSNI(t *testing.T) {
}
}
}
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)
}
}