Commit 97487e6f authored by Matthew Holt's avatar Matthew Holt

vendor: Update lego to fix error handling bug (closes #2124)

parent 694d2c9b
...@@ -244,10 +244,8 @@ func (c *ACMEClient) Obtain(name string) error { ...@@ -244,10 +244,8 @@ func (c *ACMEClient) Obtain(name string) error {
acmeMu.Unlock() acmeMu.Unlock()
namesObtaining.Remove([]string{name}) namesObtaining.Remove([]string{name})
if err != nil { if err != nil {
// Error - try to fix it or report it to the user and abort // for a certain kind of error, we can enumerate the error per-domain
if failures, ok := err.(acme.ObtainError); ok && len(failures) > 0 { if failures, ok := err.(acme.ObtainError); ok && len(failures) > 0 {
// in this case, we can enumerate the error per-domain
var errMsg string // combine all the failures into a single error message var errMsg string // combine all the failures into a single error message
for errDomain, obtainErr := range failures { for errDomain, obtainErr := range failures {
if obtainErr == nil { if obtainErr == nil {
...@@ -261,9 +259,7 @@ func (c *ACMEClient) Obtain(name string) error { ...@@ -261,9 +259,7 @@ func (c *ACMEClient) Obtain(name string) error {
return fmt.Errorf("[%s] failed to obtain certificate: %v", name, err) return fmt.Errorf("[%s] failed to obtain certificate: %v", name, err)
} }
// double-check that we actually got a certificate; check a couple fields // double-check that we actually got a certificate, in case there's a bug upstream (see issue #2121)
// TODO: This is a temporary workaround for what I think is a bug in the acmev2 package (March 2018)
// but it might not hurt to keep this extra check in place (April 18, 2018: might be fixed now.)
if certificate.Domain == "" || certificate.Certificate == nil { if certificate.Domain == "" || certificate.Certificate == nil {
return errors.New("returned certificate was empty; probably an unchecked error obtaining it") return errors.New("returned certificate was empty; probably an unchecked error obtaining it")
} }
......
...@@ -189,7 +189,7 @@ func (c *Client) ResolveAccountByKey() (*RegistrationResource, error) { ...@@ -189,7 +189,7 @@ func (c *Client) ResolveAccountByKey() (*RegistrationResource, error) {
logf("[INFO] acme: Trying to resolve account by key") logf("[INFO] acme: Trying to resolve account by key")
acc := accountMessage{OnlyReturnExisting: true} acc := accountMessage{OnlyReturnExisting: true}
hdr, err := postJSON(c.jws, c.directory.NewAccountURL, acc, &acc) hdr, err := postJSON(c.jws, c.directory.NewAccountURL, acc, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -294,24 +294,24 @@ DNSNames: ...@@ -294,24 +294,24 @@ DNSNames:
if err != nil { if err != nil {
return CertificateResource{}, err return CertificateResource{}, err
} }
authz, failures := c.getAuthzForOrder(order) authz, err := c.getAuthzForOrder(order)
// If any challenge fails - return. Do not generate partial SAN certificates. if err != nil {
if len(failures) > 0 { // If any challenge fails, return. Do not generate partial SAN certificates.
/*for _, auth := range authz { /*for _, auth := range authz {
c.disableAuthz(auth) c.disableAuthz(auth)
}*/ }*/
return CertificateResource{}, err
return CertificateResource{}, failures
} }
errs := c.solveChallengeForAuthz(authz) err = c.solveChallengeForAuthz(authz)
// If any challenge fails - return. Do not generate partial SAN certificates. if err != nil {
if len(errs) > 0 { // If any challenge fails, return. Do not generate partial SAN certificates.
return CertificateResource{}, errs return CertificateResource{}, err
} }
logf("[INFO][%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", ")) logf("[INFO][%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
failures := make(ObtainError)
cert, err := c.requestCertificateForCsr(order, bundle, csr.Raw, nil) cert, err := c.requestCertificateForCsr(order, bundle, csr.Raw, nil)
if err != nil { if err != nil {
for _, chln := range authz { for _, chln := range authz {
...@@ -322,7 +322,12 @@ DNSNames: ...@@ -322,7 +322,12 @@ DNSNames:
// Add the CSR to the certificate so that it can be used for renewals. // Add the CSR to the certificate so that it can be used for renewals.
cert.CSR = pemEncode(&csr) cert.CSR = pemEncode(&csr)
return cert, failures // do not return an empty failures map, because
// it would still be a non-nil error value
if len(failures) > 0 {
return cert, failures
}
return cert, nil
} }
// ObtainCertificate tries to obtain a single certificate using all domains passed into it. // ObtainCertificate tries to obtain a single certificate using all domains passed into it.
...@@ -336,7 +341,7 @@ DNSNames: ...@@ -336,7 +341,7 @@ DNSNames:
// the whole certificate will fail. // the whole certificate will fail.
func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto.PrivateKey, mustStaple bool) (CertificateResource, error) { func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto.PrivateKey, mustStaple bool) (CertificateResource, error) {
if len(domains) == 0 { if len(domains) == 0 {
return CertificateResource{}, errors.New("Passed no domains into ObtainCertificate") return CertificateResource{}, errors.New("No domains to obtain a certificate for")
} }
if bundle { if bundle {
...@@ -349,24 +354,24 @@ func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto ...@@ -349,24 +354,24 @@ func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto
if err != nil { if err != nil {
return CertificateResource{}, err return CertificateResource{}, err
} }
authz, failures := c.getAuthzForOrder(order) authz, err := c.getAuthzForOrder(order)
// If any challenge fails - return. Do not generate partial SAN certificates. if err != nil {
if len(failures) > 0 { // If any challenge fails, return. Do not generate partial SAN certificates.
/*for _, auth := range authz { /*for _, auth := range authz {
c.disableAuthz(auth) c.disableAuthz(auth)
}*/ }*/
return CertificateResource{}, err
return CertificateResource{}, failures
} }
errs := c.solveChallengeForAuthz(authz) err = c.solveChallengeForAuthz(authz)
// If any challenge fails - return. Do not generate partial SAN certificates. if err != nil {
if len(errs) > 0 { // If any challenge fails, return. Do not generate partial SAN certificates.
return CertificateResource{}, errs return CertificateResource{}, err
} }
logf("[INFO][%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", ")) logf("[INFO][%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
failures := make(ObtainError)
cert, err := c.requestCertificateForOrder(order, bundle, privKey, mustStaple) cert, err := c.requestCertificateForOrder(order, bundle, privKey, mustStaple)
if err != nil { if err != nil {
for _, auth := range authz { for _, auth := range authz {
...@@ -374,7 +379,12 @@ func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto ...@@ -374,7 +379,12 @@ func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto
} }
} }
return cert, failures // do not return an empty failures map, because
// it would still be a non-nil error value
if len(failures) > 0 {
return cert, failures
}
return cert, nil
} }
// RevokeCertificate takes a PEM encoded certificate or bundle and tries to revoke it at the CA. // RevokeCertificate takes a PEM encoded certificate or bundle and tries to revoke it at the CA.
...@@ -485,9 +495,10 @@ func (c *Client) createOrderForIdentifiers(domains []string) (orderResource, err ...@@ -485,9 +495,10 @@ func (c *Client) createOrderForIdentifiers(domains []string) (orderResource, err
// Looks through the challenge combinations to find a solvable match. // Looks through the challenge combinations to find a solvable match.
// Then solves the challenges in series and returns. // Then solves the challenges in series and returns.
func (c *Client) solveChallengeForAuthz(authorizations []authorization) ObtainError { func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
// loop through the resources, basically through the domains.
failures := make(ObtainError) failures := make(ObtainError)
// loop through the resources, basically through the domains.
for _, authz := range authorizations { for _, authz := range authorizations {
if authz.Status == "valid" { if authz.Status == "valid" {
// Boulder might recycle recent validated authz (see issue #267) // Boulder might recycle recent validated authz (see issue #267)
...@@ -508,7 +519,12 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) ObtainEr ...@@ -508,7 +519,12 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) ObtainEr
} }
} }
return failures // be careful not to return an empty failures map, for
// even an empty ObtainError is a non-nil error value
if len(failures) > 0 {
return failures
}
return nil
} }
// Checks all challenges from the server in order and returns the first matching solver. // Checks all challenges from the server in order and returns the first matching solver.
...@@ -523,7 +539,7 @@ func (c *Client) chooseSolver(auth authorization, domain string) (int, solver) { ...@@ -523,7 +539,7 @@ func (c *Client) chooseSolver(auth authorization, domain string) (int, solver) {
} }
// Get the challenges needed to proof our identifier to the ACME server. // Get the challenges needed to proof our identifier to the ACME server.
func (c *Client) getAuthzForOrder(order orderResource) ([]authorization, ObtainError) { func (c *Client) getAuthzForOrder(order orderResource) ([]authorization, error) {
resc, errc := make(chan authorization), make(chan domainError) resc, errc := make(chan authorization), make(chan domainError)
delay := time.Second / overallRequestLimit delay := time.Second / overallRequestLimit
...@@ -544,7 +560,7 @@ func (c *Client) getAuthzForOrder(order orderResource) ([]authorization, ObtainE ...@@ -544,7 +560,7 @@ func (c *Client) getAuthzForOrder(order orderResource) ([]authorization, ObtainE
} }
var responses []authorization var responses []authorization
failures := make(map[string]error) failures := make(ObtainError)
for i := 0; i < len(order.Authorizations); i++ { for i := 0; i < len(order.Authorizations); i++ {
select { select {
case res := <-resc: case res := <-resc:
...@@ -559,7 +575,12 @@ func (c *Client) getAuthzForOrder(order orderResource) ([]authorization, ObtainE ...@@ -559,7 +575,12 @@ func (c *Client) getAuthzForOrder(order orderResource) ([]authorization, ObtainE
close(resc) close(resc)
close(errc) close(errc)
return responses, failures // be careful to not return an empty failures map;
// even if empty, they become non-nil error values
if len(failures) > 0 {
return responses, failures
}
return responses, nil
} }
func logAuthz(order orderResource) { func logAuthz(order orderResource) {
......
...@@ -193,7 +193,7 @@ ...@@ -193,7 +193,7 @@
"importpath": "github.com/xenolf/lego/acmev2", "importpath": "github.com/xenolf/lego/acmev2",
"repository": "https://github.com/xenolf/lego", "repository": "https://github.com/xenolf/lego",
"vcs": "git", "vcs": "git",
"revision": "6e962fbfb37f9ea4a8201e32acb1b94ffb3b8398", "revision": "fad2257e11ae4ff31ed03739386873aa405dec2d",
"branch": "acmev2", "branch": "acmev2",
"path": "/acmev2", "path": "/acmev2",
"notests": true "notests": true
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment