Skip to content

Commit 5304069

Browse files
PKI: Do not set NextUpdate OCSP field when ocsp_expiry is 0 (#24192)
* Do not set NextUpdate OCSP field when ocsp_expiry is 0 * Add cl
1 parent 4ac07e1 commit 5304069

File tree

4 files changed

+56
-17
lines changed

4 files changed

+56
-17
lines changed

builtin/logical/pki/path_ocsp.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,14 @@ func genResponse(cfg *crlConfig, caBundle *certutil.ParsedCertBundle, info *ocsp
510510
Status: info.ocspStatus,
511511
SerialNumber: info.serialNumber,
512512
ThisUpdate: curTime,
513-
NextUpdate: curTime.Add(duration),
514513
ExtraExtensions: []pkix.Extension{},
515514
SignatureAlgorithm: revSigAlg,
516515
}
517516

517+
if duration > 0 {
518+
template.NextUpdate = curTime.Add(duration)
519+
}
520+
518521
if info.ocspStatus == ocsp.Revoked {
519522
template.RevokedAt = *info.revocationTimeUTC
520523
template.RevocationReason = ocsp.Unspecified

builtin/logical/pki/path_ocsp_test.go

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"strconv"
1616
"strings"
1717
"testing"
18+
"time"
1819

1920
"github.com/hashicorp/go-secure-stdlib/parseutil"
2021
vaulthttp "github.com/hashicorp/vault/http"
@@ -467,6 +468,18 @@ func TestOcsp_HigherLevel(t *testing.T) {
467468
require.Equal(t, certToRevoke.SerialNumber, ocspResp.SerialNumber)
468469
}
469470

471+
// TestOcsp_NextUpdate make sure that we are setting the appropriate values
472+
// for the NextUpdate field within our responses.
473+
func TestOcsp_NextUpdate(t *testing.T) {
474+
// Within the runOcspRequestTest, with a ocspExpiry of 0,
475+
// we will validate that NextUpdate was not set in the response
476+
runOcspRequestTest(t, "POST", "ec", 0, 0, crypto.SHA256, 0)
477+
478+
// Within the runOcspRequestTest, with a ocspExpiry of 24 hours, we will validate
479+
// that NextUpdate is set and has a time 24 hours larger than ThisUpdate
480+
runOcspRequestTest(t, "POST", "ec", 0, 0, crypto.SHA256, 24*time.Hour)
481+
}
482+
470483
func TestOcsp_ValidRequests(t *testing.T) {
471484
type caKeyConf struct {
472485
keyType string
@@ -506,13 +519,15 @@ func TestOcsp_ValidRequests(t *testing.T) {
506519
localTT.reqHash)
507520
t.Run(testName, func(t *testing.T) {
508521
runOcspRequestTest(t, localTT.reqType, localTT.keyConf.keyType, localTT.keyConf.keyBits,
509-
localTT.keyConf.sigBits, localTT.reqHash)
522+
localTT.keyConf.sigBits, localTT.reqHash, 12*time.Hour)
510523
})
511524
}
512525
}
513526

514-
func runOcspRequestTest(t *testing.T, requestType string, caKeyType string, caKeyBits int, caKeySigBits int, requestHash crypto.Hash) {
515-
b, s, testEnv := setupOcspEnvWithCaKeyConfig(t, caKeyType, caKeyBits, caKeySigBits)
527+
func runOcspRequestTest(t *testing.T, requestType string, caKeyType string,
528+
caKeyBits int, caKeySigBits int, requestHash crypto.Hash, ocspExpiry time.Duration,
529+
) {
530+
b, s, testEnv := setupOcspEnvWithCaKeyConfig(t, caKeyType, caKeyBits, caKeySigBits, ocspExpiry)
516531

517532
// Non-revoked cert
518533
resp, err := SendOcspRequest(t, b, s, requestType, testEnv.leafCertIssuer1, testEnv.issuer1, requestHash)
@@ -574,17 +589,28 @@ func runOcspRequestTest(t *testing.T, requestType string, caKeyType string, caKe
574589
require.Equal(t, testEnv.leafCertIssuer2.SerialNumber, ocspResp.SerialNumber)
575590

576591
// Verify that our thisUpdate and nextUpdate fields are updated as expected
577-
thisUpdate := ocspResp.ThisUpdate
578-
nextUpdate := ocspResp.NextUpdate
579-
require.True(t, thisUpdate.Before(nextUpdate),
580-
fmt.Sprintf("thisUpdate %s, should have been before nextUpdate: %s", thisUpdate, nextUpdate))
581-
nextUpdateDiff := nextUpdate.Sub(thisUpdate)
582-
expectedDiff, err := parseutil.ParseDurationSecond(defaultCrlConfig.OcspExpiry)
592+
resp, err = CBRead(b, s, "config/crl")
593+
requireSuccessNonNilResponse(t, resp, err, "failed reading from config/crl")
594+
requireFieldsSetInResp(t, resp, "ocsp_expiry")
595+
ocspExpiryRaw := resp.Data["ocsp_expiry"].(string)
596+
expectedDiff, err := parseutil.ParseDurationSecond(ocspExpiryRaw)
583597
require.NoError(t, err, "failed to parse default ocsp expiry value")
584-
require.Equal(t, expectedDiff, nextUpdateDiff,
585-
fmt.Sprintf("the delta between thisUpdate %s and nextUpdate: %s should have been around: %s but was %s",
586-
thisUpdate, nextUpdate, defaultCrlConfig.OcspExpiry, nextUpdateDiff))
587598

599+
thisUpdate := ocspResp.ThisUpdate
600+
require.Less(t, time.Since(thisUpdate), 10*time.Second, "expected ThisUpdate field to be within the last 10 seconds")
601+
if expectedDiff != 0 {
602+
nextUpdate := ocspResp.NextUpdate
603+
require.False(t, nextUpdate.IsZero(), "nextUpdate field value should have been a non-zero time")
604+
require.True(t, thisUpdate.Before(nextUpdate),
605+
fmt.Sprintf("thisUpdate %s, should have been before nextUpdate: %s", thisUpdate, nextUpdate))
606+
nextUpdateDiff := nextUpdate.Sub(thisUpdate)
607+
require.Equal(t, expectedDiff, nextUpdateDiff,
608+
fmt.Sprintf("the delta between thisUpdate %s and nextUpdate: %s should have been around: %s but was %s",
609+
thisUpdate, nextUpdate, defaultCrlConfig.OcspExpiry, nextUpdateDiff))
610+
} else {
611+
// With the config value set to 0, we shouldn't have a NextUpdate field set
612+
require.True(t, ocspResp.NextUpdate.IsZero(), "nextUpdate value was not zero as expected was: %v", ocspResp.NextUpdate)
613+
}
588614
requireOcspSignatureAlgoForKey(t, testEnv.issuer2.SignatureAlgorithm, ocspResp.SignatureAlgorithm)
589615
requireOcspResponseSignedBy(t, ocspResp, testEnv.issuer2)
590616
}
@@ -610,16 +636,22 @@ type ocspTestEnv struct {
610636
}
611637

612638
func setupOcspEnv(t *testing.T, keyType string) (*backend, logical.Storage, *ocspTestEnv) {
613-
return setupOcspEnvWithCaKeyConfig(t, keyType, 0, 0)
639+
return setupOcspEnvWithCaKeyConfig(t, keyType, 0, 0, 12*time.Hour)
614640
}
615641

616-
func setupOcspEnvWithCaKeyConfig(t *testing.T, keyType string, caKeyBits int, caKeySigBits int) (*backend, logical.Storage, *ocspTestEnv) {
642+
func setupOcspEnvWithCaKeyConfig(t *testing.T, keyType string, caKeyBits int, caKeySigBits int, ocspExpiry time.Duration) (*backend, logical.Storage, *ocspTestEnv) {
617643
b, s := CreateBackendWithStorage(t)
618644
var issuerCerts []*x509.Certificate
619645
var leafCerts []*x509.Certificate
620646
var issuerIds []issuerID
621647
var keyIds []keyID
622648

649+
resp, err := CBWrite(b, s, "config/crl", map[string]interface{}{
650+
"ocsp_enable": true,
651+
"ocsp_expiry": fmt.Sprintf("%ds", int(ocspExpiry.Seconds())),
652+
})
653+
requireSuccessNonNilResponse(t, resp, err, "config/crl failed")
654+
623655
for i := 0; i < 2; i++ {
624656
resp, err := CBWrite(b, s, "root/generate/internal", map[string]interface{}{
625657
"key_type": keyType,

changelog/24192.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
secrets/pki: Do not set nextUpdate field in OCSP responses when ocsp_expiry is 0
3+
```

website/content/api-docs/secret/pki.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4199,8 +4199,9 @@ the CRL.
41994199
- `ocsp_disable` `(bool: false)` - Disables or enables the OCSP responder in Vault.
42004200

42014201
- `ocsp_expiry` `(string: "12h")` - The amount of time an OCSP response can be cached for,
4202-
(controls the NextUpdate field), useful for OCSP stapling refresh durations. Setting to 0
4203-
should effectively disable caching in third party systems.
4202+
(controls the NextUpdate field), useful for OCSP stapling refresh durations. If set to 0
4203+
the NextUpdate field is not set, indicating newer revocation information is available
4204+
all the time.
42044205

42054206
- `auto_rebuild` `(bool: false)` - Enables or disables periodic rebuilding of
42064207
the CRL upon expiry.

0 commit comments

Comments
 (0)