History

Make SSL cipher suite configurable (#17440)

zeripath committed 4 years ago

Commit c96be0c1 parent 9f14fe49 files · +266 −54Browse files

Showing the changes to cmd/web_https.go (1 of 9 files). Show all

Unified · Split

cmd/web_https.go+191−0
@@ -0,0 +1,191 @@
1+// Copyright 2021 The Gitea Authors. All rights reserved.
2+// Use of this source code is governed by a MIT-style
3+// license that can be found in the LICENSE file.
4+
5+package cmd
6+
7+import (
8+ "crypto/tls"
9+ "net/http"
10+ "os"
11+ "strings"
12+
13+ "code.gitea.io/gitea/modules/graceful"
14+ "code.gitea.io/gitea/modules/log"
15+ "code.gitea.io/gitea/modules/setting"
16+ "github.com/klauspost/cpuid/v2"
17+)
18+
19+var tlsVersionStringMap = map[string]uint16{
20+ "": tls.VersionTLS12, // Default to tls.VersionTLS12
21+ "tlsv1.0": tls.VersionTLS10,
22+ "tlsv1.1": tls.VersionTLS11,
23+ "tlsv1.2": tls.VersionTLS12,
24+ "tlsv1.3": tls.VersionTLS13,
25+}
26+
27+func toTLSVersion(version string) uint16 {
28+ tlsVersion, ok := tlsVersionStringMap[strings.TrimSpace(strings.ToLower(version))]
29+ if !ok {
30+ log.Warn("Unknown tls version: %s", version)
31+ return 0
32+ }
33+ return tlsVersion
34+}
35+
36+var curveStringMap = map[string]tls.CurveID{
37+ "x25519": tls.X25519,
38+ "p256": tls.CurveP256,
39+ "p384": tls.CurveP384,
40+ "p521": tls.CurveP521,
41+}
42+
43+func toCurvePreferences(preferences []string) []tls.CurveID {
44+ ids := make([]tls.CurveID, 0, len(preferences))
45+ for _, pref := range preferences {
46+ id, ok := curveStringMap[strings.TrimSpace(strings.ToLower(pref))]
47+ if !ok {
48+ log.Warn("Unknown curve: %s", pref)
49+ }
50+ if id != 0 {
51+ ids = append(ids, id)
52+ }
53+ }
54+ return ids
55+}
56+
57+var cipherStringMap = map[string]uint16{
58+ "rsa_with_rc4_128_sha": tls.TLS_RSA_WITH_RC4_128_SHA,
59+ "rsa_with_3des_ede_cbc_sha": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
60+ "rsa_with_aes_128_cbc_sha": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
61+ "rsa_with_aes_256_cbc_sha": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
62+ "rsa_with_aes_128_cbc_sha256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
63+ "rsa_with_aes_128_gcm_sha256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
64+ "rsa_with_aes_256_gcm_sha384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
65+ "ecdhe_ecdsa_with_rc4_128_sha": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
66+ "ecdhe_ecdsa_with_aes_128_cbc_sha": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
67+ "ecdhe_ecdsa_with_aes_256_cbc_sha": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
68+ "ecdhe_rsa_with_rc4_128_sha": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
69+ "ecdhe_rsa_with_3des_ede_cbc_sha": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
70+ "ecdhe_rsa_with_aes_128_cbc_sha": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
71+ "ecdhe_rsa_with_aes_256_cbc_sha": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
72+ "ecdhe_ecdsa_with_aes_128_cbc_sha256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
73+ "ecdhe_rsa_with_aes_128_cbc_sha256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
74+ "ecdhe_rsa_with_aes_128_gcm_sha256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
75+ "ecdhe_ecdsa_with_aes_128_gcm_sha256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
76+ "ecdhe_rsa_with_aes_256_gcm_sha384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
77+ "ecdhe_ecdsa_with_aes_256_gcm_sha384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
78+ "ecdhe_rsa_with_chacha20_poly1305_sha256": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
79+ "ecdhe_ecdsa_with_chacha20_poly1305_sha256": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
80+ "ecdhe_rsa_with_chacha20_poly1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
81+ "ecdhe_ecdsa_with_chacha20_poly1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
82+ "aes_128_gcm_sha256": tls.TLS_AES_128_GCM_SHA256,
83+ "aes_256_gcm_sha384": tls.TLS_AES_256_GCM_SHA384,
84+ "chacha20_poly1305_sha256": tls.TLS_CHACHA20_POLY1305_SHA256,
85+}
86+
87+func toTLSCiphers(cipherStrings []string) []uint16 {
88+ ciphers := make([]uint16, 0, len(cipherStrings))
89+ for _, cipherString := range cipherStrings {
90+ cipher, ok := cipherStringMap[strings.TrimSpace(strings.ToLower(cipherString))]
91+ if !ok {
92+ log.Warn("Unknown cipher: %s", cipherString)
93+ }
94+ if cipher != 0 {
95+ ciphers = append(ciphers, cipher)
96+ }
97+ }
98+
99+ return ciphers
100+}
101+
102+// defaultCiphers uses hardware support to check if AES is specifically
103+// supported by the CPU.
104+//
105+// If AES is supported AES ciphers will be preferred over ChaCha based ciphers
106+// (This code is directly inspired by the certmagic code.)
107+func defaultCiphers() []uint16 {
108+ if cpuid.CPU.Supports(cpuid.AESNI) {
109+ return defaultCiphersAESfirst
110+ }
111+ return defaultCiphersChaChaFirst
112+}
113+
114+var (
115+ defaultCiphersAES = []uint16{
116+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
117+ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
118+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
119+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
120+ }
121+
122+ defaultCiphersChaCha = []uint16{
123+ tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
124+ tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
125+ }
126+
127+ defaultCiphersAESfirst = append(defaultCiphersAES, defaultCiphersChaCha...)
128+ defaultCiphersChaChaFirst = append(defaultCiphersChaCha, defaultCiphersAES...)
129+)
130+
131+// runHTTPs listens on the provided network address and then calls
132+// Serve to handle requests on incoming TLS connections.
133+//
134+// Filenames containing a certificate and matching private key for the server must
135+// be provided. If the certificate is signed by a certificate authority, the
136+// certFile should be the concatenation of the server's certificate followed by the
137+// CA's certificate.
138+func runHTTPS(network, listenAddr, name, certFile, keyFile string, m http.Handler) error {
139+ tlsConfig := &tls.Config{}
140+ if tlsConfig.NextProtos == nil {
141+ tlsConfig.NextProtos = []string{"h2", "http/1.1"}
142+ }
143+
144+ if version := toTLSVersion(setting.SSLMinimumVersion); version != 0 {
145+ tlsConfig.MinVersion = version
146+ }
147+ if version := toTLSVersion(setting.SSLMaximumVersion); version != 0 {
148+ tlsConfig.MaxVersion = version
149+ }
150+
151+ // Set curve preferences
152+ tlsConfig.CurvePreferences = []tls.CurveID{
153+ tls.X25519,
154+ tls.CurveP256,
155+ }
156+ if curves := toCurvePreferences(setting.SSLCurvePreferences); len(curves) > 0 {
157+ tlsConfig.CurvePreferences = curves
158+ }
159+
160+ // Set cipher suites
161+ tlsConfig.CipherSuites = defaultCiphers()
162+ if ciphers := toTLSCiphers(setting.SSLCipherSuites); len(ciphers) > 0 {
163+ tlsConfig.CipherSuites = ciphers
164+ }
165+
166+ tlsConfig.Certificates = make([]tls.Certificate, 1)
167+
168+ certPEMBlock, err := os.ReadFile(certFile)
169+ if err != nil {
170+ log.Error("Failed to load https cert file %s for %s:%s: %v", certFile, network, listenAddr, err)
171+ return err
172+ }
173+
174+ keyPEMBlock, err := os.ReadFile(keyFile)
175+ if err != nil {
176+ log.Error("Failed to load https key file %s for %s:%s: %v", keyFile, network, listenAddr, err)
177+ return err
178+ }
179+
180+ tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlock, keyPEMBlock)
181+ if err != nil {
182+ log.Error("Failed to create certificate from cert file %s and key file %s for %s:%s: %v", certFile, keyFile, network, listenAddr, err)
183+ return err
184+ }
185+
186+ return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m)
187+}
188+
189+func runHTTPSWithTLSConfig(network, listenAddr, name string, tlsConfig *tls.Config, m http.Handler) error {
190+ return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m)
191+}