~juju-qa/ubuntu/xenial/juju/2.0-rc2

« back to all changes in this revision

Viewing changes to src/golang.org/x/crypto/acme/acme.go

  • Committer: Nicholas Skaggs
  • Date: 2016-09-30 14:39:30 UTC
  • mfrom: (1.8.1)
  • Revision ID: nicholas.skaggs@canonical.com-20160930143930-vwwhrefh6ftckccy
import upstream

Show diffs side-by-side

added added

removed removed

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