Skip to content

Commit 41d7136

Browse files
author
James Munnelly
committed
Merge latest changes from upstream crypto/acme library
1 parent 959aba2 commit 41d7136

File tree

3 files changed

+55
-23
lines changed

3 files changed

+55
-23
lines changed

third_party/crypto/acme/acme.go

+48-15
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ const (
4646
// Max number of collected nonces kept in memory.
4747
// Expect usual peak of 1 or 2.
4848
maxNonces = 100
49+
50+
// User-Agent, bump the version each time a change is made to the
51+
// handling of API requests.
52+
userAgent = "go-acme/2"
4953
)
5054

5155
// Client is an ACME client.
@@ -73,6 +77,11 @@ type Client struct {
7377
// will have no effect.
7478
DirectoryURL string
7579

80+
// UserAgent is an optional string that identifies this client and
81+
// version to the ACME server. It should be set to something like
82+
// "myclient/1.2.3".
83+
UserAgent string
84+
7685
noncesMu sync.Mutex
7786
nonces map[string]struct{} // nonces collected from previous responses
7887

@@ -274,6 +283,13 @@ func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) {
274283
sleep := timeSleeper(ctx)
275284
for {
276285
o, err := c.GetOrder(ctx, url)
286+
if e, ok := err.(*Error); ok && e.StatusCode >= 500 && e.StatusCode <= 599 {
287+
// retriable 5xx error
288+
if err := sleep(retryAfter(e.Header.Get("Retry-After"))); err != nil {
289+
return nil, err
290+
}
291+
continue
292+
}
277293
if err != nil {
278294
return nil, err
279295
}
@@ -392,32 +408,36 @@ func (c *Client) DeactivateAuthorization(ctx context.Context, url string) error
392408
return nil
393409
}
394410

395-
// WaitAuthorization retrieves authorization details. If the authorization is not in
396-
// a final state (StatusValid/StatusInvalid), it retries the request until the authorization
397-
// is final, ctx is cancelled by the caller, an error response is received, or the ACME CA
398-
// responded with a 4xx error.
411+
// WaitAuthorization polls an authorization at the given URL
412+
// until it is in one of the final states, StatusValid or StatusInvalid,
413+
// the ACME CA responded with a 4xx error code, or the context is done.
399414
//
400415
// It returns a non-nil Authorization only if its Status is StatusValid.
401416
// In all other cases WaitAuthorization returns an error.
402-
// If the Status is StatusInvalid or StatusDeactivated, the returned error will be of type AuthorizationError.
417+
// If the Status is StatusInvalid, StatusDeactivated, or StatusRevoked the
418+
// returned error will be of type AuthorizationError.
403419
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
404420
sleep := sleeper(ctx)
405421
for {
406422
res, err := c.get(ctx, url)
407423
if err != nil {
408424
return nil, err
409425
}
410-
if res.StatusCode != http.StatusOK {
411-
err = responseError(res)
412-
res.Body.Close()
413-
return nil, err
414-
}
415426
if res.StatusCode >= 400 && res.StatusCode <= 499 {
416427
// Non-retriable error. For instance, Let's Encrypt may return 404 Not Found
417428
// when requesting an expired authorization.
418429
defer res.Body.Close()
419430
return nil, responseError(res)
420431
}
432+
433+
retry := res.Header.Get("Retry-After")
434+
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
435+
res.Body.Close()
436+
if err := sleep(retry); err != nil {
437+
return nil, err
438+
}
439+
continue
440+
}
421441
var raw wireAuthz
422442
err = json.NewDecoder(res.Body).Decode(&raw)
423443
res.Body.Close()
@@ -427,13 +447,13 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
427447
switch raw.Status {
428448
case StatusValid:
429449
return raw.authorization(url), nil
430-
case StatusInvalid, StatusDeactivated:
450+
case StatusInvalid, StatusDeactivated, StatusRevoked:
431451
return nil, AuthorizationError{raw.authorization(url)}
432452
case StatusPending, StatusProcessing: // fall through to sleep
433453
default:
434454
return nil, fmt.Errorf("acme: unknown authorization status %q", raw.Status)
435455
}
436-
if err := sleep(res.Header.Get("Retry-After")); err != nil {
456+
if err := sleep(retry); err != nil {
437457
return nil, err
438458
}
439459
}
@@ -723,30 +743,43 @@ func (c *Client) httpClient() *http.Client {
723743
}
724744

725745
func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) {
726-
req, err := http.NewRequest("GET", urlStr, nil)
746+
req, err := c.newRequest("GET", urlStr, nil)
727747
if err != nil {
728748
return nil, err
729749
}
730750
return c.do(ctx, req)
731751
}
732752

733753
func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) {
734-
req, err := http.NewRequest("HEAD", urlStr, nil)
754+
req, err := c.newRequest("HEAD", urlStr, nil)
735755
if err != nil {
736756
return nil, err
737757
}
738758
return c.do(ctx, req)
739759
}
740760

741761
func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) {
742-
req, err := http.NewRequest("POST", urlStr, body)
762+
req, err := c.newRequest("POST", urlStr, body)
743763
if err != nil {
744764
return nil, err
745765
}
746766
req.Header.Set("Content-Type", contentType)
747767
return c.do(ctx, req)
748768
}
749769

770+
func (c *Client) newRequest(method, url string, body io.Reader) (*http.Request, error) {
771+
req, err := http.NewRequest(method, url, body)
772+
if err != nil {
773+
return nil, err
774+
}
775+
ua := userAgent
776+
if c.UserAgent != "" {
777+
ua += " " + c.UserAgent
778+
}
779+
req.Header.Set("User-Agent", ua)
780+
return req, nil
781+
}
782+
750783
func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) {
751784
res, err := c.httpClient().Do(req.WithContext(ctx))
752785
if err != nil {

third_party/crypto/acme/integration_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ import (
2323
)
2424

2525
// This test works with Pebble and Let's Encrypt staging.
26-
// For pebble use: ACME_DIRECTORY_URL=https://localhost:14000/dir go test
26+
// For pebble use: ACME_DIRECTORY_URL=https://localhost:14000/dir go test -tags integration_test
2727
// For Let's Encrypt you'll need a publicly accessible HTTP server like `ngrok http 8080` and then
28-
// TEST_HOST=xxx.ngrok.io:8080 ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory TEST_ACCOUNT_GET=1 TEST_REVOKE=1 go test
28+
// TEST_HOST=xxx.ngrok.io:8080 ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory TEST_ACCOUNT_GET=1 TEST_REVOKE=1 go test -tags integration_test
2929
func TestIntegration(t *testing.T) {
3030
dir := os.Getenv("ACME_DIRECTORY_URL")
3131
testAccountGet := os.Getenv("TEST_ACCOUNT_GET") != ""

third_party/crypto/acme/types.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ const (
2020
StatusInvalid = "invalid"
2121
StatusRevoked = "revoked"
2222
StatusDeactivated = "deactivated"
23-
StatusReady = "ready"
2423
)
2524

2625
// CRLReasonCode identifies the reason for a certificate revocation.
@@ -216,7 +215,7 @@ type Order struct {
216215
URL string
217216

218217
// Status is the status of the order. It will be one of StatusPending,
219-
// StatusReady, StatusProcessing, StatusValid, and StatusInvalid.
218+
// StatusProcessing, StatusValid, and StatusInvalid.
220219
Status string
221220

222221
// Expires is the teimstamp after which the server will consider the order invalid.
@@ -287,16 +286,16 @@ type Authorization struct {
287286
// Identifier is the identifier that the account is authorized to represent.
288287
Identifier AuthzID
289288

289+
// Wildcard is true if the authorization is for the base domain of a wildcard identifier.
290+
Wildcard bool
291+
290292
// Expires is the timestamp after which the server will consider this authorization invalid.
291293
Expires time.Time
292294

293295
// Challenges is the list of challenges that the client can fulfill in order
294296
// to prove posession of the identifier. For valid/invalid authorizations,
295297
// this is the list of challenges that were used.
296298
Challenges []*Challenge
297-
298-
// Wildcard is set to true if this authorization is for a 'wildcard' dnsName.
299-
Wildcard bool
300299
}
301300

302301
// AuthzID is an identifier that an account is authorized to represent.
@@ -328,8 +327,8 @@ func (z *wireAuthz) authorization(url string) *Authorization {
328327
Status: z.Status,
329328
Expires: z.Expires,
330329
Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
331-
Challenges: make([]*Challenge, len(z.Challenges)),
332330
Wildcard: z.Wildcard,
331+
Challenges: make([]*Challenge, len(z.Challenges)),
333332
}
334333
for i, v := range z.Challenges {
335334
a.Challenges[i] = v.challenge()

0 commit comments

Comments
 (0)