caddytls: fix TLS state races and ECH rotation retry (#7756)

* caddytls: fix data race in session ticket key rotation

stayUpdated copies the map header (configs := s.configs) under the
lock, then iterates the original map after releasing it. Concurrent
calls to register/unregister mutate the same map.

Hold the lock for the entire iteration instead.

* caddytls: fix data race in AllMatchingCertificates

AllMatchingCertificates reads the package-level certCache without
acquiring certCacheMu, while Cleanup sets certCache to nil under
the write lock. The adjacent HasCertificateForSubject correctly
acquires certCacheMu.RLock.

Add the missing RLock/RUnlock to match.

* caddytls: fix ECH key rotation stopping permanently on error

When rotateECHKeys returns an error, the rotation goroutine returns
immediately, stopping all future key rotation for the lifetime of
the process.

Change return to continue, matching the error handling for
publishECHConfigs two lines below.
This commit is contained in:
cbro
2026-05-20 02:35:40 -04:00
committed by GitHub
parent 0125ae39cc
commit 325c244ea7
2 changed files with 5 additions and 4 deletions
+2 -3
View File
@@ -137,11 +137,10 @@ func (s *SessionTicketService) stayUpdated() {
case newKeys := <-keysChan:
s.mu.Lock()
s.currentKeys = newKeys
configs := s.configs
s.mu.Unlock()
for cfg := range configs {
for cfg := range s.configs {
cfg.SetSessionTicketKeys(newKeys)
}
s.mu.Unlock()
case <-s.stopChan:
return
}
+3 -1
View File
@@ -440,7 +440,7 @@ func (t *TLS) Start() error {
t.EncryptedClientHello.configsMu.Unlock()
if err != nil {
echLogger.Error("rotating ECH configs failed", zap.Error(err))
return
continue
}
err := t.publishECHConfigs(echLogger)
if err != nil {
@@ -879,6 +879,8 @@ func (t *TLS) getAutomationPolicyForName(name string) *AutomationPolicy {
// AllMatchingCertificates returns the list of all certificates in
// the cache which could be used to satisfy the given SAN.
func AllMatchingCertificates(san string) []certmagic.Certificate {
certCacheMu.RLock()
defer certCacheMu.RUnlock()
return certCache.AllMatchingCertificates(san)
}