From d7129803488e81e6df691161b774908bf801e527 Mon Sep 17 00:00:00 2001
From: Niall Sheridan <nsheridan@gmail.com>
Date: Wed, 28 Dec 2016 14:54:57 +0000
Subject: [PATCH] Add LetsEncrypt support

When configured the server will request a TLS certificate for the specified server name from LetsEncrypt
---
 README.md                                     |   2 +
 cmd/cashierd/main.go                          |  18 +-
 server/config/config.go                       |  24 +-
 vendor/golang.org/x/crypto/acme/acme.go       | 946 ++++++++++++++++++
 .../x/crypto/acme/autocert/autocert.go        | 793 +++++++++++++++
 .../x/crypto/acme/autocert/cache.go           | 130 +++
 .../x/crypto/acme/autocert/renewal.go         | 125 +++
 vendor/golang.org/x/crypto/acme/jws.go        | 153 +++
 vendor/golang.org/x/crypto/acme/types.go      | 209 ++++
 vendor/vendor.json                            |  12 +
 10 files changed, 2397 insertions(+), 15 deletions(-)
 create mode 100644 vendor/golang.org/x/crypto/acme/acme.go
 create mode 100644 vendor/golang.org/x/crypto/acme/autocert/autocert.go
 create mode 100644 vendor/golang.org/x/crypto/acme/autocert/cache.go
 create mode 100644 vendor/golang.org/x/crypto/acme/autocert/renewal.go
 create mode 100644 vendor/golang.org/x/crypto/acme/jws.go
 create mode 100644 vendor/golang.org/x/crypto/acme/types.go

diff --git a/README.md b/README.md
index 493f60cc..a9d68a61 100644
--- a/README.md
+++ b/README.md
@@ -103,6 +103,8 @@ For any option that takes a file path as a parameter (e.g. SSH signing key, TLS
 - `use_tls` : boolean. If this is set then `tls_key` and `tls_cert` are required.
 - `tls_key` : string. Path to the TLS key. See the [note](#a-note-on-files) on files above.
 - `tls_cert` : string. Path to the TLS cert. See the [note](#a-note-on-files) on files above.
+- `letsencrypt_servername`: string. If set will request a certificate from LetsEncrypt. This should match the expected FQDN of the server.
+- `letsencrypt_cachedir: string. Directory to cache the LetsEncrypt certificate.
 - `address` : string. IP address to listen on. If unset the server listens on all addresses.
 - `port` : int. Port to listen on.
 - `user` : string. User to which the server drops privileges to.
diff --git a/cmd/cashierd/main.go b/cmd/cashierd/main.go
index 7df85e6d..12d744db 100644
--- a/cmd/cashierd/main.go
+++ b/cmd/cashierd/main.go
@@ -18,6 +18,7 @@ import (
 	"strings"
 
 	"go4.org/wkfs"
+	"golang.org/x/crypto/acme/autocert"
 	"golang.org/x/oauth2"
 
 	"github.com/gorilla/csrf"
@@ -342,10 +343,19 @@ func main() {
 
 	tlsConfig := &tls.Config{}
 	if config.Server.UseTLS {
-		tlsConfig.Certificates = make([]tls.Certificate, 1)
-		tlsConfig.Certificates[0], err = loadCerts(config.Server.TLSCert, config.Server.TLSKey)
-		if err != nil {
-			log.Fatal(err)
+		if config.Server.LetsEncryptServername != "" {
+			m := autocert.Manager{
+				Prompt:     autocert.AcceptTOS,
+				Cache:      autocert.DirCache(config.Server.LetsEncryptCache),
+				HostPolicy: autocert.HostWhitelist(config.Server.LetsEncryptServername),
+			}
+			tlsConfig.GetCertificate = m.GetCertificate
+		} else {
+			tlsConfig.Certificates = make([]tls.Certificate, 1)
+			tlsConfig.Certificates[0], err = loadCerts(config.Server.TLSCert, config.Server.TLSKey)
+			if err != nil {
+				log.Fatal(err)
+			}
 		}
 		l = tls.NewListener(l, tlsConfig)
 	}
diff --git a/server/config/config.go b/server/config/config.go
index 2d821f9b..5f3f458c 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -29,17 +29,19 @@ type Database map[string]string
 
 // Server holds the configuration specific to the web server and sessions.
 type Server struct {
-	UseTLS       bool     `mapstructure:"use_tls"`
-	TLSKey       string   `mapstructure:"tls_key"`
-	TLSCert      string   `mapstructure:"tls_cert"`
-	Addr         string   `mapstructure:"address"`
-	Port         int      `mapstructure:"port"`
-	User         string   `mapstructure:"user"`
-	CookieSecret string   `mapstructure:"cookie_secret"`
-	CSRFSecret   string   `mapstructure:"csrf_secret"`
-	HTTPLogFile  string   `mapstructure:"http_logfile"`
-	Database     Database `mapstructure:"database"`
-	Datastore    string   `mapstructure:"datastore"` // Deprecated. TODO: remove.
+	UseTLS                bool     `mapstructure:"use_tls"`
+	TLSKey                string   `mapstructure:"tls_key"`
+	TLSCert               string   `mapstructure:"tls_cert"`
+	LetsEncryptServername string   `mapstructure:"letsencrypt_servername"`
+	LetsEncryptCache      string   `mapstructure:"letsencrypt_cachedir"`
+	Addr                  string   `mapstructure:"address"`
+	Port                  int      `mapstructure:"port"`
+	User                  string   `mapstructure:"user"`
+	CookieSecret          string   `mapstructure:"cookie_secret"`
+	CSRFSecret            string   `mapstructure:"csrf_secret"`
+	HTTPLogFile           string   `mapstructure:"http_logfile"`
+	Database              Database `mapstructure:"database"`
+	Datastore             string   `mapstructure:"datastore"` // Deprecated. TODO: remove.
 }
 
 // Auth holds the configuration specific to the OAuth provider.
diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go
new file mode 100644
index 00000000..8aafada0
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/acme.go
@@ -0,0 +1,946 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package acme provides an implementation of the
+// Automatic Certificate Management Environment (ACME) spec.
+// See https://tools.ietf.org/html/draft-ietf-acme-acme-02 for details.
+//
+// Most common scenarios will want to use autocert subdirectory instead,
+// which provides automatic access to certificates from Let's Encrypt
+// and any other ACME-based CA.
+//
+// This package is a work in progress and makes no API stability promises.
+package acme
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/sha256"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"math/big"
+	"net/http"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"golang.org/x/net/context"
+	"golang.org/x/net/context/ctxhttp"
+)
+
+// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
+const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
+
+const (
+	maxChainLen = 5       // max depth and breadth of a certificate chain
+	maxCertSize = 1 << 20 // max size of a certificate, in bytes
+)
+
+// CertOption is an optional argument type for Client methods which manipulate
+// certificate data.
+type CertOption interface {
+	privateCertOpt()
+}
+
+// WithKey creates an option holding a private/public key pair.
+// The private part signs a certificate, and the public part represents the signee.
+func WithKey(key crypto.Signer) CertOption {
+	return &certOptKey{key}
+}
+
+type certOptKey struct {
+	key crypto.Signer
+}
+
+func (*certOptKey) privateCertOpt() {}
+
+// WithTemplate creates an option for specifying a certificate template.
+// See x509.CreateCertificate for template usage details.
+//
+// In TLSSNIxChallengeCert methods, the template is also used as parent,
+// resulting in a self-signed certificate.
+// The DNSNames field of t is always overwritten for tls-sni challenge certs.
+func WithTemplate(t *x509.Certificate) CertOption {
+	return (*certOptTemplate)(t)
+}
+
+type certOptTemplate x509.Certificate
+
+func (*certOptTemplate) privateCertOpt() {}
+
+// Client is an ACME client.
+// The only required field is Key. An example of creating a client with a new key
+// is as follows:
+//
+// 	key, err := rsa.GenerateKey(rand.Reader, 2048)
+// 	if err != nil {
+// 		log.Fatal(err)
+// 	}
+// 	client := &Client{Key: key}
+//
+type Client struct {
+	// Key is the account key used to register with a CA and sign requests.
+	// Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey.
+	Key crypto.Signer
+
+	// HTTPClient optionally specifies an HTTP client to use
+	// instead of http.DefaultClient.
+	HTTPClient *http.Client
+
+	// DirectoryURL points to the CA directory endpoint.
+	// If empty, LetsEncryptURL is used.
+	// Mutating this value after a successful call of Client's Discover method
+	// will have no effect.
+	DirectoryURL string
+
+	dirMu sync.Mutex // guards writes to dir
+	dir   *Directory // cached result of Client's Discover method
+}
+
+// Discover performs ACME server discovery using c.DirectoryURL.
+//
+// It caches successful result. So, subsequent calls will not result in
+// a network round-trip. This also means mutating c.DirectoryURL after successful call
+// of this method will have no effect.
+func (c *Client) Discover(ctx context.Context) (Directory, error) {
+	c.dirMu.Lock()
+	defer c.dirMu.Unlock()
+	if c.dir != nil {
+		return *c.dir, nil
+	}
+
+	dirURL := c.DirectoryURL
+	if dirURL == "" {
+		dirURL = LetsEncryptURL
+	}
+	res, err := ctxhttp.Get(ctx, c.HTTPClient, dirURL)
+	if err != nil {
+		return Directory{}, err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		return Directory{}, responseError(res)
+	}
+
+	var v struct {
+		Reg    string `json:"new-reg"`
+		Authz  string `json:"new-authz"`
+		Cert   string `json:"new-cert"`
+		Revoke string `json:"revoke-cert"`
+		Meta   struct {
+			Terms   string   `json:"terms-of-service"`
+			Website string   `json:"website"`
+			CAA     []string `json:"caa-identities"`
+		}
+	}
+	if json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return Directory{}, err
+	}
+	c.dir = &Directory{
+		RegURL:    v.Reg,
+		AuthzURL:  v.Authz,
+		CertURL:   v.Cert,
+		RevokeURL: v.Revoke,
+		Terms:     v.Meta.Terms,
+		Website:   v.Meta.Website,
+		CAA:       v.Meta.CAA,
+	}
+	return *c.dir, nil
+}
+
+// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format.
+// The exp argument indicates the desired certificate validity duration. CA may issue a certificate
+// with a different duration.
+// If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain.
+//
+// In the case where CA server does not provide the issued certificate in the response,
+// CreateCert will poll certURL using c.FetchCert, which will result in additional round-trips.
+// In such scenario the caller can cancel the polling with ctx.
+//
+// CreateCert returns an error if the CA's response or chain was unreasonably large.
+// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
+func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) {
+	if _, err := c.Discover(ctx); err != nil {
+		return nil, "", err
+	}
+
+	req := struct {
+		Resource  string `json:"resource"`
+		CSR       string `json:"csr"`
+		NotBefore string `json:"notBefore,omitempty"`
+		NotAfter  string `json:"notAfter,omitempty"`
+	}{
+		Resource: "new-cert",
+		CSR:      base64.RawURLEncoding.EncodeToString(csr),
+	}
+	now := timeNow()
+	req.NotBefore = now.Format(time.RFC3339)
+	if exp > 0 {
+		req.NotAfter = now.Add(exp).Format(time.RFC3339)
+	}
+
+	res, err := postJWS(ctx, c.HTTPClient, c.Key, c.dir.CertURL, req)
+	if err != nil {
+		return nil, "", err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusCreated {
+		return nil, "", responseError(res)
+	}
+
+	curl := res.Header.Get("location") // cert permanent URL
+	if res.ContentLength == 0 {
+		// no cert in the body; poll until we get it
+		cert, err := c.FetchCert(ctx, curl, bundle)
+		return cert, curl, err
+	}
+	// slurp issued cert and CA chain, if requested
+	cert, err := responseCert(ctx, c.HTTPClient, res, bundle)
+	return cert, curl, err
+}
+
+// FetchCert retrieves already issued certificate from the given url, in DER format.
+// It retries the request until the certificate is successfully retrieved,
+// context is cancelled by the caller or an error response is received.
+//
+// The returned value will also contain the CA (issuer) certificate if the bundle argument is true.
+//
+// FetchCert returns an error if the CA's response or chain was unreasonably large.
+// Callers are encouraged to parse the returned value to ensure the certificate is valid
+// and has expected features.
+func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
+	for {
+		res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
+		if err != nil {
+			return nil, err
+		}
+		defer res.Body.Close()
+		if res.StatusCode == http.StatusOK {
+			return responseCert(ctx, c.HTTPClient, res, bundle)
+		}
+		if res.StatusCode > 299 {
+			return nil, responseError(res)
+		}
+		d := retryAfter(res.Header.Get("retry-after"), 3*time.Second)
+		select {
+		case <-time.After(d):
+			// retry
+		case <-ctx.Done():
+			return nil, ctx.Err()
+		}
+	}
+}
+
+// RevokeCert revokes a previously issued certificate cert, provided in DER format.
+//
+// The key argument, used to sign the request, must be authorized
+// to revoke the certificate. It's up to the CA to decide which keys are authorized.
+// For instance, the key pair of the certificate may be authorized.
+// If the key is nil, c.Key is used instead.
+func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
+	if _, err := c.Discover(ctx); err != nil {
+		return err
+	}
+
+	body := &struct {
+		Resource string `json:"resource"`
+		Cert     string `json:"certificate"`
+		Reason   int    `json:"reason"`
+	}{
+		Resource: "revoke-cert",
+		Cert:     base64.RawURLEncoding.EncodeToString(cert),
+		Reason:   int(reason),
+	}
+	if key == nil {
+		key = c.Key
+	}
+	res, err := postJWS(ctx, c.HTTPClient, key, c.dir.RevokeURL, body)
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		return responseError(res)
+	}
+	return nil
+}
+
+// AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service
+// during account registration. See Register method of Client for more details.
+func AcceptTOS(tosURL string) bool { return true }
+
+// Register creates a new account registration by following the "new-reg" flow.
+// It returns registered account. The a argument is not modified.
+//
+// The registration may require the caller to agree to the CA's Terms of Service (TOS).
+// If so, and the account has not indicated the acceptance of the terms (see Account for details),
+// Register calls prompt with a TOS URL provided by the CA. Prompt should report
+// whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS.
+func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) {
+	if _, err := c.Discover(ctx); err != nil {
+		return nil, err
+	}
+
+	var err error
+	if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil {
+		return nil, err
+	}
+	var accept bool
+	if a.CurrentTerms != "" && a.CurrentTerms != a.AgreedTerms {
+		accept = prompt(a.CurrentTerms)
+	}
+	if accept {
+		a.AgreedTerms = a.CurrentTerms
+		a, err = c.UpdateReg(ctx, a)
+	}
+	return a, err
+}
+
+// GetReg retrieves an existing registration.
+// The url argument is an Account URI.
+func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) {
+	a, err := c.doReg(ctx, url, "reg", nil)
+	if err != nil {
+		return nil, err
+	}
+	a.URI = url
+	return a, nil
+}
+
+// UpdateReg updates an existing registration.
+// It returns an updated account copy. The provided account is not modified.
+func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) {
+	uri := a.URI
+	a, err := c.doReg(ctx, uri, "reg", a)
+	if err != nil {
+		return nil, err
+	}
+	a.URI = uri
+	return a, nil
+}
+
+// Authorize performs the initial step in an authorization flow.
+// The caller will then need to choose from and perform a set of returned
+// challenges using c.Accept in order to successfully complete authorization.
+//
+// If an authorization has been previously granted, the CA may return
+// a valid authorization (Authorization.Status is StatusValid). If so, the caller
+// need not fulfill any challenge and can proceed to requesting a certificate.
+func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) {
+	if _, err := c.Discover(ctx); err != nil {
+		return nil, err
+	}
+
+	type authzID struct {
+		Type  string `json:"type"`
+		Value string `json:"value"`
+	}
+	req := struct {
+		Resource   string  `json:"resource"`
+		Identifier authzID `json:"identifier"`
+	}{
+		Resource:   "new-authz",
+		Identifier: authzID{Type: "dns", Value: domain},
+	}
+	res, err := postJWS(ctx, c.HTTPClient, c.Key, c.dir.AuthzURL, req)
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusCreated {
+		return nil, responseError(res)
+	}
+
+	var v wireAuthz
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	if v.Status != StatusPending && v.Status != StatusValid {
+		return nil, fmt.Errorf("acme: unexpected status: %s", v.Status)
+	}
+	return v.authorization(res.Header.Get("Location")), nil
+}
+
+// GetAuthorization retrieves an authorization identified by the given URL.
+//
+// If a caller needs to poll an authorization until its status is final,
+// see the WaitAuthorization method.
+func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
+	res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
+		return nil, responseError(res)
+	}
+	var v wireAuthz
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	return v.authorization(url), nil
+}
+
+// RevokeAuthorization relinquishes an existing authorization identified
+// by the given URL.
+// The url argument is an Authorization.URI value.
+//
+// If successful, the caller will be required to obtain a new authorization
+// using the Authorize method before being able to request a new certificate
+// for the domain associated with the authorization.
+//
+// It does not revoke existing certificates.
+func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
+	req := struct {
+		Resource string `json:"resource"`
+		Status   string `json:"status"`
+		Delete   bool   `json:"delete"`
+	}{
+		Resource: "authz",
+		Status:   "deactivated",
+		Delete:   true,
+	}
+	res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req)
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		return responseError(res)
+	}
+	return nil
+}
+
+// WaitAuthorization polls an authorization at the given URL
+// until it is in one of the final states, StatusValid or StatusInvalid,
+// or the context is done.
+//
+// It returns a non-nil Authorization only if its Status is StatusValid.
+// In all other cases WaitAuthorization returns an error.
+// If the Status is StatusInvalid, the returned error is ErrAuthorizationFailed.
+func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
+	var count int
+	sleep := func(v string, inc int) error {
+		count += inc
+		d := backoff(count, 10*time.Second)
+		d = retryAfter(v, d)
+		wakeup := time.NewTimer(d)
+		defer wakeup.Stop()
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		case <-wakeup.C:
+			return nil
+		}
+	}
+
+	for {
+		res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
+		if err != nil {
+			return nil, err
+		}
+		retry := res.Header.Get("retry-after")
+		if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
+			res.Body.Close()
+			if err := sleep(retry, 1); err != nil {
+				return nil, err
+			}
+			continue
+		}
+		var raw wireAuthz
+		err = json.NewDecoder(res.Body).Decode(&raw)
+		res.Body.Close()
+		if err != nil {
+			if err := sleep(retry, 0); err != nil {
+				return nil, err
+			}
+			continue
+		}
+		if raw.Status == StatusValid {
+			return raw.authorization(url), nil
+		}
+		if raw.Status == StatusInvalid {
+			return nil, ErrAuthorizationFailed
+		}
+		if err := sleep(retry, 0); err != nil {
+			return nil, err
+		}
+	}
+}
+
+// GetChallenge retrieves the current status of an challenge.
+//
+// A client typically polls a challenge status using this method.
+func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
+	res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
+		return nil, responseError(res)
+	}
+	v := wireChallenge{URI: url}
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	return v.challenge(), nil
+}
+
+// Accept informs the server that the client accepts one of its challenges
+// previously obtained with c.Authorize.
+//
+// The server will then perform the validation asynchronously.
+func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) {
+	auth, err := keyAuth(c.Key.Public(), chal.Token)
+	if err != nil {
+		return nil, err
+	}
+
+	req := struct {
+		Resource string `json:"resource"`
+		Type     string `json:"type"`
+		Auth     string `json:"keyAuthorization"`
+	}{
+		Resource: "challenge",
+		Type:     chal.Type,
+		Auth:     auth,
+	}
+	res, err := postJWS(ctx, c.HTTPClient, c.Key, chal.URI, req)
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	// Note: the protocol specifies 200 as the expected response code, but
+	// letsencrypt seems to be returning 202.
+	if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
+		return nil, responseError(res)
+	}
+
+	var v wireChallenge
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	return v.challenge(), nil
+}
+
+// DNS01ChallengeRecord returns a DNS record value for a dns-01 challenge response.
+// A TXT record containing the returned value must be provisioned under
+// "_acme-challenge" name of the domain being validated.
+//
+// The token argument is a Challenge.Token value.
+func (c *Client) DNS01ChallengeRecord(token string) (string, error) {
+	ka, err := keyAuth(c.Key.Public(), token)
+	if err != nil {
+		return "", err
+	}
+	b := sha256.Sum256([]byte(ka))
+	return base64.RawURLEncoding.EncodeToString(b[:]), nil
+}
+
+// HTTP01ChallengeResponse returns the response for an http-01 challenge.
+// Servers should respond with the value to HTTP requests at the URL path
+// provided by HTTP01ChallengePath to validate the challenge and prove control
+// over a domain name.
+//
+// The token argument is a Challenge.Token value.
+func (c *Client) HTTP01ChallengeResponse(token string) (string, error) {
+	return keyAuth(c.Key.Public(), token)
+}
+
+// HTTP01ChallengePath returns the URL path at which the response for an http-01 challenge
+// should be provided by the servers.
+// The response value can be obtained with HTTP01ChallengeResponse.
+//
+// The token argument is a Challenge.Token value.
+func (c *Client) HTTP01ChallengePath(token string) string {
+	return "/.well-known/acme-challenge/" + token
+}
+
+// TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response.
+// Servers can present the certificate to validate the challenge and prove control
+// over a domain name.
+//
+// The implementation is incomplete in that the returned value is a single certificate,
+// computed only for Z0 of the key authorization. ACME CAs are expected to update
+// their implementations to use the newer version, TLS-SNI-02.
+// For more details on TLS-SNI-01 see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3.
+//
+// The token argument is a Challenge.Token value.
+// If a WithKey option is provided, its private part signs the returned cert,
+// and the public part is used to specify the signee.
+// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
+//
+// The returned certificate is valid for the next 24 hours and must be presented only when
+// the server name of the client hello matches exactly the returned name value.
+func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
+	ka, err := keyAuth(c.Key.Public(), token)
+	if err != nil {
+		return tls.Certificate{}, "", err
+	}
+	b := sha256.Sum256([]byte(ka))
+	h := hex.EncodeToString(b[:])
+	name = fmt.Sprintf("%s.%s.acme.invalid", h[:32], h[32:])
+	cert, err = tlsChallengeCert([]string{name}, opt)
+	if err != nil {
+		return tls.Certificate{}, "", err
+	}
+	return cert, name, nil
+}
+
+// TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response.
+// Servers can present the certificate to validate the challenge and prove control
+// over a domain name. For more details on TLS-SNI-02 see
+// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3.
+//
+// The token argument is a Challenge.Token value.
+// If a WithKey option is provided, its private part signs the returned cert,
+// and the public part is used to specify the signee.
+// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
+//
+// The returned certificate is valid for the next 24 hours and must be presented only when
+// the server name in the client hello matches exactly the returned name value.
+func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
+	b := sha256.Sum256([]byte(token))
+	h := hex.EncodeToString(b[:])
+	sanA := fmt.Sprintf("%s.%s.token.acme.invalid", h[:32], h[32:])
+
+	ka, err := keyAuth(c.Key.Public(), token)
+	if err != nil {
+		return tls.Certificate{}, "", err
+	}
+	b = sha256.Sum256([]byte(ka))
+	h = hex.EncodeToString(b[:])
+	sanB := fmt.Sprintf("%s.%s.ka.acme.invalid", h[:32], h[32:])
+
+	cert, err = tlsChallengeCert([]string{sanA, sanB}, opt)
+	if err != nil {
+		return tls.Certificate{}, "", err
+	}
+	return cert, sanA, nil
+}
+
+// doReg sends all types of registration requests.
+// The type of request is identified by typ argument, which is a "resource"
+// in the ACME spec terms.
+//
+// A non-nil acct argument indicates whether the intention is to mutate data
+// of the Account. Only Contact and Agreement of its fields are used
+// in such cases.
+func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Account) (*Account, error) {
+	req := struct {
+		Resource  string   `json:"resource"`
+		Contact   []string `json:"contact,omitempty"`
+		Agreement string   `json:"agreement,omitempty"`
+	}{
+		Resource: typ,
+	}
+	if acct != nil {
+		req.Contact = acct.Contact
+		req.Agreement = acct.AgreedTerms
+	}
+	res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req)
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	if res.StatusCode < 200 || res.StatusCode > 299 {
+		return nil, responseError(res)
+	}
+
+	var v struct {
+		Contact        []string
+		Agreement      string
+		Authorizations string
+		Certificates   string
+	}
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	var tos string
+	if v := linkHeader(res.Header, "terms-of-service"); len(v) > 0 {
+		tos = v[0]
+	}
+	var authz string
+	if v := linkHeader(res.Header, "next"); len(v) > 0 {
+		authz = v[0]
+	}
+	return &Account{
+		URI:            res.Header.Get("Location"),
+		Contact:        v.Contact,
+		AgreedTerms:    v.Agreement,
+		CurrentTerms:   tos,
+		Authz:          authz,
+		Authorizations: v.Authorizations,
+		Certificates:   v.Certificates,
+	}, nil
+}
+
+func responseCert(ctx context.Context, client *http.Client, res *http.Response, bundle bool) ([][]byte, error) {
+	b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
+	if err != nil {
+		return nil, fmt.Errorf("acme: response stream: %v", err)
+	}
+	if len(b) > maxCertSize {
+		return nil, errors.New("acme: certificate is too big")
+	}
+	cert := [][]byte{b}
+	if !bundle {
+		return cert, nil
+	}
+
+	// Append CA chain cert(s).
+	// At least one is required according to the spec:
+	// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3.1
+	up := linkHeader(res.Header, "up")
+	if len(up) == 0 {
+		return nil, errors.New("acme: rel=up link not found")
+	}
+	if len(up) > maxChainLen {
+		return nil, errors.New("acme: rel=up link is too large")
+	}
+	for _, url := range up {
+		cc, err := chainCert(ctx, client, url, 0)
+		if err != nil {
+			return nil, err
+		}
+		cert = append(cert, cc...)
+	}
+	return cert, nil
+}
+
+// responseError creates an error of Error type from resp.
+func responseError(resp *http.Response) error {
+	// don't care if ReadAll returns an error:
+	// json.Unmarshal will fail in that case anyway
+	b, _ := ioutil.ReadAll(resp.Body)
+	e := struct {
+		Status int
+		Type   string
+		Detail string
+	}{
+		Status: resp.StatusCode,
+	}
+	if err := json.Unmarshal(b, &e); err != nil {
+		// this is not a regular error response:
+		// populate detail with anything we received,
+		// e.Status will already contain HTTP response code value
+		e.Detail = string(b)
+		if e.Detail == "" {
+			e.Detail = resp.Status
+		}
+	}
+	return &Error{
+		StatusCode:  e.Status,
+		ProblemType: e.Type,
+		Detail:      e.Detail,
+		Header:      resp.Header,
+	}
+}
+
+// chainCert fetches CA certificate chain recursively by following "up" links.
+// Each recursive call increments the depth by 1, resulting in an error
+// if the recursion level reaches maxChainLen.
+//
+// First chainCert call starts with depth of 0.
+func chainCert(ctx context.Context, client *http.Client, url string, depth int) ([][]byte, error) {
+	if depth >= maxChainLen {
+		return nil, errors.New("acme: certificate chain is too deep")
+	}
+
+	res, err := ctxhttp.Get(ctx, client, url)
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		return nil, responseError(res)
+	}
+	b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
+	if err != nil {
+		return nil, err
+	}
+	if len(b) > maxCertSize {
+		return nil, errors.New("acme: certificate is too big")
+	}
+	chain := [][]byte{b}
+
+	uplink := linkHeader(res.Header, "up")
+	if len(uplink) > maxChainLen {
+		return nil, errors.New("acme: certificate chain is too large")
+	}
+	for _, up := range uplink {
+		cc, err := chainCert(ctx, client, up, depth+1)
+		if err != nil {
+			return nil, err
+		}
+		chain = append(chain, cc...)
+	}
+
+	return chain, nil
+}
+
+// postJWS signs the body with the given key and POSTs it to the provided url.
+// The body argument must be JSON-serializable.
+func postJWS(ctx context.Context, client *http.Client, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
+	nonce, err := fetchNonce(ctx, client, url)
+	if err != nil {
+		return nil, err
+	}
+	b, err := jwsEncodeJSON(body, key, nonce)
+	if err != nil {
+		return nil, err
+	}
+	return ctxhttp.Post(ctx, client, url, "application/jose+json", bytes.NewReader(b))
+}
+
+func fetchNonce(ctx context.Context, client *http.Client, url string) (string, error) {
+	resp, err := ctxhttp.Head(ctx, client, url)
+	if err != nil {
+		return "", nil
+	}
+	defer resp.Body.Close()
+	enc := resp.Header.Get("replay-nonce")
+	if enc == "" {
+		return "", errors.New("acme: nonce not found")
+	}
+	return enc, nil
+}
+
+// linkHeader returns URI-Reference values of all Link headers
+// with relation-type rel.
+// See https://tools.ietf.org/html/rfc5988#section-5 for details.
+func linkHeader(h http.Header, rel string) []string {
+	var links []string
+	for _, v := range h["Link"] {
+		parts := strings.Split(v, ";")
+		for _, p := range parts {
+			p = strings.TrimSpace(p)
+			if !strings.HasPrefix(p, "rel=") {
+				continue
+			}
+			if v := strings.Trim(p[4:], `"`); v == rel {
+				links = append(links, strings.Trim(parts[0], "<>"))
+			}
+		}
+	}
+	return links
+}
+
+// retryAfter parses a Retry-After HTTP header value,
+// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
+// It returns d if v cannot be parsed.
+func retryAfter(v string, d time.Duration) time.Duration {
+	if i, err := strconv.Atoi(v); err == nil {
+		return time.Duration(i) * time.Second
+	}
+	t, err := http.ParseTime(v)
+	if err != nil {
+		return d
+	}
+	return t.Sub(timeNow())
+}
+
+// backoff computes a duration after which an n+1 retry iteration should occur
+// using truncated exponential backoff algorithm.
+//
+// The n argument is always bounded between 0 and 30.
+// The max argument defines upper bound for the returned value.
+func backoff(n int, max time.Duration) time.Duration {
+	if n < 0 {
+		n = 0
+	}
+	if n > 30 {
+		n = 30
+	}
+	var d time.Duration
+	if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
+		d = time.Duration(x.Int64()) * time.Millisecond
+	}
+	d += time.Duration(1<<uint(n)) * time.Second
+	if d > max {
+		return max
+	}
+	return d
+}
+
+// keyAuth generates a key authorization string for a given token.
+func keyAuth(pub crypto.PublicKey, token string) (string, error) {
+	th, err := JWKThumbprint(pub)
+	if err != nil {
+		return "", err
+	}
+	return fmt.Sprintf("%s.%s", token, th), nil
+}
+
+// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges
+// with the given SANs and auto-generated public/private key pair.
+// To create a cert with a custom key pair, specify WithKey option.
+func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
+	var (
+		key  crypto.Signer
+		tmpl *x509.Certificate
+	)
+	for _, o := range opt {
+		switch o := o.(type) {
+		case *certOptKey:
+			if key != nil {
+				return tls.Certificate{}, errors.New("acme: duplicate key option")
+			}
+			key = o.key
+		case *certOptTemplate:
+			var t = *(*x509.Certificate)(o) // shallow copy is ok
+			tmpl = &t
+		default:
+			// package's fault, if we let this happen:
+			panic(fmt.Sprintf("unsupported option type %T", o))
+		}
+	}
+	if key == nil {
+		var err error
+		if key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil {
+			return tls.Certificate{}, err
+		}
+	}
+	if tmpl == nil {
+		tmpl = &x509.Certificate{
+			SerialNumber:          big.NewInt(1),
+			NotBefore:             time.Now(),
+			NotAfter:              time.Now().Add(24 * time.Hour),
+			BasicConstraintsValid: true,
+			KeyUsage:              x509.KeyUsageKeyEncipherment,
+		}
+	}
+	tmpl.DNSNames = san
+
+	der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key)
+	if err != nil {
+		return tls.Certificate{}, err
+	}
+	return tls.Certificate{
+		Certificate: [][]byte{der},
+		PrivateKey:  key,
+	}, nil
+}
+
+// encodePEM returns b encoded as PEM with block of type typ.
+func encodePEM(typ string, b []byte) []byte {
+	pb := &pem.Block{Type: typ, Bytes: b}
+	return pem.EncodeToMemory(pb)
+}
+
+// timeNow is useful for testing for fixed current time.
+var timeNow = time.Now
diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
new file mode 100644
index 00000000..4b15816a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
@@ -0,0 +1,793 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package autocert provides automatic access to certificates from Let's Encrypt
+// and any other ACME-based CA.
+//
+// This package is a work in progress and makes no API stability promises.
+package autocert
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/tls"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io"
+	mathrand "math/rand"
+	"net/http"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"golang.org/x/crypto/acme"
+	"golang.org/x/net/context"
+)
+
+// pseudoRand is safe for concurrent use.
+var pseudoRand *lockedMathRand
+
+func init() {
+	src := mathrand.NewSource(timeNow().UnixNano())
+	pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
+}
+
+// AcceptTOS always returns true to indicate the acceptance of a CA Terms of Service
+// during account registration.
+func AcceptTOS(tosURL string) bool { return true }
+
+// HostPolicy specifies which host names the Manager is allowed to respond to.
+// It returns a non-nil error if the host should be rejected.
+// The returned error is accessible via tls.Conn.Handshake and its callers.
+// See Manager's HostPolicy field and GetCertificate method docs for more details.
+type HostPolicy func(ctx context.Context, host string) error
+
+// HostWhitelist returns a policy where only the specified host names are allowed.
+// Only exact matches are currently supported. Subdomains, regexp or wildcard
+// will not match.
+func HostWhitelist(hosts ...string) HostPolicy {
+	whitelist := make(map[string]bool, len(hosts))
+	for _, h := range hosts {
+		whitelist[h] = true
+	}
+	return func(_ context.Context, host string) error {
+		if !whitelist[host] {
+			return errors.New("acme/autocert: host not configured")
+		}
+		return nil
+	}
+}
+
+// defaultHostPolicy is used when Manager.HostPolicy is not set.
+func defaultHostPolicy(context.Context, string) error {
+	return nil
+}
+
+// Manager is a stateful certificate manager built on top of acme.Client.
+// It obtains and refreshes certificates automatically,
+// as well as providing them to a TLS server via tls.Config.
+//
+// A simple usage example:
+//
+//	m := autocert.Manager{
+//		Prompt: autocert.AcceptTOS,
+//		HostPolicy: autocert.HostWhitelist("example.org"),
+//	}
+//	s := &http.Server{
+//		Addr: ":https",
+//		TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
+//	}
+//	s.ListenAndServeTLS("", "")
+//
+// To preserve issued certificates and improve overall performance,
+// use a cache implementation of Cache. For instance, DirCache.
+type Manager struct {
+	// Prompt specifies a callback function to conditionally accept a CA's Terms of Service (TOS).
+	// The registration may require the caller to agree to the CA's TOS.
+	// If so, Manager calls Prompt with a TOS URL provided by the CA. Prompt should report
+	// whether the caller agrees to the terms.
+	//
+	// To always accept the terms, the callers can use AcceptTOS.
+	Prompt func(tosURL string) bool
+
+	// Cache optionally stores and retrieves previously-obtained certificates.
+	// If nil, certs will only be cached for the lifetime of the Manager.
+	//
+	// Manager passes the Cache certificates data encoded in PEM, with private/public
+	// parts combined in a single Cache.Put call, private key first.
+	Cache Cache
+
+	// HostPolicy controls which domains the Manager will attempt
+	// to retrieve new certificates for. It does not affect cached certs.
+	//
+	// If non-nil, HostPolicy is called before requesting a new cert.
+	// If nil, all hosts are currently allowed. This is not recommended,
+	// as it opens a potential attack where clients connect to a server
+	// by IP address and pretend to be asking for an incorrect host name.
+	// Manager will attempt to obtain a certificate for that host, incorrectly,
+	// eventually reaching the CA's rate limit for certificate requests
+	// and making it impossible to obtain actual certificates.
+	//
+	// See GetCertificate for more details.
+	HostPolicy HostPolicy
+
+	// RenewBefore optionally specifies how early certificates should
+	// be renewed before they expire.
+	//
+	// If zero, they're renewed 1 week before expiration.
+	RenewBefore time.Duration
+
+	// Client is used to perform low-level operations, such as account registration
+	// and requesting new certificates.
+	// If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
+	// directory endpoint and a newly-generated ECDSA P-256 key.
+	//
+	// Mutating the field after the first call of GetCertificate method will have no effect.
+	Client *acme.Client
+
+	// Email optionally specifies a contact email address.
+	// This is used by CAs, such as Let's Encrypt, to notify about problems
+	// with issued certificates.
+	//
+	// If the Client's account key is already registered, Email is not used.
+	Email string
+
+	// ForceRSA makes the Manager generate certificates with 2048-bit RSA keys.
+	//
+	// If false, a default is used. Currently the default
+	// is EC-based keys using the P-256 curve.
+	ForceRSA bool
+
+	clientMu sync.Mutex
+	client   *acme.Client // initialized by acmeClient method
+
+	stateMu sync.Mutex
+	state   map[string]*certState // keyed by domain name
+
+	// tokenCert is keyed by token domain name, which matches server name
+	// of ClientHello. Keys always have ".acme.invalid" suffix.
+	tokenCertMu sync.RWMutex
+	tokenCert   map[string]*tls.Certificate
+
+	// renewal tracks the set of domains currently running renewal timers.
+	// It is keyed by domain name.
+	renewalMu sync.Mutex
+	renewal   map[string]*domainRenewal
+}
+
+// GetCertificate implements the tls.Config.GetCertificate hook.
+// It provides a TLS certificate for hello.ServerName host, including answering
+// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored.
+//
+// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
+// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
+// The error is propagated back to the caller of GetCertificate and is user-visible.
+// This does not affect cached certs. See HostPolicy field description for more details.
+func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
+	name := hello.ServerName
+	if name == "" {
+		return nil, errors.New("acme/autocert: missing server name")
+	}
+
+	// check whether this is a token cert requested for TLS-SNI challenge
+	if strings.HasSuffix(name, ".acme.invalid") {
+		m.tokenCertMu.RLock()
+		defer m.tokenCertMu.RUnlock()
+		if cert := m.tokenCert[name]; cert != nil {
+			return cert, nil
+		}
+		if cert, err := m.cacheGet(name); err == nil {
+			return cert, nil
+		}
+		// TODO: cache error results?
+		return nil, fmt.Errorf("acme/autocert: no token cert for %q", name)
+	}
+
+	// regular domain
+	name = strings.TrimSuffix(name, ".") // golang.org/issue/18114
+	cert, err := m.cert(name)
+	if err == nil {
+		return cert, nil
+	}
+	if err != ErrCacheMiss {
+		return nil, err
+	}
+
+	// first-time
+	ctx := context.Background() // TODO: use a deadline?
+	if err := m.hostPolicy()(ctx, name); err != nil {
+		return nil, err
+	}
+	cert, err = m.createCert(ctx, name)
+	if err != nil {
+		return nil, err
+	}
+	m.cachePut(name, cert)
+	return cert, nil
+}
+
+// cert returns an existing certificate either from m.state or cache.
+// If a certificate is found in cache but not in m.state, the latter will be filled
+// with the cached value.
+func (m *Manager) cert(name string) (*tls.Certificate, error) {
+	m.stateMu.Lock()
+	if s, ok := m.state[name]; ok {
+		m.stateMu.Unlock()
+		s.RLock()
+		defer s.RUnlock()
+		return s.tlscert()
+	}
+	defer m.stateMu.Unlock()
+	cert, err := m.cacheGet(name)
+	if err != nil {
+		return nil, err
+	}
+	signer, ok := cert.PrivateKey.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("acme/autocert: private key cannot sign")
+	}
+	if m.state == nil {
+		m.state = make(map[string]*certState)
+	}
+	s := &certState{
+		key:  signer,
+		cert: cert.Certificate,
+		leaf: cert.Leaf,
+	}
+	m.state[name] = s
+	go m.renew(name, s.key, s.leaf.NotAfter)
+	return cert, nil
+}
+
+// cacheGet always returns a valid certificate, or an error otherwise.
+func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
+	if m.Cache == nil {
+		return nil, ErrCacheMiss
+	}
+	// TODO: might want to define a cache timeout on m
+	ctx := context.Background()
+	data, err := m.Cache.Get(ctx, domain)
+	if err != nil {
+		return nil, err
+	}
+
+	// private
+	priv, pub := pem.Decode(data)
+	if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
+		return nil, errors.New("acme/autocert: no private key found in cache")
+	}
+	privKey, err := parsePrivateKey(priv.Bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	// public
+	var pubDER [][]byte
+	for len(pub) > 0 {
+		var b *pem.Block
+		b, pub = pem.Decode(pub)
+		if b == nil {
+			break
+		}
+		pubDER = append(pubDER, b.Bytes)
+	}
+	if len(pub) > 0 {
+		return nil, errors.New("acme/autocert: invalid public key")
+	}
+
+	// verify and create TLS cert
+	leaf, err := validCert(domain, pubDER, privKey)
+	if err != nil {
+		return nil, err
+	}
+	tlscert := &tls.Certificate{
+		Certificate: pubDER,
+		PrivateKey:  privKey,
+		Leaf:        leaf,
+	}
+	return tlscert, nil
+}
+
+func (m *Manager) cachePut(domain string, tlscert *tls.Certificate) error {
+	if m.Cache == nil {
+		return nil
+	}
+
+	// contains PEM-encoded data
+	var buf bytes.Buffer
+
+	// private
+	switch key := tlscert.PrivateKey.(type) {
+	case *ecdsa.PrivateKey:
+		if err := encodeECDSAKey(&buf, key); err != nil {
+			return err
+		}
+	case *rsa.PrivateKey:
+		b := x509.MarshalPKCS1PrivateKey(key)
+		pb := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: b}
+		if err := pem.Encode(&buf, pb); err != nil {
+			return err
+		}
+	default:
+		return errors.New("acme/autocert: unknown private key type")
+	}
+
+	// public
+	for _, b := range tlscert.Certificate {
+		pb := &pem.Block{Type: "CERTIFICATE", Bytes: b}
+		if err := pem.Encode(&buf, pb); err != nil {
+			return err
+		}
+	}
+
+	// TODO: might want to define a cache timeout on m
+	ctx := context.Background()
+	return m.Cache.Put(ctx, domain, buf.Bytes())
+}
+
+func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
+	b, err := x509.MarshalECPrivateKey(key)
+	if err != nil {
+		return err
+	}
+	pb := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
+	return pem.Encode(w, pb)
+}
+
+// createCert starts the domain ownership verification and returns a certificate
+// for that domain upon success.
+//
+// If the domain is already being verified, it waits for the existing verification to complete.
+// Either way, createCert blocks for the duration of the whole process.
+func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certificate, error) {
+	// TODO: maybe rewrite this whole piece using sync.Once
+	state, err := m.certState(domain)
+	if err != nil {
+		return nil, err
+	}
+	// state may exist if another goroutine is already working on it
+	// in which case just wait for it to finish
+	if !state.locked {
+		state.RLock()
+		defer state.RUnlock()
+		return state.tlscert()
+	}
+
+	// We are the first; state is locked.
+	// Unblock the readers when domain ownership is verified
+	// and the we got the cert or the process failed.
+	defer state.Unlock()
+	state.locked = false
+
+	der, leaf, err := m.authorizedCert(ctx, state.key, domain)
+	if err != nil {
+		return nil, err
+	}
+	state.cert = der
+	state.leaf = leaf
+	go m.renew(domain, state.key, state.leaf.NotAfter)
+	return state.tlscert()
+}
+
+// certState returns a new or existing certState.
+// If a new certState is returned, state.exist is false and the state is locked.
+// The returned error is non-nil only in the case where a new state could not be created.
+func (m *Manager) certState(domain string) (*certState, error) {
+	m.stateMu.Lock()
+	defer m.stateMu.Unlock()
+	if m.state == nil {
+		m.state = make(map[string]*certState)
+	}
+	// existing state
+	if state, ok := m.state[domain]; ok {
+		return state, nil
+	}
+
+	// new locked state
+	var (
+		err error
+		key crypto.Signer
+	)
+	if m.ForceRSA {
+		key, err = rsa.GenerateKey(rand.Reader, 2048)
+	} else {
+		key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	state := &certState{
+		key:    key,
+		locked: true,
+	}
+	state.Lock() // will be unlocked by m.certState caller
+	m.state[domain] = state
+	return state, nil
+}
+
+// authorizedCert starts domain ownership verification process and requests a new cert upon success.
+// The key argument is the certificate private key.
+func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
+	// TODO: make m.verify retry or retry m.verify calls here
+	if err := m.verify(ctx, domain); err != nil {
+		return nil, nil, err
+	}
+	client, err := m.acmeClient(ctx)
+	if err != nil {
+		return nil, nil, err
+	}
+	csr, err := certRequest(key, domain)
+	if err != nil {
+		return nil, nil, err
+	}
+	der, _, err = client.CreateCert(ctx, csr, 0, true)
+	if err != nil {
+		return nil, nil, err
+	}
+	leaf, err = validCert(domain, der, key)
+	if err != nil {
+		return nil, nil, err
+	}
+	return der, leaf, nil
+}
+
+// verify starts a new identifier (domain) authorization flow.
+// It prepares a challenge response and then blocks until the authorization
+// is marked as "completed" by the CA (either succeeded or failed).
+//
+// verify returns nil iff the verification was successful.
+func (m *Manager) verify(ctx context.Context, domain string) error {
+	client, err := m.acmeClient(ctx)
+	if err != nil {
+		return err
+	}
+
+	// start domain authorization and get the challenge
+	authz, err := client.Authorize(ctx, domain)
+	if err != nil {
+		return err
+	}
+	// maybe don't need to at all
+	if authz.Status == acme.StatusValid {
+		return nil
+	}
+
+	// pick a challenge: prefer tls-sni-02 over tls-sni-01
+	// TODO: consider authz.Combinations
+	var chal *acme.Challenge
+	for _, c := range authz.Challenges {
+		if c.Type == "tls-sni-02" {
+			chal = c
+			break
+		}
+		if c.Type == "tls-sni-01" {
+			chal = c
+		}
+	}
+	if chal == nil {
+		return errors.New("acme/autocert: no supported challenge type found")
+	}
+
+	// create a token cert for the challenge response
+	var (
+		cert tls.Certificate
+		name string
+	)
+	switch chal.Type {
+	case "tls-sni-01":
+		cert, name, err = client.TLSSNI01ChallengeCert(chal.Token)
+	case "tls-sni-02":
+		cert, name, err = client.TLSSNI02ChallengeCert(chal.Token)
+	default:
+		err = fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
+	}
+	if err != nil {
+		return err
+	}
+	m.putTokenCert(name, &cert)
+	defer func() {
+		// verification has ended at this point
+		// don't need token cert anymore
+		go m.deleteTokenCert(name)
+	}()
+
+	// ready to fulfill the challenge
+	if _, err := client.Accept(ctx, chal); err != nil {
+		return err
+	}
+	// wait for the CA to validate
+	_, err = client.WaitAuthorization(ctx, authz.URI)
+	return err
+}
+
+// putTokenCert stores the cert under the named key in both m.tokenCert map
+// and m.Cache.
+func (m *Manager) putTokenCert(name string, cert *tls.Certificate) {
+	m.tokenCertMu.Lock()
+	defer m.tokenCertMu.Unlock()
+	if m.tokenCert == nil {
+		m.tokenCert = make(map[string]*tls.Certificate)
+	}
+	m.tokenCert[name] = cert
+	m.cachePut(name, cert)
+}
+
+// deleteTokenCert removes the token certificate for the specified domain name
+// from both m.tokenCert map and m.Cache.
+func (m *Manager) deleteTokenCert(name string) {
+	m.tokenCertMu.Lock()
+	defer m.tokenCertMu.Unlock()
+	delete(m.tokenCert, name)
+	if m.Cache != nil {
+		m.Cache.Delete(context.Background(), name)
+	}
+}
+
+// renew starts a cert renewal timer loop, one per domain.
+//
+// The loop is scheduled in two cases:
+// - a cert was fetched from cache for the first time (wasn't in m.state)
+// - a new cert was created by m.createCert
+//
+// The key argument is a certificate private key.
+// The exp argument is the cert expiration time (NotAfter).
+func (m *Manager) renew(domain string, key crypto.Signer, exp time.Time) {
+	m.renewalMu.Lock()
+	defer m.renewalMu.Unlock()
+	if m.renewal[domain] != nil {
+		// another goroutine is already on it
+		return
+	}
+	if m.renewal == nil {
+		m.renewal = make(map[string]*domainRenewal)
+	}
+	dr := &domainRenewal{m: m, domain: domain, key: key}
+	m.renewal[domain] = dr
+	dr.start(exp)
+}
+
+// stopRenew stops all currently running cert renewal timers.
+// The timers are not restarted during the lifetime of the Manager.
+func (m *Manager) stopRenew() {
+	m.renewalMu.Lock()
+	defer m.renewalMu.Unlock()
+	for name, dr := range m.renewal {
+		delete(m.renewal, name)
+		dr.stop()
+	}
+}
+
+func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
+	const keyName = "acme_account.key"
+
+	genKey := func() (*ecdsa.PrivateKey, error) {
+		return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	}
+
+	if m.Cache == nil {
+		return genKey()
+	}
+
+	data, err := m.Cache.Get(ctx, keyName)
+	if err == ErrCacheMiss {
+		key, err := genKey()
+		if err != nil {
+			return nil, err
+		}
+		var buf bytes.Buffer
+		if err := encodeECDSAKey(&buf, key); err != nil {
+			return nil, err
+		}
+		if err := m.Cache.Put(ctx, keyName, buf.Bytes()); err != nil {
+			return nil, err
+		}
+		return key, nil
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	priv, _ := pem.Decode(data)
+	if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
+		return nil, errors.New("acme/autocert: invalid account key found in cache")
+	}
+	return parsePrivateKey(priv.Bytes)
+}
+
+func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
+	m.clientMu.Lock()
+	defer m.clientMu.Unlock()
+	if m.client != nil {
+		return m.client, nil
+	}
+
+	client := m.Client
+	if client == nil {
+		client = &acme.Client{DirectoryURL: acme.LetsEncryptURL}
+	}
+	if client.Key == nil {
+		var err error
+		client.Key, err = m.accountKey(ctx)
+		if err != nil {
+			return nil, err
+		}
+	}
+	var contact []string
+	if m.Email != "" {
+		contact = []string{"mailto:" + m.Email}
+	}
+	a := &acme.Account{Contact: contact}
+	_, err := client.Register(ctx, a, m.Prompt)
+	if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict {
+		// conflict indicates the key is already registered
+		m.client = client
+		err = nil
+	}
+	return m.client, err
+}
+
+func (m *Manager) hostPolicy() HostPolicy {
+	if m.HostPolicy != nil {
+		return m.HostPolicy
+	}
+	return defaultHostPolicy
+}
+
+func (m *Manager) renewBefore() time.Duration {
+	if m.RenewBefore > maxRandRenew {
+		return m.RenewBefore
+	}
+	return 7 * 24 * time.Hour // 1 week
+}
+
+// certState is ready when its mutex is unlocked for reading.
+type certState struct {
+	sync.RWMutex
+	locked bool              // locked for read/write
+	key    crypto.Signer     // private key for cert
+	cert   [][]byte          // DER encoding
+	leaf   *x509.Certificate // parsed cert[0]; always non-nil if cert != nil
+}
+
+// tlscert creates a tls.Certificate from s.key and s.cert.
+// Callers should wrap it in s.RLock() and s.RUnlock().
+func (s *certState) tlscert() (*tls.Certificate, error) {
+	if s.key == nil {
+		return nil, errors.New("acme/autocert: missing signer")
+	}
+	if len(s.cert) == 0 {
+		return nil, errors.New("acme/autocert: missing certificate")
+	}
+	return &tls.Certificate{
+		PrivateKey:  s.key,
+		Certificate: s.cert,
+		Leaf:        s.leaf,
+	}, nil
+}
+
+// certRequest creates a certificate request for the given common name cn
+// and optional SANs.
+func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) {
+	req := &x509.CertificateRequest{
+		Subject:  pkix.Name{CommonName: cn},
+		DNSNames: san,
+	}
+	return x509.CreateCertificateRequest(rand.Reader, req, key)
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+//
+// Inspired by parsePrivateKey in crypto/tls/tls.go.
+func parsePrivateKey(der []byte) (crypto.Signer, error) {
+	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+		return key, nil
+	}
+	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+		switch key := key.(type) {
+		case *rsa.PrivateKey:
+			return key, nil
+		case *ecdsa.PrivateKey:
+			return key, nil
+		default:
+			return nil, errors.New("acme/autocert: unknown private key type in PKCS#8 wrapping")
+		}
+	}
+	if key, err := x509.ParseECPrivateKey(der); err == nil {
+		return key, nil
+	}
+
+	return nil, errors.New("acme/autocert: failed to parse private key")
+}
+
+// validCert parses a cert chain provided as der argument and verifies the leaf, der[0],
+// corresponds to the private key, as well as the domain match and expiration dates.
+// It doesn't do any revocation checking.
+//
+// The returned value is the verified leaf cert.
+func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) {
+	// parse public part(s)
+	var n int
+	for _, b := range der {
+		n += len(b)
+	}
+	pub := make([]byte, n)
+	n = 0
+	for _, b := range der {
+		n += copy(pub[n:], b)
+	}
+	x509Cert, err := x509.ParseCertificates(pub)
+	if len(x509Cert) == 0 {
+		return nil, errors.New("acme/autocert: no public key found")
+	}
+	// verify the leaf is not expired and matches the domain name
+	leaf = x509Cert[0]
+	now := timeNow()
+	if now.Before(leaf.NotBefore) {
+		return nil, errors.New("acme/autocert: certificate is not valid yet")
+	}
+	if now.After(leaf.NotAfter) {
+		return nil, errors.New("acme/autocert: expired certificate")
+	}
+	if err := leaf.VerifyHostname(domain); err != nil {
+		return nil, err
+	}
+	// ensure the leaf corresponds to the private key
+	switch pub := leaf.PublicKey.(type) {
+	case *rsa.PublicKey:
+		prv, ok := key.(*rsa.PrivateKey)
+		if !ok {
+			return nil, errors.New("acme/autocert: private key type does not match public key type")
+		}
+		if pub.N.Cmp(prv.N) != 0 {
+			return nil, errors.New("acme/autocert: private key does not match public key")
+		}
+	case *ecdsa.PublicKey:
+		prv, ok := key.(*ecdsa.PrivateKey)
+		if !ok {
+			return nil, errors.New("acme/autocert: private key type does not match public key type")
+		}
+		if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 {
+			return nil, errors.New("acme/autocert: private key does not match public key")
+		}
+	default:
+		return nil, errors.New("acme/autocert: unknown public key algorithm")
+	}
+	return leaf, nil
+}
+
+func retryAfter(v string) time.Duration {
+	if i, err := strconv.Atoi(v); err == nil {
+		return time.Duration(i) * time.Second
+	}
+	if t, err := http.ParseTime(v); err == nil {
+		return t.Sub(timeNow())
+	}
+	return time.Second
+}
+
+type lockedMathRand struct {
+	sync.Mutex
+	rnd *mathrand.Rand
+}
+
+func (r *lockedMathRand) int63n(max int64) int64 {
+	r.Lock()
+	n := r.rnd.Int63n(max)
+	r.Unlock()
+	return n
+}
+
+// for easier testing
+var timeNow = time.Now
diff --git a/vendor/golang.org/x/crypto/acme/autocert/cache.go b/vendor/golang.org/x/crypto/acme/autocert/cache.go
new file mode 100644
index 00000000..1c67f6ce
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/autocert/cache.go
@@ -0,0 +1,130 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+	"errors"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+
+	"golang.org/x/net/context"
+)
+
+// ErrCacheMiss is returned when a certificate is not found in cache.
+var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
+
+// Cache is used by Manager to store and retrieve previously obtained certificates
+// as opaque data.
+//
+// The key argument of the methods refers to a domain name but need not be an FQDN.
+// Cache implementations should not rely on the key naming pattern.
+type Cache interface {
+	// Get returns a certificate data for the specified key.
+	// If there's no such key, Get returns ErrCacheMiss.
+	Get(ctx context.Context, key string) ([]byte, error)
+
+	// Put stores the data in the cache under the specified key.
+	// Inderlying implementations may use any data storage format,
+	// as long as the reverse operation, Get, results in the original data.
+	Put(ctx context.Context, key string, data []byte) error
+
+	// Delete removes a certificate data from the cache under the specified key.
+	// If there's no such key in the cache, Delete returns nil.
+	Delete(ctx context.Context, key string) error
+}
+
+// DirCache implements Cache using a directory on the local filesystem.
+// If the directory does not exist, it will be created with 0700 permissions.
+type DirCache string
+
+// Get reads a certificate data from the specified file name.
+func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
+	name = filepath.Join(string(d), name)
+	var (
+		data []byte
+		err  error
+		done = make(chan struct{})
+	)
+	go func() {
+		data, err = ioutil.ReadFile(name)
+		close(done)
+	}()
+	select {
+	case <-ctx.Done():
+		return nil, ctx.Err()
+	case <-done:
+	}
+	if os.IsNotExist(err) {
+		return nil, ErrCacheMiss
+	}
+	return data, err
+}
+
+// Put writes the certificate data to the specified file name.
+// The file will be created with 0600 permissions.
+func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
+	if err := os.MkdirAll(string(d), 0700); err != nil {
+		return err
+	}
+
+	done := make(chan struct{})
+	var err error
+	go func() {
+		defer close(done)
+		var tmp string
+		if tmp, err = d.writeTempFile(name, data); err != nil {
+			return
+		}
+		// prevent overwriting the file if the context was cancelled
+		if ctx.Err() != nil {
+			return // no need to set err
+		}
+		name = filepath.Join(string(d), name)
+		err = os.Rename(tmp, name)
+	}()
+	select {
+	case <-ctx.Done():
+		return ctx.Err()
+	case <-done:
+	}
+	return err
+}
+
+// Delete removes the specified file name.
+func (d DirCache) Delete(ctx context.Context, name string) error {
+	name = filepath.Join(string(d), name)
+	var (
+		err  error
+		done = make(chan struct{})
+	)
+	go func() {
+		err = os.Remove(name)
+		close(done)
+	}()
+	select {
+	case <-ctx.Done():
+		return ctx.Err()
+	case <-done:
+	}
+	if err != nil && !os.IsNotExist(err) {
+		return err
+	}
+	return nil
+}
+
+// writeTempFile writes b to a temporary file, closes the file and returns its path.
+func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) {
+	// TempFile uses 0600 permissions
+	f, err := ioutil.TempFile(string(d), prefix)
+	if err != nil {
+		return "", err
+	}
+	if _, err := f.Write(b); err != nil {
+		f.Close()
+		return "", err
+	}
+	return f.Name(), f.Close()
+}
diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal.go b/vendor/golang.org/x/crypto/acme/autocert/renewal.go
new file mode 100644
index 00000000..1a5018c8
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/autocert/renewal.go
@@ -0,0 +1,125 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+	"crypto"
+	"sync"
+	"time"
+
+	"golang.org/x/net/context"
+)
+
+// maxRandRenew is a maximum deviation from Manager.RenewBefore.
+const maxRandRenew = time.Hour
+
+// domainRenewal tracks the state used by the periodic timers
+// renewing a single domain's cert.
+type domainRenewal struct {
+	m      *Manager
+	domain string
+	key    crypto.Signer
+
+	timerMu sync.Mutex
+	timer   *time.Timer
+}
+
+// start starts a cert renewal timer at the time
+// defined by the certificate expiration time exp.
+//
+// If the timer is already started, calling start is a noop.
+func (dr *domainRenewal) start(exp time.Time) {
+	dr.timerMu.Lock()
+	defer dr.timerMu.Unlock()
+	if dr.timer != nil {
+		return
+	}
+	dr.timer = time.AfterFunc(dr.next(exp), dr.renew)
+}
+
+// stop stops the cert renewal timer.
+// If the timer is already stopped, calling stop is a noop.
+func (dr *domainRenewal) stop() {
+	dr.timerMu.Lock()
+	defer dr.timerMu.Unlock()
+	if dr.timer == nil {
+		return
+	}
+	dr.timer.Stop()
+	dr.timer = nil
+}
+
+// renew is called periodically by a timer.
+// The first renew call is kicked off by dr.start.
+func (dr *domainRenewal) renew() {
+	dr.timerMu.Lock()
+	defer dr.timerMu.Unlock()
+	if dr.timer == nil {
+		return
+	}
+
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
+	defer cancel()
+	// TODO: rotate dr.key at some point?
+	next, err := dr.do(ctx)
+	if err != nil {
+		next = maxRandRenew / 2
+		next += time.Duration(pseudoRand.int63n(int64(next)))
+	}
+	dr.timer = time.AfterFunc(next, dr.renew)
+	testDidRenewLoop(next, err)
+}
+
+// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
+// Instead, it requests a new certificate independently and, upon success,
+// replaces dr.m.state item with a new one and updates cache for the given domain.
+//
+// It may return immediately if the expiration date of the currently cached cert
+// is far enough in the future.
+//
+// The returned value is a time interval after which the renewal should occur again.
+func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
+	// a race is likely unavoidable in a distributed environment
+	// but we try nonetheless
+	if tlscert, err := dr.m.cacheGet(dr.domain); err == nil {
+		next := dr.next(tlscert.Leaf.NotAfter)
+		if next > dr.m.renewBefore()+maxRandRenew {
+			return next, nil
+		}
+	}
+
+	der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain)
+	if err != nil {
+		return 0, err
+	}
+	state := &certState{
+		key:  dr.key,
+		cert: der,
+		leaf: leaf,
+	}
+	tlscert, err := state.tlscert()
+	if err != nil {
+		return 0, err
+	}
+	dr.m.cachePut(dr.domain, tlscert)
+	dr.m.stateMu.Lock()
+	defer dr.m.stateMu.Unlock()
+	// m.state is guaranteed to be non-nil at this point
+	dr.m.state[dr.domain] = state
+	return dr.next(leaf.NotAfter), nil
+}
+
+func (dr *domainRenewal) next(expiry time.Time) time.Duration {
+	d := expiry.Sub(timeNow()) - dr.m.renewBefore()
+	// add a bit of randomness to renew deadline
+	n := pseudoRand.int63n(int64(maxRandRenew))
+	d -= time.Duration(n)
+	if d < 0 {
+		return 0
+	}
+	return d
+}
+
+var testDidRenewLoop = func(next time.Duration, err error) {}
diff --git a/vendor/golang.org/x/crypto/acme/jws.go b/vendor/golang.org/x/crypto/acme/jws.go
new file mode 100644
index 00000000..49ba313c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/jws.go
@@ -0,0 +1,153 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha256"
+	_ "crypto/sha512" // need for EC keys
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"math/big"
+)
+
+// jwsEncodeJSON signs claimset using provided key and a nonce.
+// The result is serialized in JSON format.
+// See https://tools.ietf.org/html/rfc7515#section-7.
+func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) {
+	jwk, err := jwkEncode(key.Public())
+	if err != nil {
+		return nil, err
+	}
+	alg, sha := jwsHasher(key)
+	if alg == "" || !sha.Available() {
+		return nil, ErrUnsupportedKey
+	}
+	phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce)
+	phead = base64.RawURLEncoding.EncodeToString([]byte(phead))
+	cs, err := json.Marshal(claimset)
+	if err != nil {
+		return nil, err
+	}
+	payload := base64.RawURLEncoding.EncodeToString(cs)
+	hash := sha.New()
+	hash.Write([]byte(phead + "." + payload))
+	sig, err := jwsSign(key, sha, hash.Sum(nil))
+	if err != nil {
+		return nil, err
+	}
+
+	enc := struct {
+		Protected string `json:"protected"`
+		Payload   string `json:"payload"`
+		Sig       string `json:"signature"`
+	}{
+		Protected: phead,
+		Payload:   payload,
+		Sig:       base64.RawURLEncoding.EncodeToString(sig),
+	}
+	return json.Marshal(&enc)
+}
+
+// jwkEncode encodes public part of an RSA or ECDSA key into a JWK.
+// The result is also suitable for creating a JWK thumbprint.
+// https://tools.ietf.org/html/rfc7517
+func jwkEncode(pub crypto.PublicKey) (string, error) {
+	switch pub := pub.(type) {
+	case *rsa.PublicKey:
+		// https://tools.ietf.org/html/rfc7518#section-6.3.1
+		n := pub.N
+		e := big.NewInt(int64(pub.E))
+		// Field order is important.
+		// See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
+		return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`,
+			base64.RawURLEncoding.EncodeToString(e.Bytes()),
+			base64.RawURLEncoding.EncodeToString(n.Bytes()),
+		), nil
+	case *ecdsa.PublicKey:
+		// https://tools.ietf.org/html/rfc7518#section-6.2.1
+		p := pub.Curve.Params()
+		n := p.BitSize / 8
+		if p.BitSize%8 != 0 {
+			n++
+		}
+		x := pub.X.Bytes()
+		if n > len(x) {
+			x = append(make([]byte, n-len(x)), x...)
+		}
+		y := pub.Y.Bytes()
+		if n > len(y) {
+			y = append(make([]byte, n-len(y)), y...)
+		}
+		// Field order is important.
+		// See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
+		return fmt.Sprintf(`{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`,
+			p.Name,
+			base64.RawURLEncoding.EncodeToString(x),
+			base64.RawURLEncoding.EncodeToString(y),
+		), nil
+	}
+	return "", ErrUnsupportedKey
+}
+
+// jwsSign signs the digest using the given key.
+// It returns ErrUnsupportedKey if the key type is unknown.
+// The hash is used only for RSA keys.
+func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) {
+	switch key := key.(type) {
+	case *rsa.PrivateKey:
+		return key.Sign(rand.Reader, digest, hash)
+	case *ecdsa.PrivateKey:
+		r, s, err := ecdsa.Sign(rand.Reader, key, digest)
+		if err != nil {
+			return nil, err
+		}
+		rb, sb := r.Bytes(), s.Bytes()
+		size := key.Params().BitSize / 8
+		if size%8 > 0 {
+			size++
+		}
+		sig := make([]byte, size*2)
+		copy(sig[size-len(rb):], rb)
+		copy(sig[size*2-len(sb):], sb)
+		return sig, nil
+	}
+	return nil, ErrUnsupportedKey
+}
+
+// jwsHasher indicates suitable JWS algorithm name and a hash function
+// to use for signing a digest with the provided key.
+// It returns ("", 0) if the key is not supported.
+func jwsHasher(key crypto.Signer) (string, crypto.Hash) {
+	switch key := key.(type) {
+	case *rsa.PrivateKey:
+		return "RS256", crypto.SHA256
+	case *ecdsa.PrivateKey:
+		switch key.Params().Name {
+		case "P-256":
+			return "ES256", crypto.SHA256
+		case "P-384":
+			return "ES384", crypto.SHA384
+		case "P-512":
+			return "ES512", crypto.SHA512
+		}
+	}
+	return "", 0
+}
+
+// JWKThumbprint creates a JWK thumbprint out of pub
+// as specified in https://tools.ietf.org/html/rfc7638.
+func JWKThumbprint(pub crypto.PublicKey) (string, error) {
+	jwk, err := jwkEncode(pub)
+	if err != nil {
+		return "", err
+	}
+	b := sha256.Sum256([]byte(jwk))
+	return base64.RawURLEncoding.EncodeToString(b[:]), nil
+}
diff --git a/vendor/golang.org/x/crypto/acme/types.go b/vendor/golang.org/x/crypto/acme/types.go
new file mode 100644
index 00000000..0513b2e5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/types.go
@@ -0,0 +1,209 @@
+package acme
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+)
+
+// ACME server response statuses used to describe Authorization and Challenge states.
+const (
+	StatusUnknown    = "unknown"
+	StatusPending    = "pending"
+	StatusProcessing = "processing"
+	StatusValid      = "valid"
+	StatusInvalid    = "invalid"
+	StatusRevoked    = "revoked"
+)
+
+// CRLReasonCode identifies the reason for a certificate revocation.
+type CRLReasonCode int
+
+// CRL reason codes as defined in RFC 5280.
+const (
+	CRLReasonUnspecified          CRLReasonCode = 0
+	CRLReasonKeyCompromise        CRLReasonCode = 1
+	CRLReasonCACompromise         CRLReasonCode = 2
+	CRLReasonAffiliationChanged   CRLReasonCode = 3
+	CRLReasonSuperseded           CRLReasonCode = 4
+	CRLReasonCessationOfOperation CRLReasonCode = 5
+	CRLReasonCertificateHold      CRLReasonCode = 6
+	CRLReasonRemoveFromCRL        CRLReasonCode = 8
+	CRLReasonPrivilegeWithdrawn   CRLReasonCode = 9
+	CRLReasonAACompromise         CRLReasonCode = 10
+)
+
+var (
+	// ErrAuthorizationFailed indicates that an authorization for an identifier
+	// did not succeed.
+	ErrAuthorizationFailed = errors.New("acme: identifier authorization failed")
+
+	// ErrUnsupportedKey is returned when an unsupported key type is encountered.
+	ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
+)
+
+// Error is an ACME error, defined in Problem Details for HTTP APIs doc
+// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
+type Error struct {
+	// StatusCode is The HTTP status code generated by the origin server.
+	StatusCode int
+	// ProblemType is a URI reference that identifies the problem type,
+	// typically in a "urn:acme:error:xxx" form.
+	ProblemType string
+	// Detail is a human-readable explanation specific to this occurrence of the problem.
+	Detail string
+	// Header is the original server error response headers.
+	Header http.Header
+}
+
+func (e *Error) Error() string {
+	return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
+}
+
+// Account is a user account. It is associated with a private key.
+type Account struct {
+	// URI is the account unique ID, which is also a URL used to retrieve
+	// account data from the CA.
+	URI string
+
+	// Contact is a slice of contact info used during registration.
+	Contact []string
+
+	// The terms user has agreed to.
+	// A value not matching CurrentTerms indicates that the user hasn't agreed
+	// to the actual Terms of Service of the CA.
+	AgreedTerms string
+
+	// Actual terms of a CA.
+	CurrentTerms string
+
+	// Authz is the authorization URL used to initiate a new authz flow.
+	Authz string
+
+	// Authorizations is a URI from which a list of authorizations
+	// granted to this account can be fetched via a GET request.
+	Authorizations string
+
+	// Certificates is a URI from which a list of certificates
+	// issued for this account can be fetched via a GET request.
+	Certificates string
+}
+
+// Directory is ACME server discovery data.
+type Directory struct {
+	// RegURL is an account endpoint URL, allowing for creating new
+	// and modifying existing accounts.
+	RegURL string
+
+	// AuthzURL is used to initiate Identifier Authorization flow.
+	AuthzURL string
+
+	// CertURL is a new certificate issuance endpoint URL.
+	CertURL string
+
+	// RevokeURL is used to initiate a certificate revocation flow.
+	RevokeURL string
+
+	// Term is a URI identifying the current terms of service.
+	Terms string
+
+	// Website is an HTTP or HTTPS URL locating a website
+	// providing more information about the ACME server.
+	Website string
+
+	// CAA consists of lowercase hostname elements, which the ACME server
+	// recognises as referring to itself for the purposes of CAA record validation
+	// as defined in RFC6844.
+	CAA []string
+}
+
+// Challenge encodes a returned CA challenge.
+type Challenge struct {
+	// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
+	Type string
+
+	// URI is where a challenge response can be posted to.
+	URI string
+
+	// Token is a random value that uniquely identifies the challenge.
+	Token string
+
+	// Status identifies the status of this challenge.
+	Status string
+}
+
+// Authorization encodes an authorization response.
+type Authorization struct {
+	// URI uniquely identifies a authorization.
+	URI string
+
+	// Status identifies the status of an authorization.
+	Status string
+
+	// Identifier is what the account is authorized to represent.
+	Identifier AuthzID
+
+	// Challenges that the client needs to fulfill in order to prove possession
+	// of the identifier (for pending authorizations).
+	// For final authorizations, the challenges that were used.
+	Challenges []*Challenge
+
+	// A collection of sets of challenges, each of which would be sufficient
+	// to prove possession of the identifier.
+	// Clients must complete a set of challenges that covers at least one set.
+	// Challenges are identified by their indices in the challenges array.
+	// If this field is empty, the client needs to complete all challenges.
+	Combinations [][]int
+}
+
+// AuthzID is an identifier that an account is authorized to represent.
+type AuthzID struct {
+	Type  string // The type of identifier, e.g. "dns".
+	Value string // The identifier itself, e.g. "example.org".
+}
+
+// wireAuthz is ACME JSON representation of Authorization objects.
+type wireAuthz struct {
+	Status       string
+	Challenges   []wireChallenge
+	Combinations [][]int
+	Identifier   struct {
+		Type  string
+		Value string
+	}
+}
+
+func (z *wireAuthz) authorization(uri string) *Authorization {
+	a := &Authorization{
+		URI:          uri,
+		Status:       z.Status,
+		Identifier:   AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
+		Combinations: z.Combinations, // shallow copy
+		Challenges:   make([]*Challenge, len(z.Challenges)),
+	}
+	for i, v := range z.Challenges {
+		a.Challenges[i] = v.challenge()
+	}
+	return a
+}
+
+// wireChallenge is ACME JSON challenge representation.
+type wireChallenge struct {
+	URI    string `json:"uri"`
+	Type   string
+	Token  string
+	Status string
+}
+
+func (c *wireChallenge) challenge() *Challenge {
+	v := &Challenge{
+		URI:    c.URI,
+		Type:   c.Type,
+		Token:  c.Token,
+		Status: c.Status,
+	}
+	if v.Status == "" {
+		v.Status = StatusPending
+	}
+	return v
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 526d10b0..1412468a 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -534,6 +534,18 @@
 			"revision": "399a9d7bfe85437346a5ec4ef0450fc2f1084e61",
 			"revisionTime": "2016-09-23T17:06:11Z"
 		},
+		{
+			"checksumSHA1": "TK1Yr8BbwionaaAvM+77lwAAx/8=",
+			"path": "golang.org/x/crypto/acme",
+			"revision": "f6b343c37ca80bfa8ea539da67a0b621f84fab1d",
+			"revisionTime": "2016-12-21T04:54:10Z"
+		},
+		{
+			"checksumSHA1": "fvFbUkZIL96D/kWOJwJRMESGjQQ=",
+			"path": "golang.org/x/crypto/acme/autocert",
+			"revision": "f6b343c37ca80bfa8ea539da67a0b621f84fab1d",
+			"revisionTime": "2016-12-21T04:54:10Z"
+		},
 		{
 			"checksumSHA1": "dwOedwBJ1EIK9+S3t108Bx054Y8=",
 			"path": "golang.org/x/crypto/curve25519",
-- 
GitLab