Skip to content

Commit

Permalink
Add AlwaysDeactivateAuthorizations flag to ObtainRequest (#1480)
Browse files Browse the repository at this point in the history
Co-authored-by: Fernandez Ludovic <[email protected]>
  • Loading branch information
MartinWeindel and ldez authored Sep 8, 2021
1 parent d2e526e commit 6d0e0e1
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 31 deletions.
4 changes: 2 additions & 2 deletions certificate/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
return responses, nil
}

func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder) {
func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force bool) {
for _, authzURL := range order.Authorizations {
auth, err := c.core.Authorizations.Get(authzURL)
if err != nil {
log.Infof("Unable to get the authorization for: %s", authzURL)
continue
}

if auth.Status == acme.StatusValid {
if auth.Status == acme.StatusValid && !force {
log.Infof("Skipping deactivating of valid auth: %s", authzURL)
continue
}
Expand Down
44 changes: 30 additions & 14 deletions certificate/certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,30 @@ type Resource struct {
// If you do not want that you can supply your own private key in the privateKey parameter.
// If this parameter is non-nil it will be used instead of generating a new one.
//
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
// If `Bundle` is true, the `[]byte` contains both the issuer certificate and your issued certificate as a bundle.
//
// If `AlwaysDeactivateAuthorizations` is true, the authorizations are also relinquished if the obtain request was successful.
// See https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.2.
type ObtainRequest struct {
Domains []string
Bundle bool
PrivateKey crypto.PrivateKey
MustStaple bool
PreferredChain string
Domains []string
Bundle bool
PrivateKey crypto.PrivateKey
MustStaple bool
PreferredChain string
AlwaysDeactivateAuthorizations bool
}

// ObtainForCSRRequest The request to obtain a certificate matching the CSR passed into it.
//
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
// If `Bundle` is true, the `[]byte` contains both the issuer certificate and your issued certificate as a bundle.
//
// If `AlwaysDeactivateAuthorizations` is true, the authorizations are also relinquished if the obtain request was successful.
// See https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.2.
type ObtainForCSRRequest struct {
CSR *x509.CertificateRequest
Bundle bool
PreferredChain string
CSR *x509.CertificateRequest
Bundle bool
PreferredChain string
AlwaysDeactivateAuthorizations bool
}

type resolver interface {
Expand Down Expand Up @@ -117,14 +125,14 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
authz, err := c.getAuthorizations(order)
if err != nil {
// If any challenge fails, return. Do not generate partial SAN certificates.
c.deactivateAuthorizations(order)
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
return nil, err
}

err = c.resolver.Solve(authz)
if err != nil {
// If any challenge fails, return. Do not generate partial SAN certificates.
c.deactivateAuthorizations(order)
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
return nil, err
}

Expand All @@ -138,6 +146,10 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
}
}

if request.AlwaysDeactivateAuthorizations {
c.deactivateAuthorizations(order, true)
}

// Do not return an empty failures map, because
// it would still be a non-nil error value
if len(failures) > 0 {
Expand Down Expand Up @@ -178,14 +190,14 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
authz, err := c.getAuthorizations(order)
if err != nil {
// If any challenge fails, return. Do not generate partial SAN certificates.
c.deactivateAuthorizations(order)
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
return nil, err
}

err = c.resolver.Solve(authz)
if err != nil {
// If any challenge fails, return. Do not generate partial SAN certificates.
c.deactivateAuthorizations(order)
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
return nil, err
}

Expand All @@ -199,6 +211,10 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
}
}

if request.AlwaysDeactivateAuthorizations {
c.deactivateAuthorizations(order, true)
}

if cert != nil {
// Add the CSR to the certificate so that it can be used for renewals.
cert.CSR = certcrypto.PEMEncode(request.CSR)
Expand Down
22 changes: 14 additions & 8 deletions cmd/cmd_renew.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ func createRenew() cli.Command {
Name: "preferred-chain",
Usage: "If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used.",
},
cli.StringFlag{
Name: "always-deactivate-authorizations",
Usage: "Force the authorizations to be relinquished even if the certificate request was successful.",
},
},
}
}
Expand Down Expand Up @@ -127,11 +131,12 @@ func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *Certif
}

request := certificate.ObtainRequest{
Domains: merge(certDomains, domains),
Bundle: bundle,
PrivateKey: privateKey,
MustStaple: ctx.Bool("must-staple"),
PreferredChain: ctx.String("preferred-chain"),
Domains: merge(certDomains, domains),
Bundle: bundle,
PrivateKey: privateKey,
MustStaple: ctx.Bool("must-staple"),
PreferredChain: ctx.String("preferred-chain"),
AlwaysDeactivateAuthorizations: ctx.Bool("always-deactivate-authorizations"),
}
certRes, err := client.Certificate.Obtain(request)
if err != nil {
Expand Down Expand Up @@ -174,9 +179,10 @@ func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *Certificat
log.Infof("[%s] acme: Trying renewal with %d hours remaining", domain, int(timeLeft.Hours()))

certRes, err := client.Certificate.ObtainForCSR(certificate.ObtainForCSRRequest{
CSR: csr,
Bundle: bundle,
PreferredChain: ctx.String("preferred-chain"),
CSR: csr,
Bundle: bundle,
PreferredChain: ctx.String("preferred-chain"),
AlwaysDeactivateAuthorizations: ctx.Bool("always-deactivate-authorizations"),
})
if err != nil {
log.Fatal(err)
Expand Down
20 changes: 13 additions & 7 deletions cmd/cmd_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func createRun() cli.Command {
Name: "preferred-chain",
Usage: "If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used.",
},
cli.StringFlag{
Name: "always-deactivate-authorizations",
Usage: "Force the authorizations to be relinquished even if the certificate request was successful.",
},
},
}
}
Expand Down Expand Up @@ -163,10 +167,11 @@ func obtainCertificate(ctx *cli.Context, client *lego.Client) (*certificate.Reso
if len(domains) > 0 {
// obtain a certificate, generating a new private key
request := certificate.ObtainRequest{
Domains: domains,
Bundle: bundle,
MustStaple: ctx.Bool("must-staple"),
PreferredChain: ctx.String("preferred-chain"),
Domains: domains,
Bundle: bundle,
MustStaple: ctx.Bool("must-staple"),
PreferredChain: ctx.String("preferred-chain"),
AlwaysDeactivateAuthorizations: ctx.Bool("always-deactivate-authorizations"),
}
return client.Certificate.Obtain(request)
}
Expand All @@ -179,8 +184,9 @@ func obtainCertificate(ctx *cli.Context, client *lego.Client) (*certificate.Reso

// obtain a certificate for this CSR
return client.Certificate.ObtainForCSR(certificate.ObtainForCSRRequest{
CSR: csr,
Bundle: bundle,
PreferredChain: ctx.String("preferred-chain"),
CSR: csr,
Bundle: bundle,
PreferredChain: ctx.String("preferred-chain"),
AlwaysDeactivateAuthorizations: ctx.Bool("always-deactivate-authorizations"),
})
}

0 comments on commit 6d0e0e1

Please sign in to comment.