Skip to content

Commit 3c87f21

Browse files
authored
GODRIVER-4101 Add tlsDisableCertificateRevocationCheck option. (#2571)
1 parent 5e5fba9 commit 3c87f21

11 files changed

Lines changed: 586 additions & 163 deletions

File tree

internal/spectest/skip.go

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ var skipTests = map[string][]skipCase{
7979
},
8080
},
8181

82-
// Unsupported TLS behavior in connection strings.
83-
"unsupported connstring behavior": {
82+
// The Go driver does not support the tlsAllowInvalidCertificates or
83+
// tlsAllowInvalidHostnames URI options.
84+
"tlsAllowInvalidCertificates/tlsAllowInvalidHostnames are not supported": {
8485
{
8586
tests: []string{
8687
"TestURIOptionsSpec/tls-options.json/tlsAllowInvalidCertificates_and_tlsDisableCertificateRevocationCheck_both_present_(and_true)_raises_an_error",
@@ -91,22 +92,6 @@ var skipTests = map[string][]skipCase{
9192
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck=true_and_tlsAllowInvalidCertificates=false_raises_an_error",
9293
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck=false_and_tlsAllowInvalidCertificates=true_raises_an_error",
9394
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck_and_tlsAllowInvalidCertificates_both_present_(and_false)_raises_an_error",
94-
"TestURIOptionsSpec/tls-options.json/tlsInsecure_and_tlsDisableCertificateRevocationCheck_both_present_(and_true)_raises_an_error",
95-
"TestURIOptionsSpec/tls-options.json/tlsInsecure=true_and_tlsDisableCertificateRevocationCheck=false_raises_an_error",
96-
"TestURIOptionsSpec/tls-options.json/tlsInsecure=false_and_tlsDisableCertificateRevocationCheck=true_raises_an_error",
97-
"TestURIOptionsSpec/tls-options.json/tlsInsecure_and_tlsDisableCertificateRevocationCheck_both_present_(and_false)_raises_an_error",
98-
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck_and_tlsInsecure_both_present_(and_true)_raises_an_error",
99-
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck=true_and_tlsInsecure=false_raises_an_error",
100-
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck=false_and_tlsInsecure=true_raises_an_error",
101-
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck_and_tlsInsecure_both_present_(and_false)_raises_an_error",
102-
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck_and_tlsDisableOCSPEndpointCheck_both_present_(and_true)_raises_an_error",
103-
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck=true_and_tlsDisableOCSPEndpointCheck=false_raises_an_error",
104-
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck=false_and_tlsDisableOCSPEndpointCheck=true_raises_an_error",
105-
"TestURIOptionsSpec/tls-options.json/tlsDisableCertificateRevocationCheck_and_tlsDisableOCSPEndpointCheck_both_present_(and_false)_raises_an_error",
106-
"TestURIOptionsSpec/tls-options.json/tlsDisableOCSPEndpointCheck_and_tlsDisableCertificateRevocationCheck_both_present_(and_true)_raises_an_error",
107-
"TestURIOptionsSpec/tls-options.json/tlsDisableOCSPEndpointCheck=true_and_tlsDisableCertificateRevocationCheck=false_raises_an_error",
108-
"TestURIOptionsSpec/tls-options.json/tlsDisableOCSPEndpointCheck=false_and_tlsDisableCertificateRevocationCheck=true_raises_an_error",
109-
"TestURIOptionsSpec/tls-options.json/tlsDisableOCSPEndpointCheck_and_tlsDisableCertificateRevocationCheck_both_present_(and_false)_raises_an_error",
11095
"TestURIOptionsSpec/tls-options.json/tlsAllowInvalidCertificates_and_tlsDisableOCSPEndpointCheck_both_present_(and_true)_raises_an_error",
11196
"TestURIOptionsSpec/tls-options.json/tlsAllowInvalidCertificates=true_and_tlsDisableOCSPEndpointCheck=false_raises_an_error",
11297
"TestURIOptionsSpec/tls-options.json/tlsAllowInvalidCertificates=false_and_tlsDisableOCSPEndpointCheck=true_raises_an_error",

mongo/options/clientoptions.go

Lines changed: 100 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -269,45 +269,46 @@ type DriverInfo struct {
269269
// can be set through the ClientOptions setter functions. See each function for
270270
// documentation.
271271
type ClientOptions struct {
272-
AppName *string
273-
Auth *Credential
274-
AutoEncryptionOptions *AutoEncryptionOptions
275-
ConnectTimeout *time.Duration
276-
Compressors []string
277-
Dialer ContextDialer
278-
Direct *bool
279-
DisableOCSPEndpointCheck *bool
280-
DriverInfo *DriverInfo
281-
HeartbeatInterval *time.Duration
282-
Hosts []string
283-
HTTPClient *http.Client
284-
LoadBalanced *bool
285-
LocalThreshold *time.Duration
286-
LoggerOptions *LoggerOptions
287-
MaxConnIdleTime *time.Duration
288-
MaxPoolSize *uint64
289-
MinPoolSize *uint64
290-
MaxConnecting *uint64
291-
PoolMonitor *event.PoolMonitor
292-
Monitor *event.CommandMonitor
293-
ServerMonitor *event.ServerMonitor
294-
ReadConcern *readconcern.ReadConcern
295-
ReadPreference *readpref.ReadPref
296-
BSONOptions *BSONOptions
297-
Registry *bson.Registry
298-
ReplicaSet *string
299-
RetryReads *bool
300-
RetryWrites *bool
301-
ServerAPIOptions *ServerAPIOptions
302-
ServerMonitoringMode *string
303-
ServerSelectionTimeout *time.Duration
304-
SRVMaxHosts *int
305-
SRVServiceName *string
306-
Timeout *time.Duration
307-
TLSConfig *tls.Config
308-
WriteConcern *writeconcern.WriteConcern
309-
ZlibLevel *int
310-
ZstdLevel *int
272+
AppName *string
273+
Auth *Credential
274+
AutoEncryptionOptions *AutoEncryptionOptions
275+
ConnectTimeout *time.Duration
276+
Compressors []string
277+
Dialer ContextDialer
278+
Direct *bool
279+
DisableCertificateRevocationCheck *bool
280+
DisableOCSPEndpointCheck *bool
281+
DriverInfo *DriverInfo
282+
HeartbeatInterval *time.Duration
283+
Hosts []string
284+
HTTPClient *http.Client
285+
LoadBalanced *bool
286+
LocalThreshold *time.Duration
287+
LoggerOptions *LoggerOptions
288+
MaxConnIdleTime *time.Duration
289+
MaxPoolSize *uint64
290+
MinPoolSize *uint64
291+
MaxConnecting *uint64
292+
PoolMonitor *event.PoolMonitor
293+
Monitor *event.CommandMonitor
294+
ServerMonitor *event.ServerMonitor
295+
ReadConcern *readconcern.ReadConcern
296+
ReadPreference *readpref.ReadPref
297+
BSONOptions *BSONOptions
298+
Registry *bson.Registry
299+
ReplicaSet *string
300+
RetryReads *bool
301+
RetryWrites *bool
302+
ServerAPIOptions *ServerAPIOptions
303+
ServerMonitoringMode *string
304+
ServerSelectionTimeout *time.Duration
305+
SRVMaxHosts *int
306+
SRVServiceName *string
307+
Timeout *time.Duration
308+
TLSConfig *tls.Config
309+
WriteConcern *writeconcern.WriteConcern
310+
ZlibLevel *int
311+
ZstdLevel *int
311312

312313
MaxAdaptiveRetries *uint
313314
EnableOverloadRetargeting *bool
@@ -545,6 +546,10 @@ func setURIOpts(uri string, opts *ClientOptions) error {
545546
opts.ZstdLevel = &connString.ZstdLevel
546547
}
547548

549+
if connString.SSLDisableCertificateRevocationCheckSet {
550+
opts.DisableCertificateRevocationCheck = &connString.SSLDisableCertificateRevocationCheck
551+
}
552+
548553
if connString.SSLDisableOCSPEndpointCheckSet {
549554
opts.DisableOCSPEndpointCheck = &connString.SSLDisableOCSPEndpointCheck
550555
}
@@ -625,6 +630,24 @@ func (c *ClientOptions) Validate() error {
625630
}
626631
}
627632

633+
// tlsDisableCertificateRevocationCheck conflicts with tlsInsecure and with
634+
// tlsDisableOCSPEndpointCheck whenever both are present, whatever values they hold.
635+
if c.DisableCertificateRevocationCheck != nil {
636+
if c.DisableOCSPEndpointCheck != nil {
637+
return errors.New("tlsDisableOCSPEndpointCheck cannot be used with tlsDisableCertificateRevocationCheck")
638+
}
639+
640+
// A tls.Config cannot distinguish InsecureSkipVerify being set to false from it never
641+
// having been set, so fall back to the connection string when there is one.
642+
insecureSet := c.TLSConfig != nil && c.TLSConfig.InsecureSkipVerify
643+
if c.connString != nil && c.connString.SSLInsecureSet {
644+
insecureSet = true
645+
}
646+
if insecureSet {
647+
return errors.New("sslInsecure/tlsInsecure cannot be used with tlsDisableCertificateRevocationCheck")
648+
}
649+
}
650+
628651
if mode := c.ServerMonitoringMode; mode != nil && !connstring.IsValidServerMonitoringMode(*mode) {
629652
return fmt.Errorf("invalid server monitoring mode: %q", *mode)
630653
}
@@ -689,8 +712,7 @@ func (c *ClientOptions) Validate() error {
689712
}
690713

691714
// ApplyURI parses the given URI and sets options accordingly. The URI can contain host names, IPv4/IPv6 literals, or
692-
// an SRV record that will be resolved when the Client is created. When using an SRV record, TLS support is
693-
// implicitly enabled. Specify the "tls=false" URI option to override this.
715+
// an SRV record that will be resolved when the Client is created.
694716
//
695717
// If the connection string contains any options that have previously been set, it will overwrite them. Options that
696718
// correspond to multiple URI parameters, such as WriteConcern, will be completely overwritten if any of the query
@@ -702,6 +724,24 @@ func (c *ClientOptions) Validate() error {
702724
//
703725
// For more information about the URI format, see https://www.mongodb.com/docs/manual/reference/connection-string/. See
704726
// mongo.Connect documentation for examples of using URIs for different Client configurations.
727+
//
728+
// # Implicit TLS
729+
//
730+
// TLS is enabled implicitly when the URI uses the "mongodb+srv" scheme, or when any of the following URI options is
731+
// present, whatever value it is set to:
732+
//
733+
// tlsCAFile (sslCertificateAuthorityFile)
734+
// tlsCertificateKeyFile (sslClientCertificateKeyFile)
735+
// tlsCertificateFile
736+
// tlsPrivateKeyFile
737+
// tlsDisableOCSPEndpointCheck
738+
// tlsDisableCertificateRevocationCheck
739+
//
740+
// The value is not consulted: "tlsDisableOCSPEndpointCheck=false" enables TLS just as "=true" does.
741+
//
742+
// The "tls=false" URI option overrides implicit enablement. With the "mongodb+srv" scheme it always does. When TLS
743+
// was enabled by one of the options listed above, it does so only if it appears later in the connection string than
744+
// that option.
705745
func (c *ClientOptions) ApplyURI(uri string) *ClientOptions {
706746
if c.err != nil {
707747
return c
@@ -1123,6 +1163,25 @@ func (c *ClientOptions) SetAutoEncryptionOptions(aeopts *AutoEncryptionOptions)
11231163
return c
11241164
}
11251165

1166+
// SetDisableCertificateRevocationCheck specifies whether or not the driver should check the revocation status of
1167+
// certificates presented by the server.
1168+
//
1169+
// If set to true, the driver will not check certificate revocation status via OCSP. If set to false, the driver
1170+
// checks revocation status and reaches out to OCSP responders when needed.
1171+
//
1172+
// Certificate chain and hostname verification are unaffected, so this is a narrower relaxation than tlsInsecure,
1173+
// which disables certificate verification entirely.
1174+
//
1175+
// This can also be set through the tlsDisableCertificateRevocationCheck URI option. The default value is false.
1176+
//
1177+
// This option must not be combined with tlsInsecure or tlsDisableOCSPEndpointCheck. If either of those was
1178+
// supplied, doing so is an error.
1179+
func (c *ClientOptions) SetDisableCertificateRevocationCheck(disableCheck bool) *ClientOptions {
1180+
c.DisableCertificateRevocationCheck = &disableCheck
1181+
1182+
return c
1183+
}
1184+
11261185
// SetDisableOCSPEndpointCheck specifies whether or not the driver should reach out to OCSP responders to verify the
11271186
// certificate status for certificates presented by the server that contain a list of OCSP responders.
11281187
//

mongo/options/clientoptions_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"go.mongodb.org/mongo-driver/v2/internal/httputil"
3030
"go.mongodb.org/mongo-driver/v2/internal/optionsutil"
3131
"go.mongodb.org/mongo-driver/v2/internal/ptrutil"
32+
"go.mongodb.org/mongo-driver/v2/internal/require"
3233
"go.mongodb.org/mongo-driver/v2/mongo/readconcern"
3334
"go.mongodb.org/mongo-driver/v2/mongo/readpref"
3435
"go.mongodb.org/mongo-driver/v2/mongo/writeconcern"
@@ -81,6 +82,7 @@ func TestClientOptions(t *testing.T) {
8182
{"TLSConfig", (*ClientOptions).SetTLSConfig, &tls.Config{}, "TLSConfig", false},
8283
{"WriteConcern", (*ClientOptions).SetWriteConcern, writeconcern.Majority(), "WriteConcern", false},
8384
{"ZlibLevel", (*ClientOptions).SetZlibLevel, 6, "ZlibLevel", true},
85+
{"DisableCertificateRevocationCheck", (*ClientOptions).SetDisableCertificateRevocationCheck, true, "DisableCertificateRevocationCheck", true},
8486
{"DisableOCSPEndpointCheck", (*ClientOptions).SetDisableOCSPEndpointCheck, true, "DisableOCSPEndpointCheck", true},
8587
{"LoadBalanced", (*ClientOptions).SetLoadBalanced, true, "LoadBalanced", true},
8688
}
@@ -1086,6 +1088,23 @@ func TestApplyURI(t *testing.T) {
10861088
"along with tlsCertificateFile or tlsPrivateKeyFile")),
10871089
},
10881090
},
1091+
{
1092+
name: "disable certificate revocation check",
1093+
uri: "mongodb://localhost/?tlsDisableCertificateRevocationCheck=true",
1094+
wantopts: &ClientOptions{
1095+
Hosts: []string{"localhost"},
1096+
DisableCertificateRevocationCheck: ptrutil.Ptr[bool](true),
1097+
err: nil,
1098+
},
1099+
},
1100+
{
1101+
name: "disable certificate revocation check conflicts with tlsInsecure",
1102+
uri: "mongodb://localhost/?tlsInsecure=false&tlsDisableCertificateRevocationCheck=false",
1103+
wantopts: &ClientOptions{
1104+
err: errors.New("error validating uri: " +
1105+
"sslInsecure/tlsInsecure cannot be used with tlsDisableCertificateRevocationCheck"),
1106+
},
1107+
},
10891108
{
10901109
name: "disable OCSP endpoint check",
10911110
uri: "mongodb://localhost/?tlsDisableOCSPEndpointCheck=true",
@@ -1286,3 +1305,95 @@ func TestApplyURI(t *testing.T) {
12861305
})
12871306
}
12881307
}
1308+
1309+
func TestValidateDisableCertificateRevocationCheck(t *testing.T) {
1310+
const (
1311+
insecureURI = "mongodb://localhost/?tlsInsecure=%t"
1312+
endpointCheckURI = "mongodb://localhost/?tlsDisableOCSPEndpointCheck=%t"
1313+
1314+
insecureMsg = "sslInsecure/tlsInsecure cannot be used with tlsDisableCertificateRevocationCheck"
1315+
endpointMsg = "tlsDisableOCSPEndpointCheck cannot be used with tlsDisableCertificateRevocationCheck"
1316+
)
1317+
1318+
// Paths that connstring cannot cover, because the conflicting options are not both supplied
1319+
// through a URI. Validate inspects the final state, so both orderings are included.
1320+
conflicts := []struct {
1321+
name string
1322+
opts *ClientOptions
1323+
wantErr string
1324+
}{
1325+
{
1326+
name: "setters, both true",
1327+
opts: Client().SetDisableOCSPEndpointCheck(true).SetDisableCertificateRevocationCheck(true),
1328+
wantErr: endpointMsg,
1329+
},
1330+
{
1331+
// Presence is what conflicts, not the values.
1332+
name: "setters, both false",
1333+
opts: Client().SetDisableOCSPEndpointCheck(false).SetDisableCertificateRevocationCheck(false),
1334+
wantErr: endpointMsg,
1335+
},
1336+
{
1337+
name: "setters, reversed order",
1338+
opts: Client().SetDisableCertificateRevocationCheck(true).SetDisableOCSPEndpointCheck(false),
1339+
wantErr: endpointMsg,
1340+
},
1341+
{
1342+
name: "InsecureSkipVerify via TLSConfig",
1343+
opts: Client().
1344+
SetTLSConfig(&tls.Config{InsecureSkipVerify: true}).
1345+
SetDisableCertificateRevocationCheck(true),
1346+
wantErr: insecureMsg,
1347+
},
1348+
{
1349+
name: "URI tlsInsecure=true then setter",
1350+
opts: Client().ApplyURI(fmt.Sprintf(insecureURI, true)).SetDisableCertificateRevocationCheck(true),
1351+
wantErr: insecureMsg,
1352+
},
1353+
{
1354+
// tlsInsecure=false leaves InsecureSkipVerify false, so this is only detectable
1355+
// through the connection string.
1356+
name: "URI tlsInsecure=false then setter",
1357+
opts: Client().ApplyURI(fmt.Sprintf(insecureURI, false)).SetDisableCertificateRevocationCheck(true),
1358+
wantErr: insecureMsg,
1359+
},
1360+
{
1361+
name: "setter then URI tlsInsecure=true",
1362+
opts: Client().SetDisableCertificateRevocationCheck(true).ApplyURI(fmt.Sprintf(insecureURI, true)),
1363+
wantErr: insecureMsg,
1364+
},
1365+
{
1366+
name: "URI tlsDisableOCSPEndpointCheck then setter",
1367+
opts: Client().ApplyURI(fmt.Sprintf(endpointCheckURI, true)).SetDisableCertificateRevocationCheck(true),
1368+
wantErr: endpointMsg,
1369+
},
1370+
}
1371+
1372+
for _, tc := range conflicts {
1373+
t.Run(tc.name, func(t *testing.T) {
1374+
err := tc.opts.Validate()
1375+
require.EqualError(t, err, tc.wantErr)
1376+
})
1377+
}
1378+
1379+
allowed := []struct {
1380+
name string
1381+
opts *ClientOptions
1382+
}{
1383+
{"option alone", Client().SetDisableCertificateRevocationCheck(true)},
1384+
{"option alone, set to false", Client().SetDisableCertificateRevocationCheck(false)},
1385+
{
1386+
"option with a TLSConfig that does not skip verification",
1387+
Client().SetTLSConfig(&tls.Config{}).SetDisableCertificateRevocationCheck(true),
1388+
},
1389+
{"option via URI alone", Client().ApplyURI("mongodb://localhost/?tlsDisableCertificateRevocationCheck=true")},
1390+
{"tlsInsecure alone", Client().ApplyURI(fmt.Sprintf(insecureURI, true))},
1391+
{"tlsDisableOCSPEndpointCheck alone", Client().ApplyURI(fmt.Sprintf(endpointCheckURI, true))},
1392+
}
1393+
1394+
for _, tc := range allowed {
1395+
t.Run(tc.name, func(t *testing.T) {
1396+
require.NoError(t, tc.opts.Validate(), "expected no error")
1397+
})
1398+
}
1399+
}

0 commit comments

Comments
 (0)