Invalidates OCSP cache with a grace period. (#14723) (#14725)

* Resolves a bug where a cache is valid when we check the cache, but not valid by the time we check the OCSP responses of the entire chain.

* Add changelog.

* Updated error message.

Co-authored-by: Kit Haines <khaines@mit.edu>
This commit is contained in:
Vault Automation 2026-05-11 17:50:23 -06:00 committed by GitHub
parent bd8da3ad0f
commit bba9a218f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 1 deletions

3
changelog/_14723.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
client/ocsp: Adds a grace period to renew the cached entry for OCSP response.
```

View File

@ -924,12 +924,28 @@ func (c *Client) extractOCSPCacheResponseValue(cacheValue *ocspCachedResponse, s
sdkOcspStatus := internalStatusCodeToSDK(cacheValue.status)
return validateOCSP(conf, &ocsp.Response{
status, err := validateOCSP(conf, &ocsp.Response{
ProducedAt: time.Unix(int64(cacheValue.producedAt), 0).UTC(),
ThisUpdate: time.Unix(int64(cacheValue.thisUpdate), 0).UTC(),
NextUpdate: time.Unix(int64(cacheValue.nextUpdate), 0).UTC(),
Status: sdkOcspStatus,
})
if err != nil {
return nil, err
}
// If this cached OCSP response is going to expire in the next 15 seconds treat this as a missed cache. This
// prevents an error where the OCSP response is valid now, but is not valid after OCSP responses from other certs
// has returned. OCSP timeouts are generally 5-15 seconds.
if curTime.Add(15 * time.Second).After(time.Unix(int64(cacheValue.nextUpdate), 0).UTC()) {
return &ocspStatus{
code: ocspCacheExpired,
err: fmt.Errorf("ocsp response expires within 15 seconds. treating as expired to provide grade period. current: %v, nextUpdate time: %v",
time.Unix(int64(currentTime), 0).UTC(), time.Unix(int64(cacheValue.nextUpdate), 0).UTC()),
}, nil
}
return status, nil
}
func internalStatusCodeToSDK(internalStatusCode ocspStatusCode) int {

View File

@ -208,6 +208,13 @@ func TestUnitCheckOCSPResponseCache(t *testing.T) {
if err == nil && isValidOCSPStatus(ost.code) {
t.Fatalf("should have failed.")
}
// buffer-time check
c.ocspResponseCache.Add(dummyKey, &ocspCachedResponse{time: float64(currentTime), nextUpdate: float64(currentTime)})
ost, err = c.checkOCSPResponseCache(&dummyKey, subject, issuer, conf)
if err == nil && isValidOCSPStatus(ost.code) {
t.Fatalf("should have failed.")
}
}
// TestUnitValidOCSPResponse validates various combinations of acceptable OCSP responses