Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/crypto/acme/autocert: better error messages for failed validations #60554

Open
mjl- opened this issue Jun 1, 2023 · 1 comment
Open

x/crypto/acme/autocert: better error messages for failed validations #60554

mjl- opened this issue Jun 1, 2023 · 1 comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@mjl-
Copy link

mjl- commented Jun 1, 2023

What version of Go are you using (go version)?

Does this issue reproduce with the latest release?

Yes, with latest golang.org/x/crypto/acme/autocert on 2023-06-01.

What did you do?

I'm using golang.org/x/crypto/acme/autocert in https://github.com/mjl-/mox. A user of mox couldn't get a TLS certificate with autocert through Let's Encrypt. The error message only contained "no viable challenge type found". They had to try different software to see the error messages Let's Encrypt was sending back. Autocert does not expose the errors, even though they describe nicely what the problem was (CAA lookup failed in this case).

What did you expect to see?

An error message like this:

unable to satisfy "https://acme-v02.api.letsencrypt.org/[...]" for domain "domain.example": no viable challenge type found (failures: tls-alpn-01: acme: authorization error for domain.example: 403 urn:ietf:params:acme:error:caa: CAA record for domain.example prevents issuance)

What did you see instead?

unable to satisfy "https://acme-v02.api.letsencrypt.org/[...]" for domain "domain.example": no viable challenge type found 

Suggested patch

diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
index 6b4cdf4..d3fca39 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
@@ -694,7 +694,8 @@ func (m *Manager) verifyRFC(ctx context.Context, client *acme.Client, domain str
 	// all order authorizations: if we've tried a challenge type once and it didn't work,
 	// it will most likely not work on another order's authorization either.
 	challengeTypes := m.supportedChallengeTypes()
-	nextTyp := 0 // challengeTypes index
+	nextTyp := 0         // challengeTypes index
+	var authErrs []error // Validation errors, possibly hinting at a solution.
 AuthorizeOrderLoop:
 	for {
 		o, err := client.AuthorizeOrder(ctx, acme.DomainIDs(domain))
@@ -735,18 +736,29 @@ AuthorizeOrderLoop:
 				nextTyp++
 			}
 			if chal == nil {
-				return nil, fmt.Errorf("acme/autocert: unable to satisfy %q for domain %q: no viable challenge type found", z.URI, domain)
+				details := ""
+				if len(authErrs) > 0 {
+					details = " (failures: " + authErrs[0].Error()
+					for _, err := range authErrs[1:] {
+						details += "; " + err.Error()
+					}
+					details += ")"
+				}
+				return nil, fmt.Errorf("acme/autocert: unable to satisfy %q for domain %q: no viable challenge type found%s", z.URI, domain, details)
 			}
 			// Respond to the challenge and wait for validation result.
 			cleanup, err := m.fulfill(ctx, client, chal, domain)
 			if err != nil {
+				authErrs = append(authErrs, fmt.Errorf("challenge %s: preparing response for validation: %v", chal.Type, err))
 				continue AuthorizeOrderLoop
 			}
 			defer cleanup()
 			if _, err := client.Accept(ctx, chal); err != nil {
+				authErrs = append(authErrs, fmt.Errorf("challenge %s: requesting validation: %v", chal.Type, err))
 				continue AuthorizeOrderLoop
 			}
 			if _, err := client.WaitAuthorization(ctx, z.URI); err != nil {
+				authErrs = append(authErrs, fmt.Errorf("challenge %s: %v", chal.Type, err))
 				continue AuthorizeOrderLoop
 			}
 		}
@@ -755,6 +767,7 @@ AuthorizeOrderLoop:
 		// Wait for the CA to update the order status.
 		o, err = client.WaitOrder(ctx, o.URI)
 		if err != nil {
+			authErrs = append(authErrs, fmt.Errorf("waiting for order: %v", err))
 			continue AuthorizeOrderLoop
 		}
 		return o, nil

@gopherbot gopherbot added this to the Unreleased milestone Jun 1, 2023
@mknyszek
Copy link
Contributor

mknyszek commented Jun 1, 2023

CC @FiloSottile @rolandshoemaker @golang/security

@mknyszek mknyszek added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jun 1, 2023
mjl- added a commit to mjl-/autocert that referenced this issue Oct 13, 2023
…essage

if you have a caa record that doesn't allow a CA to make a certificate, it will
now show in the error message. before, the message just said "no viable
challenge type found".

this is golang/go#60554
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

3 participants