diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 1024a6b4..59b3e516 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -186,6 +186,7 @@ type ServerConfig struct { TLSAllowUnencryptedDOH bool TLSv12Roots *x509.CertPool // list of root CAs for TLSv1.2 + TLSCiphers []uint16 // list of TLS ciphers to use // Called when the configuration is changed by HTTP request ConfigModified func() @@ -348,6 +349,7 @@ func (s *Server) Prepare(config *ServerConfig) error { } } upstream.RootCAs = s.conf.TLSv12Roots + upstream.CipherSuites = s.conf.TLSCiphers if len(proxyConfig.Upstreams) == 0 { log.Fatal("len(proxyConfig.Upstreams) == 0") diff --git a/home/dns.go b/home/dns.go index e19079ce..f1a5a501 100644 --- a/home/dns.go +++ b/home/dns.go @@ -172,6 +172,7 @@ func generateServerConfig() dnsforward.ServerConfig { } } newconfig.TLSv12Roots = Context.tlsRoots + newconfig.TLSCiphers = Context.tlsCiphers newconfig.TLSAllowUnencryptedDOH = tlsConf.AllowUnencryptedDOH newconfig.FilterHandler = applyAdditionalFiltering diff --git a/home/home.go b/home/home.go index 69447bc6..8689d4ea 100644 --- a/home/home.go +++ b/home/home.go @@ -80,6 +80,7 @@ type homeContext struct { disableUpdate bool // If set, don't check for updates controlLock sync.Mutex tlsRoots *x509.CertPool // list of root CAs for TLSv1.2 + tlsCiphers []uint16 // list of TLS ciphers to use transport *http.Transport client *http.Client appSignalChannel chan os.Signal // Channel for receiving OS signals by the console app @@ -174,6 +175,7 @@ func run(args options) { initConfig() Context.tlsRoots = util.LoadSystemRootCAs() + Context.tlsCiphers = util.InitTLSCiphers() Context.transport = &http.Transport{ DialContext: customDialContext, Proxy: getHTTPProxy, diff --git a/home/web.go b/home/web.go index 28db3948..a6c515e0 100644 --- a/home/web.go +++ b/home/web.go @@ -176,6 +176,7 @@ func (w *Web) httpServerLoop() { Certificates: []tls.Certificate{w.httpsServer.cert}, MinVersion: tls.VersionTLS12, RootCAs: Context.tlsRoots, + CipherSuites: Context.tlsCiphers, }, } diff --git a/util/tls.go b/util/tls.go index a4d125f9..48b8b35a 100644 --- a/util/tls.go +++ b/util/tls.go @@ -1,12 +1,14 @@ package util import ( + "crypto/tls" "crypto/x509" "io/ioutil" "os" "runtime" "github.com/AdguardTeam/golibs/log" + "golang.org/x/sys/cpu" ) // LoadSystemRootCAs - load root CAs from the system @@ -45,3 +47,51 @@ func LoadSystemRootCAs() *x509.CertPool { } return nil } + +// InitTLSCiphers - the same as initDefaultCipherSuites() from src/crypto/tls/common.go +// but with the difference that we don't use so many other default ciphers. +func InitTLSCiphers() []uint16 { + var ciphers []uint16 + + // Check the cpu flags for each platform that has optimized GCM implementations. + // Worst case, these variables will just all be false. + var ( + hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ + hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL + // Keep in sync with crypto/aes/cipher_s390x.go. + hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) + + hasGCMAsm = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X + ) + + if hasGCMAsm { + // If AES-GCM hardware is provided then prioritise AES-GCM + // cipher suites. + ciphers = []uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + } + } else { + // Without AES-GCM hardware, we put the ChaCha20-Poly1305 + // cipher suites first. + ciphers = []uint16{ + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + } + } + + otherCiphers := []uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + } + ciphers = append(ciphers, otherCiphers...) + return ciphers +}