From fe1c6e037d66f17987aaef8aa7b35c53f85769dd Mon Sep 17 00:00:00 2001 From: ZhenLian Date: Tue, 15 Nov 2022 15:06:50 -0800 Subject: [PATCH] advancedtls: add min/max TLS version option --- security/advancedtls/advancedtls.go | 29 +++++++++++++++++++++++ security/advancedtls/advancedtls_test.go | 30 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/security/advancedtls/advancedtls.go b/security/advancedtls/advancedtls.go index 9a33bd583f6e..4a1607e9cf8f 100644 --- a/security/advancedtls/advancedtls.go +++ b/security/advancedtls/advancedtls.go @@ -162,6 +162,19 @@ const ( SkipVerification ) +// TLSVersionOptions contains the TLS version requirements for a client/server. +type TLSVersionOptions struct { + // MinVersion contains the minimum TLS version that is acceptable. + // By default, TLS 1.2 is currently used as the minimum when acting as a + // client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum + // supported by this package, both as a client and as a server. + MinVersion uint16 + // MaxVersion contains the maximum TLS version that is acceptable. + // By default, the maximum version supported by this package is used, + // which is currently TLS 1.3. + MaxVersion uint16 +} + // ClientOptions contains the fields needed to be filled by the client. type ClientOptions struct { // IdentityOptions is OPTIONAL on client side. This field only needs to be @@ -184,6 +197,9 @@ type ClientOptions struct { // RevocationConfig is the configurations for certificate revocation checks. // It could be nil if such checks are not needed. RevocationConfig *RevocationConfig + // VersionOptions contains the requirements for the TLS version being used. + // If not set, the default values would be used. + VersionOptions TLSVersionOptions } // ServerOptions contains the fields needed to be filled by the server. @@ -205,6 +221,9 @@ type ServerOptions struct { // RevocationConfig is the configurations for certificate revocation checks. // It could be nil if such checks are not needed. RevocationConfig *RevocationConfig + // VersionOptions contains the requirements for the TLS version being used. + // If not set, the default values would be used. + VersionOptions TLSVersionOptions } func (o *ClientOptions) config() (*tls.Config, error) { @@ -222,11 +241,16 @@ func (o *ClientOptions) config() (*tls.Config, error) { if o.IdentityOptions.GetIdentityCertificatesForServer != nil { return nil, fmt.Errorf("GetIdentityCertificatesForServer cannot be specified on the client side") } + if o.VersionOptions.MinVersion > o.VersionOptions.MaxVersion { + return nil, fmt.Errorf("the minimum TLS version is larger than maximum TLS version") + } config := &tls.Config{ ServerName: o.ServerNameOverride, // We have to set InsecureSkipVerify to true to skip the default checks and // use the verification function we built from buildVerifyFunc. InsecureSkipVerify: true, + MinVersion: o.VersionOptions.MinVersion, + MaxVersion: o.VersionOptions.MaxVersion, } // Propagate root-certificate-related fields in tls.Config. switch { @@ -293,6 +317,9 @@ func (o *ServerOptions) config() (*tls.Config, error) { if o.IdentityOptions.GetIdentityCertificatesForClient != nil { return nil, fmt.Errorf("GetIdentityCertificatesForClient cannot be specified on the server side") } + if o.VersionOptions.MinVersion > o.VersionOptions.MaxVersion { + return nil, fmt.Errorf("Minumum TLS version is larger than maximum TLS version") + } clientAuth := tls.NoClientCert if o.RequireClientCert { // We have to set clientAuth to RequireAnyClientCert to force underlying @@ -302,6 +329,8 @@ func (o *ServerOptions) config() (*tls.Config, error) { } config := &tls.Config{ ClientAuth: clientAuth, + MinVersion: o.VersionOptions.MinVersion, + MaxVersion: o.VersionOptions.MaxVersion, } // Propagate root-certificate-related fields in tls.Config. switch { diff --git a/security/advancedtls/advancedtls_test.go b/security/advancedtls/advancedtls_test.go index 7092d46e60fa..12a90ea48149 100644 --- a/security/advancedtls/advancedtls_test.go +++ b/security/advancedtls/advancedtls_test.go @@ -91,6 +91,7 @@ func (s) TestClientOptionsConfigErrorCases(t *testing.T) { clientVType VerificationType IdentityOptions IdentityCertificateOptions RootOptions RootCertificateOptions + VersionOptions TLSVersionOptions }{ { desc: "Skip default verification and provide no root credentials", @@ -122,6 +123,13 @@ func (s) TestClientOptionsConfigErrorCases(t *testing.T) { }, }, }, + { + desc: "Invalid min/max TLS versions", + VersionOptions: TLSVersionOptions{ + MinVersion: tls.VersionTLS13, + MaxVersion: tls.VersionTLS12, + }, + }, } for _, test := range tests { test := test @@ -130,6 +138,7 @@ func (s) TestClientOptionsConfigErrorCases(t *testing.T) { VType: test.clientVType, IdentityOptions: test.IdentityOptions, RootOptions: test.RootOptions, + VersionOptions: test.VersionOptions, } _, err := clientOptions.config() if err == nil { @@ -145,6 +154,7 @@ func (s) TestClientOptionsConfigSuccessCases(t *testing.T) { clientVType VerificationType IdentityOptions IdentityCertificateOptions RootOptions RootCertificateOptions + VersionOptions TLSVersionOptions }{ { desc: "Use system default if no fields in RootCertificateOptions is specified", @@ -159,6 +169,10 @@ func (s) TestClientOptionsConfigSuccessCases(t *testing.T) { IdentityOptions: IdentityCertificateOptions{ IdentityProvider: fakeProvider{pt: provTypeIdentity}, }, + VersionOptions: TLSVersionOptions{ + MinVersion: tls.VersionTLS12, + MaxVersion: tls.VersionTLS13, + }, }, } for _, test := range tests { @@ -168,6 +182,7 @@ func (s) TestClientOptionsConfigSuccessCases(t *testing.T) { VType: test.clientVType, IdentityOptions: test.IdentityOptions, RootOptions: test.RootOptions, + VersionOptions: test.VersionOptions, } clientConfig, err := clientOptions.config() if err != nil { @@ -192,6 +207,7 @@ func (s) TestServerOptionsConfigErrorCases(t *testing.T) { serverVType VerificationType IdentityOptions IdentityCertificateOptions RootOptions RootCertificateOptions + VersionOptions TLSVersionOptions }{ { desc: "Skip default verification and provide no root credentials", @@ -229,6 +245,13 @@ func (s) TestServerOptionsConfigErrorCases(t *testing.T) { }, }, }, + { + desc: "Invalid min/max TLS versions", + VersionOptions: TLSVersionOptions{ + MinVersion: tls.VersionTLS13, + MaxVersion: tls.VersionTLS12, + }, + }, } for _, test := range tests { test := test @@ -238,6 +261,7 @@ func (s) TestServerOptionsConfigErrorCases(t *testing.T) { RequireClientCert: test.requireClientCert, IdentityOptions: test.IdentityOptions, RootOptions: test.RootOptions, + VersionOptions: test.VersionOptions, } _, err := serverOptions.config() if err == nil { @@ -254,6 +278,7 @@ func (s) TestServerOptionsConfigSuccessCases(t *testing.T) { serverVType VerificationType IdentityOptions IdentityCertificateOptions RootOptions RootCertificateOptions + VersionOptions TLSVersionOptions }{ { desc: "Use system default if no fields in RootCertificateOptions is specified", @@ -275,6 +300,10 @@ func (s) TestServerOptionsConfigSuccessCases(t *testing.T) { return nil, nil }, }, + VersionOptions: TLSVersionOptions{ + MinVersion: tls.VersionTLS12, + MaxVersion: tls.VersionTLS13, + }, }, } for _, test := range tests { @@ -285,6 +314,7 @@ func (s) TestServerOptionsConfigSuccessCases(t *testing.T) { RequireClientCert: test.requireClientCert, IdentityOptions: test.IdentityOptions, RootOptions: test.RootOptions, + VersionOptions: test.VersionOptions, } serverConfig, err := serverOptions.config() if err != nil {