From e8d5e719a43419c265a9f5e724fb97d870dd1a49 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Sun, 29 Oct 2023 10:27:13 +0800 Subject: [PATCH] add tls options --- config/config.go | 17 ++- config/parsing/node/parse.go | 8 +- config/parsing/service/parse.go | 6 +- internal/util/tls/tls.go | 198 ++++++++++++++++++++++++++++++-- 4 files changed, 203 insertions(+), 26 deletions(-) diff --git a/config/config.go b/config/config.go index f26243a..7d7055c 100644 --- a/config/config.go +++ b/config/config.go @@ -99,11 +99,12 @@ type MetricsConfig struct { } type TLSConfig struct { - CertFile string `yaml:"certFile,omitempty" json:"certFile,omitempty"` - KeyFile string `yaml:"keyFile,omitempty" json:"keyFile,omitempty"` - CAFile string `yaml:"caFile,omitempty" json:"caFile,omitempty"` - Secure bool `yaml:",omitempty" json:"secure,omitempty"` - ServerName string `yaml:"serverName,omitempty" json:"serverName,omitempty"` + CertFile string `yaml:"certFile,omitempty" json:"certFile,omitempty"` + KeyFile string `yaml:"keyFile,omitempty" json:"keyFile,omitempty"` + CAFile string `yaml:"caFile,omitempty" json:"caFile,omitempty"` + Secure bool `yaml:",omitempty" json:"secure,omitempty"` + ServerName string `yaml:"serverName,omitempty" json:"serverName,omitempty"` + Options *TLSOptions `yaml:",omitempty" json:"options,omitempty"` // for auto-generated default certificate. Validity time.Duration `yaml:",omitempty" json:"validity,omitempty"` @@ -111,6 +112,12 @@ type TLSConfig struct { Organization string `yaml:",omitempty" json:"organization,omitempty"` } +type TLSOptions struct { + MinVersion string `yaml:"minVersion,omitempty" json:"minVersion,omitempty"` + MaxVersion string `yaml:"maxVersion,omitempty" json:"maxVersion,omitempty"` + CipherSuites []string `yaml:"cipherSuites,omitempty" json:"cipherSuites,omitempty"` +} + type PluginConfig struct { Type string `json:"type"` Addr string `json:"addr"` diff --git a/config/parsing/node/parse.go b/config/parsing/node/parse.go index 19570de..04f051c 100644 --- a/config/parsing/node/parse.go +++ b/config/parsing/node/parse.go @@ -57,9 +57,7 @@ func ParseNode(hop string, cfg *config.NodeConfig) (*chain.Node, error) { if tlsCfg.ServerName == "" { tlsCfg.ServerName = serverName } - tlsConfig, err := tls_util.LoadClientConfig( - tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile, - tlsCfg.Secure, tlsCfg.ServerName) + tlsConfig, err := tls_util.LoadClientConfig(tlsCfg) if err != nil { nodeLogger.Error(err) return nil, err @@ -99,9 +97,7 @@ func ParseNode(hop string, cfg *config.NodeConfig) (*chain.Node, error) { if tlsCfg.ServerName == "" { tlsCfg.ServerName = serverName } - tlsConfig, err = tls_util.LoadClientConfig( - tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile, - tlsCfg.Secure, tlsCfg.ServerName) + tlsConfig, err = tls_util.LoadClientConfig(tlsCfg) if err != nil { nodeLogger.Error(err) return nil, err diff --git a/config/parsing/service/parse.go b/config/parsing/service/parse.go index f9fa73c..089c1b7 100644 --- a/config/parsing/service/parse.go +++ b/config/parsing/service/parse.go @@ -55,8 +55,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { if tlsCfg == nil { tlsCfg = &config.TLSConfig{} } - tlsConfig, err := tls_util.LoadServerConfig( - tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile) + tlsConfig, err := tls_util.LoadServerConfig(tlsCfg) if err != nil { listenerLogger.Error(err) return nil, err @@ -149,8 +148,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { if tlsCfg == nil { tlsCfg = &config.TLSConfig{} } - tlsConfig, err = tls_util.LoadServerConfig( - tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile) + tlsConfig, err = tls_util.LoadServerConfig(tlsCfg) if err != nil { handlerLogger.Error(err) return nil, err diff --git a/internal/util/tls/tls.go b/internal/util/tls/tls.go index 131f94f..e6b67fb 100644 --- a/internal/util/tls/tls.go +++ b/internal/util/tls/tls.go @@ -6,9 +6,43 @@ import ( "errors" "net" "os" + "strings" "time" "github.com/go-gost/core/logger" + "github.com/go-gost/x/config" +) + +const ( + VersionTLS10 = "VersionTLS10" + VersionTLS11 = "VersionTLS11" + VersionTLS12 = "VersionTLS12" + VersionTLS13 = "VersionTLS13" +) + +const ( + TLS_RSA_WITH_RC4_128_SHA = "TLS_RSA_WITH_RC4_128_SHA" + TLS_RSA_WITH_3DES_EDE_CBC_SHA = "TLS_RSA_WITH_3DES_EDE_CBC_SHA" + TLS_RSA_WITH_AES_128_CBC_SHA = "TLS_RSA_WITH_AES_128_CBC_SHA" + TLS_RSA_WITH_AES_256_CBC_SHA = "TLS_RSA_WITH_AES_256_CBC_SHA" + TLS_RSA_WITH_AES_128_CBC_SHA256 = "TLS_RSA_WITH_AES_128_CBC_SHA256" + TLS_RSA_WITH_AES_128_GCM_SHA256 = "TLS_RSA_WITH_AES_128_GCM_SHA256" + TLS_RSA_WITH_AES_256_GCM_SHA384 = "TLS_RSA_WITH_AES_256_GCM_SHA384" + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA" + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" + TLS_ECDHE_RSA_WITH_RC4_128_SHA = "TLS_ECDHE_RSA_WITH_RC4_128_SHA" + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA" + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" ) // LoadDefaultConfig loads the certificate from cert & key files and optional CA file. @@ -33,19 +67,19 @@ func LoadDefaultConfig(certFile, keyFile, caFile string) (*tls.Config, error) { } // LoadServerConfig loads the certificate from cert & key files and client CA file. -func LoadServerConfig(certFile, keyFile, caFile string) (*tls.Config, error) { - if certFile == "" && keyFile == "" { +func LoadServerConfig(config *config.TLSConfig) (*tls.Config, error) { + if config.CertFile == "" && config.KeyFile == "" { return nil, nil } - cert, err := tls.LoadX509KeyPair(certFile, keyFile) + cert, err := tls.LoadX509KeyPair(config.CertFile, config.KeyFile) if err != nil { return nil, err } cfg := &tls.Config{Certificates: []tls.Certificate{cert}} - pool, err := loadCA(caFile) + pool, err := loadCA(config.CAFile) if err != nil { return nil, err } @@ -54,17 +88,88 @@ func LoadServerConfig(certFile, keyFile, caFile string) (*tls.Config, error) { cfg.ClientAuth = tls.RequireAndVerifyClientCert } + if opts := config.Options; opts != nil { + switch strings.ToLower(opts.MinVersion) { + case strings.ToLower(VersionTLS10): + cfg.MinVersion = tls.VersionTLS10 + case strings.ToLower(VersionTLS11): + cfg.MinVersion = tls.VersionTLS11 + case strings.ToLower(VersionTLS12): + cfg.MinVersion = tls.VersionTLS12 + case strings.ToLower(VersionTLS13): + cfg.MinVersion = tls.VersionTLS13 + } + switch strings.ToLower(opts.MaxVersion) { + case strings.ToLower(VersionTLS10): + cfg.MaxVersion = tls.VersionTLS10 + case strings.ToLower(VersionTLS11): + cfg.MaxVersion = tls.VersionTLS11 + case strings.ToLower(VersionTLS12): + cfg.MaxVersion = tls.VersionTLS12 + case strings.ToLower(VersionTLS13): + cfg.MaxVersion = tls.VersionTLS13 + } + for _, v := range opts.CipherSuites { + switch strings.ToLower(v) { + case strings.ToLower(TLS_RSA_WITH_RC4_128_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_RC4_128_SHA) + case strings.ToLower(TLS_RSA_WITH_3DES_EDE_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA) + case strings.ToLower(TLS_RSA_WITH_AES_128_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_128_CBC_SHA) + case strings.ToLower(TLS_RSA_WITH_AES_256_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_256_CBC_SHA) + case strings.ToLower(TLS_RSA_WITH_AES_128_CBC_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_128_CBC_SHA256) + case strings.ToLower(TLS_RSA_WITH_AES_128_GCM_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_128_GCM_SHA256) + case strings.ToLower(TLS_RSA_WITH_AES_256_GCM_SHA384): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_256_GCM_SHA384) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) + case strings.ToLower(TLS_ECDHE_RSA_WITH_RC4_128_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA) + case strings.ToLower(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) + case strings.ToLower(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) + } + } + } + return cfg, nil } // LoadClientConfig loads the certificate from cert & key files and CA file. -func LoadClientConfig(certFile, keyFile, caFile string, verify bool, serverName string) (*tls.Config, error) { +func LoadClientConfig(config *config.TLSConfig) (*tls.Config, error) { var cfg *tls.Config - if certFile == "" && keyFile == "" { + if config.CertFile == "" && config.KeyFile == "" { cfg = &tls.Config{} } else { - cert, err := tls.LoadX509KeyPair(certFile, keyFile) + cert, err := tls.LoadX509KeyPair(config.CertFile, config.KeyFile) if err != nil { return nil, err } @@ -74,17 +179,88 @@ func LoadClientConfig(certFile, keyFile, caFile string, verify bool, serverName } } - rootCAs, err := loadCA(caFile) + rootCAs, err := loadCA(config.CAFile) if err != nil { return nil, err } cfg.RootCAs = rootCAs - cfg.ServerName = serverName - cfg.InsecureSkipVerify = !verify + cfg.ServerName = config.ServerName + cfg.InsecureSkipVerify = !config.Secure + + if opts := config.Options; opts != nil { + switch strings.ToLower(opts.MinVersion) { + case strings.ToLower(VersionTLS10): + cfg.MinVersion = tls.VersionTLS10 + case strings.ToLower(VersionTLS11): + cfg.MinVersion = tls.VersionTLS11 + case strings.ToLower(VersionTLS12): + cfg.MinVersion = tls.VersionTLS12 + case strings.ToLower(VersionTLS13): + cfg.MinVersion = tls.VersionTLS13 + } + switch strings.ToLower(opts.MaxVersion) { + case strings.ToLower(VersionTLS10): + cfg.MaxVersion = tls.VersionTLS10 + case strings.ToLower(VersionTLS11): + cfg.MaxVersion = tls.VersionTLS11 + case strings.ToLower(VersionTLS12): + cfg.MaxVersion = tls.VersionTLS12 + case strings.ToLower(VersionTLS13): + cfg.MaxVersion = tls.VersionTLS13 + } + for _, v := range opts.CipherSuites { + switch strings.ToLower(v) { + case strings.ToLower(TLS_RSA_WITH_RC4_128_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_RC4_128_SHA) + case strings.ToLower(TLS_RSA_WITH_3DES_EDE_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA) + case strings.ToLower(TLS_RSA_WITH_AES_128_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_128_CBC_SHA) + case strings.ToLower(TLS_RSA_WITH_AES_256_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_256_CBC_SHA) + case strings.ToLower(TLS_RSA_WITH_AES_128_CBC_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_128_CBC_SHA256) + case strings.ToLower(TLS_RSA_WITH_AES_128_GCM_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_128_GCM_SHA256) + case strings.ToLower(TLS_RSA_WITH_AES_256_GCM_SHA384): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_RSA_WITH_AES_256_GCM_SHA384) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) + case strings.ToLower(TLS_ECDHE_RSA_WITH_RC4_128_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA) + case strings.ToLower(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + case strings.ToLower(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) + case strings.ToLower(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) + case strings.ToLower(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256): + cfg.CipherSuites = append(cfg.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) + } + } + } // If the root ca is given, but skip verify, we verify the certificate manually. - if cfg.RootCAs != nil && !verify { + if cfg.RootCAs != nil && !config.Secure { cfg.VerifyConnection = func(state tls.ConnectionState) error { opts := x509.VerifyOptions{ Roots: cfg.RootCAs,