1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package acme provides an implementation of the
6 // Automatic Certificate Management Environment (ACME) spec.
7 // See https://tools.ietf.org/html/draft-ietf-acme-acme-02 for details.
9 // Most common scenarios will want to use autocert subdirectory instead,
10 // which provides automatic access to certificates from Let's Encrypt
11 // and any other ACME-based CA.
13 // This package is a work in progress and makes no API stability promises.
42 // LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
43 const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
46 maxChainLen = 5 // max depth and breadth of a certificate chain
47 maxCertSize = 1 << 20 // max size of a certificate, in bytes
49 // Max number of collected nonces kept in memory.
50 // Expect usual peak of 1 or 2.
54 // CertOption is an optional argument type for Client methods which manipulate
56 type CertOption interface {
60 // WithKey creates an option holding a private/public key pair.
61 // The private part signs a certificate, and the public part represents the signee.
62 func WithKey(key crypto.Signer) CertOption {
63 return &certOptKey{key}
66 type certOptKey struct {
70 func (*certOptKey) privateCertOpt() {}
72 // WithTemplate creates an option for specifying a certificate template.
73 // See x509.CreateCertificate for template usage details.
75 // In TLSSNIxChallengeCert methods, the template is also used as parent,
76 // resulting in a self-signed certificate.
77 // The DNSNames field of t is always overwritten for tls-sni challenge certs.
78 func WithTemplate(t *x509.Certificate) CertOption {
79 return (*certOptTemplate)(t)
82 type certOptTemplate x509.Certificate
84 func (*certOptTemplate) privateCertOpt() {}
86 // Client is an ACME client.
87 // The only required field is Key. An example of creating a client with a new key
90 // key, err := rsa.GenerateKey(rand.Reader, 2048)
94 // client := &Client{Key: key}
97 // Key is the account key used to register with a CA and sign requests.
98 // Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey.
101 // HTTPClient optionally specifies an HTTP client to use
102 // instead of http.DefaultClient.
103 HTTPClient *http.Client
105 // DirectoryURL points to the CA directory endpoint.
106 // If empty, LetsEncryptURL is used.
107 // Mutating this value after a successful call of Client's Discover method
108 // will have no effect.
111 dirMu sync.Mutex // guards writes to dir
112 dir *Directory // cached result of Client's Discover method
115 nonces map[string]struct{} // nonces collected from previous responses
118 // Discover performs ACME server discovery using c.DirectoryURL.
120 // It caches successful result. So, subsequent calls will not result in
121 // a network round-trip. This also means mutating c.DirectoryURL after successful call
122 // of this method will have no effect.
123 func (c *Client) Discover(ctx context.Context) (Directory, error) {
125 defer c.dirMu.Unlock()
130 dirURL := c.DirectoryURL
132 dirURL = LetsEncryptURL
134 res, err := c.get(ctx, dirURL)
136 return Directory{}, err
138 defer res.Body.Close()
139 c.addNonce(res.Header)
140 if res.StatusCode != http.StatusOK {
141 return Directory{}, responseError(res)
145 Reg string `json:"new-reg"`
146 Authz string `json:"new-authz"`
147 Cert string `json:"new-cert"`
148 Revoke string `json:"revoke-cert"`
150 Terms string `json:"terms-of-service"`
151 Website string `json:"website"`
152 CAA []string `json:"caa-identities"`
155 if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
156 return Directory{}, err
164 Website: v.Meta.Website,
170 // CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format.
171 // The exp argument indicates the desired certificate validity duration. CA may issue a certificate
172 // with a different duration.
173 // If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain.
175 // In the case where CA server does not provide the issued certificate in the response,
176 // CreateCert will poll certURL using c.FetchCert, which will result in additional round-trips.
177 // In such scenario the caller can cancel the polling with ctx.
179 // CreateCert returns an error if the CA's response or chain was unreasonably large.
180 // Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
181 func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) {
182 if _, err := c.Discover(ctx); err != nil {
187 Resource string `json:"resource"`
188 CSR string `json:"csr"`
189 NotBefore string `json:"notBefore,omitempty"`
190 NotAfter string `json:"notAfter,omitempty"`
192 Resource: "new-cert",
193 CSR: base64.RawURLEncoding.EncodeToString(csr),
196 req.NotBefore = now.Format(time.RFC3339)
198 req.NotAfter = now.Add(exp).Format(time.RFC3339)
201 res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req)
205 defer res.Body.Close()
206 if res.StatusCode != http.StatusCreated {
207 return nil, "", responseError(res)
210 curl := res.Header.Get("Location") // cert permanent URL
211 if res.ContentLength == 0 {
212 // no cert in the body; poll until we get it
213 cert, err := c.FetchCert(ctx, curl, bundle)
214 return cert, curl, err
216 // slurp issued cert and CA chain, if requested
217 cert, err := c.responseCert(ctx, res, bundle)
218 return cert, curl, err
221 // FetchCert retrieves already issued certificate from the given url, in DER format.
222 // It retries the request until the certificate is successfully retrieved,
223 // context is cancelled by the caller or an error response is received.
225 // The returned value will also contain the CA (issuer) certificate if the bundle argument is true.
227 // FetchCert returns an error if the CA's response or chain was unreasonably large.
228 // Callers are encouraged to parse the returned value to ensure the certificate is valid
229 // and has expected features.
230 func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
232 res, err := c.get(ctx, url)
236 defer res.Body.Close()
237 if res.StatusCode == http.StatusOK {
238 return c.responseCert(ctx, res, bundle)
240 if res.StatusCode > 299 {
241 return nil, responseError(res)
243 d := retryAfter(res.Header.Get("Retry-After"), 3*time.Second)
245 case <-time.After(d):
248 return nil, ctx.Err()
253 // RevokeCert revokes a previously issued certificate cert, provided in DER format.
255 // The key argument, used to sign the request, must be authorized
256 // to revoke the certificate. It's up to the CA to decide which keys are authorized.
257 // For instance, the key pair of the certificate may be authorized.
258 // If the key is nil, c.Key is used instead.
259 func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
260 if _, err := c.Discover(ctx); err != nil {
265 Resource string `json:"resource"`
266 Cert string `json:"certificate"`
267 Reason int `json:"reason"`
269 Resource: "revoke-cert",
270 Cert: base64.RawURLEncoding.EncodeToString(cert),
276 res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body)
280 defer res.Body.Close()
281 if res.StatusCode != http.StatusOK {
282 return responseError(res)
287 // AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service
288 // during account registration. See Register method of Client for more details.
289 func AcceptTOS(tosURL string) bool { return true }
291 // Register creates a new account registration by following the "new-reg" flow.
292 // It returns registered account. The a argument is not modified.
294 // The registration may require the caller to agree to the CA's Terms of Service (TOS).
295 // If so, and the account has not indicated the acceptance of the terms (see Account for details),
296 // Register calls prompt with a TOS URL provided by the CA. Prompt should report
297 // whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS.
298 func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) {
299 if _, err := c.Discover(ctx); err != nil {
304 if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil {
308 if a.CurrentTerms != "" && a.CurrentTerms != a.AgreedTerms {
309 accept = prompt(a.CurrentTerms)
312 a.AgreedTerms = a.CurrentTerms
313 a, err = c.UpdateReg(ctx, a)
318 // GetReg retrieves an existing registration.
319 // The url argument is an Account URI.
320 func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) {
321 a, err := c.doReg(ctx, url, "reg", nil)
329 // UpdateReg updates an existing registration.
330 // It returns an updated account copy. The provided account is not modified.
331 func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) {
333 a, err := c.doReg(ctx, uri, "reg", a)
341 // Authorize performs the initial step in an authorization flow.
342 // The caller will then need to choose from and perform a set of returned
343 // challenges using c.Accept in order to successfully complete authorization.
345 // If an authorization has been previously granted, the CA may return
346 // a valid authorization (Authorization.Status is StatusValid). If so, the caller
347 // need not fulfill any challenge and can proceed to requesting a certificate.
348 func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) {
349 if _, err := c.Discover(ctx); err != nil {
353 type authzID struct {
354 Type string `json:"type"`
355 Value string `json:"value"`
358 Resource string `json:"resource"`
359 Identifier authzID `json:"identifier"`
361 Resource: "new-authz",
362 Identifier: authzID{Type: "dns", Value: domain},
364 res, err := c.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req)
368 defer res.Body.Close()
369 if res.StatusCode != http.StatusCreated {
370 return nil, responseError(res)
374 if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
375 return nil, fmt.Errorf("acme: invalid response: %v", err)
377 if v.Status != StatusPending && v.Status != StatusValid {
378 return nil, fmt.Errorf("acme: unexpected status: %s", v.Status)
380 return v.authorization(res.Header.Get("Location")), nil
383 // GetAuthorization retrieves an authorization identified by the given URL.
385 // If a caller needs to poll an authorization until its status is final,
386 // see the WaitAuthorization method.
387 func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
388 res, err := c.get(ctx, url)
392 defer res.Body.Close()
393 if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
394 return nil, responseError(res)
397 if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
398 return nil, fmt.Errorf("acme: invalid response: %v", err)
400 return v.authorization(url), nil
403 // RevokeAuthorization relinquishes an existing authorization identified
405 // The url argument is an Authorization.URI value.
407 // If successful, the caller will be required to obtain a new authorization
408 // using the Authorize method before being able to request a new certificate
409 // for the domain associated with the authorization.
411 // It does not revoke existing certificates.
412 func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
414 Resource string `json:"resource"`
415 Status string `json:"status"`
416 Delete bool `json:"delete"`
419 Status: "deactivated",
422 res, err := c.retryPostJWS(ctx, c.Key, url, req)
426 defer res.Body.Close()
427 if res.StatusCode != http.StatusOK {
428 return responseError(res)
433 // WaitAuthorization polls an authorization at the given URL
434 // until it is in one of the final states, StatusValid or StatusInvalid,
435 // or the context is done.
437 // It returns a non-nil Authorization only if its Status is StatusValid.
438 // In all other cases WaitAuthorization returns an error.
439 // If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
440 func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
441 sleep := sleeper(ctx)
443 res, err := c.get(ctx, url)
447 retry := res.Header.Get("Retry-After")
448 if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
450 if err := sleep(retry, 1); err != nil {
456 err = json.NewDecoder(res.Body).Decode(&raw)
459 if err := sleep(retry, 0); err != nil {
464 if raw.Status == StatusValid {
465 return raw.authorization(url), nil
467 if raw.Status == StatusInvalid {
468 return nil, raw.error(url)
470 if err := sleep(retry, 0); err != nil {
476 // GetChallenge retrieves the current status of an challenge.
478 // A client typically polls a challenge status using this method.
479 func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
480 res, err := c.get(ctx, url)
484 defer res.Body.Close()
485 if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
486 return nil, responseError(res)
488 v := wireChallenge{URI: url}
489 if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
490 return nil, fmt.Errorf("acme: invalid response: %v", err)
492 return v.challenge(), nil
495 // Accept informs the server that the client accepts one of its challenges
496 // previously obtained with c.Authorize.
498 // The server will then perform the validation asynchronously.
499 func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) {
500 auth, err := keyAuth(c.Key.Public(), chal.Token)
506 Resource string `json:"resource"`
507 Type string `json:"type"`
508 Auth string `json:"keyAuthorization"`
510 Resource: "challenge",
514 res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req)
518 defer res.Body.Close()
519 // Note: the protocol specifies 200 as the expected response code, but
520 // letsencrypt seems to be returning 202.
521 if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
522 return nil, responseError(res)
526 if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
527 return nil, fmt.Errorf("acme: invalid response: %v", err)
529 return v.challenge(), nil
532 // DNS01ChallengeRecord returns a DNS record value for a dns-01 challenge response.
533 // A TXT record containing the returned value must be provisioned under
534 // "_acme-challenge" name of the domain being validated.
536 // The token argument is a Challenge.Token value.
537 func (c *Client) DNS01ChallengeRecord(token string) (string, error) {
538 ka, err := keyAuth(c.Key.Public(), token)
542 b := sha256.Sum256([]byte(ka))
543 return base64.RawURLEncoding.EncodeToString(b[:]), nil
546 // HTTP01ChallengeResponse returns the response for an http-01 challenge.
547 // Servers should respond with the value to HTTP requests at the URL path
548 // provided by HTTP01ChallengePath to validate the challenge and prove control
549 // over a domain name.
551 // The token argument is a Challenge.Token value.
552 func (c *Client) HTTP01ChallengeResponse(token string) (string, error) {
553 return keyAuth(c.Key.Public(), token)
556 // HTTP01ChallengePath returns the URL path at which the response for an http-01 challenge
557 // should be provided by the servers.
558 // The response value can be obtained with HTTP01ChallengeResponse.
560 // The token argument is a Challenge.Token value.
561 func (c *Client) HTTP01ChallengePath(token string) string {
562 return "/.well-known/acme-challenge/" + token
565 // TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response.
566 // Servers can present the certificate to validate the challenge and prove control
567 // over a domain name.
569 // The implementation is incomplete in that the returned value is a single certificate,
570 // computed only for Z0 of the key authorization. ACME CAs are expected to update
571 // their implementations to use the newer version, TLS-SNI-02.
572 // For more details on TLS-SNI-01 see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3.
574 // The token argument is a Challenge.Token value.
575 // If a WithKey option is provided, its private part signs the returned cert,
576 // and the public part is used to specify the signee.
577 // If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
579 // The returned certificate is valid for the next 24 hours and must be presented only when
580 // the server name of the client hello matches exactly the returned name value.
581 func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
582 ka, err := keyAuth(c.Key.Public(), token)
584 return tls.Certificate{}, "", err
586 b := sha256.Sum256([]byte(ka))
587 h := hex.EncodeToString(b[:])
588 name = fmt.Sprintf("%s.%s.acme.invalid", h[:32], h[32:])
589 cert, err = tlsChallengeCert([]string{name}, opt)
591 return tls.Certificate{}, "", err
593 return cert, name, nil
596 // TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response.
597 // Servers can present the certificate to validate the challenge and prove control
598 // over a domain name. For more details on TLS-SNI-02 see
599 // https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3.
601 // The token argument is a Challenge.Token value.
602 // If a WithKey option is provided, its private part signs the returned cert,
603 // and the public part is used to specify the signee.
604 // If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
606 // The returned certificate is valid for the next 24 hours and must be presented only when
607 // the server name in the client hello matches exactly the returned name value.
608 func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
609 b := sha256.Sum256([]byte(token))
610 h := hex.EncodeToString(b[:])
611 sanA := fmt.Sprintf("%s.%s.token.acme.invalid", h[:32], h[32:])
613 ka, err := keyAuth(c.Key.Public(), token)
615 return tls.Certificate{}, "", err
617 b = sha256.Sum256([]byte(ka))
618 h = hex.EncodeToString(b[:])
619 sanB := fmt.Sprintf("%s.%s.ka.acme.invalid", h[:32], h[32:])
621 cert, err = tlsChallengeCert([]string{sanA, sanB}, opt)
623 return tls.Certificate{}, "", err
625 return cert, sanA, nil
628 // doReg sends all types of registration requests.
629 // The type of request is identified by typ argument, which is a "resource"
630 // in the ACME spec terms.
632 // A non-nil acct argument indicates whether the intention is to mutate data
633 // of the Account. Only Contact and Agreement of its fields are used
635 func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Account) (*Account, error) {
637 Resource string `json:"resource"`
638 Contact []string `json:"contact,omitempty"`
639 Agreement string `json:"agreement,omitempty"`
644 req.Contact = acct.Contact
645 req.Agreement = acct.AgreedTerms
647 res, err := c.retryPostJWS(ctx, c.Key, url, req)
651 defer res.Body.Close()
652 if res.StatusCode < 200 || res.StatusCode > 299 {
653 return nil, responseError(res)
659 Authorizations string
662 if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
663 return nil, fmt.Errorf("acme: invalid response: %v", err)
666 if v := linkHeader(res.Header, "terms-of-service"); len(v) > 0 {
670 if v := linkHeader(res.Header, "next"); len(v) > 0 {
674 URI: res.Header.Get("Location"),
676 AgreedTerms: v.Agreement,
679 Authorizations: v.Authorizations,
680 Certificates: v.Certificates,
684 // retryPostJWS will retry calls to postJWS if there is a badNonce error,
685 // clearing the stored nonces after each error.
686 // If the response was 4XX-5XX, then responseError is called on the body,
687 // the body is closed, and the error returned.
688 func (c *Client) retryPostJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
689 sleep := sleeper(ctx)
691 res, err := c.postJWS(ctx, key, url, body)
695 // handle errors 4XX-5XX with responseError
696 if res.StatusCode >= 400 && res.StatusCode <= 599 {
697 err := responseError(res)
699 // according to spec badNonce is urn:ietf:params:acme:error:badNonce
700 // however, acme servers in the wild return their version of the error
701 // https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
702 if ae, ok := err.(*Error); ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") {
703 // clear any nonces that we might've stored that might now be
706 retry := res.Header.Get("Retry-After")
707 if err := sleep(retry, 1); err != nil {
718 // postJWS signs the body with the given key and POSTs it to the provided url.
719 // The body argument must be JSON-serializable.
720 func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
721 nonce, err := c.popNonce(ctx, url)
725 b, err := jwsEncodeJSON(body, key, nonce)
729 res, err := c.post(ctx, url, "application/jose+json", bytes.NewReader(b))
733 c.addNonce(res.Header)
737 // popNonce returns a nonce value previously stored with c.addNonce
738 // or fetches a fresh one from the given URL.
739 func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
741 defer c.noncesMu.Unlock()
742 if len(c.nonces) == 0 {
743 return c.fetchNonce(ctx, url)
746 for nonce = range c.nonces {
747 delete(c.nonces, nonce)
753 // clearNonces clears any stored nonces
754 func (c *Client) clearNonces() {
756 defer c.noncesMu.Unlock()
757 c.nonces = make(map[string]struct{})
760 // addNonce stores a nonce value found in h (if any) for future use.
761 func (c *Client) addNonce(h http.Header) {
762 v := nonceFromHeader(h)
767 defer c.noncesMu.Unlock()
768 if len(c.nonces) >= maxNonces {
772 c.nonces = make(map[string]struct{})
774 c.nonces[v] = struct{}{}
777 func (c *Client) httpClient() *http.Client {
778 if c.HTTPClient != nil {
781 return http.DefaultClient
784 func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) {
785 req, err := http.NewRequest("GET", urlStr, nil)
789 return c.do(ctx, req)
792 func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) {
793 req, err := http.NewRequest("HEAD", urlStr, nil)
797 return c.do(ctx, req)
800 func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) {
801 req, err := http.NewRequest("POST", urlStr, body)
805 req.Header.Set("Content-Type", contentType)
806 return c.do(ctx, req)
809 func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) {
810 res, err := c.httpClient().Do(req.WithContext(ctx))
814 // Prefer the unadorned context error.
815 // (The acme package had tests assuming this, previously from ctxhttp's
816 // behavior, predating net/http supporting contexts natively)
817 // TODO(bradfitz): reconsider this in the future. But for now this
818 // requires no test updates.
819 return nil, ctx.Err()
827 func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) {
828 resp, err := c.head(ctx, url)
832 defer resp.Body.Close()
833 nonce := nonceFromHeader(resp.Header)
835 if resp.StatusCode > 299 {
836 return "", responseError(resp)
838 return "", errors.New("acme: nonce not found")
843 func nonceFromHeader(h http.Header) string {
844 return h.Get("Replay-Nonce")
847 func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bool) ([][]byte, error) {
848 b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
850 return nil, fmt.Errorf("acme: response stream: %v", err)
852 if len(b) > maxCertSize {
853 return nil, errors.New("acme: certificate is too big")
860 // Append CA chain cert(s).
861 // At least one is required according to the spec:
862 // https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3.1
863 up := linkHeader(res.Header, "up")
865 return nil, errors.New("acme: rel=up link not found")
867 if len(up) > maxChainLen {
868 return nil, errors.New("acme: rel=up link is too large")
870 for _, url := range up {
871 cc, err := c.chainCert(ctx, url, 0)
875 cert = append(cert, cc...)
880 // responseError creates an error of Error type from resp.
881 func responseError(resp *http.Response) error {
882 // don't care if ReadAll returns an error:
883 // json.Unmarshal will fail in that case anyway
884 b, _ := ioutil.ReadAll(resp.Body)
885 e := &wireError{Status: resp.StatusCode}
886 if err := json.Unmarshal(b, e); err != nil {
887 // this is not a regular error response:
888 // populate detail with anything we received,
889 // e.Status will already contain HTTP response code value
892 e.Detail = resp.Status
895 return e.error(resp.Header)
898 // chainCert fetches CA certificate chain recursively by following "up" links.
899 // Each recursive call increments the depth by 1, resulting in an error
900 // if the recursion level reaches maxChainLen.
902 // First chainCert call starts with depth of 0.
903 func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte, error) {
904 if depth >= maxChainLen {
905 return nil, errors.New("acme: certificate chain is too deep")
908 res, err := c.get(ctx, url)
912 defer res.Body.Close()
913 if res.StatusCode != http.StatusOK {
914 return nil, responseError(res)
916 b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
920 if len(b) > maxCertSize {
921 return nil, errors.New("acme: certificate is too big")
925 uplink := linkHeader(res.Header, "up")
926 if len(uplink) > maxChainLen {
927 return nil, errors.New("acme: certificate chain is too large")
929 for _, up := range uplink {
930 cc, err := c.chainCert(ctx, up, depth+1)
934 chain = append(chain, cc...)
940 // linkHeader returns URI-Reference values of all Link headers
941 // with relation-type rel.
942 // See https://tools.ietf.org/html/rfc5988#section-5 for details.
943 func linkHeader(h http.Header, rel string) []string {
945 for _, v := range h["Link"] {
946 parts := strings.Split(v, ";")
947 for _, p := range parts {
948 p = strings.TrimSpace(p)
949 if !strings.HasPrefix(p, "rel=") {
952 if v := strings.Trim(p[4:], `"`); v == rel {
953 links = append(links, strings.Trim(parts[0], "<>"))
960 // sleeper returns a function that accepts the Retry-After HTTP header value
961 // and an increment that's used with backoff to increasingly sleep on
962 // consecutive calls until the context is done. If the Retry-After header
963 // cannot be parsed, then backoff is used with a maximum sleep time of 10
965 func sleeper(ctx context.Context) func(ra string, inc int) error {
967 return func(ra string, inc int) error {
969 d := backoff(count, 10*time.Second)
970 d = retryAfter(ra, d)
971 wakeup := time.NewTimer(d)
982 // retryAfter parses a Retry-After HTTP header value,
983 // trying to convert v into an int (seconds) or use http.ParseTime otherwise.
984 // It returns d if v cannot be parsed.
985 func retryAfter(v string, d time.Duration) time.Duration {
986 if i, err := strconv.Atoi(v); err == nil {
987 return time.Duration(i) * time.Second
989 t, err := http.ParseTime(v)
993 return t.Sub(timeNow())
996 // backoff computes a duration after which an n+1 retry iteration should occur
997 // using truncated exponential backoff algorithm.
999 // The n argument is always bounded between 0 and 30.
1000 // The max argument defines upper bound for the returned value.
1001 func backoff(n int, max time.Duration) time.Duration {
1009 if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
1010 d = time.Duration(x.Int64()) * time.Millisecond
1012 d += time.Duration(1<<uint(n)) * time.Second
1019 // keyAuth generates a key authorization string for a given token.
1020 func keyAuth(pub crypto.PublicKey, token string) (string, error) {
1021 th, err := JWKThumbprint(pub)
1025 return fmt.Sprintf("%s.%s", token, th), nil
1028 // tlsChallengeCert creates a temporary certificate for TLS-SNI challenges
1029 // with the given SANs and auto-generated public/private key pair.
1030 // To create a cert with a custom key pair, specify WithKey option.
1031 func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
1034 tmpl *x509.Certificate
1036 for _, o := range opt {
1037 switch o := o.(type) {
1040 return tls.Certificate{}, errors.New("acme: duplicate key option")
1043 case *certOptTemplate:
1044 var t = *(*x509.Certificate)(o) // shallow copy is ok
1047 // package's fault, if we let this happen:
1048 panic(fmt.Sprintf("unsupported option type %T", o))
1053 if key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil {
1054 return tls.Certificate{}, err
1058 tmpl = &x509.Certificate{
1059 SerialNumber: big.NewInt(1),
1060 NotBefore: time.Now(),
1061 NotAfter: time.Now().Add(24 * time.Hour),
1062 BasicConstraintsValid: true,
1063 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
1064 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
1069 der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key)
1071 return tls.Certificate{}, err
1073 return tls.Certificate{
1074 Certificate: [][]byte{der},
1079 // encodePEM returns b encoded as PEM with block of type typ.
1080 func encodePEM(typ string, b []byte) []byte {
1081 pb := &pem.Block{Type: typ, Bytes: b}
1082 return pem.EncodeToMemory(pb)
1085 // timeNow is useful for testing for fixed current time.
1086 var timeNow = time.Now