From 6d8f122a5160f6d9e4c51579f2429dfaa62c7271 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Fri, 16 Feb 2018 06:47:51 -0800 Subject: Upgrading server dependancies (#8308) --- vendor/github.com/rsc/letsencrypt/lets.go | 781 ------------------------------ 1 file changed, 781 deletions(-) delete mode 100644 vendor/github.com/rsc/letsencrypt/lets.go (limited to 'vendor/github.com/rsc/letsencrypt/lets.go') diff --git a/vendor/github.com/rsc/letsencrypt/lets.go b/vendor/github.com/rsc/letsencrypt/lets.go deleted file mode 100644 index 485abfa1c..000000000 --- a/vendor/github.com/rsc/letsencrypt/lets.go +++ /dev/null @@ -1,781 +0,0 @@ -// 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 letsencrypt obtains TLS certificates from LetsEncrypt.org. -// -// LetsEncrypt.org is a service that issues free SSL/TLS certificates to servers -// that can prove control over the given domain's DNS records or -// the servers pointed at by those records. -// -// Warning -// -// Like any other random code you find on the internet, this package should -// not be relied upon in important, production systems without thorough testing -// to ensure that it meets your needs. -// -// In the long term you should be using -// https://golang.org/x/crypto/acme/autocert instead of this package. -// Send improvements there, not here. -// -// This is a package that I wrote for my own personal web sites (swtch.com, rsc.io) -// in a hurry when my paid-for SSL certificate was expiring. It has no tests, -// has barely been used, and there is some anecdotal evidence that it does -// not properly renew certificates in a timely fashion, so servers that run for -// more than 3 months may run into trouble. -// I don't run this code anymore: to simplify maintenance, I moved the sites -// off of Ubuntu VMs and onto Google App Engine, configured with inexpensive -// long-term certificates purchased from cheapsslsecurity.com. -// -// This package was interesting primarily as an example of how simple the API -// for using LetsEncrypt.org could be made, in contrast to the low-level -// implementations that existed at the time. In that respect, it helped inform -// the design of the golang.org/x/crypto/acme/autocert package. -// -// Quick Start -// -// A complete HTTP/HTTPS web server using TLS certificates from LetsEncrypt.org, -// redirecting all HTTP access to HTTPS, and maintaining TLS certificates in a file -// letsencrypt.cache across server restarts. -// -// package main -// -// import ( -// "fmt" -// "log" -// "net/http" -// "rsc.io/letsencrypt" -// ) -// -// func main() { -// http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { -// fmt.Fprintf(w, "Hello, TLS!\n") -// }) -// var m letsencrypt.Manager -// if err := m.CacheFile("letsencrypt.cache"); err != nil { -// log.Fatal(err) -// } -// log.Fatal(m.Serve()) -// } -// -// Overview -// -// The fundamental type in this package is the Manager, which -// manages obtaining and refreshing a collection of TLS certificates, -// typically for use by an HTTPS server. -// The example above shows the most basic use of a Manager. -// The use can be customized by calling additional methods of the Manager. -// -// Registration -// -// A Manager m registers anonymously with LetsEncrypt.org, including agreeing to -// the letsencrypt.org terms of service, the first time it needs to obtain a certificate. -// To register with a particular email address and with the option of a -// prompt for agreement with the terms of service, call m.Register. -// -// GetCertificate -// -// The Manager's GetCertificate method returns certificates -// from the Manager's cache, filling the cache by requesting certificates -// from LetsEncrypt.org. In this way, a server with a tls.Config.GetCertificate -// set to m.GetCertificate will demand load a certificate for any host name -// it serves. To force loading of certificates ahead of time, install m.GetCertificate -// as before but then call m.Cert for each host name. -// -// A Manager can only obtain a certificate for a given host name if it can prove -// control of that host name to LetsEncrypt.org. By default it proves control by -// answering an HTTPS-based challenge: when -// the LetsEncrypt.org servers connect to the named host on port 443 (HTTPS), -// the TLS SNI handshake must use m.GetCertificate to obtain a per-host certificate. -// The most common way to satisfy this requirement is for the host name to -// resolve to the IP address of a (single) computer running m.ServeHTTPS, -// or at least running a Go TLS server with tls.Config.GetCertificate set to m.GetCertificate. -// However, other configurations are possible. For example, a group of machines -// could use an implementation of tls.Config.GetCertificate that cached -// certificates but handled cache misses by making RPCs to a Manager m -// on an elected leader machine. -// -// In typical usage, then, the setting of tls.Config.GetCertificate to m.GetCertificate -// serves two purposes: it provides certificates to the TLS server for ordinary serving, -// and it also answers challenges to prove ownership of the domains in order to -// obtain those certificates. -// -// To force the loading of a certificate for a given host into the Manager's cache, -// use m.Cert. -// -// Persistent Storage -// -// If a server always starts with a zero Manager m, the server effectively fetches -// a new certificate for each of its host name from LetsEncrypt.org on each restart. -// This is unfortunate both because the server cannot start if LetsEncrypt.org is -// unavailable and because LetsEncrypt.org limits how often it will issue a certificate -// for a given host name (at time of writing, the limit is 5 per week for a given host name). -// To save server state proactively to a cache file and to reload the server state from -// that same file when creating a new manager, call m.CacheFile with the name of -// the file to use. -// -// For alternate storage uses, m.Marshal returns the current state of the Manager -// as an opaque string, m.Unmarshal sets the state of the Manager using a string -// previously returned by m.Marshal (usually a different m), and m.Watch returns -// a channel that receives notifications about state changes. -// -// Limits -// -// To avoid hitting basic rate limits on LetsEncrypt.org, a given Manager limits all its -// interactions to at most one request every minute, with an initial allowed burst of -// 20 requests. -// -// By default, if GetCertificate is asked for a certificate it does not have, it will in turn -// ask LetsEncrypt.org for that certificate. This opens a potential attack where attackers -// connect to a server by IP address and pretend to be asking for an incorrect host name. -// Then GetCertificate will attempt to obtain a certificate for that host, incorrectly, -// eventually hitting LetsEncrypt.org's rate limit for certificate requests and making it -// impossible to obtain actual certificates. Because servers hold certificates for months -// at a time, however, an attack would need to be sustained over a time period -// of at least a month in order to cause real problems. -// -// To mitigate this kind of attack, a given Manager limits -// itself to an average of one certificate request for a new host every three hours, -// with an initial allowed burst of up to 20 requests. -// Long-running servers will therefore stay -// within the LetsEncrypt.org limit of 300 failed requests per month. -// Certificate refreshes are not subject to this limit. -// -// To eliminate the attack entirely, call m.SetHosts to enumerate the exact set -// of hosts that are allowed in certificate requests. -// -// Web Servers -// -// The basic requirement for use of a Manager is that there be an HTTPS server -// running on port 443 and calling m.GetCertificate to obtain TLS certificates. -// Using standard primitives, the way to do this is: -// -// srv := &http.Server{ -// Addr: ":https", -// TLSConfig: &tls.Config{ -// GetCertificate: m.GetCertificate, -// }, -// } -// srv.ListenAndServeTLS("", "") -// -// However, this pattern of serving HTTPS with demand-loaded TLS certificates -// comes up enough to wrap into a single method m.ServeHTTPS. -// -// Similarly, many HTTPS servers prefer to redirect HTTP clients to the HTTPS URLs. -// That functionality is provided by RedirectHTTP. -// -// The combination of serving HTTPS with demand-loaded TLS certificates and -// serving HTTPS redirects to HTTP clients is provided by m.Serve, as used in -// the original example above. -// -package letsencrypt - -import ( - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/tls" - "crypto/x509" - "encoding/json" - "encoding/pem" - "fmt" - "io/ioutil" - "log" - "net" - "net/http" - "os" - "strings" - "sync" - "time" - - "golang.org/x/net/context" - "golang.org/x/time/rate" - - "github.com/xenolf/lego/acme" -) - -const letsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" -const debug = false - -// A Manager m takes care of obtaining and refreshing a collection of TLS certificates -// obtained by LetsEncrypt.org. -// The zero Manager is not yet registered with LetsEncrypt.org and has no TLS certificates -// but is nonetheless ready for use. -// See the package comment for an overview of how to use a Manager. -type Manager struct { - mu sync.Mutex - state state - rateLimit *rate.Limiter - newHostLimit *rate.Limiter - certCache map[string]*cacheEntry - certTokens map[string]*tls.Certificate - watchChan chan struct{} -} - -// Serve runs an HTTP/HTTPS web server using TLS certificates obtained by the manager. -// The HTTP server redirects all requests to the HTTPS server. -// The HTTPS server obtains TLS certificates as needed and responds to requests -// by invoking http.DefaultServeMux. -// -// Serve does not return unitil the HTTPS server fails to start or else stops. -// Either way, Serve can only return a non-nil error, never nil. -func (m *Manager) Serve() error { - l, err := net.Listen("tcp", ":http") - if err != nil { - return err - } - defer l.Close() - go http.Serve(l, http.HandlerFunc(RedirectHTTP)) - - return m.ServeHTTPS() -} - -// ServeHTTPS runs an HTTPS web server using TLS certificates obtained by the manager. -// The HTTPS server obtains TLS certificates as needed and responds to requests -// by invoking http.DefaultServeMux. -// ServeHTTPS does not return unitil the HTTPS server fails to start or else stops. -// Either way, ServeHTTPS can only return a non-nil error, never nil. -func (m *Manager) ServeHTTPS() error { - srv := &http.Server{ - Addr: ":https", - TLSConfig: &tls.Config{ - GetCertificate: m.GetCertificate, - }, - } - return srv.ListenAndServeTLS("", "") -} - -// RedirectHTTP is an HTTP handler (suitable for use with http.HandleFunc) -// that responds to all requests by redirecting to the same URL served over HTTPS. -// It should only be invoked for requests received over HTTP. -func RedirectHTTP(w http.ResponseWriter, r *http.Request) { - if r.TLS != nil || r.Host == "" { - http.Error(w, "not found", 404) - } - - u := r.URL - u.Host = r.Host - u.Scheme = "https" - http.Redirect(w, r, u.String(), 302) -} - -// state is the serializable state for the Manager. -// It also implements acme.User. -type state struct { - Email string - Reg *acme.RegistrationResource - Key string - key *ecdsa.PrivateKey - Hosts []string - Certs map[string]stateCert -} - -func (s *state) GetEmail() string { return s.Email } -func (s *state) GetRegistration() *acme.RegistrationResource { return s.Reg } -func (s *state) GetPrivateKey() crypto.PrivateKey { return s.key } - -type stateCert struct { - Cert string - Key string -} - -func (cert stateCert) toTLS() (*tls.Certificate, error) { - c, err := tls.X509KeyPair([]byte(cert.Cert), []byte(cert.Key)) - if err != nil { - return nil, err - } - return &c, err -} - -type cacheEntry struct { - host string - m *Manager - - mu sync.Mutex - cert *tls.Certificate - timeout time.Time - refreshing bool - err error -} - -func (m *Manager) init() { - m.mu.Lock() - if m.certCache == nil { - m.rateLimit = rate.NewLimiter(rate.Every(1*time.Minute), 20) - m.newHostLimit = rate.NewLimiter(rate.Every(3*time.Hour), 20) - m.certCache = map[string]*cacheEntry{} - m.certTokens = map[string]*tls.Certificate{} - m.watchChan = make(chan struct{}, 1) - m.watchChan <- struct{}{} - } - m.mu.Unlock() -} - -// Watch returns the manager's watch channel, -// which delivers a notification after every time the -// manager's state (as exposed by Marshal and Unmarshal) changes. -// All calls to Watch return the same watch channel. -// -// The watch channel includes notifications about changes -// before the first call to Watch, so that in the pattern below, -// the range loop executes once immediately, saving -// the result of setup (along with any background updates that -// may have raced in quickly). -// -// m := new(letsencrypt.Manager) -// setup(m) -// go backgroundUpdates(m) -// for range m.Watch() { -// save(m.Marshal()) -// } -// -func (m *Manager) Watch() <-chan struct{} { - m.init() - m.updated() - return m.watchChan -} - -func (m *Manager) updated() { - select { - case m.watchChan <- struct{}{}: - default: - } -} - -func (m *Manager) CacheFile(name string) error { - f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - return err - } - f.Close() - data, err := ioutil.ReadFile(name) - if err != nil { - return err - } - if len(data) > 0 { - if err := m.Unmarshal(string(data)); err != nil { - return err - } - } - go func() { - for range m.Watch() { - err := ioutil.WriteFile(name, []byte(m.Marshal()), 0600) - if err != nil { - log.Printf("writing letsencrypt cache: %v", err) - } - } - }() - return nil -} - -// Registered reports whether the manager has registered with letsencrypt.org yet. -func (m *Manager) Registered() bool { - m.init() - m.mu.Lock() - defer m.mu.Unlock() - return m.registered() -} - -func (m *Manager) registered() bool { - return m.state.Reg != nil && m.state.Reg.Body.Agreement != "" -} - -// Register registers the manager with letsencrypt.org, using the given email address. -// Registration may require agreeing to the letsencrypt.org terms of service. -// If so, Register calls prompt(url) where url is the URL of the terms of service. -// Prompt should report whether the caller agrees to the terms. -// A nil prompt func is taken to mean that the user always agrees. -// The email address is sent to LetsEncrypt.org but otherwise unchecked; -// it can be omitted by passing the empty string. -// -// Calling Register is only required to make sure registration uses a -// particular email address or to insert an explicit prompt into the -// registration sequence. If the manager is not registered, it will -// automatically register with no email address and automatic -// agreement to the terms of service at the first call to Cert or GetCertificate. -func (m *Manager) Register(email string, prompt func(string) bool) error { - m.init() - m.mu.Lock() - defer m.mu.Unlock() - - return m.register(email, prompt) -} - -func (m *Manager) register(email string, prompt func(string) bool) error { - if m.registered() { - return fmt.Errorf("already registered") - } - m.state.Email = email - if m.state.key == nil { - key, err := newKey() - if err != nil { - return fmt.Errorf("generating key: %v", err) - } - Key, err := marshalKey(key) - if err != nil { - return fmt.Errorf("generating key: %v", err) - } - m.state.key = key - m.state.Key = string(Key) - } - - c, err := acme.NewClient(letsEncryptURL, &m.state, acme.EC256) - if err != nil { - return fmt.Errorf("create client: %v", err) - } - reg, err := c.Register() - if err != nil { - return fmt.Errorf("register: %v", err) - } - - m.state.Reg = reg - if reg.Body.Agreement == "" { - if prompt != nil && !prompt(reg.TosURL) { - return fmt.Errorf("did not agree to TOS") - } - if err := c.AgreeToTOS(); err != nil { - return fmt.Errorf("agreeing to TOS: %v", err) - } - } - - m.updated() - - return nil -} - -// Marshal returns an encoding of the manager's state, -// suitable for writing to disk and reloading by calling Unmarshal. -// The state includes registration status, the configured host list -// from SetHosts, and all known certificates, including their private -// cryptographic keys. -// Consequently, the state should be kept private. -func (m *Manager) Marshal() string { - m.init() - m.mu.Lock() - js, err := json.MarshalIndent(&m.state, "", "\t") - m.mu.Unlock() - if err != nil { - panic("unexpected json.Marshal failure") - } - return string(js) -} - -// Unmarshal restores the state encoded by a previous call to Marshal -// (perhaps on a different Manager in a different program). -func (m *Manager) Unmarshal(enc string) error { - m.init() - var st state - if err := json.Unmarshal([]byte(enc), &st); err != nil { - return err - } - if st.Key != "" { - key, err := unmarshalKey(st.Key) - if err != nil { - return err - } - st.key = key - } - m.mu.Lock() - m.state = st - m.mu.Unlock() - for host, cert := range m.state.Certs { - c, err := cert.toTLS() - if err != nil { - log.Printf("letsencrypt: ignoring entry for %s: %v", host, err) - continue - } - m.certCache[host] = &cacheEntry{host: host, m: m, cert: c} - } - m.updated() - return nil -} - -// SetHosts sets the manager's list of known host names. -// If the list is non-nil, the manager will only ever attempt to acquire -// certificates for host names on the list. -// If the list is nil, the manager does not restrict the hosts it will -// ask for certificates for. -func (m *Manager) SetHosts(hosts []string) { - m.init() - m.mu.Lock() - m.state.Hosts = append(m.state.Hosts[:0], hosts...) - m.mu.Unlock() - m.updated() -} - -// GetCertificate can be placed a tls.Config's GetCertificate field to make -// the TLS server use Let's Encrypt certificates. -// Each time a client connects to the TLS server expecting a new host name, -// the TLS server's call to GetCertificate will trigger an exchange with the -// Let's Encrypt servers to obtain that certificate, subject to the manager rate limits. -// -// As noted in the Manager's documentation comment, -// to obtain a certificate for a given host name, that name -// must resolve to a computer running a TLS server on port 443 -// that obtains TLS SNI certificates by calling m.GetCertificate. -// In the standard usage, then, installing m.GetCertificate in the tls.Config -// both automatically provisions the TLS certificates needed for -// ordinary HTTPS service and answers the challenges from LetsEncrypt.org. -func (m *Manager) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { - m.init() - - host := clientHello.ServerName - - if debug { - log.Printf("GetCertificate %s", host) - } - - if strings.HasSuffix(host, ".acme.invalid") { - m.mu.Lock() - cert := m.certTokens[host] - m.mu.Unlock() - if cert == nil { - return nil, fmt.Errorf("unknown host") - } - return cert, nil - } - - return m.Cert(host) -} - -// Cert returns the certificate for the given host name, obtaining a new one if necessary. -// -// As noted in the documentation for Manager and for the GetCertificate method, -// obtaining a certificate requires that m.GetCertificate be associated with host. -// In most servers, simply starting a TLS server with a configuration referring -// to m.GetCertificate is sufficient, and Cert need not be called. -// -// The main use of Cert is to force the manager to obtain a certificate -// for a particular host name ahead of time. -func (m *Manager) Cert(host string) (*tls.Certificate, error) { - host = strings.ToLower(host) - if debug { - log.Printf("Cert %s", host) - } - - m.init() - m.mu.Lock() - if !m.registered() { - m.register("", nil) - } - - ok := false - if m.state.Hosts == nil { - ok = true - } else { - for _, h := range m.state.Hosts { - if host == h { - ok = true - break - } - } - } - if !ok { - m.mu.Unlock() - return nil, fmt.Errorf("unknown host") - } - - // Otherwise look in our cert cache. - entry, ok := m.certCache[host] - if !ok { - r := m.rateLimit.Reserve() - ok := r.OK() - if ok { - ok = m.newHostLimit.Allow() - if !ok { - r.Cancel() - } - } - if !ok { - m.mu.Unlock() - return nil, fmt.Errorf("rate limited") - } - entry = &cacheEntry{host: host, m: m} - m.certCache[host] = entry - } - m.mu.Unlock() - - entry.mu.Lock() - defer entry.mu.Unlock() - entry.init() - if entry.err != nil { - return nil, entry.err - } - return entry.cert, nil -} - -func (e *cacheEntry) init() { - if e.err != nil && time.Now().Before(e.timeout) { - return - } - if e.cert != nil { - if e.timeout.IsZero() { - t, err := certRefreshTime(e.cert) - if err != nil { - e.err = err - e.timeout = time.Now().Add(1 * time.Minute) - e.cert = nil - return - } - e.timeout = t - } - if time.Now().After(e.timeout) && !e.refreshing { - e.refreshing = true - go e.refresh() - } - return - } - - cert, refreshTime, err := e.m.verify(e.host) - e.m.mu.Lock() - e.m.certCache[e.host] = e - e.m.mu.Unlock() - e.install(cert, refreshTime, err) -} - -func (e *cacheEntry) install(cert *tls.Certificate, refreshTime time.Time, err error) { - e.cert = nil - e.timeout = time.Time{} - e.err = nil - - if err != nil { - e.err = err - e.timeout = time.Now().Add(1 * time.Minute) - return - } - - e.cert = cert - e.timeout = refreshTime -} - -func (e *cacheEntry) refresh() { - e.m.rateLimit.Wait(context.Background()) - cert, refreshTime, err := e.m.verify(e.host) - - e.mu.Lock() - defer e.mu.Unlock() - e.refreshing = false - if err == nil { - e.install(cert, refreshTime, nil) - } -} - -func (m *Manager) verify(host string) (cert *tls.Certificate, refreshTime time.Time, err error) { - c, err := acme.NewClient(letsEncryptURL, &m.state, acme.EC256) - if err != nil { - return - } - if err = c.SetChallengeProvider(acme.TLSSNI01, tlsProvider{m}); err != nil { - return - } - c.SetChallengeProvider(acme.TLSSNI01, tlsProvider{m}) - c.ExcludeChallenges([]acme.Challenge{acme.HTTP01}) - acmeCert, errmap := c.ObtainCertificate([]string{host}, true, nil, false) - if len(errmap) > 0 { - if debug { - log.Printf("ObtainCertificate %v => %v", host, errmap) - } - err = fmt.Errorf("%v", errmap) - return - } - entryCert := stateCert{ - Cert: string(acmeCert.Certificate), - Key: string(acmeCert.PrivateKey), - } - cert, err = entryCert.toTLS() - if err != nil { - if debug { - log.Printf("ObtainCertificate %v toTLS failure: %v", host, err) - } - err = err - return - } - if refreshTime, err = certRefreshTime(cert); err != nil { - return - } - - m.mu.Lock() - if m.state.Certs == nil { - m.state.Certs = make(map[string]stateCert) - } - m.state.Certs[host] = entryCert - m.mu.Unlock() - m.updated() - - return cert, refreshTime, nil -} - -func certRefreshTime(cert *tls.Certificate) (time.Time, error) { - xc, err := x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - if debug { - log.Printf("ObtainCertificate to X.509 failure: %v", err) - } - return time.Time{}, err - } - t := xc.NotBefore.Add(xc.NotAfter.Sub(xc.NotBefore) / 2) - monthEarly := xc.NotAfter.Add(-30 * 24 * time.Hour) - if t.Before(monthEarly) { - t = monthEarly - } - return t, nil -} - -// tlsProvider implements acme.ChallengeProvider for TLS handshake challenges. -type tlsProvider struct { - m *Manager -} - -func (p tlsProvider) Present(domain, token, keyAuth string) error { - cert, dom, err := acme.TLSSNI01ChallengeCert(keyAuth) - if err != nil { - return err - } - - p.m.mu.Lock() - p.m.certTokens[dom] = &cert - p.m.mu.Unlock() - - return nil -} - -func (p tlsProvider) CleanUp(domain, token, keyAuth string) error { - _, dom, err := acme.TLSSNI01ChallengeCert(keyAuth) - if err != nil { - return err - } - - p.m.mu.Lock() - delete(p.m.certTokens, dom) - p.m.mu.Unlock() - - return nil -} - -func marshalKey(key *ecdsa.PrivateKey) ([]byte, error) { - data, err := x509.MarshalECPrivateKey(key) - if err != nil { - return nil, err - } - return pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: data}), nil -} - -func unmarshalKey(text string) (*ecdsa.PrivateKey, error) { - b, _ := pem.Decode([]byte(text)) - if b == nil { - return nil, fmt.Errorf("unmarshalKey: missing key") - } - if b.Type != "EC PRIVATE KEY" { - return nil, fmt.Errorf("unmarshalKey: found %q, not %q", b.Type, "EC PRIVATE KEY") - } - k, err := x509.ParseECPrivateKey(b.Bytes) - if err != nil { - return nil, fmt.Errorf("unmarshalKey: %v", err) - } - return k, nil -} - -func newKey() (*ecdsa.PrivateKey, error) { - return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) -} -- cgit v1.2.3-1-g7c22