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. 4 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. 8// 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. 12// 13// This package is a work in progress and makes no API stability promises. 14package acme 15 16import ( 17 "bytes" 18 "context" 19 "crypto" 20 "crypto/ecdsa" 21 "crypto/elliptic" 22 "crypto/rand" 23 "crypto/sha256" 24 "crypto/tls" 25 "crypto/x509" 26 "encoding/base64" 27 "encoding/hex" 28 "encoding/json" 29 "encoding/pem" 30 "errors" 31 "fmt" 32 "io" 33 "io/ioutil" 34 "math/big" 35 "net/http" 36 "strconv" 37 "strings" 38 "sync" 39 "time" 40) 41 42// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA. 43const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" 44 45const ( 46 maxChainLen = 5 // max depth and breadth of a certificate chain 47 maxCertSize = 1 << 20 // max size of a certificate, in bytes 48 49 // Max number of collected nonces kept in memory. 50 // Expect usual peak of 1 or 2. 51 maxNonces = 100 52) 53 54// Client is an ACME client. 55// The only required field is Key. An example of creating a client with a new key 56// is as follows: 57// 58// key, err := rsa.GenerateKey(rand.Reader, 2048) 59// if err != nil { 60// log.Fatal(err) 61// } 62// client := &Client{Key: key} 63// 64type Client struct { 65 // Key is the account key used to register with a CA and sign requests. 66 // Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey. 67 Key crypto.Signer 68 69 // HTTPClient optionally specifies an HTTP client to use 70 // instead of http.DefaultClient. 71 HTTPClient *http.Client 72 73 // DirectoryURL points to the CA directory endpoint. 74 // If empty, LetsEncryptURL is used. 75 // Mutating this value after a successful call of Client's Discover method 76 // will have no effect. 77 DirectoryURL string 78 79 dirMu sync.Mutex // guards writes to dir 80 dir *Directory // cached result of Client's Discover method 81 82 noncesMu sync.Mutex 83 nonces map[string]struct{} // nonces collected from previous responses 84} 85 86// Discover performs ACME server discovery using c.DirectoryURL. 87// 88// It caches successful result. So, subsequent calls will not result in 89// a network round-trip. This also means mutating c.DirectoryURL after successful call 90// of this method will have no effect. 91func (c *Client) Discover(ctx context.Context) (Directory, error) { 92 c.dirMu.Lock() 93 defer c.dirMu.Unlock() 94 if c.dir != nil { 95 return *c.dir, nil 96 } 97 98 dirURL := c.DirectoryURL 99 if dirURL == "" { 100 dirURL = LetsEncryptURL 101 } 102 res, err := c.get(ctx, dirURL) 103 if err != nil { 104 return Directory{}, err 105 } 106 defer res.Body.Close() 107 c.addNonce(res.Header) 108 if res.StatusCode != http.StatusOK { 109 return Directory{}, responseError(res) 110 } 111 112 var v struct { 113 Reg string `json:"new-reg"` 114 Authz string `json:"new-authz"` 115 Cert string `json:"new-cert"` 116 Revoke string `json:"revoke-cert"` 117 Meta struct { 118 Terms string `json:"terms-of-service"` 119 Website string `json:"website"` 120 CAA []string `json:"caa-identities"` 121 } 122 } 123 if err := json.NewDecoder(res.Body).Decode(&v); err != nil { 124 return Directory{}, err 125 } 126 c.dir = &Directory{ 127 RegURL: v.Reg, 128 AuthzURL: v.Authz, 129 CertURL: v.Cert, 130 RevokeURL: v.Revoke, 131 Terms: v.Meta.Terms, 132 Website: v.Meta.Website, 133 CAA: v.Meta.CAA, 134 } 135 return *c.dir, nil 136} 137 138// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format. 139// The exp argument indicates the desired certificate validity duration. CA may issue a certificate 140// with a different duration. 141// If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain. 142// 143// In the case where CA server does not provide the issued certificate in the response, 144// CreateCert will poll certURL using c.FetchCert, which will result in additional round-trips. 145// In such a scenario, the caller can cancel the polling with ctx. 146// 147// CreateCert returns an error if the CA's response or chain was unreasonably large. 148// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features. 149func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) { 150 if _, err := c.Discover(ctx); err != nil { 151 return nil, "", err 152 } 153 154 req := struct { 155 Resource string `json:"resource"` 156 CSR string `json:"csr"` 157 NotBefore string `json:"notBefore,omitempty"` 158 NotAfter string `json:"notAfter,omitempty"` 159 }{ 160 Resource: "new-cert", 161 CSR: base64.RawURLEncoding.EncodeToString(csr), 162 } 163 now := timeNow() 164 req.NotBefore = now.Format(time.RFC3339) 165 if exp > 0 { 166 req.NotAfter = now.Add(exp).Format(time.RFC3339) 167 } 168 169 res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req) 170 if err != nil { 171 return nil, "", err 172 } 173 defer res.Body.Close() 174 if res.StatusCode != http.StatusCreated { 175 return nil, "", responseError(res) 176 } 177 178 curl := res.Header.Get("Location") // cert permanent URL 179 if res.ContentLength == 0 { 180 // no cert in the body; poll until we get it 181 cert, err := c.FetchCert(ctx, curl, bundle) 182 return cert, curl, err 183 } 184 // slurp issued cert and CA chain, if requested 185 cert, err := c.responseCert(ctx, res, bundle) 186 return cert, curl, err 187} 188 189// FetchCert retrieves already issued certificate from the given url, in DER format. 190// It retries the request until the certificate is successfully retrieved, 191// context is cancelled by the caller or an error response is received. 192// 193// The returned value will also contain the CA (issuer) certificate if the bundle argument is true. 194// 195// FetchCert returns an error if the CA's response or chain was unreasonably large. 196// Callers are encouraged to parse the returned value to ensure the certificate is valid 197// and has expected features. 198func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) { 199 for { 200 res, err := c.get(ctx, url) 201 if err != nil { 202 return nil, err 203 } 204 defer res.Body.Close() 205 if res.StatusCode == http.StatusOK { 206 return c.responseCert(ctx, res, bundle) 207 } 208 if res.StatusCode > 299 { 209 return nil, responseError(res) 210 } 211 d := retryAfter(res.Header.Get("Retry-After"), 3*time.Second) 212 select { 213 case <-time.After(d): 214 // retry 215 case <-ctx.Done(): 216 return nil, ctx.Err() 217 } 218 } 219} 220 221// RevokeCert revokes a previously issued certificate cert, provided in DER format. 222// 223// The key argument, used to sign the request, must be authorized 224// to revoke the certificate. It's up to the CA to decide which keys are authorized. 225// For instance, the key pair of the certificate may be authorized. 226// If the key is nil, c.Key is used instead. 227func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error { 228 if _, err := c.Discover(ctx); err != nil { 229 return err 230 } 231 232 body := &struct { 233 Resource string `json:"resource"` 234 Cert string `json:"certificate"` 235 Reason int `json:"reason"` 236 }{ 237 Resource: "revoke-cert", 238 Cert: base64.RawURLEncoding.EncodeToString(cert), 239 Reason: int(reason), 240 } 241 if key == nil { 242 key = c.Key 243 } 244 res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body) 245 if err != nil { 246 return err 247 } 248 defer res.Body.Close() 249 if res.StatusCode != http.StatusOK { 250 return responseError(res) 251 } 252 return nil 253} 254 255// AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service 256// during account registration. See Register method of Client for more details. 257func AcceptTOS(tosURL string) bool { return true } 258 259// Register creates a new account registration by following the "new-reg" flow. 260// It returns the registered account. The account is not modified. 261// 262// The registration may require the caller to agree to the CA's Terms of Service (TOS). 263// If so, and the account has not indicated the acceptance of the terms (see Account for details), 264// Register calls prompt with a TOS URL provided by the CA. Prompt should report 265// whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS. 266func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) { 267 if _, err := c.Discover(ctx); err != nil { 268 return nil, err 269 } 270 271 var err error 272 if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil { 273 return nil, err 274 } 275 var accept bool 276 if a.CurrentTerms != "" && a.CurrentTerms != a.AgreedTerms { 277 accept = prompt(a.CurrentTerms) 278 } 279 if accept { 280 a.AgreedTerms = a.CurrentTerms 281 a, err = c.UpdateReg(ctx, a) 282 } 283 return a, err 284} 285 286// GetReg retrieves an existing registration. 287// The url argument is an Account URI. 288func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) { 289 a, err := c.doReg(ctx, url, "reg", nil) 290 if err != nil { 291 return nil, err 292 } 293 a.URI = url 294 return a, nil 295} 296 297// UpdateReg updates an existing registration. 298// It returns an updated account copy. The provided account is not modified. 299func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) { 300 uri := a.URI 301 a, err := c.doReg(ctx, uri, "reg", a) 302 if err != nil { 303 return nil, err 304 } 305 a.URI = uri 306 return a, nil 307} 308 309// Authorize performs the initial step in an authorization flow. 310// The caller will then need to choose from and perform a set of returned 311// challenges using c.Accept in order to successfully complete authorization. 312// 313// If an authorization has been previously granted, the CA may return 314// a valid authorization (Authorization.Status is StatusValid). If so, the caller 315// need not fulfill any challenge and can proceed to requesting a certificate. 316func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) { 317 if _, err := c.Discover(ctx); err != nil { 318 return nil, err 319 } 320 321 type authzID struct { 322 Type string `json:"type"` 323 Value string `json:"value"` 324 } 325 req := struct { 326 Resource string `json:"resource"` 327 Identifier authzID `json:"identifier"` 328 }{ 329 Resource: "new-authz", 330 Identifier: authzID{Type: "dns", Value: domain}, 331 } 332 res, err := c.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req) 333 if err != nil { 334 return nil, err 335 } 336 defer res.Body.Close() 337 if res.StatusCode != http.StatusCreated { 338 return nil, responseError(res) 339 } 340 341 var v wireAuthz 342 if err := json.NewDecoder(res.Body).Decode(&v); err != nil { 343 return nil, fmt.Errorf("acme: invalid response: %v", err) 344 } 345 if v.Status != StatusPending && v.Status != StatusValid { 346 return nil, fmt.Errorf("acme: unexpected status: %s", v.Status) 347 } 348 return v.authorization(res.Header.Get("Location")), nil 349} 350 351// GetAuthorization retrieves an authorization identified by the given URL. 352// 353// If a caller needs to poll an authorization until its status is final, 354// see the WaitAuthorization method. 355func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) { 356 res, err := c.get(ctx, url) 357 if err != nil { 358 return nil, err 359 } 360 defer res.Body.Close() 361 if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { 362 return nil, responseError(res) 363 } 364 var v wireAuthz 365 if err := json.NewDecoder(res.Body).Decode(&v); err != nil { 366 return nil, fmt.Errorf("acme: invalid response: %v", err) 367 } 368 return v.authorization(url), nil 369} 370 371// RevokeAuthorization relinquishes an existing authorization identified 372// by the given URL. 373// The url argument is an Authorization.URI value. 374// 375// If successful, the caller will be required to obtain a new authorization 376// using the Authorize method before being able to request a new certificate 377// for the domain associated with the authorization. 378// 379// It does not revoke existing certificates. 380func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { 381 req := struct { 382 Resource string `json:"resource"` 383 Status string `json:"status"` 384 Delete bool `json:"delete"` 385 }{ 386 Resource: "authz", 387 Status: "deactivated", 388 Delete: true, 389 } 390 res, err := c.retryPostJWS(ctx, c.Key, url, req) 391 if err != nil { 392 return err 393 } 394 defer res.Body.Close() 395 if res.StatusCode != http.StatusOK { 396 return responseError(res) 397 } 398 return nil 399} 400 401// WaitAuthorization polls an authorization at the given URL 402// until it is in one of the final states, StatusValid or StatusInvalid, 403// or the context is done. 404// 405// It returns a non-nil Authorization only if its Status is StatusValid. 406// In all other cases WaitAuthorization returns an error. 407// If the Status is StatusInvalid, the returned error is of type *AuthorizationError. 408func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) { 409 sleep := sleeper(ctx) 410 for { 411 res, err := c.get(ctx, url) 412 if err != nil { 413 return nil, err 414 } 415 retry := res.Header.Get("Retry-After") 416 if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { 417 res.Body.Close() 418 if err := sleep(retry, 1); err != nil { 419 return nil, err 420 } 421 continue 422 } 423 var raw wireAuthz 424 err = json.NewDecoder(res.Body).Decode(&raw) 425 res.Body.Close() 426 if err != nil { 427 if err := sleep(retry, 0); err != nil { 428 return nil, err 429 } 430 continue 431 } 432 if raw.Status == StatusValid { 433 return raw.authorization(url), nil 434 } 435 if raw.Status == StatusInvalid { 436 return nil, raw.error(url) 437 } 438 if err := sleep(retry, 0); err != nil { 439 return nil, err 440 } 441 } 442} 443 444// GetChallenge retrieves the current status of an challenge. 445// 446// A client typically polls a challenge status using this method. 447func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) { 448 res, err := c.get(ctx, url) 449 if err != nil { 450 return nil, err 451 } 452 defer res.Body.Close() 453 if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { 454 return nil, responseError(res) 455 } 456 v := wireChallenge{URI: url} 457 if err := json.NewDecoder(res.Body).Decode(&v); err != nil { 458 return nil, fmt.Errorf("acme: invalid response: %v", err) 459 } 460 return v.challenge(), nil 461} 462 463// Accept informs the server that the client accepts one of its challenges 464// previously obtained with c.Authorize. 465// 466// The server will then perform the validation asynchronously. 467func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) { 468 auth, err := keyAuth(c.Key.Public(), chal.Token) 469 if err != nil { 470 return nil, err 471 } 472 473 req := struct { 474 Resource string `json:"resource"` 475 Type string `json:"type"` 476 Auth string `json:"keyAuthorization"` 477 }{ 478 Resource: "challenge", 479 Type: chal.Type, 480 Auth: auth, 481 } 482 res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req) 483 if err != nil { 484 return nil, err 485 } 486 defer res.Body.Close() 487 // Note: the protocol specifies 200 as the expected response code, but 488 // letsencrypt seems to be returning 202. 489 if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { 490 return nil, responseError(res) 491 } 492 493 var v wireChallenge 494 if err := json.NewDecoder(res.Body).Decode(&v); err != nil { 495 return nil, fmt.Errorf("acme: invalid response: %v", err) 496 } 497 return v.challenge(), nil 498} 499 500// DNS01ChallengeRecord returns a DNS record value for a dns-01 challenge response. 501// A TXT record containing the returned value must be provisioned under 502// "_acme-challenge" name of the domain being validated. 503// 504// The token argument is a Challenge.Token value. 505func (c *Client) DNS01ChallengeRecord(token string) (string, error) { 506 ka, err := keyAuth(c.Key.Public(), token) 507 if err != nil { 508 return "", err 509 } 510 b := sha256.Sum256([]byte(ka)) 511 return base64.RawURLEncoding.EncodeToString(b[:]), nil 512} 513 514// HTTP01ChallengeResponse returns the response for an http-01 challenge. 515// Servers should respond with the value to HTTP requests at the URL path 516// provided by HTTP01ChallengePath to validate the challenge and prove control 517// over a domain name. 518// 519// The token argument is a Challenge.Token value. 520func (c *Client) HTTP01ChallengeResponse(token string) (string, error) { 521 return keyAuth(c.Key.Public(), token) 522} 523 524// HTTP01ChallengePath returns the URL path at which the response for an http-01 challenge 525// should be provided by the servers. 526// The response value can be obtained with HTTP01ChallengeResponse. 527// 528// The token argument is a Challenge.Token value. 529func (c *Client) HTTP01ChallengePath(token string) string { 530 return "/.well-known/acme-challenge/" + token 531} 532 533// TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response. 534// Servers can present the certificate to validate the challenge and prove control 535// over a domain name. 536// 537// The implementation is incomplete in that the returned value is a single certificate, 538// computed only for Z0 of the key authorization. ACME CAs are expected to update 539// their implementations to use the newer version, TLS-SNI-02. 540// For more details on TLS-SNI-01 see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3. 541// 542// The token argument is a Challenge.Token value. 543// If a WithKey option is provided, its private part signs the returned cert, 544// and the public part is used to specify the signee. 545// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. 546// 547// The returned certificate is valid for the next 24 hours and must be presented only when 548// the server name of the client hello matches exactly the returned name value. 549func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { 550 ka, err := keyAuth(c.Key.Public(), token) 551 if err != nil { 552 return tls.Certificate{}, "", err 553 } 554 b := sha256.Sum256([]byte(ka)) 555 h := hex.EncodeToString(b[:]) 556 name = fmt.Sprintf("%s.%s.acme.invalid", h[:32], h[32:]) 557 cert, err = tlsChallengeCert([]string{name}, opt) 558 if err != nil { 559 return tls.Certificate{}, "", err 560 } 561 return cert, name, nil 562} 563 564// TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response. 565// Servers can present the certificate to validate the challenge and prove control 566// over a domain name. For more details on TLS-SNI-02 see 567// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3. 568// 569// The token argument is a Challenge.Token value. 570// If a WithKey option is provided, its private part signs the returned cert, 571// and the public part is used to specify the signee. 572// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. 573// 574// The returned certificate is valid for the next 24 hours and must be presented only when 575// the server name in the client hello matches exactly the returned name value. 576func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { 577 b := sha256.Sum256([]byte(token)) 578 h := hex.EncodeToString(b[:]) 579 sanA := fmt.Sprintf("%s.%s.token.acme.invalid", h[:32], h[32:]) 580 581 ka, err := keyAuth(c.Key.Public(), token) 582 if err != nil { 583 return tls.Certificate{}, "", err 584 } 585 b = sha256.Sum256([]byte(ka)) 586 h = hex.EncodeToString(b[:]) 587 sanB := fmt.Sprintf("%s.%s.ka.acme.invalid", h[:32], h[32:]) 588 589 cert, err = tlsChallengeCert([]string{sanA, sanB}, opt) 590 if err != nil { 591 return tls.Certificate{}, "", err 592 } 593 return cert, sanA, nil 594} 595 596// doReg sends all types of registration requests. 597// The type of request is identified by typ argument, which is a "resource" 598// in the ACME spec terms. 599// 600// A non-nil acct argument indicates whether the intention is to mutate data 601// of the Account. Only Contact and Agreement of its fields are used 602// in such cases. 603func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Account) (*Account, error) { 604 req := struct { 605 Resource string `json:"resource"` 606 Contact []string `json:"contact,omitempty"` 607 Agreement string `json:"agreement,omitempty"` 608 }{ 609 Resource: typ, 610 } 611 if acct != nil { 612 req.Contact = acct.Contact 613 req.Agreement = acct.AgreedTerms 614 } 615 res, err := c.retryPostJWS(ctx, c.Key, url, req) 616 if err != nil { 617 return nil, err 618 } 619 defer res.Body.Close() 620 if res.StatusCode < 200 || res.StatusCode > 299 { 621 return nil, responseError(res) 622 } 623 624 var v struct { 625 Contact []string 626 Agreement string 627 Authorizations string 628 Certificates string 629 } 630 if err := json.NewDecoder(res.Body).Decode(&v); err != nil { 631 return nil, fmt.Errorf("acme: invalid response: %v", err) 632 } 633 var tos string 634 if v := linkHeader(res.Header, "terms-of-service"); len(v) > 0 { 635 tos = v[0] 636 } 637 var authz string 638 if v := linkHeader(res.Header, "next"); len(v) > 0 { 639 authz = v[0] 640 } 641 return &Account{ 642 URI: res.Header.Get("Location"), 643 Contact: v.Contact, 644 AgreedTerms: v.Agreement, 645 CurrentTerms: tos, 646 Authz: authz, 647 Authorizations: v.Authorizations, 648 Certificates: v.Certificates, 649 }, nil 650} 651 652// retryPostJWS will retry calls to postJWS if there is a badNonce error, 653// clearing the stored nonces after each error. 654// If the response was 4XX-5XX, then responseError is called on the body, 655// the body is closed, and the error returned. 656func (c *Client) retryPostJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) { 657 sleep := sleeper(ctx) 658 for { 659 res, err := c.postJWS(ctx, key, url, body) 660 if err != nil { 661 return nil, err 662 } 663 // handle errors 4XX-5XX with responseError 664 if res.StatusCode >= 400 && res.StatusCode <= 599 { 665 err := responseError(res) 666 res.Body.Close() 667 // according to spec badNonce is urn:ietf:params:acme:error:badNonce 668 // however, acme servers in the wild return their version of the error 669 // https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4 670 if ae, ok := err.(*Error); ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") { 671 // clear any nonces that we might've stored that might now be 672 // considered bad 673 c.clearNonces() 674 retry := res.Header.Get("Retry-After") 675 if err := sleep(retry, 1); err != nil { 676 return nil, err 677 } 678 continue 679 } 680 return nil, err 681 } 682 return res, nil 683 } 684} 685 686// postJWS signs the body with the given key and POSTs it to the provided url. 687// The body argument must be JSON-serializable. 688func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) { 689 nonce, err := c.popNonce(ctx, url) 690 if err != nil { 691 return nil, err 692 } 693 b, err := jwsEncodeJSON(body, key, nonce) 694 if err != nil { 695 return nil, err 696 } 697 res, err := c.post(ctx, url, "application/jose+json", bytes.NewReader(b)) 698 if err != nil { 699 return nil, err 700 } 701 c.addNonce(res.Header) 702 return res, nil 703} 704 705// popNonce returns a nonce value previously stored with c.addNonce 706// or fetches a fresh one from the given URL. 707func (c *Client) popNonce(ctx context.Context, url string) (string, error) { 708 c.noncesMu.Lock() 709 defer c.noncesMu.Unlock() 710 if len(c.nonces) == 0 { 711 return c.fetchNonce(ctx, url) 712 } 713 var nonce string 714 for nonce = range c.nonces { 715 delete(c.nonces, nonce) 716 break 717 } 718 return nonce, nil 719} 720 721// clearNonces clears any stored nonces 722func (c *Client) clearNonces() { 723 c.noncesMu.Lock() 724 defer c.noncesMu.Unlock() 725 c.nonces = make(map[string]struct{}) 726} 727 728// addNonce stores a nonce value found in h (if any) for future use. 729func (c *Client) addNonce(h http.Header) { 730 v := nonceFromHeader(h) 731 if v == "" { 732 return 733 } 734 c.noncesMu.Lock() 735 defer c.noncesMu.Unlock() 736 if len(c.nonces) >= maxNonces { 737 return 738 } 739 if c.nonces == nil { 740 c.nonces = make(map[string]struct{}) 741 } 742 c.nonces[v] = struct{}{} 743} 744 745func (c *Client) httpClient() *http.Client { 746 if c.HTTPClient != nil { 747 return c.HTTPClient 748 } 749 return http.DefaultClient 750} 751 752func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) { 753 req, err := http.NewRequest("GET", urlStr, nil) 754 if err != nil { 755 return nil, err 756 } 757 return c.do(ctx, req) 758} 759 760func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) { 761 req, err := http.NewRequest("HEAD", urlStr, nil) 762 if err != nil { 763 return nil, err 764 } 765 return c.do(ctx, req) 766} 767 768func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) { 769 req, err := http.NewRequest("POST", urlStr, body) 770 if err != nil { 771 return nil, err 772 } 773 req.Header.Set("Content-Type", contentType) 774 return c.do(ctx, req) 775} 776 777func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) { 778 res, err := c.httpClient().Do(req.WithContext(ctx)) 779 if err != nil { 780 select { 781 case <-ctx.Done(): 782 // Prefer the unadorned context error. 783 // (The acme package had tests assuming this, previously from ctxhttp's 784 // behavior, predating net/http supporting contexts natively) 785 // TODO(bradfitz): reconsider this in the future. But for now this 786 // requires no test updates. 787 return nil, ctx.Err() 788 default: 789 return nil, err 790 } 791 } 792 return res, nil 793} 794 795func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) { 796 resp, err := c.head(ctx, url) 797 if err != nil { 798 return "", err 799 } 800 defer resp.Body.Close() 801 nonce := nonceFromHeader(resp.Header) 802 if nonce == "" { 803 if resp.StatusCode > 299 { 804 return "", responseError(resp) 805 } 806 return "", errors.New("acme: nonce not found") 807 } 808 return nonce, nil 809} 810 811func nonceFromHeader(h http.Header) string { 812 return h.Get("Replay-Nonce") 813} 814 815func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bool) ([][]byte, error) { 816 b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1)) 817 if err != nil { 818 return nil, fmt.Errorf("acme: response stream: %v", err) 819 } 820 if len(b) > maxCertSize { 821 return nil, errors.New("acme: certificate is too big") 822 } 823 cert := [][]byte{b} 824 if !bundle { 825 return cert, nil 826 } 827 828 // Append CA chain cert(s). 829 // At least one is required according to the spec: 830 // https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3.1 831 up := linkHeader(res.Header, "up") 832 if len(up) == 0 { 833 return nil, errors.New("acme: rel=up link not found") 834 } 835 if len(up) > maxChainLen { 836 return nil, errors.New("acme: rel=up link is too large") 837 } 838 for _, url := range up { 839 cc, err := c.chainCert(ctx, url, 0) 840 if err != nil { 841 return nil, err 842 } 843 cert = append(cert, cc...) 844 } 845 return cert, nil 846} 847 848// responseError creates an error of Error type from resp. 849func responseError(resp *http.Response) error { 850 // don't care if ReadAll returns an error: 851 // json.Unmarshal will fail in that case anyway 852 b, _ := ioutil.ReadAll(resp.Body) 853 e := &wireError{Status: resp.StatusCode} 854 if err := json.Unmarshal(b, e); err != nil { 855 // this is not a regular error response: 856 // populate detail with anything we received, 857 // e.Status will already contain HTTP response code value 858 e.Detail = string(b) 859 if e.Detail == "" { 860 e.Detail = resp.Status 861 } 862 } 863 return e.error(resp.Header) 864} 865 866// chainCert fetches CA certificate chain recursively by following "up" links. 867// Each recursive call increments the depth by 1, resulting in an error 868// if the recursion level reaches maxChainLen. 869// 870// First chainCert call starts with depth of 0. 871func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte, error) { 872 if depth >= maxChainLen { 873 return nil, errors.New("acme: certificate chain is too deep") 874 } 875 876 res, err := c.get(ctx, url) 877 if err != nil { 878 return nil, err 879 } 880 defer res.Body.Close() 881 if res.StatusCode != http.StatusOK { 882 return nil, responseError(res) 883 } 884 b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1)) 885 if err != nil { 886 return nil, err 887 } 888 if len(b) > maxCertSize { 889 return nil, errors.New("acme: certificate is too big") 890 } 891 chain := [][]byte{b} 892 893 uplink := linkHeader(res.Header, "up") 894 if len(uplink) > maxChainLen { 895 return nil, errors.New("acme: certificate chain is too large") 896 } 897 for _, up := range uplink { 898 cc, err := c.chainCert(ctx, up, depth+1) 899 if err != nil { 900 return nil, err 901 } 902 chain = append(chain, cc...) 903 } 904 905 return chain, nil 906} 907 908// linkHeader returns URI-Reference values of all Link headers 909// with relation-type rel. 910// See https://tools.ietf.org/html/rfc5988#section-5 for details. 911func linkHeader(h http.Header, rel string) []string { 912 var links []string 913 for _, v := range h["Link"] { 914 parts := strings.Split(v, ";") 915 for _, p := range parts { 916 p = strings.TrimSpace(p) 917 if !strings.HasPrefix(p, "rel=") { 918 continue 919 } 920 if v := strings.Trim(p[4:], `"`); v == rel { 921 links = append(links, strings.Trim(parts[0], "<>")) 922 } 923 } 924 } 925 return links 926} 927 928// sleeper returns a function that accepts the Retry-After HTTP header value 929// and an increment that's used with backoff to increasingly sleep on 930// consecutive calls until the context is done. If the Retry-After header 931// cannot be parsed, then backoff is used with a maximum sleep time of 10 932// seconds. 933func sleeper(ctx context.Context) func(ra string, inc int) error { 934 var count int 935 return func(ra string, inc int) error { 936 count += inc 937 d := backoff(count, 10*time.Second) 938 d = retryAfter(ra, d) 939 wakeup := time.NewTimer(d) 940 defer wakeup.Stop() 941 select { 942 case <-ctx.Done(): 943 return ctx.Err() 944 case <-wakeup.C: 945 return nil 946 } 947 } 948} 949 950// retryAfter parses a Retry-After HTTP header value, 951// trying to convert v into an int (seconds) or use http.ParseTime otherwise. 952// It returns d if v cannot be parsed. 953func retryAfter(v string, d time.Duration) time.Duration { 954 if i, err := strconv.Atoi(v); err == nil { 955 return time.Duration(i) * time.Second 956 } 957 t, err := http.ParseTime(v) 958 if err != nil { 959 return d 960 } 961 return t.Sub(timeNow()) 962} 963 964// backoff computes a duration after which an n+1 retry iteration should occur 965// using truncated exponential backoff algorithm. 966// 967// The n argument is always bounded between 0 and 30. 968// The max argument defines upper bound for the returned value. 969func backoff(n int, max time.Duration) time.Duration { 970 if n < 0 { 971 n = 0 972 } 973 if n > 30 { 974 n = 30 975 } 976 var d time.Duration 977 if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil { 978 d = time.Duration(x.Int64()) * time.Millisecond 979 } 980 d += time.Duration(1<<uint(n)) * time.Second 981 if d > max { 982 return max 983 } 984 return d 985} 986 987// keyAuth generates a key authorization string for a given token. 988func keyAuth(pub crypto.PublicKey, token string) (string, error) { 989 th, err := JWKThumbprint(pub) 990 if err != nil { 991 return "", err 992 } 993 return fmt.Sprintf("%s.%s", token, th), nil 994} 995 996// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges 997// with the given SANs and auto-generated public/private key pair. 998// The Subject Common Name is set to the first SAN to aid debugging. 999// To create a cert with a custom key pair, specify WithKey option. 1000func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { 1001 var ( 1002 key crypto.Signer 1003 tmpl *x509.Certificate 1004 ) 1005 for _, o := range opt { 1006 switch o := o.(type) { 1007 case *certOptKey: 1008 if key != nil { 1009 return tls.Certificate{}, errors.New("acme: duplicate key option") 1010 } 1011 key = o.key 1012 case *certOptTemplate: 1013 var t = *(*x509.Certificate)(o) // shallow copy is ok 1014 tmpl = &t 1015 default: 1016 // package's fault, if we let this happen: 1017 panic(fmt.Sprintf("unsupported option type %T", o)) 1018 } 1019 } 1020 if key == nil { 1021 var err error 1022 if key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil { 1023 return tls.Certificate{}, err 1024 } 1025 } 1026 if tmpl == nil { 1027 tmpl = &x509.Certificate{ 1028 SerialNumber: big.NewInt(1), 1029 NotBefore: time.Now(), 1030 NotAfter: time.Now().Add(24 * time.Hour), 1031 BasicConstraintsValid: true, 1032 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 1033 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 1034 } 1035 } 1036 tmpl.DNSNames = san 1037 if len(san) > 0 { 1038 tmpl.Subject.CommonName = san[0] 1039 } 1040 1041 der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) 1042 if err != nil { 1043 return tls.Certificate{}, err 1044 } 1045 return tls.Certificate{ 1046 Certificate: [][]byte{der}, 1047 PrivateKey: key, 1048 }, nil 1049} 1050 1051// encodePEM returns b encoded as PEM with block of type typ. 1052func encodePEM(typ string, b []byte) []byte { 1053 pb := &pem.Block{Type: typ, Bytes: b} 1054 return pem.EncodeToMemory(pb) 1055} 1056 1057// timeNow is useful for testing for fixed current time. 1058var timeNow = time.Now 1059