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:
@@ -146,6 +146,15 @@ type Manager struct {
|
|||||||
// is EC-based keys using the P-256 curve.
|
// is EC-based keys using the P-256 curve.
|
||||||
ForceRSA bool
|
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
|
clientMu sync.Mutex
|
||||||
client *acme.Client // initialized by acmeClient method
|
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 {
|
if err := m.verify(ctx, client, domain); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
csr, err := certRequest(key, domain)
|
csr, err := certRequest(key, domain, m.ExtraExtensions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -870,12 +879,12 @@ func (s *certState) tlscert() (*tls.Certificate, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// certRequest creates a certificate request for the given common name cn
|
// certRequest generates a CSR for the given common name cn and optional SANs.
|
||||||
// and optional SANs.
|
func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) {
|
||||||
func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) {
|
|
||||||
req := &x509.CertificateRequest{
|
req := &x509.CertificateRequest{
|
||||||
Subject: pkix.Name{CommonName: cn},
|
Subject: pkix.Name{CommonName: cn},
|
||||||
DNSNames: san,
|
DNSNames: san,
|
||||||
|
ExtraExtensions: ext,
|
||||||
}
|
}
|
||||||
return x509.CreateCertificateRequest(rand.Reader, req, key)
|
return x509.CreateCertificateRequest(rand.Reader, req, key)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user