// 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. // // 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) 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.TLSSNI01ChallengeCertDomain(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.TLSSNI01ChallengeCertDomain(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) }