fix(ssl): implement OCSP refreshAll to actually refresh stale responses

refreshAll() was a no-op — it checked which entries needed refreshing
but never called fetchOCSP. Now it:
- Stores cert/issuer pairs when registering certificates
- Actually fetches fresh OCSP responses for stale/expired entries
- Updates error counts and marks entries as failed after max retries
This commit is contained in:
xfy 2026-06-03 01:14:09 +08:00
parent 3b84d62971
commit eb404f98a2

View File

@ -42,6 +42,7 @@ import (
// 当 OCSP 查询失败时TLS 握手仍可继续进行。 // 当 OCSP 查询失败时TLS 握手仍可继续进行。
type OCSPManager struct { type OCSPManager struct {
responses map[string]*ocspResponse responses map[string]*ocspResponse
certs map[string]certPair
client *http.Client client *http.Client
stopChan chan struct{} stopChan chan struct{}
refreshInterval time.Duration refreshInterval time.Duration
@ -51,6 +52,11 @@ type OCSPManager struct {
running bool running bool
} }
type certPair struct {
cert *x509.Certificate
issuer *x509.Certificate
}
// ocspResponse OCSP 响应缓存条目。 // ocspResponse OCSP 响应缓存条目。
// //
// 保存 OCSP 响应数据及其元数据,用于证书状态验证。 // 保存 OCSP 响应数据及其元数据,用于证书状态验证。
@ -129,6 +135,7 @@ func NewOCSPManager(cfg *OCSPConfig) *OCSPManager {
return &OCSPManager{ return &OCSPManager{
responses: make(map[string]*ocspResponse), responses: make(map[string]*ocspResponse),
certs: make(map[string]certPair),
client: &http.Client{ client: &http.Client{
Timeout: timeout, Timeout: timeout,
}, },
@ -182,25 +189,37 @@ func (m *OCSPManager) refreshLoop() {
// refreshAll 刷新所有缓存的 OCSP 响应。 // refreshAll 刷新所有缓存的 OCSP 响应。
func (m *OCSPManager) refreshAll() { func (m *OCSPManager) refreshAll() {
var toRefresh []string
m.mu.RLock() m.mu.RLock()
certs := make([]string, 0, len(m.responses)) for serial, resp := range m.responses {
for serial := range m.responses { if resp == nil || time.Now().After(resp.nextUpdate) || resp.status != statusValid {
certs = append(certs, serial) toRefresh = append(toRefresh, serial)
}
} }
m.mu.RUnlock() m.mu.RUnlock()
for _, serial := range certs { for _, serial := range toRefresh {
m.mu.RLock() m.mu.RLock()
resp, ok := m.responses[serial] pair, ok := m.certs[serial]
m.mu.RUnlock() m.mu.RUnlock()
if !ok {
if ok && resp != nil {
// 检查是否需要刷新
if time.Now().Before(resp.nextUpdate) && resp.status == statusValid {
continue continue
} }
response, err := m.fetchOCSP(pair.cert, pair.issuer)
m.mu.Lock()
if err != nil {
if existing, exists := m.responses[serial]; exists {
existing.errors++
if existing.errors >= m.maxRetries {
existing.status = statusFailed
} }
} }
} else {
m.responses[serial] = response
}
m.mu.Unlock()
}
} }
// RegisterCertificate 注册证书以进行 OCSP Stapling。 // RegisterCertificate 注册证书以进行 OCSP Stapling。
@ -226,6 +245,10 @@ func (m *OCSPManager) RegisterCertificate(cert *x509.Certificate, issuer *x509.C
serial := cert.SerialNumber.String() serial := cert.SerialNumber.String()
m.mu.Lock()
m.certs[serial] = certPair{cert: cert, issuer: issuer}
m.mu.Unlock()
// 获取初始 OCSP 响应 // 获取初始 OCSP 响应
response, err := m.fetchOCSP(cert, issuer) response, err := m.fetchOCSP(cert, issuer)
if err != nil { if err != nil {