diff --git a/caddy/helpers.go b/caddy/helpers.go index d8f40970..a22e7f5c 100644 --- a/caddy/helpers.go +++ b/caddy/helpers.go @@ -13,7 +13,7 @@ import ( ) func init() { - letsencrypt.OnRenew = func() error { return Restart(nil) } + letsencrypt.OnChange = func() error { return Restart(nil) } } // isLocalhost returns true if the string looks explicitly like a localhost address. diff --git a/caddy/letsencrypt/letsencrypt.go b/caddy/letsencrypt/letsencrypt.go index 3ae904cf..4d58bebb 100644 --- a/caddy/letsencrypt/letsencrypt.go +++ b/caddy/letsencrypt/letsencrypt.go @@ -18,12 +18,6 @@ import ( "github.com/xenolf/lego/acme" ) -// OnRenew is the function that will be used to restart -// the application or the part of the application that uses -// the certificates maintained by this package. When at least -// one certificate is renewed, this function will be called. -var OnRenew func() error - // Activate sets up TLS for each server config in configs // as needed. It only skips the config if the cert and key // are already provided or if plaintext http is explicitly @@ -40,7 +34,9 @@ var OnRenew func() error // Also note that calling this function activates asset // management automatically, which . func Activate(configs []server.Config) ([]server.Config, error) { - // First identify and configure any elligible hosts for which + // TODO: Is multiple activation (before a deactivation) an error? + + // First identify and configure any eligible hosts for which // we already have certs and keys in storage from last time. configLen := len(configs) // avoid infinite loop since this loop appends plaintext to the slice for i := 0; i < configLen; i++ { @@ -269,6 +265,7 @@ func autoConfigure(cfg *server.Config, allConfigs []server.Config) []server.Conf // TODO: Handle these errors better if err == nil { ocsp, status, err := acme.GetOCSPForCert(bundleBytes) + ocspStatus[&bundleBytes] = status if err == nil && status == acme.OCSPGood { cfg.TLS.OCSPStaple = ocsp } @@ -402,3 +399,8 @@ var rsaKeySizeToUse = RSA_2048 // stopChan is used to signal the maintenance goroutine // to terminate. var stopChan chan struct{} + +// ocspStatus maps certificate bundle to OCSP status at start. +// It is used during regular OCSP checks to see if the OCSP +// status has changed. +var ocspStatus = make(map[*[]byte]int) diff --git a/caddy/letsencrypt/maintain.go b/caddy/letsencrypt/maintain.go index bca1e3d8..62af5e1c 100644 --- a/caddy/letsencrypt/maintain.go +++ b/caddy/letsencrypt/maintain.go @@ -10,6 +10,13 @@ import ( "github.com/xenolf/lego/acme" ) +// OnChange is a callback function that will be used to restart +// the application or the part of the application that uses +// the certificates maintained by this package. When at least +// one certificate is renewed or an OCSP status changes, this +// function will be called. +var OnChange func() error + // maintainAssets is a permanently-blocking function // that loops indefinitely and, on a regular schedule, checks // certificates for expiration and initiates a renewal of certs @@ -30,15 +37,25 @@ func maintainAssets(configs []server.Config, stopChan chan struct{}) { for _, err := range errs { log.Printf("[ERROR] cert renewal: %v\n", err) } - if n > 0 && OnRenew != nil { - err := OnRenew() + if n > 0 && OnChange != nil { + err := OnChange() if err != nil { - log.Printf("[ERROR] onrenew callback: %v\n", err) + log.Printf("[ERROR] onchange after cert renewal: %v\n", err) } } } case <-ocspTicker.C: - // TODO: Update OCSP + for bundle, oldStatus := range ocspStatus { + _, newStatus, err := acme.GetOCSPForCert(*bundle) + if err == nil && newStatus != oldStatus && OnChange != nil { + log.Printf("[INFO] ocsp status changed from %v to %v\n", oldStatus, newStatus) + err := OnChange() + if err != nil { + log.Printf("[ERROR] onchange after ocsp update: %v\n", err) + } + break + } + } case <-stopChan: renewalTicker.Stop() ocspTicker.Stop()