diff options
Diffstat (limited to 'vendor/github.com/caddyserver')
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/acmeclient.go | 12 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/certificates.go | 6 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/certmagic.go | 4 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/config.go | 233 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/crypto.go | 11 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/dnsutil.go | 14 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/go.mod | 10 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/go.sum | 59 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/handshake.go | 4 | ||||
-rw-r--r-- | vendor/github.com/caddyserver/certmagic/maintain.go | 126 |
10 files changed, 352 insertions, 127 deletions
diff --git a/vendor/github.com/caddyserver/certmagic/acmeclient.go b/vendor/github.com/caddyserver/certmagic/acmeclient.go index 8a61a08255..cc876b9252 100644 --- a/vendor/github.com/caddyserver/certmagic/acmeclient.go +++ b/vendor/github.com/caddyserver/certmagic/acmeclient.go @@ -298,14 +298,22 @@ func (c *acmeClient) throttle(ctx context.Context, names []string) error { } rateLimitersMu.Unlock() if c.mgr.Logger != nil { - c.mgr.Logger.Info("waiting on internal rate limiter", zap.Strings("identifiers", names)) + c.mgr.Logger.Info("waiting on internal rate limiter", + zap.Strings("identifiers", names), + zap.String("ca", c.acmeClient.Directory), + zap.String("account", c.mgr.Email), + ) } err := rl.Wait(ctx) if err != nil { return err } if c.mgr.Logger != nil { - c.mgr.Logger.Info("done waiting on internal rate limiter", zap.Strings("identifiers", names)) + c.mgr.Logger.Info("done waiting on internal rate limiter", + zap.Strings("identifiers", names), + zap.String("ca", c.acmeClient.Directory), + zap.String("account", c.mgr.Email), + ) } return nil } diff --git a/vendor/github.com/caddyserver/certmagic/certificates.go b/vendor/github.com/caddyserver/certmagic/certificates.go index 09dc340d03..e6dab5e0ff 100644 --- a/vendor/github.com/caddyserver/certmagic/certificates.go +++ b/vendor/github.com/caddyserver/certmagic/certificates.go @@ -47,8 +47,11 @@ type Certificate struct { // The hex-encoded hash of this cert's chain's bytes. hash string - // Whether this certificate is under our management + // Whether this certificate is under our management. managed bool + + // The unique string identifying the issuer of this certificate. + issuerKey string } // NeedsRenewal returns true if the certificate is @@ -126,6 +129,7 @@ func (cfg *Config) loadManagedCertificate(domain string) (Certificate, error) { return cert, err } cert.managed = true + cert.issuerKey = certRes.issuerKey return cert, nil } diff --git a/vendor/github.com/caddyserver/certmagic/certmagic.go b/vendor/github.com/caddyserver/certmagic/certmagic.go index 03844b4ad9..bb33b90c55 100644 --- a/vendor/github.com/caddyserver/certmagic/certmagic.go +++ b/vendor/github.com/caddyserver/certmagic/certmagic.go @@ -410,6 +410,10 @@ type CertificateResource struct { // Any extra information associated with the certificate, // usually provided by the issuer implementation. IssuerData interface{} `json:"issuer_data,omitempty"` + + // The unique string identifying the issuer of the + // certificate; internally useful for storage access. + issuerKey string `json:"-"` } // NamesKey returns the list of SANs as a single string, diff --git a/vendor/github.com/caddyserver/certmagic/config.go b/vendor/github.com/caddyserver/certmagic/config.go index 1428a14e46..cce969b8bd 100644 --- a/vendor/github.com/caddyserver/certmagic/config.go +++ b/vendor/github.com/caddyserver/certmagic/config.go @@ -24,6 +24,7 @@ import ( "crypto/x509/pkix" "encoding/asn1" "encoding/json" + "errors" "fmt" weakrand "math/rand" "net" @@ -247,7 +248,7 @@ func newWithCache(certCache *Cache, cfg Config) *Config { // interactive use (i.e. when an administrator is present) so // that errors can be reported and fixed immediately. func (cfg *Config) ManageSync(domainNames []string) error { - return cfg.manageAll(nil, domainNames, false) + return cfg.manageAll(context.Background(), domainNames, false) } // ClientCredentials returns a list of TLS client certificate chains for the given identifiers. @@ -326,7 +327,12 @@ func (cfg *Config) manageOne(ctx context.Context, domainName string, async bool) } // if we don't have one in storage, obtain one obtain := func() error { - err := cfg.ObtainCert(ctx, domainName, !async) + var err error + if async { + err = cfg.ObtainCertAsync(ctx, domainName) + } else { + err = cfg.ObtainCertSync(ctx, domainName) + } if err != nil { return fmt.Errorf("%s: obtaining certificate: %w", domainName, err) } @@ -357,7 +363,12 @@ func (cfg *Config) manageOne(ctx context.Context, domainName string, async bool) // for an existing certificate, make sure it is renewed renew := func() error { - err := cfg.RenewCert(ctx, domainName, !async) + var err error + if async { + err = cfg.RenewCertAsync(ctx, domainName, false) + } else { + err = cfg.RenewCertSync(ctx, domainName, false) + } if err != nil { return fmt.Errorf("%s: renewing certificate: %w", domainName, err) } @@ -401,34 +412,38 @@ func (cfg *Config) Unmanage(domainNames []string) { cfg.certCache.mu.Unlock() } -// ObtainCert obtains a certificate for name using cfg, as long -// as a certificate does not already exist in storage for that -// name. The name must qualify and cfg must be flagged as Managed. -// This function is a no-op if storage already has a certificate -// for name. -// -// It only obtains and stores certificates (and their keys), -// it does not load them into memory. If interactive is true, -// the user may be shown a prompt. -// TODO: consider moving interactive param into the Config struct, -// and maybe retry settings into the Config struct as well? (same for RenewCert) -func (cfg *Config) ObtainCert(ctx context.Context, name string, interactive bool) error { +// ObtainCertSync generates a new private key and obtains a certificate for +// name using cfg in the foreground; i.e. interactively and without retries. +// It stows the renewed certificate and its assets in storage if successful. +// It DOES NOT load the certificate into the in-memory cache. This method +// is a no-op if storage already has a certificate for name. +func (cfg *Config) ObtainCertSync(ctx context.Context, name string) error { + return cfg.obtainCert(ctx, name, true) +} + +// ObtainCertAsync is the same as ObtainCertSync(), except it runs in the +// background; i.e. non-interactively, and with retries if it fails. +func (cfg *Config) ObtainCertAsync(ctx context.Context, name string) error { + return cfg.obtainCert(ctx, name, false) +} + +func (cfg *Config) obtainCert(ctx context.Context, name string, interactive bool) error { if len(cfg.Issuers) == 0 { return fmt.Errorf("no issuers configured; impossible to obtain or check for existing certificate in storage") } + + // if storage has all resources for this certificate, obtain is a no-op if cfg.storageHasCertResourcesAnyIssuer(name) { return nil } + // ensure storage is writeable and readable // TODO: this is not necessary every time; should only perform check once every so often for each storage, which may require some global state... err := cfg.checkStorage() if err != nil { return fmt.Errorf("failed storage check: %v - storage is probably misconfigured", err) } - return cfg.obtainCert(ctx, name, interactive) -} -func (cfg *Config) obtainCert(ctx context.Context, name string, interactive bool) error { log := loggerNamed(cfg.Logger, "obtain") if log != nil { @@ -437,7 +452,7 @@ func (cfg *Config) obtainCert(ctx context.Context, name string, interactive bool // ensure idempotency of the obtain operation for this name lockKey := cfg.lockKey(certIssueLockOp, name) - err := acquireLock(ctx, cfg.Storage, lockKey) + err = acquireLock(ctx, cfg.Storage, lockKey) if err != nil { return fmt.Errorf("unable to acquire lock '%s': %v", lockKey, err) } @@ -467,16 +482,24 @@ func (cfg *Config) obtainCert(ctx context.Context, name string, interactive bool return nil } - privateKey, err := cfg.KeySource.GenerateKey() + // if storage has a private key already, use it; otherwise, + // we'll generate our own + privKey, privKeyPEM, issuers, err := cfg.reusePrivateKey(name) if err != nil { return err } - privKeyPEM, err := encodePrivateKey(privateKey) - if err != nil { - return err + if privKey == nil { + privKey, err = cfg.KeySource.GenerateKey() + if err != nil { + return err + } + privKeyPEM, err = encodePrivateKey(privKey) + if err != nil { + return err + } } - csr, err := cfg.generateCSR(privateKey, []string{name}) + csr, err := cfg.generateCSR(privKey, []string{name}) if err != nil { return err } @@ -484,21 +507,37 @@ func (cfg *Config) obtainCert(ctx context.Context, name string, interactive bool // try to obtain from each issuer until we succeed var issuedCert *IssuedCertificate var issuerUsed Issuer - for _, issuer := range cfg.Issuers { + for i, issuer := range issuers { + log.Debug(fmt.Sprintf("trying issuer %d/%d", i+1, len(cfg.Issuers)), + zap.String("issuer", issuer.IssuerKey())) + if prechecker, ok := issuer.(PreChecker); ok { err = prechecker.PreCheck(ctx, []string{name}, interactive) if err != nil { continue } } + issuedCert, err = issuer.Issue(ctx, csr) if err == nil { issuerUsed = issuer break } + + // err is usually wrapped, which is nice for simply printing it, but + // with our structured error logs we only need the problem string + errToLog := err + var problem acme.Problem + if errors.As(err, &problem) { + errToLog = problem + } + log.Error("could not get certificate from issuer", + zap.String("identifier", name), + zap.String("issuer", issuer.IssuerKey()), + zap.Error(errToLog)) } if err != nil { - // TODO: only the error from the last issuer will be returned, oh well? + // only the error from the last issuer will be returned, but we logged the others return fmt.Errorf("[%s] Obtain: %w", name, err) } @@ -532,6 +571,47 @@ func (cfg *Config) obtainCert(ctx context.Context, name string, interactive bool return err } +// reusePrivateKey looks for a private key for domain in storage in the configured issuers +// paths. For the first private key it finds, it returns that key both decoded and PEM-encoded, +// as well as the reordered list of issuers to use instead of cfg.Issuers (because if a key +// is found, that issuer should be tried first, so it is moved to the front in a copy of +// cfg.Issuers). +func (cfg *Config) reusePrivateKey(domain string) (privKey crypto.PrivateKey, privKeyPEM []byte, issuers []Issuer, err error) { + // make a copy of cfg.Issuers so that if we have to reorder elements, we don't + // inadvertently mutate the configured issuers (see append calls below) + issuers = make([]Issuer, len(cfg.Issuers)) + copy(issuers, cfg.Issuers) + + for i, issuer := range issuers { + // see if this issuer location in storage has a private key for the domain + privateKeyStorageKey := StorageKeys.SitePrivateKey(issuer.IssuerKey(), domain) + privKeyPEM, err = cfg.Storage.Load(privateKeyStorageKey) + if _, ok := err.(ErrNotExist); ok { + err = nil // obviously, it's OK to not have a private key; so don't prevent obtaining a cert + continue + } + if err != nil { + return nil, nil, nil, fmt.Errorf("loading existing private key for reuse with issuer %s: %v", issuer.IssuerKey(), err) + } + + // we loaded a private key; try decoding it so we can use it + privKey, err = decodePrivateKey(privKeyPEM) + if err != nil { + return nil, nil, nil, err + } + + // since the private key was found in storage for this issuer, move it + // to the front of the list so we prefer this issuer first + issuers = append([]Issuer{issuer}, append(issuers[:i], issuers[i+1:]...)...) + break + } + + return +} + +// storageHasCertResourcesAnyIssuer returns true if storage has all the +// certificate resources in storage from any configured issuer. It checks +// all configured issuers in order. func (cfg *Config) storageHasCertResourcesAnyIssuer(name string) bool { for _, iss := range cfg.Issuers { if cfg.storageHasCertResources(iss, name) { @@ -541,23 +621,36 @@ func (cfg *Config) storageHasCertResourcesAnyIssuer(name string) bool { return false } -// RenewCert renews the certificate for name using cfg. It stows the -// renewed certificate and its assets in storage if successful. It -// DOES NOT update the in-memory cache with the new certificate. -func (cfg *Config) RenewCert(ctx context.Context, name string, interactive bool) error { +// RenewCertSync renews the certificate for name using cfg in the foreground; +// i.e. interactively and without retries. It stows the renewed certificate +// and its assets in storage if successful. It DOES NOT update the in-memory +// cache with the new certificate. The certificate will not be renewed if it +// is not close to expiring unless force is true. +// +// Renewing a certificate is the same as obtaining a certificate, except that +// the existing private key already in storage is reused. +func (cfg *Config) RenewCertSync(ctx context.Context, name string, force bool) error { + return cfg.renewCert(ctx, name, force, true) +} + +// RenewCertAsync is the same as RenewCertSync(), except it runs in the +// background; i.e. non-interactively, and with retries if it fails. +func (cfg *Config) RenewCertAsync(ctx context.Context, name string, force bool) error { + return cfg.renewCert(ctx, name, force, false) +} + +func (cfg *Config) renewCert(ctx context.Context, name string, force, interactive bool) error { if len(cfg.Issuers) == 0 { return fmt.Errorf("no issuers configured; impossible to renew or check existing certificate in storage") } + // ensure storage is writeable and readable // TODO: this is not necessary every time; should only perform check once every so often for each storage, which may require some global state... err := cfg.checkStorage() if err != nil { return fmt.Errorf("failed storage check: %v - storage is probably misconfigured", err) } - return cfg.renewCert(ctx, name, interactive) -} -func (cfg *Config) renewCert(ctx context.Context, name string, interactive bool) error { log := loggerNamed(cfg.Logger, "renew") if log != nil { @@ -566,7 +659,7 @@ func (cfg *Config) renewCert(ctx context.Context, name string, interactive bool) // ensure idempotency of the renew operation for this name lockKey := cfg.lockKey(certIssueLockOp, name) - err := acquireLock(ctx, cfg.Storage, lockKey) + err = acquireLock(ctx, cfg.Storage, lockKey) if err != nil { return fmt.Errorf("unable to acquire lock '%s': %v", lockKey, err) } @@ -597,13 +690,22 @@ func (cfg *Config) renewCert(ctx context.Context, name string, interactive bool) // check if renew is still needed - might have been renewed while waiting for lock timeLeft, needsRenew := cfg.managedCertNeedsRenewal(certRes) if !needsRenew { - if log != nil { - log.Info("certificate appears to have been renewed already", - zap.String("identifier", name), - zap.Duration("remaining", timeLeft)) + if force { + if log != nil { + log.Info("certificate does not need to be renewed, but renewal is being forced", + zap.String("identifier", name), + zap.Duration("remaining", timeLeft)) + } + } else { + if log != nil { + log.Info("certificate appears to have been renewed already", + zap.String("identifier", name), + zap.Duration("remaining", timeLeft)) + } + return nil } - return nil } + if log != nil { log.Info("renewing certificate", zap.String("identifier", name), @@ -629,14 +731,27 @@ func (cfg *Config) renewCert(ctx context.Context, name string, interactive bool) continue } } + issuedCert, err = issuer.Issue(ctx, csr) if err == nil { issuerUsed = issuer break } + + // err is usually wrapped, which is nice for simply printing it, but + // with our structured error logs we only need the problem string + errToLog := err + var problem acme.Problem + if errors.As(err, &problem) { + errToLog = problem + } + log.Error("could not get certificate from issuer", + zap.String("identifier", name), + zap.String("issuer", issuer.IssuerKey()), + zap.Error(errToLog)) } if err != nil { - // TODO: only the error from the last issuer will be returned, oh well? + // only the error from the last issuer will be returned, but we logged the others return fmt.Errorf("[%s] Renew: %w", name, err) } @@ -705,6 +820,9 @@ func (cfg *Config) generateCSR(privateKey crypto.PrivateKey, sans []string) (*x5 // RevokeCert revokes the certificate for domain via ACME protocol. It requires // that cfg.Issuers is properly configured with the same issuer that issued the // certificate being revoked. See RFC 5280 ยง5.3.1 for reason codes. +// +// The certificate assets are deleted from storage after successful revocation +// to prevent reuse. func (cfg *Config) RevokeCert(ctx context.Context, domain string, reason int, interactive bool) error { for i, issuer := range cfg.Issuers { issuerKey := issuer.IssuerKey() @@ -730,17 +848,9 @@ func (cfg *Config) RevokeCert(ctx context.Context, domain string, reason int, in cfg.emit("cert_revoked", domain) - err = cfg.Storage.Delete(StorageKeys.SiteCert(issuerKey, domain)) - if err != nil { - return fmt.Errorf("certificate revoked, but unable to delete certificate file: %v", err) - } - err = cfg.Storage.Delete(StorageKeys.SitePrivateKey(issuerKey, domain)) + err = cfg.deleteSiteAssets(issuerKey, domain) if err != nil { - return fmt.Errorf("certificate revoked, but unable to delete private key: %v", err) - } - err = cfg.Storage.Delete(StorageKeys.SiteMeta(issuerKey, domain)) - if err != nil { - return fmt.Errorf("certificate revoked, but unable to delete certificate metadata: %v", err) + return fmt.Errorf("certificate revoked, but unable to fully clean up assets from issuer %s: %v", issuerKey, err) } } @@ -877,6 +987,29 @@ func (cfg *Config) storageHasCertResources(issuer Issuer, domain string) bool { cfg.Storage.Exists(metaKey) } +// deleteSiteAssets deletes the folder in storage containing the +// certificate, private key, and metadata file for domain from the +// issuer with the given issuer key. +func (cfg *Config) deleteSiteAssets(issuerKey, domain string) error { + err := cfg.Storage.Delete(StorageKeys.SiteCert(issuerKey, domain)) + if err != nil { + return fmt.Errorf("deleting certificate file: %v", err) + } + err = cfg.Storage.Delete(StorageKeys.SitePrivateKey(issuerKey, domain)) + if err != nil { + return fmt.Errorf("deleting private key: %v", err) + } + err = cfg.Storage.Delete(StorageKeys.SiteMeta(issuerKey, domain)) + if err != nil { + return fmt.Errorf("deleting metadata file: %v", err) + } + err = cfg.Storage.Delete(StorageKeys.CertsSitePrefix(issuerKey, domain)) + if err != nil { + return fmt.Errorf("deleting site asset folder: %v", err) + } + return nil +} + // lockKey returns a key for a lock that is specific to the operation // named op being performed related to domainName and this config's CA. func (cfg *Config) lockKey(op, domainName string) string { diff --git a/vendor/github.com/caddyserver/certmagic/crypto.go b/vendor/github.com/caddyserver/certmagic/crypto.go index 8d9f3c7669..a705cdde2c 100644 --- a/vendor/github.com/caddyserver/certmagic/crypto.go +++ b/vendor/github.com/caddyserver/certmagic/crypto.go @@ -229,25 +229,24 @@ func (cfg *Config) loadCertResourceAnyIssuer(certNamesKey string) (CertificateRe // loadCertResource loads a certificate resource from the given issuer's storage location. func (cfg *Config) loadCertResource(issuer Issuer, certNamesKey string) (CertificateResource, error) { - var certRes CertificateResource - issuerKey := issuer.IssuerKey() + certRes := CertificateResource{issuerKey: issuer.IssuerKey()} normalizedName, err := idna.ToASCII(certNamesKey) if err != nil { - return certRes, fmt.Errorf("converting '%s' to ASCII: %v", certNamesKey, err) + return CertificateResource{}, fmt.Errorf("converting '%s' to ASCII: %v", certNamesKey, err) } - certBytes, err := cfg.Storage.Load(StorageKeys.SiteCert(issuerKey, normalizedName)) + certBytes, err := cfg.Storage.Load(StorageKeys.SiteCert(certRes.issuerKey, normalizedName)) if err != nil { return CertificateResource{}, err } certRes.CertificatePEM = certBytes - keyBytes, err := cfg.Storage.Load(StorageKeys.SitePrivateKey(issuerKey, normalizedName)) + keyBytes, err := cfg.Storage.Load(StorageKeys.SitePrivateKey(certRes.issuerKey, normalizedName)) if err != nil { return CertificateResource{}, err } certRes.PrivateKeyPEM = keyBytes - metaBytes, err := cfg.Storage.Load(StorageKeys.SiteMeta(issuerKey, normalizedName)) + metaBytes, err := cfg.Storage.Load(StorageKeys.SiteMeta(certRes.issuerKey, normalizedName)) if err != nil { return CertificateResource{}, err } diff --git a/vendor/github.com/caddyserver/certmagic/dnsutil.go b/vendor/github.com/caddyserver/certmagic/dnsutil.go index 85f7714a80..2573cb9663 100644 --- a/vendor/github.com/caddyserver/certmagic/dnsutil.go +++ b/vendor/github.com/caddyserver/certmagic/dnsutil.go @@ -313,11 +313,17 @@ func updateDomainWithCName(r *dns.Msg, fqdn string) string { } // recursiveNameservers are used to pre-check DNS propagation. It -// prepends user-configured nameservers (custom) to the defaults -// obtained from resolv.conf and defaultNameservers and ensures -// that all server addresses have a port value. +// picks user-configured nameservers (custom) OR the defaults +// obtained from resolv.conf and defaultNameservers if none is +// configured and ensures that all server addresses have a port value. func recursiveNameservers(custom []string) []string { - servers := append(custom, systemOrDefaultNameservers(defaultResolvConf, defaultNameservers)...) + var servers []string + if len(custom) == 0 { + servers = systemOrDefaultNameservers(defaultResolvConf, defaultNameservers) + } else { + servers = make([]string, len(custom)) + copy(servers, custom) + } populateNameserverPorts(servers) return servers } diff --git a/vendor/github.com/caddyserver/certmagic/go.mod b/vendor/github.com/caddyserver/certmagic/go.mod index a17f10f1bd..42665bf1b3 100644 --- a/vendor/github.com/caddyserver/certmagic/go.mod +++ b/vendor/github.com/caddyserver/certmagic/go.mod @@ -4,10 +4,10 @@ go 1.14 require ( github.com/klauspost/cpuid/v2 v2.0.6 - github.com/libdns/libdns v0.2.0 + github.com/libdns/libdns v0.2.1 github.com/mholt/acmez v0.1.3 - github.com/miekg/dns v1.1.30 - go.uber.org/zap v1.15.0 - golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de - golang.org/x/net v0.0.0-20200707034311-ab3426394381 + github.com/miekg/dns v1.1.42 + go.uber.org/zap v1.17.0 + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a + golang.org/x/net v0.0.0-20210525063256-abc453219eb5 ) diff --git a/vendor/github.com/caddyserver/certmagic/go.sum b/vendor/github.com/caddyserver/certmagic/go.sum index ac4235326f..1251ac84f0 100644 --- a/vendor/github.com/caddyserver/certmagic/go.sum +++ b/vendor/github.com/caddyserver/certmagic/go.sum @@ -1,4 +1,3 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -12,12 +11,12 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/libdns/libdns v0.2.0 h1:ewg3ByWrdUrxrje8ChPVMBNcotg7H9LQYg+u5De2RzI= -github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= +github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= +github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/mholt/acmez v0.1.3 h1:J7MmNIk4Qf9b8mAGqAh4XkNeowv3f1zW816yf4zt7Qk= github.com/mholt/acmez v0.1.3/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= -github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= -github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY= +github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -25,54 +24,62 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= -golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/caddyserver/certmagic/handshake.go b/vendor/github.com/caddyserver/certmagic/handshake.go index beb5cc3e9f..5506719c2b 100644 --- a/vendor/github.com/caddyserver/certmagic/handshake.go +++ b/vendor/github.com/caddyserver/certmagic/handshake.go @@ -375,7 +375,7 @@ func (cfg *Config) obtainOnDemandCertificate(hello *tls.ClientHelloInfo) (Certif defer cancel() // Obtain the certificate - err = cfg.ObtainCert(ctx, name, false) + err = cfg.ObtainCertAsync(ctx, name) // immediately unblock anyone waiting for it; doing this in // a defer would risk deadlock because of the recursive call @@ -520,7 +520,7 @@ func (cfg *Config) renewDynamicCertificate(hello *tls.ClientHelloInfo, currentCe // Renew and reload the certificate renewAndReload := func(ctx context.Context, cancel context.CancelFunc) (Certificate, error) { defer cancel() - err = cfg.RenewCert(ctx, name, false) + err = cfg.RenewCertAsync(ctx, name, false) if err == nil { // even though the recursive nature of the dynamic cert loading // would just call this function anyway, we do it here to diff --git a/vendor/github.com/caddyserver/certmagic/maintain.go b/vendor/github.com/caddyserver/certmagic/maintain.go index 3e5a8736a7..63d475ced7 100644 --- a/vendor/github.com/caddyserver/certmagic/maintain.go +++ b/vendor/github.com/caddyserver/certmagic/maintain.go @@ -25,6 +25,7 @@ import ( "strings" "time" + "github.com/mholt/acmez/acme" "go.uber.org/zap" "golang.org/x/crypto/ocsp" ) @@ -250,7 +251,7 @@ func (certCache *Cache) queueRenewalTask(ctx context.Context, oldCert Certificat } // perform renewal - crucially, this happens OUTSIDE a lock on certCache - err := cfg.RenewCert(ctx, renewName, false) + err := cfg.RenewCertAsync(ctx, renewName, false) if err != nil { if cfg.OnDemand != nil { // loaded dynamically, remove dynamically @@ -280,7 +281,7 @@ func (certCache *Cache) queueRenewalTask(ctx context.Context, oldCert Certificat // Ryan Sleevi's recommendations for good OCSP support: // https://gist.github.com/sleevi/5efe9ef98961ecfb4da8 func (certCache *Cache) updateOCSPStaples(ctx context.Context) { - log := loggerNamed(certCache.logger, "maintenance") + logger := loggerNamed(certCache.logger, "maintenance") // temporary structures to store updates or tasks // so that we can keep our locks short-lived @@ -293,9 +294,13 @@ func (certCache *Cache) updateOCSPStaples(ctx context.Context) { certHash string lastNextUpdate time.Time } + type renewQueueEntry struct { + oldCert Certificate + ocspResp *ocsp.Response + } updated := make(map[string]ocspUpdate) - var updateQueue []updateQueueEntry - var renewQueue []Certificate + var updateQueue []updateQueueEntry // certs that need a refreshed staple + var renewQueue []renewQueueEntry // certs that need to be renewed (due to revocation) configs := make(map[string]*Config) // obtain brief read lock during our scan to see which staples need updating @@ -324,8 +329,8 @@ func (certCache *Cache) updateOCSPStaples(ctx context.Context) { cfg, err := certCache.getConfig(cert) if err != nil { - if log != nil { - log.Error("unable to refresh OCSP staple because getting automation config for certificate failed", + if logger != nil { + logger.Error("unable to refresh OCSP staple because getting automation config for certificate failed", zap.Strings("identifiers", cert.Names), zap.Error(err)) } @@ -333,8 +338,8 @@ func (certCache *Cache) updateOCSPStaples(ctx context.Context) { } if cfg == nil { // this is bad if this happens, probably a programmer error (oops) - if log != nil { - log.Error("no configuration associated with certificate; unable to manage OCSP staples", + if logger != nil { + logger.Error("no configuration associated with certificate; unable to manage OCSP staples", zap.Strings("identifiers", cert.Names)) } continue @@ -344,8 +349,8 @@ func (certCache *Cache) updateOCSPStaples(ctx context.Context) { if err != nil || ocspResp == nil { if cert.ocsp != nil { // if there was no staple before, that's fine; otherwise we should log the error - if log != nil { - log.Error("stapling OCSP", + if logger != nil { + logger.Error("stapling OCSP", zap.Strings("identifiers", cert.Names), zap.Error(err)) } @@ -357,8 +362,8 @@ func (certCache *Cache) updateOCSPStaples(ctx context.Context) { // If there was no staple before, or if the response is updated, make // sure we apply the update to all names on the certificate. if cert.ocsp != nil && (lastNextUpdate.IsZero() || lastNextUpdate != cert.ocsp.NextUpdate) { - if log != nil { - log.Info("advancing OCSP staple", + if logger != nil { + logger.Info("advancing OCSP staple", zap.Strings("identifiers", cert.Names), zap.Time("from", lastNextUpdate), zap.Time("to", cert.ocsp.NextUpdate)) @@ -366,10 +371,12 @@ func (certCache *Cache) updateOCSPStaples(ctx context.Context) { updated[certHash] = ocspUpdate{rawBytes: cert.Certificate.OCSPStaple, parsed: cert.ocsp} } - // If a managed certificate was revoked, we should attempt - // to replace it with a new one. If that fails, oh well. + // If a managed certificate was revoked, we should attempt to replace it with a new one. if cert.managed && ocspResp.Status == ocsp.Revoked && len(cert.Names) > 0 { - renewQueue = append(renewQueue, cert) + renewQueue = append(renewQueue, renewQueueEntry{ + oldCert: cert, + ocspResp: ocspResp, + }) configs[cert.Names[0]] = cfg } } @@ -386,35 +393,61 @@ func (certCache *Cache) updateOCSPStaples(ctx context.Context) { // We attempt to replace any certificates that were revoked. // Crucially, this happens OUTSIDE a lock on the certCache. - for _, oldCert := range renewQueue { - if log != nil { - log.Warn("OCSP status for managed certificate is REVOKED; attempting to replace with new certificate", - zap.Strings("identifiers", oldCert.Names), - zap.Time("expiration", oldCert.Leaf.NotAfter)) + for _, renew := range renewQueue { + if logger != nil { + logger.Warn("OCSP status for managed certificate is REVOKED; attempting to replace with new certificate", + zap.Strings("identifiers", renew.oldCert.Names), + zap.Time("expiration", renew.oldCert.Leaf.NotAfter)) } - renewName := oldCert.Names[0] + renewName := renew.oldCert.Names[0] cfg := configs[renewName] - // TODO: consider using a new key in this situation, but we don't know if key storage has been compromised... - err := cfg.RenewCert(ctx, renewName, false) + // if revoked for key compromise, we can't be sure whether the storage of + // the key is still safe; however, we KNOW the old key is not safe, and we + // can only hope by the time of revocation that storage has been secured; + // key management is not something we want to get into, but in this case + // it seems prudent to replace the key - and since renewal requires reuse + // of a prior key, we can't do a "renew" to replace the cert if we need a + // new key, so we'll have to do an obtain instead + var obtainInsteadOfRenew bool + if renew.ocspResp.RevocationReason == acme.ReasonKeyCompromise { + err := cfg.moveCompromisedPrivateKey(renew.oldCert, logger) + if err != nil && logger != nil { + logger.Error("could not remove compromised private key from use", + zap.Strings("identifiers", renew.oldCert.Names), + zap.String("issuer", renew.oldCert.issuerKey), + zap.Error(err)) + } + obtainInsteadOfRenew = true + } + + var err error + if obtainInsteadOfRenew { + err = cfg.ObtainCertAsync(ctx, renewName) + } else { + // notice that we force renewal; otherwise, it might see that the + // certificate isn't close to expiring and return, but we really + // need a replacement certificate! see issue #4191 + err = cfg.RenewCertAsync(ctx, renewName, true) + } if err != nil { // probably better to not serve a revoked certificate at all - if log != nil { - log.Error("unable to obtain new to certificate after OCSP status of REVOKED; removing from cache", - zap.Strings("identifiers", oldCert.Names), + if logger != nil { + logger.Error("unable to obtain new to certificate after OCSP status of REVOKED; removing from cache", + zap.Strings("identifiers", renew.oldCert.Names), zap.Error(err)) } certCache.mu.Lock() - certCache.removeCertificate(oldCert) + certCache.removeCertificate(renew.oldCert) certCache.mu.Unlock() continue } - err = cfg.reloadManagedCertificate(oldCert) + err = cfg.reloadManagedCertificate(renew.oldCert) if err != nil { - if log != nil { - log.Error("after obtaining new certificate due to OCSP status of REVOKED", - zap.Strings("identifiers", oldCert.Names), + if logger != nil { + logger.Error("after obtaining new certificate due to OCSP status of REVOKED", + zap.Strings("identifiers", renew.oldCert.Names), zap.Error(err)) } continue @@ -566,6 +599,37 @@ func deleteExpiredCerts(ctx context.Context, storage Storage, gracePeriod time.D return nil } +// moveCompromisedPrivateKey moves the private key for cert to a ".compromised" file +// by copying the data to the new file, then deleting the old one. +func (cfg *Config) moveCompromisedPrivateKey(cert Certificate, logger *zap.Logger) error { + privKeyStorageKey := StorageKeys.SitePrivateKey(cert.issuerKey, cert.Names[0]) + + privKeyPEM, err := cfg.Storage.Load(privKeyStorageKey) + if err != nil { + return err + } + + compromisedPrivKeyStorageKey := privKeyStorageKey + ".compromised" + err = cfg.Storage.Store(compromisedPrivKeyStorageKey, privKeyPEM) + if err != nil { + // better safe than sorry: as a last resort, try deleting the key so it won't be reused + cfg.Storage.Delete(privKeyStorageKey) + return err + } + + err = cfg.Storage.Delete(privKeyStorageKey) + if err != nil { + return err + } + + logger.Info("removed certificate's compromised private key from use", + zap.String("storage_path", compromisedPrivKeyStorageKey), + zap.Strings("identifiers", cert.Names), + zap.String("issuer", cert.issuerKey)) + + return nil +} + const ( // DefaultRenewCheckInterval is how often to check certificates for expiration. // Scans are very lightweight, so this can be semi-frequent. This default should |