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