|
|
@@ -65,7 +65,21 @@ type certOptKey struct {
|
|
|
key crypto.Signer
|
|
|
}
|
|
|
|
|
|
-func (co *certOptKey) privateCertOpt() {}
|
|
|
+func (*certOptKey) privateCertOpt() {}
|
|
|
+
|
|
|
+// WithTemplate creates an option for specifying a certificate template.
|
|
|
+// See x509.CreateCertificate for template usage details.
|
|
|
+//
|
|
|
+// In TLSSNIxChallengeCert methods, the template is also used as parent,
|
|
|
+// resulting in a self-signed certificate.
|
|
|
+// The DNSNames field of t is always overwritten for tls-sni challenge certs.
|
|
|
+func WithTemplate(t *x509.Certificate) CertOption {
|
|
|
+ return (*certOptTemplate)(t)
|
|
|
+}
|
|
|
+
|
|
|
+type certOptTemplate x509.Certificate
|
|
|
+
|
|
|
+func (*certOptTemplate) privateCertOpt() {}
|
|
|
|
|
|
// Client is an ACME client.
|
|
|
// The only required field is Key. An example of creating a client with a new key
|
|
|
@@ -874,7 +888,10 @@ func keyAuth(pub crypto.PublicKey, token string) (string, error) {
|
|
|
// with the given SANs and auto-generated public/private key pair.
|
|
|
// To create a cert with a custom key pair, specify WithKey option.
|
|
|
func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
|
|
- var key crypto.Signer
|
|
|
+ var (
|
|
|
+ key crypto.Signer
|
|
|
+ tmpl *x509.Certificate
|
|
|
+ )
|
|
|
for _, o := range opt {
|
|
|
switch o := o.(type) {
|
|
|
case *certOptKey:
|
|
|
@@ -882,6 +899,9 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
|
|
return tls.Certificate{}, errors.New("acme: duplicate key option")
|
|
|
}
|
|
|
key = o.key
|
|
|
+ case *certOptTemplate:
|
|
|
+ var t = *(*x509.Certificate)(o) // shallow copy is ok
|
|
|
+ tmpl = &t
|
|
|
default:
|
|
|
// package's fault, if we let this happen:
|
|
|
panic(fmt.Sprintf("unsupported option type %T", o))
|
|
|
@@ -893,15 +913,18 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
|
|
return tls.Certificate{}, err
|
|
|
}
|
|
|
}
|
|
|
- t := x509.Certificate{
|
|
|
- SerialNumber: big.NewInt(1),
|
|
|
- NotBefore: time.Now(),
|
|
|
- NotAfter: time.Now().Add(24 * time.Hour),
|
|
|
- BasicConstraintsValid: true,
|
|
|
- KeyUsage: x509.KeyUsageKeyEncipherment,
|
|
|
- DNSNames: san,
|
|
|
+ if tmpl == nil {
|
|
|
+ tmpl = &x509.Certificate{
|
|
|
+ SerialNumber: big.NewInt(1),
|
|
|
+ NotBefore: time.Now(),
|
|
|
+ NotAfter: time.Now().Add(24 * time.Hour),
|
|
|
+ BasicConstraintsValid: true,
|
|
|
+ KeyUsage: x509.KeyUsageKeyEncipherment,
|
|
|
+ }
|
|
|
}
|
|
|
- der, err := x509.CreateCertificate(rand.Reader, &t, &t, key.Public(), key)
|
|
|
+ tmpl.DNSNames = san
|
|
|
+
|
|
|
+ der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key)
|
|
|
if err != nil {
|
|
|
return tls.Certificate{}, err
|
|
|
}
|